PVE 8.1 升级将系统内核推进到了 6.5+ 版本(甚至后续更新到了 6.8)。内核版本的跨越式升级带来了更严格的设备安全检测、变化了的 IOMMU 组划分逻辑,以及全新的驱动加载顺序。
如果你在升级后启动虚拟机时,遇到了类似以下的报错,导致虚拟机无法启动或显卡报 Code 43 错误:
kvm: -device vfio-pci,host=0000:01:00.0,...: bar 0 connection broken
vfio-pci 0000:01:00.0: Invalid ROM contents
vfio-pci 0000:01:00.0: Cannot read device rom: -5
不要慌,这是由于 PVE 新内核在初始化 PCIe 设备时,宿主机驱动提前占用了 ROM Bar,或者因为节能协议(ASPM)导致 VFIO 无法读取物理设备的 VBIOS ROM。
以下是针对该问题的三种递进式解决方案。
方案一:最快临时方案 —— 关闭 ROM Bar(适用非主显卡/免 Boot 设备)
如果直通的设备不需要在虚拟机开机阶段提供视频输出(例如作为副卡进行 AI 炼丹、编解码,或者是网卡、USB 扩展卡等),最简单的办法就是直接禁止虚拟机读取该设备的物理 ROM。
操作步骤:
- 登录 PVE Web 界面。
- 选择对应的虚拟机,进入 硬件 (Hardware) 选项卡。
- 双击报错的 PCI-E 设备。
- 在弹出的配置窗口中,展开 高级 (Advanced) 选项。
- 取消勾选 ROM-Bar。
- 保存并尝试启动虚拟机。
或者,你也可以直接编辑虚拟机的配置文件:
nano /etc/pve/qemu-server/虚拟机ID.conf
找到你的 hostpci 行,在末尾加上 ,rombar=0。例如:
hostpci0: 0000:01:00,pcie=1,rombar=0
方案二:终极解决方案 —— 手动提取并挂载本地 VBIOS ROM(推荐 GPU 直通使用)
对于作为主显卡直通(需要输出亮机画面、物理接显示器)的 GPU,关闭 ROM Bar 可能会导致虚拟机无信号输出。此时最完美的解决办法是:在宿主机本地存放一个干净的 VBIOS 文件,强行喂给虚拟机。
第一步:获取你的显卡 VBIOS
- 方法 A(推荐): 访问 TechPowerUp VBIOS Database 查找与你显卡型号、品牌、显存规格完全一致的 VBIOS 文件并下载(
.rom或.bin格式)。 - 方法 B(自行提取): 如果不想用网上的,可以在 PVE 命令行自行提取(注意:提取时不能有任何程序占用显卡):
# 查找显卡 PCI 地址,例如 01:00.0 lspci # 临时解绑驱动并提取 echo 1 > /sys/bus/pci/devices/0000:01:00.0/rom cat /sys/bus/pci/devices/0000:01:00.0/rom > /usr/share/kvm/gpu_vbios.bin echo 0 > /sys/bus/pci/devices/0000:01:00.0/rom
注意(NVIDIA 显卡专属坑): 如果你使用的是 NVIDIA 显卡,且是从 TechPowerUp 下载的 ROM,该 ROM 开头通常带有 header 信息,需要使用十六进制编辑器(如 Hex Editor)删掉开头的
Uª之前的所有无用字符(使其以Uª/ 即十六进制的55 AA开头),否则 KVM 会报错格式不支持。
第二步:将 VBIOS 文件放入指定目录
将处理好的 .bin 或 .rom 文件通过 SFTP 上传到 PVE 宿主机的 /usr/share/kvm/ 目录下。假设命名为 my_gpu.bin。
确保赋予其读取权限:
chmod 644 /usr/share/kvm/my_gpu.bin
第三步:修改虚拟机配置引入该 ROM
编辑虚拟机配置文件:
nano /etc/pve/qemu-server/你的VM_ID.conf
定位到直通显卡的那一行,添加 romfile=my_gpu.bin:
hostpci0: 0000:01:00,pcie=1,x-vga=1,romfile=my_gpu.bin
保存退出,重新启动虚拟机,即可绕过物理 ROM 的读取限制。
方案三:底层排查 —— 彻底防止宿主机驱动抢占(解决根本性冲突)
PVE 8.1 升级后,系统自带的开源驱动(如 nouveau 对应英伟达,amdgpu 对应 AMD,snd_hda_intel 对应声卡)可能会先于 vfio-pci 加载,从而在内核层面“锁死”了 ROM 的读取权限。
我们需要确保这些设备在系统刚引导时,就直接被 vfio-pci 接管。
1. 完善黑名单配置
编辑黑名单文件:
nano /etc/modprobe.d/pve-blacklist.conf
确保添加了以下内容(根据你的显卡阵营选择):
# 屏蔽 NVIDIA 驱动
blacklist nouveau
blacklist nvidia
blacklist nvidia_drm
blacklist nvidia_modeset
# 屏蔽 AMD 驱动(如果直通 AMD 显卡)
blacklist amdgpu
# 屏蔽声卡驱动(防止声卡部分导致设备无法解绑)
blacklist snd_hda_intel
blacklist snd_hda_codec_hdmi
2. 强行绑定 VFIO ID
获取显卡的硬件 ID(Vendor ID 和 Device ID):
lspci -nn | grep -i vga
假设输出为:01:00.0 VGA compatible controller [0300]: NVIDIA Corporation AD104 [GeForce RTX 4070] [10de:2786] (rev a1)。其中 10de:2786 就是 ID。
编辑 vfio 配置文件:
nano /etc/modprobe.d/vfio.conf
写入以下内容(把其中的 ID 替换为你自己的显卡及配套声卡 ID):
options vfio-pci ids=10de:2786,10de:22bc disable_vga=1
3. 黄金一步:更新 initramfs 与引导
PVE 8 废弃了部分旧版引导管理方式,务必使用以下命令刷新内核模块和引导分区:
# 更新 initramfs
update-initramfs -u -k all
# 如果你的 PVE 采用 ZFS 或 UEFI 引导,务必刷新 boot tool
proxmox-boot-tool refresh
最后重启 PVE 宿主机,让配置彻底生效。
避坑提示:PVE 8.1 升级后的 grub 丢失问题
在 PVE 8.x 中,许多用户反映原本写在 /etc/default/grub 里的 intel_iommu=on 或 amd_iommu=on 在升级后失效了。
这是因为 PVE 8.1 默认采用 systemd-boot(如果系统安装在 ZFS 上)。请运行以下命令确认引导方式:
efibootmgr -v
如果是 systemd-boot,你需要修改的文件不是 grub,而是:
nano /etc/kernel/cmdline
确保该文件中整行内容的末尾包含 intel_iommu=on iommu=pt(Intel 处理器)或 amd_iommu=on iommu=pt(AMD 处理器),修改后同样需要执行 proxmox-boot-tool refresh 并重启宿主机。