文章

【笔记】虚拟化技术的分层模型

【笔记】虚拟化技术的分层模型

虚拟化不是一种单独的技术,而是把一台机器拆成多个可管理执行环境时,对 CPU、内存和 I/O 分别建立的抽象与隔离。现代虚拟机通常同时使用硬件辅助执行、两阶段地址翻译、虚拟设备、半虚拟化 I/O 和设备直通,不能用“全虚拟化”或“半虚拟化”一个标签概括整条链路。

1. 中心模型:虚拟的是一台机器,不只是 CPU

一个可运行 Guest OS 的 VM,至少需要三类能力:

flowchart TB
    G[Guest OS]
    CPU[虚拟 CPU<br/>vCPU]
    MEM[Guest Physical Memory]
    IO[虚拟设备]

    HCPU[CPU 虚拟化<br/>VM Entry / VM Exit]
    HMEM[内存虚拟化<br/>Shadow Paging 或 EPT/NPT]
    HIO[I/O 虚拟化<br/>模拟 / VirtIO / 直通]

    G --> CPU --> HCPU
    G --> MEM --> HMEM
    G --> IO --> HIO
  • CPU 虚拟化让 Guest 的内核代码能受控地使用物理 CPU;
  • 内存虚拟化让 Guest 看到连续、独占的“物理内存”,同时限制它只能访问分配给自己的 Host 内存;
  • I/O 虚拟化为 Guest 提供网卡、磁盘、时钟、中断控制器等设备,并把请求接到真实资源。

只解释 VM Entry/Exit,仍然不能回答 Guest 页表如何落到 Host 内存、虚拟网卡如何收发包,也不能构成一台完整 VM。

2. Hypervisor、VMM 与虚拟化栈

2.1 两个术语没有绝对统一的分界

Hypervisor 常译为“虚拟机监控器”或“虚拟机管理程序”;VMM 是 Virtual Machine Monitor。很多资料把两者当同义词,也有资料用 Hypervisor 指特权执行与隔离层,用 VMM 指用户态机器模型和管理进程。

因此,与其争论某个组件“算不算 Hypervisor”,不如明确它承担什么职责:

职责典型内容
受控执行进入 Guest、处理退出、注入中断、维护 vCPU 状态
地址空间Guest 内存映射、权限、缺页、脏页和迁移
机器模型主板、固件、PCI 总线、网卡、磁盘和中断控制器
生命周期创建 VM、配置资源、暂停、恢复、快照和迁移

2.2 KVM 与 QEMU 是职责互补,不是简单上下层

KVM 向用户态暴露 /dev/kvm。用户态程序创建 VM 和 vCPU,通过 KVM_RUN 让某个 vCPU 运行。KVM 使用 Linux 内核与 CPU 虚拟化扩展处理受控执行和内存隔离。

QEMU 的 system emulation 提供一台机器的模型,包括 CPU、内存和设备。它可以:

  • 使用 KVM、Xen、macOS HVF、Windows WHPX 等 accelerator;
  • 不使用硬件虚拟化,改用 TCG 做指令翻译;
  • 提供传统模拟设备、VirtIO 设备、设备直通和管理接口。

所以“QEMU 只是外设模拟器”太窄,“KVM 单独就是一整套 VM 产品”也不准确。常见的 QEMU/KVM 栈,是 QEMU 负责机器模型与用户态控制,KVM 负责 Linux 内核里的虚拟化执行能力,两者通过 KVM API 协作。

2.3 Type 1 / Type 2 只能描述部署形态

Type 1 通常指虚拟化层直接控制硬件,Type 2 通常指虚拟机软件运行在通用 Host OS 之上。这个分类适合建立直觉,但面对 KVM、Hyper-V、macOS Virtualization/Hypervisor Framework 等现代组合时会变得模糊。

桌面产品有 Host OS 和 GUI,不代表所有虚拟化工作都由普通用户态代码完成;云上系统直接控制硬件,也不代表不存在完整的管理 OS 和用户态设备模型。分析真实系统时,应继续拆 CPU、内存、设备和管理面,而不是停在 Type 1/Type 2 标签上。

3. CPU 虚拟化:让 Guest 内核直接但受控地运行

3.1 为什么早期 x86 虚拟化困难

普通应用受 OS 控制,因为敏感操作只能在高特权级执行。Guest OS 自己也要以最高特权运行和管理页表、中断、设备;如果让它直接控制物理机器,就会破坏 Host 和其他 VM。

早期实现主要有两条路:

  • 解释或动态二进制翻译:VMM 分析 Guest 指令,把不能安全直接执行的部分改写或模拟;
  • 半虚拟化:修改 Guest 内核,让它通过 hypercall 主动请求 Hypervisor 完成敏感操作。

硬件辅助虚拟化的价值不是“CPU 从此不再模拟设备”,而是让 CPU 原生支持 Guest 特权代码的受控执行。

3.2 VMX root/non-root 不是 Ring -1/Ring 0 的简单上下级

以 Intel VMX 为例,CPU 增加 VMX root 与 VMX non-root 两种运行形态。二者内部仍有原来的 privilege levels。Guest kernel 可以在 non-root 的 Ring 0 运行,但它是否能执行某项操作,还受到虚拟化控制字段约束。

“Ring -1”是便于交流的俗称,不是比 x86 Ring 0 多出来的正式 privilege ring。

3.3 VM Entry、VM Exit 与 VMCS

VMCS 保存并控制一次 vCPU 执行所需的状态,核心可以理解为:

  • Guest state:Guest 的控制寄存器、指令位置和其他体系结构状态;
  • Host state:退出后恢复到虚拟化层所需的状态;
  • execution controls:哪些事件允许直接执行,哪些触发退出;
  • exit information:退出原因和相关信息。

运行循环是:

1
2
3
4
5
6
7
8
用户态 VMM 调用 KVM_RUN
  → KVM 准备 vCPU
  → VM Entry
  → Guest 直接执行普通指令
  → 遇到配置为拦截的事件
  → VM Exit
  → KVM 或用户态 VMM 处理
  → 再次进入 Guest

并不是每条 Guest 指令都会 VM Exit。性能优化的重要方向,是让安全的普通执行、内存访问和高频 I/O 尽量留在快速路径。

3.4 vCPU 是状态与执行上下文,不等于物理核心

每个 vCPU 有独立的 Guest CPU 状态。以常见 QEMU/KVM 实现理解,vCPU 通常由 Host 线程驱动,Host scheduler 决定这个线程何时在哪个物理 CPU 上运行。

1
2
3
4
Host scheduler
  → 调度某个 vCPU thread
    → thread 进入 KVM_RUN
      → CPU 执行该 vCPU 的 Guest state

因此:

  • 一个 VM 可以有多个 vCPU;
  • 多个 vCPU 可以并行运行,也可能在物理 CPU 不足时分时运行;
  • Host scheduler 调度的是线程,不是“整个 VM”;
  • VM Exit 后通常继续处理当前 vCPU,是否换成另一个 vCPU 由 Host 调度与线程状态共同决定,不是 KVM 在每次退出时主动挑选另一台 VM。

Guest 通过固件表、虚拟 APIC 等机器模型发现多个处理器,并按正常 SMP 启动流程拉起其他 vCPU。vCPU 是虚拟机暴露给 Guest 的 CPU 拓扑,Host thread 是实现它的一种常见方式,两者不是同一个抽象层。

3.5 多 vCPU 还需要中断和时钟机器模型

只创建多个 vCPU thread,不足以让 Guest OS 看到一台可用的多核机器。虚拟化层还要提供固件 CPU 拓扑、Local APIC 或等价中断控制器,以及启动其他 vCPU 所需的机器语义。

中断路径同样需要分层:

1
2
3
4
5
物理设备或 Host 事件
  → 虚拟化层确定目标 vCPU
  → 设置虚拟中断控制器状态或请求硬件注入
  → 目标 vCPU 在可接收时观察到 Guest interrupt
  → Guest 内核的中断处理程序运行

Guest 的时间源与定时器也不能简化为“直接读 Host 时钟”。虚拟化层需要维持 Guest 可观察的时间语义,并在定时器到期时向相应 vCPU 交付虚拟中断。现代硬件可以加速部分中断和定时器路径,但 Host 调度、VM 暂停/恢复、超分和迁移仍会让虚拟时间成为需要显式管理的状态。

因此,vCPU、中断控制器和时钟/定时器应视为同一台虚拟机器模型的不同部件,不是三个孤立优化点。

4. 内存虚拟化:GVA → GPA → HPA

4.1 三种地址不能混在一起

1
2
3
4
GVA: Guest Virtual Address,Guest 进程使用的虚拟地址
GPA: Guest Physical Address,Guest OS 认为的物理地址
HVA: Host Virtual Address,VMM 进程映射 Guest RAM 时看到的地址
HPA: Host Physical Address,真实内存页地址

Guest OS 维护自己的页表,负责 GVA → GPA。虚拟化层还必须负责 GPA → HPA,保证 Guest 只能访问分配给它的 Host 页面。

HVA 是 Host 用户态管理 Guest RAM 时的重要视图,但不是 Guest CPU 最终访问内存所用的地址。Linux 内核仍然控制 HVA/HPA 映射、换页、迁移、合并和大页等 Host 内存行为。

4.2 Shadow Page Table:把两层关系压成一层

没有硬件两阶段翻译时,VMM 可以维护影子页表,让硬件实际使用的页表直接完成 GVA → HPA。Guest 仍以为自己维护 GVA → GPA,虚拟化层需要跟踪 Guest 页表变化,并把结果同步到影子页表。

这种方案不是每次普通 load/store 都进入 VMM。代价主要发生在页表切换、页表写入、缺页和影子映射失效时;同步正确性和 TLB 管理都很复杂。

4.3 EPT/NPT:由硬件完成两阶段翻译

Intel EPT、AMD NPT 属于 two-dimensional paging:

1
2
3
Guest page table: GVA → GPA
EPT/NPT:          GPA → HPA
CPU 最终得到:     GVA → GPA → HPA

普通内存访问可由 CPU 和 TLB 缓存完成两阶段翻译。缺失的 Guest 页表项由 Guest OS 处理;缺失或违规的第二阶段映射则产生 EPT violation/NPT fault,由虚拟化层处理。

“硬件自动两级翻译”不表示虚拟化层从此不管内存。KVM 仍需建立和失效第二阶段映射,处理权限、内存槽、脏页、回收、迁移和 MMIO 等事件。

5. I/O 虚拟化是一条连续谱

本节只建立设备虚拟化的通用分类;虚拟网卡、TAP、vhost、OVS、overlay 与 container 网络的完整关系,独立整理在《网络虚拟化的数据路径与隔离边界》中。

5.1 传统设备模拟:兼容真实硬件接口

VMM 可以模拟一块 Guest 已有驱动支持的真实设备,例如某种 PCI 网卡或磁盘控制器。Guest 不需要专门理解虚拟化环境,但寄存器访问、通知和设备语义需要 VMM 模拟,兼容性高,路径通常更长。

5.2 VirtIO:为虚拟环境设计的设备规范

VirtIO 是一组虚拟设备及传输规范,不是某个单一实现。它定义 Guest driver 与 device implementation 如何通过配置空间、virtqueue、通知等机制协作。

典型路径是:

1
2
3
4
5
Guest virtio driver
  → virtqueue 中提交 descriptor
  → Host backend 取出请求
  → Host 网络、存储或其他资源
  → 更新 used buffer 并通知 Guest

前后端可能由 QEMU、内核 vhost、vhost-user 进程或其他 VMM 实现。共享内存队列减少了模拟传统设备寄存器和逐请求陷入的成本,但建立队列、通知和部分控制操作仍可能跨越 Guest/Host 边界。

VirtIO 经常称为 paravirtualized I/O,因为 Guest 使用专为虚拟环境设计的驱动并主动遵循协作协议。但这只能描述 I/O 设备路径,不能据此把整台 VM 分类成“半虚拟化系统”。

5.3 设备直通:把真实设备控制面交给 Guest

设备直通把某个物理 PCI function 分配给 VM。Guest 可以使用接近裸机的设备驱动和数据路径,但 Host 仍需建立安全边界:

  • 限制设备 DMA 只能访问分配给该 VM 的内存;
  • 正确重映射中断;
  • 以可隔离的设备/IOMMU group 为分配单位;
  • 处理设备 reset、生命周期和迁移限制。

Linux VFIO 利用 IOMMU 提供受保护的用户态设备访问。IOMMU 的关键作用不是“让设备变快”,而是对设备发出的 DMA 地址做翻译和权限隔离,防止设备读写任意 Host 内存。

5.4 SR-IOV:一个设备暴露多个 PCI function

SR-IOV 是 PCI Express 能力。支持它的物理设备提供:

  • PF(Physical Function):完整管理能力,通常由 Host PF driver 控制;
  • VF(Virtual Function):能力受限但可独立枚举的 PCI function,可以分配给 VM。

SR-IOV 解决的是“一个物理设备如何呈现多个可分配 function”。它不是 CPU 全虚拟化,也不等于 IOMMU:

1
2
3
SR-IOV:设备侧拆分 PF/VF
IOMMU:平台侧隔离和翻译 DMA
VFIO:Linux 向用户态/VMM 暴露安全设备访问的框架

实际直通通常需要设备、固件/主板、IOMMU、Host driver、VFIO/VMM 和 Guest driver 共同支持。VF 接近直通数据路径,但 PF 的配置、资源切分和故障管理仍由 Host 控制。

6. 全虚拟化与半虚拟化:按“Guest 是否必须配合”判断

6.1 全虚拟化强调运行未为 Hypervisor 改写的 Guest

全虚拟化的核心价值是提供足够完整的机器接口,使未经专门改写的 Guest OS 可以运行。它可以由软件翻译实现,也可以使用硬件辅助;“全虚拟化”与“硬件辅助”不是互斥分类。

Guest 能检测到 CPUID hypervisor bit、VirtIO 设备或虚拟厂商字符串,并不会自动改变这个判断。“是否知道自己在 VM 中”只是粗糙直觉;真正关键的是 Guest 的核心执行是否必须改为 hypercall 等虚拟化专用接口才能运行。

6.2 半虚拟化强调 Guest 主动采用虚拟化接口

经典 Xen PV 会修改 Guest 内核,让原本直接操作特权状态的路径改为 hypercall。现代系统更常在局部采用半虚拟化接口,例如:

  • VirtIO 设备;
  • Hyper-V enlightened I/O 与 synthetic devices;
  • paravirtualized clock、interrupt、spinlock 等优化。

因此现实系统通常是分层混合:CPU 使用硬件辅助的全虚拟化,内存使用 EPT/NPT,I/O 使用 VirtIO,少量设备使用直通。给整套系统贴一个“纯全”或“纯半”标签,信息量反而更低。

6.3 VirtIO 既不是充分条件,也不是必要条件

  • 不充分:使用 VirtIO 只能证明该设备路径采用半虚拟化协议,不能证明 CPU、内存和所有设备都采用经典 PV。
  • 不必要:Xen PV 有自己的 frontend/backend 与 hypercall 体系;半虚拟化并不依赖 VirtIO 这一套具体规范。

7. 用典型系统校准概念

7.1 Xen

Xen 官方将其定义为 bare-metal hypervisor。它位于硬件之上,启动特权控制域 Dom0,再由 Dom0 提供管理和大量设备后端能力。Xen 既有早期 PV guest,也支持依赖硬件辅助的 HVM guest;HVM guest 还可以使用 PV driver 优化 I/O。

Xen 因此不是“只等于半虚拟化”,而是一套同时容纳 PV、HVM 和混合设备路径的虚拟化架构。

7.2 WSL 1 与 WSL 2

Microsoft 官方的关键区分是:WSL 1 使用 system call translation layer;WSL 2 使用真实 Linux kernel,并运行在受管理的 Hyper-V utility VM 中。前者不是传统 VM,后者具有真正的 Guest kernel,只是产品隐藏了大量 VM 生命周期和设备配置。

