跳转至

硬件直通

脚本实现

硬件直通的话,Github 上面已经有成熟的脚本了。

项目地址为:https://github.com/ivanhao/pvetools

在通外网的情况下,可以一键安装运行,操作十分简单,细节不再赘述:

Bash
echo "nameserver  8.8.8.8" >> /etc/resolv.conf && rm /etc/apt/sources.list.d/pve-enterprise.list && export LC_ALL=en_US.UTF-8 && apt update && apt -y install git && git clone https://github.com/ivanhao/pvetools.git && cd pvetools && ./pvetools.sh

手工实现

但是,既然写教程了,肯定还是要说一下如何手工配置硬件直通。

检测 IOMMU 是否开启

开启 IOMMU 后,BIOS 可以收集 IOMMU 硬件相关的信息以及它和 PCIe 设备连接关系的信息,使用如下命令检测是否开启,如果开启 IOMMU 的话可以看到一些 PCIe 硬件设备:

Bash
dmesg | grep -e DMAR -e IOMMU

开启 IOMMU 和 SR-IOV

IOMMU 是 Intel VT-d 和 AMD-Vi 的通用名称。

先备份一下 grub 文件:

Bash
cp /etc/default/grub /etc/default/grub.bak

然后修改 /etc/default/grub 文件:

Bash
nano /etc/default/grub

将:GRUB_CMDLINE_LINUX_DEFAULT="quiet" 下面我们主要根据自己的平台来修改这一行配置。

硬件直通可能需要用到的一些常见参数解释...... 点击展开表格 👉
参数 解释说明
quiet 默认参数,表示在启动过程中只显示重要信息
intel_iommu=on 用 intel_iommu 驱动来驱动 IOMMU 硬件单元
amd_iommu=on 用 amd_iommu 驱动来驱动 IOMMU 硬件单元
iommu=pt 只为使用透传功能的设备启用 IOMMU,并可以提供更好的功能和性能
pci=assign-busses 部分网卡开启 SR-IOV 需要这个参数,否则可能报错
PCIe_acs_override=downstream 用于将 iommu groups 拆分,方便灵活按需直通一些板载的设备
PCIe_acs_override=multifunction PCIe 直通多功能支持,提高直通完美度(可选)
nofb 该选项允许你不用一个frame缓冲来使用图形安装程序
textonly 仅在文本模式下支持 GRUB 串行控制台
nomodeset 系统启动过程中,暂时不运行图像驱动程序
video=vesafb:off 禁用 vesa 启动显示设备
video=efifb:off 禁用 efi 启动显示设备
video=simplefb:off 5.15 内核开始直通可能需要这个参数
initcall_blacklist=sysfb_init 部分 A 卡如 RX580 直通异常可能需要这个参数
pcie_aspm=off 关闭 PCIe 设备的 ASPM 节能模式,解决部分 PCIe 设备 AER 报错
pcie_aspm=force 强制 PCIe 设备及爱情 ASPM 节能模式,解决部分 PCIe 设备 AER 报错
pci=noaer 不输出 AER 报错日志,华南主板经常会 AER 报错,建议配合使用,眼不见心不烦
pci=nomsi 在系统范围内禁用 MSI 中断,主要还是解决 PCIe 相关的报错
pci=nommconf 解决 PCIe 相关的报错,PCIe Bus Error 等,华南主板可能需要这个参数
  • Intel 平台 修改为:
INI
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt textonly nomodeset nofb pci=noaer pcie_acs_override=downstream,multifunction"
  • AMD 平台 修改为:
INI
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt textonly nomodeset nofb pci=noaer pcie_acs_override=downstream,multifunction"
部分显卡如 RX580 直通的时候稍微不一样,得使用 initcall_blacklist=sysfb_init 替代 video 系列参数

INI
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt pci=assign-busses pcie_acs_override=downstream,multifunction nofb textonly nomodeset initcall_blacklist=sysfb_init"
否则大概率会卡 Failed to mmap 0000:xxx:00.0 BAR 0. Performance may be slow

改完之后更新一下 grub 并重启:

Bash
update-grub && reboot

使用如下命令查看是否拆分了 iommu groups:

