Linux用户进程内存分配及二级页表PTE的二三事

来源:互联网 发布:nba2k17流川枫捏脸数据 编辑:程序博客网 时间:2024/04/29 14:30

Linux用户进程内存分配及二级页表PTE的二三事

我们在用调试器看Linux用户进程代码时,发现了一件很有意思的事情,在一段内存空间中,有一整页(4K)都是data abort,如下:

第一页4011c000数据正常

... ...

4011cfec [0xe28dd014]   add      r13,r13,#0x14

4011cff0 [0xe8bd40f0]   ldmfd    r13!,{r4-r7,r14}

4011cff4 [0xe12fff1e]   bx       r14

4011cff8 [0xe92d41f0]   stmfd    r13!,{r4-r8,r14}

4011cffc [0xe59f4064]   ldr      r4,0x4011d068

 

第二页4011d000 都是Data abort

4011d000       *** Data abort ***

4011d004       *** Data abort ***

4011d008       *** Data abort ***

4011d00c       *** Data abort ***

... ...

 

第三页 4011e000 数据正常

4011e000        数据正常

 

由于当时并不知道Linux是如何处理用户进程的内存分配,所以认为这是一个“错误”。既然有错误,我们决定找到这个问题发生的根源。

在追踪这个问题的过程中,leeming同学做了一个很BT的实验。我简单说两句,详细大家可以去看他的文章(http://blog.chinaunix.net/u3/99423/showart_2096904.html)。大概的方法就是将物理内存全部dump出来,通过第一页的代码,比如0xe59f4064,查找其在内存中的物理地址,再通过提取物理地址的前20位,就可以查找Linux系统的二级页表(对应ARMTLBLinux中叫PTE)。这个实验虽然看上去很不可思议,但实现起来并不复杂。最终得到了Linux存放在内存中的TLB数据。

每个表项是32bit

虚拟页地址    对应表项的内容

4011c000              3156caae

4011d000              00000000

4011e000        3156faae

 

       很有意思,Data abort的数据段,对应的PTE也是空的,这难道是一个系统错误?

       NO!经过进一步的学习后发现,在Linux系统中,这是一个很正常的现象。Linux在用户进程执行时并没有建立所有内存页面的映射,而是需要用到的时候再建立映射关系。当Linux用户进程访问到没有建立映射的页表(此时PTE指针为0),会调用相应的函数进行处理,或建立、或换出,具体执行这个操作的函数叫handle_pte_fault(),位于内核的mm/memory.c中。

       但是,Linux是如何进入缺页处理的呢?

有两种情况,都是利用了ARM处理器的异常中断进行相应的处理。

       第一种是程序顺序执行,正常页面的最后一条指令执行完后进入空页面,当空页面的第一条指令进入ARM处理器流水线的执行周期时,ARM处理器会报告一个指令预取异常中断,并跳转到地址0x0c,在Linux系统中由于使用了高地址向量表,所以会跳转到0xffff000c。此时ARM处理器进入ABORT状态,执行一系列代码保存现场(代码位于/arch/arm/kernel/entry-armv.s),然后进入SVC状态执行arch/arm/mm/fault.c中的do_PrefetchAbort(),最后会调用handle_pte_fault()处理缺页异常。

       第二种情况,页面中的程序执行时需要使用未分配页面的数据,比如“ldr r0,未分配页地址”。遇到这种情况,就不是指令预取异常了,而是数据访问异常(Data abort)。此时处理器依然会进入ABORT状态,跳转到0xffff0010执行相应的vector_dabt代码(entry_armv.s)保存状态,进入SVC态,执行do_DataAbort()函数,最后同样调用handle_pte_fault()处理缺页异常。

       因此,最开始遇到的情况:三个PTE,中间是空的,这是一个很正常的情况。因为第三页很可能由于前面的调用而已经建立,第二页却还没有建立。

       至于handle_pte_fault()如何处理缺页异常,我还没有看完,就不在本文讨论了。已知至少有do_no_page()do_swap_page()do_wp_page等多种方式,此为后话。

       通过跟踪用户程序,发现Linux用户进程基本所有的页面都是这样处理,因此处理器会很频繁的进出Abort状态,执行页面处理函数,这是会不会效率有点低了呢?待研究。

      

阿虚(Rockie Cheng

       2009-11-21

 

本文为原创,转载请注明出处http://hi.baidu.com/aokikyon

如有错误,欢迎指正!