PN53 PVE 显卡直通踩坑记

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]

这个命令可以快速找到两个信息:

  1. e7:00.0
  2. 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 可能会坑在需要重启宿主机。

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *