浅谈PAE实现原理

32位系统通过物理地址扩展可以使用超过 4GiB 的物理内存,怎么做到的呢?

TL;DR
1、你以为的 32 位机器其实不一定真的是 32 位 有可能是 36 位的。
2、但是因为虚拟内存的存在,对于每个 userspace 进程而言,确实可以当成是跑在一台 32 位的机器上
3、所以对于使用虚拟内存的用户态进程来说 2^32 = 4GiB 的限制绕过了但没有完全绕过, 要访问超过 4GiB 的内存需要特殊的内核机制配合(swap)
4、可以简单理解为一台暴露的虚拟地址是 32 位的 36 位机器

众所周知一个32位进程的虚拟地址最多能表示 2^20 个页,用虚拟地址里剩下的 12bits 表示 4k 的偏移量。其能表示的内存大小上限为 2^20*2^12=2^32byte=4GiB

如实际物理内存恰好等于进程中能寻址的虚拟内存,即物理内存<=4Gib(2^32)。偏移 2^12(4k),需要 2^20 个页框表示。相应的页表项里用来寻址的部分(pfn)应该有20bits才能表示完对应到物理内存的 2^20 个页框,和32位虚拟地址空间里最多能表示的页个数相同,即虚拟内存刚好可映射到整个物理内存。

CPU 增加地址线超过32根的话在硬件层面上就能够寻址大于 4GiB 的内存了,比如拥有36条地址线的部分32位x86 cpu最大可以支持到 64GiB 的物理内存(其实这也是无法在其他32位平台上模拟运行使用了 PAE 的 ia32应用/OS 的原因,因为那些支持 PAE 的 x86 cpu 在硬件上扩展了地址线的数量为36/40/48,而其他32位平台可能真就只有32位的地址线,没法用32位的硬件来模拟寻址36位甚至更大的物理内存空间)。但现在要怎么把 OS 里的虚拟地址映射到更大的物理地址空间里去呢?


增加页表项里用来寻址部分的宽度怎么样?

假设我们现在有一根无限大的内存条

一个32位进程的虚拟地址空间里最多还是只能表示2^20个页表项(页),还是用剩下的 12bits 表示 4k 的页内偏移量,结果就是虚拟地址空间还是只有2^32这么大。映射的物理地址空间也还是只有2^32=4GiB

但是,因为页表项变长了,可以寻址的物理地址空间增加了(大于虚拟地址空间的4Gib)。或者换句话说,之所以要把页表项增长是为了让虚拟地址能映射到更大的物理地址空间里的任意位置而已。如页表项里用来寻址的部分从 20bits 增加到 40bits 的话,可寻址的物理内存空间就是2^40*2^12=2^52这么大了。但是一个32位的进程的虚拟地址空间里还是只有20位来表示页,所以最多只能映射到2^20个页那么大的物理地址空间。所以能表示的物理内存大小是一回事,单个进程的虚拟内存能映射的物理内存是另一回事了。在单个进程的虚拟内存里无法映射到整个物理内存(2^20小于2^40),但是通过特殊的内核机制多个进程的虚拟内存可以映射到物理内存里的不同部分。使用32位虚拟地址的用户态进程可以通过一些特殊的内核机制(比如win下调用AWE api)把额外的物理内存swap进自己的虚拟地址空间,用完了再swap出去,这里的swap是交换到物理内存里而不是硬盘上的页面文件里。但在同一时刻这个32位进程可见的内存大小还是只有4GiB。

点击右边的按钮加载评论,如果无法加载那估计是被墙啦..你看着办w