Setup Script for VGA Passthrough in Arch-Linux

Hi,

i'm using vga passthrough in arch-linux (host) for windows (guest).

My Specs:
i7 5820k
MSI x99S sli plus
Host gpu: evga gtx 960
guest gpu: sapphire r9 290x vapor

It works great for over a year now. So i thought i should write a setup script for when i have to set up from scratch.

It is by no means perfect or can be used in all cases.
It also assumes that the gpus in the pcie lanes will end up in different iommu groups,
that the gpu to be isolated is alone in its group,
that you're using grub as bootloader,
that the arch install is kinda fresh,
and that the two gpus are one nvidia and one amd.

What it does is set up a folder in home directory where all the VM stuff will be put.
After asking some questions it configures grub and some other files and puts/creates the necessary
qemu-scripts in this folder. The generated "qemu_setup.sh" needs basically only be used once to install windows.
For a daily use the script sets it up that one only need to start the newly created "windows" "program" with one click for example.

Besides the assumptions from above the script might also work on an arch installation that is already in use.

I'm planing to install opensuse, fedora maybe ubuntu and try to get the passthrough working and adapt the script for those options too.

TL;DR
Long story short, here is a script that sets up vga passthrough in arch. Maybe someone other than me has use for it :slight_smile:

Use at your own risk:

 #!/bin/bash
echo "Please run this script in your home folder!"
printf "\n"
echo "Choose the brand of the GPU that will be isolated for the guest "
echo "1: AMD  2:Nvidia"
read vgaChoice
if [ $vgaChoice -eq 1 ]
then
        var_vgaBrand=amd
elif [ $vgaChoice -eq 2 ]
then
        var_vgaBrand=nvidia
else
        echo "start over"
        exit
fi

var_user=$(whoami)

echo "Download the file with the pattern:"
echo "edk2.git-ovmf-*.noarch.rpm"
echo "from the following link:"
echo "https://www.kraxel.org/repos/jenkins/edk2/"
echo "Save it in your home folder and then press enter to continue"
read 
edk2file=$(find edk2*ovmf*)
echo "Enter the folder name you want to store all the virtual machine stuff in, it will be created in your home folder:"
read var_foldername
printf "\n"
mkdir $var_foldername 
echo "Give the virtual harddrive a name:"
read var_hddname
printf "\n"
echo "Enter the size you want the virtual HDD to have (e.g. 15G):"
read var_hddsize
printf "\n"
echo "Download Windows-ISO and put it in the folder you specified above. \n Enter the full name (excluding extension) of the ISO:"
read var_isoName
printf "\n"
echo "Enter the size of the memory you want to allocate to the guest in Megabyte:"
read var_memory
printf "\n"
echo "Enter the Number of cores (hyperthreading included) that will be allocated to guest:"
read var_threads
printf "\n"
echo "Enter the Number of physical cores you want to allocate to the guest:"
read var_cores
printf "\n"

var_pciID1=$(lspci -nn | grep -i "vga compatible"| grep -i $var_vgaBrand | awk '{print $NF}')
var_pciID1=${var_pciID1:1:9}
var_pciNR1=$(lspci -nn | grep -i "vga compatible"| grep -i $var_vgaBrand | awk '{print $1}')
var_pciID2=$(lspci -nn | grep -i "audio device"| grep -i $var_vgaBrand | awk '{print $NF}')
var_pciID2=${var_pciID2:1:9}
var_pciNR2=$(lspci -nn | grep -i "audio device"| grep -i $var_vgaBrand | awk '{print $1}')

cd /home/$var_user
sudo pacman -Syyuu

sudo sed -i "/#Server = file:\/\/\/home\/custompkgs/a[multilib]\nInclude = \/etc\/pacman.d\/mirrorlist \n\n[archlinuxfr] \nSigLevel = Optional \nServer = http:\/\/repo.archlinux.fr\/\$arch" "/etc/pacman.conf"
sudo pacman -Syyuu
sudo pacman -S --noconfirm wget qemu ovmf libvirt rpmextract   

