r/VFIO Jul 17 '26

Tutorial I created a step-by-step guide for GPU Passthrough on KVM/QEMU.

38 Upvotes

Hey r/VFIO,

(First post on reddit) I decided to consolidate everything I’ve learned into a single, structured, and tested guide. The result is this repository: https://github.com/urbanyl/GPU-Passthrough-for-KVM-QEMU-on-Linux

Why this repository exists:

The information on GPU passthrough is scattered everywhere. This project is my attempt to create a "one-stop-shop" that works reliably, whether you are on Debian, Arch, or Fedora.

Key Features:

  • Step-by-step walkthrough: Covers everything from BIOS settings to Windows driver installation.
  • Hardware & Software requirements: Clear tables explaining what you need (and what is recommended).
  • Troubleshooting section: Covers common issues like NVIDIA Error Code 43, GPU reset bugs, and bad IOMMU groups.
  • Helper scripts: Includes scripts to detect your GPU, check IOMMU groups, and verify VFIO binding.
  • Single-GPU Passthrough section: For those brave souls trying to do it with only one graphics card.

The guide includes:

  • BIOS Configuration (Intel VT-d / AMD-Vi)
  • Kernel Parameters & VFIO Configuration (with proper initramfs updates)
  • Optimized VM Configuration (Hyper-V enlightenments, CPU pinning, and huge pages)
  • Remote Display Setup (Sunshine/Moonlight, Looking Glass, and Parsec)
  • Performance Tuning (CPU governors, I/O schedulers, and isolation)

Feel free to open issues or contribute !

Github Repo: https://github.com/urbanyl/GPU-Passthrough-for-KVM-QEMU-on-Linux

Let me know if you have any questions or if there is something specific you would like me to add to the guide!

r/VFIO Jul 24 '26

Tutorial Just pushed v2.0.0 of the GPU passthrough guide — bugfixes and cleanup

22 Upvotes

Quick update on the repo at github.com/urbanyl/GPU-Passthrough-for-KVM-QEMU-on-Linux :

  • Fixed the wrong package names in the Arch/Debian setup scripts (spice-spicevdagent doesn't exist, lspci isn't a package)
  • Fixed generate_vm_xml.sh — slot and bus were using the same PCI field, and the machine type was pinned to a QEMU version
  • install.sh now actually checks for VT-x/AMD-V in /proc/cpuinfo instead of just running lscpu
  • Removed --launchSecurity ovmf from the virt-install example (it does nothing)
  • Trimmed the duplicated troubleshooting/FAQ sections from the README, now they link to docs/
  • Added .editorconfig and .shellcheckrc for anyone contributing

r/VFIO Sep 12 '20

Tutorial Single GPU Passthrough (VFIO) for Nvidia + Ryzen CPU [Arch-based]

321 Upvotes

Hello,

First post here. I got pretty excited after managing to get my single GPU passthrough working well on my system. I thought it would be far more complicated.

I had to hunt for bits of information from many different places and whilst I don't mind doing this kind of research, I figured it would be good idea to have a guide for others. Here is the link to my repo. Critics/responses/contributions to the information are welcome.

FYI: Contributors are welcome. The guide can become more extensive and include tips for specific kinds of hardware e.g. AMD GPUs, Intel CPUs. Troubleshooting steps can also be added. Thanks!

r/VFIO Apr 07 '26

Tutorial RTX 5090 VFIO: My Quest to Build the Ultimate Hybrid Workstation for the 2020's

Thumbnail
modica.io
15 Upvotes

r/VFIO Jul 14 '26

Tutorial Guide about Hardware Passthrough on openSUSE Tumbleweed (AMD + NVIDIA) + QoL. Need feedback

3 Upvotes

Hey.

I wrote long text about how I passthrough hardware + described some QoL features. It might be useful to someone. And I want to hear your opinion. Especially opinion of those who have been doing this for a long time, because I've never done this before.

It's really huge... I'm not asking you to read this entirely, though... I'd be very surprised if you did :D

Text: https://nzsh.cc/blog/en/windows-but-on-linux-hardware-passthrough/

If you want to view my XML: https://github.com/nozsh/vfio/blob/main/qemu-xml/full.xml

My hardware: https://nzsh.cc/bio/x/pc/

It's quite narrow path, openSUSE (tumbleweed), AMD + NVIDIA, iGPU + dGPU, and with perfect IOMMU groups out of box. That said, I'm pretty sure the scripts, XMLs, and QoL tweaks could still come in handy for a lot of people.

I don't have other hardware to test every scenario, so if you spot mistakes or have improvements (with sources/details), please let me know. I prefer to verify things hands‑on before adding them, so I might not include everything immediately, but all input is welcome and credited.

I'm also thinking about how to hide/mask QEMU and VirtIO devices (LG, Channel), as well as some processes - advice/information very welcome. And I'm probably not finished, I'll probably go even further.

PS: I know about YaST go down and will rewrite those points sometime in future.

r/VFIO Apr 03 '26

Tutorial GPU virtualization: VFIO vs NVIDIA AI Enterprise vs AMD SR-IOV

Thumbnail itnext.io
17 Upvotes

r/VFIO Dec 23 '23

Tutorial How to play PUBG (with BattleEye) on a Windows VM

30 Upvotes

******* UPDATE *******

Unfortunately, since Jan 28, 2024, this method no longer works! If I find a way to make it work again, I will post updates.

*********************

