在虚拟化环境中,将物理显卡直接分配给虚拟机(即显卡直通)是提升虚拟机图形性能的重要手段。本文将详细介绍如何在Linux系统中实现KVM多显卡直通,特别适用于需要在虚拟机中获得接近原生性能的用户。
前提条件
- 支持虚拟化的CPU(大多数现代CPU都支持)
- 支持IOMMU的主板(Intel VT-d或AMD-Vi)
- 至少一张可用于直通的独立显卡
- 运行Linux的宿主机系统
详细步骤
1. 启用BIOS中的虚拟化功能
首先需要在主板BIOS中启用虚拟化功能。根据不同的主板和CPU,这个选项可能被称为:
- Intel系统:VT-x和VT-d
- AMD系统:AMD-V和AMD-Vi
注意:部分老旧CPU可能不支持这些功能
2. 在宿主机系统中启用IOMMU组
IOMMU(Input/Output Memory Management Unit)是实现设备直通的关键技术。我们需要在Linux系统中启用它:
- 打开GRUB配置文件:
1
| sudo nano /etc/default/grub
|
- 找到
GRUB_CMDLINE_LINUX_DEFAULT
行,修改为:
1
| GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on"
|
注意:如果使用AMD处理器,请使用amd_iommu=on
替代intel_iommu=on
- 更新GRUB配置:
1 2 3 4 5
| sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo update-grub
|
- 重启系统后,验证IOMMU是否正确启用:
如果看到类似pci xxxx:xx:xx.x: Adding to iommu group xx
的输出,说明IOMMU已成功启用。
重要说明:系统中的所有设备只能按照IOMMU组为单位分配给宿主机或虚拟机。如果两个不相关的设备在同一个组内,它们必须一起分配。Linux系统不支持预留IOMMU组,因此我们需要阻止Linux内核在启动时初始化特定组内的硬件。
3. 寻找需要预留的IOMMU组
- 首先确认显卡所在的PCIe总线和产品型号:
1
| lspci -nnv | grep -i nvidia
|
输出示例:
1 2 3 4 5 6 7
| 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation Device [10de:2203] (rev a1) (prog-if 00 [VGA controller]) Kernel driver in use: nvidia Kernel modules: nvidiafb, nouveau, nvidia_drm, nvidia 01:00.1 Audio device [0403]: NVIDIA Corporation GA102 High Definition Audio Controller [10de:1aef] (rev a1) 05:00.0 VGA compatible controller [0300]: NVIDIA Corporation Device [10de:2203] (rev a1) (prog-if 00 [VGA controller]) Kernel modules: nvidiafb, nouveau, nvidia_drm, nvidia 05:00.1 Audio device [0403]: NVIDIA Corporation GA102 High Definition Audio Controller [10de:1aef] (rev a1)
|
解读PCI设备信息:
01:00.0
和01:00.1
等编号通过冒号分为三部分:PCIe的domain ID、bus ID和device id.function id
[0300]
是设备类型编号,不同类型设备(网络、存储、显卡等)有不同编号
[10de:2203]
中,10de
是NVIDIA的厂商ID,2203
表示这是一个3090Ti显卡
- 找出设备所在的IOMMU组:
1 2
| sudo dmesg | grep iommu | grep 01:00.0 sudo dmesg | grep iommu | grep 05:00.0
|
输出示例:
1 2
| [ 0.536462] pci 0000:01:00.0: Adding to iommu group 17 [ 0.536491] pci 0000:05:00.0: Adding to iommu group 20
|
- 确认IOMMU组中的所有设备:
1
| sudo dmesg | grep "iommu group 17"
|
输出示例:
1 2
| [ 0.536462] pci 0000:01:00.0: Adding to iommu group 17 [ 0.536467] pci 0000:01:00.1: Adding to iommu group 17
|
4. 屏蔽显卡驱动
有两种方法可以屏蔽显卡,使其不被宿主机系统使用:
方法一:型号屏蔽法
适用于只有一张显卡或多张显卡ID不同的情况:
- 修改GRUB配置:
1
| sudo nvim /etc/default/grub
|
- 在
GRUB_CMDLINE_LINUX_DEFAULT
中添加设备ID:
1 2 3 4 5
| # 使用pci-stub方法 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on pci-stub.ids=10de:2203,10de:1aef"
# 或使用vfio-pci方法 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on vfio-pci.ids=10de:2203,10de:1aef"
|
- 更新GRUB并重启:
1 2 3 4 5
| sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo update-grub
|
- 验证屏蔽是否成功:
1
| lspci -nnv | grep -E "(^\S|Kernel driver in use)" | grep 01:00 -A 1
|
成功屏蔽后的输出:
1 2 3 4
| 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation Device [10de:2203] (rev a1) (prog-if 00 [VGA controller]) Kernel driver in use: vfio-pci 01:00.1 Audio device [0403]: NVIDIA Corporation GA102 High Definition Audio Controller [10de:1aef] (rev a1) Kernel driver in use: vfio-pci
|
方法二:脚本屏蔽法
适用于多张相同型号显卡的情况:
- 创建VFIO脚本:
1
| sudo nano /etc/initramfs-tools/scripts/init-top/vfio.sh
|
- 添加以下内容:
1 2 3 4 5 6
| #!/bin/sh echo "vfio-pci" > /sys/bus/pci/devices/0000:01:00.0/driver_override echo "vfio-pci" > /sys/bus/pci/devices/0000:01:00.1/driver_override
exit 0
|
- 给脚本添加执行权限:
1
| sudo chmod 744 /etc/initramfs-tools/scripts/init-top/vfio.sh
|
- 更新initramfs:
1
| sudo update-initramfs -u -k all
|
- 重启系统后验证显卡驱动是否被vfio-pci接管
恢复显卡挂载:如需恢复显卡使用,只需注释掉脚本中的两行echo命令,刷新initramfs并重启即可。
5. 在KVM中使用直通显卡
完成以上步骤后,您可以在KVM虚拟机配置中添加PCI设备,选择已屏蔽的显卡,即可实现显卡直通。
参考资料