Bash
ls -l /sys/kernel/iommu_groups/*/devices

添加 VFIO 模块

为了我们的显卡顺利直通,需要添加 VFIO 模块到 /etc/modules 文件中:

Bash
echo "vfio" > /etc/modules
echo "vfio_iommu_type1s" >> /etc/modules
echo "vfio_pci" >> /etc/modules
echo "vfio_virqfd" >> /etc/modules

将常见的驱动程序加入黑名单,即让 GPU 相关设备在下次系统启动之后不使用这些驱动,把设备腾出来给 vfio 驱动用:

Bash
echo "blacklist nvidiafb" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nvidia" >> /etc/modprobe.d/blacklist.conf
echo "blacklist radeon" >> /etc/modprobe.d/blacklist.conf
echo "blacklist amdgpu" >> /etc/modprobe.d/blacklist.conf
echo "blacklist snd_hda_intel" >> /etc/modprobe.d/blacklist.conf
echo "blacklist snd_hda_codec_hdmi" >> /etc/modprobe.d/blacklist.conf
echo "blacklist i915" >> /etc/modprobe.d/blacklist.conf

然后更新内核重启机器:

Bash
update-initramfs -u && reboot

重启后,检查之前配置的 VFIO 模块是否正常加载:

Bash
lsmod |grep vfio

下图这样表示是成功加载了的。

IOMMU 中断重映射

如果没有中断重新映射,将无法使用 PCI 直通。所有使用支持英特尔定向 I/O 虚拟化技术 (VT-d) 但不支持中断重新映射的英特尔处理器和芯片组的系统都报错。较新的处理器和芯片组(AMD 和 Intel)都提供了中断重新映射支持。

可以使用如下命令来确定系统是否支持中断重映射:

Bash
dmesg | grep 'remapping'

如果看到类似下面的内容之一:

Text Only
"AMD-Vi: Interrupt remapping enabled"
"DMAR-IR: Enabled IRQ remapping in x2apic mode"

x2apic 在不同的 CPU 上可能叫法不一样,问题不大。

另外如果你的 CPU 不支持 x2apic 的话,可能是 BIOS 没有开启,我的华南 X99 是需要手动在 BIOS 里面开启的:在 【InterRCSetup】 - 【Processor Configuration】 里面可以打开 X2APIC 选项。

可以看到我们的 IOMMU 是支持中断映射的:

如果很不巧,你的电脑真的不支持 IOMMU 中断重映射的话,可以使用下面的命令修补一下:

Bash
echo "options vfio_iommu_type1 allow_unsafe_interrupts=1" > /etc/modprobe.d/iommu_unsafe_interrupts.conf

OVMF 下显卡直通

虚拟机的 BIOS 推荐为 OVMF 替代默认的 SeaBIOS。不过 OVMF 走的 UEFI 只支持高版本的 Windows (win >=8),另外机型推荐为:q35

首先查找显卡相关的 ID:

Bash
lspci -nn | grep -E "Display|VGA|Audio|AMD|NVIDIA"

除了第 1 个是主板自带的声卡以外,下面这 7 个 ID就是我显卡相关的 ID 了(多个 ID 使用逗号隔开):

INI
10de:0fc2,10de:0e1b,10de:1bb3,10de:2487,10de:228b,1002:67df,1002:aaf0

将上面查找的 ID 数据带入到下面的 ids 后面,如果使用 OVMF 的话,还建议将 disable_vga=1 添加到 vfio-pci 模块:

Bash
echo "options vfio-pci ids=10de:0fc2,10de:0e1b,10de:1bb3,10de:2487,10de:228b,1002:67df,1002:aaf0 disable_vga=1" > /etc/modprobe.d/vfio.conf

重启之后即可直接直通显卡和各种 PCIe 设备了,另外还有提醒一下, OVMF 模式下直通 GPU 的话,有些卡还需要 romfile 参数来指定显卡原本的 ROM (bios)文件才可以:

INI
hostpci0: 01:00,x-vga=on,romfile=vbios.rom
提取显卡的原始 ROM
  1. 通用方法:Windows 下使用 GPU-Z 来保存显卡的 ROM 文件
  2. 下载网上的 ROM 文件, ROM 分享下载网站:https://www.techpowerup.com/vgabios/

部分显卡不需要 romfile 参数也可以直通

  1. AMD RX400、RX500 系列测试无需 romfile 参数也可以直通
  2. AMD RX5000、RX6000 系列大多数需要 romfile 参数才可以顺利直通

防止虚拟机崩溃

某些 Windows 应用程序(如 Geforce Experience、Passmark Performance Test 和 SiSoftware Sandra crash)可能会使虚拟机崩溃。以及为了避免在PVE 下 macOS 黑苹果引导期间出现引导循环死机,我们需要添加:

Bash
echo "options kvm ignore_msrs=1 report_ignored_msrs=0" > /etc/modprobe.d/kvm.conf && update-initramfs -k all -u && reboot

其中 report_ignored_msrs=0 是为了防止控制台刷屏看到很多很多警告消息用的,修改完成重启 PVE 即可。


最后更新: 2023-03-06