sudo sed -i "s/GRUB_CMDLINE_LINUX=\"\"/GRUB_CMDLINE_LINUX=\"intel_iommu=on vfio-pci.ids=$var_pciID1,$var_pciID2\"/" "/etc/default/grub"
sudo sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="quiet"/#GRUB_CMDLINE_LINUX_DEFAULT="quiet"/' /etc/default/grub
sudo sed -i 's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=0.5/' /etc/default/grub
sudo sed -i 's/MODULES=""/MODULES="vfio vfio-pci vfio_iommu_type1 vfio_virqfd"/' /etc/mkinitcpio.conf 

sudo touch /etc/udev/rules.d/10-qemu-hw-users.rules
sudo sh -c "echo abc1 >> /etc/udev/rules.d/10-qemu-hw-users.rules"
sudo sh -c "echo abc2 >> /etc/udev/rules.d/10-qemu-hw-users.rules"
sudo sh -c "echo abc3 >> /etc/udev/rules.d/10-qemu-hw-users.rules"
sudo sed -i "s/abc1/SUBSYSTEM==\"vfio\", OWNER=\"$var_user\"/" "/etc/udev/rules.d/10-qemu-hw-users.rules"
sudo sed -i "s/abc2/SUBSYSTEM==\"usb\", OWNER=\"$var_user\"/"  "/etc/udev/rules.d/10-qemu-hw-users.rules"
sudo sed -i "s/abc3/SUBSYSTEM==\"sda1\", OWNER=\"$var_user\"/" "/etc/udev/rules.d/10-qemu-hw-users.rules"
sudo sed -i "/#user = \"root\"/auser = \"$var_user\"" "/etc/libvirt/qemu.conf"
sudo sed -i 's/#nvram = \[/nvram = \[/' /etc/libvirt/qemu.conf
sudo sed -i '/nvram = \[/a"\/usr\/share\/edk2.git\/ovmf-x64\/OVMF_CODE-pure-efi.fd:\/usr\/share\/edk2.git\/ovmf-x64\/OVMF_VARS-pure-efi.fd", \n\]' /etc/libvirt/qemu.conf

sudo sed -i 's/#cgroup_device_acl = \[/cgroup_device_acl = \[/' /etc/libvirt/qemu.conf
sudo sed -i '/cgroup_device_acl = \[/a "\/dev\/null", "\/dev\/full", "\/dev\/zero", \n "\/dev\/random", "\/dev\/urandom", \n "\/dev\/ptmx", "\/dev\/kvm", "\/dev\/kqemu", \n "\/dev\/rtc","\/dev\/hpet", "\/dev\/vfio\/vfio", \n "\/dev\/vfio\/32" \n\]' /etc/libvirt/qemu.conf

sudo  mkinitcpio -p linux
sudo grub-mkconfig -o /boot/grub/grub.cfg

mkdir -p  /tmp/efi
mv $edk2file /tmp/efi/$edk2file
cd /tmp/efi/
rpmextract.sh $edk2file
rm $edk2file
sudo cp -R . /
cd ~/

cd $var_foldername
wget https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso
qemu-img create -f qcow2 $var_hddname.qcow2 $var_hddsize

echo "cp /usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd /tmp/my_vars.fd" >> qemu_setup.sh
echo "qemu-system-x86_64  \\" >> qemu_setup.sh
echo " -enable-kvm  \\" >> qemu_setup.sh
echo " -m $var_memory  \\" >> qemu_setup.sh
echo " -cpu host,kvm=off,check  \\" >> qemu_setup.sh
echo " -smp $var_threads,sockets=1,cores=$var_cores,threads=2 \\" >> qemu_setup.sh
echo " -device vfio-pci,host=$var_pciNR1,multifunction=on  \\" >> qemu_setup.sh
echo " -device vfio-pci,host=$var_pciNR2  \\" >> qemu_setup.sh
echo " -drive if=pflash,format=raw,readonly,file=/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd   \\" >> qemu_setup.sh
echo " -drive if=pflash,format=raw,file=/tmp/my_vars.fd  \\" >> qemu_setup.sh
echo " -device virtio-scsi-pci,id=scsi  \\" >> qemu_setup.sh
echo " -drive if=virtio,id=drive0,file=/home/$var_user/$var_foldername/$var_hddname.qcow2,format=qcow2,format=qcow2,cache=none,aio=native  \\" >> qemu_setup.sh
echo " -boot order=d  \\" >> qemu_setup.sh
echo " -device ide-cd,drive=drive-cd-disk1,id=cd-disk1,unit=0,bus=ide.0  \\" >> qemu_setup.sh
echo " -drive file=/home/$var_user/$var_foldername/$var_isoName.iso,if=none,id=drive-cd-disk1,media=cdrom  \\" >> qemu_setup.sh
echo " -device ide-cd,drive=drive-cd-disk2,id=cd-disk2,unit=0,bus=ide.1  \\" >> qemu_setup.sh
echo " -drive file=/home/oli/VirtualMachine/virtio-win.iso,if=none,id=drive-cd-disk2,media=cdrom" >> qemu_setup.sh

