x86-64 页表项:64 位 Entry、物理地址位宽与标志位
拆解 x86-64 的 64 位页表项,区分物理地址字段、标志位与页大小差异。
建议先了解
- 二进制与十六进制
- 地址、指针与内存的基本概念
- 页与 4 KiB 对齐
1. 这篇笔记解决什么问题
这篇笔记集中解决三个容易混淆的问题:
- 物理地址到底是多少位?它是否由机器实际安装的 RAM 容量决定?
- 为什么 x86-64 的页表项固定是 64 bit,而机器的物理内存大小可以变化?
- 一个 64-bit 页表项中,地址和 Present、R/W、U/S、NX 等控制位是怎样同时保存的?
它位于计算机系统中的“虚拟内存 → 地址翻译 → 页表”知识链上。理解本篇后,应能够解释:
- 物理地址空间(physical address space)与实际 RAM 容量为什么不是一回事;
MAXPHYADDR的含义;- 为什么 4 KiB 对齐使页表项不必存储物理地址最低 12 bit;
- 非叶子页表项(例如 PML4E)与叶子页表项(PTE)的区别;
Reserved与Ignored为什么不能混为一谈。
核验说明:本笔记中的架构性结论按当前 x86-64 文档口径整理,并与 Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A, Chapter 4 以及 AMD64 Architecture Programmer’s Manual Volume 2: System Programming 的页表描述交叉核对。具体 CPU 支持的地址位宽和可选特性仍应以该型号的 CPUID 为准。
2. 前置知识
需要先理解:
- 二进制 bit 编号,例如
bits 51:12; - 十六进制与二进制之间的对应关系;
- 物理地址与虚拟地址是不同的地址空间;
- 对齐(alignment):4 KiB 对齐意味着地址最低 12 bit 必须为 0。
待补充:若继续深入 PWT、PCD、PAT,需要进一步学习 x86 的内存类型与缓存属性体系。
3. 核心概念
3.1 物理地址空间(Physical Address Space)
物理地址空间是 CPU/平台能够用物理地址标识的地址范围。
它不等同于“实际装了多少 RAM”。
例如,若某 CPU 支持 48-bit 物理地址:
这表示 CPU 的物理地址最多可以描述 256 TiB 的地址范围,但机器完全可以只安装 32 GiB 或 64 GiB RAM。
物理地址空间中还可以出现:
- DRAM;
- PCIe 设备的 MMIO 区域;
- 固件保留区;
- APIC 等硬件映射;
- 未映射、不可访问的空洞。
因此:
3.2 最大物理地址位宽(MAXPHYADDR)
在 x86-64 中,具体处理器支持多少位物理地址由 CPU 架构实现决定,并通过 CPUID 枚举给软件。
通常将该位宽记为:
现代 x86-64 页表格式能够容纳最高到 52-bit 的物理地址字段,但具体处理器的 MAXPHYADDR 可以小于 52。
例如:
M = 48:有效物理地址位为47:0;M = 52:有效物理地址位为51:0。
3.3 页框(Page Frame)
4 KiB 页的大小为:
因此一个 4 KiB 对齐的物理页框基址一定满足:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 000000000000
└──── 12 ────┘
最低 12 bit 恒为 0。
页表项没有必要重复保存这些 0,只需要保存物理地址的高位部分。
3.4 页表项(Page-Table Entry)
在 IA-32e/x86-64 的常见分页结构中,一个 paging-structure entry 固定为:
64 bit 中同时容纳:
- 下一层页表或最终物理页的物理地址高位;
- 页表权限和状态位;
- 一些保留位、忽略位或可选功能位。
3.5 非叶子页表项与叶子页表项
非叶子页表项(non-leaf entry)指向下一层页表。
例如 4-level paging 中:
PML4E → PDPT
PDPTE → PD
PDE → PT
当不使用 huge page 时,最后一级:
PTE → 4 KiB physical page
PTE 是叶子页表项(leaf entry)。
另外:
- PDPTE 可以在
PS=1时直接映射 1 GiB 页; - PDE 可以在
PS=1时直接映射 2 MiB 页。
4. 直观理解
可以把一个 64-bit 页表项理解为一个“压缩后的、带元数据的物理指针”。
普通 64-bit 指针似乎需要完整保存地址,但页表结构知道目标一定按 4 KiB 对齐,所以最低 12 bit 必定为 0。
于是原本:
physical address
[ 高位地址 ................................ ][000000000000]
12 bits
可以改成:
page-table entry
[ 地址高位 ................................. ][flags]
这不是说地址“变短了”,而是说最低 12 个 0 是由对齐规则隐式恢复的。
类比边界:页表项并不是 C 语言意义上的普通指针。CPU 对每一位都有架构定义,并且错误设置保留位可能触发异常。
5. 工作原理
5.1 为什么一张页表恰好有 512 个 entry
一张常规页表占一个 4 KiB page:
每个 entry 为:
所以:
因此每一级页表索引需要 9 bit。
5.2 地址字段为什么从 bit 12 开始
若物理地址位宽为 M = MAXPHYADDR,对于指向下一张 4 KiB 对齐页表的 entry:
有效地址位:bits M-1 : 12
隐含为 0 :bits 11 : 0
恢复完整页表基址时,本质上是:
或者从完整 64-bit entry 中做掩码:
5.3 4-level paging 中 PML4E 的基本结构
PML4E(Page-Map Level-4 Entry)是 L4 entry。
对于基础 4-level IA-32e page walk,可按下面的结构理解:
| bit | 含义 |
|---|---|
| 0 | P:Present |
| 1 | R/W:Read/Write |
| 2 | U/S:User/Supervisor |
| 3 | PWT:Page-Level Write-Through |
| 4 | PCD:Page-Level Cache Disable |
| 5 | A:Accessed |
| 6 | 硬件忽略位 |
| 7 | Reserved;PML4E 没有 PS 字段,必须满足架构要求 |
| 11:8 | 硬件忽略/软件可用语义需结合架构与 OS |
M-1:12 | 下一层 PDPT 的物理地址高位 |
51:M | 当 M < 52 时属于保留地址位,不能当成有效物理地址 |
| 62:52 | 基础语义下多为 ignored / feature-dependent |
| 63 | XD/NX:Execute Disable,是否可用取决于 NXE 等特性 |
关键点不是背每一位,而是理解三类位:
[ 功能/扩展位 ][ 物理地址高位 ][ 状态与权限 flags ]
[!WARNING] “Ignored” 位是否能被操作系统拿来保存软件状态,需要结合具体 CPU 特性和内核定义判断,不能因为硬件在某种模式下忽略就默认“永远可自由使用”。
5.4 最终一级 PTE 的基本结构
4 KiB PTE 与 PML4E 最大的区别是:
PTE 的地址字段指向最终 physical page,而不是下一张页表。
常见关键位包括:
| bit | 含义 |
|---|---|
| 0 | P:Present |
| 1 | R/W:Read/Write |
| 2 | U/S:User/Supervisor |
| 3 | PWT |
| 4 | PCD |
| 5 | A:Accessed |
| 6 | D:Dirty |
| 7 | PAT(对 4 KiB PTE) |
| 8 | G:Global |
| 11:9 | 架构忽略/软件使用区域之一 |
M-1:12 | 4 KiB physical page 的物理基址高位 |
51:M | M < 52 时为保留地址位 |
| 62:59 | 可由 Protection Keys 等特性解释,否则依具体配置 |
| 63 | XD/NX,是否有效取决于相关特性 |
5.5 L3/L2 的 PS 与 huge page
在常规 4-level paging 中:
PML4E
↓
PDPTE -- PS=0 --> PDE
│
└-- PS=1 --> 1 GiB page
PDE -- PS=0 --> PTE
│
└-- PS=1 --> 2 MiB page
PTE ------------> 4 KiB page
一个重要纠正:
PML4E 没有 PS 字段。
不能把“PML4E 的 bit 7 必须为 0”简单表述成“PML4E 的 PS=0”;更准确的说法是该位置在 PML4E 格式中是保留位。
6. 示例
示例 1:为什么 52-bit 物理地址只需要保存 40 个地址 bit
假设:
MAXPHYADDR = 52
page size = 4 KiB
完整物理地址有效范围是:
bits 51:0
但页框最低 12 bit 恒为 0,因此页表项只需存:
bits 51:12
位数为:
恢复时:
stored 40-bit page-frame number
↓ << 12
52-bit physical page base
因此“只存 40 bit”并不意味着物理地址只有 40 bit。
示例 2:一个非叶子 entry
假设下一张页表的物理基址是:
0x0000000000200000
并设置:
P = 1
RW = 1
US = 1
最低三位即:
111₂ = 0x7
于是一个简化示例 entry 可以写成:
0x0000000000200007
其中:
0x0000000000200000 ← 物理页表基址
0x0000000000000007 ← flags
提取基址时得到:
0x0000000000200000
示例 3:CPU 支持 48-bit 物理地址时
若:
MAXPHYADDR = 48
真正有效的物理地址字段是:
bits 47:12
不是 51:12 全部都能用于地址。
因此:
bits 51:48
不能因为 64-bit entry 中“有位置”就拿来扩展地址;它们必须满足该 CPU 架构定义的保留位要求。
7. 代码、命令或公式
7.1 通用的页框基址掩码
若:
M = MAXPHYADDR
则 4 KiB 页框地址掩码可以写成:
(((1 << M) - 1) & ~0xFFF)
例如概念性 Python:
def page_base_from_entry(entry: int, maxphyaddr: int) -> int:
mask = ((1 << maxphyaddr) - 1) & ~0xFFF
return entry & mask
这段代码只演示地址位提取,不负责检查 Present、Reserved、NX、Protection Key 等架构语义。
7.2 512 entries 的来源
7.3 Linux 查看 CPU 报告的地址位宽
可在 Linux 上尝试:
lscpu
常见输出中会包含类似 “Address sizes” 的信息。
不同发行版和 util-linux 版本的显示格式可能不同。
8. 容易混淆的概念
| 概念 A | 概念 B | 核心区别 |
|---|---|---|
| 物理地址位宽 | RAM 容量 | 前者是 CPU/平台可描述的地址范围,后者是实际安装的存储器容量 |
| 物理地址空间 | DRAM | 物理地址空间还可包含 MMIO、保留区和空洞 |
| 页表项自身地址 | 页表项中保存的地址 | 前者是该 8-byte entry 存在哪里;后者是它指向下一张页表或物理页的位置 |
| PML4E | PTE | PML4E 通常指向下一层 PDPT;4 KiB PTE 指向最终 physical page |
| Reserved | Ignored | Reserved 必须满足架构规定;Ignored 表示硬件在该语义下不使用,但软件用途仍需按架构/OS 规则 |
| 52-bit 物理地址 | 40-bit 页框号 | 4 KiB 对齐使最低 12 bit 隐含为 0,因此只需存高 40 bit |
9. 常见误区
误区:物理地址位数由实际 RAM 容量直接决定
错误原因:
把“可寻址范围”与“实际安装容量”看成同一个概念。
正确理解:
物理地址宽度首先由 CPU 架构实现及平台能力决定。机器可以只安装物理地址空间中的一小部分 RAM。
如何验证:
查看 CPU 架构报告的 physical address bits,再与机器实际内存容量对比,两者通常不是简单的 log2(RAM) 关系。
误区:换一根更大的内存条,页表 entry 格式也必须变化
错误原因:
误以为页表格式按照当前 RAM 容量动态设计。
正确理解:
x86-64 paging entry 的宽度和字段布局是架构规定的。更换 RAM 只会改变哪些物理地址实际对应 DRAM,不会把 64-bit PTE 改成另一种宽度。
如何验证:
同一 CPU 平台在不同内存容量配置下仍使用同一 ISA 页表格式。
误区:PML4E 中存了完整的 52-bit 物理地址
错误原因:
忽略了 4 KiB 对齐。
正确理解:
最低 12 bit 恒为 0,页表项只保存 M-1:12 的地址位;低位由硬件隐式补 0。
如何验证:
观察任何合法 4 KiB 页表基址,其十六进制最低 3 位必为 000。
误区:PML4E 也有一个 PS 位,只不过 PS=0
错误原因:
把 PDE/PDPTE 的 huge-page 格式机械套到 PML4E。
正确理解:
PML4E 不定义 PS 字段;对应位置是保留位,应按架构要求处理。
如何验证:
查阅 Intel SDM Volume 3A Chapter 4 或 AMD64 APM Volume 2 中 PML4E 的正式位布局。
误区:Ignored 位等于“操作系统想写什么就写什么”
错误原因:
忽略了 CPU 可选特性、未来架构扩展和 OS 自身编码约定。
正确理解:
“Ignored by hardware” 只说明在特定模式/功能组合下硬件 page walk 不使用该位。软件能否安全复用必须结合具体架构和内核实现。
如何验证:
对照对应 CPU 手册和操作系统的页表宏定义,而不是只看一张简化图。
10. 与其他知识的关系
本主题直接连接到地址翻译过程:
继续向上游需要理解:
- 虚拟内存、物理页面与多级页表
- 进程地址空间 — 待建链接
继续向下游会涉及:
- TLB — 待建链接
- Huge Page — 待建链接
- 页错误与缺页异常 — 待建链接
- x86 内存类型与 PAT — 待建链接
11. 可以亲手完成的验证
实验目标
验证“CPU 支持的物理地址位宽”与“实际 RAM 容量”不是同一概念,并练习页框地址掩码。
所需环境
- 一台 x86-64 Linux 机器;
- Python 3;
- 普通用户权限即可。
操作步骤
-
执行:
lscpu -
找到 physical address bits 或 “Address sizes” 类字段。
-
查看机器 RAM:
free -h -
比较两者。
-
用 Python 手动提取一个 entry 的页框基址:
entry = 0x0000000000200007 maxphyaddr = 52 mask = ((1 << maxphyaddr) - 1) & ~0xFFF page_base = entry & mask print(hex(page_base))
预期现象
最后的 Python 输出应为:
0x200000
同时,CPU 报告的可寻址物理范围通常远大于机器实际安装的 RAM。
如何判断结果
如果 0x200007 中的最低 flags 被掩掉后得到 0x200000,说明已经理解了“地址高位 + flags”的编码方式。
实验不能证明什么
这个实验不能证明:
- 该虚构 entry 真的存在于当前系统页表中;
- 当前 Linux 内核如何使用所有 ignored bits;
- CPU 内部 page walker 的微架构细节。
12. 尚未解决的问题
- 当前具体 CPU 型号的
MAXPHYADDR到底是多少,需要读取该机器的 CPUID 或系统报告。 - 5-level paging(LA57)启用后,虚拟地址分解会增加一级 PML5;本篇没有展开。
- CR3 低 12 bit 在 PCID 开启/关闭时含义不同,本篇只讨论页表基址这一核心部分。
- PWT、PCD、PAT 与 MTRR 如何共同决定内存类型,需要单独整理。
- 操作系统如何复用硬件 ignored bits,需要结合 Linux/Windows 等具体内核实现分析。
- Protection Keys、NX、CET 等可选机制会改变部分高位的解释,需要按 CPU 功能组合查官方手册。
13. 自测问题
- 为什么 64 GiB RAM 并不意味着 CPU 的物理地址一定只有 36 bit?
MAXPHYADDR=52且页大小为 4 KiB 时,页表项需要显式保存多少个物理页框地址 bit?- 为什么一个合法的 4 KiB 页表基址最低 12 bit 必须是 0?
- PML4E 与 4 KiB PTE 在“地址字段指向什么”这一点上有什么区别?
Reserved与Ignored的区别是什么?- 为什么
0x0000000000200007可以同时表达一个页表地址和三个低位 flag? - 为什么不能说“PML4E 的 PS=0”而应该更精确地描述 bit 7?
- 当
MAXPHYADDR=48时,页表项中的 bits51:48为什么不能当成额外的物理地址位?
参考答案
- 物理地址位宽描述 CPU/平台可寻址范围;实际 RAM 只是该范围中被 DRAM 占用的一部分,物理地址空间还可包含 MMIO、空洞和保留区。
52 - 12 = 40bit,即 bits51:12。- 4 KiB =
2^12,4 KiB 对齐地址一定是 4096 的整数倍,因此最低 12 bit 为 0。 - PML4E 通常指向下一层 PDPT;4 KiB PTE 指向最终映射的 physical page。
- Reserved 位必须满足架构规定;Ignored 位表示硬件在相应语义下不使用,但软件是否能复用仍要看具体架构和 OS。
- 目标页表基址最低 12 bit 本来就是 0,因此低位可以用于 flags;
0x7表示最低三位均为 1。 - PML4E 不定义 huge-page PS 字段;对应 bit 位置在该格式中是保留位。
- 因为有效物理地址只到 bit 47;高于
MAXPHYADDR-1的地址位必须满足架构的保留位规则。
14. 一句话总结
x86-64 的 64-bit 页表项利用 4 KiB 对齐带来的 12 个隐含低零位,把物理页框地址与权限/状态信息压在同一个 entry 中;而物理地址位宽由 CPU 的 MAXPHYADDR 决定,并不等于机器实际安装的 RAM 容量。