3. 虚拟化基本概念

在 ARM 虚拟化扩展与 EL2 系统开发中,理解虚拟化的基本概念是后续所有工作的基础。虚拟化本质上是一种资源抽象技术:它把物理硬件资源(CPU、内存、中断、外设)抽象成多个相互隔离的执行环境,让多个操作系统可以同时运行在同一台物理机器上。要掌握 ARM 上的虚拟化,必须先厘清几个核心术语及其相互关系。

一、虚拟机与 Hypervisor

虚拟机(Virtual Machine, VM)是由虚拟化层创建并管理的、具有独立 CPU、内存和外设视图的执行环境。每个虚拟机内部运行一个完整的操作系统,称为客户操作系统(Guest OS)。从 Guest OS 的视角看,它仿佛独占了一台计算机,但实际上它访问的是一组被虚拟化层截获并转发的虚拟资源。

Hypervisor(虚拟机监控器,VMM)是位于硬件与虚拟机之间的软件层,负责创建、调度、隔离和销毁虚拟机。它的核心职责包括:

  • CPU 虚拟化:为每个 vCPU 保存和恢复上下文,拦截敏感指令并模拟其行为。
  • 内存虚拟化:维护 Guest 虚拟地址到物理地址的映射,通常借助 Stage-2 页表实现。
  • 中断与外设虚拟化:将物理中断路由到正确的虚拟机,并模拟或直通外设。
  • 隔离与调度:保证虚拟机之间互不干扰,并公平分配物理资源。

在 ARM 架构中,Hypervisor 通常运行在 EL2(Exception Level 2),而 Guest OS 运行在 EL1,用户应用运行在 EL0。这种层级划分是 ARM 虚拟化扩展的核心设计。

二、Type-1 与 Type-2 虚拟化

根据 Hypervisor 在软件栈中的位置,虚拟化可分为两种类型:

  • Type-1(裸机型):Hypervisor 直接运行在物理硬件之上,不依赖宿主操作系统。它自己承担资源管理职责,性能开销小、实时性好,常见于服务器、嵌入式和汽车领域。典型代表有 Xen、KVM(在 ARM 上以 EL2 形式运行)、Jailhouse 等。
  • Type-2(宿主型):Hypervisor 作为宿主操作系统上的一个应用程序运行,依赖宿主 OS 提供驱动和资源管理。部署方便、生态成熟,但性能开销较大。典型代表有 QEMU、VirtualBox、VMware Workstation 等。

在 ARM 开发中,Type-1 更贴近硬件,能充分利用 EL2 的虚拟化扩展;Type-2 则常用于开发调试和功能验证阶段。

三、全虚拟化与半虚拟化

按照 Guest OS 是否需要感知自己被虚拟化,可分为:

  • 全虚拟化(Full Virtualization):Guest OS 无需修改,Hypervisor 通过二进制翻译或硬件辅助(如 ARM 的 HCR_EL2 陷阱机制)拦截敏感指令并模拟。优点是兼容性好,可直接运行未修改的操作系统;缺点是拦截和模拟带来性能损耗。
  • 半虚拟化(Paravirtualization):Guest OS 需要修改,主动配合 Hypervisor,通过 Hypercall 等机制发起 I/O 和特权操作。优点是性能更高、路径更短;缺点是需要修改 Guest 内核,兼容性受限。

现代 ARM 虚拟化通常采用混合策略:CPU 和内存使用硬件辅助的全虚拟化,I/O 则采用 virtio 等半虚拟化方案,兼顾兼容性与性能。

四、特权级与异常级关系

ARMv8-A 定义了四个异常级(Exception Level),它们与虚拟化角色紧密对应:

异常级 典型角色 虚拟化职责
EL0 用户应用 无特权,通过系统调用进入 EL1
EL1 Guest OS 内核 / Host OS 内核 管理 Guest 页表、处理 Guest 异常
EL2 Hypervisor 拦截敏感操作、管理 Stage-2 页表、路由中断
EL3 安全监控器(Secure Monitor) 负责安全世界与非安全世界切换

当 Guest OS 在 EL1 执行敏感指令(如访问系统寄存器、执行 WFI、修改页表基址)时,若 HCR_EL2 中相应陷阱位被置位,处理器会陷入 EL2,由 Hypervisor 模拟或转发。这就是 ARM 硬件辅助虚拟化的基本机制。

