前排提醒

本文内容已有更新。最新最快直通方法可见我的Github Repo:cmd2001/build-edk2-gvtd

不用再折腾编译,直接点开下现成的就行!

(可能需要一定英文基础)

(过气的)正文

温馨提示:本教程有较强时效性

本文写于 2023年8月26日

软件版本为:Proxmox Virtual Environment 8.0.4

内核版本:Linux 6.2.16-6-pve

测试硬件:

ASRock Deskmini B660 + Intel 12900 es(QXQ3)/Intel 13900T es(Q0PV)

Gigabyte Z490I AORUS ULTRA + Intel 10900T es(QTB0)

写这篇教程,主要是国内折腾 核显直通 的玩家很多,但真正可用的教程却很少。很多教程只是说需要提前安装系统,无法看到 BIOS 界面,进入系统后可正常使用,但对其中的原理却没有任何讲述。或者单纯以有偿或免费的形式提供一个可用的 OVMF 固件,却也不讲解其中原理。而英文论坛对这方面的叙述却很明确。这里,我就来做一个总结者和搬运工,在提供教程的同时讲解一些最基本的原理。

本文所有使用的工具均为互联网可获得的开源项目/免费软件,以及厂商提供的闭源固件。

笔者承认付费定制提供者的劳动价值,本文也无意打扰你们的生意。只是为广大 DIYer 提供一个自己折腾的选择而已。

理论上本教程定制 OVMF 部分也适用于 AMD,但虚拟机配置可能需要做出一些修改。另外 AMD 核显存在 Reset Bug 可能会导致宿主机卡死,需要在 Windows 中加额外服务进行 Hook。由于笔者手中并没有 AMD 平台的核显主机,因此没有进行相关测试。(当然如果谁愿意给我捐一台那我自然很愿意折腾)

原理:UEFI 启动是怎样点亮显示器的

现在假设你的电脑有一张独显,你的显示器接在独显上,机器采用UEFI固件引导,那么从上电到点亮屏幕,你的机器发生了什么?

答:主板 UEFI 从显卡 VBIOS 中读取 GOP 固件,并利用 GOP 固件驱动独显,点亮屏幕。之后加载操作系统,显卡被驱动接管。

现在假设你的电脑有一张核显,你的显示器接在核显上,机器采用UEFI固件引导,那么从上电到点亮屏幕,你的机器发生了什么?

答:主板 UEFI 为核显初始化内存空间,读取内置的 GOP 固件,并利用 GOP 固件驱动核显,点亮屏幕。之后加载操作系统,显卡被驱动接管。

那么,如果现在是一台虚拟机呢?

答:主板 UEFI 不会为核显初始化内存空间,并尝试读取内置的 GOP 固件,但虚拟机的 UEFI 没有这种东西,加之没有初始化内存空间,所以必然点不亮屏幕。之后加载操作系统,显卡被驱动接管,操作系统的显卡驱动重新初始化内存空间并驱动屏幕。因此屏幕会在操作系统驱动加载后启动。

那么,如果我们想要虚拟机 UEFI 点亮屏幕呢?

答:为核显外挂 VBIOS 初始化内存空间,并为虚拟机的 UEFI 集成 GOP 固件。核显外挂 VBIOS 初始化内存空间,主板 UEFI 读取内置的 GOP 固件,并利用 GOP 固件驱动独显,点亮屏幕。之后加载操作系统,显卡被驱动接管。

为核显外挂 VBIOS 已是一个十分成熟的技术,因此我们的重点就是,并为虚拟机的 UEFI 集成 GOP 固件。

(以上描述只是一个方便小白理解的,非常简化的版本,本人学艺不精,如有错误请各位大神多多指教)

宿主机准备

首先你需要安装 PVE (废话)

/etc/modules 中添加以下4行

vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

运行 update-initramfs -u -k all

修改 /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT 中添加

intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction

运行 update-grub

最后重启机器 reboot

虚拟机创建

直通 Intel 核显

所选的虚拟机类型 必须为 440fx

系统类型 必须为 Linux (一定不要选 Windows,否则装驱动后会冻屏死机,二者传递的 虚拟 CPU 参数不同)

固件类型 选择 UEFI,这是安装 Windows 11 必备的

