2. 页表与页表项:页表定义、页表项结构、权限位与属性位

页表是虚拟内存系统的核心数据结构,负责将虚拟地址(VA)映射到物理地址(PA)。在 ARMv8-A 架构中,页表采用多级树形结构,每一级页表由若干页表项(PTE)组成。本章深入剖析页表的定义、页表项的位布局,以及权限位与属性位的硬件语义。

2.1 页表定义与层级结构

页表本质上是一个存储在内存中的数组,每个数组元素称为一个页表项(PTE)。ARMv8-A 支持 4KB、16KB 和 64KB 三种页面粒度,对应不同的页表层级数。以最常见的 4KB 页面 + 48 位虚拟地址空间为例,采用 4 级页表结构:

页表级别名称索引位宽页表大小覆盖地址范围
Level 0PGD (Page Global Directory)9 bits512 × 8B = 4KB512 GB
Level 1PUD (Page Upper Directory)9 bits512 × 8B = 4KB1 GB
Level 2PMD (Page Middle Directory)9 bits512 × 8B = 4KB2 MB
Level 3PT (Page Table)9 bits512 × 8B = 4KB4 KB
关键概念: 页表本身也占用物理内存。一个 4 级页表结构在完全填充时,页表自身占用约 4MB 内存(每级 4KB × 512 个表项)。但实际使用中,只有映射的虚拟地址范围才会分配页表,因此内存开销远小于理论最大值。
页表层级与页面大小关系: ARMv8-A 允许在中间级别(Level 1 或 Level 2)直接映射大页(1GB 或 2MB),从而减少页表层级数,降低 TLB 缺失开销。这种机制称为“块映射”(Block Mapping)。

2.2 页表项结构

每个页表项(PTE)在 ARMv8-A 中固定为 8 字节(64 位)。根据页表级别和映射类型,PTE 的位布局略有差异。以下是 Level 3 页表项(指向 4KB 页面的最终映射)的标准结构:

63      54 53    51 50   48 47   44 43   40 39   36 35   32 31   30 29   28 27   26 25   24 23   22 21   20 19   18 17   16 15   14 13   12 11   10 9    8 7    6 5    4 3    2 1 0
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  Upper  |  PBHA  |  RES0  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Lower |
|  Attr  |  [3:0] |        |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Attr  |
|  [63]  |        |        |  [11]  |  [10]  |  [9]   |  [8]   |  [7]   |  [6]   |  [5]   |  [4]   |  [3]   |  [2]   |  [1]   |  [0]   |        |        |        |        |        |        |        |        |        |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
|  PXN   |  UXN   |  Cont  |  DBM   |  GP    |  nG    |  AF    |  SH    |  AP    |  AP    |  NS    |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |  Attr  |
|        |        |        |        |        |        |        |  [1:0] |  [2:1] |  [0]   |        |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |  Indx  |
|        |        |        |        |        |        |        |        |        |        |        |  [3]   |  [2]   |  [1]   |  [0]   |        |        |        |        |        |        |        |        |        |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
注意: 上述位图仅为 Level 3 页表项的标准布局。Level 0/1/2 的页表项中,物理地址字段的起始位不同(因为页面大小不同),且可能包含“块描述符”而非“页描述符”。实际编程时,必须使用 ARM 架构参考手册中的精确位定义。

2.3 权限位详解

权限位控制着对映射页面的访问权限,是内存保护的基础。ARMv8-A 页表项中的关键权限位包括:

位域名称宽度描述
[1:0]Descriptor Type2 bits00 = 无效(Fault),01 = 页表(Table),10 = 块(Block),11 = 页(Page)
[7:6]AP[2:1]2 bits访问权限:00 = EL1/EL0 读写,01 = EL1 读写/EL0 只读,10 = EL1 只读/EL0 无访问,11 = EL1 只读/EL0 只读
[5]AP[0]1 bit访问权限扩展:0 = 非特权访问受 AP[2:1] 控制,1 = 特权访问受 AP[2:1] 控制
[54]PXN1 bit特权执行永不(Privileged Execute Never):1 = 禁止特权模式执行
[53]UXN1 bit用户执行永不(User Execute Never):1 = 禁止用户模式执行
[11]nG1 bit非全局位:1 = 页表项仅在 ASID 匹配时有效(进程私有)
权限组合示例:
  • 内核代码段: AP[2:1]=10, AP[0]=0, PXN=0, UXN=1 → 仅 EL1 可读可执行,EL0 无访问
  • 用户代码段: AP[2:1]=00, AP[0]=0, PXN=1, UXN=0 → EL0 和 EL1 均可读可执行
  • 内核栈: AP[2:1]=00, AP[0]=0, PXN=1, UXN=1 → 可读写,不可执行(NX 保护)

2.4 属性位详解

属性位控制着缓存策略、共享属性、内存类型等硬件行为,直接影响系统性能和一致性:

