PSE页面大小扩展和PAE物理地址扩展
传统的IA32架构
IA32架构就是英特尔32位体系架构,从80386开始采用。32位的处理机,32位的地址总线,用两级页表去管理物理内存:
也就是说第一级是页目录,第二级是页表,通过页表中的记录去查找物理页框。顺序是这样的:
①首先,进程去查找CR3(3号控制寄存器,即PDBR 页目录基址寄存器),这里记录了这个进程对应的页目录首地址。
这里要注意一些事:
第一,进程寻址前会把自己的页目录首地址放进CR3里,对于早期的Linux而言,做法是不同的进程都使用一样的页目录首地址,即只有一张页目录。
第二,因为页目录的大小是4KB,为了方便管理,页目录表总是放在以4KB为单位的存储器边界上,所以CR3的后12位(2^12=4K)不起作用(都认为是0),只有前20位是有效的。另外对于刚刚说的早期Linux,做法是这张唯一的页目录就放在存储器的前4K位置。
②查找完CR3后,得到了后12位全0的32位页目录起始地址,这时候就找到本进程对应的页目录表了。
③页目录表一共4KB,里面每条记录都是32位地址即4B长的,所以一共有1K=1024条记录,每条记录对应着一个页表起始地址。因为每张页表也是4KB大小,所以页目录的每条记录只有高20位影响了页表起始地址,但这时后面的12位大多也是有作用的,而不能忽视掉。
其中低8位用作控制,为控制位。
④拿到页目录表后,里面有1024条记录,这时需要用线性地址(逻辑地址->物理地址转换时中间的页式地址)的高10位来选择这其中的一项。
⑤选择到这一项后,根据其前20位的值,后拼12个0即找到了32位的页表起始地址。
⑥每张页表一共4KB,里面每条记录都是32位地址即4B长的,所以一共有1K=1024条记录,每条记录对应着一个物理页面首地址,即页框的首地址。因为每张页表也是4KB大小,所以页目录的每条记录只有高20位影响了页表起始地址。
⑦拿到页表后,里面有1024条记录,这时需要用线性地址的中10位来选择这其中的一项。
⑧这时候用这条记录的前20位,拼上12位0,即是物理页框的首地址,页内寻址用线性地址的低12位。即这条记录的前20位拼上线性地址的低12位即是真实要找的物理地址。
图上的紫色箭头表示这个查表阶段要去看线性地址的哪一部分。还有这个系列的网上找的图,比较清楚:
一般PSE页面大小扩展
很多时候4KB的页不太够用,因为前面一张页目录上有1024条记录,对应1024张页表,每个页表4KB,比较直观的想法就是把这1024个4KB聚合到一起,直接使用页目录去寻物理页框首地址。
这时页目录表只用高10位,因为页框是4MB这么大的。
而线性地址中的后22位用来页内寻址。
注意:PSE需要奔腾以上的CPU,而且需要CR4(另外的控制寄存器)的第4位即PSE位为1,页目录项的第7位即PS位为1。下面是网上找的CR4的结构图:
PSE-36
因特尔处理器发展到奔腾PRO(i586开始叫奔腾,奔腾PRO是686级的CPU)时,为了能使用更大的物理内存,把ABUS从32位扩展到了36位,但处理机还是32位的,线性地址还是32位的,PSE-36是解决这个地址映射问题的一条途径。
传统的PSE只使用了10位高位页目录表记录,后面拼22位低位线性地址,寻址即32位。现在要36位,而页目录表还有很多位可以用呢,所以只要使用14位高位页目录表记录,后面拼22位低位线性地址就可以了。
PAE物理地址扩展
刚刚学到的PSE-36确实可以解决奔腾PRO的问题,但是这种方式太暴力了,页框始终是4MB大小的,这样页框太大会造成碎片浪费严重。PAE从另一个角度思考这个问题。
如果要用之前的4KB页框,也就是不使用PSE的情况,这时候页目录项和页表项都是前20位有效,剩下12位有8位是做控制的,还有1位必须是0(第8号位),即还剩下3位可分配,这20位加上这3位也就是物理页框首地址可以是这23位后面拼12个0,页内寻址时用线性地址后12位去替代这后12个0,也就是最多能寻23+12=35位还是差一位,自然的想法就是为了让物理页地址更长,也就是让页表记录的长度变长。
可以看到,页目录和页表都变成了每条记录64位,这样物理页面首地址就有更多的位可以分配了,如24位首地址+12位线性地址中的偏移量=36位地址。
这里要注意一些事:
第一,页目录表和页表仍然是4KB大小,所以宽度宽了1倍,表中记录数就减半成了512条。
第二,512条只需要9个二进制位,所以线性地址中用来索引页目录表和页表的部分都缩减成了9位,多出来了2位在线性地址最高2位,索引4条记录的页目录指针表,而CR3中存的也变成了这个表的首地址,现在看来是三级页表了!
第三,在PAE中的页目录项新拿出一位设置成了标志位,为最高位(63号位)NX位。
第四,页表项没有设置NX位,则理论上可以使用前64-12=52位,寻址空间非常大,这还是在没有考虑后面拼接低位线性地址的情况下。
PAE混用PSE
不仅把页目录表记录长度加倍成64位,而且如果其中第7位PS位为1,做PSE页面大小扩展,即不作下一层的页表,直接拿剩下的32-2-9=21位低线性地址做页内寻址。这是有意义的,因为之前4KB到4MB跳跃太大了,4MB可能是个过大的页框大小,这里21位页内地址则页框只是2MB!是比较折衷的一个大小。
查看Linux下是否支持PAE
在Linux内核编译时PAE是可选的,不过多数Linux都支持了PAE。我用学校机房的Ubuntu看了一下,先看看boot目录:
在这两个配置文件下都有,随便打开一个看下:
可以从开头的注释知道,是内核配置文件,往下翻找一下:
果然PAE是打开的。