TPM 选择开启,安全启动随意

CPU 类型选 HOST,否则装不上驱动

创建后进入 Options,打开 QEMU Guest AgentUse Local Time for UTC 以获得更好体验

懒人办法

直接下载我编译的 FV 文件替换 PVE 自带版本,并进行测试。

首先测试 PVE 文件夹的版本,如果可用则直接使用。TPM/安全启动 等功能一切完美。

如果 PVE 文件夹的版本存在点不亮屏幕/花屏等问题,再测试 EDK2 文件夹的版本。本版本存在 TPM感叹号/安全启动不能启用 等小问题。

Intel 台式 6-10代/笔记本标压6-10代/笔记本低压6-9代 选择 SKYLAKE 版本,该版本采用的 GOP/VBT 固件提取自 Gigabyte Z490I AORUS ULTRA F22 BIOS(Jun 13, 2023)

Intel 台式11-14代/笔记本标压11-14代/笔记本低压10-14代 选择 TIGERLAKE 版本,该版本采用的 GOP/VBT 固件提取自 ASRock B660M-STX BIOS 12.02 (2022/12/23)

PVE 版本采用的 PVE 基础固件:pve-edk2-firmware/stable 3.20230228-4

下载链接:PVE_GVT

替换位置:/usr/share/pve-edk2-firmware/

如何确定你要替换的文件名?

sudo qm show $VM_ID --pretty | grep .fd

这里显示我要替换的文件为:/usr/share/pve-edk2-firmware//OVMF_CODE_4M.fd

除了 OVMF 固件外,我们还需要一个 vbios_gvt_uefi.rom 文件。将这个文件放到 /usr/share/kvm/ 并修改虚拟机配置文件,添加以下两行:

hostpci0: 0000:00:02,legacy-igd=1,romfile=vbios_gvt_uefi.rom

这行用于添加核显,开启 legacy-igd 模式,加载 romfile

args: -set device.hostpci0.addr=02.0 -set device.hostpci0.x-igd-gms=1 -set device.hostpci0.x-igd-opregion=on

这行用于设置核显额外参数,包括把设备地址设置为02.0,设置x-igd-gms大小并启用x-igd-opregion

然后,把虚拟机的 显卡改为 None,避免虚拟显卡和直通的核显争抢总线地址。

这里上一下我完整的虚拟机配置,可以参考一下

agent: 1
args: -set device.hostpci0.addr=02.0 -set device.hostpci0.x-igd-gms=6 -set device.hostpci0.x-igd-opregion=on
balloon: 0
bios: ovmf
cores: 8
cpu: host
efidisk0: local:200/vm-200-disk-0.qcow2,efitype=4m,pre-enrolled-keys=1,size=528K
hookscript: local:snippets/hooks-igpupt.pl
hostpci0: 0000:00:02,legacy-igd=1,romfile=vbios_gvt_uefi.rom
kvm: 1
localtime: 1
memory: 32768
meta: creation-qemu=8.0.2,ctime=1690013047
name: WinDE
net0: virtio=C2:38:CF:B1:8C:F8,bridge=vmbr0,firewall=1
numa: 0
ostype: l26
scsihw: virtio-scsi-single
smbios1: uuid=b99591a9-ec26-4171-9754-da593fa04e70
sockets: 1
startup: up=5
tablet: 0
tpmstate0: local:200/vm-200-disk-1.raw,size=4M,version=v2.0
vga: none
vmgenid: 20ae49f0-385a-4bcb-a14c-13e96af30625

配置完成后 运行 sudo qm start $VM_ID

等待几秒,屏幕亮起并看到屏幕显示 ProxmoxTianocore 的 Logo,说明你已经成功了。

此时你可直通 USB 键盘,并按 ESC 进入 UEFI 设置。

之后正常安装 Windows 11,并利用 Windows Update 自动安装驱动即可。

固件编译

看完之前的懒人版教程,你一定会好奇:

懒人版教程已经这么复杂了

请问我们的固件是怎么来的呢,岂不是要困难上天

不不不,取得我们的固件,并不困难啦!

下载 BIOS 并提取 VBT/GOP

找到你的主板官网,下载最新的 BIOS

