1.3.5 head.s开始执行(5)

来源:互联网 发布:php文件管理插件 简洁 编辑:程序博客网 时间:2024/04/25 12:17

1.3.5 head.s开始执行(5)

上述动作的代码如下:

  1. //代码路径:boot/head.s  
  2. movl $pg0+7,_pg_dir     /* set present bit/user r/w */  
  3. movl $pg1+7,_pg_dir+4       /*  --------- " " --------- */  
  4. movl $pg2+7,_pg_dir+8       /*  --------- " " --------- */  
  5. movl $pg3+7,_pg_dir+12      /*  --------- " " --------- */  
  6. movl $pg3+4092,%edi  
  7. movl $0xfff007,%eax     /*  16Mb-4096 + 7 (r/w user,p) */ 

head程序设置完页目录表后,Linux 0.11在保护模式下支持的最大寻址地址为0xFFFFFF(16MB),此处将第4张页表(由pg3指向的位置)的最后一个页表项(pg3+4902指向的位置)指向寻址范围的最后一个页面,即0xFFF000开始的4KB字节大小的内存空间。具体请看图1-38右下方的标示。

 图1-38 页目录表设置完成后的状态

然后开始从高地址向低地址方向填写全部的4个页表,依次指向内存从高地址向低地址方向的各个页面,图1-38是首次设置页表。

继续设置页表。将第4张页表(由pg3指向的位置)的倒数第二个页表项(pg3-4+4902指向的位置)指向倒数第二个页面,即0xFFF000-0x1000(0x1000即4k,一个页面的大小)开始的4k字节内存空间。请读者认真对比图1-39和图1-38,图中有多处位置发生了变化。

最终,从高地址向低地址方向完成全部4个页表的填写,页表中的每一个页表项分别指向内存从高地址向低地址方向的各个页面,如图1-40下方所示。

这4个页表都是内核专属的页表,将来每个用户进程都有它们专属的页表,两者在寻址范围方面的区别,我们将在内存与进程一章中详细介绍。

图1-38~图1-40中所发生动作的相应代码如下:

  1. //代码路径:boot/head.s  
  2.     movl $pg3+4092,%edi  
  3.     movl $0xfff007,%eax     /*  16Mb-4096 + 7 (r/w user,p) */  
  4.     std  
  5. 1:  stosl               /* fill pages backwards-more efficient :-) */  
  6.     subl $0x1000,%eax  
  7.     jge 1b 
 图1-39 设置页表
 图1-40 页目录表和页表设置完毕的状态

这些工作完成后,内存中的布局如图1-41所示。可以看出,只有184个字节的剩余代码,由此可见在设计head程序和system模块时,其计算是非常精确的,对head.s的代码量的控制非常到位。

head程序已将页表设置完毕了,但分页机制的建立还没有完成。需要设置页目录基址寄存器CR3,使之指向页目录表,再将CR0寄存器设置的最高位(31位)置为1,如图1-42的右中部CR0寄存器的示意图。

小贴士

PG(Paging)标志:CR0寄存器的第32位,分页机制控制位。当CPU的控制寄存器CR0第1位PE(保护模式)置为1时,可设置PG位为开启。在开启后,地址映射模式采取分页机制。当CPU的控制寄存器CR0第1位PE(保护模式)置为0时,此时设置PG位将引起CPU发出异常。

CR3寄存器:3号32位控制寄存器,高20位存放页目录的基地址。当CR0中的PG标志置位时,CPU使用CR3指向的页目录和页表进行虚拟地址到物理地址的映射。


 (点击查看大图)图1-41 内存分布示意图
 图1-42 分页机制完成后的总体状态
0 0
原创粉丝点击