ASM:32位管理器的页管理

  CPU的页式内存管理单元,负责把一个线性地址,最终翻译为一个物理地址。从管理和效率的角度出发,线性地址被分为以固定长度为单位的组,称为页(page),例如一个32位的机器,线性地址最大可为4G,可以用4KB为一个页来划分,这页,整个线性地址就被划分为一个 tatol_page[2^20]的大数组,共有2的20个次方个页。这个大数组我们称之为页目录。目录中的每一个目录项,就是一个地址——对应的页的地址。

  另一类“页”,我们称之为物理页,或者是页框、页桢的。是分页单元把所有的物理内存也划分为固定长度的管理单位,它的长度一般与内存页是一一对应的。这里注意到,这个total_page数组有2^20个成员,每个成员是一个地址(32位机,一个地址也就是4字节),那么要单单要表示这么一个数组,就要占去4MB的内存空间。为了节省空间,引入了一个二级管理模式的机器来组织分页单元。文字描述太累,看图直观一些: 
在此输入图片描述

1、分页单元中,页目录是唯一的,它的地址放在CPU的CR3寄存器中,是进行地址转换的开始点。

2、每一个活动的进程,因为都有其独立的对应的虚似内存(页目录也是唯一的),那么它也对应了一个独立的页目录地址。——运行一个进程,需要将它的页目录地址放到cr3寄存器中,将别个的保存下来。

3、每一个32位的线性地址被划分为三部份,面目录索引(10位):页表索引(10位):偏移(12位)

依据以下步骤进行转换:

①、从cr3中取出进程的页目录地址(操作系统负责在调度进程的时候,把这个地址装入对应寄存器);

②、根据线性地址前十位,在数组中找到对应的索引项,因为引入了二级管理模式,页目录中的项,不再是页的地址,而是一个页表的地址。(又引入了一个数组),页的地址被放到页表中。

③、根据线性地址的中间十位,在页表(也是数组)中找到页的起始地址;

④、将页的起始地址与线性地址中最后12位相加,得到最终我们想要的页;

    这个转换过程,应该说还是非常简单地。全部由硬件完成,虽然多了一道手续,但是节约了大量的内存:

1、验证这样的二级模式是否仍能够表示4G的地址;页目录共有:210项,也就是说有这么多个页表.每个目表对应了:210页;每个页中可寻址:212个字节。还是232 = 4GB。

2、也能证这样的二级模式是否真的节约了空间;也就是算一下页目录项和页表项共占空间(2^10 4 + 2 ^10 4) = 8KB。

  如果一级页表中的一个页表条目为空,那么那所指的二级页表就根本不会存在。这表现出一种巨大的潜在节约,因为对于一个典型的程序,4GB虚拟地址空间的大部份都会是未分配的;只有一级页表才需要总是在主存中。虚拟存储器系统可以在需要时创建,并页面调入或调出二级页表,这就减少了主存的压力只有最经常使用的二级页表才需要缓存在主存中。——不过Linux并没有完全享受这种福利,它的页表目录和已分配页面相关的页表都是常驻内存的。值得一提的是,虽然页目录和页表中的项,都是4个字节,32位,但是它们都只用高20位,低12位屏蔽为0——把页表的低12屏蔽为0,是很好理解的,因为这样,它刚好和一个页面大小对应起来,大家都成整数增加。计算起来就方便多了。

  i386是二级页管理架构,更高级的CPU,还有三级,甚至四级架构,Linux为了在更高层次提供抽像,为每个CPU提供统一的界面。提供了一个四层页管理架构,来兼容这些二级、三级、四级管理架构的CPU。这四级分别为:

页全局目录PGD(对应刚才的页目录)

页上级目录PUD(新引进的)

页中间目录PMD(也就新引进的)

页表PT(对应刚才的页表)。

  整个转换依据硬件转换原理,只是多了二次数组的索引罢了。
在此输入图片描述

       那么,对于使用二级管理架构32位的硬件,现在又是四级转换了,它们怎么能够协调地工作起来呢?嗯,来看这种情况下,怎么来划分线性地址吧!从硬件的角度,32位地址被分成了三部份——也就是说,不管理软件怎么做,最终落实到硬件,也只认识这三位老大。

  从软件的角度,由于多引入了两部份,也就是说,共有五部份。——要让二层架构的硬件认识五部份也很容易,在地址划分的时候,将页上级目录和页 中间目录的长度设置为0就可以了。这样,操作系统见到的是五部份,硬件还是按它死板的三部份划分,也不会出错。

  这样,虽说是多此一举,但是考虑到64位地址,使用四层转换架构的CPU,我们就不再把中间两个设为0了,这样,软件与硬件再次和谐——抽象就是强大呀!!!

  例如,一个逻辑地址已经被转换成了线性地址,0x08147258,换成二制进,也就是:

  0000100000 0101000111 001001011000
  内核对这个地址进行划分,

  PGD = 0000100000 
  PUD = 0 
  PMD = 0 
  PT = 0101000111 
       offset = 001001011000
       现在来理解Linux针对硬件的花招,因为硬件根本看不到所谓PUD,PMD。所以,本质上要求PGD索引,直接就对应了PT的地址。而不是再到PUD和PMD中去查数组(虽然它们两个在线性地址中,长度为0,2^0 =1,也就是说,它们都是有一个数组元素的数组),那么,内核如何合理安排地址呢?
  从软件的角度上来讲,因为它的项只有一个,32位,刚好可以存放与PGD中长度一样的地址指针。那么所谓先到PUD,到PMD中做映射转换, 就变成了保持原值不变,这样,就实现了“逻辑上指向一个PUD,再指向一个PDM,但在物理上是直接指向相应的PT的这个抽象,因为硬件根本不知道有PUD、PMD这个东西”。然后交给硬件,硬件对这个地址进行划分,看到的是:

  页目录 = 0000100000

  PT = 0101000111

  offset = 001001011000

    嗯,先根据0000100000(32),在页目录数组中索引,找到其元素中的地址,取其高20位,找到页表的地址,页表的地址是由内核动态分配的,接着再加一个offset,就是最终的物理地址了。

  参考http://my.oschina.net/yang1992/blog/214425?p={{page}}

 

 

 

posted @ 2016-02-22 17:43  PhiliAI  阅读(163)  评论(0)    收藏  举报