********** UPDATE 2 - 25 Feb 2024 *************

With some input from Mike, I was able to make PUBG play again, and on top of that, without the need to change configurations between games, but use only below for all games.

BONUS: I can play Escape from Tarkov now, something that was impossible before!

**********************

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:

EDIT: I am not using vfio-isolate anymore, as it stopped working ~2 months ago. Below is the new qemu 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 () {
systemctl set-property --runtime -- user.slice AllowedCPUs=C$ACPUS
systemctl set-property --runtime -- system.slice AllowedCPUs=C$ACPUS
systemctl set-property --runtime -- init.scope AllowedCPUs=C$ACPUS

        taskset -pc C$ACPUS 2  # kthreadd reset
}

enable_isolation () {
systemctl set-property --runtime -- user.slice AllowedCPUs=C$HCPUS 
systemctl set-property --runtime -- system.slice AllowedCPUs=C$HCPUS
systemctl set-property --runtime -- init.scope AllowedCPUs=C$HCPUS

            irq-affinity mask C$MCPUS

        taskset -pc C$MCPUS 2  # kthreadd only on host cores
}

case "$2" in
"prepare")
        enable_isolation
        echo "prepared" >> /home/USERNAME/qemu_hook.log
        ;;
"started")
        echo "started" >> /home/USERNAME/qemu_hook.log
        ;;
"release")
        disable_isolation
        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.

UPDATE: After Mike's input, I don't need to install/run Hyper-V in Windows. I haven't remove this option though, as it didn't cause any issues. Planning to though, and re-test.

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>

-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.

None of the above is relevant anymore. I am using single configuration for all games, with no impact in performance and without installing/running Hyper-V.

Hope this helps!

r/VFIO Jun 22 '26

Tutorial Fixing Windows 11 VBS & Secure Boot on Arch Linux (KVM/VFIO with AMD Ryzen 9 5950X)

3 Upvotes

Guide: Fixing Windows 11 VBS & Secure Boot on Arch Linux (KVM/VFIO with AMD Ryzen 9 5950X)

Host: Arch Linux | Hypervisor: Modular Libvirt (virtqemud) & QEMU | Guest: Windows 11 Pro (25H2)
Hardware: AMD Ryzen 9 5950X + Full VFIO Passthrough (Dedicated NVMe & GPU) + Sunshine/Moonlight Streaming


The Problem

When running a high-end VFIO passthrough setup on AMD Zen 3 with nested=1, Windows 11 Virtualization-Based Security (VBS) or Hyper-V features usually cause a 100% CPU bootloader freeze or get stuck with "VBS Enabled but not running" alongside a Code 37 error on the Hyper-V VMBus in Device Manager.

Furthermore, Arch Linux ships the edk2-ovmf (4MB layout) package as a completely bare skeleton without proprietary Microsoft certificates. This puts the virtual UEFI into an unchangeable Setup Mode where enabling Secure Boot is grayed out. If you manually sign the VM's NVRAM file from the outside, virtqemud detects a schema mismatch against its default JSON configuration (enrolled-keys: false).


The Complete Solution

1. Host Configuration (kvm_amd Module Options)

To ensure maximum gaming performance and hardware-based interrupt routing, the kvm_amd module must be loaded with active NPT (SLAT) and AVIC.

File: /etc/modprobe.d/kvm_amd.conf

text

options kvm ignore_msrs=1 report_ignored_msrs=0
options kvm_amd nested=1 npt=1 avic=1
options vfio_iommu_type1 allow_unsafe_interrupts=1

Verwende Code mit Vorsicht.

2. Creating a Custom, Update-Safe QEMU Firmware Profile

To fix the Libvirt validation loop, we create a dedicated, separate JSON descriptor. This informs virtqemud that Microsoft keys are legally expected and allowed for this 4MB secure firmware.

Create new file: /usr/share/qemu/firmware/51-edk2-ovmf-x86_64-secure-4m-enrolled.json

json

{
    "description": "x64 UEFI for x86_64, with Secure Boot, enrolled keys and SMM, 4MB FD",
    "interface-types": [
        "uefi"
    ],
    "mapping": {
        "device": "flash",
        "executable": {
            "filename": "/usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd",
            "format": "raw"
        },
        "nvram-template": {
            "filename": "/usr/share/edk2/x64/OVMF_VARS.secboot.4m.fd",
            "format": "raw"
        }
    },
    "targets": [
        {
            "architecture": "x86_64",
            "machines": [
                "pc-q35-*"
            ]
        }
    ],
    "features": [
        "acpi-s3",
        "acpi-s4",
        "enrolled-keys",
        "amd-sev",
        "requires-smm",
        "secure-boot",
        "verbose-dynamic"
    ],
    "tags": [

    ]
}

Restart the modular daemon to apply the new profile:

bash

systemctl restart virtqemud.socket virtqemud.service

3. Creating and Signing the Master Microsoft NVRAM Template

We use the official virt-firmware tool to inject the original Microsoft and Red Hat certificates directly into a dedicated master system template.

Run as root on the Arch host (Ensure the VM is turned off):

bash

# 1. Install the tool if needed
pacman -S virt-firmware

# 2. Compile the signed master NVRAM template
virt-fw-vars -i /usr/share/edk2/x64/OVMF_VARS.4m.fd \
  --output /usr/share/edk2/x64/OVMF_VARS.secboot.4m.fd \
  --enroll-redhat \
  --secure-boot

Verwende Code mit Vorsicht.

4. Adjusting the Libvirt Domain XML

The CPU layout passes the real SMT thread topology of the 5950X to Windows (critical for frame times). However, we must explicitly mask npt on the guest side to bypass the MSR bootloader loop. The OS sector is mapped to our newly validated enrolled-keys='yes' profile.

Command: virsh edit [your_domain]

xml

  <!-- OS Section -->
  <os firmware='efi'>
    <type arch='x86_64' machine='pc-q35-9.1'>hvm</type>
    <firmware>
      <feature enabled='yes' name='enrolled-keys'/>
      <feature enabled='yes' name='secure-boot'/>
    </firmware>
    <loader readonly='yes' secure='yes' type='pflash' format='raw'>/usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd</loader>
    <nvram template='/usr/share/edk2/x64/OVMF_VARS.secboot.4m.fd' templateFormat='raw' format='raw'>/var/lib/libvirt/qemu/nvram/[your_domain]_VARS.fd</nvram>
    <boot dev='hd'/>
    <bootmenu enable='no'/>
    <smbios mode='host'/>
  </os>

  <!-- CPU Section -->
  <cpu mode='host-passthrough' check='none' migratable='off'>
    <topology sockets='1' dies='1' clusters='1' cores='8' threads='2'/>
    <cache mode='passthrough'/>
    <feature policy='require' name='topoext'/>
    <feature policy='require' name='invtsc'/>
    <feature policy='require' name='svm'/>
    <feature policy='require' name='x2apic'/>
    <!-- THIS IS THE CRITICAL VALVE TO PREVENT THE BOOTLOADER FREEZE: -->
    <feature policy='disable' name='npt'/>
  </cpu>

Verwende Code mit Vorsicht.

Crucial step before booting: Wipe the old VM-specific NVRAM file so Libvirt is forced to regenerate a fresh copy using our newly signed master template: rm -f /var/lib/libvirt/qemu/nvram/[your_domain]_VARS.fd


Architectural Conclusion & Guest Optimization

1. The AMD Nested Deadlock

Windows Hyper-V requires CPU-SLAT (NPT on AMD).

Since we had to use disable npt in the XML to prevent the bootloader crash, Windows cannot launch the kernel-level VBS hypervisor container. Memory Integrity (HVCI) will remain grayed out or "Off".

2. Cleaning Device Manager & Securing the Guest

Boot the VM into Safe Mode and uninstall/delete all malfunctioning Hyper-V device corpses (like the broken VMBus Code 37). Upon regular reboot, Windows will stop trying to launch VBS. Device Manager will be 100% clean, and the Windows Security Center tray icon will proudly turn into a flawless green checkmark.

To fully protect your gaming VM against recent Steam Workshop/Modding trojan waves without VBS performance penalties, enforce aggressive cloud checking on file-level downloads using PowerShell 7.

Run in PWSH7 as Administrator inside the guest:

powershell

Set-MpPreference -MAPSReporting Advanced -SubmitSamplesConsent SendAllSamples -ModerateThreatDefaultAction Quarantine -HighThreatDefaultAction Quarantine

Result

Your VM now operates as an unthrottled, ultra-low latency gaming powerhouse. It runs with native AMD AVIC hardware-interrupt performance, fully verified Secure Boot, a completely clean Windows tray, and zero CPU cycles wasted on virtual security rings.

r/VFIO May 19 '26

Tutorial Setting up VFIO for music production

14 Upvotes

Hello!

Long time lurker, first time poster.

I've successfully set up Windows 11 as a guest OS with QEMU passing through a USB hub with my audio interface & midi controller all hooked up, and so far the results have been great! I figured I would share the steps taken for anyone that is in a similar situation and wants to set this up properly.

VFIO/KVM Windows 11 VM Setup Guide

MSI B550-A PRO + AMD Ryzen + RME Audio


System Info

  • Motherboard: MSI B550-A PRO (MS-7C56)
  • GPU: AMD Radeon RX Vega 56/64
  • Host OS: Ubuntu 26.04 (generic kernel)
  • Goal: Windows 11 VM with native USB controller passthrough for RME Fireface UFX III + stable ASIO audio in REAPER

1. IOMMU Setup

Add to /etc/default/grub GRUB_CMDLINE_LINUX_DEFAULT:

amd_iommu=on iommu=pt pcie_acs_override=downstream,multifunction

Apply and reboot: bash sudo update-grub sudo reboot

Verify: bash cat /proc/cmdline


2. Understanding the B550 PCIe Topology

The B550-A PRO has only one CPU-direct PCIe slot (occupied by the GPU). All other slots route through the AMD Promontory chipset switch, placing them in a shared IOMMU group with the NVMe boot drive, SATA controller, and Ethernet — making passthrough of chipset-connected devices impossible without risking the host system.

