This commit is contained in:
aidan 2025-02-23 23:19:06 -05:00
commit f1b32326aa
5 changed files with 247 additions and 0 deletions

36
README.md Normal file
View File

@ -0,0 +1,36 @@
# QEMU-PCIE-GPU-Passthrough
![image](https://github.com/ahaas25/QEMU-PCIE-GPU-Passthrough/assets/94150901/ade6d743-e51f-43ce-a23b-c6a710b048d0)
![image](https://github.com/ahaas25/QEMU-PCIE-GPU-Passthrough/assets/94150901/69f0a2f6-576d-4934-82d1-e38f63411309)
My QEMU configuration files for passing my RTX 3070 to a Windows 11 VM.
# Credits
This is a simplified guide based on [here](https://github.com/martinopiaggi/Single-GPU-Passthrough-for-Dummies). I highly recommend reading this guide to get a better understanding of how this works.
# Patched VBIOS (NVIDIA Only)
I've provided my patched VBIOS as an example of what a correctly patched image should look like. Find the VBIOS for your graphics card and download it. Use a Hex editor to modify the rom file and search for the first instance of `VIDEO`. Look to the left of it for a `U`. Delete everything before the `U`.
# Setup Overview
This is my simplified guide based off a lot of troubleshooting.
1. Enable IOMMU and Virtualization in your BIOS.
2. Install `qemu`, `libvirt`, `virt-manager` and necessary libraries.
3. Create a Windows VM using `virt-manager` using default settings. (No device passthrough yet)
4. Ensure CPU topology is correct under `CPUs` tab. (Mine was set incorrectly by default)
5. Install Windows and ensure VM works.
6. Find your GPU's PCI bus using `lspci`. In my case my GPU is on `pci_0000_08_00_0` and the audio controller is `pci_0000_08_00_1`
7. Modify `start.sh` and `stop.sh` to suite your configuration. Change any lines refering to the GPU bus to your systems (Mine is `pci_0000_08_00_0`). Make sure to change `gdm` to your display manager if you are not using GNOME.
8. Copy `start.sh` and `stop.sh` scripts in `/etc/libvirt/hooks/qemu.d/<your_vm_name>/` keeping the file structure the same as in this repository. Ensure the scripts are executable with `chmod +x <script>`
9. Add your GPU to the virtual machine using the `Add Hardware` button. Add a `PCI Host Device` for both your graphics card and graphics card audio controller.
10. Enable XML editing for `virt-manager`. Navigate to your GPU's XML config (only for the GPU, not the audio controller) and add your custom GPU ROM under the line `</source>` with `<rom file="<path/to/bios>/<bios>.rom"/>` Note: If `libvirtd` cannot access your BIOS rom, put the ROM in `/usr/share/vgabios/<bios>.rom`
12. Start the VM. If all went well, your screen should go blank and come back to your Windows VM!
# Troubleshooting
If your VM returns you back to your display manager, run `journalctl -u libvirtd` to see what the issue is. I also found it helpful to SSH into my computer and run `virt-manager` remotely so I could see the errors (I was getting a CPU topology error which was not showing up in journalctl, but did show up in the `virt-manager` GUI). You may also find it helpful to reference my VM's XML file which is also provided in this repository.
If `modprobe` is unable to remove nvidia modules, run `nvidia-smi` to see if there are still programs running on the GPU. If there are programs still running on the GPU, you'll need to ensure they are killed in `start.sh` before starting the VM.
# My Configuration:
Linux Mint 21.3 using GNOME, Kernel 6.5.0-25-generic, NVIDIA Driver 545.29.06
Specs: AMD CPU, Gigabyte X570 motherboard, RTX 3070 GPU
VM OS: Windows 11

BIN
gpu.rom Normal file

Binary file not shown.

2
kvm.conf Normal file
View File

@ -0,0 +1,2 @@
VIRSH_GPU_VIDEO=pci_0000_08_00_0
VIRSH_GPU_AUDIO=pci_0000_08_00_1

33
qemu Normal file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# Author: SharkWipf
#
# Copy this file to /etc/libvirt/hooks, make sure it's called "qemu".
# After this file is installed, restart libvirt.
# From now on, you can easily add per-guest qemu hooks.
# Add your hooks in /etc/libvirt/hooks/qemu.d/vm_name/hook_name/state_name.
# For a list of available hooks, please refer to https://www.libvirt.org/hooks.html
#
GUEST_NAME="$1"
HOOK_NAME="$2"
STATE_NAME="$3"
MISC="${@:4}"
BASEDIR="$(dirname $0)"
HOOKPATH="$BASEDIR/qemu.d/$GUEST_NAME/$HOOK_NAME/$STATE_NAME"
set -e # If a script exits with an error, we should as well.
# check if it's a non-empty executable file
if [ -f "$HOOKPATH" ] && [ -s "$HOOKPATH" ] && [ -x "$HOOKPATH" ]; then
eval \"$HOOKPATH\" "$@"
elif [ -d "$HOOKPATH" ]; then
while read file; do
# check for null string
if [ ! -z "$file" ]; then
eval \"$file\" "$@"
fi
done <<< "$(find -L "$HOOKPATH" -maxdepth 1 -type f -executable -print;)"
fi

176
win11.xml Normal file
View File

@ -0,0 +1,176 @@
<domain type="kvm">
<name>win11</name>
<uuid>c3a16f81-6ae4-46d7-a9ba-4272442d9132</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">29360128</memory>
<currentMemory unit="KiB">29360128</currentMemory>
<vcpu placement="static">16</vcpu>
<os firmware="efi">
<type arch="x86_64" machine="pc-q35-6.2">hvm</type>
<boot dev="hd"/>
</os>
<features>
<acpi/>
<apic/>
<hyperv mode="custom">
<relaxed state="on"/>
<vapic state="on"/>
<spinlocks state="on" retries="8191"/>
</hyperv>
<vmport state="off"/>
</features>
<cpu mode="host-passthrough" check="none" migratable="on">
<topology sockets="1" dies="1" cores="8" threads="2"/>
</cpu>
<clock offset="localtime">
<timer name="rtc" tickpolicy="catchup"/>
<timer name="pit" tickpolicy="delay"/>
<timer name="hpet" present="no"/>
<timer name="hypervclock" present="yes"/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<pm>
<suspend-to-mem enabled="no"/>
<suspend-to-disk enabled="no"/>
</pm>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type="file" device="disk">
<driver name="qemu" type="qcow2" discard="unmap"/>
<source file="/var/lib/libvirt/images/win11.qcow2"/>
<target dev="sda" bus="sata"/>
<address type="drive" controller="0" bus="0" target="0" unit="0"/>
</disk>
<disk type="file" device="cdrom">
<driver name="qemu" type="raw"/>
<source file="/usr/share/images/Win11_23H2_English_x64v2.iso"/>
<target dev="sdb" bus="sata"/>
<readonly/>
<address type="drive" controller="0" bus="0" target="0" unit="1"/>
</disk>
<disk type="file" device="cdrom">
<driver name="qemu" type="raw"/>
<source file="/usr/share/images/Win11_23H2_English_x64v2.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>
<interface type="network">
<mac address="52:54:00:8e:91:14"/>
<source network="default"/>
<model type="virtio"/>
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</interface>
<input type="mouse" bus="ps2"/>
<input type="keyboard" bus="ps2"/>
<tpm model="tpm-crb">
<backend type="emulator" version="2.0"/>
</tpm>
<audio id="1" type="none"/>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x08" slot="0x00" function="0x0"/>
</source>
<rom file="/usr/share/vgabios/asus.rom"/>
<address type="pci" domain="0x0000" bus="0x04" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x08" slot="0x00" function="0x1"/>
</source>
<address type="pci" domain="0x0000" bus="0x06" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x0a" slot="0x00" function="0x3"/>
</source>
<address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/>
</hostdev>
<memballoon model="virtio">
<address type="pci" domain="0x0000" bus="0x05" slot="0x00" function="0x0"/>
</memballoon>
</devices>
</domain>