3. 页表层级与多级页表:多级页表设计动机、x86四级页表(PML4/PDPT/PD/PT)、ARMv8-A页表层级

3.1 多级页表的设计动机

在早期32位系统中,线性地址空间为4 GiB,若采用单级页表(即一个巨大的页表数组),每个进程需要维护一个包含约1M个页表项(假设4 KiB页面)的连续物理页表。这种设计存在三个致命缺陷:

  • 连续物理内存浪费:单级页表需要占用连续的物理内存(约4 MiB),即使进程只使用很少的虚拟地址。
  • 进程切换开销巨大:每次切换进程都需要刷新整个TLB,且页表本身占用大量内存带宽。
  • 稀疏地址空间支持差:对于64位地址空间,单级页表的大小将膨胀到无法接受的程度(例如48位地址空间需要约512 GiB的页表)。

多级页表通过按需分配和层级索引解决了上述问题。核心思想是将线性地址拆分为多个索引字段,每一级索引指向下一级页表的物理基址,只有实际映射的虚拟地址范围才会分配对应的页表页。

关键指标对比: 对于4 KiB页面,单级页表需要连续4 MiB物理内存;四级页表(x86-64)在最坏情况下需要约512 KiB页表页,且仅当所有层级都被使用时才分配,实际平均开销远低于单级。
设计动机总结: 多级页表以时间(多次内存访问)换取空间(按需分配页表页),并通过TLB缓存缓解性能损失。
单级页表 vs 多级页表 空间分配对比 单级页表(连续分配) 页表数组(连续4 MiB) 必须占用连续物理内存 即使进程只使用少量地址 ❌ 浪费严重 多级页表(按需分配) PML4(1页) PDPT(按需) PDPT(按需) PD(按需) PD(按需) PD(按需) ✅ 仅分配实际使用的页表页 ✅ 支持稀疏地址空间

3.2 x86四级页表(PML4/PDPT/PD/PT)

x86-64架构采用四级页表结构,支持48位虚拟地址空间(256 TiB)。线性地址被拆分为5个字段:

字段 位宽 索引级数 页表级别 每级页表项数
PML4索引 9 bit 第1级 PML4(Page Map Level 4) 512
PDPT索引 9 bit 第2级 PDPT(Page Directory Pointer Table) 512
PD索引 9 bit 第3级 PD(Page Directory) 512
PT索引 9 bit 第4级 PT(Page Table) 512
页内偏移 12 bit — — —

地址转换过程:CR3寄存器保存PML4页表的物理基址。CPU从线性地址中提取PML4索引,在PML4表中找到PDPT页的物理地址;再提取PDPT索引,找到PD页的物理地址;依次类推,最后PT索引给出物理页框号(PFN),加上页内偏移得到最终物理地址。

安全要点: 每一级页表项都包含独立的权限位(R/W、U/S、NX等)。操作系统可以在不同层级设置不同的访问权限,实现细粒度的内存保护。例如,在PDPT级别设置不可执行(NX)可以阻止整个2 MiB区域的代码执行。
x86-64 四级页表地址转换流程 线性地址(48位) PML4索引 (9 bit) PDPT索引 (9 bit) PD索引 (9 bit) PT索引 (9 bit) 页内偏移 (12 bit) PML4表 PDPT表 PD表 PT表 物理页框 关键说明 • CR3寄存器指向当前进程的PML4表物理基址。 • 每一级页表项(PTE)包含下一级页表的物理地址和权限位。 • 支持2 MiB(大页)和1 GiB(巨大页)映射,跳过中间层级。 • 页表项中的P位(Present)为0时触发缺页异常(Page Fault)。

3.3 ARMv8-A页表层级

ARMv8-A架构支持多种页表层级配置,通常使用4级页表(与x86-64类似),但具有更灵活的粒度选择。ARMv8-A的页表层级称为Translation Table,从L0到L3:

层级 名称 粒度 描述
L0 Table Level 0 — 顶级页表,覆盖整个地址空间(通常只有1个条目指向L1)
L1 Table Level 1 1 GiB块 支持1 GiB大页映射,或指向L2页表
L2 Table Level 2 2 MiB块 支持2 MiB大页映射,或指向L3页表
L3 Table Level 3 4 KiB页 最终页表,提供4 KiB页面映射

ARMv8-A与x86-64的关键差异:

  • 页表项格式不同:ARM使用Descriptor格式,包含类型(Table/Block/Page)、权限(AP[2:1])、属性(AttrIndx)等字段。
  • 权限模型:ARM使用AP(Access Permission)位和PXN(Privileged Execute Never)/UXN(User Execute Never)位实现权限控制。
  • 地址空间标识符(ASID):ARM支持ASID,允许不同进程的TLB条目共存,减少TLB刷新开销。
  • 转换粒度:ARM支持4 KiB、16 KiB、64 KiB页面粒度(通过TCR寄存器配置)。
安全特性对比: ARMv8-A的PXN/UXN位提供了与x86 NX位类似的功能,但更细粒度——PXN禁止特权级执行,UXN禁止用户级执行。此外,ARM的Stage 2页表(虚拟化扩展)为虚拟机监控器提供了额外的内存隔离层。
ARMv8-A 页表层级结构(4级) L0 Table L1 Table L2 Table L3 Table ARMv8-A 页表映射类型 L1 Block (1 GiB) L2 Block (2 MiB) L3 Page (4 KiB) • L1 Block:跳过L2和L3,直接映射1 GiB连续内存,适用于大内存区域(如显存)。 • L2 Block:跳过L3,映射2 MiB连续内存,适用于内核代码段或大块数据。 • L3 Page:标准4 KiB页面,提供最细粒度的权限控制和按需分配。

3.4 多级页表的性能与安全权衡

多级页表虽然节省了物理内存,但引入了额外的内存访问开销。每次地址转换需要多次访问物理内存(4级页表需要4次内存读取)。TLB(Translation Lookaside Buffer)通过缓存最近使用的页表项来缓解这一开销。

因素 影响 缓解措施
页表层级深度 每增加一级,转换增加一次内存访问 使用大页(2 MiB / 1 GiB)减少层级
TLB命中率 TLB未命中导致完整页表遍历 增大TLB容量、使用大页、ASID减少刷新
页表项权限检查 每级PTE都需检查权限,增加延迟 硬件并行检查、权限缓存
进程切换 CR3/TTBR0切换导致TLB失效 ASID(ARM)/ PCID(x86)避免全局刷新
安全实践建议: 在多级页表中,建议在较高层级(如L1/L2)设置严格的权限位(如只读、不可执行),以提供“纵深防御”。即使低层级页表被篡改,高层级的权限限制仍能阻止恶意访问。

3.5 本章小结

  • 多级页表通过按需分配页表页,解决了单级页表的连续内存浪费问题,支持稀疏的64位地址空间。
  • x86-64使用四级页表(PML4 → PDPT → PD → PT),线性地址拆分为5个字段,CR3寄存器指向顶级页表。
  • ARMv8-A使用四级页表(L0 → L1 → L2 → L3),支持1 GiB、2 MiB、4 KiB三种映射粒度,权限模型基于AP/PXN/UXN位。
  • 多级页表在节省空间的同时增加了转换延迟,TLB和大页机制是关键的性能优化手段。
  • 在安全方面,多级页表允许在每一级设置独立的权限位,实现分层权限控制,增强内存隔离性。