跳过正文
  1. 博客文章/

把一张 RX 6400 塞进虚拟机:PVE GPU 直通 + Windows Server RDS 部署全记录

·1337 字·7 分钟·
虚拟化 PVE Proxmox GPU Passthrough Windows Server RDS AMD RX 6400 VFIO IOMMU
Zayn
作者
Zayn
专注 Kubernetes、CI/CD、可观测性等云原生技术栈,记录生产环境中的实战经验与踩坑复盘。
目录
PVE 实践 - 这篇文章属于一个选集。
3: 本文
事情的起因很简单:几个工程师需要远程跑 Cadence、PADS、AutoCAD 和 Creo,手头只有一台装了 PVE 的 Ryzen 5600X 主机和一张 RX 6400。听起来不难,做起来全是坑。

需求拆解
#

先把需求摊开看。要跑的软件有四个,GPU 依赖程度各不相同:

软件用途对 GPU 的依赖
Cadence 16.6PCB/原理图极低,纯 2D
PADS VX2.4PCB 设计低,3D 预览需基础 OpenGL
AutoCAD 2020工程制图中,DirectX/OpenGL 加速
Creo 5.03D 建模中,OpenGL 渲染

Cadence 和 PADS 其实纯 CPU 软渲染就能应付。真正需要 GPU 的是 AutoCAD 的大图纸和 Creo 的三维装配体。所以一开始的策略是先不折腾 GPU,装好系统跑起来试试 —— 如果软渲染够用,就省了一堆事。

结论是:不够用。Creo 打开稍微复杂一点的模型就明显卡顿,AutoCAD 在缩放大图纸时也有延迟。于是只好走 GPU 直通这条路。

硬件情况
#

先说结论:这套硬件能跑通 GPU 直通,但过程不算顺利。如果你也是 B550 + RX 6400 的组合,下面的内容可能帮你省掉几个小时的排查。
项目配置
CPUAMD Ryzen 5 5600X(12 线程)
内存64GB DDR4
GPUAMD Radeon RX 6400(Navi 24,盈通,4GB)
主板B550 芯片组
存储NVMe 476GB(系统)+ 2x NVMe 931GB RAID0 + SATA 1.8TB
PVE8.4.0,内核 6.8.12-17-pve

第一道坎:IOMMU 分组
#

lspci -tv 看 PCIe 拓扑的时候就意识到问题了。RX 6400 是一张 x4 通道的入门卡,它不走 CPU 直连的 x16 插槽,而是挂在 B550 芯片组的 PCIe Switch 下面。

