4、页表配置寄存器详解:TCR_EL1、MAIR_EL1、SCTLR_EL1 中与 MMU/页表相关的位域

ARMv8-A 体系结构中,MMU 的初始化与页表配置依赖于三个核心系统寄存器:TCR_EL1(Translation Control Register)、MAIR_EL1(Memory Attribute Indirection Register)和 SCTLR_EL1(System Control Register)。这三个寄存器共同决定了虚拟地址到物理地址的翻译规则、内存属性以及 MMU 的全局使能状态。本章将逐一拆解其中与页表配置直接相关的位域,并结合实际调试场景进行说明。

4.1 TCR_EL1:翻译控制寄存器

TCR_EL1 控制 EL1 阶段(Stage 1)的地址翻译参数,包括输入地址大小、输出物理地址大小、页粒度、缓存策略以及 ASID 管理。其关键位域如下表所示:

位域 名称 功能描述 典型配置值
[37:32] IPS 中间物理地址大小(Intermediate Physical Address Size),决定 PA 范围 0b101(48位,256TB)
[31:30] TG1 TTBR1 粒度的编码(0=4KB,1=64KB,2=16KB) 0b00(4KB)
[29:28] SH1 TTBR1 对应的共享属性(00=非共享,01=预留,10=外设共享,11=内部共享) 0b11(内部共享)
[27:26] ORGN1 TTBR1 对应的外部缓存策略(00=非缓存,01=写通,10=写回,11=写回+分配) 0b11(写回+读分配写分配)
[25:24] IRGN1 TTBR1 对应的内部缓存策略(编码同 ORGN1) 0b11(写回+分配)
[23:22] EPD1 TTBR1 页表遍历使能(0=使能,1=禁止) 0b0(使能)
[21:16] T1SZ TTBR1 区域地址空间大小(64 - T1SZ = 有效虚拟地址位数) 0b100000(32位,即 64-32=32)
[15:14] TG0 TTBR0 粒度的编码(同 TG1) 0b00(4KB)
[13:12] SH0 TTBR0 对应的共享属性 0b11(内部共享)
[11:10] ORGN0 TTBR0 对应的外部缓存策略 0b11(写回+分配)
[9:8] IRGN0 TTBR0 对应的内部缓存策略 0b11(写回+分配)
[7] EPD0 TTBR0 页表遍历使能 0b0(使能)
[5:0] T0SZ TTBR0 区域地址空间大小(同 T1SZ 编码) 0b100000(32位)
调试提示: 在调试页表配置时,T0SZ 和 T1SZ 是最容易出错的位域。如果虚拟地址范围设置过小(T0SZ 值过大),会导致高地址访问触发 Translation Fault。建议在初始化阶段打印 TCR_EL1 的值,并与预期配置进行逐位比对。

下图展示了 TCR_EL1 中 T0SZ/T1SZ 如何决定虚拟地址的翻译范围,以及 TG0/TG1 如何影响页表层级数:

TCR_EL1 地址范围与粒度控制逻辑 TTBR0 区域 T0SZ = 32 → VA[31:0] TG0 = 4KB → 4级页表 TTBR1 区域 T1SZ = 32 → VA[63:32] TG1 = 4KB → 4级页表 地址空间分割 关键约束 • T0SZ + T1SZ ≤ 64,且两者之和决定了 VA 空间划分点 • TG0/TG1 必须与页表描述符中的粒度一致,否则产生粒度错误 • 典型配置:T0SZ=25(39位VA)、T1SZ=25(39位VA),覆盖整个 512GB 空间

4.2 MAIR_EL1:内存属性间接寄存器

MAIR_EL1 用于定义最多 8 个内存属性区域(Attribute Index 0~7),每个区域占用 8 位,编码了该区域的类型(Normal/Device)以及缓存策略(Write-Back/Write-Through/Non-Cacheable)。页表描述符中的 AttrIndx[2:0] 字段直接索引 MAIR_EL1 中的属性配置。

MAIR_EL1 的 64 位布局如下:

位域 索引 典型配置值 内存属性含义
[63:56] Attr7 0xFF Normal Memory, Write-Back, Read/Write Allocate
[55:48] Attr6 0x44 Device-nGnRE(非聚集、非重排、提前写确认)
[47:40] Attr5 0x00 Device-nGnRnE(最严格的 Device 类型)
[39:32] Attr4 0xBB Normal Memory, Write-Back, 不分配
[31:24] Attr3 0x88 Normal Memory, Non-Cacheable
[23:16] Attr2 0x00 (未使用)
[15:8] Attr1 0x00 (未使用)
[7:0] Attr0 0x00 (未使用)
编码规则: 每个 8 位属性字段的高 4 位定义类型(0b0000=Device, 0b1111=Normal),低 4 位定义缓存策略。例如 0xFF = 0b1111_1111 表示 Normal + 内部/外部都写回并分配;0x44 = 0b0100_0100 表示 Device-nGnRE。

下图展示了页表描述符如何通过 AttrIndx 字段索引 MAIR_EL1 中的属性配置:

MAIR_EL1 属性索引机制 页表描述符 AttrIndx[2:0] = 0b110 (索引值 = 6) MAIR_EL1 (64-bit) Attr0 Attr1 Attr2 Attr3 Attr4 Attr5 Attr6 Attr7 ← 选中 Attr6 Attr6 配置示例 MAIR_EL1[55:48] = 0x44 高4位=0b0100 → Device-nGnRE 低4位=0b0100 → 外部属性 nRE

