2. ARM架构基础回顾
要理解 ARM 虚拟化扩展,必须先回到 AArch64 的基础模型。虚拟化并不是凭空增加的一套机制,而是把原本为操作系统设计的异常级别、寄存器、内存访问与系统寄存器体系,扩展出“可被 Hypervisor 截获、路由和隔离”的能力。本节把后续章节反复用到的五个基础概念串起来:异常级别(Exception Level)、寄存器组、内存模型、系统寄存器与指令集。
一、异常级别:AArch64 的特权分层
AArch64 定义了 EL0 到 EL3 四个异常级别,级别越高特权越大。EL0 是用户态,EL1 通常运行 Guest OS 内核,EL2 是虚拟化层(Hypervisor),EL3 是安全监控层(Secure Monitor)。虚拟化的关键就在于:Guest OS 以为自己运行在 EL1,但实际上它的敏感操作会被 EL2 截获。
每个异常级别都有独立的执行状态、栈指针和异常向量表。当发生异常时,处理器会保存当前上下文并跳转到目标 EL 的向量表入口。EL2 的存在使得 Hypervisor 可以在不修改 Guest OS 的前提下,拦截对系统寄存器、内存和中断的访问。
二、寄存器组:通用寄存器与特殊寄存器
AArch64 提供 31 个 64 位通用寄存器 X0–X30,以及零寄存器 XZR。其中 X0–X7 用于参数传递和返回值,X8 常用于系统调用号,X29 为帧指针,X30 为链接寄存器(LR)。此外还有 SP(栈指针)和 PC(程序计数器),它们不是通用寄存器,不能直接参与大多数算术运算。
与虚拟化密切相关的还有几类特殊寄存器:PSTATE 保存处理器状态标志;SPSR_ELx 在异常进入时保存被中断的 PSTATE;ELR_ELx 保存异常返回地址。当 Guest 发生异常陷入 EL2 时,硬件会自动把 Guest 的 PSTATE 和 PC 分别保存到 SPSR_EL2 和 ELR_EL2,Hypervisor 据此可以精确恢复 Guest 执行。
三、内存模型:地址空间与页表层级
AArch64 采用多级页表管理虚拟地址到物理地址的转换。典型配置为 4KB 页、48 位虚拟地址、4 级页表(Level 0–Level 3)。TTBR0_ELx 和 TTBR1_ELx 分别管理低地址和高地址空间,TCR_ELx 控制地址范围与页表粒度,SCTLR_ELx 控制 MMU、缓存和对齐检查等全局行为。
虚拟化扩展在此基础上引入了 Stage-2 转换:Guest OS 维护 Stage-1 页表(VA→IPA),Hypervisor 维护 Stage-2 页表(IPA→PA)。CPU 在访问内存时自动完成两级转换,Guest 完全感知不到 Stage-2 的存在。这就是“内存虚拟化”的核心机制。
四、系统寄存器与指令集概览
AArch64 的系统寄存器通过 MRS/MSR 指令访问,命名格式为 寄存器名_ELx。虚拟化场景中,EL2 需要配置大量系统寄存器来控制 Guest 行为。下表列出后续章节高频使用的寄存器:
| 寄存器 | 所属层级 | 主要作用 |
|---|---|---|
| HCR_EL2 | EL2 | 控制 Guest 陷入行为,如是否启用 Stage-2、是否截获系统寄存器访问 |
| VTCR_EL2 | EL2 | 配置 Stage-2 页表转换参数(地址范围、粒度、起始层级) |
| VTTBR_EL2 | EL2 | 指向 Stage-2 页表基址 |
| SCTLR_EL1 | EL1 | Guest 的 MMU、缓存、对齐检查等全局控制 |
| TTBR0_EL1 / TTBR1_EL1 | EL1 | Guest Stage-1 页表基址 |
| VBAR_EL2 | EL2 | EL2 异常向量表基址 |
| ESR_EL2 | EL2 | 记录异常原因,Hypervisor 据此判断陷入类型 |
指令集方面,AArch64 采用固定 32 位指令长度,主要类别包括:数据处理指令(ADD、SUB、AND 等)、加载存储指令(LDR、STR)、分支指令(B、BL、BR)、系统指令(MRS、MSR、SVC、HVC、SMC)以及异常返回指令(ERET)。其中 HVC 用于 Guest 主动调用 Hypervisor,SMC 用于进入 EL3,ERET 用于从异常返回并恢复 PSTATE。
五、案例场景:一次 Guest 系统寄存器访问的完整路径
假设 Guest OS 在 EL1 执行 MSR TTBR0_EL1, X0 更新页表基址。若 Hypervisor 在 HCR_EL2 中设置了对应截获位,硬件不会直接写入 TTBR0_EL1,而是产生异常陷入 EL2。EL2 的异常向量表被触发,ESR_EL2 记录陷入原因,Hypervisor 读取 ESR_EL2 判断是系统寄存器访问陷入,然后模拟写入或转发到真实寄存器,最后通过 ERET 返回 Guest。整个过程 Guest 无感知。
// 伪代码:EL2 处理系统寄存器陷入
read ESR_EL2 // 获取异常原因
if (ISS 表明是 MSR/MRS 陷入) {
decode Rt, CRn, Op0, Op1, CRm, Op2
if (目标寄存器需要模拟)
emulate_write(reg, value);
else
forward_to_hardware(reg, value);
}
ELR_EL2 += 4; // 跳过陷入指令
ERET; // 返回 Guest
六、常见误区与复盘
- 误区一:认为 EL2 只在 Guest 运行时才存在。实际上 EL2 是常驻的,Host OS 也可能运行在 EL1,EL2 始终负责虚拟化控制。
- 误区二:把 Stage-2 页表当成普通页表。Stage-2 的输入是 IPA 而非 VA,且其格式与 Stage-1 不完全相同,配置时需注意 VTCR_EL2 的粒度与起始层级。
- 误区三:忽略 SPSR_EL2 和 ELR_EL2 的保存与恢复。异常返回时若未正确恢复,Guest 会跑飞或状态错乱。
- 复盘建议:调试虚拟化问题时,优先检查 HCR_EL2 的截获位配置、ESR_EL2 的异常原因字段,以及 Stage-2 页表映射是否覆盖 Guest 访问的 IPA 范围。