2. 虚拟化与设备直通基础

在讨论设备直通与 IOMMU 之前,必须先建立虚拟化的基本心智模型:虚拟机并不是“更快的模拟器”,而是由 CPU 硬件辅助、Hypervisor 调度、内存与设备资源被重新划分后形成的一台逻辑计算机。设备直通之所以有价值,正是因为它绕开了传统虚拟化中“设备访问必须经过 Hypervisor 软件模拟”的瓶颈。理解这一章,是后续配置 VT-d/AMD-Vi、VFIO、SR-IOV 与多 OS 直通工程的前提。

一、虚拟化原理:从“特权指令”到“硬件辅助”

虚拟化的核心目标,是让多个操作系统实例共享同一套物理硬件,同时彼此隔离、互不干扰。早期 x86 架构并不支持虚拟化,因为某些敏感指令在用户态执行时不会触发异常,Hypervisor 无法可靠拦截。于是出现了两种思路:一是二进制翻译,在运行时扫描并替换敏感指令;二是半虚拟化,要求 Guest OS 主动修改内核,把敏感操作换成对 Hypervisor 的调用(hypercall)。

现代虚拟化则依赖 CPU 提供的硬件辅助能力:Intel VT-x 与 AMD-V 引入了根模式与非根模式,Guest 运行在非根模式,遇到敏感指令或特定事件时自动触发 VM Exit,由 Hypervisor 处理后再 VM Entry 返回。内存方面,EPT(Intel)与 NPT(AMD)实现二级地址转换,让 Guest 物理地址到宿主物理地址的映射由硬件完成,避免影子页表的频繁同步开销。

虚拟化的三个关键抽象:CPU 虚拟化(vCPU 调度与上下文切换)、内存虚拟化(Guest 物理地址 → 宿主物理地址)、设备虚拟化(I/O 请求如何到达真实硬件)。设备直通主要解决第三个抽象的效率与保真度问题。

二、Hypervisor 类型:Type 1 与 Type 2

Hypervisor(虚拟机监视器)按运行位置可分为两类。Type 1 直接运行在裸金属上,如 VMware ESXi、Microsoft Hyper-V、Xen、KVM(严格说 KVM 是 Linux 内核模块,属于 Type 1 的宿主型实现)。Type 2 运行在宿主操作系统之上,如 VirtualBox、VMware Workstation。两者在设备直通场景中的差异非常明显:Type 1 通常能更直接地控制 IOMMU 与中断重映射,延迟更低;Type 2 需要经过宿主内核转发,配置更简单但性能与隔离性受限。

对比维度 Type 1(裸金属/宿主型) Type 2(宿主应用型)
典型代表 ESXi、Xen、KVM、Hyper-V VirtualBox、VMware Workstation
设备直通支持 PCIe Passthrough、SR-IOV、VFIO 成熟 有限,常依赖 USB 直通或实验性 PCI 直通
IOMMU 控制 可直接绑定 DMA 重映射与中断重映射 需宿主 OS 暴露,隔离粒度较粗
典型延迟 低,接近原生 较高,受宿主调度影响
适用场景 生产虚拟化、多 OS 直通、DPDK/GPU 直通 开发测试、桌面体验、轻量隔离

三、全虚拟化与半虚拟化:设备视角的差异

全虚拟化(Full Virtualization)不要求 Guest 修改内核,Guest 以为自己运行在真实硬件上,所有敏感操作由 Hypervisor 透明拦截与模拟。半虚拟化(Paravirtualization)则要求 Guest 安装特定驱动,主动与 Hypervisor 协作。以设备 I/O 为例:全虚拟化下,Guest 看到的是一块模拟的 e1000 网卡,每次收发包都要触发 VM Exit,由 QEMU 模拟寄存器读写,性能损耗大;半虚拟化下,Guest 使用 virtio 驱动,通过共享内存环(virtqueue)批量提交请求,Hypervisor 只需处理通知,效率显著提升。

但 virtio 仍然是“软件路径”:数据要从 Guest 内存拷贝到宿主,再交给真实驱动。设备直通则更进一步,把物理 PCIe 设备直接分配给 Guest,让 Guest 原生驱动直接操作硬件寄存器与 DMA,几乎消除 Hypervisor 在数据路径上的参与。这也是 GPU、NVMe、高速网卡直通时性能接近裸机的原因。