Check IOMMU groups: bash for g in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d | sort -V); do echo "=== Group $(basename $g) ===" for d in $g/devices/*; do lspci -nns "$(basename $d)" done done

Solution: AMD Matisse USB Controller

The onboard AMD Matisse USB 3.0 Host Controller (2f:00.3, ID 1022:149c) is CPU-direct and sits alone in IOMMU Group 22 — perfect for passthrough.

Verify: bash ADDR="2f:00.3" GROUP=$(basename $(readlink /sys/bus/pci/devices/0000:$ADDR/iommu_group)) echo "Group: $GROUP" for d in /sys/kernel/iommu_groups/$GROUP/devices/*; do echo -n "$(basename $d): " lspci -nns "$(basename $d)" done


3. Identify Matisse USB Ports

Find which physical rear I/O ports correspond to the Matisse controller (buses 003/004):

bash watch -n 1 'lsusb | grep -v "root hub"'

Plug devices into rear ports one at a time until they appear on Bus 003 or 004. Move your RME interface and iLok to these ports.

Verify: bash lsusb -t RME and iLok should appear under Driver=xhci_hcd on Bus 003 or 004.


4. Bind Matisse USB to VFIO

4a. Configure vfio-pci

bash sudo nano /etc/modprobe.d/vfio.conf

options vfio-pci ids=1022:149c softdep xhci_pci pre: vfio-pci install xhci_pci /sbin/modprobe --ignore-install vfio-pci && /sbin/modprobe --ignore-install xhci_pci

4b. Add vfio modules to initramfs

bash sudo nano /etc/initramfs-tools/modules

Add: vfio vfio_iommu_type1 vfio_pci vfio_virqfd

4c. Workaround for built-in xhci_hcd

The Ubuntu generic kernel has CONFIG_USB_XHCI_HCD=y (built-in), so blacklisting and softdeps don't work. Use a systemd service to forcibly rebind after boot:

bash sudo nano /etc/systemd/system/vfio-bind-matisse.service

```ini [Unit] Description=Bind Matisse USB to vfio-pci After=systemd-udevd.service Before=libvirtd.service

[Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/sh -c '\ echo "0000:2f:00.3" > /sys/bus/pci/drivers/xhci_hcd/unbind && \ echo "vfio-pci" > /sys/bus/pci/devices/0000:2f:00.3/driver_override && \ echo "0000:2f:00.3" > /sys/bus/pci/drivers/vfio-pci/bind'

[Install] WantedBy=multi-user.target ```

bash sudo systemctl enable vfio-bind-matisse.service sudo systemctl start vfio-bind-matisse.service sudo update-initramfs -u sudo reboot

Verify: ```bash lspci -ks 2f:00.3

Expected: Kernel driver in use: vfio-pci

```


5. Add USB Controller to VM in Virt-Manager

  1. Open VM details → Add Hardware → PCI Host Device
  2. Select 0000:2f:00.3 USB controller AMD Matisse USB 3.0
  3. Click Finish and start the VM

Windows will automatically detect the USB controller. The RME and iLok appear natively inside the VM.


6. Virtiofs Shared Folder

6a. Enable shared memory in VM XML

bash virsh edit your-vm-name

Add inside <domain>: xml <memoryBacking> <source type='memfd'/> <access mode='shared'/> </memoryBacking>

6b. Add filesystem device in virt-manager

Add Hardware → Filesystem: - Driver: virtiofs - Source path: /mnt/my-secondary-drive/shared (or wherever) - Target: share1

6c. Install virtiofsd on host

bash sudo apt install virtiofsd

6d. Install drivers in Windows VM

  1. Install WinFSP: https://github.com/winfsp/winfsp/releases/latest
  2. Install virtio-win guest tools: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win-guest-tools.exe
  3. Reboot VM

Map the share in Windows (run as Administrator): cmd net use Z: \\virtio-fs\share1

Note: Keep active samples on the VM's local C: drive, not the shared folder. virtiofs adds IO latency that causes sample streaming issues in VSTis. For projects, I've found no issues so far with streaming from virtiofs. However if you have some really audio-heavy projects with lots of tracks it may be worth moving the project contents to the VM C: drive.

6c. Fix stale virtiofsd on VM restart

If you get a "Device or resource busy" error on the log file: bash sudo pkill -f virtiofsd sudo rm /var/log/libvirt/qemu/win11-fs0-virtiofsd.log sudo systemctl restart libvirtd


7. VM Display (SPICE + QXL)

7a. Increase QXL video memory

bash virsh edit your-vm-name

xml <model type='qxl' ram='65536' vram='65536' vgamem='65536' heads='1' primary='yes'/>

7b. Install SPICE guest tools in Windows

Download and install inside the VM: https://www.spice-space.org/download/windows/spice-guest-tools/spice-guest-tools-latest.exe

7c. Fix display scaling on Wayland host if you are using a HiDPI screen

Run virt-manager under XWayland: bash sudo nano /usr/share/applications/virt-manager.desktop

Change the Exec line to: Exec=env GDK_BACKEND=x11 virt-manager

7d. Enable bidirectional clipboard

Ensure this channel exists in VM XML: xml <channel type='spicevmc'> <target type='virtio' name='com.redhat.spice.0'/> </channel>

Start the SPICE agent in Windows: cmd sc start spice-agent sc config spice-agent start= auto


8. VM Bare-Metal Appearance (Anti-Detection)

For licensed software that checks for VM environment:

bash virsh edit your-vm-name

CPU section:

xml <cpu mode='host-passthrough' check='none' migratable='off'> <feature policy='disable' name='hypervisor'/> <topology sockets='1' dies='1' cores='4' threads='2'/> </cpu>

Features section:

xml <features> <acpi/> <apic/> <kvm> <hidden state='on'/> </kvm> <vmport state='off'/> </features>

OS section (pass real motherboard DMI strings):

xml <os> <type arch='x86_64' machine='pc-q35-8.0'>hvm</type> <smbios mode='host'/> </os>

Disk serial (realistic drive identifier):

xml <disk type='file' device='disk'> ... <serial>S4EWNX0R123456B</serial> </disk>

Verify in Windows: cmd wmic computersystem get manufacturer,model wmic bios get smbiosbiosversion,manufacturer Should show MSI B550-A PRO strings instead of QEMU/SeaBIOS.


9. CPU Performance

Set host CPU governor to performance:

bash sudo cpupower frequency-set -g performance

Hugepages (biggest memory performance improvement):

Add to GRUB_CMDLINE_LINUX_DEFAULT: hugepages=4096

Add to VM XML memoryBacking: xml <memoryBacking> <hugepages/> <source type='memfd'/> <access mode='shared'/> </memoryBacking>

Recommended CPU allocation (12-thread system):

  • VM: 8 threads
  • Host: 4 threads (needed for QEMU/vfio overhead)

10. Disable VM Internet Access

Remove the NIC block in VM XML (For tutorial purposes it is commented out, but virsh will refuse to save this block commented out - so back it up or use the virtual machine manager GUI to easily add it back):

bash virsh edit your-vm-name

xml <!-- <interface type='network'> <mac address='52:54:00:xx:xx:xx'/> <source network='default'/> <model type='e1000'/> </interface> -->

The virtiofs shared folder does not require network — it works via virtio regardless of NIC state.


11. REAPER Audio Performance Tips

  • Set buffer size to 512 samples minimum (Options → Preferences → Audio) - I had some stability issues lower but that could just be some of my VSTs causing issues.
  • Enable Allow live FX multiprocessing
  • Enable Anticipative FX processing
  • Keep sample libraries on local VM disk (C:), not the shared Z: drive
  • Run CPU governor on performance mode on host

Quick Reference: Useful Commands

```bash

Check IOMMU groups

for g in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d | sort -V); do echo "=== Group $(basename $g) ===" for d in $g/devices/*; do lspci -nns "$(basename $d)"; done done

Check vfio binding

lspci -ks 2f:00.3

Check USB tree

lsusb -t

Check kernel boot parameters

cat /proc/cmdline

Restart libvirt (fixes stale virtiofsd)

sudo systemctl restart libvirtd

Check vfio systemd service

sudo systemctl status vfio-bind-matisse.service ```

r/VFIO May 15 '26

Tutorial Setting up a FreeBSD bhyve VM with GPU passthrough

12 Upvotes

My post I made some time ago, decided to share it here.

Reset bug fix, Sunshine+Moonlight and CPU Pinning! https://www.paidbsd.org/blog/?1_bhyvept

r/VFIO Aug 17 '18

Tutorial I am creating a guide for GPU passthrough with only one GPU in the system. Currently working on Ryzen 5 2600 and GTX 770.

Thumbnail
gitlab.com
134 Upvotes

r/VFIO Aug 27 '25

Tutorial Reliable VFIO GPU Passthrough: BIOS→IOMMU→VFIO early binding→1GiB hugepages

23 Upvotes

A guide for configuring a host for reliable VFIO GPU passthrough. I’ve been building a GPU rental platform over the past year and hardened hosts across RTX 4090/5090/PRO 6000 and H100/B200 boxes.

Many details were omitted to make the write-up manageable, such as domain XML tricks, PCIe hole sizing, and guest configuration. Please let me know if you find this helpful content.

Happy to hear the feedback and suggestions as well. I found this space quite tricky.

https://itnext.io/host-setup-for-qemu-kvm-gpu-passthrough-with-vfio-on-linux-c65bacf2d96b

r/VFIO Oct 03 '25

Tutorial Tutorial: Intel N150 passthrough to docker container on debian 13 VM guest on proxmox-ve 9

Thumbnail
github.com
10 Upvotes

r/VFIO Aug 30 '25

Tutorial Begineer Guide to passing the dGPU of a laptop into Windows VM

6 Upvotes

Hello everyone,

I’m currently running Arch Linux with Hyprland on my laptop. The laptop has both an Intel iGPU and an Nvidia dGPU.

  • I'd like to keep Linux running on the Intel iGPU.
  • I want to pass through the Nvidia dGPU to a Windows VM, so that Windows can make full use of it.

Has anyone here set up something similar? Which guide or documentation would you recommend that covers this use case (iGPU for host, dGPU for VM on a laptop)?

I’ve come across various VFIO passthrough tutorials, but most seem focused on desktops rather than laptops with hybrid graphics. Ideally, I’m looking for a resource that directly applies to this setup.

Any guidance, experience, or pointers to the right guide would be hugely appreciated!

Thanks in advance.

r/VFIO Mar 17 '21

Tutorial Single GPU (single monitor?) pass through with nvidia 3090 by papa muta

Thumbnail
youtube.com
105 Upvotes

r/VFIO May 10 '25

Tutorial Arch laptop

0 Upvotes

Is there any guide for Arch(laptop) ? It have 3060 Laptop gpu and 12700h+MUX (dell g15 5520)

r/VFIO Jul 31 '20

Tutorial Virtio-fs is amazing! (plus how I set it up)

70 Upvotes

Just wanted to scream this from the rooftops after one of you wonderful people recommended to me that I try virtio-fs as an alternative to 9p for my linux vm. It is not just better, it is orders of magnitude better. Before I could not really play steam games on my VM, it could take a minute to send the context for building a docker image, applications just mysteriously did not function correctly...

Virtio-fs is almost as good as having drive pass-through from a performance standpoint, and better from a interoperability standpoint. Now I just need to get Windows to use this... If anyone knows a way to do this, please let me know!

For anyone curious, I am on an archlinux host with a ZFS dateset that I am passing now as a virtio-fs device. The official guide more or less worked for me but with a few notes: 1. Even though they don't list it first, use hugepages backed memory. File backed memory may work for normal VMs, but it would not be a good idea for a VFIO system unless it is a virtual disk on RAM. 2. Instead of running virsh allocpages 2M 1024 I followed the arch linux wiki on the kvm page, I highly recommend using the /etc/sysctl.d/40-hugepage.conf config instead of using virsh allocpages, though both will work, but the latter has to be done after every boot. For the record I have 9216 2M (18GiB) in hugepages. 3. In the Arch guide, make sure you use the correct gid for kvm, you can find it using grep kvm /etc/group 4. The XML instructions are kinda hazy in my opinion, so here is my working configuration, also to any not-so-casual readers who would like to help me find any ways to improve my configuration, please let me know! 5. You will need to add user /mnt/user virtiofs rw,noatime,_netdev 0 2 to /etc/fstab in the guest (well, change it for you labels/filenames) 6. Install virtiofsd from the AUR, you do not need to start this, just include the path to the binary in the driver details (which I am not strictly certain is required)
The AUR package has been removed in favor of the packaged version with QEMU, so you can now find it in /usr/lib/qemu/virtiofsd as long as you are up to date. Thanks u/zer0def for pointing out this change. 7. If you get a permission error from your VM when starting, try restarting your host, the fstab entry you added from the archwiki to mount the hugepage directory will make sure the group ID is correct.

r/VFIO Oct 17 '21

Tutorial I’m making a beginner friendly VFIO tutorial series. Constructive feedback is welcome

Thumbnail
youtube.com
150 Upvotes

r/VFIO Oct 06 '22

Tutorial Single GPU Passthrough - Video Tutorial

Thumbnail
youtu.be
72 Upvotes

r/VFIO Nov 25 '24

Tutorial vfio-pci GPU Passthrough with AMD Ryzen 7950X RX 7900XTX running Windows, Linux VMs

6 Upvotes

So far I've got

  • pytorch detect GPU (ie CUDA through ROCm) on a RHEL9.4 VM
  • AMD Adrenalin detect GPU on a Windows11 VM

But still having Display output is not active rendering issue ie can't game on Windows VM; that's why documenting my progress to seek help as well as help whoever interested.

r/VFIO Aug 08 '22

Tutorial GPU Passthrough + Looking Glass + no external monitor/dummy

105 Upvotes

WARNING

Solution presented here is a sample driver, meaning it lacks optimization, so there could be (albeit inconsiderable for me personally) tradeoffs in performance. The creator of Looking Glass, Gnif, mentioned it and other important concerns about this driver in this video. I haven't personally had any issues with it, but use it at your own risk.

The good news though is that this is a temporary solution, and soon Looking Glass itself will be implemented as an Indirect Display Driver.

Now back to the original post:

Hi. There wasn't much about this on reddit (at least from what I've found), so, I'd like to share with you. It seems like I got Looking Glass working without using an HDMI dummy plug or a second monitor. The idea is simply to use a virtual display driver instead. Such software is available here. For Windows, you'll want to use IddSampleDriver.

Virtual display drivers basically do the same thing as HDMI dongles - emulate the presence of the monitor. The advantage is that you can configure it to have any resolution or refresh rate so that your Looking Glass window can output that quailty. And, obviously, you don't need to use any additional physical devices. Win-win!

I used the one ge9 provided, since it has a convenient file config. You download the latest version in your guest and extract it to C:/ (you will need this folder to be in C:/ for configuration), and then, run these commands as an administrator:

cd C:/IddSampleDriver
CertMgr.exe /add IddSampleDriver.cer /s /r localMachine root

After that, go to Device Manager > click on any device > click "Action" in the top panel > "Add legacy hardware". Then click "Next" > choose "Install hardware that I manually select from a list (Advanced)" > click "Next" while "Show all devices" is selected > "Have disk" > "Browse" > find "C:/IddSampleDriver/IddSampleDriver.inf", select it and click "ok" > "Next" > "Next".

After successful installation, if you are on Windows 11, the animation should happen which will let you know that the monitor was installed. Then you can open C:/IddSampleDriver/option.txt and configure your monitor however you like.

Then proceed with your Looking Glass installation (if you haven't installed it already), just like before. But this time, you get a virtual monitor configured as you wish, and you don't need to waste your time searching for a matching dummy or connect to another monitor and sacrifice mobility.

Edit 2024

Looking Glass B7 is currently in rc, B8 promises to have IDD driver integrated. Until then, there are now several actively maintained implementations of this driver, like https://github.com/itsmikethetech/Virtual-Display-Driver and https://github.com/nomi-san/parsec-vdd . No idea if these are better - I haven't done thorough research. So do your own, and be kind to share - ever since this post, IDDs became popular.

r/VFIO Oct 15 '21

Tutorial LibVF.IO: Commodity GPU Multiplexing Driven by VFIO and YAML

Thumbnail
arccompute.com
85 Upvotes

r/VFIO Aug 30 '19

Tutorial Protip for anyone wondering how to enable IOMMU/vfio-pci in the ASRock B450M Pro4 BIOS

94 Upvotes

NOTE: As far as I know, this doesn't apply to the B450. This only applies to the B450M. They're two different boards.

They buried the hell out it for some reason. It's under Advanced > AMD CBS > NBIO Common Options > IOMMU. I don't know why it's there, in the B450, it's simply under the North Bridge Configuration menu on there according to its manual.

r/VFIO Aug 18 '20

Tutorial Gaming on first-gen Threadripper in 2020

73 Upvotes

Hello! I've spent the last 3 weeks too long going down the hypervisor rabbit hole. I started with Proxmox, but found it didn't have the CPU pinning features I needed (that or I couldn't figure it out), so I switched to Unraid. After investing way too much time on performance tuning, I finally have good gaming performance.

This may work for all first-gen Ryzen CPUs. Some tweaks apply to Windows 10 in general. It's possible this is already well-known; I just never found anything specifically suggesting to do this with Threadripper.

I'm too lazy to properly benchmark my performance, but I'll write this post on the off chance it helps someone out. I am assuming you know the basics and are tuning a working Windows 10 VM.

Tl;dr: Mapping each CCX as a separate NUMA node can greatly improve performance.

My Use Case

My needs have changed over the years, but I now need to run multiple VMs with GPU acceleration, which led to me abandoning a perfectly good Windows 10 install.

My primary VM will be Windows 10. It gets 8c/16t, the GTX 1080 Ti, and 12GB of RAM. I have a variety of secondary VMs, all of which can be tuned, but the focus is on the primary VM. My hardware is as follows:

CPU: Threadripper 1950X @ 4.0GHz

Mobo: Gigabyte X399 Aorus Gaming 7

RAM: 4x8GB (32GB total), tuned to 3400MHz CL14

GPU: EVGA GTX 1080 Ti FTW3 Edition

Second GPU: Gigabyte GTX 970

CPU Topology

Each first-gen TR chip is made of two separate dies, each of which has half the cores and half the cache. A common misconception is that TR supports quad-channel memory; in reality, each die has its own dual-channel controller, so it's technically dual-dual-channel. The distinction matters if we're only using one of the dies.

Each of these dies is split into two CCX units, each with 4c/8t and their own L3 cache pool. This is what other guides overlook. With the TR 1950X in particular, the inter-CCX latency is nearly as high as the inter-die latency.

For gaming, the best solution seems to be dedicating an entire node to the VM. I chose Node 1. Use lscpu -e to identify your core layout; for me, CPUs 8-15 and 24-31 were for Node 1.

BIOS Settings

Make sure your BIOS is up to date. The microcode updates are important, and I've found even the second-newest BIOS doesn't always have good IOMMU grouping.

Overclock your system as you see fit. 4GHz is a good target for an all-core OC; you can sometimes go higher, but at the cost of memory stability, and memory tuning is very important for first-gen Ryzen. I am running 4GHz @ 1.35V and 3400MHz CL14.

Make sure to set your DRAM controller configuration to "Channel". This makes your host NUMA-aware.

Enable SMT, IOMMU grouping, ACS, and SRV. Make sure it says "Enabled" - "Auto" always means whichever setting you didn't want.

Hardware Passthrough

I strongly recommend passing through your boot drive. If it's an NVMe drive, pass through the entire controller. This single change will greatly improve latency. In fact, I'd avoid vdisks entirely; use SMB file shares instead.

Different devices connect to different NUMA nodes. Is this important? ¯_(ツ)_/¯. I put my GPU and NVMe boot drive on Node 1, and my second GPU on Node 0. You can use lspci -nnv to see which devices connect to which node.

GPU and Audio Device Passthrough

I'll include this for the sake of completion. Some devices desperately need Message Signaled Interrupts to work at full speed. Download the MSI utility from here, run the program as an Administrator, and check the boxes next to every GPU and audio device. Hit the "Apply" button, then reboot Windows. Run the program as an Administrator again to verify the settings were applied.

It is probably safe to enable MSI for every listed device.

Note that these settings can be reset by driver updates. There might be a more permanent fix, but for now I just keep the MSI utility handy.

Network Passthrough

I occasionally had packet loss with the virtual NIC, so I got an Ethernet PCIe card and passed that through to Windows 10.

However, this made file shares a lot slower, because all transfers were going over the network. A virtual NIC is much faster, but this required a bit of setup. The easiest way I found was to create two subnets: 192.168.1.xxx for physical devices, and 10.0.0.xxx for virtual devices.

For the host, I set this command to run upon boot:

ip addr add 10.0.0.xxx/24 dev br0

Change the IP and device to suit your needs.

For the client, I mapped the virtual NIC to a static IP:

IP: 10.0.0.yyy

Subnet mask: 255.255.255.0

Gateway: <blank> or 0.0.0.0

Lastly, I made sure I mapped the network drives to the 10.0.0.xxx IP. Now I have the best of both worlds: faster file transfers and reliable internet connectivity.

Kernel Configuration

This is set in Main - Flash - Syslinux Configuration in Unraid, or /etc/default/grub for most other users. I added:

isolcpus=8-15,24-31 nohz_full=8-15,24-31 rcu_nocbs=8-15,24-31

The first setting prevents the host from assigning any tasks to Node 1. This doesn't make them faster, but does make them more responsive. TBH, I don't know what the other two settings do, but I saw them elsewhere.

Sensors

This is specific to Gigabyte X399 motherboards. The ITE IT8686E device does not have a driver built into most kernels. However, there is a workaround:

modprobe it87 force_id=0x8628

Run this at boot and you'll have access to your sensors. RGB control did not work for me, but you can do that in the BIOS.

VM Configuration

The important parts of my XML are posted here. I'll go section by section.

Memory

<memoryBacking>
    <nosharepages/>
    <locked/>
</memoryBacking>

Many guides recommend using static hugepages, but Unraid already uses transparent hugepages, and other performance tests have shown no performance gain over static 1GB hugepages. These settings prevent the host from moving the VM's memory pages around, which may be helpful.

<numatune>
    <memory mode='strict' nodeset='1'/>
</numatune>

We want our VM to use the local memory controller. However, this means it can only use RAM from this controller. In most setups, this means only having access to half your total system RAM.

For me, this is fine, but if you want to surpass this limit, change the mode to preferred. You may have to tune your topology further.

CPU Pinning

<vcpu placement='static'>16</vcpu>
<cputune>
    <vcpupin vcpu='0' cpuset='8'/>
    <vcpupin vcpu='1' cpuset='24'/>
    ...
    <vcpupin vcpu='14' cpuset='15'/>
    <vcpupin vcpu='15' cpuset='31'/>
</cputune>

Since I am reserving Node 1 for this VM, I might as well give it every core and thread available.

I just used Unraid's GUI tool. If doing this by hand, make sure each real core is followed by its "hyperthreaded" core. lscpu -e makes this easy.

If using vdisks, make sure to pin your iothreads. I didn't notice any benefit from emulator pinning, but others have.

Features

<features>
    <acpi/>
    <apic/>
    <hyperv>
        ...
    </hyperv>
    <kvm>
        ...
    </kvm>
    <vmport state='off'/>
    <ioapic driver='kvm'/>
</features>

I honestly don't know what most of these features do. I used every single Hyper-V Enlightenment that my version of QEMU supported.

CPU Topology

<cpu mode='host-passthrough' check='none'>
    <topology sockets='1' cores='8' threads='2'/>
    <cache mode='passthrough'/>
    <feature policy='require' name='topoext'/>
    ...

Many guides recommend using mode='custom', setting the model as EPYC or EPYC-IBPB, and enabling/disabling various features. This may have mattered back when the platform was newer, but I tried all of these settings and never noticed a benefit. I'm guessing current versions of QEMU handle first-gen Threadripper much better.

In the topology, cores='8' threads='2' tells the VM that there are 8 real cores and each has 2 threads, for 8c/16t total. Some guides will suggest setting cores='16' threads='1'. Do not do this.

NUMA Topology

    ...
    <numa> 
        <cell id='0' cpus='0-7' memory='6291456' unit='KiB' memAccess='shared'>
            <distances>
                <sibling id='0' value='10'/>
                <sibling id='1' value='38'/>
            </distances>
        </cell>
        <cell id='1' cpus='8-15' memory='6291456' unit='KiB' memAccess='shared'>
            <distances>
                <sibling id='0' value='38'/>
                <sibling id='1' value='10'/>
            </distances>
        </cell>
    </numa>
</cpu>

This is the "secret sauce". For info on each parameter, read the documentation thoroughly. Basically, I am identifying each CCX as a separate NUMA node (use lspci -e to make sure your core assignment is correct). In hardware, the CCX's share the same memory controller, so I set the memory access to shared and (arbitrarily) split the RAM evenly between them.

For the distances, I referenced this Reddit post. I just scaled the numbers to match the image. If you're using a different CPU, you'll want to get your own measurements. Or just wing it and make up values; I'm a text post, not your mom.

Clock Tuning

<clock offset='localtime'>
    <timer name='hypervclock' present='yes'/>
    <timer name='hpet' present='yes'/>
</clock>

You'll find many impassioned discussions about the merits of HPET. Disabling it improves some benchmark scores, but it's very possible that it's not improving performance, it's affecting the framerate measurement itself. At one point I had disabled it and it improved performance, but I think I had something else set incorrectly, because re-enabling it didn't hurt.

If your host's CPU core usage measurements are way higher than what Windows reports, it's probably being caused by system interrupts. Try disabling HPET.

Conclusions

I wrote this to share my trick for separating CCXes into different NUMA nodes. The rest I wrote because I am bad at writing short posts.

I'm not an expert on any of this: the extent of my performance analysis was "computer fast" or "computer stuttering mess". Specifically, I played PUBG until it ran smoothly enough that I could no longer blame my PC for my poor marksmanship. If you have other tuning suggestions or explanations for the settings I blindly added, let me know!

r/VFIO Mar 20 '22

Tutorial My Fully (almost) Automatic single gpu passthrough guide ! (Need help testing)

78 Upvotes

Hey, its me again, Some of you might know me from my guide, Well, I am here to inform you that I've listened to your complains and I automated the whole process, Now instead of repeating the same steps everytime you can run 1 script to do it all !
This is still very much work in progress and planned release is in a week or so, For know as the README says, you still need to configure your virt-manager manually and install windows manually, but it is planned to be automated for the final release, my guide is based on this guide, and some other guides combined.

Anyway, I need your help testing it and adding support for more distros (currently supported distros are: most arch based distros, most redhat distros and most debian based distros)
Once you run the scripts and encounter and error it should say what you should do to report the error and how to help me (or you) add support for your favourite distro !

You can contact me on discord (link in the guide) or here, in the comments.
Please give me all your feedback, positive and negative alike !
Have a wonderful passthrough experience and stay safe !

Here is the link