1、写在开头:虚拟化直通是个十分复杂的过程
虚拟化是个很复杂的东西,存在有很多因素会影响虚拟化的成功与否,并且 Intel 的核显直通在实现上就需要处理很多条件,不是一件简单的事情,本文章以 Windows 虚拟机(Windows 10/11 经过测试均可实现)为例介绍该如何实现 Intel 的核显直通。
本篇文章是作者对基于 Unraid 平台的 QEMU + KVM 虚拟化学习的一个总结,作者没有软件工程等相关的科班本经,仅仅只是学习的一个总结,目前所得出的结论仍需要继续完善和补充,仅供参考!之所以写成文章发表,一方面是想分享所得,另一方面很重要的原因是希望能起到抛砖引玉的作用,希望有更专业的人士来补充,有错误的地方请不吝惜指正。
以下是作者 Unraid 系统的软硬件配置:
CPU:i5-8600K
核显:UHD 630
主板:华擎 Z370M PRO4
Unraid 系统版本:6.9.2
Linux 内核版本: 5.10.28
QEMU 版本:5.1.0
Libvirt 版本:6.5.0
2、在虚拟化直通上,不能简单地将 Intel 的核显视为一个嵌入到 CPU 的 GPU
在术语上,一般称 Intel 的核显为 Intel Graphics Device (IGD),下文所有涉及到核显的地方都会使用 IGD 这个缩写进行描述。
之所以这样说,是因为在虚拟化层面,IGD 并不是一个“独立”的设备可以随时随地的将其分配给虚拟机去使用而不需要任何的附加条件,我在查找资料的时候看到有这么一段话去描述IGD在虚拟化层面的状况:
IGD clearly is not a discrete GPU, but"integrated" not only means that the GPU is embedded in the system,in this case it means that the GPU is kind of smeared across the system. This is why IGD assignment hasn't "justworked" and why you need a host kernel with support for exposing certainregions through vfio and a BIOS that's aware of IGD, and it needs to be at aspecific address, etc, etc, etc.
翻译:IGD显然不是一个独立的GPU,但 "集成"不仅意味着GPU被嵌入到系统中,在这种情况下,它意味着GPU有点像“涂抹”在系统中。这就是为什么IGD的直通没那么容易实现,以及为什么你需要一个支持通过 vfio 暴露某些 region 的主机内核和一个能识别 IGD 的 BIOS,而且它需要在一个特定的虚拟化地址,等等。
在下文中,你将看到为了实现 IGD 的直通,可能需要进行如下操作:
根据硬件选择对应的直通模式(UPT / Legacy);
Linux 内核、QEMU、Libvirt 的版本不能太旧;
根据选定的直通模式,有针对性选择 Machine 类型(Q35 / i440fx)和 BIOS 类型(SeaBIOS、OMVF);
配置主机 BIOS(UEFI、Leagcu、CMS、Video Option ROM ...);
配置 Linux 内核启动参数(video=vesafb:off,efifb:off);
在 Unraid 中绑定 VFIO 驱动(vfio-pci);
提供 vBIOS (Option ROM / BIOS ROM)给到虚拟机;
编辑虚拟机 Libvirt XML 模板(PCI address、x-igd-opregion、x-igd-gms ...);
............
不同的场景需要有针对性的配置,每一种配置的背后都有对应的原理,这也就是为什么说IGD的直通并不是一个简单的过程。
3、IGD的直通存在两种模式,不同的模式需要不同的方式去实现
根据 qemu 的 Github 官方文档,这两种直通的模式分别是:
UPT(Universal Passthrough):通用直通模式(我没专门去查询正确的译名,在本文姑且做此翻译)。此模式要求使用 Intel 的 Broadwell(第五代) 或更新的型号,如果你的 CPU 低于第五代但高于第二代,那么只能使用 Legacy 模式。
Legacy:传统直通模式。此模式要求使用 Intel 的 SandyBridge(第二代) 或更新的型号。
两种模式各有自己的优势和不足,选择哪一种模式取决于你的CPU情况。
本章节主要介绍这两种模式的一些基本情况,至于具体的实现会放到后文 unraid 的虚拟机实例创建中去具体描述。
3.1:UPT 模式介绍
根据 Intel 所述,此模式需要使用 Intel 的 Broadwell(五代) 或更新的型号,所以如果你的 CPU 不符合此要求(低于第五代但高于第二代),那么只能使用 Leagcy 模式。
在此模式中,IGD 作为第二图形设备直通给虚拟机,而主图形设备是一个虚拟化的图形设备。
这个模式的意义在于提供硬件加速给到主图形设备,并可配合远程桌面软件去使用(如 VNC),但默认情况下此模式不支持物理输出(即无法输出视频信号到外接显示器),但可以通过 QEMU 的相关选项(x-igd-opregion)来开启物理输出。
相比 Legacy 模式,此模式在 IGD 的外部依赖性上没有太多的要求,因此如果你只想利用 IGD 的硬件加速功能,并且你的 CPU 型号不低于五代,那么此模式可能会比较适合你。
3.2:Legacy 模式介绍
此模式要求使用 Intel 的 SandyBridge(第二代) 或更新的型号。也就是说如果你的 CPU 型号低于第五代,但高于或等于第二代的CPU,那么你只能使用 Legacy 模式,例如常见的 i5 4590T、i7 4790等。
在此模式中,IGD 作为第一图形设备直通给虚拟机,并且只有这一个图形设备,外接的显示器会成为默认的物理输出目标(同样需要 QEMU 的相关选项来支持物理输出)。换句话说,不能存在虚拟化图形设备,否则可能会变成 UPT 模式。
4、设置服务器的 BIOS ,并根据实际情况进行调整
在正式进入到 Unraid 之前,我们需要对主机的 BIOS 进行针对性的配置。
首先的问题就是:主板 BIOS 设置对 IGD 的直通有哪些影响?为什么要针对性配置?要针对哪些配置进行设置?
对于 BIOS,我们的着重点是关于 IGD 的相关配置,因此我默认你已经将主板的 VT-d / AMD-V 、IOMMU 等相关虚拟化开启,否则将无法使用相关的虚拟化功能。
4.1:UEFI 启动还是 Legacy BIOS 启动
首先,这两种启动方式会影响 VBIOS(Video BIOS) 的加载,所以你要做的第一件事就是确定你的主板是否同时支持这两种启动模式,或者说你的主板是否支持 CSM(兼容性支持模块) 功能。
对于 UEFI 启动模式,除非你使用的是比较老一些的主板,否则大多数近些年的主板基本都是支持的。而对于 Legacy BIOS 这种传统的启动模式,如果你使用的主板(家用)比较新,而且价格还比较贵,那么有可能你的主板不会支持这种模式,因为在主板厂商看来,你都买这么贵的主板了,应该会不需要使用到这种旧的启动模式。所以插句题外话,对于服务器,建议慎重购买那些比较新的且贵的家用型主板,否则可能会因为缺乏某些支持而无法实现本文所述的 IGD 直通。至于这两种启动方式的区别,请大家自行百度。
4.1.1:那么,什么是 VBIOS?
VBIOS 是显卡或集成图形控制器(IGD)的 BIOS。与系统 BIOS 一样,BIOS 提供了一系列功能以便程序能够访问系统的硬件,而 VBIOS 也提供了一系列与视频有关的功能供程序访问视频硬件(IGD)。VBIOS 将软件与视频芯片组连接起来,其方式与系统BIOS对系统芯片组的作用相同。
BIOS(basic input/output system,基本输入输出系统,也被称为System BIOS、ROM BIOS或PC BIOS)是 CPU 在接通电源后用来启动计算机系统的程序,是用于在启动过程中执行硬件初始化(开机启动)的固件,并为操作系统和程序提供运行时服务,它还负责计算机操作系统与设备(如硬盘、显卡、键盘鼠标和打印机等)之间的数据流。
VBIOS 是 Option ROM 中的一种:Option ROM (或缩写为 OpROM) 是由 BIOS 在电脑启动时所运行的固件,它们通常存储在设备或主板的 BIOS 中。
Option ROM 本质上是一个驱动,负责 BIOS 和硬件之间的沟通,Option ROM 可能由主板的 BIOS 提供,也有可能由硬件设备自身进行提供(因为主板的BIOS不太可能会包含所有设备的 Option ROM,所以往往就需要设备自己进行提供),这些设备包括网卡、显卡或硬盘等。
而 VBIOS 就是 Option ROM 中的一种 —— 是显卡与 BIOS 之间进行沟通的桥梁,它会在计算机启动时进行加载,Video BIOS 会向 BIOS 和操作系统提供相关的显示服务。也就是说,如果 VBIOS 不能正确加载,那么就会直接影响 IGD 的正常使用,进行影响 IGD 的虚拟机直通。
4.1.2:那么 VBIOS 跟我们这里说的 UEFI 或 Legacy 启动模式有什么关系?
在于不同的启动方式可能会对 VBIOS 的加载结果有直接影响(因为有些 VBIOS 可能不支持 UEFI 或 Legacy 启动,但是这个过程我也不是很清楚,这个观点仅仅支持作者自己得出,希望大家帮纠正),也就说选择了不同的启动方式,可能会对 IGD 直通有影响。
在此因素的影响下,保守的做法一般是采用 Legacy 启动方式,或者说如果你的主板支持 CSM(兼容性支持模块) 模块,你也可以在采用 UEFI 启动的情况下,将 Option ROM Policy 设置为 “仅传统”:
如果你的主板不支持 Legacy 启动或者说不支持 CSM 模块,那么在这里就没有可选择的余地,只能采用 UEFI 启动(但并不是说就因此无法实现 IGD 的直通,而是说如果能有多一点的选择,那可选择的余地更大,所以才建议买主板的时候需要慎重选择)。
但需要重申的是,并不是说为了 IGD 直通的实现一定要采用某一个启动方式(UEFI 或 Legacy),不同的硬件产生的影响是不一样的,所以我建议可以尝试先采用 Legacy 启动方式(或者在 CSM 设置中使用 Legacy 模式去加载 Option ROM)去启动 Unraid,然后去测试 IGD 的直通,然后有需要再去测试 UEFI 启动的形式。
4.2:将“主图形适配器”设备设置为核显(IGD)
不同的 BIOS 可能在名字上有区别,需要根据你的主板设置进行判断:
如果不将主图行设备设置为 IGD,那么会直接影响 Option ROM 的加载。
4.3:共享内存、IGPU 多监视器
请将共享内存调制最大(不要设置成自动),并启用 “IGPU 多监视器”(不启用就意味着禁用核显,不同的 BIOS 名称不一样,请根据你自己的情况查找此选项):
显卡共享内存就是显卡在本地显存不够用的情况下,动态调用内存作为显存使用的那部分内存。此设置我建议设置成最大,因为在后面去做直通时,虚拟机的操作系统会因此受到影响。
5、Unraid 上的设置:使用 6.9.x 版本,VFIO驱动绑定,内核启动参数配置
5.1:建议使用 6.9.x 版本的 Unraid
之所以强调版本,是因为较新的版本所使用的 Linux 内核、QEMU、Libvirt 等版本也会更新,对于 IGD 的直通来说,要求使用 Linux 4.6 及以上版本的内核,QEMU 使用 2.7 及以上的版本。以作者的 Unraid 6.9.2 版本来说,Linux 使用的是 5.10.28 版本的内核,QEMU 使用的是 5.1.0 版本,是可以满足 IGD 的直通条件的。
5.2:将 IGD 绑定到 vfio-pci 驱动
什么是 VFIO:Virtual Function I/O (VFIO) 是一种现代化的设备直通方案,它充分利用了VT-d/AMD-Vi技术提供的DMA Remapping和Interrupt Remapping特性, 在保证直通设备的DMA安全性同时可以达到接近物理设备的I/O的性能。 用户态进程可以直接使用VFIO驱动直接访问硬件,并且由于整个过程是在IOMMU的保护下进行因此十分安全, 而且非特权用户也是可以直接使用。 换句话说,VFIO是一套完整的用户态驱动(userspace driver)方案,因为它可以安全地把设备I/O、中断、DMA等能力呈现给用户空间。
vfio-pci 是 VFIO 对 pci 设备驱动的统一封装,具体包括 PCI 配置空间模拟、PCI Bar 空间重定向,Interrupt Remapping等。
vfio-pci 会调用物理主机上的 PCI 设备驱动(pci bus driver)实现设备注册和注销等操作,这里的驱动就正是我们上面第4章所说到的 VBIOS(Option ROM),如果给到 vfio-pci 的设备驱动无法正常使用,那么就会直接导致设备直通无法成功实现。
对于 Unraid(6.9.2版本) 来说,由于集成了“VFIO-PCI CFG”插件,所以我们可以直接在“TOOLS —— System Devices”中进行绑定,绑定设置之后需要重启 Unraid 生效(但此时请先不要重启,因为我们还没讲完后面的操作,我们还需要配置一些 Linux 内核参数):
勾选 IGD 后点击“BIND SELECTED xxx”
5.3:内核启动参数配置
5.3.1:为什么组要配置内核启动参数
在说明原因之前,首先需要说明下什么是 i915:i915 是 Linux 内核中调用 intel 核显的内核驱动(字母 i 就代表的是 Intel,915 代表的是芯片组代号,但这里不需要强调),我们在 Linux 上使用 IGD 就是通过 i915 驱动模块来进行。
所以你会看到社区里的一些关于 Jellyfin、Emby 之类的影音教程文章时,会提到关于 i915 模块的一些设置,目的就是为了加载此模块来使用 IGD 的硬件加速:
那么言归正传,由于我们需要将 IGD 直通给到虚拟机,那么我们在将 IGD 给到虚拟机之前就需要尽可能保证没有其他诸如 i915 之类的驱动绑定到 IGD 上,取消相关驱动对 IGD 的控制。
我在开头讲过,IGD 的直通是一件很复杂的过程(虽然我们可能感受不到),IGD 如同“涂抹”在系统上,是因为由于 Intel 自身设计的原因,驱动层面的调用关系比较错综复杂,如同我们这里提到的 i915——我们要确保在 Unraid 中解除 i915 对 IGD 的绑定,然后才能顺利地将 IGD 直通给虚拟机,因为我们如果不这样做,那么在 IGD 直通给虚拟机后, i915 会在与 IGD 的“绑定”与“解绑定”这一过程中容易出现错误,甚至严重的时候会导致系统崩溃(产生这种结果跟 Linux 的内核有很大关系,因此才建议使用新一点的 Unraid 版本)。
解绑的方法有不少,但我们已经使用了其中一个 —— 那就是前面的 vfio-pci 绑定,我们通过在 Unraid 中使用 VFIO-PCI CFG 工具将 VFIO 驱动绑定到了 IGD,那么这个过程实际上也会将 i915 对 IGD 的绑定进行解绑。除了这种方式外,也有其他诸如下图中的方式,相信你在社区的其他教程中也看到过(使用 modprobe.blacklist 内核启动参数命令,或者也可以在 Unraid 的/etc/modprobe.d/文件中来编辑),类似的方法就不一一介绍了:
5.3.2:要配置哪些内核启动参数
前面通过 i915 驱动模块举例说明了在 Linux 中驱动对 IGD 的调用,但在 Linux 中不仅仅只有 i915 这一驱动需要调用 IGD,其他的一些层级没有 i915 这么高的驱动实际上也在调用 IGD —— 其中以 vesafb 和 efifb 为甚。
vesafb:VESA Framebuffer(在使用传统的 BIOS 启动时会采用此驱动);
efifb:EFI Framebuffer(在使用 UEFI 启动时会采用此驱动);
这两者都是 Framebuffer,根据启动方式的不同,Linux 所使用的 Framebuffer 也不同。
Linux图形栈之Framebuffer驱动:framebuffer就是帧缓存,也就是说开发者希望将图像写入帧缓存,就能看到显示设备上的图像,就是这么简单,而不必关心系统与底层显示设备的操作。
如果不取消绑定,那么当你在直通 IGD 给到虚拟机时,你可能会看到虚拟机的运行日志中出现如下信息:
Failed to mmap 0000:00:02.0 BAR <>. Performance may be slow
这就说明 vesafb 或 efifb 没有取消对 IGD 的绑定,因此你需要在 Unraid 的内核启动参数中添加如下参数:
video=vesafb:off,efifb:off
或者
video=vesafb:off video=efifb:off
那么以上就是 Linux 内核启动参数中需要配置的参数了。
需要特别说明的是,你也许会在别的教程中看到在 Unraid 的内核启动参数中配置了很多的参数,比如我从社区里面拷贝了如下参数:
append vfio-pci.ids=8086:a370,8086:a304,8086:a348,8086:a323,8086:a324,8086:15bc,8086:3e92 isolcpus=0-1 pcie_acs_override=downstream,multifunction vfio_iommu_type1.allow_unsafe_interrupts=1 modprobe.blacklist=i2c_i801,i2c_smbus,snd_hda_intel,snd_hda_codec_hdmi,i915,drm,drm_kms_helper,i2c_algo_bit video=efifb:off,vesafb:off vfio_iommu_type1.allow_unsafe_interrupts=1 initrd=/bzroot
首先,上述的配置我认为有些内容可能(我说的是可能)是没有必要的,比如说 modprobe.blacklist=snd_xxx_xxx ,snd 模块指的是 Linux 中的板载声卡驱动模块,用来调用板载声卡。
我们上面讲过,像 i915 这样的驱动在对 IGD 的绑定与解绑定上可能会产生错误,但除了 i915 之外,大多数相关设备的驱动 —— 就好比这里的 snd 驱动,在虚拟机直通中的绑定与解绑定中往往能够得到很好的处理,换句话说就是如果你将板载的声卡直通给虚拟机,那么你往往不需要做什么额外的参数配置(当然,将板载声卡通过 VFIO 绑定是必不可少的),因为 VFIO 能够很好的处理声卡驱动的绑定与解绑定。
我通过这个例子想告诉大家的是,尽量不要直接将他人的参数直接照搬过来放到自己的 Unraid 配置上,因为不同的底层物理硬件需要使用不同的策略,没有一个固定的公式来去解决问题。
所以我建议的是采用固定变量的原则去一点点排查问题,不单是这里的内核参数配置,还包括后面所说的一些内容。
6:不同直通模式下的虚拟机配置思路
在本章,我会介绍在两种不同的直通模式下的虚拟机配置思路和建议,包括如何选择 Machine 类型和 BIOS 类型等,只谈思路和相关的原理,具体完整的参考配置请见“7、不同直通模式下的 Windows 10/11 系统虚拟机参考配置”。
在开头说过,IGD 的直通存在 UPT 和 Legacy 两种模式,这两种模式各有自己的优点和缺点,并且更重要的是这两模式对 CPU 有要求,前者只能使用五带及更新的型号,后者只能使用二代及更新的型号。
不同的直通模式对虚拟机的参数配置有直接的影响,除此之外,以下两个因素还会产生影响的影响:
Machine Type:Q35 和 i440fx(两者的一些区别请大家自行百度,在本文就不做描述了)
BIOS Type:SeaBIOS 和 OMVF
SeaBIOS 与 OMVF:这两个都是 BIOS,作用也跟 BIOS 一样,都是用来初始化相关的设备,只不过是应用在虚拟机上。前者就相当于我们前面所说的 Legacy BIOS,后者就相当于 UEFI,不同的应用场景应该选择不同的 BIOS 类型。
我分别在两种直通模式的基础上,基于我现有的硬件,测试了不同的 Machine 和 BIOS 类型(见下图,但请勿参照图片的内容,因为在作者写本片文章的时候,表格内的数据未经整理和矫正):
请勿参考本图片的内容,图片的内容未经整理、矫正
在我测试结果的基础上,我会在下文提供给大家针对不同模式的虚拟机参数配置,但仅供参考,仅供参考,仅供参考!
6.1:UPT 直通模式的虚拟机参数配置思路(仅供参考)
如果你的 CPU 等于或高于第五代 CPU,那么我建议采用 UPT 模式进行直通,并可以参考以下设置:
Machine Type:Q35
BIOS:OMVF
内存:请选择4G以上的内存,等调试好系统之后再看情况进行增减
这里我选择6G的内存
前面我们说过,UPT 模式下 IGD 作为第二个图形设备传递给虚拟机,因此对于 IGD 和虚拟图形的设备如下:
新增第二个图形设备,并选择 IGD
其他的比如设置硬盘大小、选择安装镜像这些我就不赘述了,请大家自行配置。
当你配置完相关设置后,请不要勾选创建后启动虚拟机:
拖动编辑框到最底部,可以看到关于 IGD 的 XML 配置:
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</source>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</hostdev>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>:这一段的配置指的是 IGD 在虚拟机的 PCI bus 总线中的地址,被设置到了 00:02.0 的位置。
这里我需要重点解释一下 00:02.0 的 pci bus 位置,如果 IGD 被分配到了这一位置,那么会激活 Legacy 直通模式,因为 Legacy 模式下要求 IGD 的 pci bus 位置需要使用 00:02.0。因此,如果不修改这一地址,那么当你在运行虚拟机后,运行日志会有这样一行提示:
pci, host=0000:00:02.0, id=hostdev0, bus=pcie, addr=0x2 : IGD device 0000:00:02.0 cannot support legacy mode due to existing devices at address 1f.0
我们可以明显的看到“cannot support legacy mode ...”(翻译:不支持 legacy 模式)的提示,这就是因为我们没有更改默认的 IGD pci bus 地址所导致,以至于激活了 Legacy 模式,但 Q35 模型是不支持 Legacy 直通模式的,所以才会出现此错误。但不是说在 Q35 模式下 Legacy 模式就不能使用了,在作者做测试的时候,即使出现此提示也依然能够实现 IGD 的直通,具体背后逻辑我目前也不清楚。
同时,这行提示的后半句还说明了不支持的原因 ——“cannot support legacy mode due to existing devices at address 1f.0”(翻译:由于位于 1f.0 位置的设备,导致了无法支持 legacy 模式),那么为什么 1f.0 位置设备会导致 Legacy 模式无法实现?
那是因为对于 Legacy 直通模式来说,除了 IGD 设备必须指定在 00:02.0 位置之外,于此同时还有一个条件:必须要保证在 00:1f.0 的 pci bus 位置创建 LPC/ISA Bridge,但是对于 Q35 模型来说 00:1f.0 位置并不是用来创建 LPC/ISA Bridge 的,此地址作为 Q35 模型的保留地址不能随意编辑,所以才导致了“cannot support legacy mode due to existing devices at address 1f.0”的提示。
但 i440fx 模型不存在此问题,因为此模型可以在 00:1f.0 位置上创建它的 LPC/ISA Bridge,所以你不会在该模型的虚拟机日志中看到这样的提示。
那么解决办法是什么?
修改 IGD 的 pci bus 位置。可以将 <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> 中的 slot='0x02' 修改成 slot='0x04' 或 slot='0x05' 都是可以的,但前提是不能跟现有的其他设备的 pci bus 位置冲突,否则会报错,如果报错了,请尝试将 slot='0x02' 中的数字 2 改成其他更大一点的数值。所以你可以将整个 XML 复制到文本编辑器中,然后使用查找功能去检索你修改好的 bus='0x00' slot='0x0?' 地址是否跟其他设备的地址有冲突,然后再复制回去。
并且还需要保证 IGD 的 pci bus 位置要低于虚拟化图形设备的 pci bus 地址,这是 UPT 模式的一个特点。不过默认情况下创建出来 XML 配置,虚拟化图形设备的 PCI bus 会低于 IGD,所以我们一般只需要更改 IGD 的地址即可。
假设我们最终修改 IGD 的 pci bus 地址如下(仅供参考):
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</source>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</hostdev>
修改好之后,点击 Update 即可,之后即可正常安装 Windows 并安装 IGD 的显卡驱动:
6.2:Legacy 直通模式的虚拟机参数配置思路(仅供参考)
Legacy 直通模式的实现是最复杂的,在这一小节我会花多点文字尽可能讲清楚其中的逻辑。
如果你的 CPU 高于第二代但低于第五代 CPU,那么你只能采用 Legacy 模式进行直通,并可以参考以下设置:
Machine Type:i440fx
BIOS:SeaBIOS
内存:请选择4G以上的内存,等调试好系统之后再看情况进行增减
图形设备选择 IGD,且只有这一个图形设备:但是在你还没有安装系统前,请不要将图形设备设置成 IGD,请使用虚拟化的图形设备(VNC)去安装系统,调试好系统后再将图形设备更改成 IGD,然后再通过远程桌面的形式去安装 IGD 驱动等。
设置好上述配置后,在后续你可能大概率需要:
准备一个 VBIOS ROM(我会提供到网盘下载,见文章末尾,但请看完本小节)
配置虚拟机 XML ,添加 QEMU 参数,解决 IGD 大量占用系统内存的问题(附加说明如何开启物理视频输出到外接显示器)
6.2.1:为什么需要准备 VBIOS ROM?
重要声明:当用于IGD直通时,使用 VBIOS ROM 可能会损坏你的显示器(因为会产生 bad pixel clock)!作者不对任何显示器的损坏负责,请谨慎操作!
重要声明:当用于IGD直通时,使用 VBIOS ROM 可能会损坏你的显示器(因为会产生 bad pixel clock)!作者不对任何显示器的损坏负责,请谨慎操作!
重要声明:当用于IGD直通时,使用 VBIOS ROM 可能会损坏你的显示器(因为会产生 bad pixel clock)!作者不对任何显示器的损坏负责,请谨慎操作!
我在前面的“4、服务器的 BIOS 配置”提到了关于 VBIOS 的 Option ROM 相关信息:主板的 BIOS 需要在电脑启动的时候去加载 IGD 的 VBIOS(Option ROM的一种),以便正确初始化 IGD 给到操作系统去使用。那么在这里,还需要补充一个知识:Shadow RAM(或也称为 ROM Shadow)。
百度百科:在机器上电时,将自动地把系统BIOS、显示BIOS(VBIOS)及其它适配器的BIOS装载到Shadow RAM 的指定区域中。由于Shadow RAM的物理编址与对应的ROM相同,所以当需要访问BIOS时, 只需访问Shadow RAM即可,而不必再访问ROM。
如果物理主机采用 UEFI 启动模式,那么当 BIOS 在加载 VBIOS 时,会将 VBIOS “复制”(shadow)一份到 RAM 中,那么这一份复制出来的 VBIOS 将来就会给到操作系统(Linux)去使用,但这个复制出来的 VBIOS 并不是真正的 VBIOS,甚至可能是“残缺”的、不完整的。
因此,如果虚拟机的 BIOS 不能正常加载,那么我们就需要单独提供一个 VBIOS 文件给到虚拟机去使用,以便虚拟机的 BIOS(SeaBIOS 或 OMVF)能够正常加载,否则即使虚拟机能够启动也会在 Windows 的设备管理器中出现显卡驱动 43 错误的情况。
虚拟机 BIOS 不能正常加载的常见的情况之一就是VNC黑屏,且某一个CPU核心满载。
就作者自身的硬件情况,我用此 ROM 文件可以解决此问题(如果无法下载,请看文章最末尾的网盘地址),但因为不同的硬件情况,此 ROM 文件不一定能解决所有的问题:
在 Github 上也有其他的一些作者提供 ROM 文件,但我没尝试过这些 ROM 文件是否可以解决所提到的问题,这里就不一一介绍了,请自行根据下面的项目名称搜索(社区规定不能直接放链接),请谨慎尝试:
gk41-pve-ovmf
i915ovmfPkg
6.2.2:ROM 文件要如何给到虚拟机使用?
将 ROM 文件上传至 Unraid 之后,在虚拟机编辑界面的 “Graphics ROM BIOS” 选择对应的 ROM 文件即可:
6.2.3:虚拟机的 Windows 出现内存占用大的情况如何解决?
你可能会遇到 Windows 系统内存被大量占用的情况,比如社区里就有作者提到此类问题,并也提供解决办法:
那么解决办法也很简单,按照下图将 QEMU 选项添加进 XML 模板即可:
<qemu:commandline>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-igd-gms=1'/>
</qemu:commandline>
根据 vfio/pci-quirks: Set non-zero GMS memory size for IGD 的说法,之所以会出现内存占用高的问题是因为 Windows 10( 11 也有此类问题)的驱动问题所导致,使用上述的配置后,大约可以释放出 4G 左右的内存:
There is a claim that GMS memory is unused however Intel Windows 10 drivers starting from V.4534 (10/7/2016) allocate extra ~4G memory when GMS size set to 0.
6.2.4:如何实现虚拟机画面的物理输出?
你也许注意到了,在上面的那一章解决内存占用大的社区文章中,还有这样一段配置:
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-igd-opregion=on'/>
x-igd-opregion=on:根据 ArchWiki: Intel GVT-g 的说明,此段代码的作用是 retrieve the display contents from the virtual GPU by Using DMA-BUF display ,也就是实现物理输出。
之所以需要配置此参数,是因为一个特殊的内存区域 OpRegion ( x-igd-opregion 中的 opregion,但这个内存区域到底是什么我也不知道)需要提供到虚拟机的操作系统驱动。这个内存区域需要在虚拟机的 BIOS 初始化 PCI 设备的时候通过 QEMU 的 fw_cfg 接口进行暴露,从而实现物理输出。
因此,如果你想实现 IGD 的物理输出,就需要加上此参数。那么在配合结合上面所说到的内存占用大的问题同时,完整的 XML 格式如下:
<qemu:commandline>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-igd-opregion=on'/>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-igd-gms=1'/>
</qemu:commandline>
需要做补充的是,之所以需要 QEMU 的相关选项来支持物理输出,是因为这些年 Intel 没有对 GVT-g 做更进一步的支持,x-igd-opregion=on 只作为一个实验性的选项可用(x 就代表的是 “experimental 实验性的”),如果将来某天 Intel 在这一块跟进了,就不再需要添加这选项来实现物理输出了。
7、不同直通模式下的 Windows 10/11 系统虚拟机参考配置
好了,聊了那么多,这里作者提供两个根据不同直通模式下的虚拟机 Windows 系统的配置例子。
以下配置在作者自身硬件之上可以正确实现 IGD 的直通,但每个人的硬件状况不同,软件配置也不一样,因此以下内容仅供参考!
但物理显示输出未经测试,请自行尝试。
7.1:如果你的 CPU 型号 ≥ 第五代 CPU,那么建议你选择 UPT 直通模式
以下配置经过作者自身进行测试,根据我自己的硬件情况,以下配置不需要提供 ROM 文件也可以实现正常的直通,且也没有内存占用高的问题。
如果使用 ROM 文件,请谨慎操作!因为使用 VBIOS 可能会损害的显示器,作者不对此负责!
如果使用 ROM 文件,请谨慎操作!因为使用 VBIOS 可能会损害的显示器,作者不对此负责!
如果使用 ROM 文件,请谨慎操作!因为使用 VBIOS 可能会损害的显示器,作者不对此负责!
参考的配置如下:
CPU:根据你的情况来
Machine:Q35-5.1
BIOS:OMVF
内存:6G(选择4G以上,原因是因为怕会出现上面所说到的内存占用大的问题,但我自己测试没有遇到)
添加 IGD 作为第二个图形设备(初次尝试时请不要设置 ROM 文件,如果无法直通再进行尝试)
如果出现内存占用大的情况,或者说需要实现物理输出,请参考上文的内容编辑 XML 模板来添加 QEMU 选项(x-igd-opregion=on,x-igd-gms=1);
其他选项例如虚拟硬盘大小、安装镜像等请自行配置;
配置如下图所示:
XML 配置如下:
<domain>
......
<devices>
....
<graphics type='vnc' port='-1' autoport='yes' websocket='-1' listen='0.0.0.0' keymap='en-us'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<video>
<model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
</video>
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</source>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</hostdev>
<memballoon model='none'/>
</devices>
</domain>
7.2:如果你的 CPU 型号 ≥ 第二代但小于第五代,那么你只能选择 Legacy 直通模式
以下配置经过作者自身进行测试,根据我自己的硬件情况,需要提供 ROM 文件并编辑虚拟机的 XML 模板来配置相关 QEMU 选项,否则无法实现 IGD 直通与物理显示输出。
如果你和我一样出现下面的提示,那么此时就需要使用到 VBIOS ROM 文件:
unraid 会通过 vfio-pci 驱动来暴露主机的 VBIOS 文件给到虚拟机,以便虚拟机的 BIOS 能够正确初始化 IGD。但是如果主机无法提供 ROM 文件给到 vfio-pci (造成的因素很多),那么虚拟机就无法正常启动。所以这种情况下就需要我们自己去单独提供 ROM 文件给到虚拟机去加载。
使用 ROM 文件时请谨慎!因为使用 VBIOS 可能会损害的显示器,作者不对此负责!
使用 ROM 文件时请谨慎!因为使用 VBIOS 可能会损害的显示器,作者不对此负责!
使用 ROM 文件时请谨慎!因为使用 VBIOS 可能会损害的显示器,作者不对此负责!
参考的配置如下:
CPU:根据你的情况来
Machine:i440fx-5.1
BIOS:OMVF
内存:6G(选择4G以上,作者测试的时候出现了内存占用大的问题,需要配合 QEMU 来解决,但请在开始的时候选择大一点的内存,否则可能无法启动)
IGD 作为主图形设备,且唯一(但是在你还没有安装系统前,请不要将图形设备设置成 IGD,请使用虚拟化的图形设备(VNC)去安装系统,调试好系统后再将图形设备更改成 IGD,然后再通过远程桌面的形式去安装 IGD 驱动等)
其他选项例如虚拟硬盘大小、安装镜像等请自行配置;
如果出现内存占用大的情况,或者说需要实现物理输出,请参考上文的内容编辑 XML 模板来添加 QEMU 选项(x-igd-opregion=on,x-igd-gms=1);
XML 配置如下:
<domain>
......
<devices>
......
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio'/>
<source>
<address domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</source>
<rom file='/mnt/user/domains/vbios_gvt_uefi.rom'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</hostdev>
<memballoon model='none'/>
</devices>
</domain>
8、文章总结:相关案例参考,VBIOS ROM文件下载地址
IGD 的直通存在两种模式:UPT 和 Legacy,不同的模式对 CPU 的型号有要求,前者要求五代及以上,后者要求二代及以上;
这两种模式要使用不同的方式去实现,但都要求在 BIOS 中做相应的设置,其中包括启动方式(BIOS、UEFI)、OpROM 策略、主图形适配器、共享内存等;
与此同时,除了 BIOS 层面,IGD 的直通还涉及 Linux 的内核以及 QEMU 的相关选项支持,所以一般建议在使用 Unraid 的时候使用 6.9.x 版本,因为新版本的 Unraid 会使用更新的 Linux 内核以及 QEMU;
在 Unraid 中,你需要将 IGD 绑定给 VFIO 驱动(vfio-pci),并通过配置 Unraid 的内核启动参数来解除一些除了 i915 之外的驱动,以避免这些驱动对 IGD 进行控制,否则可能会导致 IGD 无法正常直通(或者影响到IGD的运行);
在 Unraid 中创建虚拟机时,需要根据所选择的直通模式来进行配置,不同的直通模式影响具体的虚拟机参数设置;
需要特别注意的是,如果需要使用 VBIOS ROM 文件,请谨慎操作,因为有可能会对你的显示器造成伤害;
虚拟机的 Machine 和 BIOS 也会对 IGD 的直通结果造成影响,对于 Windows 虚拟机来说,一般都建议使用 OMVF,并且如果你的硬件设备相对比较新,那么建议使用 Q35 模型;
ROM 文件下载地址:百度网盘(提取码:q46e)
作者编写本文章时所参考的一些重要文章(社区不让放链接,请大家根据标题自行搜索):
Intel GVT-g,
Github:qemu/docs/igd-assign.txt,
Intel Graphics assignment,
Running Windows 10 on Linux using KVM with VGA Passthrough
PCI passthrough via OVMF
Set up Intel IGD opregion to allow for passthrough of Intel integrated graphics devices
Proxmox:Pci passthrough
KVM QEMU PVE UNRAID INTEL IGD GVT-D 直通研究心得
Github:intel/gvt-linux
vfio/pci: Intel IGD support
fw/pci: Add support for mapping Intel IGD via QEMU
至此,作者已经将整个 IGD 大致的过程梳理完了,并且也提供了参考的 Windows 虚拟机参数设置的配置建议。
但正如开头所说,虚拟化是一个很复杂的过程,虽然文章很长,但实际上比起所搜集到的资料仍有很多很多的具体细节无法通过此文章呈现出来。所以,本文章仍有不少地方需要补充或者纠正,希望读者们能够提供相关建议和观点以补充本文章所缺失的内容或对结论进行纠正。
(完)
作者声明本文无利益相关,欢迎值友理性交流,和谐讨论~