跳转至

Kvm qemu显卡直通部署以及性能调优

参考

中文: https://wiki.archlinuxcn.org/wiki/PCI_passthrough_via_OVMF

英文比较全: https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF#

https://space.bilibili.com/589560036

搭建教程: https://gitlab.com/liucreator/LEDs-single-gpu-passthrough

去虚拟化: https://github.com/zhaodice/qemu-anti-detection

去虚拟化: https://ivonblog.com/posts/qemu-kvm-bypass-easy-anti-cheat/

cpu隔离: https://github.com/lennard0711/vfio?tab=readme-ov-file#cpu-isolation

安装qemu

前置需要先安装ninga

git clone https://gitlab.com/qemu-project/qemu/ -b v8.2.0
cd qemu

# 对源码打过检测补丁
git apply qemu8.2.0.patch

# 创建编译的目录
mkdir qemu_build
cd qemu_build

# 设置编译条件, 安装到/usr/local 目录下
../qemu/configure --target-list=x86_64-softmmu,x86_64-linux-user --prefix=/usr/local

make -j $(nproc)

# 由于安装到/usr/local 目录下, 所以这里需要加sudo
sudo make install

# 如果需要卸载, 可以执行
sudo make uninstall

启用iommu

查询是否开启

我amd 默认启用了 输入以下命令, 找找有没有amd_IOMMU:Detected

sudo dmesg | grep -e DMAR -e IOMMU

获取组id

运行 iommuamd.sh 这个脚本, 找到显卡相关的id, 然后复制下来, 比如我的如下, 分别是1002:73ff显卡的显示设备和1002:ab28显卡中的音频设备

OMMU group 18
        09:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 23 [Radeon RX 6600/6600 XT/6600M] [1002:73ff] (rev c1)
                Driver: amdgpu
IOMMU group 19
        09:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Navi 21/23 HDMI/DP Audio Controller [1002:ab28]
                Driver: snd_hda_intel

添加vfio到内核模块

编辑 /etc/modprobe.d/vfio.conf文件, 添加以下内容, 记得把自己的id替换掉

options vfio-pci ids=1002:73ff,1002:ab28
options vfio-pci disable_idle_d3=1
options vfio-pci disable_vga=1

安装所需要软件

# 连接器, 用于管理kvm
sudo pacman -S libvirt

# edk2-ovmf 提供了uefi引导
sudo pacman -S edk2-ovmf

# 提供了以一个qemu的图形化管理界面
sudo pacman -S virt-manager

# 网络相关
sudo pacman -S dnsmasq ebtables iptables bridge-utils

开机启用服务

sudo systemctl enable libvirtd
sudo systemctl enable virtlogd.socket

启用Libvirt

sudo systemctl start libvirtd
sudo systemctl start virtlogd.socket

启用虚拟网络

sudo virsh net-start default
sudo virsh net-autostart default

安装一个win10虚拟机

按照正常的步骤, 先安装一个windows系统, 并进入到桌面, 之后我们关掉, 继续进行下一步操作

注意点:

  • 不能使用virtio的任何设备, 因为过检测补丁的原因, virtio也无法使用不读盘
  • 所以全部使用stat设备
  • 网络设备, 和磁盘设备, 记得随便输入几个字符作为串口
  • 安装win10在引导界面, 可能选择指定的引导磁盘也没有效果, 这时候选择可以疯狂的按上下左右小键盘 可能就进去了
  • 一切正常之后, 配置显卡直通前, 要关掉virt-manager,之后再进行下面的一切操作
  • 直通前, 记得把本身的显卡视频vga或者qml这个设置为None或者直接删掉这个设备

配置Libvirt

hook

# 在Libirt里面创建一个hooks文件夹
sudo mkdir /etc/libvirt/hooks

# 把hooks文件夹中的所有文件复制到目录中
sudo cp hooks/* /etc/libvirt/hooks/

# 更改权限
sudo chmod +x /etc/libvirt/hooks/*

# 把两个脚本软链接到根目录的bin文件夹
sudo ln -s /etc/libvirt/hooks/vfio-startup.sh /bin/vfio-startup.sh
sudo ln -s /etc/libvirt/hooks/vfio-teardown.sh /bin/vfio-teardown.sh

防止休眠

编辑/etc/systemd/system/libvirt-nosleep@.service文件, 添加如下:

[Unit]
Description=Preventing sleep while libvirt domain "%i" is running

[Service]
Type=simple
ExecStart=/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/libvirt-nosleep@.service

使其变成系统文件

sudo chown root:root /etc/systemd/system/libvirt-nosleep@.service

配置Libvirt.conf

首先备份文件

mkdir bck
sudo cp /etc/libvirt/libvirtd.conf ./bck/

编辑/etc/libvirt/libvirtd.conf文件, 找到如下两行,并把#注释删掉 可以搜索unix_sock_groupunix_sock_rw_perms 改完就像下面这样:

unix_sock_group = "libvirt"
unix_sock_rw_perms = "0770"

在该文件最后添加日志配置 如果以后qemu有启动失败, 可以在sudo tail -f /var/log/libvirt/libvirtd.log查看日志

log_filters="1:qemu"
log_outputs="1:file:/var/log/libvirt/libvirtd.log"

配置qemu.conf

首先备份文件

mkdir bck
sudo cp  /etc/libvirt/qemu.conf ./bck/

编辑/etc/libvirt/qemu.conf, 可以搜索#user =#group =, 改为如下:

user = "你自己的用户名",
group = "libvirt"

添加组

sudo usermod -a -G libvirt 你自己的用户名

重启电脑或者重启libvirt

sudo systemctl restart libvirtd.service
sudo systemctl restart virtlogd.socket

配置显卡vbios

我这是a卡, 直接开搞就行, n卡自行搜索, 需要删掉vbios中的一些二进制数据才可以 注意 xxx.rom 文件最好放在~目录下, 我好想踩过坑, 具体细节忘了

cp vbios文件.rom ~/
cd ~

# 修改权限
sudo chmod -R 660 vbios文件.rom
# 更改拥有者
sudo chown 你自己的用户名:users vbios文件.rom

打开virt-manager, 添加自己的pcie设备, 注意需要把上面的保存的那两个都添加进去, 然后在pcie设备管理面板, 右侧编辑xml文件, 在</source>那一行的下面添加如下注意要修改自己的rom文件的路径:

<rom bar="on" file="/home/cnm/6600xt.rom"/>

开机吧

记得把本身的显卡视频vga或者qml这个设置为None或者直接删掉这个设备

虚拟机配置

在显卡直通完毕, 并且win10启动正常之后, 才可以进行下面的配置

设置cpu绑定

可以使用lscpu -e查看cpu信息 emulatorpin是设置虚拟机本身的程序习用的核心 下面是配置了一个6核心的虚拟机, 由于我关闭了超线程所以把物理核心的2,3,4,5,6,6分配给了win10, 我们尽量不要是用物理核心0

  <cputune>
    <vcpupin vcpu="0" cpuset="2"/>
    <vcpupin vcpu="1" cpuset="3"/>
    <vcpupin vcpu="2" cpuset="4"/>
    <vcpupin vcpu="3" cpuset="5"/>
    <vcpupin vcpu="4" cpuset="6"/>
    <vcpupin vcpu="5" cpuset="7"/>
    <emulatorpin cpuset="0,1"/>
  </cputune>

隐藏cpu信息

cpu段落

在XML配置,找到<cpu>这一段mode设为host-passthrough, 并在段落中添加如下 我这里使用这个配置之后, cpu无论如何也无法有效调度显卡,,, 玩什么游戏fps只有十几的fps, 我没有用

注意 上面十几fps是鲁大师测得,QAQ, 我实际进游戏, 是正常的!!!, 所以这个是可以加上去的

<feature policy="disable" name="hypervisor"/>

硬盘直通

就像我的截图, 记得配置好之后, 在引导选项里面也给这个磁盘打勾~

os段落

添加一行

<smbios mode="host"/>

features段落添加

有重复的就不用再次添加了

    <hyperv mode="custom">
      <relaxed state="on"/>
      <vapic state="on"/>
      <spinlocks state="on" retries="8191"/>
      <vpindex state="on"/>
      <runtime state="on"/>
      <synic state="on"/>
      <stimer state="on"/>
      <reset state="on"/>
      <frequencies state="on"/>
      <vendor_id state="on" value="random"/>

      <reenlightenment state="on"/>
      <tlbflush state="on"/>
      <ipi state="on"/>
      <evmcs state="off"/>

    </hyperv>
    <kvm>
      <hidden state="on"/>
    </kvm>
    <vmport state="off"/>
    <smm state="on"/>
    <ioapic driver="kvm"/>

屏蔽amdgpu内核模块

如果帧率过低需要, 可能是影响到了, 需要下面的方式关掉, 选择自己的设备, 按需复制

修改/etc/modprobe.d/blacklist.conf

#直通 AMD 显卡,请使用下面命令
blacklist radeon
blacklist amdgpu

#直通 Nvidia 显卡,请使用下面命令
blacklist nouveau
blacklist nvidia
blacklist nvidiafb

#直通 Intel 核显,请使用下面命令
blacklist snd_hda_intel
blacklist snd_hda_codec_hdmi
blacklist i915options

对cpu进行隔离

https://github.com/lennard0711/vfio?tab=readme-ov-file#cpu-isolation

https://blog.csdn.net/w_melody/article/details/129694715

https://codeleading.com/article/48135677974/

性能调优

参考配置

<domain type="kvm">
  <name>win10</name>
  <uuid>5a534ed8-d2ea-4a2e-8c8c-d6fd9cf435de</uuid>
  <metadata>
    <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
      <libosinfo:os id="http://microsoft.com/win/10"/>
    </libosinfo:libosinfo>
  </metadata>
  <memory unit="KiB">12194304</memory>
  <currentMemory unit="KiB">12194304</currentMemory>
  <vcpu placement="static">7</vcpu>
  <cputune>
    <vcpupin vcpu="0" cpuset="1"/>
    <vcpupin vcpu="1" cpuset="2"/>
    <vcpupin vcpu="2" cpuset="3"/>
    <vcpupin vcpu="3" cpuset="4"/>
    <vcpupin vcpu="4" cpuset="5"/>
    <vcpupin vcpu="5" cpuset="6"/>
    <vcpupin vcpu="6" cpuset="7"/>
    <emulatorpin cpuset="0"/>
  </cputune>
  <os firmware="efi">
    <type arch="x86_64" machine="pc-q35-8.2">hvm</type>
    <firmware>
      <feature enabled="no" name="enrolled-keys"/>
      <feature enabled="no" name="secure-boot"/>
    </firmware>
    <loader readonly="yes" type="pflash">/usr/share/edk2/x64/OVMF_CODE.fd</loader>
    <nvram template="/usr/share/edk2/x64/OVMF_VARS.fd">/var/lib/libvirt/qemu/nvram/win10_VARS.fd</nvram>
    <bootmenu enable="yes"/>
    <smbios mode="host"/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <hyperv mode="custom">
      <relaxed state="on"/>
      <vapic state="on"/>
      <spinlocks state="on" retries="8191"/>
      <vpindex state="on"/>
      <runtime state="on"/>
      <synic state="on"/>
      <stimer state="on"/>
      <reset state="on"/>
      <frequencies state="on"/>
      <vendor_id state="on" value="random"/>

      <reenlightenment state="on"/>
      <tlbflush state="on"/>
      <ipi state="on"/>
      <evmcs state="off"/>

    </hyperv>
    <kvm>
      <hidden state="on"/>
    </kvm>
    <vmport state="off"/>
    <smm state="on"/>
    <ioapic driver="kvm"/>
  </features>
  <cpu mode="host-passthrough" check="none" migratable="on">
    <topology sockets="1" dies="1" cores="7" threads="1"/>
    <feature policy="disable" name="hypervisor"/>
  </cpu>
  <clock offset="localtime">
    <timer name="rtc" tickpolicy="catchup"/>
    <timer name="pit" tickpolicy="delay"/>
    <timer name="hpet" present="no"/>
    <timer name="hypervclock" present="yes"/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <pm>
    <suspend-to-mem enabled="no"/>
    <suspend-to-disk enabled="no"/>
  </pm>
</domain>

上面是关闭smt超线程的, 下面是没有关闭超线程的配置, 只有cpupin不同

<domain type="kvm">
  <name>win10</name>
  <uuid>5a534ed8-d2ea-4a2e-8c8c-d6fd9cf435de</uuid>
  <metadata>
    <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
      <libosinfo:os id="http://microsoft.com/win/10"/>
    </libosinfo:libosinfo>
  </metadata>
  <memory unit="KiB">12194304</memory>
  <currentMemory unit="KiB">12194304</currentMemory>
  <vcpu placement="static">12</vcpu>
  <cputune>
    <vcpupin vcpu="0" cpuset="2"/>
    <vcpupin vcpu="2" cpuset="3"/>
    <vcpupin vcpu="4" cpuset="4"/>
    <vcpupin vcpu="6" cpuset="5"/>
    <vcpupin vcpu="8" cpuset="6"/>
    <vcpupin vcpu="10" cpuset="7"/>

    <vcpupin vcpu="1" cpuset="10"/>
    <vcpupin vcpu="3" cpuset="11"/>
    <vcpupin vcpu="5" cpuset="12"/>
    <vcpupin vcpu="7" cpuset="13"/>
    <vcpupin vcpu="9" cpuset="14"/>
    <vcpupin vcpu="11" cpuset="15"/>

    <emulatorpin cpuset="0,1,8,9"/>
  </cputune>
  <os firmware="efi">
    <type arch="x86_64" machine="pc-q35-8.2">hvm</type>
    <firmware>
      <feature enabled="no" name="enrolled-keys"/>
      <feature enabled="no" name="secure-boot"/>
    </firmware>
    <loader readonly="yes" type="pflash">/usr/share/edk2/x64/OVMF_CODE.fd</loader>
    <nvram template="/usr/share/edk2/x64/OVMF_VARS.fd">/var/lib/libvirt/qemu/nvram/win10_VARS.fd</nvram>
    <bootmenu enable="yes"/>
    <smbios mode="host"/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <hyperv mode="custom">
      <relaxed state="on"/>
      <vapic state="on"/>
      <spinlocks state="on" retries="8191"/>
      <vpindex state="on"/>
      <runtime state="on"/>
      <synic state="on"/>
      <stimer state="on"/>
      <reset state="on"/>
      <frequencies state="on"/>
      <vendor_id state="on" value="random"/>

      <reenlightenment state="on"/>
      <tlbflush state="on"/>
      <ipi state="on"/>
      <evmcs state="off"/>

    </hyperv>
    <kvm>
      <hidden state="on"/>
    </kvm>
    <vmport state="off"/>
    <smm state="on"/>
    <ioapic driver="kvm"/>
  </features>
  <cpu mode="host-passthrough" check="none" migratable="on">
    <topology sockets="1" dies="1" cores="6" threads="2"/>
  </cpu>
  <clock offset="localtime">
    <timer name="rtc" tickpolicy="catchup"/>
    <timer name="pit" tickpolicy="delay"/>
    <timer name="hpet" present="no"/>
    <timer name="hypervclock" present="yes"/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <pm>
    <suspend-to-mem enabled="no"/>
    <suspend-to-disk enabled="no"/>
  </pm>

</domain>