You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qaidvoid 9299bcb6d3 Complete Setup Done 4 years ago
README.org Complete Setup Done 4 years ago

README.org

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.

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