锐翊6800H-ES小主机PVE Windows11LTSC核显直通记录

因为之前做AIO所以开始捣鼓了下PVE虚拟化,又突发奇想想在PVE下挂一些Windows端的游戏,故有了这篇文章。

还有一个原因是网上的大部分教程对PVE8/AMD小主机并不适用。

本次使用的硬件/软件:

  • 锐翊6800H-ES迷你主机(
    16 x AMD Eng Sample: 100-000000561-40_Y)
  • 32G U盘一块
  • 引导模式:EFI (Secure Boot)
  • PVE版本:8.2.2
  • PVE内核版本:Linux 6.8.4-3-pve (2024-05-02T11:55Z)
  • Windows版本:Windows11 LTSC 24H2(26100.268)
  • Windows10 PE:微PEv2.3

准备工作

1、BIOS开启svm, iommu等,这个ES主机BIOS默认全开这些内容,无需调整

2、提取物理机的BIOS文件,以及核显的vbios文件

2.1、提取物理机BIOS

如果你像我一样,已经安装好了PVE,且手里没有其他硬盘的话,那么你需要准备一块安装了Windows PE的U盘用来提取物理机BIOS

下载并解压AFUWIN5.12(https://wwn.lanzouv.com/ixwW7094m7ra)到做好微PE的U盘内

重启物理机,快速按F2进入BIOS,修改引导顺序为U盘第一并保存重启,等待PE自动启动

运行解压后的AFUWINGUIx64.EXE文件,点击储存保存BIOS,将保存下来的bios.bin放到U盘里备用(这个文件名字不一定一样,根据自身情况即可)

下载并解压UBU 1.79.17(https://pan.baidu.com/s/1pD7NqJoOThQawJw59NyTHQ 提取码: ivwk),将储存下来的bios.bin复制到UBU的软件根目录,并双击运行UBU.bat,出现类似下图的情况按2选择核显并回车再按S后回车导出VBIOS

图片[1]-锐翊6800H-ES小主机PVE Windows11LTSC核显直通记录-Rain's Blog
按2选择核显并回车
图片[2]-锐翊6800H-ES小主机PVE Windows11LTSC核显直通记录-Rain's Blog
按S后回车导出VBIOS

此时UBU软件根目录下会出现Extracted目录,双击进入Extracted,再双击进入到GOP,一直到最后的文件夹里,会存放有导出的AMDGopDriver.efi,将文件复制出来备用

下载edk2-BaseTools-win32-masterhttps://github.com/tianocore/edk2-BaseTools-win32/archive/refs/heads/master.zip

解压后在其根目录打开CMD/PowerShell并输入以下命令

.\EfiRom.exe -f 0x1002 -i 0xffff -e D:\Download\AMDGopDriver.efi

使用这个命令进行转换,1002是amd生厂商标识。-i 0xffff这个是产品id,这个随便四位十六进制都行(不需要写具体对应显卡编号哈),你就会得到AMDGopDriver.rom,保存此文件备用

2.2、提取核显vbios

使用xi4oyu的源代码 编译后导出vbios文件使用,来自Have anyone susscesfully passthroughed the iGPU AMD Radeon 680M to VM? | Proxmox Support Forum

SSH登录到PVE中,创建vbios.c文件,复制粘贴以下代码并保存

#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;
}

然后执行以下命令

gcc vbios.c -o vbios
./vbios

此时就会导出核显的vbios文件,名称一般为vbios_1002_xxxx.bin,每个机器不一定一样

此时准备工作已经结束,你得到了AMDGopDriver.romvbios_1002_xxxx.bin这两个文件,请把他们两个用winscp(或者命令)拷贝到/usr/share/kvm目录

3.正式操作

3.1 编辑grub屏蔽pve7.2+的bug

vi /etc/default/grub
#添加或直接编辑下面这行
GRUB_CMDLINE_LINUX_DEFAULT="quiet initcall_blacklist=sysfb_init"
#保存后执行更新
update-grub

PVE8的grub里面不需要加入amd_iommu=on (开启iommu) pcie_acs_override=downstream,multifunction (强制iommu分组)这些参数,好像默认就开启了一样。

3.2 将核显加入驱动黑名单

屏蔽三大显卡驱动,

屏蔽hdmi声音驱动;

options vfio_iommu_type1 allow_unsafe_interrupts=1 允许不安全的设备中断

blacklist nvidiafb
blacklist amdgpu
blacklist i915
blacklist snd_hda_intel
options vfio_iommu_type1 allow_unsafe_interrupts=1

更新initramfs

update-initramfs -u -k all

然后输入reboot重启实体机

3.3 直通虚拟机

创建虚拟机时,CPU选择host,BIOS选择默认(OVMF),机型选择q35

在添加核显显卡pcie设备里面勾选主gpu,rom-bar,pcie-express这三个选项,并对所有功能不勾选。显示设置为无 或保持默认也可用。

图片[3]-锐翊6800H-ES小主机PVE Windows11LTSC核显直通记录-Rain's Blog

另外似乎PVE8.1后,不会在Web控制台直接显示romfile信息了,但仅仅只是不显示,我们需要手动编辑一下虚拟机配置文件即可

vi /etc/pve/qemu-server/102.conf

102为你要直通的windows虚拟机ID

添加指定的romfile,romfile文件名需要根据你提取出来的vbios文件名来修改。

0000:06:00.1为AMD的核显声卡,通常情况是和核显挨着的,请根据自身情况进行修改.

如果不指定核显声卡的romfile,那么有可能将会在安装驱动完成并重启后,触发核显43错误

hostpci0: 0000:75:00.0,pcie=1,x-vga=1,romfile=vbios_1002_1681.bin
hostpci0: 0000:75:00.0,romfile=AMDGopDriver.rom

如果遇到了43错误,那么重启虚拟机是无效的,必须重启PVE才可恢复。

在完成以上配置后,启动虚拟机即可

4.一些常见问题修复

解决AMD GPU Passthrough Reset Bug

经典远古BUG传承至今,如果不安装此服务有可能会导致在重启后无法找到GPU

下载Release v0.1.7 · inga-lovinde/RadeonResetBugFix 并将其解压到虚拟机C盘根目录,以管理员身份打开CMD/PowerShell执行下面的命令

./RadeonResetBugFixService.exe install

整个安装过程可能持续最长15分钟,期间屏幕可能会多次闪烁

如果你想试试触发这个BUG,也可以卸载此服务,同样以管理员身份打开CMD/PowerShell执行下面的命令

./RadeonResetBugFixService.exe uninstall

卸载过程最长持续5分钟,期间屏幕可能会多次闪烁

反虚拟化防止一些常见的反作弊检测

编辑虚拟机配置文件,增加以下内容

args: -cpu host,hypervisor=off,vmware-cpuid-freq=false,enforce=false,host-phys-bits=true, -smbios type=0,vendor="American Megatrends International LLC.",version=H3.7G,date='02/21/2023' -smbios type=1,manufacturer="Maxsun",product="MS-Terminator B760M",version="VER:H3.7G(2022/11/29)" -smbios type=2,manufacturer="Maxsun",product="MS-Terminator B760M",version="VER:H3.7G(2022/11/29)" -smbios type=17,manufacturer="KINGSTON",speed=3200,serial=DF1EC466,part=SED3200U1888S

总体的配置文件看起来像这样

agent: 1
args: -cpu host,hypervisor=off,vmware-cpuid-freq=false,enforce=false,host-phys-bits=true, -smbios type=0,version=UX305UA.201 -smbios type=1,manufacturer=ASUS,product=UX305UA,version=2021.1 -smbios type=2,manufacturer=Intel,version=2021.5,product='Intel i7-12700' -smbios type=3,manufacturer=XBZJ -smbios type=17,manufacturer=KINGSTON,loc_pfx=DDR4,speed=3200,serial=114514,part=FF63 -smbios type=4,manufacturer=Intel,max-speed=3200,current-speed=3200
bios: ovmf
boot: order=scsi0;net0
cores: 8
cpu: host
efidisk0: local-lvm:vm-102-disk-0,efitype=4m,pre-enrolled-keys=1,size=4M
hostpci0: 0000:75:00.0,pcie=1,x-vga=1,romfile=vbios_1002_1681.bin
hostpci1: 0000:75:00.1,romfile=AMDGopDriver.rom
machine: pc-q35-8.1
memory: 8192
meta: creation-qemu=8.1.5,ctime=1715697001
name: Win11-LTSC
net0: virtio=BC:24:11:38:3F:01,bridge=vmbr0,firewall=1
numa: 0
onboot: 1
ostype: win11
scsi0: local-lvm:vm-102-disk-1,iothread=1,size=52G
scsi1: local-lvm:vm-102-disk-2,iothread=1,size=256G
scsihw: virtio-scsi-single
smbios1: uuid=b9d30bb2-92af-49f1-a1da-170a915ca04e
sockets: 1
tpmstate0: local-lvm:vm-102-disk-3,size=4M,version=v2.0
usb0: host=046d:c547
usb1: host=320f:5055
vmgenid: 9ebb8f62-e66d-4490-b38d-40da5b3ca646

如此配置可以通过大部分的虚拟化检测,但无法通过SE虚拟化检测。

如果需要更强的过检测,那么需要重新编译pve-qemu-kvm这个包,可参考项目zhaodice/proxmox-ve-anti-detection: A patch to hide PVE itself

但即使重新编译了,也有部分反作弊无法正常通过,例如拳头的Vanguard。且此补丁可能会导致一些virtIO设备无法工作,请谨慎使用。

参考资料

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 共2条
头像
说点什么?
提交
头像

昵称

取消
昵称表情代码图片
    • 头像hijack0
      • Rain的头像-Rain's BlogRain作者0