全局命令:显卡模式切换gpu

一句话

gpu 是 max2 上管理「显卡归宿主还是归虚拟机」的全局命令。它只写状态文件,重启后由开机服务落实驱动绑定 —— 因为显卡驱动在开机时就被图形栈拿走了,运行期不可能热切换。

命令速查

命令作用何时生效
gpu打印帮助—
gpu list列出显示类设备(含同 IOMMU 组设备)只读
gpu pass <卡>把该卡及其同组设备标记为「直通」重启后
gpu host <卡>把该卡及其同组设备标记为「宿主」重启后
gpu apply按状态文件落实绑定(开机由服务调用,平时不用手跑)立即

<卡> 的写法:BDF(01:00.0 或 0000:01:00.0),或 gpu list 里显示类设备的序号(0 起)。

gpu list 的列

#  类型  设备                         PCI 位置      IOMMU 组  当前驱动  期望  一致
0  VGA   AMD Radeon 780M · 引导显卡  0000:65:00.0  18        amdgpu    宿主  ✓
  • 序号:就是 gpu pass/host 的入参(0 起)。序号会随硬件在位情况变化 —— 没插 eGPU 时 0 号就是 780M,插上后 4060 通常排前面 ⇒ 脚本里禁止写死序号。
  • 设备:由 udev 的 pci.ids 动态派生;引导显卡加 · 引导显卡 后缀;同 IOMMU 组的音频等功能行用 └ 缩进。
  • 当前驱动 / 期望 / 一致:一致 为 ✓ 表示已经是期望状态;待重启 表示状态文件已改、但驱动还没换(要重启)。
  • pci.ids 只有代号、没有营销名时,在 /etc/gpu-mode-names.conf 按 vendor:device = 展示名 补一行即可。

机制:为什么不能热切换

  • 不用内核参数(vfio-pci.ids=…):那会把开关焊进「配置基线」,改一次就得改配置重建。改用每设备自带的 driver_override 接口 —— 启动期按状态文件决定绑谁。
  • 时机卡在图形会话之前:gpu-mode-apply.service(oneshot,wantedBy=multi-user.target、before=display-manager.service、after=local-fs.target)。晚一步图形栈就把显卡拿走了。
  • 直通必须整组:显卡和它的音频功能同属一个 IOMMU 组,只切一半会被虚拟机拒绝。
  • 改状态不产生 nix 世代:状态写在 /var/lib/gpu-mode/,不属于声明式配置。

数据落点

/var/lib/gpu-mode/<BDF>.mode

vendor=0x10de        # 身份字段:防 BDF 漂移后误操作别的设备
device=0x2882
mode=passthrough     # host | passthrough

三个字段都要有。apply 时会比对 vendor/device:不符就跳过该设备(典型场景:没接 eGPU,那个 BDF 上换成了别的设备)。

怎么确认生效(判据)

gpu list                       # 期望列=直通、一致列=✓ 即已落实
basename $(readlink -f /sys/bus/pci/devices/0000:01:00.0/driver)   # 期望 vfio-pci
nvidia-smi                     # 直通后应报 Failed to initialize NVML(预期,不是故障)
ls /sys/class/drm/             # 4060 的 card 消失,只剩 780M
journalctl -u gpu-mode-apply -b | tail

apply 的日志会逐设备打印 <BDF> <旧驱动> → vfio-pci(直通)或交回内核探测(宿主)。

本机现状(2026-10-19,办公室没接 eGPU)

项实况
gpu list只有一行:0 VGA AMD Radeon 780M · 引导显卡 0000:65:00.0 组18 amdgpu 宿主 ✓,结论行「全部设备已处于期望模式」
状态文件仍是 4060 的 mode=passthrough(vendor=0x10de device=0x2882)—— 留着不动,回家插上 eGPU 重启即按直通生效
本次开机 apply⚠ 状态文件身份不符(0000:01:00.0 现在是 0x1c5c:0x174a,记录是 0x10de:0x2882)—— 跳过;0000:01:00.1 不在总线上 —— 跳过;服务状态 Finished

2026-10-19 修掉的坑:身份不符原本会 rc=1,导致没接 eGPU 时每次 nixos-rebuild 都被 gpu-mode-apply 的失败中断。现在改为「跳过、不置错」—— 设备不在位属预期状态,不是失败。真正的写失败(driver_override / bind 失败)仍会让服务失败。

坑与注意

  • BDF 会漂移:eGPU 接上时是 0000:01:00.0+01:00.1;没接时同一 BDF 可能是别的设备 ⇒ 靠状态文件里的 vendor/device 兜住,永远别只看数字。
  • 直通后宿主会失去这张卡的输出:显示布局可能变化(尤其那台显示器还在用 4060 那根线时)。
  • 回宿主必须两步:sudo gpu host 0 + 重启。没有「关掉虚拟机就自动回宿主」这回事(详见服务笔记 wK8ClezMHQJh)。
  • 回宿主那条 drivers_probe 分支在本机还没实跑过一次(项目台账记的待办)—— 第一次真回宿主时留意日志里是否出现「交回内核探测失败」。
  • 直通切换后记得重挂 USB 鼠标:kvm usb 5(USB 设备同样不写死在 XML 里)。

出处

  • 实现:/etc/nixos/modules/hardware/gpu-mode.nix + gpu-mode.sh + gpu-mode-names.conf
  • 台账:hermes-nixos-workspace/docs/gpu-passthrough-mode-switch.md §4(list 改版)/ §5.1(bind 分支首次真机成功)/ §6;docs/egpu-4060-weekend-runbook.md §10.7