PN53 6900HX + 64GB内存,用了半年多的 Win11,每次干点啥都 WSL,但是WSL 有些时候太麻烦了,而使用 VMware 太慢。所以想着换个硬盘来搞一下 Proxmox VE,把原来的 Windows 变成虚拟机,但是后来,硬盘买到手,改变主意了,直接踢掉原装的 512GB 镁光,换上国产 2T。
硬盘是京造的鲲鹏 2TB,之前也买过一根,放在了另外一台小主机里,用了两个月没啥问题。PN53 里目前除了这块硬盘外,还有一根雷克沙的中速盘和一个铨兴的SATA SSD,当初为了求稳定,买的高价的雷克沙,结果是最坑的,40G连续写入就过热掉盘,铨兴便宜盘,用来存放大文件,当系统的下载盘交换盘,挺稳定。
内存是国产光威的DDR5 4800 32GB * 2,PN53 自己说不支持单根32GB,最大只支持总64GB,实测这款是没问题的。
显卡只有 6900HX 自带的 680M。
系统是 PVE 8.0.2。
环境结束了,开始踩坑。
第一个坑,启动的时候报硬盘 IO 错误,对了下 fdisk
的输出,发现是雷克沙的盘,我又慌了。dmesg
看了下输出:
root@wpve:~# dmesg |grep nvme0
[ 1.039970] nvme nvme0: pci function 0000:01:00.0
[ 1.074772] nvme nvme0: allocated 64 MiB host memory buffer.
[ 1.095807] nvme nvme0: 16/0/0 default/read/poll queues
[ 1.101494] nvme nvme0: Ignoring bogus Namespace Identifiers
[ 1.104460] nvme0n1: p1 p2
[ 31.912492] nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS=0x10
[ 31.912502] nvme nvme0: Does your device have a faulty power saving mode enabled?
[ 31.912505] nvme nvme0: Try "nvme_core.default_ps_max_latency_us=0 pcie_aspm=off" and report a bug
[ 31.936976] nvme0n1: I/O Cmd(0x2) @ LBA 4000797184, 8 blocks, I/O Error (sct 0x3 / sc 0x71)
[ 31.936993] I/O error, dev nvme0n1, sector 4000797184 op 0x0:(READ) flags 0x80700 phys_seg 1 prio class 2
[ 31.960621] nvme nvme0: Disabling device after reset failure: -19
[ 31.972503] nvme0n1: detected capacity change from 4000797360 to 0
[ 31.972606] Buffer I/O error on dev nvme0n1, logical block 500099648, async page read
[ 31.975928] Buffer I/O error on dev nvme0n1p1, logical block 16256, async page read
[ 31.975931] Buffer I/O error on dev nvme0n1p1, logical block 16257, async page read
[ 31.975933] Buffer I/O error on dev nvme0n1p1, logical block 16258, async page read
[ 31.975935] Buffer I/O error on dev nvme0n1p1, logical block 16259, async page read
[ 31.976173] Buffer I/O error on dev nvme0n1p2, logical block 500095216, async page read
[ 32.918462] Buffer I/O error on dev nvme0n1p2, logical block 500095216, async page read
[ 32.918490] Buffer I/O error on dev nvme0n1p1, logical block 16256, async page read
[ 32.918548] Buffer I/O error on dev nvme0n1p1, logical block 16257, async page read
[ 32.918595] Buffer I/O error on dev nvme0n1p1, logical block 16258, async page read
根据提示,修改 grub
参数,/etc/default/grub
GRUB_CMDLINE_LINUX="nvme_core.default_ps_max_latency_us=0 pcie_aspm=off"
然后执行 update-grub
手动更新 grub,重启,好了。
风险不知道,有人说是可能硬盘长期工作会发热,暂时不管了。
接下来安装系统,没啥大问题,看着网上各种过期教程,把环境毁了,被迫重装了一次。
第二个坑出现在第一次安装 PVE之后,网络无效,经查 /etc/network/interfaces
里识别出来的网卡是 enp1s0
,而实际系统是 enp3s0
,手工改掉,重启网络就好了。
官方 PCIe 直通的教程:https://pve.proxmox.com/wiki/PCI(e)_Passthrough
接下来,显卡直通所有涉及到的改动如下:
1 /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet iommu=pt"
2 /etc/modules-load.d/vfio.conf
vfio
vfio_iommu_type1
vfio_pci
比官方教程少了 vfio_virqfd
,据说是被集成到了 vfio
里,不管了,反正就这样。
3 /etc/modprobe.d/vfio.conf
options vfio-pci ids=1002:1681,1002:1640
blacklist amdgpu
blacklist snd_hda_intel
blacklist 是阻止 PVE 自己加载 amdgpu
,结果就是,生效后系统控制台会失效,所以执行之前务必先把远程访问的搞定。
更新 2023-12-11:原来只使用了VGA的设备(.0),导致 win11 的显卡一直有问题,所以这里需要把 .0 和 .1 的设备以及驱动都处理了。方法同下
参数来源:
root@wpve:~# lspci -nnk |grep 680M -C 3
pcilib: Error reading /sys/bus/pci/devices/0000:00:08.3/label: Operation not permitted
Subsystem: Shenzhen Longsys Electronics Co., Ltd. Device [1d97:1602]
Kernel driver in use: nvme
Kernel modules: nvme
e7:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Rembrandt [Radeon 680M] [1002:1681] (rev c7)
Subsystem: ASUSTeK Computer Inc. Rembrandt [Radeon 680M] [1043:8870]
Kernel driver in use: vfio-pci
Kernel modules: amdgpu
e7:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Rembrandt Radeon High Definition Audio Controller [1002:1640]
这个命令可以快速找到两个信息:
- e7:00.0
- 1002:1681
2的这个跟配置文件的 ids= 的参数匹配。但是观察到其他人奇奇怪怪的教程里都有很多ids,想直通那个就直通哪个吧,ids配上即可。
然后,我看到其他人教程里好像他们的设备跟 680M 在一个组的还有其他设备,如音频,但是我的电脑没有。一个手工查看的方法如下:
root@wpve:~# find /sys/kernel/iommu_groups/ -type l |grep e7
/sys/kernel/iommu_groups/25/devices/0000:e7:00.5
/sys/kernel/iommu_groups/23/devices/0000:e7:00.3
/sys/kernel/iommu_groups/21/devices/0000:e7:00.1
/sys/kernel/iommu_groups/26/devices/0000:e7:00.6
/sys/kernel/iommu_groups/24/devices/0000:e7:00.4
/sys/kernel/iommu_groups/22/devices/0000:e7:00.2
/sys/kernel/iommu_groups/20/devices/0000:e7:00.0
root@wpve:~# find /sys/kernel/iommu_groups/ -type l |grep '/20/'
/sys/kernel/iommu_groups/20/devices/0000:e7:00.0
先按 lspci
的输出里的 e7
去搜,找到组路径的 20,然后再去看 20的目录下的设备。
4 更新
update-initramfs -u -k all
reboot
5 提取GPU的vbios,代码来自 https://forum.proxmox.com/threads/have-anyone-susscesfully-passthroughed-the-igpu-amd-radeon-680m-to-vm.119178/#post-521265
“`
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef uint32_t ULONG;
typedef uint8_t UCHAR;
typedef uint16_t USHORT;
typedef struct {
ULONG Signature;
ULONG TableLength; // Length
UCHAR Revision;
UCHAR Checksum;
UCHAR OemId[6];
UCHAR OemTableId[8]; // UINT64 OemTableId;
ULONG OemRevision;
ULONG CreatorId;
ULONG CreatorRevision;
} AMD_ACPI_DESCRIPTION_HEADER;
typedef struct {
AMD_ACPI_DESCRIPTION_HEADER SHeader;
UCHAR TableUUID[16]; // 0x24
ULONG VBIOSImageOffset; // 0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the stucture.
ULONG Lib1ImageOffset; // 0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the stucture.
ULONG Reserved[4]; // 0x3C
} UEFI_ACPI_VFCT;
typedef struct {
ULONG PCIBus; // 0x4C
ULONG PCIDevice; // 0x50
ULONG PCIFunction; // 0x54
USHORT VendorID; // 0x58
USHORT DeviceID; // 0x5A
USHORT SSVID; // 0x5C
USHORT SSID; // 0x5E
ULONG Revision; // 0x60
ULONG ImageLength; // 0x64
} VFCT_IMAGE_HEADER;
typedef struct {
VFCT_IMAGE_HEADER VbiosHeader;
UCHAR VbiosContent[1];
} GOP_VBIOS_CONTENT;
int main(int argc, char** argv)
{
FILE* fp_vfct;
FILE* fp_vbios;
UEFI_ACPI_VFCT* pvfct;
char vbios_name[0x400];
if (!(fp_vfct = fopen("/sys/firmware/acpi/tables/VFCT", "r"))) {
perror(argv[0]);
return -1;
}
if (!(pvfct = malloc(sizeof(UEFI_ACPI_VFCT)))) {
perror(argv[0]);
return -1;
}
if (sizeof(UEFI_ACPI_VFCT) != fread(pvfct, 1, sizeof(UEFI_ACPI_VFCT), fp_vfct)) {
fprintf(stderr, "%s: failed to read VFCT header!\n", argv[0]);
return -1;
}
ULONG offset = pvfct->VBIOSImageOffset;
ULONG tbl_size = pvfct->SHeader.TableLength;
if (!(pvfct = realloc(pvfct, tbl_size))) {
perror(argv[0]);
return -1;
}
if (tbl_size - sizeof(UEFI_ACPI_VFCT) != fread(pvfct + 1, 1, tbl_size - sizeof(UEFI_ACPI_VFCT), fp_vfct)) {
fprintf(stderr, "%s: failed to read VFCT body!\n", argv[0]);
return -1;
}
fclose(fp_vfct);
while (offset < tbl_size) {
GOP_VBIOS_CONTENT* vbios = (GOP_VBIOS_CONTENT*)((char*)pvfct + offset);
VFCT_IMAGE_HEADER* vhdr = &vbios->VbiosHeader;
if (!vhdr->ImageLength)
break;
snprintf(vbios_name, sizeof(vbios_name), "vbios_%x_%x.bin", vhdr->VendorID, vhdr->DeviceID);
if (!(fp_vbios = fopen(vbios_name, "wb"))) {
perror(argv[0]);
return -1;
}
if (vhdr->ImageLength != fwrite(&vbios->VbiosContent, 1, vhdr->ImageLength, fp_vbios)) {
fprintf(stderr, "%s: failed to dump vbios %x:%x\n", argv[0], vhdr->VendorID, vhdr->DeviceID);
return -1;
}
fclose(fp_vbios);
printf("dump vbios %x:%x to %s\n", vhdr->VendorID, vhdr->DeviceID, vbios_name);
offset += sizeof(VFCT_IMAGE_HEADER);
offset += vhdr->ImageLength;
}
return 0;
}
假设保存成 dump-vbios.c
apt update
apt install build-essential
gcc dump-vbios.c -o dump-vbios
./dump-vbios
会生成 vbios_1002_1681.bin
,复制到 /usr/share/kvm
目录下,供后续guest 直通显卡时使用。
上边改动第3步的细节里的 lspci
的输出里,可以看到 680M 紧接着的内容里是
Kernel driver in use: vfio-pci
Kernel modules: amdgpu
因为我当前电脑已经完成了直通,如果新的电脑,应该两个都是 amdgpu。
第三个坑,务必不要上来就用 Windows 11,务必使用 Windows 10 做测试。
PVE的文档里(https://pve.proxmox.com/wiki/PCI_Passthrough#How_to_know_if_a_graphics_card_is_UEFI_.28OVMF.29_compatible),提到了一个 UEFI 兼容的东西,给了一个工具 https://github.com/awilliam/rom-parser,但是很遗憾,按这样的教程没法提取 rom,但是我用生成的程序去解析 vbios_1002_1681.bin
,得到的输出(只看到了type 0)按文档的说法是不支持 OVMF / UEFI,我无法理解。
而看到这之前,我尝试 Windows 11 尝试了大半天,未果,回到 Windows 10,很快就完成了。
更新2023-12-11:坑已填。
第四个坑,不要信任 PVE Web 控制台来添加 PCIe 的直通,添加完要做修改。
我从网页上添加之后的效果是 /etc/pve/qemu-server/100.conf
:
hostpci0: 0000:e7:00,pcie=1,x-vga=1
搞了几次,只要启动虚拟机,host 系统直接死掉。需要手工改成
hostpci0: 0000:e7:00.0,pcie=1,x-vga=1,romfile=vbios_1002_1681.bin
具体参数看文档。
其他细节:
- CPU 使用 host
- 开启 NUMA
- Q35
- 装 virtio 的驱动,装 virtio 的 qemu agent
都是各路文档教程里的点。
至此,正常默认安装的 Windows 10,使用 SeaBios 启动,就可以直通了。
接下来,第五个坑,Windows 11。(往下翻,看更新)
假设前边关于 680M 不支持 UEFI 这个事情是真的(假设不是因为Linux兼容性,或者华硕 BIOS 限制等),那就意味着只能把 Windows 11 装在 SeaBios下,也就是不开启 TPM 和 SecureBoot。
我试过clone 这个好用的 Windows 10 去升级,过不去检查,就没搞了。
最终选择的方案是,在 Windows 11 安装界面,改注册表。
正常图形安装界面,SHIFT+ F10,绕过网络账户前,可以regedit直接去添加
HKEY_LOCAL_MACHINE\SYSTEM\Setup
创建一个名为“LabConfig”的项,在“LabConfig”下创建两个 DWORD
键 BypassTPMCheck 值 1
键 BypassSecureBootCheck 值 1
再去 oobe\BypassNRO.cmd
绕过网络用户,完成本地用户安装。
之所以让用本地用户安装,是因为网络用户开远程桌面这个事情,我实在没弄懂微软的正确姿势是什么。
第六个坑,Windows 10 和 11 都会遇到,尤其 Windows 11 坑上加坑。(往下翻,看更新)
正常安装系统时,肯定不会先开 GPU 直通,所以都是 console 下直接操作,安装好之后开远程桌面去装驱动,激活,装系统更新和软件。
但是一个古老的传统,微软的远程桌面极大概率无法正常安装本地显卡驱动。所以我们需要 向日葵。推荐的操作是:
- 安装向日葵企业版本的被控端
- 登录账号完成绑定
然后手机上,或者再开个普通虚拟机来等候主机上线,毕竟直通之后成功之前,啥都看不见。而这个时候:如果是 Windows 10,正常进入系统更新的时候,会自动且正确地安装AMD 的显卡驱动,只需要等就行;如果是 Windows 11,你会发现,向日葵连上去之后,主机分辨率可能异乎寻常的小,且啥都干不了,开远程桌面之后分辨率会恢复到正常可用的状态,缺依旧无法装显卡驱动,反正我也不知道我是以什么姿势完成的驱动安装,这个部分至少折腾了半天。
其他事情就是诸如蓝牙键盘鼠标的驱动等,或者USB 接收器,把设备添加到虚拟机即可,也许会要求重启guest。
这里遇到一个问题,我用的一个便宜的 USB 音箱,挂载作为音频设备,好像没充进电,很神奇。
还有,我win11 开直通的虚拟机一启动,host先崩掉自动重启,然后win 11直通的虚拟机才能正常工作。win 10 一切正常。
更新 2023-12-11:坑5 坑6请无视,Windows 11 按这个走。
Windows 11 正常安装,不需要做任何work around。安装好后配置远程桌面,安装AMD驱动。驱动不要用AMD的最新版,建议用 Asus给的版本。
Windows 11 确实有问题,而且设备管理器里显卡报错 Error 43,同样的配置 SeaBios + Windows 10 是不报错的。
参考 https://github.com/isc30/ryzen-7000-series-proxmox,获得 AMDGopDriver.rom,并放在 /usr/share/kvm/。
主机 pci/pcie 配置参考:
hostpci0: 0000:e7:00.0,pcie=1,x-vga=1,romfile=vbios_1002_1681.bin
hostpci1: 0000:e7:00.1,pcie=1,romfile=AMDGopDriver.rom
继续参考刚才的github仓库,如果还是 error 43,重启主机。所以 Windows 11 可能会坑在需要重启宿主机。