虚拟化是个很复杂的东西,存在有很多因素会影响虚拟化的成功与否,并且 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.
翻译: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
其他的比如设置硬盘大小、选择安装镜像这些我就不赘述了,请大家自行配置。
当你配置完相关设置后,请不要勾选创建后启动虚拟机:
我们创建好虚拟机后,使用 XML 试图去进行编辑:
拖动编辑框到最底部,可以看到关于 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 的显卡驱动:
网友评论