下载最新版的 UEFI BIOS Updater(当前为:UBU_v1.79.17)。

如果找不到下载地址,可从本站下载:UBU_v1.79.17

接着运行 UBU.bat,打开你下载的 BIOS 文件。

UBU 会自动分析你的 BIOS 映像。

根据提示按2,按S提取 VBTGOPGOP 如上文所说的,是用于 UEFI 固件点亮显示器的。 VBT 是用于传统 BIOS 模式的。为了更好的兼容性,这里我们选择同时集成两个文件。

这里能找到我们所需的两个文件,IntelGopDriver.efivbt.bin

编译 OVMF 固件

系统准备

在你的 PVE 上创建一个 Ubuntu LXC 容器,并安装 DockerGit

遵循这个项目,编译 OVMF 固件

https://github.com/Kethen/edk2-build-intel-gop

注意原作者在脚本里用的是 Podman,而目前 LXC 中运行 Podman 仍存在一些问题,因此我们可以编辑脚本,将所有 podman 替换成 docker,即可运行。

由于目前的网络环境,可能需要为 Docker 换源,并为脚本配置快速上网方式。

编译固件

接着,将你上一步提取的 GOPVBT 移动到指定位置。

mkdir gop
cp <intel gop driver efi> gop/IntelGopDriver.efi
cp <intel gop vbt> gop/Vbt.bin

这里如何将你的 GOPVBT 传输到 LXC 容器?sftp 即可。(你都折腾 PVE 了肯定会这个吧)

最后 sudo bash build_ovmf.sh 开始构建。

生成的 ./edk2/Build/OvmfX64/DEBUG_GCC5/FV/OVMF_CODE.fd 就是你所需要的文件。

用它替换 PVE/usr/share/pve-edk2-firmware/OVMF_CODE_4M.fd 试试看,你的虚拟机是不是能看到 TianoCore 的启动界面了?

二进制移植

如果细心的你成功地用上面的固件引导 Windows 11,可能会发现一些问题:

最明显的:设备管理器 TPM设备 黄色感叹号,设备固件无法初始化。

这是因为我们采用的 https://github.com/Kethen/edk2 的基础版太老了,没有 PVE 最新的 TPM 支持。

怎么办?最正规的方法当然是 fork 一份最新的pve-edk2,自己打核显补丁!

不过我们自然不想把大量的时间耗费在移植代码上,因此我们选择一个投机取巧的方法:二进制移植!

/usr/share/pve-edk2-firmware/ 提取 PVE 原版的 OVMF_CODE_4M.fdOVMF_CODE_4M.secboot.fd,和我们编译的 OVMF_CODE.fd 放到同一个文件夹里。

接着,下载 mmtool_ v5.0.0.7 放到相同文件夹。注意一定要是 5.0.0.7 这个版本。因为 AMI 在更高版本的 mmtools 禁用了编辑非 Aptio 平台映像的功能。(而我们的 OVMF 固件显然不基于 Aptio 平台)

如果找不到下载地址,可从本站下载:mmtool_v5.0.0.7

mmtool 打开 OVMF_CODE.fd,提取其中的 IntelGopDriverPlatformGOPPolicy和中间的无名文件,提取方式选择未压缩的。

3 个文件分别是:编译过的 GOP段,加载GOP需要的段和VBT段。

接着用 mmtool 打开 OVMF_CODE_4M.fd,在卷索引 02:00-00 按顺序插入 3 个文件(GOPDriver,VBT,PlatformGOPPolicy),插入选项选择不压缩。

最后别忘了保存映像。另一个 OVMF_CODE_4M.secboot.fd 也如法炮制。

最后将文件复制回 PVE 并替换原有文件,启动虚拟机。

看看 TianoCoreLogo 是不是变成 Proxmox 了?进入系统,看看 TPM 是不是已经可用了?

最终效果图:

最后,祝大家折腾顺利,玩机开心!

参考

https://wiki.archlinux.org/title/Intel_GVT-g#Using_DMA-BUF_with_UEFI/OVMF

https://projectacrn.github.io/latest/tutorials/gpu-passthru.html

https://github.com/Kethen/edk2

https://www.bilibili.com/video/BV1Nm4y1x7ZM


Faster than LIGHT