使用PCI直通使得虚拟机里能使用显卡。
参考:
核显+独显直通: https://lantian.pub/article/modify-computer/laptop-intel-nvidia-optimus-passthrough.lantian/
Archwiki: https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)
KVM:https://www.bilibili.com/video/BV1dQ4y1o78R
飞蚊话:https://www.bilibili.com/video/BV1ff4y1q7fA
〇、吾电脑的情况
和台式机一样,核显出厂被屏蔽,只剩独显了。这就需要编写脚本使得显卡能在宿主机、客户机之间切换。
优点:
- 高性能,游戏渲染延迟小(独显直通显示器,核显不会和 CPU 和独显抢电)
- 省钱(没有复杂的切换电路)
缺点:
费电(独显需要一直开着)
- 但你买几万块钱的游戏本估计也不关心续航了。
对显卡直通的毁灭性打击
- 因为你只有一块显卡,一旦直通进虚拟机,你的主系统就没有显卡可用了。
- 如果你要坚持进行直通,你需要自己编写显卡在虚拟机和主机之间切换的脚本,并且需要准备一种方法在失去显示的时候进行调试。
- 艺高人胆大的可以上。
双显卡的步骤:
安装
vfio-pci
防止宿主机调用独显,
克隆核显
配置 Intel GVT-g 虚拟核显
配置NVIDIA显卡直通欺骗NVIDIA驱动
一、创建非直通KVM虚拟机
1. 启用IOMMU
若是systemd 启动器:
nano /boot/loader/entries/arch.conf
我用grub
引导,所以
sudo vim /etc/default/grub
在 GRUB_CMDLINE_LINUX_DEFAULT
中,添加intel_iommu=on
和 iommu=pt
之后,生成配置文件:
sudo grub-mkconfig -o /boot/grub/grub.cfg
在重启之后,检查 dmesg 以确认 IOMMU 已经被正确启用:
sudo dmesg | grep -e DMAR -e IOMMU
脚本检测结果:(USB-C 和显卡在一个组)
IOMMU group 1
00:01.0 PCI bridge [0604]: Intel Corporation 6th-10th Gen Core Processor PCIe Controller (x16) [8086:1901] (rev 07)
Driver: pcieport
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU116M [GeForce GTX 1660 Ti Mobile] [10de:2191] (rev a1)
Driver: nvidia
01:00.1 Audio device [0403]: NVIDIA Corporation TU116 High Definition Audio Controller [10de:1aeb] (rev a1)
Driver: snd_hda_intel
01:00.2 USB controller [0c03]: NVIDIA Corporation TU116 USB 3.1 Host Controller [10de:1aec] (rev a1)
Driver: xhci_hcd
Usb bus:
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Usb bus:
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
01:00.3 Serial bus controller [0c80]: NVIDIA Corporation TU116 USB Type-C UCSI Controller [10de:1aed] (rev a1)
Driver: nvidia-gpu
2. 启用VFIO模块
若是双显卡直通,则需要启动时禁用NVIDIA独显,则需要编辑钩子
/etc/mkinitcpio.conf
,在MODULE()
中添加:MODULES=(vfio_pci vfio vfio_iommu_type1 vfio_virqfd)
并且删除
nvidia
等与 NVIDIA 驱动相关的内核模块。这样 PCIe 直通模块就会在系统启动的早期抢占独显,阻止 NVIDIA 驱动后续占用。
之后,运行
mkinitcpio -P
更新 initramfs,重启电脑。
单显卡直通,则需要在进入虚拟机时移交显卡的控制权。因此只需要添加内核的配置文件:
/etc/modprobe.d/vfio.conf
options vfio-pci ids=10de:2191,10de:1aeboptions vfio-pci disable_idle_d3=1options vfio-pci disable_vga=1
给 vfio-pci
这个负责 PCIe 直通的内核驱动一个配置,让它去管理独显。ids
参数就是要直通的独显的制造商 ID 和设备 ID。
先实验只直通图像和音频,不知道是否可行
3. 创建虚拟机
安装qemu和libvirt所需要的包:
sudo pacman -S qemu libvirt edk2-ovmf virt-manager dnsmasq ebtables iptables bridge-utils
开机启用服务
sudo systemctl enable libvirtdsudo systemctl enable virtlogd.socket
开始Libvirt
sudo systemctl start libvirtdsudo systemctl start virtlogd.socket
启用虚拟网络
sudo virsh net-start defaultsudo virsh net-autostart default
启用 sshd
以备后续操作 systemctl enable sshd --now
创建一个虚拟机
下载vitro-win 驱动 https://github.com/virtio-win/virtio-win-pkg-scripts
安装虚拟机前需要先设置CPU数、virtIO驱动盘。安装界面需要加载驱动。
二、Libvirt QEMU 配置和脚本
配置libvirt脚本
在Libirt里面创建一个hooks文件夹sudo mkdir /etc/libvirt/hooks
把这里的三个文件放到hooks文件夹里面
都变成可执行的文件sudo chmod +x /etc/libvirt/hooks/*
把两个脚本软链接到根目录的bin文件夹
sudo ln -s /etc/libvirt/hooks/vfio-startup.sh /bin/vfio-startup.shsudo ln -s /etc/libvirt/hooks/vfio-teardown.sh /bin/vfio-teardown.sh
防止Libvirt在运行时休眠
sudo nano /etc/systemd/system/[email protected]
在[email protected]里面添加:
[Unit]Description=Preventing sleep while libvirt domain "%i" is running[Service]Type=simpleExecStart=/usr/bin/systemd-inhibit --what=sleep --why="Libvirt domain \"%i\" is running" --who=%U --mode=block sleep infinity
更改权限:
sudo chmod 644 -R /etc/systemd/system/[email protected]
变成系统文件
sudo chown root:root /etc/systemd/system/[email protected]
配置qemu
编辑libvirt.conf
sudo nano /etc/libvirt/libvirtd.conf
找到这两行,把前面的
#
删掉:unix_sock_group = "libvirt"unix_sock_rw_perms = "0770"
可以选择把这两行添加到文件的最后面(日志文件):
log_filters="1:qemu"log_outputs="1:file:/var/log/libvirt/libvirtd.log"
编辑qemu.conf
sudo nano /etc/libvirt/qemu.conf
把 #user = "root"
改成 user = "yourusername"
,#group = "root"
改成 group = "libvirt"
把自己添加到libvirt组里面:sudo usermod -a -G libvirt 用户名
之后,重启电脑或者重启libvirt
sudo systemctl restart libvirtd.servicesudo systemctl restart virtlogd.socket
三、显卡直通
提取显卡vbios,使用 GPU-Z
。
或者使用hp下载bios,但我未成功。
打vbios补丁(NVIDIA)
安装十六进制编辑器
bless
,打开显卡vbios.rom
- 查找字符"VIDEO"
把VIDEO
前面第一个大写U.
(十六进制是55)之前的所有的headers都删掉. - 保存到某个地方
我在Arch上保存到个人主目录文件夹是没问题的
Arch、Fedora可以保存到/var/lib/libvirt/vbios
里面,
Ubuntu/OpenSUSE/Mint(用AppArmour的发行版)可以保存到/usr/share/vgabios
里面。 - 修改权限:
sudo chmod -R 660 vbios文件.rom
- 更改拥有者
sudo chown 你的用户名:users vbios文件.rom
- 查找字符"VIDEO"
[可选项] 绕过错误43
**2021年4月以后的英伟达显卡驱动已经不需要绕过虚拟化检测了。因此这一步不需要做了。
但要记住,直通进去后,装上新版的显卡驱动。**
把显卡 BIOS 添加到虚拟机的 UEFI 固件(即 OVMF)中。
# 根据 GitHub 上用户反馈,UEFI 固件编译完成后不能移动位置
# 所以要先找好存放的地方
cd /opt
git clone https://github.com/tianocore/edk2.git
# 安装编译过程中需要的依赖
pikaur -S git python2 iasl nasm subversion perl-libwww vim dos2unix gcc5
# 假设你导出的显卡 BIOS 存放在 /vbios.rom
cd edk2/OvmfPkg/AcpiPlatformDxe
xxd -i /vbios.rom vrom.h
# 编辑 vrom.h,把 unsigned char 数组的名字修改成 VROM_BIN
# 把文件末尾的长度变量改名为 VROM_BIN_LEN,并记录下长度值,我的是 167936
wget https://github.com/jscinoz/optimus-vfio-docs/files/1842788/ssdt.txt -O ssdt.asl
# 编辑 ssdt.asl,修改第 37 行为 VROM_BIN_LEN 的值
# 然后执行下面这行命令,会报错但是没关系,只要 Ssdt.aml 有了就行
iasl -f ssdt.asl
xxd -c1 Ssdt.aml | tail -n +37 | cut -f2 -d' ' | paste -sd' ' | sed 's/ //g' | xxd -r -p > vrom_table.aml
xxd -i vrom_table.aml | sed 's/vrom_table_aml/vrom_table/g' > vrom_table.h
# 返回 edk2 的目录下打补丁
cd ../..
wget https://gist.github.com/jscinoz/c43a81882929ceaf7ec90afd820cd470/raw/139799c87fc806a966250e5686e15a28676fc84e/nvidia-hack.diff
patch -p1 < nvidia-hack.diff
# 开始编译 OVMF
make -C BaseTools
. ./edksetup.sh BaseTools
# 修改 Conf/target.txt 中如下变量的值:
# - ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
# - TARGET_ARCH = X64
# - TOOL_CHAIN_TAG = GCC5
build
# 等待编译完成,确认 Build/OvmfX64/DEBUG_GCC5/FV 文件夹下有这两个文件:
# - OVMF_CODE.fd
# - OVMF_VARS.fd
# 然后替换你的虚拟机的 UEFI 参数,注意修改虚拟机名
cp Build/OvmfX64/DEBUG_GCC5/FV/OVMF_VARS.fd /var/lib/libvirt/qemu/nvram/Win10_VARS.fd
配置qemu
添加libvirt的pcie直通
在Libvirt中把显卡相关的PCIE部件全部添加进去。并编辑它们的XML设置,添加:rom
在这里 source
后
<rom bar="on" file="/home/gakki/qemu_VM/vBIOS/TU106.rom"/>
改善性能的设置
设置CPU模式为host-passthrough
配置CPU拓扑:套接字、核心、超线程
学习了