3. ARMv7-A MMU 寄存器详解:TTBR0/TTBR1、SCTLR、DACR、PRRR/NMRR

在 ARMv7-A 架构中,MMU 的行为由一组系统控制寄存器精确配置。这些寄存器决定了页表的基地址、转换粒度、内存属性、访问权限以及对齐策略。对于 QNX 实时系统而言,错误配置任何一个关键寄存器都可能导致系统崩溃、缓存一致性问题或安全漏洞。本节将逐一拆解 TTBR0、TTBR1、SCTLR、DACR、PRRR/NMRR 这五个核心寄存器的位域定义与工程配置要点。

调试经验: 在 QNX 启动早期(如 startup 汇编阶段),MMU 通常处于关闭状态。一旦使能 MMU(SCTLR.M=1),所有取指和访存都将经过页表转换。因此,必须在使能前确保 TTBR0/TTBR1 指向有效的页表物理地址,且页表内容已正确初始化。

3.1 页表基址寄存器:TTBR0 与 TTBR1

TTBR0(Translation Table Base Register 0)和 TTBR1(Translation Table Base Register 1)分别存储一级页表的基地址。ARMv7-A 通过虚拟地址的高位决定使用哪个寄存器:若虚拟地址高位为 0,则使用 TTBR0;若为 1,则使用 TTBR1。这种机制允许操作系统为内核空间(高地址)和用户空间(低地址)维护独立的页表。

位域 名称 描述 工程注意事项
[31:14] BASE 一级页表基地址的高 18 位,页表必须 16KB 对齐 QNX 中通常将页表放在非缓存、非共享的内存区域,避免页表 walk 时产生缓存一致性问题
[13:7] RGN 页表内存区域属性(Outer 缓存策略) 建议配置为 0b01(Outer Write-Back, Write-Allocate),提高页表遍历性能
[6] NOS 非共享位(Not Outer Shareable) 单核系统可置 1;多核系统需根据页表共享策略设置
[5:4] IRGN Inner 缓存策略 推荐 0b11(Write-Back, Read-Allocate, Write-Allocate)
[3:1] SH 可共享属性(Shareability) 0b00 非共享;0b11 内外共享。多核 IPC 区域必须设为共享
[0] PD0/PD1 页表遍历禁止位(TTBR0 使用 PD0,TTBR1 使用 PD1) 置 1 时禁止使用该 TTBR 进行页表遍历,用于切换地址空间时临时隔离
QNX 典型配置: 在 startup 阶段,TTBR0 指向 1:1 映射的启动页表(物理地址 = 虚拟地址),TTBR1 指向内核高地址页表。切换至用户进程时,TTBR0 会更新为当前进程的用户页表,而 TTBR1 始终保持内核页表不变。
TTBR0 / TTBR1 地址空间划分与页表选择 虚拟地址空间 0x00000000 ~ 0xFFFFFFFF 分界点 低地址区域 (VA[31]=0) 高地址区域 (VA[31]=1) TTBR0 页表基址 TTBR1 页表基址 说明:硬件根据 VA[31] 自动选择 TTBR。QNX 内核位于高地址,用户进程位于低地址。 进程切换时只需更新 TTBR0,TTBR1 保持不变,避免内核页表重复加载。

3.2 系统控制寄存器:SCTLR

SCTLR(System Control Register)是 ARMv7-A 中最重要的控制寄存器之一,它控制着 MMU、缓存、对齐检查、分支预测等核心功能的使能状态。在 QNX 启动流程中,SCTLR 的配置顺序直接影响系统稳定性。