核心关系:EL2 是虚拟化的控制中枢,EL1 是 Guest 内核的运行级,EL0 是 Guest 应用的运行级。Hypervisor 通过配置 HCR_EL2、VTCR_EL2、VTTBR_EL2 等寄存器,控制 Guest 的行为并维护地址翻译。

五、典型场景与配置示例

下面以 KVM on ARM64 为例,展示 Hypervisor 启动 Guest 时的关键寄存器配置片段:

// 配置 HCR_EL2:启用 Stage-2 翻译,设置陷阱位
hcr_el2 = HCR_RW        // EL1 为 AArch64
        | HCR_VM        // 启用 Stage-2 地址翻译
        | HCR_IMO       // 路由 IRQ 到 EL2
        | HCR_FMO       // 路由 FIQ 到 EL2
        | HCR_TSC       // 陷阱 SMC 指令
        | HCR_TWE;      // 陷阱 WFE 指令

// 设置 VTTBR_EL2:指向 Stage-2 页表基址
vttbr_el2 = (vmid << 48) | stage2_pgd_pa;

// 设置 VTCR_EL2:Stage-2 翻译控制
vtcr_el2 = VTCR_T0SZ(32)   // 输入地址 32 位
         | VTCR_SL0(1)     // 起始层级
         | VTCR_IRGN0(1)   // 内部写回缓存
         | VTCR_ORGN0(1);  // 外部写回缓存

// 进入 Guest:设置 ELR_EL2 和 SPSR_EL2 后执行 eret
elr_el2 = guest_entry;
spsr_el2 = SPSR_EL1h;      // 目标为 EL1h
asm volatile("eret");

这段代码体现了 Hypervisor 如何通过 EL2 寄存器控制 Guest 的执行环境。理解这些寄存器的含义,是后续开发 EL2 系统的基础。

六、常见误区与复盘

误区一:认为 Type-1 一定比 Type-2 快。实际上,若 Type-2 的宿主 OS 驱动优化良好,某些 I/O 场景下性能差距并不明显,关键取决于具体负载和硬件辅助能力。

误区二:把全虚拟化等同于“不需要修改 Guest”。全虚拟化确实不需要修改 Guest OS,但 Hypervisor 需要做大量指令拦截和模拟,性能开销可能高于半虚拟化。

误区三:混淆 EL2 与 EL3 的职责。EL2 负责虚拟化,EL3 负责安全世界切换,两者目标不同,不能互相替代。

复盘建议:在学习 ARM 虚拟化时,建议先画出 EL0/EL1/EL2/EL3 的层级图,再标注每个层级能访问的寄存器和指令,最后结合 HCR_EL2 的陷阱位理解“什么情况下会陷入 EL2”。这样能把抽象概念转化为可操作的调试思路。

ARMv8-A 异常级与虚拟化角色关系 EL3 安全监控器(Secure Monitor) 负责安全世界与非安全世界切换,不直接参与虚拟化 EL2 Hypervisor(虚拟机监控器) 拦截敏感指令 · 管理 Stage-2 页表 · 路由中断 · 调度 vCPU 关键寄存器:HCR_EL2 · VTCR_EL2 · VTTBR_EL2 · ELR_EL2 EL1 Guest OS 内核 管理 Guest 页表 · 处理 Guest 异常 执行敏感指令时可能陷入 EL2 EL1 Host OS 内核(Type-2 场景) 提供驱动与资源管理 承载 Type-2 Hypervisor 应用 EL0 Guest 用户应用 通过系统调用进入 EL1 EL0 Host 用户应用 如 QEMU 进程(Type-2) 陷阱/陷入 Hypercall 系统调用 系统调用 EL3 安全监控 EL2 Hypervisor EL1 内核 EL0 应用 陷阱路径

通过本节的学习,应当建立起“虚拟机—Hypervisor—异常级”三位一体的认知框架:虚拟机是被隔离的执行环境,Hypervisor 是运行在 EL2 的管理者,异常级则提供了硬件层面的权限划分与陷阱机制。Type-1/Type-2 决定了 Hypervisor 的部署形态,全虚拟化/半虚拟化决定了 Guest 的配合程度,而 EL0~EL3 的层级关系则决定了指令与寄存器的访问权限。这些概念相互交织,构成了 ARM 虚拟化扩展的完整图景。