Native-Like Windows Experience on Linux

Run Windows inside Linux without rebooting using pure GPU passthrough.

View on GitHub Sponsor

Overview

This is a 2-in-1 system implementation with a single .sh script that allows you to run Windows inside Linux without requiring a reboot. It uses GPU passthrough (VFIO) technology to give the Windows virtual machine direct access to your dedicated GPU, providing near-native gaming performance while keeping your Linux host system intact.


Designed for: NVIDIA GPU + Intel CPU
Compatibility: May also work with AMD GPUs and CPUs with minor adjustments

My testing configuration: Lenovo ThinkPad P53 • Intel i7-9850H • 128GB RAM • NVIDIA Quadro RTX 5000 Max-Q 16GB

Prerequisites

  • Hardware: IOMMU-capable CPU and motherboard (Intel VT-d or AMD-Vi).
  • Software: QEMU/KVM, OVMF, VFIO kernel modules, virtio-win drivers.
  • BIOS Settings: Enable IOMMU/VT-d in BIOS.
  • Windows Settings: Disable Fast Startup in Windows Power Options (see Known Issues).
  • Kernel Parameters: Add intel_iommu=on iommu=pt* or amd_iommu=on iommu=pt* to your bootloader.

⚠️ *Security Note: The iommu=pt parameter is recommended for maximum gaming performance as it minimizes overhead and latency. However, it effectively disables DMA protection for passed-through devices.

As noted by the community, forcing the IOMMU to passthrough mode means that if a malicious device is flashed with rogue firmware, it could potentially retain access to host memory even after the VM is shut down.

If you prioritize strict security over marginal performance gains, or do not fully trust your devices/firmware, you may omit iommu=pt and simply use intel_iommu=on or amd_iommu=on.

Setup

Creating the VM Directory

Create a directory in /opt to store your VM files:

# Create the directory
sudo mkdir -p /opt/windowsvm

# Set appropriate permissions
sudo chown $USER:$USER /opt/windowsvm

# Create the disk image (256G is the size)
qemu-img create -f qcow2 /opt/windowsvm/emugaming.qcow2 256G

# Create NVRAM file
cp /usr/share/edk2/x64/OVMF_VARS.4m.fd /opt/windowsvm/nvram.fd

# Download virtio-win drivers
wget -O /opt/windowsvm/virtio-win.iso https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.240/virtio-win.iso
            

Understanding Files

.qcow2 is the virtual disk image. It acts as your C: drive. It grows dynamically up to the max size.

nvram.fd acts as the UEFI (BIOS) storage for the VM, saving boot settings and Secure Boot keys.

VBIOS Patching (NVIDIA)

Advanced users may need to remove UEFI headers from their GPU VBIOS. Use tools like nvflash and okteta to dump and patch the ROM. Reference the full README for step-by-step hex editing instructions.

Initial Windows Installation

Use a basic script to install Windows before using the main passthrough script.

#!/bin/bash
VM_DIR="/opt/windowsvm"
DISK_IMAGE="$VM_DIR/windows11drive.qcow2"
NVRAM="$VM_DIR/nvram.fd"
WINDOWS_ISO="/path/to/windows.iso"

qemu-system-x86_64 \
  -name "windows11" \
  -machine type=q35,accel=kvm \
  -enable-kvm \
  -cpu host \
  -smp cores=4 \
  -m 8G \
  -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
  -drive if=pflash,format=raw,file=$NVRAM \
  -drive if=none,id=disk0,format=qcow2,file=$DISK_IMAGE \
  -device virtio-blk-pci,drive=disk0 \
  -drive file=$WINDOWS_ISO,media=cdrom,index=0 \
  -drive file=/opt/windowsvm/virtio-win.iso,media=cdrom,index=1 \
  -net nic,model=virtio \
  -net user \
  -vga qxl \
  -device qemu-xhci \
  -device usb-tablet

Important: During installation, you must load drivers from the virtio-win ISO to see your hard drive.

What the Script Does

  1. Auto-Detects & Stops Display Manager: Reads the /etc/systemd/system/display-manager.service symlink to detect any active DM (SDDM, GDM, LightDM, LY, greetd, etc.) and stops it to free the GPU.
  2. Unbinds NVIDIA Drivers: Unbinds virtual consoles and removes all NVIDIA kernel modules so the host fully releases the GPU.
  3. Loads VFIO: Binds the GPU components (Video, Audio, USB, Serial) to vfio-pci for passthrough.
  4. Launches QEMU: Starts the VM with the passed-through GPU and all configured USB devices.
  5. Returns to Linux: After the VM shuts down, the script automatically:
    • Unbinds all GPU devices from VFIO and unloads VFIO modules
    • Reprobes PCI devices and rescans the PCI bus
    • Reloads NVIDIA kernel modules and wakes the GPU
    • Rebinds USB (xHCI) controllers so passthrough devices work without replugging
    • Restarts the display manager
  6. Session Logging: Every run creates a timestamped log file (vfio-windows-aio-YYYY-MM-DD_HH-MM-SS.log) for debugging.

QEMU Configuration Explained

The script uses several flags to optimize performance and hide virtualization:

  • -machine type=q35,accel=kvm: Uses modern chipset emulation and KVM hardware acceleration.
  • -cpu host...: Passes through host CPU features.
  • hv_vendor_id=NV43FIX: Critical for NVIDIA. Spoofs vendor ID to prevent Error 43 where drivers refuse to load in a VM.
  • -device vfio-pci...: The actual flags that attach the physical GPU to the virtual machine.

Known Issues

✅ Fixed — NVIDIA Driver Recovery: The script now correctly unbinds VFIO before loading NVIDIA modules, rescans the PCI bus, and rebinds USB controllers. The GPU fully restores after VM shutdown without a reboot.

⚠️ Fast Startup Must Be Disabled

QEMU will not detect a Windows VM shutdown if Fast Startup is enabled. Windows Fast Startup performs a hybrid hibernate instead of a real ACPI shutdown, so QEMU never receives the power-off signal.

Fix:

  1. Open Control PanelPower Options
  2. Click Choose what the power buttons do
  3. Click Change settings that are currently unavailable
  4. Uncheck Turn on fast startup (recommended)
  5. Click Save changes

⚠️ Low Volume

Audio from the VM might be quiet. Fix: Set your Linux host volume to 100% before starting the VM.