WSL 2 不要求出现 virtio-* 设备;Hyper-V 有自己的虚拟设备与集成接口。具体的发行版、文件、命令、配置和网络边界独立整理在《WSL 的架构、互操作与使用边界》中。

7.3 Parallels、OrbStack 等桌面产品

在现代 Mac 上,桌面虚拟化产品可以利用 Apple 提供的 Hypervisor/Virtualization 能力运行未为产品本身重写的 Guest OS,并通过专用 Guest Tools、虚拟设备和共享服务优化 I/O 与桌面体验。

“用了专用驱动”不等于整台 VM 是经典半虚拟化,“产品运行在 macOS 应用层”也不等于 CPU 虚拟化由普通用户态代码独立完成。对闭源产品,应把官方承诺、现场观测和合理推断分开,不根据性能表现猜测其私有数据路径。

8. 一套更可靠的分析顺序

遇到一个虚拟化产品或架构时,按下面顺序拆解:

  1. Guest 是否有独立 kernel,还是共享 Host kernel?
  2. Guest 指令由硬件辅助直接执行,还是由解释器/二进制翻译执行?
  3. vCPU 由什么 Host 执行实体驱动,谁负责调度?
  4. GVA → GPA → HPA 由影子页表还是两阶段翻译完成?
  5. 每类设备使用传统模拟、半虚拟化协议还是直通?
  6. DMA 和中断如何隔离?是否使用 IOMMU、VFIO、SR-IOV?
  7. 哪些属于产品公开承诺,哪些只是现场观测或推断?

这套问题比先问“它是全虚拟化还是半虚拟化”更能还原真实系统。

9. 易混点

说法更准确的理解
Guest 知道自己在 VM,所以是半虚拟化能检测 VM 不等于核心执行必须采用 PV 接口
KVM 就是一整套虚拟机KVM 提供内核虚拟化 API,完整机器通常还需要用户态 VMM 和设备模型
QEMU 只是网卡、磁盘模拟器QEMU 提供完整 system emulation,也能使用 KVM 等 accelerator 或 TCG
vCPU 就是物理 CPUvCPU 是 Guest CPU 状态与执行上下文,常由 Host thread 驱动和调度
VM Exit 时 KVM 选择另一台 VMHost scheduler 调度 vCPU thread;VM Exit 通常处理当前 vCPU 的事件
EPT 后内存不再需要 KVM 管理EPT 加速翻译,KVM 仍管理映射、权限、缺页、回收和脏页
VirtIO 就是半虚拟化 VMVirtIO 只说明相应 I/O 设备使用 paravirtualized protocol
SR-IOV 就是设备直通SR-IOV 拆分 PF/VF;VF 还需通过 IOMMU/VFIO 等安全分配
IOMMU 负责创建 VFVF 由 SR-IOV 设备创建;IOMMU 负责 DMA 翻译与隔离

10. 复习索引

  1. VM 的完整模型是 CPU、内存、I/O 三条虚拟化链路;
  2. Hypervisor/VMM 术语有重叠,分析职责比争论名称更可靠;
  3. KVM API 创建 VM/vCPU,KVM_RUN 驱动 vCPU 执行,QEMU 提供机器模型和管理面;
  4. vCPU 常由 Host thread 驱动,真正选择运行线程的是 Host scheduler;
  5. 内存核心链路是 GVA → GPA → HPA,可由 shadow paging 或 EPT/NPT 完成;
  6. I/O 从传统设备模拟,演进到 VirtIO,再到 VFIO/IOMMU 保护下的设备直通;
  7. SR-IOV 负责设备拆分,IOMMU 负责 DMA 隔离,两者不是同一种能力;
  8. 全虚拟化、硬件辅助、半虚拟化 I/O 可以同时存在于一台现代 VM 中;
  9. 分析闭源产品时,只写官方承诺、可重复观测和明确标边界的推断。

11. 核验入口

本文由作者按照 CC BY 4.0 进行授权