armv8虚拟化扫盲
armv8虚拟化扫盲
虚拟化概述
根据虚拟化实现方式不同,分为软件虚拟化和硬件虚拟化
软件虚拟化之qemu
- qemu也可以使用type2级别的硬件虚拟化配合,如果没有kvm硬件加速支持,qemu可以纯粹的软件虚拟化
qemu采用TCG中间指令格式,将guest os的指令翻译成TCG指令,然后再将TGC指令翻译成host os的指令
硬件虚拟化
type1虚拟化
type1虚拟化是hypervisor直接运行到硬件上,管理所有的硬件资源和虚拟机,
框图如下:
这种方式存在一个问题,就是hypervisor需要实现所有设备驱动,开发工作大
type2虚拟化
type2虚拟化中的hypervisor运行在host os上,host os负责管理硬件资源,而hypervisor作为host os的组件
这种方式的问题是:
由于host os EL1和hypervisor EL2处于不同异常等级,需要通过异常方式实现系统调用,效率比type1低
解决方案:
目前armv8.1通过vhe扩展支持,使得host os和hypervisor都运行在EL2,通过函数直接调用,提高了效率
半虚拟化
- 提出原因:
全虚拟化的guest os不需要修改任何代码,执行方式和真实硬件基本一致。但是涉及到IO操作每次都需要返回到hypervisor,效率较低
- 解决方案:virtio+
定义了guest os驱动与hypervisor中模拟设备之间的io数据通信协议,通过通道的方式管理它们之间的数据传输,从而避免了频繁的IO操作
armv8虚拟化实现支持
虚拟化需要对:cpu 内存 iO设备 中断控制器以及timer等提供虚拟化实现
虚拟化方面 | 关键技术 | 作用 |
---|---|---|
CPU 虚拟化 | EL2 异常等级、敏感指令捕获、虚拟寄存器 | 解决特权操作模拟问题,提高性能 |
内存虚拟化 | 影子页表、两级页表、VMID | 解决内存地址转换问题,提高效率和性能 |
IO 虚拟化 | 设备地址模拟、缺页异常处理 | 实现设备访问模拟 |
DMA 虚拟化 | SMMU | 解决 DMA 地址转换问题 |
中断虚拟化 | GICv3 虚拟中断注入 | 简化中断注入流程,提高效率 |
定时器虚拟化 | 虚拟和物理定时器、计数器 | 确定共享 CPU 下定时器触发时间 |
cpu虚拟化
armv8提供了4个异常等级,应用程序运行在EL0,guest os运行在EL1,hypervisor运行在EL2,图示如下:
对于一般的指令,guest os无须陷入EL2,但是对于硬件状态相关的操作,仍需要陷入EL2进行处理,armv8提供了hcr_el2寄存器进行配置:
hcr_el2控制寄存器:
(a) 虚拟化基础配置
VM (Virtualization MMU)
- 当置1时,启用第二阶段地址转换(Stage 2 Translation),即Hypervisor为VM提供独立的内存映射。
RW (Register Width)
控制EL1的执行状态:
-
RW=1
:EL1运行在AArch64模式。 -
RW=0
:EL1运行在AArch32模式。
-
(b) 异常与中断路由
TGE (Trap General Exceptions)
TGE=1
时,EL0的所有异常(如系统寄存器访问)被路由到EL2。常用于容器化场景。
IMO/FMO/AMO (Interrupt Routing)
- IMO=1:将物理IRQ中断路由到EL2。
- FMO=1:将物理FIQ中断路由到EL2。
- AMO=1:将物理SError(系统错误)中断路由到EL2。
VI/VF (Virtual Interrupts)
- VI=1:向VM注入虚拟IRQ中断。
- VF=1:向VM注入虚拟FIQ中断。
(c) 指令与操作捕获
TIDCP (Trap ID Co-processor)
- 置1时,捕获EL1的某些缓存/TLB维护指令(如
IC IVAU
),陷入EL2处理,确保VM隔离性。
- 置1时,捕获EL1的某些缓存/TLB维护指令(如
DC (Data Cache Control)
- 控制数据缓存操作(如
DC CIVAC
)是否被捕获。
- 控制数据缓存操作(如
TID[0-4] (Trap ID Registers)
捕获对特定系统寄存器的访问。例如:
- TID3=1:捕获
CTR_EL0
(缓存类型寄存器)的访问。 - TID4=1:捕获对调试寄存器的访问(如
MDSCR_EL1
)。
- TID3=1:捕获
(d) 内存与调试
PTW (Protected Table Walk)
- 置1时,禁止页表遍历(Page Table Walk)使用非安全内存,增强安全性。
TD (Trap Debug)
- 置1时,将EL1的调试事件(如断点)路由到EL2。
系统寄存器捕获和虚拟寄存器支持
部分系统寄存器在 hypervisor 和 guest os 视角不同,如 ID_AA64MMFR0_EL1。访问频率低的寄存器,hypervisor 捕获访问并提供虚拟值;访问频率高的寄存器,如为MIDR_EL1定义了VMIDR_EL2,为MPIDR_EL1定义了VMPIDR_EL2。hypervisor在切换到vcpu之前其值写入这些虚拟寄存器中,当guest os访问MIDR_EL1时,其实际获取到的即为VMIDR_EL2中的值。通过以上方式,guest os对这类寄存器的访问将不再需要触发异常
vhe支持
vhe主要是为了支持在type2虚拟化下,将host os和hypervisor都运行在EL2中,以提高hypervisor和虚拟机之间的切换代价。其主要包含以下特性:
vhe提出原因: 在type2虚拟化中,对于没有vhe支持的armv8,host os运行在EL1,hypervisor运行在EL2,处于不同异常等级,切换效率较低
vhe特性如下:
- 增加了ttbr1_el2寄存器对ASDI(ASID是Address Space Identifier,每个进程拥有独立的虚拟地址空间,传统上下文切换需清空TLB(否则不同进程的地址映射会冲突)。ASID为每个进程分配唯一标识符,使TLB可同时缓存多个地址空间的条目,切换时仅需更新ASID,无需刷新整个TLB TTBR0_EL1 = [物理页表基址] | (ASID << 48) 进程切换时,仅仅需要更新TTBR0_EL1中的ASID,保留TLB缓存)支持:在不支持vhe情况下,ttbr0_el2映射地址范围较小。进程切换需要刷新TLB,导致开销
- 寄存器重定向:硬件支持对EL1的访问重定向到EL2。
如果需要访问真实的EL1寄存器,ARMv8.1引入了一种新的寄存器命名方式:通过_EL12后缀直接访问EL1寄存器,即使VHE已启用。
1 | // 读取EL1的SCTLR寄存器 |
内存虚拟化
基本概念:
(1)HVA(host virtual address):host视角下的虚拟地址
(2)HPA(host physical address):host视角下的物理地址
(3)GVA(guest virtual address):guest视角下的虚拟地址
(4)GPA(guest physical address):guest视角下的物理地址
(5)IPA(intermediate physical address):它与gpa含义相同,是arm的对guest物理地址的一种命名方式
影子页表(hypervisor为每个vm中的每个进程都维护一张合并了GVA–>GPA和GPA–>HPA两级页表关系的shadow页表。当guest os执行页表切换操作时,hypervisor将截获该操作,并用这张合并后的页表替换掉guest os本身的页表。它就像影子一样覆盖掉了guest os的页表,因此其被称为影子页表)
对于不支持硬件虚拟化的系统,由于只有一个MMU,只能实现一级的VA->PA转换,无法直接实现
影子页表开销较大,为此硬件引入2级页表,通过1级GVA->GPA转换,二级页表完成GPA->HPA转换
armv8两级页表
armv8 两级页表中,第一级页表由 guest os 创建用于 GVA->GPA(IPA)转换,第二级由 hypervisor 创建用于 GPA(IPA)->HPA 转换。armv8 为每个虚拟机提供 VMID,提高虚拟机切换效率和性能,页表转换时选择两级页表中访问限制更严格的属性
特性 | Stage 1(阶段1转换) | Stage 2(阶段2转换) |
---|---|---|
作用对象 | 虚拟机(VM)内部的进程 | 虚拟机(VM)本身 |
输入地址 → 输出地址 | 虚拟地址(VA)→ 中间物理地址(IPA) | 中间物理地址(IPA)→ 实际物理地址(PA) |
管理者 | VM的操作系统(EL1) | Hypervisor(EL2) |
目的 | 隔离VM内的进程内存空间 | 隔离不同VM的物理内存空间 |
启用条件 | 默认启用(由MMU控制) | 需设置HCR_EL2.VM=1 启用 |
页表寄存器 | TTBR0_EL1 /TTBR1_EL1 (VM内) |
VTTBR_EL2 (Hypervisor设置) |
TLB标识 | 使用ASID区分进程 | 使用VMID区分虚拟机 |
IO虚拟化
虚拟机需模拟外设地址空间,对于物理地址,为 IPA 分配物理页框并建立 stage 2 页表;对于共享设备,hypervisor 截获 IO 访问操作并模拟设备功能,通过不创建 IO 空间的 stage 2 页表产生缺页异常实现。
hypervisor捕获到缺页异常后,就可以根据HPFAR_EL2寄存器获取引起异常的地址,并根据ESR_EL2获取产生异常的原因,最后根据这些信息执行实际的设备模拟流程。以下为其流程图:
DMA虚拟化
DMA 操作以 IPA 地址为源和目的地址会出错,无硬件扩展时,hypervisor 截获 DMA 地址设置操作并分配物理内存;引入 SMMU ( SMMU的核心功能 地址转换:将设备发起的DMA请求中的虚拟地址(IOVA)转换为物理地址(PA),支持多级页表。 访问控制:检查设备对内存区域的读写权限,防止非法访问。 中断重映射:将设备中断路由到正确的虚拟机或Hypervisor。)后,hypervisor 为 DMA 创建 SMMU 页表实现内存访问
中断虚拟化
无硬件支持时,虚拟机模拟虚拟中断控制器处理中断。GICv3 在硬件层面提供虚拟中断注入功能,包括一组 list register 寄存器、vIRQ 和 vFIQ 中断信号、虚拟 cpu interface 寄存器。
有硬件支持后,hypervisor 模拟虚拟 distributor 和 redistributor,由于虚拟cpu interface已经由硬件支持,因此不再需要hypervisor模拟。hypervisor捕获物理中断注入虚拟中断,调度 vcpu 运行。
中断路由:
IMO/FMO/AMO:控制物理中断类型(IRQ/FIQ/SError)是否路由到EL2。
1
2HCR_EL2.IMO = 1; // 物理IRQ路由到EL2
HCR_EL2.FMO = 0; // 物理FIQ由VM直接处理VI/VF:向VM注入虚拟中断。
1
2HCR_EL2.VI = 1; // 注入虚拟IRQ到VM
HCR_EL2.VF = 0; // 不注入虚拟FIQ
定时器虚拟化
armv8 每个 CPU 有 generic timer 定时器,虚拟化后物理 CPU 被 vcpu 共享,定时器触发存在问题。armv8 提供虚拟和物理定时器及计数器,虚拟计数器有与物理计数器的 offset 偏移值,由 hypervisor 设置,以此确定定时器触发时间。
ARMv8定时器硬件基础
ARMv8的通用定时器(Generic Timer)为每个CPU核心提供以下关键组件:
系统计数器(System Counter) :全局递增的64位计数器,频率固定(如1GHz)。
物理定时器(Physical Timer) :基于系统计数器的比较寄存器(
CNTP_CVAL_EL0
)和控制寄存器(CNTP_CTL_EL0
)。虚拟定时器(Virtual Timer) :专为虚拟化设计,基于 CNTVOFF_EL2 的偏移值,提供虚拟机独立的计时视图。
1
虚拟时间 = 系统计数器值 - CNTVOFF_EL2