[guide] How to run PUBG with BattlEye in a VFIO Virtual Machine
***** UDPATED 25 Feb 2024 *****
The update is for few changes, in order to play Escape From Tarkov also, something that was impossible before. Thank you to Mike11207 who provided his XML, and I was able to merge both into a new one.
Lots of users face problems with anti-cheat software when playing in Windows VM. Same for me. Most of the time, when a game does not allow me to use a VM, I just uninstall it and play something else. However, PUBG is a bit different story, as we have a team with my friends and also I have been playing since 2017 before it started kicking VM users about a year ago.
So, I set a goal to myself to make it work, but without any salty change (like re-compile kernel, etc) that will risk a ban to my account. Therefore it would only contain configuration changes and nothing else.
Last couple of weeks I have been playing/testing all of my games (Battlefield, Sniper Elite, Civilization, Assetto Corsa, DCS, God Of War, Assassin's Creed, Hell Let Loose, and many others) to verify performance is good and I have no problems playing online. The only game I didn't manage to play is Escape From Tarkov. Hopefully, there are many others planed for 2024, so I can try them when they come out.
First of all, my setup:
Gigabyte Aorus Master X670E
AMD Ryzen 7950X3D
64GB DDR5 RAM
Gigabyte RTX 4080 OC
Few M2, SSD
-in order to achieve better memory performance, I am using "locked" parameter, which means host cannot use that memory. Depending on your total size, you might need to remove this.
-I am using vfio-isolate to isolate half of the cores, with this script:
```
#!/bin/bash
#/etc/libvirt/hooks/qemu
HCPUS=8-15,24-31
MCPUS=0-7,16-23
ACPUS=0-31
UNDOFILE=/var/run/libvirt/qemu/vfio-isolate-undo.bin
disable_isolation () {
cpuset-modify --cpus C$ACPUS /system.slice \
cpuset-modify --cpus C$ACPUS /user.slice \
irq-affinity mask C$ACPUS
taskset -pc 0-23 2 # kthreadd reset
enable_isolation () {
drop-caches \
cpuset-modify --cpus C$HCPUS /system.slice \
cpuset-modify --cpus C$HCPUS /user.slice \
move-tasks / /system.slice \
compact-memory \
irq-affinity mask C$MCPUS
taskset -pc $HCPUS 2 # kthreadd only on host cores
case "$2" in
echo "prepared" >> /home/username/qemu_hook.log
"started")
;;
"release")
echo "released" >> /home/username/qemu_hook.log
esac
```
-My grub parameters (I am using Manjaro which has ACS patch pre-installed, but maybe it is not needed anymore):
```
GRUB_CMDLINE_LINUX_DEFAULT="resume=UUID=2a36b9fe.... udev.log_priority=3 amd_iommu=force_enable iommu=pt hugepages=16384 systemd.unified_cgroup_hierarchy=1 kvm.ignore_msrs=1 pcie_acs_override=downstream,multifunction vfio_iommu_type1.allow_unsafe_interrupts=1
```
-I am not excluding PCI IDs in Grub, as that doesn't work anymore in Kernel 6.x. I am using "driverctl" to override just my RTX4080 IDs:
```
sudo driverctl set-override 0000:01:00.0 vfio-pci
sudo driverctl set-override 0000:01:00.1 vfio-pci
```
You only need to run this once and works for permanent pass-through. If you are doing "single GPU pass-through", you may have to adapt this.
-My "/etc/modprobe.d/kvm.conf". I have this one in order to be able to install/run Hyper-V in Windows. If you don't need that, you can omit this, but PUBG won't run without it.
******** I am NOT using Hyper-V in Windows, since Mike's update. I haven't test to remove this option yet, but doesn't cause any issues.
```
options kvm_amd nested=1
```
So, here is my XML file:
```
<domain type="kvm">
<name>win11-games</name>
<uuid>1e666676-xxxx...</uuid>
<metadata>
<libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
<libosinfo:os id="http://microsoft.com/win/11"/>
</libosinfo:libosinfo>
</metadata>
<memory unit="KiB">33554432</memory>
<currentMemory unit="KiB">33554432</currentMemory>
<memoryBacking>
<hugepages/>
<nosharepages/>
<locked/>
<access mode="private"/>
<allocation mode="immediate"/>
<discard/>
</memoryBacking>
<vcpu placement="static">16</vcpu>
<iothreads>2</iothreads>
<cputune>
<vcpupin vcpu="0" cpuset="0"/>
<vcpupin vcpu="1" cpuset="16"/>
<vcpupin vcpu="2" cpuset="1"/>
<vcpupin vcpu="3" cpuset="17"/>
<vcpupin vcpu="4" cpuset="2"/>
<vcpupin vcpu="5" cpuset="18"/>
<vcpupin vcpu="6" cpuset="3"/>
<vcpupin vcpu="7" cpuset="19"/>
<vcpupin vcpu="8" cpuset="4"/>
<vcpupin vcpu="9" cpuset="20"/>
<vcpupin vcpu="10" cpuset="5"/>
<vcpupin vcpu="11" cpuset="21"/>
<vcpupin vcpu="12" cpuset="6"/>
<vcpupin vcpu="13" cpuset="22"/>
<vcpupin vcpu="14" cpuset="7"/>
<vcpupin vcpu="15" cpuset="23"/>
<emulatorpin cpuset="15,31"/>
<iothreadpin iothread="1" cpuset="13,29"/>
<iothreadpin iothread="2" cpuset="14,30"/>
<emulatorsched scheduler="fifo" priority="10"/>
<vcpusched vcpus="0" scheduler="rr" priority="1"/>
<vcpusched vcpus="1" scheduler="rr" priority="1"/>
<vcpusched vcpus="2" scheduler="rr" priority="1"/>
<vcpusched vcpus="3" scheduler="rr" priority="1"/>
<vcpusched vcpus="4" scheduler="rr" priority="1"/>
<vcpusched vcpus="5" scheduler="rr" priority="1"/>
<vcpusched vcpus="6" scheduler="rr" priority="1"/>
<vcpusched vcpus="7" scheduler="rr" priority="1"/>
<vcpusched vcpus="8" scheduler="rr" priority="1"/>
<vcpusched vcpus="9" scheduler="rr" priority="1"/>
<vcpusched vcpus="10" scheduler="rr" priority="1"/>
<vcpusched vcpus="11" scheduler="rr" priority="1"/>
<vcpusched vcpus="12" scheduler="rr" priority="1"/>
<vcpusched vcpus="13" scheduler="rr" priority="1"/>
<vcpusched vcpus="14" scheduler="rr" priority="1"/>
<vcpusched vcpus="15" scheduler="rr" priority="1"/>
</cputune>
<sysinfo type="smbios">
<bios>
<entry name="vendor">American Megatrends International, LLC.</entry>
<entry name="version">F21</entry>
<entry name="date">10/01/2024</entry>
</bios>
<system>
<entry name="manufacturer">Gigabyte Technology Co., Ltd.</entry>
<entry name="product">X670E AORUS MASTER</entry>
<entry name="version">1.0</entry>
<entry name="serial">12345678</entry>
<entry name="uuid">1e666676-xxxx...</entry>
<entry name="sku">GBX670EAM</entry>
<entry name="family">X670E MB</entry>
</system>
</sysinfo>
<os firmware="efi">
<type arch="x86_64" machine="pc-q35-8.1">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/win11-games_VARS.fd</nvram>
<smbios mode="sysinfo"/>
</os>
<features>
<acpi/>
<apic/>
<hyperv mode="passthrough">
<relaxed state="on"/>
<vapic state="on"/>
<spinlocks state="on" retries="8191"/>
<vpindex state="on"/>
<synic state="on"/>
<stimer state="on">
<direct state="on"/>
</stimer>
<reset state="on"/>
<vendor_id state="on" value="OriginalAMD"/>
<frequencies state="on"/>
<reenlightenment state="off"/>
<tlbflush state="on"/>
<ipi state="on"/>
<evmcs state="off"/>
<avic state="on"/>
</hyperv>
<kvm>
<hidden state="on"/>
</kvm>
<vmport state="off"/>
<smm state="on"/>
<ioapic driver="kvm"/>
</features>
<cpu mode="host-passthrough" check="none" migratable="off">
<topology sockets="1" dies="1" cores="8" threads="2"/>
<cache mode="passthrough"/>
<feature policy="require" name="hypervisor"/>
<feature policy="disable" name="aes"/>
<feature policy="require" name="topoext"/>
<feature policy="disable" name="x2apic"/>
<feature policy="disable" name="svm"/>
<feature policy="require" name="amd-stibp"/>
<feature policy="require" name="ibpb"/>
<feature policy="require" name="stibp"/>
<feature policy="require" name="virt-ssbd"/>
<feature policy="require" name="amd-ssbd"/>
<feature policy="require" name="pdpe1gb"/>
<feature policy="require" name="tsc-deadline"/>
<feature policy="require" name="tsc_adjust"/>
<feature policy="require" name="arch-capabilities"/>
<feature policy="require" name="rdctl-no"/>
<feature policy="require" name="skip-l1dfl-vmentry"/>
<feature policy="require" name="mds-no"/>
<feature policy="require" name="pschange-mc-no"/>
<feature policy="require" name="invtsc"/>
<feature policy="require" name="cmp_legacy"/>
<feature policy="require" name="xsaves"/>
<feature policy="require" name="perfctr_core"/>
<feature policy="require" name="clzero"/>
<feature policy="require" name="xsaveerptr"/>
</cpu>
<clock offset="timezone" timezone="Europe/Dublin">
<timer name="rtc" present="no" tickpolicy="catchup"/>
<timer name="pit" tickpolicy="discard"/>
<timer name="hpet" present="no"/>
<timer name="kvmclock" present="no"/>
<timer name="hypervclock" present="yes"/>
<timer name="tsc" present="yes" mode="native"/>
</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>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type="block" device="disk">
<driver name="qemu" type="raw" cache="none" io="native"/>
<source dev="/dev/sdb"/>
<target dev="sdb" bus="sata"/>
<boot order="1"/>
<address type="drive" controller="0" bus="0" target="0" unit="1"/>
</disk>
<disk type="file" device="cdrom">
<driver name="qemu" type="raw"/>
<source file="/home/USERNAME/Downloads/Linux/virtio-win-0.1.229.iso"/>
<target dev="sdc" bus="sata"/>
<readonly/>
<address type="drive" controller="0" bus="0" target="0" unit="2"/>
</disk>
<controller type="usb" index="0" model="qemu-xhci" ports="15">
<address type="pci" domain="0x0000" bus="0x02" slot="0x00" function="0x0"/>
</controller>
<controller type="pci" index="0" model="pcie-root"/>
<controller type="pci" index="1" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="1" port="0x10"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0" multifunction="on"/>
</controller>
<controller type="pci" index="2" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="2" port="0x11"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x1"/>
</controller>
<controller type="pci" index="3" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="3" port="0x12"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x2"/>
</controller>
<controller type="pci" index="4" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="4" port="0x13"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x3"/>
</controller>
<controller type="pci" index="5" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="5" port="0x14"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x4"/>
</controller>
<controller type="pci" index="6" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="6" port="0x15"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x5"/>
</controller>
<controller type="pci" index="7" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="7" port="0x16"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x6"/>
</controller>
<controller type="pci" index="8" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="8" port="0x17"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x7"/>
</controller>
<controller type="pci" index="9" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="9" port="0x18"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x0" multifunction="on"/>
</controller>
<controller type="pci" index="10" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="10" port="0x19"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x1"/>
</controller>
<controller type="pci" index="11" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="11" port="0x1a"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x2"/>
</controller>
<controller type="pci" index="12" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="12" port="0x1b"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x3"/>
</controller>
<controller type="pci" index="13" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="13" port="0x1c"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x4"/>
</controller>
<controller type="pci" index="14" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="14" port="0x1d"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x03" function="0x5"/>
</controller>
<controller type="sata" index="0">
<address type="pci" domain="0x0000" bus="0x00" slot="0x1f" function="0x2"/>
</controller>
<controller type="virtio-serial" index="0">
<address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/>
</controller>
<interface type="direct">
<mac address="52:54:00:20:e2:43"/>
<source dev="enp13s0" mode="bridge"/>
<model type="e1000e"/>
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</interface>
<serial type="pty">
<target type="isa-serial" port="0">
<model name="isa-serial"/>
</target>
</serial>
<console type="pty">
<target type="serial" port="0"/>
</console>
<channel type="spicevmc">
<target type="virtio" name="com.redhat.spice.0"/>
<address type="virtio-serial" controller="0" bus="0" port="1"/>
</channel>
<input type="mouse" bus="ps2"/>
<input type="keyboard" bus="ps2"/>
<graphics type="spice" autoport="yes">
<listen type="address"/>
<image compression="off"/>
</graphics>
<sound model="ich9">
<address type="pci" domain="0x0000" bus="0x00" slot="0x1b" function="0x0"/>
</sound>
<audio id="1" type="spice"/>
<video>
<model type="virtio" heads="1" primary="yes">
<acceleration accel3d="no"/>
</model>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
</video>
<hostdev mode="subsystem" type="usb" managed="yes">
<source>
<vendor id="0x1e7d"/>
<product id="0x2cb6"/>
</source>
<address type="usb" bus="0" port="3"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x02" slot="0x00" function="0x0"/>
</source>
<address type="pci" domain="0x0000" bus="0x04" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</source>
<address type="pci" domain="0x0000" bus="0x05" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x01" slot="0x00" function="0x1"/>
</source>
<address type="pci" domain="0x0000" bus="0x06" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="usb" managed="yes">
<source>
<vendor id="0x187c"/>
<product id="0x100e"/>
</source>
<address type="usb" bus="0" port="4"/>
</hostdev>
<redirdev bus="usb" type="spicevmc">
<address type="usb" bus="0" port="1"/>
</redirdev>
<redirdev bus="usb" type="spicevmc">
<address type="usb" bus="0" port="2"/>
</redirdev>
<watchdog model="itco" action="reset"/>
<memballoon model="none"/>
</devices>
</domain>
```
After latest update, below section is irrelevant. Works for all games without changes, and without installing/running Hyper-V in Windows.-Below settings, do NOT allow Hyper-V to function correct and report the system as "Virtual Machine", therefore some anti-cheats block you from playing, ex "PUBG-BattlEye".
```<feature policy="disable" name="svm"/>
<feature policy="require" name="hypervisor"/>
```
If you change them to this
```<feature policy="require" name="svm"/>
<feature policy="disable" name="hypervisor"/>
```
it will allow Hyper-V to run, and PUBG plays without any issues, but you might experience slow framerate in certain games and/or benchmarks. With both features to "require" and Hyper-V installed, it won't boot (at least my system doesn't).
So, what I am doing is changing these two settings in order to play PUBG and any other games that won't work in VM, and if I experience any frame-drops, or slow performance in other games, I just shut down the VM, revert these two and boot my VM back up.
Hope this helps!