位域 名称 功能 QNX 推荐值
[0] M MMU 使能 1(使能)
[1] A 对齐检查使能 1(使能,捕获非对齐访问错误)
[2] C 数据缓存使能 1(使能)
[3] W 写缓冲使能 1(使能)
[11] Z 分支预测使能 1(使能,提升性能)
[12] I 指令缓存使能 1(使能)
[16] EE 端序控制(异常处理) 0(小端)
[22] U 非对齐访问支持 1(允许非对齐访问,但需配合对齐检查位)
[29] AFE 访问标志使能 0(禁用,QNX 不使用硬件访问标志)
[30] TE Thumb 异常使能 0(异常处理使用 ARM 指令集)
关键调试点: 在 QNX 中,如果 SCTLR.A(对齐检查)置 1 但 SCTLR.U(非对齐支持)未正确配置,某些驱动程序中的非对齐内存访问会触发 Data Abort 异常。调试时若遇到诡异的对齐错误,应首先检查这两个位的组合状态。
SCTLR 寄存器关键位域与 QNX 启动配置流程 SCTLR 32 位寄存器位域分布 M [0] C [2] I [12] A [1] U [22] AFE [29] Z [11] QNX 启动阶段 SCTLR 配置顺序: 1. 关闭 MMU (M=0) → 2. 初始化页表 → 3. 设置 TTBR0/TTBR1 → 4. 使能缓存 (C=1, I=1) 5. 使能对齐检查 (A=1) → 6. 使能 MMU (M=1) → 7. 使能分支预测 (Z=1)

3.3 域访问控制寄存器:DACR

DACR(Domain Access Control Register)为 ARMv7-A 的 16 个域(Domain)分别配置访问权限。每个域对应 2 位控制字段,决定该域内页表项所映射内存的访问模式。QNX 利用域机制实现内核与用户空间的快速隔离。

域编号 位域 编码 访问模式 QNX 典型用途
0 [1:0] 0b11 Manager(管理者) 内核关键内存区域,不检查页表权限位
1 [3:2] 0b01 Client(客户端) 用户进程内存区域,由页表项 AP 位控制权限
2 [5:4] 0b01 Client 设备寄存器映射区域
3~14 [29:6] 0b01 Client 其他内存区域
15 [31:30] 0b11 Manager 页表本身所在内存区域,避免递归权限检查
性能优化: 将内核核心区域(如中断向量表、页表基址)配置为 Manager 域(0b11),可以跳过页表项中的 AP 权限检查,减少页表 walk 的访问延迟。但需注意:Manager 域内的内存无法通过页表项设置只读保护,必须谨慎使用。
DACR 域访问控制与 QNX 域分配策略 域 0: Manager 域 1: Client 域 2: Client 域 15: Manager 域 3~14 内核关键区 用户进程 设备寄存器 页表自身 其他区域 DACR 编码规则: 0b00: 无访问(任何访问都产生域异常) 0b01: Client(由页表项 AP 位决定读写权限) 0b11: Manager(不检查页表 AP 位,允许所有访问)

3.4 主区域属性寄存器:PRRR 与 NMRR

PRRR(Primary Region Remap Register)和 NMRR(Normal Memory Remap Register)共同定义了内存区域的缓存策略与共享属性。ARMv7-A 使用页表项中的 TEX[2:0]、C、B 位组合索引 PRRR/NMRR,从而决定最终的内存类型(Strongly-Ordered、Device、Normal 等)以及 Write-Back/Write-Through 策略。

寄存器 位域宽度 功能 QNX 典型配置
PRRR 32 位,8 个 4 位字段 定义 TEX[2:0]/C/B 组合对应的内存类型和共享属性 PRRR=0xEEAA4400(典型值,支持 Normal/Device/Strongly-Ordered)
NMRR 32 位,8 个 4 位字段 定义 Normal 内存的 Inner/Outer 缓存策略 NMRR=0x40E040E0(Inner/Outer Write-Back, Write-Allocate)
常见错误: 在 QNX 中,如果 PRRR/NMRR 配置与页表项中的 TEX/C/B 编码不一致,会导致内存属性混乱。例如,将 Device 类型内存错误地配置为 Normal Write-Back,可能引发 DMA 缓存一致性问题。调试时建议使用 memmap -v 命令验证实际生效的内存属性。
PRRR/NMRR 与页表项 TEX/C/B 的映射关系 页表项 TEX[2:0] / C / B 5 位编码 → 索引 0~7 PRRR 内存类型 / 共享属性 NMRR Normal 缓存策略 最终内存属性 常见内存类型与 PRRR/NMRR 索引对应关系: 索引 0: Strongly-Ordered(TEX=000, C=0, B=0) 索引 4: Device(TEX=000, C=0, B=1) 索引 7: Normal Write-Back Write-Allocate(TEX=001, C=1, B=1)

