虚拟化页面 table 的工作原理

How virtualized page table works

阅读有关虚拟化页面 table 的概念,其中部分页面 table 被放入虚拟内存中。 Wikipedia 以及 Patterson & Hennessy(页面错误部分中的 5.7 详细说明)说您不将 entire 页面 table 放入虚拟内存的原因是它会导致循环页面错误。但在我看来,还有一个更基本的问题——首先如何找到页面 table?似乎您必须 一些 记录物理内存中的位置才能通过定位页面 table.

开始翻译过程

为了进一步澄清我的问题,我的困惑不是 "why can't all the page tables be in memory"。相反,给出的理由 是 "prevent against circular page faults"。似乎更根本的理由应该是 "the processor must have some physical address as a starting point",不管你怎么称呼它,它都是一个物理页面 table。这和"circular page faults"有什么关系?看起来更基本。

But it seems to me like there's an even more basic issue - how you would find the page table in the first place?

这是一个问题,处理器采用不同的方法。一种方法是为系统 space 和用户 space 使用单独的页表。系统space 页表指定了物理地址。用户 space 表指定逻辑地址。因此,访问用户 space 表需要通过系统 space 表进行逻辑到物理的转换。

70 年代的 VAX 架构使用虚拟化线性页面 table 方法来实现分页。 VAX将32位虚拟地址space划分为四个范围:

  • P0:0x00000000 - 0x3fffffff。
  • P1:0x40000000 - 0x7fffffff。
  • S0:0x80000000 - 0xbfffffff。
  • S1:0xc0000000 - 0xffffffff。

P0(称为程序区)和P1(称为控制区)为用户专用分区,S0为系统(内核)分区,S1为保留分区。所以每个进程都有自己的一组 P0 和 P1 映射,但是所有进程和内核共享相同的 S0 映射。

请注意,虚拟地址的最高两位有效位用于确定访问虚拟内存的哪一部分。每个部分(S1 除外,它不可用)由页面 table 定义。特别地,P0和P1定义了一个虚拟化的pagetable(pagetable映射到虚拟内存),但是S0的pagetable没有被虚拟化。每页 table 都是 4 字节页 table 条目的连续数组。每个页面 table 条目要么无效要么有效(这意味着它包含 512 字节页面的物理地址)。

VAX提供了6个寄存器来定义页tables:页table基地址寄存器和页table长度寄存器分别用于虚拟地址的三段space P0、P1 和 S0。 P0和P1的基地址寄存器包含两个最高有效位为10的虚拟地址。也就是说,S0的table页包含包含P0和P1物理地址的table页条目。这样就可以让任意进程的P0和P1的pagetables驻留在主存或者副存中。另一方面,S0的基地址寄存器包含S0页的物理地址table.

所以本质上,一个进程的页table被分成三个连续的页table,其中两个是虚拟的,一个常驻内存。来自 Wikipedia:

It was mentioned that creating a page table structure that contained mappings for every virtual page in the virtual address space could end up being wasteful. But, we can get around the excessive space concerns by putting the page table in virtual memory, and letting the virtual memory system manage the memory for the page table.

However, part of this linear page table structure must always stay resident in physical memory, in order to prevent against circular page faults, that look for a key part of the page table that is not present in the page table, which is not present in the page table, etc.

S0 的页面 table 是线性页面 table 的一部分,必须始终驻留在内存中(即未虚拟化)。但为什么一定要那样呢?如果 S0 的基地址寄存器包含一个虚拟地址而不是页的物理地址 table 会怎样?但是那样的话,处理器怎么才能算出页面table的物理基址呢?我们需要一些具有已知物理地址的额外数据结构,使我们能够计算出页面 table 的物理地址。为了便于讨论,让我们假设我们有这样一个存储在某处的数据结构。页面 table 是否可以完全换出到辅助存储?是的,如果我们在该数据结构中有类似 "present bit" 或 "valid bit" 的东西,我们就可以做到这一点。但是,当前位被设置为假,在访问任何虚拟地址的内存时都会发生页面错误。 OS 现在需要处理页面错误,如果它需要访问任何虚拟地址,它将再次出现页面错误,依此类推。

否则,一般来说,如果页面错误处理程序设计为仅使用指向始终存在的数据和代码的物理地址(通过关闭分页),那么您可以有效地绕过虚拟化整个页面table。但这会使处理程序的设计相当复杂。

将页面 table 划分为多个连续数组,就像它在 VAX 中的做法一样,这意味着页面 table (S0's) 的某些部分必须始终存在。


但是如果S0的页面table包含查找P0和P1的页面table的条目,那么这不也是一个多级页面table有效吗?为了回答这个问题,让我们比较一下地址转换在 VAX 和 32 位 x86 中是如何完成的。

在VAX翻译中,虚拟页码与页table索引相同。

|31|29                  9|8       0|
------------------------------------
|  | virtual page number | offset  |
------------------------------------
|  |  page table index   | offset  |
------------------------------------

在 32 位 x86 转换中(禁用 PAE 和 PSE),虚拟页号被划分为二级页的两个索引 table。

|31                  12|11        0|
------------------------------------
|  virtual page number |  offset   |
------------------------------------
| PT 1 index|PT 2 index|  offset   |
------------------------------------

在 VAX 中,只有访问用户页面 tables 需要两级查找。更重要的是,两次查找是使用两个不同的虚拟地址执行的。另一方面,访问系统页面 table 只需要使用单个虚拟地址进行一次查找。相比之下,在 x86 中,所有访问都需要使用相同的虚拟地址进行两级查找。

x86架构支持虚拟化多级页面tables.

我们可以设计一个混合页面 table,它可能比两者都更强大。如果我们使用S1分区作为第三个用户分区。我们可以为其 table 添加一个基地址寄存器,其中包含物理地址而不是虚拟地址(如 P0 和 P1)。通过这种方式,即使进程可以获得线性页面 table 的潜在性能优势,同时如果 OS 内存管理器需要,仍然允许虚拟化。不过,我不知道有任何架构使用过这种设计。

回复:您的更新:这是陈述同一要求的两种不同方式。

这是一个归谬法论点:考虑一个CPU,其中page-table指针都是虚拟地址:TLB-miss或page -故障处理程序需要处理另一个页面错误或 TLB 未命中,因为它没有可以直接使用的物理地址。

这是您 运行 遇到的 "circular" 问题,以及为什么某处必须有一个物理地址,否则它就是 catch-22 / turtles all the way down 类型的情况.