Intel处理器从80386到Pentium使用32位物理地址,理论上,这样可以访问4GB的RAM。然而,大型服务器需要大于4GB的RAM来同时运行数以千计的进程,所以必须扩展32位80x86所支持的RAM容量。(这里是不是了解了为啥叫x86啊,这个x代表1个数字,最小为3,表示早期的386系列CPU以及之后的系列,只不过最新的系列不再按照x86命名了)

       从pentium pro 处理器开始,intel引入一种叫做 PAE 的机制,Linux 中使用了这种机制。Intel通过在它的处理器上把管脚数从32增加到36已经满足了这些需求,可以寻址64GB。同时引入了一种新的分页机制PAE(Physical Address Extension,物理地址扩展),它把32位线性地址转换为36位物理地址才能使用所增加的物理内存,通过设置CR4的第5位来开启对PAE的支持。引入PAE就是为了访问大于4GB的RAM,线性地址仍然是32位,而物理地址是36位。也就是线性地址空间仍为4GB,每个进程可支配4G虚拟内存空间。只不过原来的情况下,所有进程使用共同使用者剩下的3G物理内存,当进程多了的时候,内存压力会很大,那么为了减少这3G物理内存的冲突,扩展了可用的内存空间,这样冲突的概率就下降了。

       64GB的RAM被分为2^24个页框,页表项的物理地址字段从20位扩展到了24位。PAE表项必须包含12个标志位和24个物理地址位,总数之和为36,页表项大小从32位变为64位(因为36不能被4096整除,所以只能用64了)。这样原来一个页框有1024个entry,现在有512个entry。开启PAE的80x86 32位使用的是三级页表,第一级是新引入的PDPT(页目录指针表,相当于PGD了),第二级是PMD,第三级是PTE。PDPT只有4个entry,每个对应1GB RAM,每个entry 是64位。CR3中有27位作为PDPT的起始地址。为什么这么设计呢?

这是因为在4K的page设置的情况下,每个page只能存512个entry(无论是目录表项,还是页表项),表示0-511这个范围,需要9位bit位,这占用了32位线性地址中的9位,同理,由于页目录项与页表项具有同样的结构,高一级的页目录表中也仅能包含512个页表项(目录项),同样占用了32位线性地址中的9位,此时,线性地址剩余位数为:32位(总位数)-12位(页内偏移量)-9位(指示页表中的索引)-9位(指示页目录表中的索引)=2位,同时,Linux引入了一个页目录指针表(PDPT)的页表新级别,由4个64位表项构成,剩余的2位即用来指向PDPT中4个项中的一个(这就是PDPT为啥只有4个entry的原因,因为只有2位可用啦)。

未启用PAE下的4K分页的页表结构

【未启用PAE下的4M分页的页表结构】

开启PAE后,用27位来存储page directory pointer table的起始地址。

下边分两种情况来讨论,一个是PS=0,一个是PS=1:

当CR4的第5位被置位(开启PAE),第4位被置位(开启PSE)

启用PAE下2M分页的页表结构

  • 线性地址31~30,用来指向一个PDPT的entry
  • 线性地址29~21,用来指向一个pmd的entry
  • 线性地址20~0,为4MB大页中的offset

当CR4的第5位被置位(开启PAE),第4位被清除(关闭PSE)

启用PAE下4K分页的页表结构

  • 线性地址31~30,用来指向一个PDPT的entry
  • 线性地址29~21,用来指向一个pmd的entry
  • 线性地址20~12,用来指向一个pte
  • 线性地址11~0,为4KB页中的offset

如何访问64GB?

从上边的三级分页可以看到2^2*2^9*2^9*2^11=4GB,仍然访问的是4GB。访问64GB方法如下:

  • 修改CR3中的值使其指向不同的PDPT,这样就指向不同的4GB
  • 修改PDP entry中的值,使其指向不同的PMD表,这样可以指向不同的1GB

但是实际上是不能访问这么大的内存的,实际可用的内存被限制在16GB,因为如果有64GB,那么每个struct page结构需要32字节,总共512MB,这样ZONE_NORMAL的内核地址空间就被大量占用,这样是不允许的

参考文献:

https://blog.csdn.net/geekdonie/article/details/15494503

https://blog.csdn.net/hsly_support/article/details/7463569

Logo

更多推荐