echo "cp /usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd /tmp/my_vars.fd" >> qemu_run.sh
echo "qemu-system-x86_64  \\" >> qemu_run.sh
echo " -enable-kvm  \\" >> qemu_run.sh
echo " -m $var_memory  \\" >> qemu_run.sh
echo " -cpu host,kvm=off,check  \\" >> qemu_run.sh
echo " -smp $var_threads,sockets=1,cores=$var_cores,threads=2 \\" >> qemu_run.sh
echo " -device vfio-pci,host=$var_pciNR1,multifunction=on  \\" >> qemu_run.sh
echo " -device vfio-pci,host=$var_pciNR2  \\" >> qemu_run.sh
echo " -drive if=pflash,format=raw,readonly,file=/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd   \\" >> qemu_run.sh
echo " -drive if=pflash,format=raw,file=/tmp/my_vars.fd  \\" >> qemu_run.sh
echo " -device virtio-scsi-pci,id=scsi  \\" >> qemu_run.sh
echo " -drive if=virtio,id=drive0,file=/home/$var_user/$var_foldername/$var_hddname.qcow2,format=qcow2,format=qcow2,cache=none,aio=native  \\" >> qemu_run.sh
echo " -device ide-cd,drive=drive-cd-disk1,id=cd-disk1,unit=0,bus=ide.0  \\" >> qemu_run.sh
echo " -drive file=/home/oli/VirtualMachine/virtio-win.iso,if=none,id=drive-cd-disk1,media=cdrom" >> qemu_run.sh
chmod +x qemu_run.sh
chmod +x qemu_setup.sh

wget https://cdn2.iconfinder.com/data/icons/metro-uinvert-dock/256/OS_Windows_8.png 
mv OS_Windows_8.png IconWindows.png
sudo touch /usr/share/applications/Windows.desktop
sudo sh -c "echo [Desktop Entry] >> /usr/share/applications/Windows.desktop"
sudo sh -c "echo Name=Windows >> /usr/share/applications/Windows.desktop"
sudo sh -c "echo Comment=Virtual Machine for Gaming with Windows >> /usr/share/applications/Windows.desktop"
sudo sh -c "echo abc123 >> /usr/share/applications/Windows.desktop"
sudo sed -i "s/abc123/Exec=\/home\/$var_user\/$var_foldername\/qemu_run.sh %U/" "/usr/share/applications/Windows.desktop"
sudo sh -c "echo abc123 >> /usr/share/applications/Windows.desktop"
sudo sed -i "s/abc123/Icon=\/home\/$var_user\/$var_foldername\/IconWindows.png/" "/usr/share/applications/Windows.desktop"
sudo sh -c "echo Terminal=false  >> /usr/share/applications/Windows.desktop"
sudo sh -c "echo Type=Application  >> /usr/share/applications/Windows.desktop"
sudo sh -c "echo Categories=Virtual-Machine\;  >> /usr/share/applications/Windows.desktop"

cd ~/
echo "After you hit enter the system will reboot"
read
sudo reboot
2 Likes

Just a note:

You can use

```bash
[...]
```

codeblocks to format that code for easier readability :slight_smile:

awesome thanks! :slight_smile: