因为之前做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://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
此时UBU软件根目录下会出现Extracted
目录,双击进入Extracted
,再双击进入到GOP
,一直到最后的文件夹里,会存放有导出的AMDGopDriver.efi
,将文件复制出来备用
下载edk2-BaseTools-win32-master(https://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编译器的,执行下面的命令安装
apt update
apt -y install build-essential
然后执行以下命令
gcc vbios.c -o vbios
./vbios
此时就会导出核显的vbios文件,名称一般为vbios_1002_xxxx.bin
,每个机器不一定一样
此时准备工作已经结束,你得到了AMDGopDriver.rom
和vbios_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这三个选项,并对所有功能不勾选。显示设置为无 或保持默认也可用。
另外似乎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设备无法工作,请谨慎使用。
- 最新
- 最热
只看作者