3.5 寄存器配置综合示例

以下代码展示了 QNX startup 汇编阶段中,上述五个寄存器的典型配置序列。该代码片段通常位于 startup.S 或 board_init.S 中,在 MMU 使能之前执行。

@ QNX ARMv7-A MMU 寄存器初始化序列 (汇编)
@ 假设页表已位于 _page_table_base

    @ 1. 设置 TTBR0: 用户页表基址, Inner/Outer Write-Back, 共享
    LDR     r0, =_page_table_base
    ORR     r0, r0, #0x48          @ IRGN=0b10 (Write-Back), RGN=0b01 (Outer WB)
    ORR     r0, r0, #0x08          @ SH=0b01 (Inner Shareable)
    MCR     p15, 0, r0, c2, c0, 0  @ 写 TTBR0

    @ 2. 设置 TTBR1: 内核页表基址, 属性同上
    LDR     r0, =_kernel_page_table
    ORR     r0, r0, #0x48
    ORR     r0, r0, #0x08
    MCR     p15, 0, r0, c2, c0, 1  @ 写 TTBR1

    @ 3. 设置 DACR: 域0=Manager, 域1~14=Client, 域15=Manager
    LDR     r0, =0xC0000001        @ 域15=11b, 域0=01b, 其余默认0
    MCR     p15, 0, r0, c3, c0, 0  @ 写 DACR

    @ 4. 设置 PRRR 和 NMRR
    LDR     r0, =0xEEAA4400        @ PRRR 典型值
    MCR     p15, 0, r0, c10, c2, 0 @ 写 PRRR
    LDR     r0, =0x40E040E0        @ NMRR 典型值
    MCR     p15, 0, r0, c10, c2, 1 @ 写 NMRR

    @ 5. 设置 SCTLR: 使能 MMU, 缓存, 对齐检查, 分支预测
    MRC     p15, 0, r0, c1, c0, 0  @ 读 SCTLR
    ORR     r0, r0, #0x0001        @ M=1 (MMU 使能)
    ORR     r0, r0, #0x0004        @ C=1 (数据缓存)
    ORR     r0, r0, #0x1000        @ I=1 (指令缓存)
    ORR     r0, r0, #0x0002        @ A=1 (对齐检查)
    ORR     r0, r0, #0x0800        @ Z=1 (分支预测)
    BIC     r0, r0, #0x20000000    @ AFE=0 (禁用访问标志)
    MCR     p15, 0, r0, c1, c0, 0  @ 写 SCTLR

    @ 6. 同步屏障,确保配置生效
    DSB
    ISB
调试检查清单: 当 MMU 使能后系统立即崩溃时,按以下顺序排查寄存器配置:
1. TTBR0/TTBR1 的 BASE 位域是否指向有效的物理地址?
2. 页表所在内存是否配置为 Manager 域(DACR 域15)?
3. SCTLR.M 使能前,页表项是否已填充有效的下一级页表地址或块映射?
4. PRRR/NMRR 是否与页表项中的 TEX/C/B 编码一致?

3.6 寄存器配置错误案例分析

错误场景 现象 根因 解决方案
TTBR0 未 16KB 对齐 MMU 使能后立即触发 Undefined Instruction 异常 硬件忽略低位,实际页表基址错误 确保页表基址低 14 位为 0
DACR 域0 配置为 Client 内核访问页表时产生 Domain Fault 页表所在域未设为 Manager,权限检查失败 将页表所在域设为 0b11
PRRR 索引 7 配置为 Device Normal 内存性能急剧下降 页表项 TEX=001/C=1/B=1 被映射为 Device 类型 PRRR 索引 7 应配置为 Normal Write-Back
SCTLR.A=1 但 U=0 非对齐访问触发 Data Abort 对齐检查使能但非对齐支持未使能