浅析linux内核内存管理之临时内核页表

来源:互联网 发布:杭州的淘宝大学 编辑:程序博客网 时间:2024/05/15 00:11
                   浅析linux内核内存管理之临时内核页表

                                                



临时页全局目录是在内核编译过程中静态地初始化的,而临时页表是由startup_32()汇编语言函数初始化的。临时页全局目录存放在swapper_pg_dir变量中,临时页表在pg0变量开始出存放,紧接在内核未初始化的数据段(_end符号后)后面。假设内存使用的段,临时页表和128KB的内存范围能容纳于RAM前8MB空间,为了映射8MB空间需要两个页表,一个是pg0处,另一个存放在pg0后边。为了在实模式和保护模式下都能对这8MB寻址,因此内核必须创建一个映射,把从0x00000000到0x007fffff的线性地址和从0xc0000000到0xc07fffff的线性地址映射到从0x00000000到0x007fffff。所以要设置临时页全局目录的第0,1,768,769项,其他项为0。


临时内核页表设置的代码在arch/i386/kernel/head.S中:  

[html] view plaincopy
  1.  91page_pde_offset = (__PAGE_OFFSET >> 20);  
  2.  92  
  3.  93        movl $(pg0 - __PAGE_OFFSET), %edi  
  4.  94        movl $(swapper_pg_dir - __PAGE_OFFSET), %edx  
  5.  95        movl $0x007, %eax                       /* 0x007 = PRESENT+RW+USER */  
  6.  9610:  
  7.  97        leal 0x007(%edi),%ecx                   /* Create PDE entry */  
  8.  98        movl %ecx,(%edx)                        /* Store identity PDE entry */  
  9.  99        movl %ecx,page_pde_offset(%edx)         /* Store kernel PDE entry */  
  10. 100        addl $4,%edx  
  11. 101        movl $1024, %ecx  
  12. 10211:  
  13. 103        stosl  
  14. 104        addl $0x1000,%eax  
  15. 105        loop 11b  
  16. 106        /* End condition: we must map up to and including INIT_MAP_BEYOND_END */  
  17. 107        /* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */  
  18. 108        leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp  
  19. 109        cmpl %ebp,%eax  
  20. 110        jb 10b  
  21. 111        movl %edi,(init_pg_tables_end - __PAGE_OFFSET)  
91 计算__PAGE_OFFSET在页目录中的偏移
93 %edi保存pg0的物理地址,pg0定义在连接脚本 arch/i386/kernel/vmlinux.lds中,gcc编译内核以后形成的符号地址都是虚拟地址,在我的系统redhat 9.0内核2.6.11环境下,pg0为 0xc04d4000,这个可以在System.map文件中查看到
94 将swapper_pg_dir的物理地址存放到%edi中
95 存放低12位的标志到%eax中
97 将pg0的物理地址与标志位合到一起,创建一个页目录项
98 将这个页目录项存储在swapper_pg_dir的临时页全局目录中,在第一次循环中填充0号表项,第二次循环填充1号表项
99 在第一次循环填充768号表项,第二次循环填充769号表项
100 edx指向下一个表项
101 设置计数,即要设置临时页全局目录表1024个表项
103 eax->[edi];edi = edi + 4
104 填充pg0时,一个表项对应一个page,一个page是4KB,所以加0x1000
105 一直循环,填充pg0的1024个表项;下一次大循环,填充pg0后边的那个页表的1024个表项
108 将INIT_MAP_BEYOND_END+0x007+%edi与%ebp比较,如果小于就进行下一轮大循环,此时是填充pg0后的第二个页表
111 init_pg_tables_end存放pg0+0x2000


[html] view plaincopy
  1. 183/*  
  2. 184 * Enable paging  
  3. 185 */  
  4. 186        movl $swapper_pg_dir-__PAGE_OFFSET,%eax  
  5. 187        movl %eax,%cr3          /* set the page table pointer.. */  
  6. 188        movl %cr0,%eax  
  7. 189        orl $0x80000000,%eax  
  8. 190        movl %eax,%cr0          /* ..and set paging (PG) bit */  
  9. 191        ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */  
  10. 1921:  
  11. 193        /* Set up the stack pointer */  
  12. 194        lss stack_start,%esp  

获得临时页全局目录的物理地址,存放在cr3中,并设置cr0的PG标志位,此时开启了分页功能
原创粉丝点击