位域名称宽度描述
[4:2]AttrIndx[2:0]3 bits内存属性索引,指向 MAIR(Memory Attribute Indirection Register)中的属性配置
[10:8]SH[1:0]2 bits共享属性:00 = 非共享,01 = 预留,10 = 外部共享,11 = 内部共享
[10]AF1 bit访问标志:1 = 页面已被访问(硬件自动置位,软件可清除用于页面回收)
[51]DBM1 bit脏位管理(Dirty Bit Management):1 = 启用硬件脏位跟踪
[52]Cont1 bit连续页表项提示:1 = 相邻 16 个页表项形成连续映射,可合并为单条 TLB 条目
[50:48]PBHA[3:0]4 bits页表项属性提示(Page-Based Hardware Attributes):由具体实现定义,用于自定义硬件优化
MAIR 寄存器: ARMv8-A 使用 MAIR_EL1 寄存器定义 8 个内存属性槽位(AttrIndx 0~7)。每个槽位编码了内存类型(Normal/Device)、缓存策略(Write-Back/Write-Through/Write-Combine)和 transient 提示。页表项中的 AttrIndx 字段选择使用哪个槽位。

2.5 页表项结构 SVG 图

下图展示了 ARMv8-A Level 3 页表项的完整位布局,以及关键字段的功能分组:

ARMv8-A Level 3 页表项(PTE)位布局 位索引: 63 54 52 51 50 48 47 12 11 10 8 7 5 2 PXN UXN Cont DBM PBHA RES0 PA[47:12] nG AF SH AP AttrIndx Type 执行权限 PXN / UXN 缓存/共享属性 AttrIndx / SH / PBHA 访问/脏位管理 AF / DBM / Cont 访问控制 AP / nG / Type 物理地址(PA)生成 PA[47:12] = PTE[47:12](页表项中的物理页帧号) PA[11:0] = VA[11:0](页内偏移直接来自虚拟地址) 描述符类型(Type 字段) • 00 = Fault(无效):页面未映射,访问触发缺页异常 • 01 = Table(页表):指向下一级页表的基地址(仅 Level 0/1/2) • 10 = Block(块):直接映射大页(1GB 或 2MB,仅 Level 1/2) • 11 = Page(页):最终 4KB 页面映射(仅 Level 3)

2.6 页表项权限与属性组合示例

以下示例展示了典型操作系统场景中页表项的配置:

内存区域AP[2:1]AP[0]PXNUXNAttrIndxSHAF描述
内核代码100010 (Normal WB)111仅 EL1 可读可执行,内部共享
内核数据000110 (Normal WB)111EL1/EL0 可读写,不可执行
用户代码000100 (Normal WB)111EL0 可读可执行,EL1 可读
用户栈000110 (Normal WB)111EL0 可读写,不可执行
MMIO 寄存器000114 (Device nGnRE)001非共享,严格顺序,不可缓存
页表自身000110 (Normal WB)111可读写,内部共享,可缓存
重要提示: 页表项中的 AF(访问标志)位必须由软件在首次访问前置位,否则 MMU 会触发 Access Flag 异常。现代操作系统通常通过缺页异常处理程序统一管理 AF 位,实现页面置换和访问计数。

2.7 页表项操作流程

操作系统在建立或修改虚拟地址映射时,需要遵循以下步骤操作页表项:

  1. 分配页表物理页: 从物理内存分配器获取 4KB 对齐的物理页帧,用于存放页表项数组。
  2. 清零页表: 将新分配的页表全部写为 0(Fault 描述符),确保所有条目初始为无效状态。
  3. 设置页表项: 根据映射需求,构造 64 位页表项值,包括物理地址、权限位、属性位和描述符类型。
  4. 内存屏障: 使用 DSB 指令确保页表写入完成,再使用 ISB 指令刷新指令流水线。
  5. TLB 失效: 使用 TLBI 指令使受影响虚拟地址范围的 TLB 条目失效。
  6. 验证映射: 通过访问映射地址确认无异常,必要时检查 PAR_EL1 寄存器获取物理地址。
// 示例:设置 Level 3 页表项(ARMv8-A 汇编风格)
// x0 = 页表基地址,x1 = 虚拟地址索引,x2 = 物理地址,x3 = 属性值

// 计算页表项地址
LSR     x4, x1, #12          // 提取 VA[47:12] 作为页表索引
AND     x4, x4, #0x1FF       // 取低 9 位(Level 3 索引)
LSL     x4, x4, #3           // 乘以 8(每项 8 字节)
ADD     x4, x0, x4           // 页表项地址 = 基地址 + 索引 * 8

// 构造页表项
AND     x2, x2, #0x0000FFFFFFFFF000  // 提取物理页帧号 PA[47:12]
ORR     x2, x2, x3           // 合并属性位
ORR     x2, x2, #0x3         // 设置描述符类型为 Page(11)

// 写入页表项
STR     x2, [x4]             // 写入内存

// 内存屏障与 TLB 失效
DSB     SY                   // 确保存储完成
TLBI    VAE1, x1             // 使虚拟地址对应的 TLB 条目失效
DSB     SY                   // 等待 TLB 失效完成
ISB     SY                   // 刷新流水线
性能优化提示: 批量设置连续页表项时,可以使用 STP(Store Pair)指令一次写入两个 64 位值,并利用 Contiguous 位(Cont=1)提示 MMU 合并 TLB 条目。连续映射的 16 个 4KB 页面可合并为单条 64KB TLB 条目,显著降低 TLB 缺失率。

2.8 页表项与多级页表协同 SVG 图

下图展示了 4 级页表结构中,各级页表项如何协同完成虚拟地址到物理地址的映射:

4 级页表地址映射流程 虚拟地址 VA[47:0] L0 索引 [47:39] L1 索引 [38:30] L2 索引 [29:21] L3 索引 [20:12] 页内偏移 [11:0] Level 0 页表 PGD Level 1 页表 PUD Level 2 页表 PMD ← 上一章 📖 返回目录 下一章 →