【问题标题】:How virtualized page table works虚拟化页表的工作原理
【发布时间】:2018-05-14 00:03:27
【问题描述】:

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

为了进一步澄清我的问题,我的困惑不是“为什么所有页表都不能在内存中”。相反,给定的基本原理是“防止循环页面错误”。似乎基本原理应该是“处理器必须有一些物理地址作为起点”,无论你怎么称呼它,它都是一个物理页表。这与“循环页面错误”有什么关系?似乎更加基础。

【问题讨论】:

  • 能否引用 Wikipedia 中的引语,并说明您指的是 Patterson & Hennessy 的哪个页面,以便我们更好地理解这个问题?
  • 我只听说过 VM 来宾/主机上下文中的虚拟化页表,其中有两个单独的转换步骤(从来宾虚拟到来宾物理,以及从主机虚拟到主机物理)。
  • 就像 Wikipedia 所说的那样,如果您想调出页表的某些部分,则至少需要顶级页面目录才能驻留在已知的物理地址中。但它的条目可能是物理地址(当存在下一级目录时),也可能是不存在的下一级表的某种虚拟或磁盘引用。

标签: cpu-architecture virtual-memory


【解决方案1】:

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

  • P0: 0x00000000 - 0x3fffffff。
  • P1:0x40000000 - 0x7fffffff。
  • S0: 0x80000000 - 0xbfffffff。
  • 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 的页表的物理地址。

所以本质上,一个进程的页表被划分为三个连续的页表,其中两个是虚拟化的,一个始终驻留在内存中。来自Wikipedia

有人提到创建一个页表结构,其中包含 虚拟地址空间中每个虚拟页面的映射可能会结束 浪费。但是,我们可以绕过过多的空间问题 通过将页表放在虚拟内存中,并让虚拟 内存系统管理页表的内存。

但是,这种线性页表结构的一部分必须始终保持不变 常驻物理内存,防止循环页面 查找页表中不存在的关键部分的错误 在页表中,在页表中不存在,等等。

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)。通过这种方式,即使是进程也可以获得线性页表的潜在性能优势,同时如果操作系统内存管理器需要,仍然允许虚拟化。不过,我不知道有任何架构使用过这种设计。

【讨论】:

  • 你的回答很有道理。我的困惑并不完全是“为什么所有页表都不能在内存中”。相反,给定的基本原理 是“防止循环页面错误”。似乎基本原理应该是“处理器必须有一些物理地址作为起点”,无论你怎么称呼它,它都是一个物理页表。这与“循环页面错误”有什么关系?似乎更基本。谢谢!
  • @allstar 维基百科关于虚拟化页表的部分写于 2004 年,此后再也没有更新过。我不知道如何联系写那部分的人。但我认为这个人将虚拟化页表与多级页表混淆了。具体来说,想象一个处理器,其寄存器跟踪基本虚拟地址、基本物理地址和页表的当前位。如果当前位为零,则发生缺页,但要调用缺页处理程序,必须将其虚拟地址转换为物理地址...
  • ...但是要做到这一点,需要访问页表,这再次导致页面错误,等等。这就是那个人的意思。但这是多级页表设计,不是虚拟化页表。
【解决方案2】:

re:您的更新:这是陈述相同要求的两种不同方式。

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

这是您会遇到的“循环”问题,以及为什么在某处必须有一个物理地址,否则这是一种 catch-22 / turtles all the way down 类型的情况。

【讨论】:

    【解决方案3】:

    但在我看来,还有一个更基本的问题——首先如何找到页表?

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

    【讨论】:

      猜你喜欢
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 1970-01-01
      • 2017-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多