Skip to content

Instantly share code, notes, and snippets.

@shikanime
Last active June 7, 2018 17:33
Show Gist options
  • Save shikanime/425c5a6fd6e610b223ba6e3996e3d479 to your computer and use it in GitHub Desktop.
Save shikanime/425c5a6fd6e610b223ba6e3996e3d479 to your computer and use it in GitHub Desktop.
Ubuntu host KVM PCI passthough
# Check if hugepages is enable
hugeadm --explain
# Check dmesg to ensure that pci-stub has claimed the devices correctly
dmesg | grep pci-stub
# First check if the system is in UEFI mode
# If this isn't populated the system isn't in UEFI mode
dmesg | grep -i efi
# Update and install Qemu/KVM
sudo apt-get update
sudo apt-get install qemu-kvm qemu-utils qemu-efi ovmf libvirt-bin libvirt-dev libvirt0 virt-manager
# Load KVM kernel modules at boot time
echo "# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
pci_stub
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd
kvm
kvm_intel
" | sudo tee /etc/modules
# Enable IOMMU in GRUB
sudo sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT.*/GRUB_CMDLINE_LINUX_DEFAULT="modprobe.blacklist=nouveau quiet intel_iommu=on" /g' /etc/default/grub
sudo update-grub
# Reboot system
reboot
# Check IOMMU is working
# To ensure IOMMU has been enabled, check for the string Directed I/O, which will be prefixed with either DMAR or PCI-DMA.
dmesg | grep -i 'Directed I/O'
echo "
# Enable IPv4 forwarding
net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.conf.default.proxy_arp=1
# Enable IPv6 forwarding & IPv6 Autoconfiguration (optional)
net.ipv6.conf.all.autoconf = 0
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.proxy_ndp=1
" | sudo tee --append /etc/sysctl.conf
# Network interfaces
# auto lo
# iface lo inet loopback
# auto eno1
# iface eno1 inet manual
# iface eno1 inet6 manual
# auto vbr0
# iface vbr0 inet static
# address YOUR_IPV4_ADDRESS
# netmask YOUR_IPV4_NETMASK
# gateway YOUR_IPV4_GATEWAY
# bridge_ports eno1
# bridge_stp off
# bridge_waitport 0
# bridge_fd 0
# iface vbr0 inet6 static
# address YOUR_IPV6_ADDRESS
# netmask 64
# gateway YOUR_IPV6_GATEWAY
# bridge_ports eno1
# bridge_stp off
# bridge_waitport 0
# bridge_fd 0
# Search for PCI graphic card and their HDMI audio buddies
# In the [...] is composed in VID:PID
# e.g. In this case 1002:67df has a vendor ID of 0x1002 and product ID of 0x67df
# We also need to remember the location (first column), which we will use to determine IOMMU groupings.
for dp in $(find /sys/kernel/iommu_groups/*/devices/*); do
ploc=$(basename $dp | sed 's/0000://');
igrp=$(echo $dp | awk -F/ '{print $5}');
dinfo=$(lspci -nn | grep -E "^$ploc");
echo "[IOMMU $igrp] $dinfo";
done
# pci_stub ids=VID:PID,VID:PID,
for arg in "$@"; do
echo "pci_stub ids=$arg" | sudo tee --append /etc/initramfs-tools/modules
done
# TODO: Add note 1
# Rebuild initrd image
sudo update-initramfs -u
# TODO: Add note 2
# Reboot
reboot
# Note 1
# # Open or create /etc/modprobe.d/local.conf:
# gksudo xed /etc/modprobe.d/local.conf
# # and insert the following:
# options vfio-pci ids=VID:PID
# # To load vfio and other required modules at boot, edit the /etc/initramfs-tools/modules file:
# gksudo xed /etc/initramfs-tools/modules
# # At the end of the file add:
# vfio
# vfio_iommu_type1
# vfio_pci
# vfio_virqfd
# vhost-net
# Note 2 - step 1
# # If you get
# # hugeadm:ERROR: No hugetlbfs mount points found
# # then you need to enable hugepages. To do so, edit /etc/default/qemu-kvm as root:
# gksudo xed /etc/default/qemu-kvm
# # and add or uncomment
# KVM_HUGEPAGES=1
# Note 2 - step 2
# We want to reserve 8GB for Windows:
# 8GB = 8x1024MB = 8192MB
# Our hugepage size is 2MB, so we need to reserve:
# 8192MB/2MB = 4096 hugepages
# We need to add some % extra space for overhead (some say 2%, some say 10%), to be on the safe side I use 4500 (if memory is scarce, you should be OK with 4300, perhaps less – see comments here).
# gksudo xed /etc/sysctl.conf
# # Then add the following lines into the file:
# # Set hugetables / hugepages for KVM single guest using 8GB RAM
# vm.nr_hugepages = 4500
# Note the sub-optimal shmmax value. We fix it temporarily with:
# sudo hugeadm --set-recommended-shmmax
# And permanently by editing /etc/sysctl.conf:
# gksudo xed /etc/sysctl.conf
# and adding the following line:
# kernel.shmmax = 9437184000
#!/bin/bash
vmname="windows10vm"
if ps -A | grep -q $vmname; then
echo "$vmname is already running." &
exit 1
else
# use pulseaudio
export QEMU_AUDIO_DRV=pa
export QEMU_PA_SAMPLES=8192
export QEMU_AUDIO_TIMER_PERIOD=99
export QEMU_PA_SERVER=/run/user/1000/pulse/native
cp /usr/share/OVMF/OVMF_VARS.fd /tmp/my_vars.fd
qemu-system-x86_64 \
-name $vmname,process=$vmname \
-machine type=q35,accel=kvm \
-cpu host,kvm=off \
-smp 4,sockets=1,cores=2,threads=2 \
-m 8G \
-mem-path /run/hugepages/kvm \
-mem-prealloc \
-balloon none \
-rtc clock=host,base=localtime \
-vga none \
-nographic \
-serial none \
-parallel none \
-soundhw hda \
-usb -usbdevice host:045e:076c -usbdevice host:045e:0750 \
-device vfio-pci,host=02:00.0,multifunction=on \
-device vfio-pci,host=02:00.1 \
-drive if=pflash,format=raw,readonly,file=/usr/share/OVMF/OVMF_CODE.fd \
-drive if=pflash,format=raw,file=/tmp/my_vars.fd \
-boot order=dc \
-drive id=disk0,if=virtio,cache=none,format=raw,file=/media/user/win.img \
-drive file=/home/user/ISOs/win10.iso,index=1,media=cdrom \
-drive file=/home/user/Downloads/virtio-win-0.1.140.iso,index=2,media=cdrom \
-netdev type=tap,id=net0,ifname=vmtap0,vhost=on \
-device virtio-net-pci,netdev=net0,mac=00:16:3e:00:01:01
exit 0
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment