Songqian Li's Blog

去历史上留点故事

硬件虚拟化介绍

硬件虚拟化要做的事情

体系结构支持

体系结构 实现功能 作用
模式切换 Host CPU <-> Guest CPU 切换 CPU 资源隔离
二阶段地址转换 GVA-> GPA
GPA-> HPA 内存资源隔离
中断控制器支持 中断注入和透传 中断资源隔离
IOMMU DMA Remapping DMA 和设备访问内存隔离

相应的硬件实现

x86 架构
image.png
AMD 架构
image.png
RISC-V 架构
image.png

相关软件支持

软件 举例
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 线程

image.png

x86 架构

VMX Operation Mode

image.png
只有在 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

image.png
Notions:

  1. 一个 vCPU 对应一个 VMCS 状态;
  2. 只有 x86 支持在 vm-entry 和 vm exit 的时候,VMCS 由硬件进行保存和恢复。
  3. 虚拟化优化方向:减少vm emtryvm exit过程。

ARM 架构

Exception Level

  • EL0
    • Host App: Host CPU
    • Guest App:Guest CPU
  • EL1:Guest CPU
  • EL2: Host CPU
  • EL3

image.png

模式切换方法

  • 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,机器态)

image.png

模式切换方法

  • vm entry: sret 指令
  • vm exit: 指令或异常

上下文状态

上下文状态自定义,由软件来实现保存和恢复。
image.png

内存虚拟化

基本概念

GVA:Guest Virtual Address
GPA:Guest Physical Address
HVA:Host Virual Address,主机虚拟地址
HPA:Host Physical Address,主机物理地址

转换关系和维护

image.png

  • GVA ->GPA:Guest OS 维护
  • HVA -> HPA: Host OS 维护
  • GPA <-> HVA: qemu/KVM
  • GPA <-> HPA: 硬件支持 EPT/NPT

内存虚拟化目标:如何让 Guest 的访问地址(GVA/GPA)转换成 HPA,且由硬件实现。

软件实现——影子页表

能够直接完成 GVA->HPA 的转换。
被 Hpyervisor 载入到物理 MMU 中的页表是影子页表。
缺陷:

  1. 需要为 Guest OS 的每个进程维护一个影子页表,资源消耗大;
  2. Guest OS 在读写 CR3、执行 INVLPG 指令或客户页表不完整等情况下均会导致 vm exit,内存虚拟化效率很低;
  3. Guest OS 的页表和和影子页表的同步也比较复杂;

x86 架构

EPT/NPT

  • Intel:EPT,Extended Page Table
  • AMD:NPT

二阶段地址转换,完成内存虚拟化

  1. GVA -> GPA:CR3 指向 Guest OS 页表,完成第一阶段转换,由硬件 MMU 完成;
  2. GPA -> HPA:EPTP,指向 EPT 表,完成第二阶段转换,由硬件自动完成。

image.png
相对影子页表,只需要一张表即可完成 Guest OS 的内存虚拟化。

ARMv8 架构

VTTBR

VTTBR:Virtualization Translation Table Base Register
image.png

二阶段地址转换

  1. GVA -> GPA(IPA):TTBRn_EL1
  2. GPA -> HPA:VTTBR0_EL2

RISC-V 架构

vsatp&hgatp

vsatp:Virtual Supervisor Address Translation and Protection Register
hgatp:Hypervisor Guest Address Translation and Protection Register
image.png

二阶段地址转换

  1. GVA -> GPA(IPA):vsatp
  2. GPA -> HPA:hgatp

中断虚拟化

基本概念

IPI:Inter-Processor Interrupt,处理器间中断
MSI:Message Signaled Interrupt,消息信号中断

中断处理流程

  1. 中断触发:中断源发生中断事件,向 CPU 发送中断信号
  2. 检测中断:CPU 检测到中断,停止当前执行流程,跳转到中断向量
  3. 处理中断: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 的处理。
image.png

Posted Interrupt

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

ARMv8 架构

中断控制器:中断注入——GICv3

image.png

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

image.png

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;

image.png
image.png

例子:KVM 通过 IMSIC 注入中断
image.png

  1. HART0 的 KVM 写 MMIO 到某 HVA
  2. HVA 通过 SATP 和转换变为 HPA
  3. 写入 HARTx 的 IMSIC 的寄存器
  4. 发送信号给 HARTx 的 CSR
  5. 注入中断到 HARTx 的 Guest_A 的 vCPU B

例子:Guest_A vCPU_A 发送到 Guest_A vCPU_B 的 IPI 中断
image.png

  1. HART0 的 Guest_A 的 vCPU A 写 MMIO 到某 GVA
  2. GVA 通过 VSATP 和 HGATP, 经过两次转换变为 HPA
  3. 写入 HARTx 的 IMSIC 的寄存器
  4. 发送信号给 HARTx 的 CSR
  5. 触发 HARTx 的 Guest_A 的 vCPU B 的 IPI

设备虚拟化

基本概念

