#!/bin/bash # qemu start script for a vm with uefi, tpm 2.0, hyper-v enlightenments and # spice # # note: install virtio drivers and spice-guest-tools set -eEuo pipefail pwd=$(dirname "$0") # vm resources smp=16 mem=32G diskimg="$pwd/overlay.qcow2" # spice settings # password is randomly generated and written to $passwdpipe on each boot spiceaddr=localhost spiceport=5900 spiceuri="spice://$spiceaddr:$spiceport" spicesecret=$(openssl rand -base64 32) passwdpipe="$HOME/.spice_passwd" # uefi firmware files (copy /usr/share/OVMF) ovmfdir="$pwd/OVMF" # tpm settings (use /tmp so apparmor stops complaining) tpmbackup="$pwd/tpm_state.tar" tpmdir="$(mktemp -d)" tpmsock="$tpmdir/swtpm.sock" tpmpid="$tpmdir/swtpm.pid" # restore tpm state if [ -f "$tpmbackup" ]; then tar -xf "$tpmbackup" -C "$tpmdir" fi cleanup() { # kill swtpm daemon if [ -f "$tpmpid" ]; then kill "$(cat "$tpmpid")" 2>/dev/null || true fi # backup tpm state rm -f "$tpmsock" "$tpmpid" "$tpmdir/.lock" tar -cf "$tpmbackup" -C "$tpmdir" . rm -rf "$tpmdir" # delete $passwdpipe rm -f "$passwdpipe" } # print a separator line sep() { printf '%*s' "$(tput cols)" '' | tr ' ' '-' } # print variable pv() { for var in "$@"; do echo "$var = ${!var}" done } trap cleanup EXIT # EXIT includes ERR # print relevant settings sep pv diskimg spiceuri sep # setup named pipe if [ ! -p "$passwdpipe" ]; then rm -rf "$passwdpipe" mkfifo -m 600 "$passwdpipe" fi # write password to pipe (readable only once) echo "$spicesecret" > "$passwdpipe" & # create tpm socket swtpm socket \ --tpm2 \ --daemon \ --tpmstate dir="$tpmdir" \ --ctrl type=unixio,path="$tpmsock" \ --pid file="$tpmpid" # start vm qemu-system-x86_64 \ -enable-kvm \ -m $mem \ -smp $smp,sockets=1,cores=$smp,threads=1 \ -cpu host,hv_relaxed,hv_vapic,hv_vpindex,hv_time,hv_synic,hv_stimer,hv_tlbflush,hv_ipi,hv_reset,hv_frequencies,hv_spinlocks=0x1fff,hv_no-nonarch-coresharing=auto \ -drive if=pflash,format=raw,readonly=on,file="$ovmfdir/OVMF_CODE.fd" \ -drive if=pflash,format=raw,file="$ovmfdir/OVMF_VARS.fd" \ -chardev socket,id=chrtpm,path="$tpmsock" \ -tpmdev emulator,id=tpm0,chardev=chrtpm \ -device tpm-tis,tpmdev=tpm0 \ -device virtio-net-pci,netdev=net0 \ -netdev user,id=net0 \ -object iothread,id=io1 \ -device virtio-blk-pci,drive=disk0,iothread=io1 \ -drive file="$diskimg",if=none,id=disk0,cache=none,aio=io_uring,discard=unmap,detect-zeroes=unmap \ -device virtio-rng-pci \ -vga qxl \ -object secret,id=spicesecret,file=/dev/fd/3 \ -spice port=$spiceport,addr=$spiceaddr,password-secret=spicesecret,streaming-video=off,image-compression=quic,playback-compression=on,jpeg-wan-compression=always,agent-mouse=on \ -device qemu-xhci,id=usb \ -device usb-tablet,bus=usb.0 \ -device virtio-serial-pci \ -chardev spicevmc,id=vdagent,name=vdagent \ -device virtserialport,chardev=vdagent,name=com.redhat.spice.0 \ -chardev spiceport,name=org.spice-space.webdav.0,id=charchannel1 \ -device virtserialport,chardev=charchannel1,name=org.spice-space.webdav.0 \ -rtc clock=host \ -monitor stdio \ 3<<<"$spicesecret"