三种设备访问路径:从软件模拟到硬件直通 全虚拟化 Guest OS + 原生驱动 模拟设备 e1000 / IDE QEMU 逐寄存器模拟 物理 PCIe 设备 每次 I/O 触发 VM Exit,开销最大 半虚拟化 Guest OS + virtio 驱动 virtqueue 共享内存环 Hypervisor 批量转发 物理 PCIe 设备 减少 VM Exit,仍有数据拷贝 设备直通 Guest OS + 原生驱动 IOMMU 地址/中断重映射 VFIO 隔离与绑定 物理 PCIe 设备 数据路径最短,接近原生

四、设备直通的定义与价值

设备直通(Device Passthrough),又称 PCIe Passthrough,是指把宿主上的一个物理 PCIe 设备(或 SR-IOV 虚拟功能 VF)直接分配给某个虚拟机,使 Guest 内的原生驱动能够直接访问该设备的配置空间、MMIO 寄存器与 DMA 引擎。Hypervisor 不再模拟该设备,只负责在设备分配、DMA 重映射和中断投递上做安全隔离。

它的价值主要体现在三个方面:

  • 性能接近原生:消除模拟层与数据拷贝,GPU 渲染、NVMe 高 IOPS、25/100G 网卡转发等场景收益显著。
  • 功能完整:模拟设备往往只覆盖基础功能,直通后 Guest 可使用厂商驱动的全部特性,如 GPU 编码器、网卡卸载、NVMe 多队列。
  • 降低 CPU 开销:I/O 不再由宿主 CPU 代劳,vCPU 可以专注于业务负载,提升整机密度。
设备直通不是“把设备从宿主拿走”那么简单。宿主必须放弃对该设备的驱动绑定,改由 VFIO 等框架接管;同时 IOMMU 必须开启,否则设备 DMA 可以访问任意物理内存,Guest 就能越权读写宿主或其他虚拟机内存。

五、典型场景与配置片段

以 KVM/QEMU 为例,直通一块网卡通常需要先确认 IOMMU 分组,再把设备绑定到 vfio-pci,最后在 QEMU 命令行中通过 -device vfio-pci 分配。下面是一段常见的检查与绑定命令:

# 确认 IOMMU 已开启
dmesg | grep -e DMAR -e IOMMU

# 查看设备与 IOMMU 分组
lspci -nn | grep -i ethernet
for d in /sys/kernel/iommu_groups/*/devices/*; do
  echo "IOMMU Group $(basename $(dirname $(dirname $d))): $(lspci -nns ${d##*/})"
done

# 绑定到 vfio-pci
echo 0000:01:00.0 > /sys/bus/pci/devices/0000:01:00.0/driver/unbind
echo vfio-pci > /sys/bus/pci/devices/0000:01:00.0/driver_override
echo 0000:01:00.0 > /sys/bus/pci/drivers/vfio-pci/bind

在 QEMU 中分配该设备:

qemu-system-x86_64 \
  -enable-kvm \
  -m 8G \
  -cpu host \
  -device vfio-pci,host=01:00.0,id=net0 \
  -drive file=guest.qcow2,if=virtio

六、常见误区与复盘

误区一:只要开启 VT-d 就能直通。 实际上还需要内核支持、VFIO 绑定、IOMMU 分组合理,以及设备本身支持 FLR(Function Level Reset),否则 Guest 重启后设备可能无法恢复。

误区二:直通一定比 virtio 快。 对于小包、低频 I/O,virtio 的批量通知机制可能更省 CPU;直通的优势在高吞吐、低延迟、功能完整场景。选型应基于实测。

误区三:忽略 IOMMU 分组。 如果目标设备与宿主关键设备(如 SATA 控制器、USB 控制器)在同一分组,强行直通会连带把宿主设备也交给 Guest,导致宿主失去磁盘或键鼠。此时需要 ACS 覆盖或更换插槽。

直通前务必确认设备所在 IOMMU 分组是否“干净”。分组不干净时,不要贸然绑定 vfio-pci,否则可能造成宿主失去关键设备,甚至无法远程恢复。