4.3 SCTLR_EL1:系统控制寄存器中的 MMU 相关位域

SCTLR_EL1 是系统控制的核心寄存器,其中与 MMU 和页表直接相关的位域包括 M、C、I、WXN、UWXN 等。这些位域控制 MMU 的全局使能、缓存策略以及内存访问权限。

位域 名称 功能描述 典型配置
[0] M MMU 使能位(0=禁用,1=使能) 1(使能)
[2] C 数据缓存使能(0=禁用,1=使能) 1(使能)
[3] SA 栈对齐检查(0=禁用,1=使能) 0(禁用)
[12] I 指令缓存使能(0=禁用,1=使能) 1(使能)
[19] WXN 写权限不可执行(0=允许,1=禁止可写页面执行) 1(禁止)
[21] UWXN 用户写权限不可执行(0=允许,1=禁止用户可写页面执行) 1(禁止)
[25] EE 异常字节序(0=小端,1=大端) 0(小端)
[28] nTWE 陷阱 WFE(0=不陷阱,1=陷阱) 0(不陷阱)
[29] nTWI 陷阱 WFI(0=不陷阱,1=陷阱) 0(不陷阱)
关键注意事项: 修改 SCTLR_EL1 的 M 位(MMU 使能)时,必须确保当前执行的代码位于与 MMU 使能后相同的映射区域,否则会导致立即跳转失败。通常的做法是:先配置页表并写入 TTBR0_EL1/TTBR1_EL1,然后执行 ISB 指令,最后修改 SCTLR_EL1 的 M 位,并紧跟一个 ISB + DSB 序列。

下图展示了 SCTLR_EL1 中 MMU 相关位域如何协同工作:

SCTLR_EL1 MMU 相关位域协同关系 SCTLR_EL1 M 位 (bit 0) MMU 全局使能 C 位 (bit 2) 数据缓存使能 WXN 位 (bit 19) 写权限不可执行 使能顺序:配置 TCR_EL1 + MAIR_EL1 → 写入 TTBR0_EL1/TTBR1_EL1 → ISB → 置位 SCTLR_EL1.M → ISB + DSB

4.4 寄存器配置的典型初始化流程

在实际工程中,MMU 初始化通常遵循以下步骤。每一步都涉及上述寄存器的特定位域:

  1. 设置 MAIR_EL1:定义 8 个内存属性区域,包括 Normal Cacheable、Device 等。
  2. 设置 TCR_EL1:配置 T0SZ/T1SZ、TG0/TG1、IPS 以及缓存策略。
  3. 写入 TTBR0_EL1 / TTBR1_EL1:将页表基地址写入对应寄存器。
  4. 执行 ISB:确保之前的配置指令完成。
  5. 设置 SCTLR_EL1:置位 M、C、I 位,使能 MMU 和缓存。
  6. 执行 ISB + DSB:确保 MMU 使能生效。
调试技巧: 在步骤 5 之前,可以通过读取 TCR_EL1 和 MAIR_EL1 来验证配置是否正确。使用 mrs x0, tcr_el1 和 mrs x0, mair_el1 指令读取,并与预期值比对。常见错误包括 T0SZ 设置过大导致高地址翻译失败,以及 MAIR_EL1 中 AttrIndx 索引超出已定义范围。

以下是一个典型的初始化代码片段(ARM64 汇编):

// 配置 MAIR_EL1
ldr x0, =0xBBFF4400          // Attr0=0x00, Attr1=0x00, Attr2=0x00, Attr3=0x88
                             // Attr4=0xBB, Attr5=0x44, Attr6=0xFF, Attr7=0x00
msr mair_el1, x0

// 配置 TCR_EL1
ldr x0, =0x80803520          // T0SZ=32, TG0=4KB, IPS=48bit
                             // T1SZ=32, TG1=4KB, 内外缓存写回+分配
msr tcr_el1, x0

// 写入 TTBR0_EL1(页表基地址在 x1 中)
msr ttbr0_el1, x1

// 执行 ISB 确保配置完成
isb

// 使能 MMU、数据缓存、指令缓存
mrs x0, sctlr_el1
orr x0, x0, #(1 << 0)       // 置位 M 位
orr x0, x0, #(1 << 2)       // 置位 C 位
orr x0, x0, #(1 << 12)      // 置位 I 位
msr sctlr_el1, x0

// 执行 ISB + DSB 确保使能生效
isb
dsb sy

4.5 常见配置错误与调试方法

错误现象 可能原因 排查方法
Translation Fault T0SZ/T1SZ 设置错误,或页表描述符无效 检查 TCR_EL1 的 T0SZ/T1SZ 是否与 VA 范围匹配
Permission Fault 页表描述符中的 AP 位与 SCTLR_EL1 的 WXN 冲突 检查 WXN 位是否置位,以及页表 AP 字段
Alignment Fault TTBR0_EL1 未按页大小对齐 确保 TTBR 基地址低 12 位为 0
Cache Coherency 问题 MAIR_EL1 中 Normal 与 Device 属性混用不当 检查 AttrIndx 索引是否指向正确的 MAIR 槽
MMU 使能后立即崩溃 SCTLR_EL1.M 使能前未执行 ISB 在修改 SCTLR_EL1 前后添加 ISB
工程建议: 在调试初期,建议先使用 Identity Mapping(虚拟地址 = 物理地址)来简化问题。此时 T0SZ 设置为 64 - 物理地址位数,页表描述符中的输出地址与输入地址相同。这样可以快速验证 MMU 使能流程,再逐步切换到非恒等映射。