1. AArch64内存管理基础概念
在Armv8/9架构中,内存管理单元(MMU)负责将程序使用的虚拟地址(VA)转换为物理地址(PA)。这种转换机制使得操作系统能够实现内存隔离、权限控制和地址空间抽象等关键功能。AArch64架构采用基于页表的地址转换机制,其核心组件包括:
- 转换表基址寄存器(TTBR):存储页表基地址,EL3仅使用TTBR0_EL3
- 内存属性间接寄存器(MAIR):定义内存类型(如Normal/Device)和缓存策略
- 转换控制寄存器(TCR):配置地址空间大小、页表粒度和缓存属性
- 系统控制寄存器(SCTLR):全局控制MMU和缓存使能
关键点:AArch64支持4KB、16KB和64KB三种页粒度,本文以最常见的4KB配置为例。选择4KB粒度时,单级页表可管理1GB块,二级页表可管理2MB块,三级页表则对应4KB页。
2. 单级页表配置实践
2.1 页表内存分配
在裸机环境中,我们需要手动分配并初始化页表。对于4KB粒度的单级页表(L1),需要4KB对齐的连续内存空间:
.section TT,"ax" .align 12 /* 4KB对齐 (2^12=4096) */ .global tt_l1_base tt_l1_base: .fill 4096, 1, 0 /* 填充4KB零值 */技术细节:
- 每个L1表项占8字节,4KB空间可容纳512个表项
- 零值表项表示无效区域(触发fault)
- 对齐要求来自硬件规范,未对齐访问会导致异常
2.2 MAIR属性配置
MAIR_EL3通过8位索引定义内存类型,典型配置如下:
MOV x0, #0x000000000000FF44 /* 索引0:Non-Cacheable 索引1:WBWA 索引2:Device-nGnRnE */ MSR MAIR_EL3, x0各字段含义:
- 0x44 (b01000100):Normal内存,内外均无缓存
- 0xFF (b11111111):Normal内存,回写式缓存(Write-Back)
- 0x00 (b00000000):严格设备内存(nGnRnE)
2.3 TCR寄存器配置
TCR_EL3控制转换参数,关键位域设置:
MOV x0, #0x19 /* T0SZ=25 (64-25=39位VA空间) */ ORR x0, x0, #(0x1 << 8) /* IRGN0=01 (内缓存WBWA) */ ORR x0, x0, #(0x1 << 10)/* ORGN0=01 (外缓存WBWA) */ ORR x0, x0, #(0x3 << 12)/* SH0=11 (内部共享) */ MSR TCR_EL3, x0配置解析:
- 39位VA空间(512GB)正好可由单级L1表覆盖
- 缓存策略需与MAIR设置匹配
- Shareable属性对多核系统至关重要
2.4 页表项构造
L1表项模板定义示例:
.equ TT_S1_NORMAL_WBWA, 0x405 /* AF=1, SH=00, AP=00, NS=0, INDX=01 */位域分解:
- [1:0]:块描述符类型(b01)
- [4:2]:MAIR索引(b001对应索引1)
- [6]:NS位(安全状态)
- [10]:AF(Access Flag)
- [8:7]:AP(访问权限)
2.5 典型映射场景
映射3GB地址空间的代码实现:
LDR x1, =tt_l1_base /* 0x00000000-0x3FFFFFFF: Device */ LDR x0, =TT_S1_DEVICE_nGnRnE STR x0, [x1] /* 0x40000000-0x7FFFFFFF: Device */ LDR x0, =TT_S1_DEVICE_nGnRnE ORR x0, x0, #0x40000000 STR x0, [x1, #8] /* 0x80000000-0xBFFFFFFF: Normal WBWA */ LDR x0, =TT_S1_NORMAL_WBWA ORR x0, x0, #TT_S1_INNER_SHARED ORR x0, x0, #0x80000000 STR x0, [x1, #16]3. 多级页表配置实践
3.1 二级页表结构
当需要更细粒度(如2MB)映射时,需引入L2页表:
Virtual Address Space: ┌─────────────┐ │ L1 Table │───┐ └─────────────┘ │ ┌──────▼──────┐ │ L2 Table │───▶ 2MB Blocks └─────────────┘内存分配需包含L1和L2表:
.align 12 tt_l1_base: .fill 4096, 1, 0 tt_l2_base: .fill 4096, 1, 0 /* 二级表同样4KB对齐 */3.2 L1表项配置
指向L2表的特殊表项格式:
LDR x2, =tt_l2_base LDR x0, =TT_S1_TABLE /* 表描述符模板 */ ORR x0, x0, x2 /* 组合L2表基址 */ STR x0, [x1, #16] /* 写入L1表第三项 */关键区别:
- 描述符类型位[1:0]=b11(页表描述符)
- 地址字段指向下级页表物理地址
- 其他属性位对下级表无效
3.3 L2表项配置
L2表管理2MB块,属性设置与L1类似:
LDR x1, =tt_l2_base LDR x0, =TT_S1_NORMAL_WBWA ORR x0, x0, #TT_S1_INNER_SHARED ORR x0, x0, #0x80000000 /* 物理地址 */ STR x0, [x1] /* 首项映射0x80000000-0x801FFFFF */性能考量:
- 每个L2表可管理1GB空间(512×2MB)
- 按需填充表项可节省内存
- 常用区域应预加载以减少TLB miss
4. MMU启用与调试
4.1 启用流程
完整启用序列:
/* 1. 无效化TLB */ TLBI ALLE3 DSB SY ISB /* 2. 设置SCTLR */ MOV x0, #(1 << 0) /* M=1 (MMU enable) */ ORR x0, x0, #(1 << 2) /* C=1 (数据缓存) */ ORR x0, x0, #(1 << 12) /* I=1 (指令缓存) */ MSR SCTLR_EL3, x0 ISB /* 确保MMU生效 */关键步骤:
- 清除旧TLB条目避免误匹配
- 按顺序启用MMU和缓存
- 屏障指令保证时序正确性
4.2 调试技巧
通过模拟器(如Arm FVP)观察TLB行为:
TTW ITLB LPAE 1:1 80002010 0000000080000705 : BLOCK ATTRIDX=1 NS=0 AP=0 SH=3 AF=1 ADDR=0x0000000080000000日志解读:
- TTW:表遍历(Table Walk)
- 1:1:L1表查询
- 0x80002010:表项地址
- 0x80000705:表项内容
- 属性字段与MAIR/TCR设置对应
5. 实战经验与优化
5.1 页表设计原则
粒度选择:
- 大块(1GB):适合外设区域和固定内存
- 中块(2MB):通用内存区域
- 小块(4KB):需要精细管理的区域
属性配置:
- 设备内存必须标记为nGnRnE/nGnRE
- 可缓存区域设置正确的shareability域
- 敏感区域配置适当的AP权限位
性能优化:
- 热点区域使用大页减少TLB压力
- 相邻相同属性区域使用Contiguous位
- 预加载关键页表项到TLB
5.2 常见问题排查
问题1:启用MMU后立即触发abort
- 检查页表基址是否4KB对齐
- 确认TLB已正确无效化
- 验证SCTLR.M位是否成功设置
问题2:设备访问出错
- 确认MAIR设备类型索引正确
- 检查页表项NS位与安全状态匹配
- 验证AP权限位是否允许当前访问
问题3:多核缓存一致性问题
- 确保shareability属性配置正确
- 关键数据使用cache维护指令
- 考虑使用inner/outer缓存策略组合
6. Armv9特性扩展
虽然本文示例基于pre-Armv9架构,但需要注意新特性影响:
- FEAT_S1PIE:改变权限检查模型
- FEAT_THE:支持分层权限控制
- FEAT_RME:引入GPT(Granule Protection Table)
在移植到Armv9平台时,需查阅最新架构参考手册确认寄存器位域变化。例如,SCTLR_EL3.EE位在Armv9中已废弃,改用系统寄存器控制端序。