2. ARMv7/v8 MMU 架构基础:页表层级结构与转换粒度
在 QNX 实时操作系统中,MMU(Memory Management Unit)是虚拟地址到物理地址转换的核心硬件单元。ARMv7(32位)和 ARMv8(64位)架构的 MMU 采用多级页表(Multi-Level Page Table)机制,通过层级化的页表结构实现高效地址翻译与权限控制。本章深入解析 TTB、L1/L2/L3 页表层级、描述符格式以及 4K/16K/64K 转换粒度,为后续 QNX 页表配置与调试奠定基础。
2.1 页表层级结构总览
ARM MMU 使用 翻译表基地址寄存器(TTBR) 指向第一级页表的物理基地址。页表层级从 L1 到 L3,每一级页表包含若干描述符,指向下一级页表或直接映射到物理内存块。层级深度与页面粒度相关,典型配置为 4K 粒度时使用 L1/L2/L3 三级页表。
关键概念: TTB(Translation Table Base)存储于 CP15 寄存器(ARMv7)或系统寄存器 TTBR0_EL1/TTBR1_EL1(ARMv8),是 MMU 遍历页表的入口点。
2.2 页表描述符格式
每个页表条目(Page Table Entry, PTE)包含物理地址高位、访问权限、内存属性、域标识等控制位。ARMv7 与 ARMv8 的描述符格式存在差异,但核心字段功能一致。
2.2.1 ARMv7 短描述符格式(4 字节)
| 位域 | 宽度(位) | 功能描述 |
|---|---|---|
| [31:20] | 12 | 物理地址高位(PA[31:20]),与页内偏移拼接形成 32 位物理地址 |
| [19:12] | 8 | 域标识(Domain),用于权限检查与域访问控制 |
| [11:10] | 2 | 访问权限位(AP[2:1]),控制用户/特权读/写 |
| [9] | 1 | 可共享位(Shareable),多核一致性控制 |
| [8:6] | 3 | 内存属性(TEX[2:0]),缓存策略与内存类型 |
| [5] | 1 | 非安全位(NS),安全世界与非安全世界隔离 |
| [4] | 1 | 可执行位(XN),禁止执行标记 |
| [3:2] | 2 | 页表类型(L1: 0b11 页表, 0b10 段; L2: 0b01 大页, 0b11 小页) |
| [1:0] | 2 | 条目类型(0b10 表描述符, 0b01 块描述符, 0b11 页描述符) |
调试提示: 在 QNX 系统崩溃转储中,检查 L1/L2 描述符的 [1:0] 位可快速判断页表遍历是否中断。若该字段为 0b00,表示无效条目,MMU 将触发 Translation Fault。
2.2.2 ARMv8 长描述符格式(8 字节)
ARMv8 使用 64 位描述符,支持 48 位物理地址空间。L1/L2 描述符为 表描述符 或 块描述符,L3 描述符为 页描述符。
| 位域 | 宽度(位) | 功能描述 |
|---|---|---|
| [63:48] | 16 | 物理地址高位(PA[47:32]),扩展物理地址支持 |
| [47:12] | 36 | 物理地址中低位(PA[31:12]),与页内偏移拼接 |
| [11:10] | 2 | 访问权限(AP[2:1]),与 ARMv7 兼容 |
| [9:8] | 2 | 内存属性索引(AttrIndx[1:0]),指向 MAIR 寄存器配置 |
| [7] | 1 | 非安全位(NS) |
| [6] | 1 | 可执行位(XN) |
| [5] | 1 | 可执行位(PXN),特权级禁止执行 |
| [4:2] | 3 | 保留位(RES0),必须为 0 |
| [1] | 1 | 非安全访问位(nG),ASID 匹配控制 |
| [0] | 1 | 有效位(Valid),0 表示无效条目 |
2.3 转换粒度与页表层级关系
ARMv7/v8 支持三种页面粒度:4K、16K、64K。粒度决定了页表层级深度和每级页表的索引位数。QNX 默认使用 4K 粒度,兼顾灵活性与内存利用率。
| 粒度 | 页内偏移位数 | L1 索引位数 | L2 索引位数 | L3 索引位数 | 页表层级数 | 典型应用 |
|---|---|---|---|---|---|---|
| 4K | 12 | 12 | 12 | 8 | 3 | QNX 标准配置,细粒度内存保护 |
| 16K | 14 | 11 | 11 | 8 | 3 | 减少 TLB 缺失,适合大内存系统 |
| 64K | 16 | 10 | 10 | 8 | 3 | 硬件加速场景,减少页表占用 |
工程注意: 在 QNX 系统中切换页面粒度需要重新初始化 MMU 并刷新 TLB。4K 粒度下 L3 页表条目数最多(256 个),页表总大小约为 4 MB(L1: 16KB + L2: 16KB + L3: 每进程 1MB)。16K/64K 粒度可减少页表层级深度,但可能造成内部碎片。
2.4 地址翻译流程示例(4K 粒度)
以 ARMv8 4K 粒度为例,虚拟地址 VA[47:0] 被拆分为:
- VA[47:39]:9 位 L1 索引(512 条目)
- VA[38:30]:9 位 L2 索引(512 条目)
- VA[29:21]:9 位 L3 索引(512 条目)
- VA[20:12]:9 位 L3 索引(ARMv8 4K 实际使用 9 位 L3 索引,共 512 条目)
- VA[11:0]:12 位页内偏移
MMU 遍历流程:
- 从 TTBR0_EL1 读取 L1 页表基地址。
- 使用 VA[47:39] 作为索引,在 L1 页表中获取表描述符,指向 L2 页表。
- 使用 VA[38:30] 作为索引,在 L2 页表中获取表描述符,指向 L3 页表。
- 使用 VA[29:21] 作为索引,在 L3 页表中获取页描述符,得到物理页基地址。
- 物理页基地址 + VA[11:0] 偏移 = 最终物理地址。
2.5 QNX 中的页表配置实践
QNX 系统启动时,内核通过 mmu_init() 函数初始化页表。关键配置参数包括:
- 页面粒度:通过内核构建选项
ARM_PAGE_SIZE设置,可选 4K/16K/64K。 - TTBR 选择:QNX 使用 TTBR0 映射用户空间,TTBR1 映射内核空间,实现地址空间隔离。
- 域访问控制:通过
DACR寄存器(ARMv7)或MAIR寄存器(ARMv8)配置内存类型与缓存策略。
调试命令: 在 QNX 中,使用
pidin -p <pid> -v 查看进程页表信息;使用 asinfo 工具转储当前 MMU 配置与页表层级。
2.6 常见页表错误与调试要点
| 错误类型 | MMU 异常 | 典型原因 | 调试方法 |
|---|---|---|---|
| Translation Fault | Data/Instruction Abort | 页表条目无效(Valid=0)或未映射 | 检查 TTBR 地址与 L1/L2/L3 描述符有效位 |
| Permission Fault | Prefetch/Data Abort | AP 位禁止当前特权级访问 | 对比访问模式与 AP 字段配置 |
| Domain Fault | Data Abort | 域访问控制寄存器(DACR)禁止访问 | 检查 DACR 值与页表 Domain 字段 |
| Alignment Fault | Data Abort | 访问地址未对齐到粒度边界 | 检查虚拟地址低 12 位(4K 粒度) |
调试陷阱: ARMv8 中 L3 页表条目数可能为 512(9 位索引)或 256(8 位索引),取决于粒度配置。QNX 默认 4K 粒度使用 9 位 L3 索引,共 512 条目。若手动修改页表,务必确认索引位数与页表大小匹配,否则会导致 Translation Fault。