graph TD
    CPU["Ryzen 5 5600X
PCIe Root Complex"] CPU -->|"Root Port 00:01.1
CPU 直连 x4"| NVMe1["ADATA NVMe"] CPU -->|"Root Port 00:01.2
CPU 直连 x4"| Chipset["B550 芯片组 Switch"] CPU -->|"Root Port 00:03.1~3
CPU 直连"| NVMe234["3x WD NVMe"] Chipset --> USB["USB 3.1"] Chipset --> SATA["SATA"] Chipset -->|"芯片组桥接 → Navi 内置 Switch"| GPU["RX 6400"] Chipset --> WiFi["MT7921 WiFi"] Chipset --> ETH["RTL8125 2.5G"] style GPU fill:#e74c3c,color:#fff style Chipset fill:#3498db,color:#fff

问题在于,挂在同一个芯片组 Switch 下的设备全部被内核归到了同一个 IOMMU Group 17 —— 一共 12 个设备:

IOMMU Group 17:
  02:00.0 USB 3.1 控制器
  02:00.1 SATA 控制器
  02:00.2 芯片组 Switch 上行端口
  03:00.0 / 03:08.0 / 03:09.0 PCIe 桥接
  04:00.0 Navi 内置 Switch 上行端口
  05:00.0 Navi 内置 Switch 下行端口
  06:00.0 RX 6400 GPU              ← 我们要的
  06:00.1 HDMI/DP 音频控制器        ← 我们要的
  07:00.0 MT7921 WiFi 网卡
  08:00.0 RTL8125 有线网卡

PCI 直通的规则是:要么把整个 IOMMU 组的设备全部传给虚拟机,要么一个都不传。显然不能把 USB、SATA 和网卡全交出去 —— 宿主机还要用这些东西。

主板上也没有多余的 CPU 直连 x16 槽位给我换一张 x8/x16 的显卡,四个 NVMe 已经把 CPU 的 PCIe 通道占满了。所以换卡方案也走不通。

ACS Override:强制拆分 IOMMU 组
#

ACS(Access Control Services)是 PCIe 规范中的一项安全特性,控制设备之间的 DMA 数据流。当 PCIe Switch 不支持 ACS 时,其下的设备可以绕过 IOMMU 直接互相访问内存,内核因此将它们归入同一个 IOMMU 组。pcie_acs_override 参数让内核假装硬件支持 ACS,从而将每个设备拆到独立的组。代价是放弃了硬件级 DMA 隔离 —— 家用环境风险可以忽略。

PVE 的内核已经内置了 ACS Override 补丁(可以通过 grep pcie_acs_overrides /proc/kallsyms 验证),所以不需要自己编译内核。

宿主机配置
#

这一段涉及四个文件的修改,全部做完后才重启。漏掉任何一步都会导致 GPU 没法正确交给 vfio-pci。

GRUB 参数
#

编辑 /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt pcie_acs_override=downstream,multifunction vfio-pci.ids=1002:743f,1002:ab28 video=vesafb:off video=efifb:off initcall_blacklist=sysfb_init"

这行参数做了六件事:

参数干什么的
amd_iommu=on启用 IOMMU
iommu=ptpassthrough 模式,不直通的设备不经 IOMMU 翻译,性能更好
pcie_acs_override=downstream,multifunction拆分 IOMMU 组
vfio-pci.ids=1002:743f,1002:ab28让 GPU(743f)和它的音频控制器(ab28)在启动时就被 vfio-pci 抢占
video=vesafb:off video=efifb:off禁用内核帧缓冲,不让宿主机碰 GPU
initcall_blacklist=sysfb_init避免 sysfb 与 GPU 的 BOOTFB 冲突
怎么查你的设备 ID?运行 lspci -nn | grep -i vga,输出里方括号内的 1002:743f 就是 Vendor:Device ID。音频控制器用 lspci -nn | grep -i audio | grep AMD 查。

VFIO 模块配置
#

三个 modprobe 配置文件:

/etc/modprobe.d/vfio.conf

options vfio-pci ids=1002:743f,1002:ab28
softdep amdgpu pre: vfio-pci

softdep 这行很关键 —— 它告诉内核在加载 amdgpu 驱动之前先加载 vfio-pci,确保 vfio-pci 能抢先绑定 GPU。没有这行的话,amdgpu 可能先把显卡占住,vfio-pci 就拿不到了。

/etc/modprobe.d/blacklist-amdgpu.conf

blacklist amdgpu

双保险,直接把 amdgpu 拉黑。

/etc/modprobe.d/kvm.conf

options kvm ignore_msrs=1

Windows 会访问一些 KVM 不认识的 MSR(Model Specific Register),默认行为是内核直接 panic。加上这个参数让它忽略掉。

内核模块
#

/etc/modules 中追加:

vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

更新引导并重启
#

update-grub
update-initramfs -u -k all
reboot
重启后宿主机没有本地显示输出了。 GPU 已经被 vfio-pci 接管,宿主机的显示器会黑屏。后续只能通过 SSH 或 PVE Web UI(https://宿主机IP:8006)管理。确保你的 SSH 连接正常再重启。

验证
#

重启后 SSH 进来检查:

# 内核参数是否生效
cat /proc/cmdline
# 确认能看到 pcie_acs_override 和 vfio-pci.ids

# GPU 是否被 vfio-pci 绑定
lspci -s 06:00.0 -k
# Kernel driver in use: vfio-pci  ← 看到这个就对了

# IOMMU 组是否成功拆分
ls /sys/kernel/iommu_groups/ | wc -l
# 修改前 26 个组,修改后 37 个组

验证 GPU 独立在自己的 IOMMU 组中(不再和 USB、SATA 混在一起):

find /sys/kernel/iommu_groups/ -type l | \
  while read l; do
    g=$(echo $l | awk -F/ '{print $5}')
    d=$(basename $l)
    echo "Group $g: $(lspci -s $d)"
  done | grep "06:00"

# 期望输出:
# Group 25: 06:00.0 VGA ... AMD Radeon RX 6400
# Group 26: 06:00.1 Audio ... Navi 21/23 HDMI/DP

创建 Windows Server 2022 虚拟机
#

一个关于 UEFI 的教训
#

一开始我用的是 OVMF(UEFI BIOS)+ Q35 + Secure Boot + TPM 2.0 的"豪华"配置。结果发现 VM 怎么都不从 ISO 启动 —— 直接跳到 UEFI Shell 或者 BIOS 设置界面。

排查过程走了三轮弯路:

  1. IDE 光驱 → OVMF 根本不认 IDE 设备的启动能力,换 SATA
  2. SATA 光驱 → 还是进 UEFI Shell → 重建 EFI NVRAM(删除 efidisk 再创建),无效
  3. 关闭 Secure Bootpre-enrolled-keys=0)→ 依然无效

ISO 挂载是正常的(mount -o loop 确认过 /efi/boot/bootx64.efi 存在且签名有效),QEMU Monitor 里也能看到光驱已挂载。就是不引导。

最后换了 SeaBIOS 一次就进安装界面了。Windows Server 2022 不强制要求 UEFI/TPM(那是 Windows 11 桌面版的要求),用 SeaBIOS 完全没问题。

VM 创建参数
#

qm create 200 \
  --name win-server-2022-rds \
  --memory 8192 \
  --balloon 4096 \
  --cores 6 \
  --sockets 1 \
  --cpu host \
  --ostype win11 \
  --machine pc-q35-9.2 \
  --bios seabios \
  --scsihw virtio-scsi-single \
  --scsi0 sda:100,ssd=1,iothread=1,cache=writeback,discard=on \
  --sata0 sda:iso/windows-server-2022.iso,media=cdrom \
  --sata1 local:iso/virtio-win-0.1.285.iso,media=cdrom \
  --net0 virtio,bridge=vmbr0,firewall=0 \
  --vga virtio \
  --boot "order=sata0;scsi0" \
  --agent 1 \
  --numa 1

几个值得注意的选项:

  • machine: pc-q35-9.2 —— Q35 芯片组才支持 PCIe passthrough,i440fx 不行
  • scsihw: virtio-scsi-single —— 半虚拟化磁盘控制器,性能远好于 IDE/SATA 模拟,但 Windows 安装时需要从 VirtIO ISO 加载驱动
  • balloon: 4096 —— 内存上限 8GB,最低可缩到 4GB,让宿主机能回收闲置内存
  • cache: writeback —— 写缓存,提升磁盘写入性能
  • 选择 Standard (Desktop Experience) —— 不要选纯 Server Core,RDS 桌面访问需要完整 GUI

安装过程
#

安装 Windows 时磁盘选择界面会显示空白(看不到 VirtIO SCSI 磁盘),需要手动加载驱动:

  1. 点击 “加载驱动程序”
  2. 浏览 VirtIO ISO → vioscsi\2k22\amd64 → 加载 SCSI 驱动
  3. 再加载一次 → NetKVM\2k22\amd64 → 网卡驱动
  4. 现在能看到 100GB 磁盘了,选中继续安装

装好系统后从 VirtIO ISO 运行 virtio-win-guest-tools.exe,一次性安装全部驱动和 QEMU Guest Agent。

GPU 直通
#

系统装好后把 GPU 挂上去:

qm set 200 --hostpci0 0000:06:00,pcie=1

0000:06:00 会同时包含 .0(GPU)和 .1(音频),pcie=1 启用 PCIe 模式。

启动 VM 时可能看到这样的警告:

error writing '1' to '/sys/bus/pci/devices/0000:06:00.0/reset': Inappropriate ioctl for device
failed to reset PCI device '0000:06:00.0', but trying to continue...

这是 AMD 消费级卡的通病(Reset Bug),不影响正常使用,但 VM 关机后再启动可能需要冷启动宿主机

驱动安装:绕过 AMD 的 OS 检查
#

GPU 进了 VM,Windows 设备管理器里也能看到 —— 但显示为 Microsoft 基本显示适配器,状态是 Error。需要装 AMD 驱动。

问题是 AMD Adrenalin 安装器不支持 Windows Server。运行后直接报 Error 184(不支持的操作系统)。但驱动本身是兼容的,只是安装器做了 OS 检查。

绕过方法:手动安装

  1. 下载 Adrenalin 驱动(选 Windows 10/11 版本)
  2. 运行安装包 → 它会解压文件到 C:\AMD\ → 然后报错退出(正常,我们只要解压出来的文件)
  3. 设备管理器 → 找到 Error 状态的显示适配器 → 右键 → 更新驱动程序
  4. 浏览我的电脑以查找驱动程序 → 路径填 C:\AMD\ → 勾选 “包含子文件夹”
  5. 如果提示兼容性警告,选 “仍然安装”
  6. 重启
备选方案:RX 6400 和 Radeon PRO W6400 是同一颗 Navi 24 芯片。PRO 驱动官方支持 Windows Server 2022,可以试试从 PRO W6400 的驱动页面下载后用同样的方式手动安装。另外 GitHub 上有一个 AMD_DriverMagic_PatchWinServer2022-2025 工具,可以修改驱动 INF 文件绕过 OS 检查,实现完整 Adrenalin 安装。

配置 RDS 远程桌面服务
#

GPU 搞定后,配置 RDS 让多个用户能同时通过 RDP 登录。

安装 RDS 角色
#

Install-WindowsFeature -Name RDS-RD-Server -IncludeManagementTools -Restart

一个关于域环境的坑
#

装好 RDS 打开服务器管理器的 “远程桌面服务” 页面时,会看到一行提示:

“你当前是以计算机上本地管理员身份登录的。必须以域用户的身份登录才能管理服务器和集合。”

这意味着 RDS 的完整管理功能(创建集合、发布 RemoteApp)需要 Active Directory 域环境。对于我们这种单机场景,搭域控太重了。

更简单的方案:不用 RemoteApp,直接让每个用户 RDP 登录完整桌面,各自打开需要的软件。实际使用中 RemoteApp 和完整桌面对 GPU 的消耗差距可以忽略 —— GPU 的主要负载来自 CAD 应用本身,不在桌面合成。

多用户 RDP 配置
#

# 开启远程桌面
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" `
  -Name "fDenyTSConnections" -Value 0

# 允许同一用户建立多个会话
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" `
  -Name "fSingleSessionPerUser" -Value 0

# 放行防火墙
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"

启用 RDP 会话的 GPU 加速
#

这一步很容易被忽略 —— Windows Server 的 RDP 会话默认不使用 GPU,而是用 Microsoft Basic Render Driver 做 CPU 软渲染。即使你已经直通了 GPU 并装好了驱动,RDP 会话也不会自动使用它。

# 让 RDS 会话使用硬件图形适配器
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" `
  /v bEnumerateHWBeforeSW /t REG_DWORD /d 1 /f

# 启用 H.264/AVC 444 编码(画质更好)
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" `
  /v AVC444ModePreferred /t REG_DWORD /d 1 /f

# 优先使用 GPU 硬件编码
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" `
  /v AVCHardwareEncodePreferred /t REG_DWORD /d 1 /f

也可以走组策略:gpedit.msc → 计算机配置 → 管理模板 → Windows 组件 → 远程桌面服务 → 远程桌面会话主机 → 远程会话环境 → 启用 “对所有远程桌面服务会话使用硬件默认图形适配器”

创建用户
#

net user user1 P@ssw0rd123 /add
net user user2 P@ssw0rd123 /add
net localgroup "Remote Desktop Users" user1 /add
net localgroup "Remote Desktop Users" user2 /add

重启后,各用户可以用 mstsc 同时连接到 VM IP,各自在独立的桌面会话中使用 CAD 软件。

VM 最终配置
#

agent: 1
balloon: 4096
bios: seabios
boot: order=scsi0
cores: 6
cpu: host
hostpci0: 0000:06:00,pcie=1
machine: pc-q35-9.2
memory: 8192
name: win-server-2022-rds
net0: virtio=BC:24:11:34:E1:5E,bridge=vmbr0
numa: 1
ostype: win11
scsi0: md0:200/vm-200-disk-0.qcow2,cache=writeback,discard=on,iothread=1,size=100G,ssd=1
scsihw: virtio-scsi-single
vga: virtio

踩坑清单
#

在这个项目里踩过的坑,按被坑的程度排序:

OVMF 不引导 ISO
#

花了很长时间在 UEFI 引导上,尝试了 IDE 光驱、SATA 光驱、重建 EFI NVRAM、关闭 Secure Boot,全部失败。最终发现 SeaBIOS 一次成功。教训是不要在不必要的地方追求"正确"的配置 —— Windows Server 2022 用 SeaBIOS 跑得好好的。

GRUB 配置丢失
#

中间遇到一次网络中断后重启,发现 GRUB 参数被重置回 quiet,所有 IOMMU 和 VFIO 配置全部失效。modprobe 配置文件和 /etc/modules 的改动也丢了。原因不明,可能是 PVE 的某次自动更新覆盖了配置。后来重新配置了一遍才恢复。

建议:改完配置文件后用 etckeeper 或手动备份 /etc/default/grub/etc/modprobe.d//etc/modules。被覆盖一次就够受的了。

AMD 驱动 Error 184
#

AMD 的消费级驱动安装器硬编码了 OS 白名单,不包含 Windows Server。但底层驱动(INF 文件)本身兼容 Server 内核。通过设备管理器手动指向解压后的驱动目录可以成功安装。

AMD Reset Bug
#

消费级 AMD 显卡(RDNA/RDNA2)普遍存在 GPU Reset Bug —— VM 关机后 GPU 不能正确重置,再次启动 VM 时 GPU 无法初始化。解决方法只有冷启动宿主机。在需要频繁重启 VM 的调试阶段会比较痛苦。

RDS 需要域环境
#

RDS 的 RemoteApp、集合管理等高级功能只在 Active Directory 域环境下可用。无域环境只能走最基础的多用户 RDP 桌面登录。对于三五个用户的小团队来说,全桌面 RDP 反而更简单直接。

使用建议
#

经过实际测试后的一些经验:

事项说明
用户并发RX 6400 只有 4GB 显存,建议控制在 2-3 个并发用户
软件选择Cadence/PADS 这类 2D 软件其实不需要 GPU 直通,CPU 软渲染足矣
驱动稳定性消费级 GPU 在多 RDS 会话下可能触发 dwm.exe 崩溃,据社区反馈 6-15 用户时出现概率较高
宿主机管理GPU 直通后宿主机没有本地显示,确保 SSH 和 Web UI 始终可达
BIOS 设置如果遇到直通不工作,检查 BIOS 里的 ReBAR / SAM / C.A.M. 设置,禁用通常能解决问题
许可证注意 CAD 软件在多用户终端服务器上的授权方式,部分厂商有单独的网络许可要求

参考资料
#

PVE 实践 - 这篇文章属于一个选集。
3: 本文

相关文章

PVE AutoSnap 自动快照工具使用指南
·391 字·2 分钟
虚拟化 备份 PVE Proxmox AutoSnap 虚拟化
VMware ESXi 虚拟机克隆完整操作指南
·244 字·2 分钟
虚拟化 Vmware Esxi 虚拟化 克隆
3 行 YAML 接入生产级 GitLab CI/CD:gitlab-ci-templates 实战
·152 字·1 分钟
DevOps Engineering GitLab CI CI/CD Devops ArgoCD SonarQube 模板化