1. 课程导入

在云计算、智能汽车、移动终端与边缘计算快速融合的今天,虚拟化早已不再是x86服务器的专属能力。ARM架构通过一系列虚拟化扩展,把原本由Hypervisor软件模拟完成的关键操作下沉到硬件,使虚拟机监控器更轻、更快、更安全。本课程围绕ARM虚拟化扩展(ARM Virtualization Extensions)与EL2异常级别系统开发展开,目标是让你从"知道有EL2"进阶到"能设计、能编码、能调试一个运行在EL2的轻量Hypervisor"。

一、学习目标:从概念到可运行系统

本课程不是单纯罗列寄存器手册,而是以"能落地"为最终检验标准。完成学习后,你应当能够:

  • 解释ARMv8-A异常级别模型,说明EL0/EL1/EL2/EL3各自的职责与切换条件;
  • 掌握HCR_EL2、VTCR_EL2、VTTBR_EL2、ICH_*等核心寄存器的配置语义;
  • 理解Stage-2地址翻译机制,能独立配置两级页表并完成IPA到PA的映射;
  • 使用GICv3/vGIC完成虚拟中断的注入、维护与EOI处理;
  • 在EL2实现vCPU上下文保存恢复、异常向量表与陷入(trap)分发;
  • 能够定位常见的EL2启动失败、Stage-2缺页、中断丢失等问题。
核心判断标准:当Guest操作系统在EL1执行一条特权指令时,硬件是否按你的预期陷入EL2,并由你的代码正确模拟或转发——这是检验EL2系统是否真正跑通的分水岭。

二、核心概念:异常级别与虚拟化扩展

ARMv8-A定义了四个异常级别。EL0运行用户程序,EL1运行Guest内核或Host内核,EL2是虚拟化扩展的专属级别,EL3负责安全监控。虚拟化的本质,是让Guest内核"以为"自己运行在EL1,而实际的控制权掌握在EL2的Hypervisor手中。

支撑这一"错觉"的关键硬件能力包括:

  • Stage-2翻译:Guest的虚拟地址先经Stage-1(由Guest自己控制)得到中间物理地址IPA,再由EL2控制的Stage-2翻译为真实物理地址PA;
  • 陷入与模拟:通过HCR_EL2中的TGE、TSC、TWI等控制位,把敏感操作路由到EL2;
  • 虚拟中断:借助GICv3的List Register与ICH_*系统寄存器,向vCPU注入虚拟IRQ/FIQ;
  • vCPU上下文:EL2需要保存和恢复Guest的通用寄存器、系统寄存器与浮点/SIMD状态。

下面的SVG以结构关系图的形式,展示了从Guest应用一路到物理硬件的层级、地址翻译路径与陷入路径,帮助你建立整体空间感。

ARM虚拟化扩展:异常级别、地址翻译与陷入路径 EL0 · Guest 用户态 应用程序 / 库函数,使用虚拟地址 VA,无特权指令 VA EL1 · Guest 内核 页表基址 TTBR0_EL1 / TTBR1_EL1,Stage-1 翻译:VA → IPA IPA EL2 · Hypervisor(本课程核心) HCR_EL2 控制陷入 · VTCR_EL2 定义 Stage-2 页表 · VTTBR_EL2 指向 IPA→PA 映射 vCPU 上下文保存/恢复 · 异常向量表 · vGIC 虚拟中断注入 PA EL3 · Secure Monitor 安全世界切换、SCR_EL3 配置、SMC 调用入口 物理硬件 CPU 核心 · 内存 · GICv3 中断控制器 · 定时器 · MMU 陷入 虚拟中断 特权递增

三、整体知识框架与学习路径

课程内容按"由静到动、由单点到系统"的顺序组织,可分为五个层次:

  1. 基础层:ARMv8异常级别、系统寄存器命名规则、AArch64执行状态;
  2. 翻译层:Stage-1与Stage-2页表、IPA/PA、TLB与ASID/VMID;
  3. 控制层:HCR_EL2陷入策略、异常向量表、vCPU上下文切换;
  4. 中断层:GICv3架构、vGIC、List Register、虚拟中断生命周期;
  5. 系统层:启动流程、内存隔离、设备直通与性能调优。

建议的学习路径是:先建立异常级别与地址翻译的直觉,再动手写一个最小EL2启动代码,随后逐步加入Stage-2页表、vCPU切换和虚拟中断,最后完成一个可启动Guest的轻量Hypervisor。

四、典型场景与最小启动片段

假设我们要在QEMU或真实开发板上启动一个Guest Linux。EL2代码在启动阶段通常需要完成以下动作:设置异常向量表、配置HCR_EL2、建立Stage-2页表、初始化vGIC,然后通过ERET进入Guest的EL1入口。

/* 伪代码:EL2 初始化关键步骤 */
setup_vector_table();              /* 安装 EL2 异常向量 */
write_hcr_el2(HCR_TGE | HCR_TSC | HCR_TWI | HCR_VM);
write_vtcr_el2(VTCR_T0SZ | VTCR_SL0 | VTCR_IRGN0 | VTCR_ORGN0);
write_vttbr_el2(stage2_table_pa | VMID);
vgic_init();
set_elr_el2(guest_entry);
set_spsr_el2(SPSR_EL1h);
eret();                            /* 进入 Guest EL1 */
调试建议:在EL2异常向量入口处打印ESR_EL2、FAR_EL2和ELR_EL2,可以快速判断是Stage-2缺页、未定义指令还是中断注入失败。

五、常见误区与复盘要点

误区现象纠正思路
认为EL2只是"多一个级别"配置HCR_EL2后Guest仍直接访问硬件EL2的价值在于Stage-2翻译与陷入控制,必须同时配置页表和陷入位
混淆VA、IPA、PA页表填错,Guest启动即缺页Stage-1输出IPA,Stage-2输入IPA输出PA,两级页表职责不同
忽略VMID与TLB切换vCPU后地址翻译错乱不同Guest使用不同VMID,必要时执行TLB失效
虚拟中断只配GIC不配ICHGuest收不到中断需通过ICH_LR*写入List Register并设置HCR_EL2.IMO/FMO

复盘时请始终回到三个问题:这条指令应该由谁执行?这个地址应该由谁翻译?这个中断应该由谁递送?把这三个问题回答清楚,EL2系统的设计就不会偏离方向。