Skip to content

Instantly share code, notes, and snippets.

@PedroHLC
Last active August 28, 2019 20:18
Show Gist options
  • Save PedroHLC/427d71bef2f2f6d45609edae3c0eb51e to your computer and use it in GitHub Desktop.
Save PedroHLC/427d71bef2f2f6d45609edae3c0eb51e to your computer and use it in GitHub Desktop.
Script used in UFSCar for running guest computers using vfio passthrough
#!/usr/bin/env sh
# ======================================================================================
# Maintaned by Pedro H Lara Campos <[email protected]>
# Contributors:
# Marcos Laerte
# Paulo Matias
# Version: 2019.08.28-6
# --------------------------------------------------------------------------------------
: ${PSEUDO_RUN:=0}
# Power off baremetal if this script ends (expected or not)
function exit_gracefully() {
[ '1' = "$PSEUDO_RUN" ] || poweroff
}
trap exit_gracefully EXIT HUP INT TERM
set -o errexit
# ======================================================================================
# * Constants and Settings
# --------------------------------------------------------------------------------------
# ** SIn Machines
# ======================================================================================
# OptiPlex 7010
readonly _O7010_ID='OptiPlex 7010'
# sequence: video, usb, usb, xhci, audio
readonly _O7010_BUS="\
0000:00:02.0 \
0000:00:1d.0 \
0000:00:1a.0 \
0000:00:14.0 \
0000:00:1b.0"
readonly _O7010_DEV="\
8086 0162 \
8086 1e26 \
8086 1e31 \
8086 1e2d \
8086 1e20"
# OptiPlex 7040
readonly _O7040_ID='OptiPlex 7040'
# sequence: video, usb, usb, xhci, audio, isa, memctrl, smbus
readonly _O7040_BUS="\
0000:00:02.0 \
0000:00:14.0 \
0000:00:14.2 \
0000:00:1f.3 \
0000:00:1f.0 \
0000:00:1f.2 \
0000:00:1f.4"
readonly _O7040_DEV="\
8086 1912 \
8086 a12f \
8086 a131 \
8086 a170 \
8086 a146 \
8086 a121 \
8086 a123"
# OptiPlex 9020
readonly _O9020_ID='OptiPlex 9020'
# sequence: video, usb, usb, xhci, audio
readonly _O9020_BUS="\
0000:00:02.0 \
0000:00:1d.0 \
0000:00:1a.0 \
0000:00:14.0 \
0000:00:1b.0"
readonly _O9020_DEV="\
'8086 0412' \
'8086 8c26' \
'8086 8c2d' \
'8086 8c31' \
'8086 8c20'"
# --------------------------------------------------------------------------------------
# ** QEMU Parameters
# ======================================================================================
readonly _QEMU_ARGS_BASE="\
-accel kvm \
-m 7G \
-cpu host \
-smp cores=`nproc` \
-machine pc \
-nodefaults \
-device virtio-scsi-pci,id=scsi \
-boot menu=off"
readonly _QEMU_WIN='-rtc base=localtime,clock=vm'
readonly _QEMU_NIX='-serial mon:stdio'
# ======================================================================================
# * Failure Functions
# ======================================================================================
wrong_args() {
echo 'Incorrect parameters usage, use: run_guest.sh [OSTYPE] [RAW_DRIVE]' 1>&2
exit 11
}
invalid_ostype() {
echo 'Invalid OSTYPE' 1>&2
exit 12
}
invalid_main_drive() {
echo 'Invalid RAW_DRIVE' 1>&2
exit 13
}
invalid_machine() {
echo 'Not running on a valid machine' 1>&2
exit 14
}
error_real_iface() {
echo 'Default network interface not found' 1>&2
exit 15
}
error_guest_mac() {
echo 'Impossible to guest/generate mac address' 1>&2
exit 16
}
# ======================================================================================
# * Main Functions
# ======================================================================================
parse_args() {
_OSTYPE="$1"
_MAIN_DRIVE="$2"
([ '' = "$_OSTYPE" ] || [ '' = "$_MAIN_DRIVE" ]) && wrong_args
[ -f "$_MAIN_DRIVE" ] || invalid_main_drive
}
detect_machine() {
case "`cctk --sysname | sed 's/^sysname=//'`" in
"$_O7010_ID")
_VFIO_BUS="${_O7010_BUS}";
_VFIO_DEV="${_O7010_DEV}";;
"$_O7040_ID")
_VFIO_BUS="${_O7040_BUS}";
_VFIO_DEV="${_O7040_DEV}";;
"$_O9020_ID")
_VFIO_BUS="${_O9020_BUS}";
_VFIO_DEV="${_O9020_DEV}";;
*)
invalid_machine;;
esac
}
vfio_all() {
[ '1' = "$PSEUDO_RUN" ] && return
for _PCI in ${_VFIO_BUS}; do
continue echo "$_PCI" > /sys/bus/pci/devices/"$_PCI"/driver/unbind
while [ -d " /sys/bus/pci/devices/"$_PCI"/driver" ]; do
sleep 1
echo "$_PCI" > /sys/bus/pci/devices/"$_PCI"/driver/unbind
done
done
for _PCI in ${_VFIO_DEV}; do
continue echo "$_PCI" > /sys/bus/pci/drivers/vfio-pci/new_id
while [ -d " /sys/bus/pci/devices/"$_PCI"/driver" ]; do
sleep 1
echo "$_PCI" > /sys/bus/pci/drivers/vfio-pci/new_id
done
done
}
detect_guest() {
case "$_OSTYPE" in
'windows')
_QEMU_ARGS="${_QEMU_ARGS} ${_QEMU_WIN}";;
'linux')
_QEMU_ARGS="${_QEMU_ARGS} ${_QEMU_NIX}";;
*)
invalid_guest;;
esac
}
prepare_guest_mac() {
_REAL_IFACE=`ip route show default | awk '/default/ {print $5}'`
[ '' = "$_REAL_IFACE" ] && error_real_iface
_GUEST_MAC=`cat /sys/class/net/${_REAL_IFACE}/address |\
sed 's/^..:..:../00:16:3E/'`
[ '' = "$_GUEST_MAC" ] && error_guest_mac
}
prepare_qemu_args() {
_QEMU_ARGS="${_QEMU_ARGS_BASE}"
for _PCI in ${_VFIO_BUS}; do
_PCI_SPLT="`echo "$_PCI" | sed 's/[:\.]/ /g'`"
set -- $_PCI_SPLT
_QEMU_ARGS="${_QEMU_ARGS} \
-device vfio-pci-nohotplug,host=$1:$2.$3,bus=pci.$2,addr=0x$3"
done
_QEMU_ARGS="${_QEMU_ARGS} \
-drive if=none,id=hd_sys,file=/dev/zvol/${_MAIN_DRIVE},format=raw \
-device scsi-hd,drive=hd_sys \
-netdev user,hostfwd=tcp:0.0.0.0:3389-:3389,id=net_sys,macaddr=$_GUEST_MAC \
-device virtio-net-pci,netdev=net_sys"
detect_guest
}
run_qemu() {
if [ '1' = "$PSEUDO_RUN" ]; then
echo "$_QEMU_ARGS"
else
qemu-system-x86_64 $_QEMU_ARGS
fi
}
# ======================================================================================
# * Main routine
# ======================================================================================
parse_args $@
detect_machine
vfio_all
prepare_qemu_args
run_qemu
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment