VFIO(Virtual Function I/O)是一个现代化的、安全的内核框架,用于在用户空间实现设备直通,例如在 QEMU/KVM 虚拟化环境中。vfio-pci 是该框架下的 PCI 设备驱动。
1. 核心概念:设备直通
设备直通允许虚拟机独占并直接访问宿主机上的一个物理硬件设备。对于虚拟机来说,这个设备就像直接插在它自己的主板上一样,从而可以获得近乎原生的性能。
-
传统模拟:QEMU 完全通过软件模拟一个设备(如 e1000 网卡),性能较差。
-
半虚拟化:使用 virtio 等驱动,在宿主机和虚拟机之间使用高效的通信机制,性能很好,但仍然是虚拟设备。
-
设备直通:虚拟机直接使用物理设备,绕过 VMM 的大部分干预,性能最高。vfio-pci 就是实现 PCI/PCIe 设备直通的关键。
2. 配置 VFIO-PCI 直通
配置步骤如下,下面我们来详细讲解每个步骤。

2.1 确认硬件和 BIOS 支持
IOMMU 支持
-
对于 Intel CPU:需要支持 VT-d (Virtualization Technology for Directed I/O)。
-
对于 AMD CPU:需要支持 AMD-Vi。
-
如何确认:在 BIOS/UEFI 中确保这些功能已开启。然后在 Linux 中执行:
dmesg | grep -e DMAR -e IOMMU
如果看到 DMAR 表或 IOMMU 被初始化的相关信息,则表示支持。
OMMU 分组检查 执行以下命令检查 IOMMU 分组情况:
shopt -s nullglob
for g in /sys/kernel/iommu_groups/*; do
echo "IOMMU Group ${g##*/}:"
for d in $g/devices/*; do
echo -e "\\t$(lspci -nns ${d##*/})"
done
done
2.2 配置 Linux 内核以使用 VFIO
启用内核模块: 确保 vfio_pci、vfio、vfio_iommu_type1 和 vfio_virqfd 模块已加载。通常需要修改 initramfs 来在早期启动时加载它们。
配置内核参数: 在 GRUB 引导器中,修改 /etc/default/grub 文件中的 GRUB_CMDLINE_LINUX 行。
-
对于 Intel:
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"
-
对于 AMD:
GRUB_CMDLINE_LINUX="amd_iommu=on iommu=pt"
-
iommu=pt 表示只为需要直通的设备启用 IOMMU,有助于提升性能。
让 VFIO 提前接管设备(推荐): 为了防止宿主机系统抢先占用你想要直通的设备,可以在内核参数中指定 vfio-pci 来绑定它们。首先,获取设备的 Vendor ID 和 Device ID:
lspci -n -s <设备PCI地址,如 01:00.0>
# 输出示例:01:00.0 0300: 10de:1b80 (rev a1)
然后,同样在 /etc/default/grub 的内核参数中添加:
GRUB_CMDLINE_LINUX="… vfio-pci.ids=10de:1b80,8086:100e"
多个设备 ID 用逗号分隔。
更新配置: 修改后,更新 GRUB 并重建 initramfs,然后重启。
sudo update-grub
sudo update-initramfs -u
sudo reboot
2.3 验证并手动绑定设备(可选)
重启后,验证设备是否已被 vfio-pci 驱动绑定:
lspci -kn -s <设备PCI地址>
在输出中,你应该看到 Kernel driver in use: vfio-pci。
如果未能自动绑定,你可以手动操作:
# 1. 解绑原有驱动
echo <设备PCI地址> | sudo tee /sys/bus/pci/devices/<设备PCI地址>/driver/unbind
# 2. 绑定到 vfio-pci
echo <vendor id> <device id> | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
# 或者直接使用 PCI ID
echo <设备PCI地址> | sudo tee /sys/bus/pci/drivers/vfio-pci/bind
2.4 在 QEMU 命令行中添加设备
最后,在启动 QEMU 虚拟机时,使用 -device vfio-pci 来将设备传递给虚拟机。
-device vfio-pci,host=<BB:DD.F>[,…其他选项]
3. 典型示例
直通一个 GPU
qemu-system-x86_64 \\
… # 其他参数(内存、CPU等)
-device vfio-pci,host=01:00.0,multifunction=on \\
-device vfio-pci,host=01:00.1 \\
…
-
host=01:00.0:指定要直通的设备在宿主机上的 PCI 地址。
-
multifunction=on:如果设备是多功能设备(如 GPU 通常带一个音频控制器 01:00.1),需要此参数,并且必须同时传递所有功能设备。
直通一个网卡
qemu-system-x86_64 \\
… # 其他参数
-net none \\ # 确保不为此设备创建默认网络
-device vfio-pci,host=06:00.0 \\
…
4. 重要注意事项
-
安全性:VFIO 设计上是安全的,它利用 IOMMU 进行 DMA 隔离,防止设备直接访问任意内存。
-
GPU 直通:这是最常见的用途(也称为 "VGA Passthrough" 或 "GPU Passthrough")。通常还需要在 QEMU 参数中隐藏虚拟化状态、使用特定的 BIOS 设置(如 vgabios 转储)等,过程更为复杂。
-
驱动程序冲突:最大的挑战是确保宿主机没有占用设备。使用内核参数提前绑定是最可靠的方法。
-
IOMMU 分组:如果设备所在的 IOMMU 组中有其他不想直通的设备,你将无法单独直通该设备。解决此问题可能需要使用支持 ACS override 的内核参数(pci=acs_override=on)或特定的 PCIe 插槽,但这可能会降低系统安全性。
IOMMU Group 10:
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP106 [GeForce GTX 1060 6GB] [10de:1c03] (rev a1)
01:00.1 Audio device [0403]: NVIDIA Corporation GP106 High Definition Audio Controller [10de:10f1] (rev a1)-
独立分组:理想的直通设备应该位于独立的 IOMMU 组中。
-
多功能设备:如上面的 Group 10,包含 GPU (01:00.0) 和其音频控制器 (01:00.1),它们必须一起直通。
-
问题分组:如果一个组包含不相关的设备(如 GPU + 网卡),则无法单独直通其中一个。
-
VFIO-PCI 驱动是实现高性能 PCI/PCIe 设备直通的工业标准方法。虽然配置过程稍显复杂,但它能让你在虚拟机中获得最佳的硬件性能,尤其适用于图形工作站、游戏虚拟机和需要低延迟网络的应用场景。
技术交流,欢迎加入社区:GPUers。
