需求拆解#
先把需求摊开看。要跑的软件有四个,GPU 依赖程度各不相同:
| 软件 | 用途 | 对 GPU 的依赖 |
|---|---|---|
| Cadence 16.6 | PCB/原理图 | 极低,纯 2D |
| PADS VX2.4 | PCB 设计 | 低,3D 预览需基础 OpenGL |
| AutoCAD 2020 | 工程制图 | 中,DirectX/OpenGL 加速 |
| Creo 5.0 | 3D 建模 | 中,OpenGL 渲染 |
Cadence 和 PADS 其实纯 CPU 软渲染就能应付。真正需要 GPU 的是 AutoCAD 的大图纸和 Creo 的三维装配体。所以一开始的策略是先不折腾 GPU,装好系统跑起来试试 —— 如果软渲染够用,就省了一堆事。
结论是:不够用。Creo 打开稍微复杂一点的模型就明显卡顿,AutoCAD 在缩放大图纸时也有延迟。于是只好走 GPU 直通这条路。
硬件情况#
| 项目 | 配置 |
|---|---|
| CPU | AMD Ryzen 5 5600X(12 线程) |
| 内存 | 64GB DDR4 |
| GPU | AMD Radeon RX 6400(Navi 24,盈通,4GB) |
| 主板 | B550 芯片组 |
| 存储 | NVMe 476GB(系统)+ 2x NVMe 931GB RAID0 + SATA 1.8TB |
| PVE | 8.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 组#
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=pt | passthrough 模式,不直通的设备不经 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 冲突 |
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
验证#
重启后 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 设置界面。
排查过程走了三轮弯路:
- IDE 光驱 → OVMF 根本不认 IDE 设备的启动能力,换 SATA
- SATA 光驱 → 还是进 UEFI Shell → 重建 EFI NVRAM(删除 efidisk 再创建),无效
- 关闭 Secure Boot(
pre-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 磁盘),需要手动加载驱动:
- 点击 “加载驱动程序”
- 浏览 VirtIO ISO →
vioscsi\2k22\amd64→ 加载 SCSI 驱动 - 再加载一次 →
NetKVM\2k22\amd64→ 网卡驱动 - 现在能看到 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 检查。
绕过方法:手动安装
- 下载 Adrenalin 驱动(选 Windows 10/11 版本)
- 运行安装包 → 它会解压文件到
C:\AMD\→ 然后报错退出(正常,我们只要解压出来的文件) - 设备管理器 → 找到 Error 状态的显示适配器 → 右键 → 更新驱动程序
- 浏览我的电脑以查找驱动程序 → 路径填
C:\AMD\→ 勾选 “包含子文件夹” - 如果提示兼容性警告,选 “仍然安装”
- 重启
配置 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 软件在多用户终端服务器上的授权方式,部分厂商有单独的网络许可要求 |
参考资料#
- Proxmox VE PCI Passthrough 官方文档
- GPU Passthrough w/ Radeon RX 6400 - HaynesLab
- GPU Passthrough - Radeon 6800xt and beyond(Proxmox 论坛)
- Install RDS in Workgroup without Domain - woshub.com
- AMD_DriverMagic_PatchWinServer2022-2025
- Modding Adrenalin Driver for Windows Server 2022(guru3D 论坛)
- Windows Server 2022 RDS and GPU question(Microsoft Q&A)
