HOOOS

PVE 8.1 升级后 PCIe 直通失效?彻底解决 vfio-pci Cannot read device rom 报错

0 24 极客老柴 Proxmox VEPCIe直通显卡直通
Apple

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。

操作步骤:

  1. 登录 PVE Web 界面。
  2. 选择对应的虚拟机,进入 硬件 (Hardware) 选项卡。
  3. 双击报错的 PCI-E 设备
  4. 在弹出的配置窗口中,展开 高级 (Advanced) 选项。
  5. 取消勾选 ROM-Bar
  6. 保存并尝试启动虚拟机。

或者,你也可以直接编辑虚拟机的配置文件:

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)删掉开头的 之前的所有无用字符(使其以 / 即十六进制的 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=onamd_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 并重启宿主机。

点评评价

captcha
健康