-
Tomway started following VM GPU passthrough issues - vfio_region_write failed: Device or resource busy , Complete 2026 Guide: Windows 11 Gaming VM with Secure Boot, TPM 2.0, and Anti-Cheat Support on Unraid (Call of Duty / Ricochet / EAC / Vanguard / BattlEye) and Nvidia GPU Passthrough with vbios - No Display with VM's (System Log and Diagnostics Attached!)
-
Complete 2026 Guide: Windows 11 Gaming VM with Secure Boot, TPM 2.0, and Anti-Cheat Support on Unraid (Call of Duty / Ricochet / EAC / Vanguard / BattlEye)
# The Complete 2026 Guide: Windows 11 Gaming VM with Secure Boot, TPM 2.0, and Anti-Cheat Support on Unraid (Call of Duty / Ricochet / EAC / Vanguard / BattlEye) **Tested on**: Unraid 7.1.4, AMD Ryzen 9 7950X, ASUS TUF GAMING B650M-PLUS, NVIDIA RTX 3060, WD Black SN850X 2TB NVMe (bare-metal Windows install via PCI passthrough) **Result**: Smoother frame times than I ever got even running Windows directly on bare metal. Call of Duty (with Ricochet anti-cheat) launches and plays without stutter or attestation errors. This guide will save you the 6+ hours of debugging it took to get here. --- ## TL;DR (jump to the fix) Modern anti-cheat (Ricochet, EAC, Vanguard, BattlEye) requires: - **UEFI boot** with **Secure Boot enabled and enforcing** (not just present) - **TPM 2.0** properly initialized - **A "real-looking" SMBIOS** (not "QEMU / EDK II") - **Hardware that doesn't scream VM** in CPUID Unraid 7.1.x ships OVMF firmware **without Secure Boot or TPM compiled in** (`OVMF_CODE-pure-efi-tpm.fd` is misleadingly named). This is the root of 90% of VM gaming pain in 2026. The fix: 1. Extract Fedora's `OVMF_CODE_4M.secboot.fd` + `OVMF_VARS_4M.secboot.fd` (has SB + TPM + MS keys pre-enrolled) 2. Mount a 1GB hugetlbfs (Unraid doesn't do this by default) 3. Pin VM to a **single CCD** on Ryzen (massive latency improvement) 4. Spoof SMBIOS to look like real hardware 5. Set Windows to Ultimate Performance, disable HAGS Full XML and commands below. --- ## Why this guide exists — let's normalize gaming VMs again A few years ago, gaming VMs on Unraid / Proxmox / Arch with VFIO passthrough were thriving. You'd build a single tower with all your storage, run Plex, run a dozen Docker containers, and have a Windows gaming VM that performed within 5% of bare metal. Then anti-cheat got aggressive. Ricochet, Vanguard, and the latest Easy Anti-Cheat started checking Secure Boot state, TPM attestation, and SMBIOS strings. Suddenly half the gaming VM guides on the internet stopped working. Posts from 2022-2023 telling you to use OVMF without TPM, or boot a vdisk with SeaBIOS, will make COD refuse to launch. This guide is a 2026 update that gets you a fully attested, anti-cheat-compatible Windows 11 gaming VM. You can run your home server **and** play AAA multiplayer titles without dual-booting. **One machine, many uses.** That's what Unraid is supposed to be. --- ## You don't have to debug this alone — use Claude Code Real talk: this guide exists because I went through 6+ hours of debugging with **Claude Code** (Anthropic's terminal-based AI assistant) helping me at every step. It read my XML, parsed libvirt error logs, suggested OVMF builds, walked me through OVMF firmware menus, and rewrote my XML 11 times as we discovered new issues. **If you're going to do this yourself, run Claude Code in your Unraid SSH session.** It can: - Read your current VM XML and tell you what's missing - Parse `/var/log/libvirt/qemu/<vm>.log` errors and suggest fixes - Generate the exact `<sysinfo>` SMBIOS block for your motherboard - Check `/proc/cmdline`, `/sys/kernel/mm/hugepages/`, `mdcmd status`, and other diagnostic outputs in real time - Generate `nano` keystroke instructions if you've never edited Linux config files - Write your `/boot/config/go` modifications correctly With **Unraid's own MCP API** (now in public beta), an AI agent can read your system state, edit XMLs, mount filesystems, and basically perform this entire process autonomously. We're at the point where setting up a gaming VM should be a 5-minute conversation, not a 6-hour rabbit hole. The tools are there — use them. [Claude Code](https://claude.ai/code) | [Unraid API](https://docs.unraid.net/API/) | [Anthropic Console](https://console.anthropic.com) --- ## Hardware tested | Component | Spec | |-----------|------| | **CPU** | AMD Ryzen 9 7950X (16 cores / 32 threads, two CCDs) | | **Motherboard** | ASUS TUF GAMING B650M-PLUS | | **GPU** | NVIDIA RTX 3060 (single GPU, passed through) | | **RAM** | 32 GB DDR5 | | **Boot drive (VM)** | WD Black SN850X 2TB NVMe (PCIe passthrough — Windows installed bare-metal style) | | **Host OS** | Unraid 7.1.4 (QEMU 9.2.3, libvirt 11.2.0, kernel 6.12.24) | This guide adapts to any AMD Ryzen 5000/7000/9000 + Nvidia/AMD GPU. Intel users: same OVMF/SMBIOS/TPM steps, different CPU pinning math. --- ## Common error messages this guide solves If you've Googled any of these, you're in the right place: - `internal error: Unable to find any usable hugetlbfs mount for 1048576 KiB` - `operation failed: unable to find any master var store for loader` - `Numerical result out of range` (cgroup cpuset) - `unable to write to '/sys/fs/cgroup/.../cpuset.cpus': Numerical result out of range` - COD: **"BIOS firmware: Update Required"** / **"Failed Attestation Status will be applied"** - `Get-Tpm` returns `False` for everything in Windows - `msinfo32` shows **Secure Boot State: Off** despite enrolling keys - VM boots TianoCore but Windows won't load (no boot device) - VM crashes 28 seconds after start, libvirtd kills it - `mt76x2u ... failed:-110` spamming dmesg - Stuttering / micro-lag in games despite high FPS - `Confirm-SecureBootUEFI` returns `False` --- ## Part 1 — BIOS settings (do this first) ### ASUS TUF B650M-PLUS specifically Boot into BIOS (Del at POST) → F7 for Advanced Mode. | Setting | Path | Value | |---------|------|-------| | **Ai Overclock Tuner** | Ai Tweaker | **Auto** (or just enable EXPO if you want memory speed; do NOT use any "Gaming" / "Eco" preset — these can disable a CCD) | | **SMT Control** | Advanced → AMD CBS → CPU Common Options → Performance | **Auto** (keeps all 32 threads) | | **CCD Control** | Advanced → AMD CBS → CPU Common Options → Performance | **Auto** (keeps both CCDs) | | **Global C-state Control** | Advanced → AMD CBS → CPU Common Options | **Disabled** or limit to C2 (reduces latency spikes) | | **Power Supply Idle Control** | Advanced → AMD CBS → CPU Common Options | **Typical** | | **PCIe ASPM** | Advanced → PCH Configuration | **Disabled** | | **fTPM / AMD CPU fTPM** | Advanced → AMD fTPM Configuration | **Enabled** (host TPM, separate from vTPM) | | **CSM** | Boot → CSM | **Disabled** (UEFI only) | | **IOMMU** | Advanced → AMD CBS → NBIO Common Options | **Enabled** | | **SVM Mode** | Advanced → CPU Configuration | **Enabled** (AMD-V virtualization) | ### Verify after BIOS save + reboot ```bash lscpu | head -20 # Expected: # CPU(s): 32 # Thread(s) per core: 2 # Core(s) per socket: 16 ``` If you only see 8 or 16 CPUs, an EZ Tuning preset has nuked one of your CCDs or SMT. Go back to BIOS and check those settings. --- ## Part 2 — Hugepages setup (massive performance boost) 1GB hugepages eliminate TLB misses and cut memory latency dramatically. This is the single biggest factor in eliminating VM gaming stutter. ### Edit `/boot/syslinux/syslinux.cfg` Append `default_hugepagesz=1G hugepagesz=1G hugepages=24` to the kernel command line of the default Unraid OS label. Example: ``` label Unraid OS menu default kernel /bzimage append pcie_acs_override=multifunction vfio_iommu_type1.allow_unsafe_interrupts=1 default_hugepagesz=1G hugepagesz=1G hugepages=24 initrd=/bzroot ``` This pre-allocates 24 GB of 1GB hugepages at boot — enough for a 22 GB VM with headroom. ### Mount hugetlbfs (Unraid doesn't do this for 1GB pages) Edit `/boot/config/go`. Add **before** `emhttp`: ```bash # Mount 1GB hugetlbfs for VMs mkdir -p /dev/hugepages1G mount -t hugetlbfs -o pagesize=1G hugetlbfs /dev/hugepages1G ``` ### Reboot and verify ```bash cat /proc/cmdline | grep huge # Should show: ... default_hugepagesz=1G hugepagesz=1G hugepages=24 ... cat /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages # Should show: 24 mount | grep huge # Should show TWO mounts: # hugetlbfs on /dev/hugepages (default 2MB) # hugetlbfs on /dev/hugepages1G (pagesize=1024M) ``` ⚠️ Without the `mount` step, libvirt errors with `Unable to find any usable hugetlbfs mount for 1048576 KiB` even though the kernel has the hugepages allocated. --- ## Part 3 — OVMF firmware (the part that breaks Secure Boot) ### Why Unraid's bundled OVMF doesn't work Unraid 7.1.x ships: - `/usr/share/qemu/ovmf-x64/OVMF_CODE-pure-efi.fd` - `/usr/share/qemu/ovmf-x64/OVMF_CODE-pure-efi-tpm.fd` - corresponding VARS files **The "pure-efi" naming is misleading.** These builds are compiled WITHOUT the Secure Boot enforcement code path. You can enroll Microsoft keys all day, and the firmware state will never flip to Enabled. Windows will report `Secure Boot State: Off`. ### The fix — extract Fedora's edk2-ovmf via Docker Fedora ships `OVMF_CODE_4M.secboot.fd` with **SecureBoot + TPM + SMM all compiled in**, AND `OVMF_VARS_4M.secboot.fd` with **Microsoft keys pre-enrolled**. No manual key enrollment needed. ```bash mkdir -p /mnt/user/isos/ovmf docker run --rm -v /mnt/user/isos/ovmf:/out fedora:latest bash -c ' dnf install -y edk2-ovmf qemu-img && qemu-img convert -f qcow2 -O raw /usr/share/edk2/ovmf/OVMF_CODE_4M.secboot.qcow2 /out/OVMF_CODE_4M.secboot.fd && qemu-img convert -f qcow2 -O raw /usr/share/edk2/ovmf/OVMF_VARS_4M.secboot.qcow2 /out/OVMF_VARS_4M.secboot.fd && chmod 644 /out/OVMF_*4M* ' ls -la /mnt/user/isos/ovmf/ # Expected: # OVMF_CODE_4M.secboot.fd ~3.5 MB # OVMF_VARS_4M.secboot.fd ~540 KB ``` Storing them in `/mnt/user/isos/ovmf/` keeps them on the array (persistent across reboots — `/usr/share` is tmpfs on Unraid). ### Clean up old NVRAM (if you tried previous OVMF builds) ```bash rm -f /etc/libvirt/qemu/nvram/<your-vm-uuid>_VARS-pure-efi-tpm.fd rm -f /etc/libvirt/qemu/nvram/<your-vm-uuid>_VARS.secboot.fd ``` (Replace `<your-vm-uuid>` with the value from your VM XML's `<uuid>` tag. libvirt will copy a fresh VARS file with MS keys baked in on next start.) --- ## Part 4 — Complete VM XML Replace `<your-vm-uuid>` with your VM's actual UUID. Adjust the GPU/NVMe PCI addresses and USB devices to match `lspci -nn` and `lsusb` on your system. ```xml <?xml version='1.0' encoding='UTF-8'?> <domain type='kvm'> <name>Windows 11 Gaming VM SSD - Secure Boot</name> <uuid>YOUR-UUID-HERE</uuid> <memory unit='KiB'>23068672</memory> <currentMemory unit='KiB'>23068672</currentMemory> <memoryBacking> <hugepages> <page size='1048576' unit='KiB'/> </hugepages> <nosharepages/> <locked/> </memoryBacking> <vcpu placement='static'>16</vcpu> <iothreads>1</iothreads> <cputune> <!-- Pin all 16 vCPUs to CCD1 (cores 8-15 + threads 24-31) Host gets CCD0 (cores 0-7 + threads 16-23) for Unraid --> <vcpupin vcpu='0' cpuset='8'/> <vcpupin vcpu='1' cpuset='24'/> <vcpupin vcpu='2' cpuset='9'/> <vcpupin vcpu='3' cpuset='25'/> <vcpupin vcpu='4' cpuset='10'/> <vcpupin vcpu='5' cpuset='26'/> <vcpupin vcpu='6' cpuset='11'/> <vcpupin vcpu='7' cpuset='27'/> <vcpupin vcpu='8' cpuset='12'/> <vcpupin vcpu='9' cpuset='28'/> <vcpupin vcpu='10' cpuset='13'/> <vcpupin vcpu='11' cpuset='29'/> <vcpupin vcpu='12' cpuset='14'/> <vcpupin vcpu='13' cpuset='30'/> <vcpupin vcpu='14' cpuset='15'/> <vcpupin vcpu='15' cpuset='31'/> <emulatorpin cpuset='0,16'/> <iothreadpin iothread='1' cpuset='0,16'/> </cputune> <os> <type arch='x86_64' machine='pc-q35-9.2'>hvm</type> <loader readonly='yes' secure='yes' type='pflash' format='raw'>/mnt/user/isos/ovmf/OVMF_CODE_4M.secboot.fd</loader> <nvram template='/mnt/user/isos/ovmf/OVMF_VARS_4M.secboot.fd' format='raw'>/etc/libvirt/qemu/nvram/YOUR-UUID-HERE_VARS_4M.secboot.fd</nvram> <bootmenu enable='yes' timeout='5000'/> <smbios mode='sysinfo'/> </os> <sysinfo type='smbios'> <bios> <entry name='vendor'>American Megatrends Inc.</entry> <entry name='version'>2429</entry> <entry name='date'>11/14/2024</entry> <entry name='release'>5.29</entry> </bios> <system> <entry name='manufacturer'>ASUS</entry> <entry name='product'>System Product Name</entry> <entry name='version'>System Version</entry> <entry name='serial'>System Serial Number</entry> <entry name='uuid'>YOUR-UUID-HERE</entry> <entry name='sku'>SKU</entry> <entry name='family'>To be filled by O.E.M.</entry> </system> <baseBoard> <entry name='manufacturer'>ASUSTeK COMPUTER INC.</entry> <entry name='product'>TUF GAMING B650M-PLUS</entry> <entry name='version'>Rev 1.xx</entry> <entry name='serial'>230123456789</entry> <entry name='asset'>Default string</entry> <entry name='location'>Default string</entry> </baseBoard> <chassis> <entry name='manufacturer'>Default string</entry> <entry name='version'>Default string</entry> <entry name='serial'>Default string</entry> <entry name='asset'>Default string</entry> <entry name='sku'>Default string</entry> </chassis> </sysinfo> <features> <acpi/> <apic/> <hyperv mode='custom'> <relaxed state='on'/> <vapic state='on'/> <spinlocks state='on' retries='8191'/> <vpindex state='on'/> <synic state='on'/> <stimer state='on'/> <reset state='on'/> <frequencies state='on'/> <vendor_id state='on' value='none'/> </hyperv> <kvm> <hidden state='on'/> </kvm> <ioapic driver='kvm'/> <smm state='on'/> </features> <cpu mode='host-passthrough' check='none' migratable='on'> <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='disable' name='hypervisor'/> </cpu> <clock offset='localtime'> <timer name='hpet' 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>restart</on_crash> <devices> <emulator>/usr/local/sbin/qemu</emulator> <!-- Win11 ISO + virtio-win drivers (keep until Windows is happy, then can remove) --> <disk type='file' device='cdrom'> <driver name='qemu' type='raw'/> <source file='/mnt/user/isos/Win11_23H2_EnglishInternational_x64v2.iso'/> <target dev='hda' bus='sata'/> <readonly/> <boot order='2'/> <address type='drive' controller='0' bus='0' target='0' unit='0'/> </disk> <disk type='file' device='cdrom'> <driver name='qemu' type='raw'/> <source file='/mnt/user/isos/virtio-win-0.1.285-1.iso'/> <target dev='hdb' bus='sata'/> <readonly/> <address type='drive' controller='0' bus='0' target='0' unit='1'/> </disk> <controller type='usb' index='0' model='qemu-xhci' ports='15'> <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </controller> <controller type='pci' index='0' model='pcie-root'/> <!-- Multiple PCIe root ports needed for hostdev attachments --> <controller type='pci' index='1' model='pcie-root-port'> <model name='pcie-root-port'/> <target chassis='1' port='0x8'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> </controller> <controller type='pci' index='2' model='pcie-root-port'> <model name='pcie-root-port'/> <target chassis='2' port='0x9'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> </controller> <controller type='pci' index='3' model='pcie-root-port'> <model name='pcie-root-port'/> <target chassis='3' port='0xa'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> </controller> <controller type='pci' index='4' model='pcie-root-port'> <model name='pcie-root-port'/> <target chassis='4' port='0xb'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x3'/> </controller> <controller type='pci' index='5' model='pcie-root-port'> <model name='pcie-root-port'/> <target chassis='5' port='0xc'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x4'/> </controller> <controller type='virtio-serial' index='0'> <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> </controller> <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> </controller> <interface type='bridge'> <mac address='52:54:00:78:34:57'/> <source bridge='br0'/> <model type='virtio-net'/> <driver name='vhost' queues='8'/> <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='unix'> <target type='virtio' name='org.qemu.guest_agent.0'/> <address type='virtio-serial' controller='0' bus='0' port='1'/> </channel> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <tpm model='tpm-crb'> <backend type='emulator' version='2.0' persistent_state='yes'/> </tpm> <audio id='1' type='none'/> <!-- GPU passthrough: RTX 3060 + audio --> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </source> <rom file='/mnt/disk1/Media/RTX 3060 vbios TP.rom'/> <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> </hostdev> <!-- NVMe passthrough (managed='yes' so libvirt auto-detaches from host) --> <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> <address domain='0x0000' bus='0x0b' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> </hostdev> <!-- USB device passthroughs (mouse, keyboard, etc.) --> <hostdev mode='subsystem' type='usb' managed='no'> <source> <vendor id='0x0b05'/> <product id='0x19af'/> </source> <address type='usb' bus='0' port='1'/> </hostdev> <watchdog model='itco' action='reset'/> <memballoon model='none'/> </devices> </domain> ``` ### Why each part of this XML matters | Element | Purpose | |---------|---------| | `<loader secure='yes'>` | Tells libvirt to enable SMM-enforced Secure Boot | | `<smm state='on'/>` | Required for Secure Boot enforcement | | `<bootmenu>` | Lets you press ESC at boot for OVMF firmware menu | | `<sysinfo>` SMBIOS spoof | Makes Windows see "ASUS TUF" instead of "QEMU" | | `<feature policy='disable' name='hypervisor'/>` | Removes the CPUID hypervisor flag (most VM detection's first check) | | `<kvm><hidden state='on'/>` | Hides KVM CPUID leaf | | `<hyperv>` enlightenments | Tells Windows it's on Hyper-V, lets KVM optimize Windows scheduling | | `<vendor_id state='on' value='none'/>` | Hides "KVMKVMKVM" CPU vendor string | | `<page size='1048576'>` hugepages | 1GB pages → near-zero TLB misses | | `<locked/>` memory | Host can't swap/page VM memory | | Single CCD pinning (cores 8-15, threads 24-31) | All vCPUs share one L3 cache → no cross-CCD latency penalty | | `emulatorpin` to CCD0 | QEMU helper threads run on host's cores, not stealing yours | | `iothreadpin` | Dedicated I/O thread, off vCPU cores | | `invtsc` feature | Stable timer for Windows | | `<tpm model='tpm-crb'>` | Windows 11 prefers CRB over TIS | | `persistent_state='yes'` on TPM | Survives VM restarts (BitLocker stays happy) | | `managed='yes'` on NVMe hostdev | libvirt auto-detaches from host nvme driver, no VFIO bind required | --- ## Part 5 — Windows-side optimizations After the VM boots into Windows: ### Power plan: Ultimate Performance ```powershell powercfg -duplicatescheme e9a42b02-d5df-448d-aa00-03f14749eb61 ``` Then **Control Panel → Power Options → Ultimate Performance** (selected). ### Disable HAGS (Hardware-accelerated GPU scheduling) Settings → System → Display → Graphics → Default settings → toggle **off**. HAGS sometimes causes stutter in VMs, especially with Nvidia drivers + COD. ### Nvidia control panel - Power management mode: **Prefer Maximum Performance** - Vertical sync: **Off** (use in-game) - Low Latency Mode: **Ultra** ### Disable Game Mode + Game Bar Settings → Gaming → Game Mode → **Off**. Game Bar can also cause hitches in long sessions. ### Verify Secure Boot + TPM ```powershell Confirm-SecureBootUEFI # Should return True Get-Tpm # All fields should be True ``` `msinfo32` → **Secure Boot State: On**, **BIOS Mode: UEFI**. ### Verify SMBIOS spoof ```powershell Get-WmiObject Win32_ComputerSystem | Select Manufacturer, Model Get-WmiObject Win32_BIOS | Select Manufacturer, SMBIOSBIOSVersion, ReleaseDate Get-WmiObject Win32_BaseBoard | Select Manufacturer, Product, Version ``` Should show "ASUS / TUF GAMING B650M-PLUS / American Megatrends 2429" — NOT "QEMU / EDK II". --- ## Performance results Subjective gameplay smoothness is night and day: - **Before this guide**: stutters every 1-2 seconds, FPS hits the cap but feels janky - **After**: cleaner frame times than I get on bare metal Windows on the exact same hardware Why VM beats bare metal here: Unraid scheduler isolation + 1GB hugepages + locked memory means the VM has zero contention from background OS noise. On bare metal Windows, every Defender scan, telemetry hit, or Windows Update cycle introduces frame time variance. In the VM, all that lives on the host (Unraid), separated by hardware boundaries. --- ## Troubleshooting reference ### `Unable to find any usable hugetlbfs mount for 1048576 KiB` Hugepages allocated but not mounted. See Part 2 — `/dev/hugepages1G` mount. ### `unable to find any master var store for loader` NVRAM template path missing or wrong. Check `<nvram template='...'>` points at an existing OVMF VARS file. ### `Numerical result out of range` (cpuset) Pinning to CPU IDs that don't exist. Run `nproc` on host. If it shows 8 instead of 32, BIOS has SMT or a CCD disabled. Check `lscpu | head -20`. ### Get-Tpm all False, but TPM device shown in XML OVMF doesn't have TPM compiled in. Use Fedora's `OVMF_CODE_4M.secboot.fd` — see Part 3. ### COD: "BIOS firmware: Update Required" / Failed Attestation - Verify SMBIOS spoof actually applied (Windows-side WMI checks above) - Sign in with Microsoft account - Update Windows to latest - Clear and re-init TPM in Windows (Settings → Privacy & Security → Security processor troubleshooting) - Note: Activision officially does not support VMs. Some weeks/builds work, others don't. EAC and BattlEye are more forgiving. ### VM crashes 28 seconds after start Often `<watchdog action='reset'/>` triggering because something inside the VM stopped responding (GPU driver crash, NVMe detach failure). Check `/var/log/libvirt/qemu/<vm>.log` for hints. ### Stuttering despite high FPS You're spanning CCDs. Reduce vCPUs and pin to one CCD. See Part 4 cputune. ### NVMe passthrough fails to start Ensure NVMe is NOT assigned to array, NOT in any pool, NOT mounted. With `managed='yes'`, libvirt handles detach. Check Main tab in webGUI — the drive should be in "Unassigned Devices", not the array. --- ## Diagnostic commands cheatsheet ```bash # CPU topology lscpu | head -20 nproc cat /proc/cmdline # Hugepages cat /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages cat /sys/kernel/mm/hugepages/hugepages-1048576kB/free_hugepages mount | grep huge # CCD layout (which CPUs share L3 cache) cat /sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_list cat /sys/devices/system/cpu/cpu8/cache/index3/shared_cpu_list # OVMF files available ls /usr/share/qemu/ovmf-x64/ /mnt/user/isos/ovmf/ 2>/dev/null # VM run state virsh list --all virsh dumpxml "Windows 11 Gaming VM SSD - Secure Boot" # VM start log (most recent attempt) tail -150 "/var/log/libvirt/qemu/Windows 11 Gaming VM SSD - Secure Boot.log" # Live QEMU command line ps -ef | grep qemu-system # TPM emulator log cat "/var/log/swtpm/libvirt/qemu/Windows 11 Gaming VM SSD - Secure Boot-swtpm.log" # Array / disk status mdcmd status | grep -E "diskNumber|diskName|rdevStatus|rdevName" | head -30 # Restart libvirt /etc/rc.d/rc.libvirt restart ``` --- ## Appendix A — Why manual Secure Boot key enrollment doesn't work on Unraid (and what we tried first) Most older guides tell you to manually enroll Microsoft Secure Boot keys via the OVMF firmware menu. **This does not work on Unraid 7.x.** We spent 2 hours discovering this. Here's the dead-end path so you don't repeat it: ### Step 1 — Download Microsoft's Secure Boot certs (this part is tricky) Microsoft's official cert download URLs return **403 Forbidden** for `wget`/`curl` even with browser user-agent headers: ```bash # THIS DOES NOT WORK curl -A "Mozilla/5.0" "https://go.microsoft.com/fwlink/?LinkId=321185" # Returns HTML 403 page disguised as a .crt file ``` Use Microsoft's **official GitHub mirror** instead — these URLs work without auth: ```bash mkdir -p /tmp/mskeys && cd /tmp/mskeys curl -L -o MicCorKEKCA2011.der "https://raw.githubusercontent.com/microsoft/secureboot_objects/main/PreSignedObjects/KEK/Certificates/MicCorKEKCA2011_2011-06-24.der" curl -L -o MicWinProPCA2011.der "https://raw.githubusercontent.com/microsoft/secureboot_objects/main/PreSignedObjects/DB/Certificates/MicWinProPCA2011_2011-10-19.der" curl -L -o MicCorUEFCA2011.der "https://raw.githubusercontent.com/microsoft/secureboot_objects/main/PreSignedObjects/DB/Certificates/MicCorUEFCA2011_2011-06-27.der" # Verify they're real certs (~1500-2000 bytes each, NOT 4410-byte HTML) file *.der ls -la *.der ``` You should see `Certificate, Version=3` for each. If you see `HTML document`, you got the wrong URLs. ### Step 2 — Get the certs onto a disk OVMF can read Unraid doesn't have `mkisofs` or `genisoimage`. Build a FAT32 disk image with a GPT partition table (raw FAT on a small disk often gets ignored by OVMF's file browser): ```bash # Build a 64MB image with GPT + FAT32 partition dd if=/dev/zero of=/mnt/user/isos/secureboot-keys.img bs=1M count=64 parted -s /mnt/user/isos/secureboot-keys.img mklabel gpt parted -s /mnt/user/isos/secureboot-keys.img mkpart ESP fat32 1MiB 100% parted -s /mnt/user/isos/secureboot-keys.img set 1 esp on # Format the partition LOOP=$(losetup -f --show -P /mnt/user/isos/secureboot-keys.img) mkfs.vfat -F 32 "${LOOP}p1" # Copy certs in mkdir -p /mnt/sbkeys mount "${LOOP}p1" /mnt/sbkeys cp /tmp/mskeys/*.der /mnt/sbkeys/ ls -la /mnt/sbkeys/ # Cleanup umount /mnt/sbkeys losetup -d "$LOOP" ``` Attach this image to the VM as `device='disk'` (not cdrom) on the SATA bus, replacing the Win11 ISO temporarily. ### Step 3 — Boot into OVMF firmware menu and try to enroll keys Add `<bootmenu enable='yes' timeout='5000'/>` to your `<os>` block, start VM, hammer ESC at the TianoCore splash. Navigate: - **Device Manager** → **Secure Boot Configuration** - Tick **Attempt Secure Boot** - Set **Secure Boot Mode** → **Custom Mode** - **Custom Secure Boot Options** → enroll in this order: **DB → KEK → PK** - DB Options → Enroll Signature Using File → MicWinProPCA2011.der → Commit - DB Options → again → MicCorUEFCA2011.der → Commit - KEK Options → Enroll KEK Using File → MicCorKEKCA2011.der → Commit - PK Options → Enroll PK Using File → MicCorKEKCA2011.der → Commit (PK enrollment activates Secure Boot) ### Step 4 — Discover that none of this matters After enrollment, **Secure Boot State** still shows **Disabled** in the OVMF menu, and Windows reports `Secure Boot State: Off`. Why? ```bash # Check if the OVMF binary even has Secure Boot strings compiled in grep -aoc "TPM2\|TCG2" /usr/share/qemu/ovmf-x64/OVMF_CODE-pure-efi-tpm.fd # Returns 0 — but this test is unreliable since OVMF strings are compressed ``` The actual test is "does the OVMF firmware menu have a working **Attempt Secure Boot** checkbox after key enrollment". On Unraid's bundled `OVMF_CODE-pure-efi-tpm.fd`, the answer is no. The "pure-efi" naming is a giveaway: this build excludes the SecureBoot enforcement code path. Same for `OVMF_CODE.secboot.fd` (the 2MB variant) which Fedora also ships — it has the strings but lacks TPM. ### The right answer Use Fedora's **`OVMF_CODE_4M.secboot.fd`** (the 4M variant) — it has SecureBoot + TPM + SMM all compiled in, AND `OVMF_VARS_4M.secboot.fd` has Microsoft keys **pre-enrolled** so you skip the entire firmware menu dance. See Part 3 of this guide. Total time saved by knowing this upfront: ~2 hours. --- ## Appendix B — Lessons learned about anti-cheat in 2026 What works (with this guide): - ✅ Easy Anti-Cheat (Fortnite, Apex, etc.) - ✅ BattlEye (PUBG, R6 Siege, DayZ, ARK, Tarkov*) - ✅ Vanguard (Valorant) — usually - ⚠️ Ricochet (Call of Duty) — works but Activision actively blocks VMs; menu loads, gameplay smooth, but you may get attestation warnings or random kicks \*Tarkov is hit or miss; depends on the BattlEye config of the day. What still doesn't work: - ❌ Faceit (CS2 third-party) — explicitly blocks VMs - ❌ ESEA — same - ❌ Some VAC-secured competitive matchmaking modes Activision/Microsoft attestation flow: 1. VM boots, OVMF measures SecureBoot keys + bootloader into TPM PCRs 2. Windows boots, measures kernel and driver loads 3. Ricochet collects PCR values, sends to Microsoft's attestation cloud API 4. API checks PCR values against database of known-good real-hardware signatures 5. VM TPM measurements don't match any real OEM motherboard → "Failed Attestation" There is no XML you can write that bypasses this — it's cryptographic comparison against Microsoft's database. SMBIOS spoofing fixes the first-pass surface checks, which gets you into the game menu and matches in most cases. But TPM attestation is the wall. Workarounds that sometimes help: - Sign in with a Microsoft account (some attestation calls trust the linked identity) - Update Windows fully (newer attestation client is more permissive) - Accept that COD VM gameplay is best-effort --- ## Conclusion In 2026, modern anti-cheat means gaming VMs need to look exactly like real hardware. The default Unraid OVMF doesn't do this. The good news: Fedora ships a perfect OVMF for free, and with the right XML you can get smoother gameplay than bare metal. Key takeaways: 1. Use **Fedora's OVMF_CODE_4M.secboot.fd** (Unraid's bundled OVMF won't work) 2. Mount **1GB hugetlbfs manually** (Unraid only does 2MB by default) 3. Pin to **a single CCD** on Ryzen 4. Spoof **SMBIOS** with realistic motherboard info 5. Hide the **hypervisor CPUID flag** 6. Use **AI assistants** like Claude Code to handle the debugging loop Gaming VMs are absolutely viable in 2026. They had a rough patch when anti-cheat got aggressive, but the tools are catching up. Let's normalise this — there's no reason to maintain a separate gaming PC if your Unraid box is already a beast. --- ## Credits and resources - **Built with**: [Claude Code](https://claude.ai/code) (Anthropic Sonnet 4.7, 1M context window) — debugged with me line-by-line for ~6 hours - **Unraid**: [forums.unraid.net](https://forums.unraid.net), [docs.unraid.net](https://docs.unraid.net) - **Unraid API/MCP**: [docs.unraid.net/API/](https://docs.unraid.net/API/) — connect Claude or another agent for autonomous VM management - **OVMF**: [Fedora's edk2-ovmf package](https://packages.fedoraproject.org/pkgs/edk2/edk2-ovmf/) - **SMBIOS spec**: [DMTF System Management BIOS](https://www.dmtf.org/standards/smbios) - **Anti-cheat compatibility**: [areweanticheatyet.com](https://areweanticheatyet.com) If this guide helped you, drop a reply on the Unraid forum thread so others can find it. The more of us who post working configs in 2026, the easier this gets for the next person. **Tags**: #unraid #vfio #gaming-vm #windows11 #secure-boot #tpm #call-of-duty #ricochet #anti-cheat #ryzen #7950x #hugepages #ovmf #kvm #qemu #libvirt
-
VM GPU passthrough issues - vfio_region_write failed: Device or resource busy
I'm having the same error myself, i've tried all kinds of fixes and watched every video SpaceInvaderOne has made about Nvidia GPU passthrough and still no display. I just need it to work temporarily until i can get hold of a RTX 3080 at a non extortionate rate. This is the error code in the log (Log Screenshot Attached) 2021-04-05T18:23:12.073130Z qemu-system-x86_64: vfio_region_write(0000:2b:00.0:region3+0x111d780, 0xccff0000ccff,8) failed: Device or resource busy 2021-04-05T18:23:12.074649Z qemu-system-x86_64: vfio_region_write(0000:2b:00.0:region3+0x1121708, 0x0,8) failed: Device or resource busy Unraid 6.9.1 Motherboard: MSI Tomahawk b550 (MS-7c91) Version 2. CPU: AMD Ryzen 5600x 6-core. GPU: Nvidia GeForce GTX 650 ti. RAM: 16gb DDR4 3200mhz. Latest Bios Installed I've tried both types of vbios (Hex editing and Script in unraid) All IOMMU Groups passed through successfully and i can boot into GUI Mode! IOMMU groups enabled in bios as well as VM's
Tomway
Members
-
Joined
-
Last visited