3. ARMv8-A 页表格式:描述符结构与属性位详解
ARMv8-A 架构的页表采用多级查找结构,每一级页表条目(Page Table Entry, PTE)称为描述符。描述符不仅包含下一级页表的物理地址,还携带了内存属性、访问权限、安全状态等关键信息。理解描述符的格式是配置 MMU 和管理 TLB 的基础。
3.1 页表描述符通用结构
每个描述符占用 64 位(8 字节),其通用布局如下:
| 位域 | 宽度 (bit) | 描述 |
|---|---|---|
| [63:48] | 16 | 物理地址高位(PA[47:32] 或 PA[35:32],取决于配置) |
| [47:12] | 36 | 物理地址低位(PA[35:0] 或 PA[31:0]),页内偏移对齐 |
| [11:10] | 2 | 访问权限位(AP[2:1]) |
| [9] | 1 | 可共享位(SH) |
| [8:6] | 3 | 内存属性索引(AttrIndx[2:0]) |
| [5] | 1 | 非安全位(NS) |
| [4] | 1 | 访问标志位(AF) |
| [3:2] | 2 | 提示位(Hint),如连续页表(Contiguous) |
| [1:0] | 2 | 描述符类型(Type):00=无效,01=Table,10=Block/Page,11=保留 |
关键点:描述符的最低两位 [1:0] 决定了该条目的类型。硬件通过检查这两个位来区分当前级是继续查表(Table)还是直接映射(Block/Page)。
3.2 页表项类型:Table / Block / Page
ARMv8-A 页表项分为三种核心类型,分别对应不同的页表层级和映射粒度:
- Table 描述符(类型 01):指向下一级页表的基地址。仅在非末级页表中出现。
- Block 描述符(类型 10):直接映射一个连续的大内存块(如 2MB、1GB)。仅在 L1/L2 级页表中出现。
- Page 描述符(类型 10):映射一个标准 4KB 页。仅在 L3(末级)页表中出现。
- Invalid 描述符(类型 00):表示该条目未使用,访问将触发缺页异常。
注意:Block 和 Page 描述符在二进制编码上都是
10,硬件通过页表层级(L0/L1/L2/L3)来区分它们。L0/L1/L2 中的 10 视为 Block,L3 中的 10 视为 Page。
3.3 描述符类型与层级关系 SVG 图
下图展示了 4 级页表中描述符类型与层级之间的对应关系:
3.4 关键属性位详解
描述符中的属性位控制着内存的访问行为、缓存策略和安全隔离。以下是核心属性位的详细说明:
| 属性位 | 位域 | 功能描述 | 典型配置 |
|---|---|---|---|
| Type | [1:0] | 描述符类型:Invalid / Table / Block-Page | 01(Table)或 10(Block/Page) |
| AF | [4] | 访问标志位(Access Flag)。必须置 1,否则访问时触发 Access Flag 异常 | 1(已访问) |
| AP[2:1] | [11:10] | 数据访问权限:EL0/EL1 读写控制 | 00:EL0 无访问,EL1 读写;11:EL0/EL1 读写 |
| AttrIndx | [8:6] | 内存属性索引,指向 MAIR 寄存器中的属性配置 | 000:Normal 内存;001:Device 内存 |
| SH | [9] | 可共享性(Shareability):Non-shareable / Inner Shareable / Outer Shareable | 11:Outer Shareable(多核共享) |
| NS | [5] | 非安全位(Non-Secure)。在安全世界中标记页表是否属于非安全空间 | 0:安全;1:非安全 |
| Contiguous | [3] | 连续页表提示位。置 1 表示相邻 16 个条目构成连续映射,可合并为单 TLB 条目 | 0:非连续;1:连续(需 16 个连续条目同时置位) |
| PXN | [53] | 特权执行不可行(Privileged Execute Never)。禁止 EL1 执行该页代码 | 1:禁止特权执行 |
| UXN | [54] | 用户执行不可行(User Execute Never)。禁止 EL0 执行该页代码 | 1:禁止用户执行 |
常见错误:忘记设置 AF 位([4]=1)是页表配置中最常见的错误之一。如果 AF 为 0,MMU 在第一次访问时会触发 Access Flag 异常,导致内核崩溃或性能下降(软件需手动置位并重试)。
3.5 属性位组合与内存类型 SVG 图
下图展示了 AttrIndx、SH 和 AP 位如何共同决定最终的内存访问行为:
3.6 连续页表(Contiguous Hint)
ARMv8-A 支持连续页表提示(Contiguous Bit),允许将相邻的 16 个页表条目合并为单个 TLB 条目,从而减少 TLB 压力。该特性对性能敏感的大块内存映射(如内核线性映射)尤为重要。
- 条件:16 个连续描述符必须同时置位 Contiguous 位,且映射的物理地址连续、属性完全一致。
- 效果:TLB 只需缓存 1 个条目即可覆盖 16 个页(4KB 页 → 64KB 范围;2MB Block → 32MB 范围)。
- 限制:连续页表不能跨页表边界;软件必须保证 16 个条目的物理地址和属性完全一致。
性能收益:在 Linux 内核中,连续页表常用于 vmalloc 区域和线性映射区域。实测表明,启用连续页表可减少 TLB 缺失率 30%~50%,对数据库和 HPC 负载提升显著。
3.7 页表描述符配置示例
以下是一个 L2 Block 描述符的配置示例,映射 2MB 的 Normal 内存,可共享,EL0/EL1 可读写:
// L2 Block 描述符配置(64 位)
// 物理地址基址:0x80000000(假设)
// 属性:Normal 内存,Outer Shareable,EL0/EL1 读写,AF=1
uint64_t l2_block_desc = 0x0000008000000000ULL // PA[47:12] = 0x80000000 >> 12
| (0x3ULL << 10) // AP[2:1] = 11 (EL0/EL1 读写)
| (0x3ULL << 9) // SH = 11 (Outer Shareable)
| (0x0ULL << 6) // AttrIndx = 000 (Normal)
| (0x1ULL << 4) // AF = 1
| (0x0ULL << 3) // Contiguous = 0
| (0x2ULL << 0); // Type = 10 (Block)
调试建议:在 QEMU 或真实硬件上调试页表时,建议先打印描述符的十六进制值,然后逐位解析 Type、AF、AP 和 AttrIndx,确保与预期一致。使用
readelf -l 或内核的 dump_page 工具辅助验证。
3.8 本章小结
- ARMv8-A 页表描述符为 64 位,最低两位 [1:0] 决定类型:Invalid、Table、Block/Page。
- Table 描述符指向下一级页表;Block 描述符用于大块映射(1GB/2MB);Page 描述符用于 4KB 标准页。
- 关键属性位包括 AF(访问标志)、AP(权限)、AttrIndx(内存类型索引)、SH(可共享性)和 Contiguous(连续提示)。
- 连续页表可合并 16 个条目为单 TLB 条目,是提升 TLB 覆盖范围的重要手段。
- 属性位的组合最终通过 MAIR 寄存器、权限检查和可共享性逻辑决定内存访问行为。