硬件虚拟化介绍
硬件虚拟化要做的事情
体系结构支持
| 体系结构 | 实现功能 | 作用 | 
|---|---|---|
| 模式切换 | Host CPU <-> Guest CPU 切换 | CPU 资源隔离 | 
| 二阶段地址转换 | GVA-> GPA | |
| GPA-> HPA | 内存资源隔离 | |
| 中断控制器支持 | 中断注入和透传 | 中断资源隔离 | 
| IOMMU | DMA Remapping | DMA 和设备访问内存隔离 | 
相应的硬件实现
x86 架构

AMD 架构

RISC-V 架构

相关软件支持
| 软件 | 举例 | 
|---|---|
| Firmware | OpenSBI、BIOS | 
| Hypervisor | KVM,XEN | 
| I/O 用户态 | qemu | 
| OS | Linux | 
CPU 虚拟化
CPU 支持模式切换:硬件支持
- 
Host CPU <-> Guest CPU:CPU 运行环境的隔离,CPU 虚拟化的基础
 
模式切换
- 
vm entry:从 Host CPU 进入到 Guest CPU,由特殊指令实现;
 - 
vm exit:从 Guest CPU 退出到 Host CPU,执行特定指令;中断;异常
 
切换过程的上下文的保存和恢复
由于 guest CPU 看不到 Host CPU state,故都是在 Host CPU 模式下操作
- 
vm entry 前:保存 Host CPU State,恢复 Guest CPU state
 - 
vm exit 后:保存 Guest CPU state,恢复 Host CPU State
 
vCPU:一个 Linux 线程

x86 架构
VMX Operation Mode

只有在 VMX Operation Mode 下才可以实现:
- 
VMX root mode:Host CPU
 - 
VMX non-root mode: Guest CPU
 
使用 VMXON 和 VMXOFF 开启和关闭。
模式切换方法
- 
vm entry: vmlaunch/vmresume 指令
 - 
vm exit:执行指令;发生异常或中断
 
上下文状态:VMCS,Virtual Machine Control Structure

Notions:
- 
一个 vCPU 对应一个 VMCS 状态;
 - 
只有 x86 支持在 vm-entry 和 vm exit 的时候,VMCS 由硬件进行保存和恢复。
 - 
虚拟化优化方向:减少
vm emtry和vm exit过程。 
ARM 架构
Exception Level
- 
EL0
- Host App: Host CPU
 - Guest App:Guest CPU
 
 - 
EL1:Guest CPU
 - 
EL2: Host CPU
 - 
EL3
 

模式切换方法
- 
vm entry: eret 指令
 - 
vm exit: 指令或异常
 
上下文状态
上下文状态自定义,由软件来实现保存和恢复。
RISC-V 架构
Privilege Level
- 
U(User Mode,用户态): Host CPU
 - 
VU(Virtualized User Mode,虚拟化用户态):Guest CPU
 - 
VS(Virtual Supervisor Mode,虚拟化监管态):Guest CPU
 - 
HS(Host Supervisor Mode,宿主机监管态):Host CPU
 - 
M(Machine Mode,机器态)
 

模式切换方法
- 
vm entry: sret 指令
 - 
vm exit: 指令或异常
 
上下文状态
上下文状态自定义,由软件来实现保存和恢复。

内存虚拟化
基本概念
GVA:Guest Virtual Address
GPA:Guest Physical Address
HVA:Host Virual Address,主机虚拟地址
HPA:Host Physical Address,主机物理地址
转换关系和维护

- 
GVA ->GPA:Guest OS 维护
 - 
HVA -> HPA: Host OS 维护
 - 
GPA <-> HVA: qemu/KVM
 - 
GPA <-> HPA: 硬件支持 EPT/NPT
 
内存虚拟化目标:如何让 Guest 的访问地址(GVA/GPA)转换成 HPA,且由硬件实现。
软件实现——影子页表
能够直接完成 GVA->HPA 的转换。被 Hpyervisor 载入到物理 MMU 中的页表是影子页表。缺陷:
- 
需要为 Guest OS 的每个进程维护一个影子页表,资源消耗大;
 - 
Guest OS 在读写 CR3、执行 INVLPG 指令或客户页表不完整等情况下均会导致 vm exit,内存虚拟化效率很低;
 - 
Guest OS 的页表和和影子页表的同步也比较复杂;
 
x86 架构
EPT/NPT
- 
Intel:EPT,Extended Page Table
 - 
AMD:NPT
 
二阶段地址转换,完成内存虚拟化
- 
GVA -> GPA:CR3 指向 Guest OS 页表,完成第一阶段转换,由硬件 MMU 完成;
 - 
GPA -> HPA:EPTP,指向 EPT 表,完成第二阶段转换,由硬件自动完成。
 

相对影子页表,只需要一张表即可完成 Guest OS 的内存虚拟化。
ARMv8 架构
VTTBR
VTTBR:Virtualization Translation Table Base Register

二阶段地址转换
- 
GVA -> GPA(IPA):TTBRn_EL1
 - 
GPA -> HPA:VTTBR0_EL2
 
RISC-V 架构
vsatp&hgatp
vsatp:Virtual Supervisor Address Translation and Protection Register
hgatp:Hypervisor Guest Address Translation and Protection Register

二阶段地址转换
- 
GVA -> GPA(IPA):vsatp
 - 
GPA -> HPA:hgatp
 
