7940HS机械师创物者mini2小主机PVE Windows11LTSC核显直通记录

154次阅读
没有评论

共计 8257 个字符,预计需要花费 21 分钟才能阅读完成。

因为之前做 AIO 所以开始捣鼓了下 PVE 虚拟化,又突发奇想想在 PVE 下挂一些 Windows 端的游戏,故有了这篇文章。
还有一个原因是网上的大部分教程对 PVE8/AMD 小主机并不适用。

本次使用的硬件 / 软件:

  • 机械师 R7940HS 迷你主机
  • 32G U 盘一块
  • 引导模式:EFI (Secure Boot)
  • PVE 版本:8.2.7
  • PVE 内核版本:Linux 6.8.12-4-pve (2024-11-06T15:04Z)
  • Windows 版本:Windows11 LTSC 23H2(22631.4037)
  • Windows10 PE:微 PEv2.3

准备工作

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

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

2.1、提取物理机 BIOS

如果你像我一样,已经安装好了 PVE,且手里没有其他硬盘的话,那么你需要准备一块安装了 Windows PE 的 U 盘用来提取物理机 BIOS
UBU:https://winraid.level1techs.com/t/tool-guide-news-uefi-bios-updater-ubu/30357
ffs:https://github.com/pbatard/ffs/releases
下载并解压 AFUWIN5.12(https://www.123pan.com/s/qsLMjv-to3Qh.html 提取码 G1Sz)到做好微 PE 的 U 盘内

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

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

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

 

7940HS 机械师创物者 mini2 小主机 PVE Windows11LTSC 核显直通记录

按 2 选择核显并回车

7940HS 机械师创物者 mini2 小主机 PVE Windows11LTSC 核显直通记录

按 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

7940HS 机械师创物者 mini2 小主机 PVE Windows11LTSC 核显直通记录
使用这个命令进行转换,1002 是 amd 生厂商标识。-i 0xffff 这个是产品 id,这个可以填你的显卡设备 id 后四位,例如图中 15bf,你就会得到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 编译器的,执行下面的命令安装

apt update
apt -y install build-essential

然后执行以下命令

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 允许不安全的设备中断

vi /etc/modprobe.d/pve-blacklist.conf
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 这三个选项,并对所有功能不勾选。显示设置为无 或保持默认也可用。

7940HS 机械师创物者 mini2 小主机 PVE Windows11LTSC 核显直通记录

另外似乎 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:65:00.0,pcie=1,x-vga=1,romfile=vbios_1002_1681.bin
hostpci1: 0000:65:00.1,romfile=AMDGopDriver.rom

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

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

nano /etc/pve/qemu-server/102.conf 最终配置:

#args: -bios /root/OVMF_7940HS.fd

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:65:00.0,pcie=1,x-vga=1,romfile=vbios_1002_15bf.bin
hostpci1: 0000:65:00.1,romfile=AMDGopDriver.rom
machine: pc-q35-8.1
memory: 8192
meta: creation-qemu=9.0.2,ctime=1731600826
name: win11
net0: virtio=BC:24:11:13:DB:1E,bridge=vmbr0,firewall=1
numa: 0
ostype: win11
scsi0: local-lvm:vm-102-disk-1,iothread=1,size=256G
scsihw: virtio-scsi-single
smbios1: uuid=44b99bd3-0b43-47f1-a1ea-c21f990051dc
sockets: 1
tpmstate0: local-lvm:vm-102-disk-2,size=4M,version=v2.0
vga: none
vmgenid: 27831fa9-9439-4e0c-980c-f6ae5e64df50

注意安装 win 后,要把 virtio 驱动装上,还有单独去官网下载 amd 显卡驱动安装。

最终效果图

7940HS 机械师创物者 mini2 小主机 PVE Windows11LTSC 核显直通记录
7940HS 机械师创物者 mini2 小主机 PVE Windows11LTSC 核显直通记录

4. 一些常见问题修复

解决AMD GPU Passthrough Reset Bug

经典远古 BUG 传承至今,如果不安装此服务有可能会导致在重启后无法找到 GPU,这个补丁的机制就是修复 pve 内 win 关机和重启的操作导致 gpu 消息,补丁会在关机时卸载 gpu,然后开机时再加载 gpu 驱动,期间可能会 hdmi 直通黑屏,所以每次开机需要等 1 - 2 分钟,等 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 设备无法工作,请谨慎使用。

参考资料

正文完
 
alecctv
版权声明:本站原创文章,由 alecctv 2024-11-18发表,共计8257字。
转载说明:除特殊说明外本站文章皆由ooly.cc发布,转载请注明出处。
评论(没有评论)
验证码