64位Linux内核如何在兼容模式下管理32位应用程序的页表?

64位Linux内核如何在兼容模式下管理32位应用程序的页表?

目前我正在读《Understanding the Linux Kernel》一书。其中有如下说法:

对于没有物理地址扩展的 32 位体系结构,两个分页级别就足够了。 Linux 本质上消除了页上目录和页中目录字段,因为它们包含零位。然而,页面上层目录和页面中间目录在指针序列中的位置被保留,以便相同的代码可以在32位和64位体系结构上工作。内核通过将页面上层目录和页面中间目录中的条目数设置为1并将这两个条目映射到页面全局目录的正确条目来保留页面上层目录和页面中间目录的位置。

因此,具有 4 级分页的 64 位 Linux 内核的页表层次结构如下所示:

PML4 (Linux: PGD) -> 512 * PDPT (Linux: PUD) -> 512 * PD (Linux: PMD) -> 512 * PT

因此,在文本中据说两个级别就足够了(就像在正常的 32 位分页中一样),这就是为什么 PUD 和 PMD 被“消除”,但这两个表中的任何一个的长度为 1 并保存在序列的正确顺序。
根据我的理解,这意味着 PML4 (PGD) 对应于 PD (PMD),并且由指向 PT 的直接指针组成。因此PUD和PMD被“跳过”。但这似乎并不正确,因为在模式切换到内核模式后,必须使用 64 位页表来完成分页才能访问内核页面。此外,此映射方案不允许映射 4GB 边界以上的内存(例如内核页面)。
另一种解释可能是 32 位地址零扩展为 64 位,并且对于层次结构中的前两个表,使用第一个条目。然后,您可以使用剩余的位来选择剩余两个表中的条目以及页框内的偏移量。但这似乎也不正确,因为每个表中条目的位数在 32 位和 64 位模式下是不同的。所以这也会带来麻烦。
这就是为什么一定有一些我没有考虑到的事情。我希望有一个人可以澄清事情。

答案1

首先,不可能像那样在 64 位系统上运行 32 位可执行文件。所以你不需要将 32 位地址转换为 64 位地址或类似的东西。

其次,32 位(无 PAE)根本不允许映射 4 GB 边界以上的内存。

我对这个问题思考了很多,并通过多次阅读该部分,我找到了答案。您可能在 StackOverflow 上看到过类似的问题:Linux 内核内存管理分页级别

但我尝试解释一下我是如何理解的。我试图解释的是四级分页如何在 32 位系统上工作。

第一句话很重要

[...]通过说页上目录和页中目录字段包含零位来消除它们。

这并不意味着内核这些字段为零,但它说这些字段为零,但没有在某处表达这一点。因此,您可以使用通常的 32 位地址分隔来进行两级分页。

这意味着您使用 PML4 虚拟地址的 10 个最高有效位(Linux:PGD)。

PML4(Linux:PGD)指向只有一个条目的PDPT(Linux:PUD)。因为内核说索引/偏移量为零,所以只采用这个条目。

PDPT (Linux: PUD) 的唯一条目指向 PD (Linux: PMD),而 PD (Linux: PMD) 也只有一个条目。内核再次指出,索引/偏移量为零,因此仅采用该条目。

最后,PD(Linux:PMD)的唯一条目指向PT,其中虚拟地址的中间10位用作索引来查找想要的页面。

简而言之:

[1024 *] PML4 (Linux: PGD) -> 1 * PDPT (Linux: PUD) -> 1 * PD (Linux: PMD) -> 1024 * PT

相关内容