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 异常级别与虚拟化截获路径 EL3 — Secure Monitor 安全世界与普通世界切换、SMC 调用、TrustZone 管理 EL2 — Hypervisor(虚拟化层) 截获 Guest 敏感操作、管理 Stage-2 页表、虚拟中断注入 EL1 — Guest OS 内核 / Host OS 内核 页表管理、中断处理、系统寄存器配置(部分被 EL2 截获) EL0 — 用户态应用程序 无特权指令、通过 SVC/HVC 陷入内核或 Hypervisor SVC HVC / 陷入 SMC 虚拟化核心:Guest 在 EL1 执行敏感操作 → 被 EL2 截获 → Hypervisor 模拟或转发

二、寄存器组:通用寄存器与特殊寄存器

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 的存在。这就是“内存虚拟化”的核心机制。

关键点:Stage-1 由 Guest OS 控制,Stage-2 由 Hypervisor 控制。两者组合后,Guest 看到的“物理地址”其实是中间物理地址 IPA,而非真正的 PA。

四、系统寄存器与指令集概览

AArch64 的系统寄存器通过 MRS/MSR 指令访问,命名格式为 寄存器名_ELx。虚拟化场景中,EL2 需要配置大量系统寄存器来控制 Guest 行为。下表列出后续章节高频使用的寄存器:

寄存器 所属层级 主要作用
HCR_EL2EL2控制 Guest 陷入行为,如是否启用 Stage-2、是否截获系统寄存器访问
VTCR_EL2EL2配置 Stage-2 页表转换参数(地址范围、粒度、起始层级)
VTTBR_EL2EL2指向 Stage-2 页表基址
SCTLR_EL1EL1Guest 的 MMU、缓存、对齐检查等全局控制
TTBR0_EL1 / TTBR1_EL1EL1Guest Stage-1 页表基址
VBAR_EL2EL2EL2 异常向量表基址
ESR_EL2EL2记录异常原因,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 范围。
学习建议:把 EL0–EL3 的层级关系、Stage-1/Stage-2 的转换路径、HCR_EL2 的截获控制这三条主线记牢,后续学习 vGIC、Stage-2 缺页异常和虚拟中断注入时会顺畅很多。