IOMMU:Input-Output Memory Management Unit

  • MMU:CPU 通过 VA 访问内存
  • IOMMU:设备通过 IO VA 访问内存

image.png

IOMMU 作用

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

IOMMU 地址转换

image.png

  • X86 IOMMU:包括 dma remapping 和 interrupt remapping
    • Intel:VT-D
    • AMD:AMD IOMMU
  • ARMv8:SMMUv3
  • RISC-V:RISC-V IOMMU

设备透传

image.pngVFIO:Virtual Function I/O 是 Linux 下利用 IOMMU 构建设备直通方案。用户态进程可以使用 VFIO 驱动直接访问硬件,并且由于整个过程是在 IOMMU 的保护下进行因此十分安全, 而且非特权用户也是可以直接使用。
实现了 VM 中的 GPA 映射到 HPA,并且使用 DMA-remapping 将设备中断发送回 VM。

设备透传的作用

  • 透传 GPU/网络设备给虚拟机
  • 虚机的 GPU/网络驱动,不需要做任何修改就可以直接使用透传设备
  • 性能损耗最小

设备透传的应用

  • GPU 设备透传
  • 网卡透传
  • 磁盘透传

参考

相关文章
评论
分享
  • GPU虚拟化

    用户层虚拟化 本地 API 拦截和 API formwarding 在用户态实现一个函数库,假设叫 libwrapper, 它要实现底层库的所有 API; 让 APP 调用这个 libwrapper。如何做? libwrap...

    GPU虚拟化
  • 《操作系统真象还原》:第十章 输入输出系统

    上一章中我们遇到的字符混乱和 GP 异常问题,根本原因是由于临界区代码的资源竞争,这需要一些互斥的方法来保证操作的原子性。 10.1 同步机制——锁 10.1.1 排查 GP 异常,理解原子操作 多线程执行刷屏时光标值越界导致...

    《操作系统真象还原》:第十章 输入输出系统
  • 《操作系统真象还原》:第九章 线程

    线程和进程将分两部分实现,本章先讲解线程。 9.1 实现内核线程 9.1.1 执行流 在处理器数量不变的情况下,多任务操作系统采用多道程序设计的方式,使处理器在所有任务之间来回切换,这称为“伪并行”,由操作系统中的任务调度器决定当...

    《操作系统真象还原》:第九章 线程
  • 《操作系统真象还原》:第八章 内存管理系统

    8.1 makefile 简介 这部分可参考阮一峰的讲解:https://www.ruanyifeng.com/blog/2015/02/make.html 8.1.1 makefile 是什么 makefile 是 Linu...

    《操作系统真象还原》:第八章 内存管理系统
  • 《操作系统真象还原》:第七章 中断

    7.1 中断是什么,为什么要有中断 运用中断能够显著提升并发,从而大幅提升效率。 7.2 操作系统是中断驱动的 略 7.3 中断分类 把中断按事件来源分类,来自 CPU 外部的中断就称为外部中断,来自 CPU 内部的中断称为内部...

    《操作系统真象还原》:第七章 中断
  • 《操作系统真象还原》:第六章 完善内核

    6.1 函数调用约定简介 咱们实验使用cdecl。这里提一下stdcall,cdecl与stdcall的区别在于由谁来回收栈空间。 stdcall是被调用者清理参数所占的栈空间。 举例来说: 12int subtract(int ...

    《操作系统真象还原》:第六章 完善内核
  • 《操作系统真象还原》:第五章 保护模式进阶——加载内核

    5.3 加载内核 5.3.1 用 C 语言写内核 第一个 C 语言代码: 1234int main(void) { while(1); return 0;} 这个内核文件什么都没做,通过while(1)这个死循...

    《操作系统真象还原》:第五章 保护模式进阶——加载内核
  • 《操作系统真象还原》:第五章 保护模式进阶——内存分页机制

    从这一刻起,我们才算开始了真正的操作系统学习之旅 5.1 获取物理内存容量 5.1.1 Linux 获取内存的方法 在 Linux 2.6 内核总是用detect_memory函数来获取内存容量的。其函数本质上是通过调用 BI...

    《操作系统真象还原》:第五章 保护模式进阶——内存分页机制
  • 《操作系统真象还原》:第四章 保护模式入门

    4.1 保护模式概述 在本章大家会见到全局描述符表、中断描述符表、各种门结构,这是 CPU 提供给应用的,咱们用好就行。 保护模式强调的是“保护”,它是在 Intel 80286 CPU 中首次出现,这是继 8086 之后,Inte...

    《操作系统真象还原》:第四章 保护模式入门
  • 《操作系统真象还原》:第三章 完善MBR——I/O接口

    3.3 让我们对显示器说点什么吧 3.3.1 CPU 如何与外设通信——IO 接口 IO 接口功能: 设置数据缓冲,解决 CPU 与外设的速度不匹配 设置信号电平转换电路 设置数据格式转换 设置时序控制电路来同步 CPU 和外部...

    《操作系统真象还原》:第三章 完善MBR——I/O接口