The VAX https://en.wikipedia.org/wiki/VAX70年代的架构使用虚拟化线性页表方法来实现分页。 VAX 将 32 位虚拟地址空间划分为四个范围:
- P0:0x00000000 - 0x3fffffff。
- P1:0x40000000 - 0x7fffffff。
- S0:0x80000000 - 0xbffffffff。
- S1:0xc0000000 - 0xffffffff。
P0(称为程序区域)和P1(称为控制区域)是用户特定的分区,S0是系统(内核)分区,S1是保留的。因此,每个进程都有自己的一组 P0 和 P1 映射,但所有进程和内核共享相同的 S0 映射。
请注意,虚拟地址的最高两个有效位用于确定要访问虚拟内存的哪一部分。每个节(S1 除外,它不可用)都由页表定义。具体来说,P0和P1是由虚拟化页表定义的(页表映射到虚拟内存),但S0的页表没有虚拟化。每个页表都是 4 字节页表条目的连续数组。每个页表条目要么无效,要么有效(这意味着它包含 512 字节页的物理地址)。
VAX提供了6个寄存器来定义页表:一个页表基地址寄存器和一个页表长度寄存器,分别用于虚拟地址空间P0、P1和S0的三个部分。 P0和P1的基地址寄存器包含虚拟地址,其最高两位为10。也就是说,S0的页表包含包含P0和P1的物理地址的页表条目。这使得任何进程的P0和P1的页表都可以驻留在主存或辅助存储器中。另一方面,S0的基地址寄存器包含S0的页表的物理地址。
所以本质上,一个进程的页表被划分为三个连续的页表,其中两个是虚拟化的,一个永远驻留在内存中。从维基百科 https://en.wikipedia.org/wiki/Page_table#Virtualized_page_table:
有人提到创建一个包含以下内容的页表结构
虚拟地址空间中每个虚拟页的映射可能会结束
起来很浪费。但是,我们可以解决过多的空间问题
通过将页表放入虚拟内存中,并让虚拟内存
内存系统管理内存的页表。
然而,该线性页表结构的一部分必须始终保留
驻留在物理内存中,以防止循环页
错误,寻找页表中不存在的关键部分
在页表中,不存在于页表中,等等。
S0 的页表是线性页表的一部分,必须始终驻留在内存中(即,未虚拟化)。但为什么一定要这样呢?如果 S0 的基地址寄存器包含虚拟地址而不是页表的物理地址,会发生什么情况?但那样的话,处理器如何计算出页表的物理基地址呢?我们需要一些具有已知物理地址的附加数据结构,使我们能够找出页表的物理地址。为了便于论证,我们假设我们有一个存储在某处的数据结构。页表是否可以完全换出到辅助存储?是的,如果我们在该数据结构中有“当前位”或“有效位”之类的东西,我们就可以做到这一点。然而,当前位被设置为假,当访问任意虚拟地址的内存时会发生页面错误。操作系统现在需要处理页面错误,如果需要访问任何虚拟地址,它将再次出现页面错误,依此类推。
否则,一般来说,如果页错误处理程序被设计为仅使用指向始终存在的数据和代码的物理地址(通过关闭分页),那么您可以有效地绕过虚拟化整个页表。但这会使处理程序的设计变得相当复杂。
将页表划分为多个连续数组(就像在 VAX 中所做的那样)意味着页表的某些部分(S0)必须始终存在。
但是如果S0的页表包含查找P0和P1的页表的条目,那么这不也是一个有效的多级页表吗?为了回答这个问题,我们来比较一下 VAX 和 32 位 x86 中的地址转换是如何完成的。
在VAX翻译中,虚拟页号与页表索引相同。
|31|29 9|8 0|
------------------------------------
| | virtual page number | offset |
------------------------------------
| | page table index | offset |
------------------------------------
在 32 位 x86 转换中(禁用 PAE 和 PSE),虚拟页号被划分为两级页表的两个索引。
|31 12|11 0|
------------------------------------
| virtual page number | offset |
------------------------------------
| PT 1 index|PT 2 index| offset |
------------------------------------
在VAX中,只有对用户页表的访问才需要两级查找。更重要的是,这两次查找是使用两个不同的虚拟地址执行的。另一方面,对系统页表的访问仅需要使用单个虚拟地址的单个查找。相比之下,在 x86 中,所有访问都需要使用相同虚拟地址进行两级查找。
x86架构支持虚拟化多级页表。
我们可以设计一个可能比两者都更强大的混合页表。如果我们使用S1分区作为第三个用户分区。我们可以为其表添加一个基地址寄存器,其中包含物理地址而不是虚拟地址(如 P0 和 P1)。通过这种方式,即使是进程也可以获得线性页表的潜在性能优势,同时如果操作系统内存管理器需要,仍然允许虚拟化。但我不知道有任何架构使用过这种设计。