中断虚拟化
基本概念
IPI:Inter-Processor Interrupt,处理器间中断
MSI:Message Signaled Interrupt,消息信号中断
中断处理流程
- 
中断触发:中断源发生中断事件,向 CPU 发送中断信号
 - 
检测中断:CPU 检测到中断,停止当前执行流程,跳转到中断向量
 - 
处理中断:CPU 保存上下文,调用和执行中断处理函数,然后返回原有执行流程
 
中断来源不同,导致虚拟化方式不同:
- 
IPI:inter-processor interrupt
 - 
timer 中断
 - 
external 中断:包括 MSI
 
虚拟化方法一:发生 vm exit 和中断注入
- 
如果中断发生在当前 pCPU 上:如果 vCPU 处于运行状态,Guest CPU 不会发生 vm exit,中断直接投递给 vCPU;
 - 
如果 vCPU 处于等待状态,调用 kvm_kick_cpu, 唤醒 vCPU 的线程,把中断信息投递到 Guest CPU State,让 vCPU 进入 Guest CPU 模式
 - 
如果中断发生在其他 pCPU,需要向当前 pCPU 发送 IPI
 - 
vCPU 在 Guest CPU 模式下完成处理中断
 
特点
- 
中断发生时,vCPU 会发生 vm exit,效率低
 - 
在没有中断控制器的特殊支持时,大多数硬件都支持此种中断虚拟化
 
虚拟化方法二: 中断直接投递给 vCPU
- 
如果中断发生在当前 pCPU 上:
- 如果 vCPU 处于运行状态,Guest CPU 不会发生 vm exit,中断直接投递给 vCPU;
 - 如果 vCPU 处于等待状态,调用 kvm_kick_cpu, 唤醒 vCPU 的线程,把中断信息投递到 Guest CPU State,让 vCPU 进入 Guest CPU 模式;
 
 - 
如果中断发生在其他 pCPU,需要向当前 pCPU 发送 IPI
 - 
vCPU 在 Guest CPU 模式下完成处理中断;
 
特点
- 
需要中断控制器的特殊支持;
 - 
vCPU 不需要产生 vm exit,效率高;
 
x86 架构
中断控制器:LAPIC、IOAPIC
每个 CPU 接一个 Local APIC,通过地址总线接 IOAPIC,IPAPIC 完成外部中断的投递,Local APIC 完成 IPI 或者 Timer 的处理。

Posted Interrupt

外部中断到来时,中断直接投递到 VCPU 的 Posted Descriptor,Posted Descripter 利用事件通知 pCPU。详细解释:

ARMv8 架构
中断控制器:中断注入——GICv3

中断控制器:中断透传——GICv4

RISC-V 架构
中断控制器:PLIC
- 
不支持 MSI
 - 
不支持中断虚拟化
 
AIA 定义的两个控制器
RISC-V Advanced Interrupt Architecture:AIA,定义了两个控制器:
- 
Incoming Message Signaled Interrupt Controller (IMSIC):支持 MSI;支持 IPI 虚拟化;
 - 
Advanced Platform Level Interrupt Controller (APLIC):支持 Wired Interrupt;
 


例子:KVM 通过 IMSIC 注入中断

- 
HART0 的 KVM 写 MMIO 到某 HVA
 - 
HVA 通过 SATP 和转换变为 HPA
 - 
写入 HARTx 的 IMSIC 的寄存器
 - 
发送信号给 HARTx 的 CSR
 - 
注入中断到 HARTx 的 Guest_A 的 vCPU B
 
例子:Guest_A vCPU_A 发送到 Guest_A vCPU_B 的 IPI 中断

- 
HART0 的 Guest_A 的 vCPU A 写 MMIO 到某 GVA
 - 
GVA 通过 VSATP 和 HGATP, 经过两次转换变为 HPA
 - 
写入 HARTx 的 IMSIC 的寄存器
 - 
发送信号给 HARTx 的 CSR
 - 
触发 HARTx 的 Guest_A 的 vCPU B 的 IPI
 
设备虚拟化
基本概念
IOMMU:Input-Output Memory Management Unit
- 
MMU:CPU 通过 VA 访问内存
 - 
IOMMU:设备通过 IO VA 访问内存
 

IOMMU 作用
- 
DMA 设备的虚拟地址转换。完成 IOVA -> HPA 的转换。把设备发送的 IOVA 转换成 HPA。
 - 
DMA 设备的内存写保护
 - 
Interrupt remapping 和虚拟化
 - 
IO 设备可以共享页表
 
IOMMU 地址转换

- 
X86 IOMMU:包括 dma remapping 和 interrupt remapping
- Intel:VT-D
 - AMD:AMD IOMMU
 
 - 
ARMv8:SMMUv3
 - 
RISC-V:RISC-V IOMMU
 
设备透传
VFIO:Virtual Function I/O 是 Linux 下利用 IOMMU 构建设备直通方案。用户态进程可以使用 VFIO 驱动直接访问硬件,并且由于整个过程是在 IOMMU 的保护下进行因此十分安全, 而且非特权用户也是可以直接使用。实现了 VM 中的 GPA 映射到 HPA,并且使用 DMA-remapping 将设备中断发送回 VM。
设备透传的作用
- 
透传 GPU/网络设备给虚拟机
 - 
虚机的 GPU/网络驱动,不需要做任何修改就可以直接使用透传设备
 - 
性能损耗最小
 
设备透传的应用
- 
GPU 设备透传
 - 
网卡透传
 - 
磁盘透传