线性地址 space x86 - 位分段计算

linear address space x86 - bits segmentation calculation

我有一个问题,根据我得到的最终答案,我不确定如何正确解决。 鉴于:

  1. 页面大小为 4KB (2^12)。
  2. 虚拟地址space为32位
  3. 物理内存大小为 16TB (2^44B)。
  4. PTE 仅存储 PFN。
  5. 内页表大小为一页。

我需要计算32位的位分割。 最终答案(没有解释)是DIR 10位,Inner Table 10位,offset 12位。 我确实了解 12 个偏移量的位从何而来 (log2(#Page)),但后来我被其他 20 位卡住了,我不知道如何拆分。 提前致谢:)

看来这实际上与 x86 页面 table 无关。其他东西的大小恰好与旧版 x86(非 PAE)相同,但它们采用不同的 PTE 格式。

如果我们采用 PTE 仅存储 PFN 表示没有实际 x86 具有的 present/dirty/permissions/等位,那么给出的答案是有道理的,所以字面意思是每一位每个 PTE 都是 PFN 的一部分。因此,对于其中 12 位在页内偏移的 44 位物理地址,PTE 需要保存 44 - 12 = 32-bit 页框(物理页)编号。这为您提供了 4 字节的 PTE,大小与传统 x86(非 PAE,非 x86-64)相同。

但是在真正的 x86 中,PTE 的低 12 位是标志,所以不需要移位,只需要 mask/or 来将物理地址拆分或合并到 PTE 的 PFN 字段和偏移量-页内(不需要翻译的低 12 位)。 https://wiki.osdev.org/Paging#MMU 有 page-directory 和 page-table 条目的格式图,两者基本相同。由于高 20 位是 PFN,传统的 x86 分页将 32 位虚拟地址转换为 32 位物理地址。

给定 4 字节 PTE 和其他与实际 x86 相同的所有内容(物理地址大小除外),您最终得到与实际 x86 相同的几何结构:每页 1024 个 PTE,因此 10 位页面的每个级别 table。 10 + 10 + 12 = 32 所以这处理 32 位虚拟地址。

内页 table 大小为一页。 告诉您 PTE 以 4096 字节、1024 个 PTE 的连续组出现。如果不是这样,选择将是任意的,你 可以 有一个 3 级设计,如 6 位(顶层)、10 位(中层)、4 位(底层) ).但是为了有效地打包东西,OS 的分配器必须管理更小的内存单元。


相比之下,PAE 和 x86-64 page-table 格式具有 8 字节的 PTE,允许更宽的物理地址,同时仍有必要的 flag/metadata 位空间,仍在低 12 位. 对于 x86-64,这意味着 4 个级别,每个级别转换 9 位 => 4x9 + 12 = 48 位虚拟。


这对于实际使用来说当然是完全不切实际的,你不会想到这么愚蠢/不切实际的设计也就不足为奇了。

每组页面 table 都需要“完整”(填充所有 1024 个二级 table),因为 PTE 无法指示它不存在。 (或者在页面的第一层 table,PTE 中不存在整个 4MiB)。所以你永远不会有 #PF 异常,从而破坏了虚拟化内存的多个主要好处。

任何您没有分配 space 的内存区域都可以映射到某处的同一物理页面,因此您实际上不需要每个进程 4GiB 的物理内存。 (甚至可以共享这些地区的二级页面 table)。但是越界访问的影响是读取/写入来自其他进程的任何垃圾,而不是通过段错误实际检测软件错误。

您可以使用段限制来切断对虚拟地址 space 某些部分的使用,可能至少允许保护内核免受用户 space 的影响。或许还可以做更多,但 IDK 关于用#SS 和#GP 异常真正替换#PF 异常,除非这个假设的机器有一种机制将故障地址传达给异常处理程序。 (就像实际 x86 中 #PF 的 CR2,为内核提供寻址模式 + 段基试图访问但未在页面 tables 中找到并允许的最终线性虚拟地址。)