8.8 KiB
- Resources from ArchWiki and joeknock's passthrough guide
- Set up IOMMU
- Set up VM
- Installation
- Starting services
- Start default network
- Setup Guest OS
- Launch virt-manager, and start creating guest. On final step, check "Customize before install".
- > In the "Overview" section, set Chipset to "Q35" and firmware to "UEFI".
- > In the "CPUs" section, change CPU model to "host-passthrough". You need to type it manually. According to Arch Wiki, this makes sure that the CPU is detected properly. Without it, some applications may complain about your CPU being of an unknown model.
- > Set Disk Bus of Storage to "virtio".
- > Set NIC Device Model to "virtio".
- Now, you can Begin Installation. You can continue installing Windows right now or after setting up Passthrough.
- Attach PCI devices
- NVIDIA GPU Patching
- Keyboard/mouse Passthrough
- You need to modify libvirt configuration.
- Find your keyboard and mouse devices. Use the devices having event in their name.
- Verify you selected the right device by using following command. You should see output on terminal when using that device..
- Add devices to the configuration. Add it before closing </domain> tag Replace "MOUSE_NAME" and "KEYBOARD_NAME" with your device id.
- Switch from PS/2 to virtio inputs. Add it before mouse/keyboard ps2 config.
- Include these devices in qemu config. You can replace entire file.
- Add user to different groups
- Libvirt Hooks
- Passing VM Audio to Host via Pulseaudio
- Tweaks
Resources from ArchWiki and joeknock's passthrough guide
Set up IOMMU
Enable IOMMU
Load /etc/default/grub and append "intel_iommu=on" or "amd_iommu=on" to GRUB_CMDLINE_LINUX_DEFAULT. Also, "iommu=pt".
Update grub configuration.
grub-mkconfig -o /boot/grub/grub.cfg
Verify IOMMU is enabled successfully
You should see "IOMMU enabled" in output.
dmesg | grep -i -e DMAR -e IOMMU | grep enabled
Set up VM
Installation
Install the required packages.
sudo pacman -S qemu libvirt edk2-ovmf virt-manager dnsmasq ebtables iptables
Get virtio drivers ready
You can't install Windows without virtio drivers. Click here to download.
YOu need to add it to VM CDROM. You'll get "Media driver missing" error when installing Windows. Select '/virtio-disk/amd64/win10'
Install virtio drivers from CDROM after installing Windows to get everything working..
Starting services
Enable and start libvirt service
sudo systemctl enable libvirtd
sudo systemctl start libvirtd
Start default network
This may not be needed. If default network isn't started by default for you, start the network manually.
sudo virsh net-start default
sudo virsh net-autostart default
Setup Guest OS
Launch virt-manager, and start creating guest. On final step, check "Customize before install".
> In the "Overview" section, set Chipset to "Q35" and firmware to "UEFI".
> In the "CPUs" section, change CPU model to "host-passthrough". You need to type it manually. According to Arch Wiki, this makes sure that the CPU is detected properly. Without it, some applications may complain about your CPU being of an unknown model.
> Set Disk Bus of Storage to "virtio".
> Set NIC Device Model to "virtio".
Now, you can Begin Installation. You can continue installing Windows right now or after setting up Passthrough.
Attach PCI devices
Remove devices such as Spice Channel, XQL video adaper, USB tablet, etc.
Click on "Add Hardware" and add PCI devices for GPU and HDMI Audio. For NVIDIA GPU, GPU ROM should be patched. See next section.
NVIDIA GPU Patching
Dump GPU VBIOS
Using GPU-Z in Windows is the easiest method of dumping VBIOS. The following command didn't work for me but it's worth trying.
su
echo 1 > /sys/bus/pci/devices/0000:01:00.0/rom
cat /sys/bus/pci/devices/0000:01:00.0/rom > vbios.rom
echo 0 > /sys/bus/pci/devices/0000:01:00.0/rom
Patch VBIOS file
Use Hex Editor and search string "VIDEO", and remove everything before HEX value 55. There are bunch of 0s or fs usually..
Using Patched VBIOS file
You need to edit configution file of VM.
sudo virsh edit win10
Search for hostdev. Add
<rom file="path/to/your/patched_vbios.rom"/>
before <address> tag.
Keyboard/mouse Passthrough
You need to modify libvirt configuration.
sudo virsh edit win10
Modify first line
<domain type='kvm'>
to
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
Find your keyboard and mouse devices. Use the devices having event in their name.
ls /dev/input/by-id/
Verify you selected the right device by using following command. You should see output on terminal when using that device..
cat /dev/input/by-id/your_device
Add devices to the configuration. Add it before closing </domain> tag Replace "MOUSE_NAME" and "KEYBOARD_NAME" with your device id.
<qemu:commandline>
<qemu:arg value='-object'/>
<qemu:arg value='input-linux,id=mouse1,evdev=/dev/input/by-id/MOUSE_NAME'/>
<qemu:arg value='-object'/>
<qemu:arg value='input-linux,id=kbd1,evdev=/dev/input/by-id/KEYBOARD_NAME,grab_all=on,repeat=on'/>
</qemu:commandline>
Switch from PS/2 to virtio inputs. Add it before mouse/keyboard ps2 config.
<input type='mouse' bus='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/>
</input>
<input type='keyboard' bus='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/>
</input>
Include these devices in qemu config. You can replace entire file.
user = "your_username"
group = "kvm"
cgroup_device_acl = [
"/dev/kvm",
"/dev/input/by-id/KEYBOARD_NAME",
"/dev/input/by-id/MOUSE_NAME",
"/dev/null", "/dev/full", "/dev/zero",
"/dev/random", "/dev/urandom",
"/dev/ptmx", "/dev/kvm", "/dev/kqemu",
"/dev/rtc","/dev/hpet", "/dev/sev"
]
Add user to different groups
Add user to groups input, kvm, libvirt to make sure it has access to required config and devices.
sudo usermod -aG input,kvm,libvirt username
Restart libvirtd service
sudo systemctl restart libvirtd
Libvirt Hooks
Libvirt hooks automates the process of running specific tasks during VM startup and shutdown.
Create libvirt hook
sudo mkdir /etc/libvirt/hooks/
sudo touch /etc/libvirt/hooks/qemu
Add following content to the qemu hook
More at: PassthroughPost
Restart libvirtd service after creating qemu hook
#!/bin/bash
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.
if [ -f "$HOOKPATH" ]; then
eval \""$HOOKPATH"\" "$@"
elif [ -d "$HOOKPATH" ]; then
while read file; do
eval \""$file"\" "$@"
done <<< "$(find -L "$HOOKPATH" -maxdepth 1 -type f -executable -print;)"
fi
Create start script
Create script that gets executed by libvirt hook when you start VM. Script name can be anything..
sudo mkdir -p /etc/libvirt/hooks/qemu.d/win10/prepare/begin
sudo touch /etc/libvirt/hooks/qemu.d/win10/prepare/begin/start.sh
sudo chmod +x /etc/libvirt/hooks/qemu.d/win10/prepare/begin/start.sh
Add the following content to script:
#!/bin/bash
set -x
# Stop display manager
systemctl stop display-manager
# Unbind EFI Framebuffer
echo efi-framebuffer.0 > /sys/bus/platform/drivers/efi-framebuffer/unbind
# Remove nvidia modules from kernel
modprobe -r nvidia_drm nvidia_modeset nvidia_uvm nvidia
# Figure it out AMD
# Detach GPU devices from host
virsh nodedev-detach pci_0000_01_00_0
virsh nodedev-detach pci_0000_01_00_1
# Add vfio-pci to linux kernel
modprobe vfio-pci
Create stop script
Create script that gets executed by libvirt hook when you shutdown/destroy VM. Script name can be anything..
sudo mkdir -p /etc/libvirt/hooks/qemu.d/win10/release/end
sudo touch /etc/libvirt/hooks/qemu.d/win10/release/end/shutdown.sh
sudo chmod +x /etc/libvirt/hooks/qemu.d/win10/release/end/shutdown.sh
Add the following content to script:
#!/bin/bash
set -x
# Remove vfio-pci from kernel
modprobe -r vfio-pci
# Attach GPU devices to host
virsh nodedev-reattach pci_0000_01_00_0
virsh nodedev-reattach pci_0000_01_00_1
# Rebind framebuffer to host
echo "efi-framebuffer.0" > /sys/bus/platform/drivers/efi-framebuffer/bind
# Add NVIDIA modules back to kernel
modprobe nvidia_drm
modprobe nvidia_modeset
modprobe nvidia_uvm
modprobe nvidia
# Restart Display Manager
systemctl start display-manager
Passing VM Audio to Host via Pulseaudio
Virtual machine's audio can be routed to host as an application using libvirt.
Add following config inside <qemu:commandline> tag we set up during keyboard/mouse passthrough.
<qemu:arg value="-audiodev"/>
<qemu:arg value="pa,id=snd0,server=/run/user/1000/pulse/native"/>
Tweaks
NVIDIA has troubles with VM. So, get ready to smash things up.
Switch to full KVM mode
Add to <features> tag.
<ioapic driver='kvm'/>
Error 43 fix
NVIDIA checks if an hypervisor is running and fails if it detects one. It can be fixed by spoofing vendor_id for the hypervisor.
Add to <hyperv> tag
<vendor_id state='on' value='whatever'/>
Add to <features> tag
<kvm>
<hidden state='on'/>
</kvm>