2. x86_64 分页模式:4级分页与5级分页的演进
x86-64 架构从诞生至今,其分页机制经历了从 4级分页 到 5级分页 的演进。这一演进的核心驱动力是物理地址空间的持续增长需求。本章将深入剖析这两种分页模式的层级结构、页表项格式以及它们之间的关键差异。
2.1 从 4 级到 5 级:地址空间的扩展
最初的 x86-64 架构(AMD64)定义了 48 位虚拟地址空间,并使用 4 级分页结构来管理。然而,随着硬件技术的发展,物理内存容量迅速增长,48 位虚拟地址空间(256 TiB)逐渐成为瓶颈。为了支持更大的物理内存(例如 4 PiB 以上),Intel 在 Ice Lake 及后续处理器中引入了 5 级分页(5-Level Paging, 5LP),将虚拟地址扩展到 57 位。
- 4级分页: 虚拟地址 48 位,物理地址最大支持 52 位(4 PiB),页表层级为 PML4 → PDPT → PD → PT。
- 5级分页: 虚拟地址 57 位,物理地址最大支持 52 位(4 PiB),页表层级为 PML5 → PML4 → PDPT → PD → PT。
2.2 4级分页层级结构详解
4 级分页是 x86-64 最经典的分页模式。它将 48 位虚拟地址划分为 4 个索引字段和一个偏移量,分别用于遍历 4 级页表。每一级页表都是一个包含 512 个表项(Entry)的数组,每个表项 8 字节,因此每级页表大小为 4 KiB(一个标准页面)。
下图展示了 4 级分页的地址转换流程:
2.3 5级分页层级结构详解
5 级分页在 PML4 之上增加了一级名为 PML5(Page Map Level 5) 的页表。虚拟地址因此扩展到 57 位,其中高 9 位用于索引 PML5 表。这使得页表层级变为 5 级,地址转换路径更长,但换来了更大的地址空间。
下图展示了 5 级分页的地址转换流程:
2.4 页表项(PTE)格式详解
无论是 4 级还是 5 级分页,每一级页表中的表项(Page Table Entry, PTE)都具有相同的 8 字节结构。页表项包含了物理地址的高位以及一系列控制位。理解 PTE 的格式是掌握分页机制的关键。
下表详细列出了标准 4KB 页面的页表项格式:
| 位域 | 宽度 | 名称 | 描述 |
|---|---|---|---|
| 63:52 | 12 | Ignored / Reserved | 在 4 级分页中为 0;在 5 级分页中,PML5E 的 [63:52] 用于 PML5 索引。 |
| 51:12 | 40 | 物理地址 (PA) | 物理页帧号(PFN)的高 40 位。与低 12 位偏移组合形成 52 位物理地址。 |
| 11:9 | 3 | Ignored | 可供软件使用的位(如用于页替换算法)。 |
| 8 | 1 | G (Global) | 全局页标志。若置位,该页在 TLB 刷新时不会被清除(需配合 CR4.PGE)。 |
| 7 | 1 | PAT (Page Attribute Table) | 页属性表索引,用于更精细的内存缓存控制。 |
| 6 | 1 | D (Dirty) | 脏页标志。由硬件在写入页面时置位,表示页面已被修改。 |
| 5 | 1 | A (Accessed) | 访问标志。由硬件在读取或写入页面时置位,表示页面已被访问。 |
| 4:3 | 2 | PCD / PWT | 缓存控制位:Page-level Cache Disable 和 Page-level Write-Through。 |
| 2 | 1 | U/S (User/Supervisor) | 权限位。0 表示超级用户(内核)权限,1 表示用户权限。 |
| 1 | 1 | R/W (Read/Write) | 读写位。0 表示只读,1 表示可读写。 |
| 0 | 1 | P (Present) | 存在位。0 表示该页表项无效(页不在内存中),访问将触发缺页异常。 |
2.5 4级与5级分页的对比总结
下表从多个维度对比了 4 级分页与 5 级分页:
| 特性 | 4级分页 | 5级分页 |
|---|---|---|
| 虚拟地址宽度 | 48 位 | 57 位 |
| 最大虚拟地址空间 | 256 TiB | 128 PiB |
| 页表层级数 | 4 级 (PML4, PDPT, PD, PT) | 5 级 (PML5, PML4, PDPT, PD, PT) |
| CR3 指向 | PML4 表基地址 | PML5 表基地址 |
| 最大物理地址 | 52 位 (4 PiB) | 52 位 (4 PiB) |
| 硬件支持 | 所有 x86-64 处理器 | Intel Ice Lake 及后续、AMD Zen 4 及后续 |
| Linux 内核支持 | 默认配置 | 需启用 CONFIG_X86_5LEVEL 编译选项 |
/proc/cpuinfo 中的 la57 标志来判断当前 CPU 是否支持 5 级分页。内核启动时,会根据 CPU 能力自动选择使用 4 级还是 5 级分页模式。
2.6 页表项格式的SVG结构图
下图以图形化的方式展示了标准 4KB 页面的页表项(PTE)的位布局:
2.7 大页(Huge Pages)支持
除了标准的 4KB 页面,x86-64 分页还支持大页(Huge Pages),以减少 TLB 缺失并提升性能。大页通过在页表中间层级设置 PS(Page Size) 位来实现。
- 2 MiB 大页: 在 PD(Page Directory) 层级设置 PS 位。此时 PDE 不再指向 PT,而是直接指向一个 2 MiB 的物理页帧。虚拟地址中不再有 PT 索引,偏移量扩展为 21 位。
- 1 GiB 大页: 在 PDPT(Page Directory Pointer Table) 层级设置 PS 位。此时 PDPTE 直接指向一个 1 GiB 的物理页帧。虚拟地址中不再有 PD 和 PT 索引,偏移量扩展为 30 位。
- 减少 TLB 压力: 一个 TLB 表项可以映射更大的内存区域。
- 减少页表遍历次数: 跳过中间层级,加速地址转换。
- 降低页表内存开销: 对于大块连续内存,使用大页可以显著减少页表本身的页数。
2.8 页表项中的权限与保护
页表项中的 U/S 和 R/W 位共同决定了页面的访问权限。此外,NX(No-Execute) 位(位 63)用于防止代码在数据页上执行,这是现代操作系统实现数据执行保护(DEP)的基础。
下表总结了权限位的组合效果:
| U/S | R/W | NX | 超级用户(内核) | 用户态 |
|---|---|---|---|---|
| 0 | 0 | 0 | 可读、可执行 | 不可访问 |
| 0 | 1 | 0 | 可读写、可执行 | 不可访问 |
| 1 | 0 | 0 | 可读、可执行 | 可读、可执行 |
| 1 | 1 | 0 | 可读写、可执行 | 可读写、可执行 |
| 0 | 0 | 1 | 可读 | 不可访问 |
| 1 | 0 | 1 | 可读 | 可读 |
CONFIG_DEBUG_PAGEALLOC 等选项对内核页面进行严格的权限控制。