分页机制(转)

转:http://blog.csdn.net/h_armony/article/details/9842831  

  分页与分段最大的不同之处在于分页是用来固定长度的页面(一般为4KB)。如果仅适用分段地址转换,那么存储在物理内存中的一个数据结构将包含器所有部分。但如果适用了分页,那么一个数据结构就可以一部分存储在物理内存中,而另一部分保存在磁盘中。这也就是分页机制在现代内存管理中存在的重要性。

  那么首先我们还是熟悉一下分页机制的基本概念。

  如上图所示,分页是在分段的基础上将线性地址转化为物理地址。转换时使用了两级页表,第一级是页目录,大小为4KB,存储在一个物理页上,每个表项4字节长,共有1024个表项。每个表项对应第二级的一个页表,第二级的每个页表也有1024个表项,每个表项对应一个物理页。页目录表的表项简称PDE(Page Directory Entry),页表的表项简称PTE(Page Table Entry)。

  整个转换过程:

  1)获取页目录表项:从CR3中的高20位获取页目录所在的物理地址,再将线性地址的高10位作为索引找到页目录表项;

  2)获取页表项:从页目录表项中高20位获取页表所在的物理地址,再将线性地址的中间10位作为索引找到页表项;

  3)获取物理地址:从页表项中高20位获取页所在的物理地址,再加上线性地址的低12位,便得到了物理地址;

  注:1)在32位X86中,上述高20位在使用过程中,首先需要左移12位,构成32位地址;

    2)启动页机制:将CR0的第31位置1;

 

   CR3、PDE以及PTE结构(自P2055)

  下面我们还是通过分析代码来理解分页:

  [cpp]  view plain copy
  1. PageDirBase  equ 200000h ; 页目录开始地址:2M  
  2. PageTblBase  equ 201000h ; 页表开始地址: 2M+4K  
  3.   
  4. ; 启动分页机制 --------------------------------------------------------------  
  5. SetupPaging:  
  6.     ; 为简化处理, 所有线性地址对应相等的物理地址.  
  7.   
  8.     ; 首先初始化页目录  
  9.     mov ax, SelectorPageDir ; 此段首地址为 PageDirBase  200000h(2M)                             
  10.     mov es, ax          ; es:[edi]指向PageDirBase,页目录表基地址                                       
  11.     mov ecx, 1024       ; 共 1K 个表项,循环1024次                                    
  12.     xor edi, edi  
  13.     xor eax, eax  
  14.     mov eax, PageTblBase | PG_P  | PG_USU | PG_RWW  ; eax里是PageTblBase(201000h)加上属性PG_P  | PG_USU | PG_RWW后的结果,也就是第一个页表的地址和属性                 
  15.   
  16.               
  17. .1:  
  18.     stosd               ; es:[edi] ← eax    ; 把第一个页表地址、属性填入页目录基地址,也就是第一个页目录表项里                            
  19.   
  20.       
  21.     add eax, 4096       ; 为了简化, 所有页表在内存中是连续的.   ;eax里存的其实就是页目录表项的内容,这里在第一个表项内容基础上加上4096,相当与第二个表项指向的页  
  22.   
  23.                                           表基地址是PageTblBase+4096,下面是循环以此类推...                      
  24.     loop    .1                      ;循环1024次,完成页目录里1024个表项的初始化  
  25.   
  26.     ; 再初始化所有页表 (1K 个, 4M 内存空间)                                        
  27.     mov ax, SelectorPageTbl ; 此段首地址为 PageTblBase  
  28.     mov es, ax                  ; es:[edi]指向PageTblBase,页表基地址  
  29.     mov ecx, 1024 * 1024    ; 1024个页表,每个页表有1024个表项, 也就是有 1M 个页  
  30.     xor edi, edi  
  31.     xor eax, eax  
  32.     mov eax, PG_P  | PG_USU | PG_RWW                     ; 这里属性前没有地址,其实地址是0,也就是将线性地址0开始的4K空间映射到物理地址上  
  33. .2:  
  34.     stosd                           ; es:[edi] ← eax    ; 把第一个页表地址、属性填入页表基地址,也就是第一个页表里  
  35.     add eax, 4096       ; 下一页表里存放的基地址在前一个的基地址基础上+4049,实际就是表明一个页的大小为4K  
  36.     loop    .2          ; 循环1M次,每次映射1页(4K大小的空间),所以总共映射了4G空间                                       
  37.   
  38.     mov eax, PageDirBase                                              
  39.     mov cr3, eax        ;cr3寄存器里存入PageDirBase基地址                                          
  40.     mov eax, cr0                                                  
  41.     or  eax, 80000000h  
  42.     mov cr0, eax            ;将控制寄存器cr0的PE标志(位31)置为1,开启分页机制                                            
  43.     jmp short .3  
  44. .3:  
  45.     nop  
  46.   
  47.     ret  
  48. ; 分页机制启动完毕 ----------------------------------------------------------  

 

  上述程序大致做了这样的事:构建页目录表和页表,为了构建简单,表项都在内存中连续存放,将页目录表基地址存入cr3中,然后开启分页机制。

关键的地方是在页目录表和页表结构里的基地址内容:

  PDE里页表基址:依次为201000,202000......600000。总共1024个,每两个页表基地址相差4K,这是由于一个页表基址指向的是1024个页表的基地址,而每个页表4个字节。

  PTE里页基址:依次为0000 0000,0000 01000......FFFF FFFF。总共1024*1024个,没两个页基址相差4K,这是由于一个页面占4K。这样就将4G的地址空间全都映射到了。

 

  分页的图示:

 

  书中还提到一句话 "切换任务时通过改变cr3的值来切换页目录,从而改变地址映射关系”,这应该是切换进程时要做的事吧。

转载于:https://www.cnblogs.com/szqxzh/p/4723343.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值