现在的位置: 首页 > 综合 > 正文

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

2018年06月10日 ⁄ 综合 ⁄ 共 2083字 ⁄ 字号 评论关闭

Linux

用户进程内存分配及二级页表
PTE

的二三事

我们在用调试器看
Linux

用户进程代码时,发现了一件很有意思的事情,在一段内存空间中,有一整页(
4K

)都是
data abort

,如下:

第一页
4011c
000

数据正常

... ...

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

系统的二级页表(对应
ARM


TLB


Linux

中叫
PTE

)。这个实验虽然看上去很不可思议,但实现起来并不复杂。最终得到了
Linux

存放在内存中的
TLB

数据。

每个表项是
32bit

虚拟页地址
   


对应表项的内容

4011c
000             
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


如有错误,欢迎指正!

抱歉!评论已关闭.