launch-qemu.sh (9626B)
1#!/bin/bash 2 3# 4# user changeable parameters 5# 6HDA="/home/amd/fedora-30.raw" 7MEM="2048" 8SMP="4" 9VNC="" 10CONSOLE="serial" 11USE_VIRTIO="1" 12 13SEV="0" 14SEV_ES="0" 15SEV_SNP="0" 16ALLOW_DEBUG="0" 17USE_GDB="0" 18 19EXEC_PATH="$PREFIX/usr/local" 20UEFI_PATH="$EXEC_PATH/share/qemu" 21 22usage() { 23 echo "$0 [options]" 24 echo "Available <commands>:" 25 echo " -sev launch SEV guest" 26 echo " -sev-es launch SEV guest" 27 echo " -sev-snp launch SNP guest" 28 echo " -bios the bios to use (default $UEFI_PATH)" 29 echo " -hda PATH hard disk file (default $HDA)" 30 echo " -mem MEM guest memory size in MB (default $MEM)" 31 echo " -smp NCPUS number of virtual cpus (default $SMP)" 32 echo " -cdrom CDROM image" 33 echo " -allow-debug dump vmcb on exit and enable the trace" 34 exit 1 35} 36 37add_opts() { 38 echo -n "$* " >> ${QEMU_CMDLINE} 39} 40 41exit_from_int() { 42 stop_network 43 rm -rf ${QEMU_CMDLINE} 44 # restore the mapping 45 stty intr ^c 46 exit 1 47} 48 49run_cmd () { 50 $* 51 if [ $? -ne 0 ]; then 52 echo "command $* failed" 53 exit 1 54 fi 55} 56 57get_cbitpos() { 58 modprobe cpuid 59 # 60 # Get C-bit position directly from the hardware 61 # Reads of /dev/cpu/x/cpuid have to be 16 bytes in size 62 # and the seek position represents the CPUID function 63 # to read. 64 # The skip parameter of DD skips ibs-sized blocks, so 65 # can't directly go to 0x8000001f function (since it 66 # is not a multiple of 16). So just start at 0x80000000 67 # function and read 32 functions to get to 0x8000001f 68 # To get to EBX, which contains the C-bit position, skip 69 # the first 4 bytes (EAX) and then convert 4 bytes. 70 # 71 72 EBX=$(dd if=/dev/cpu/0/cpuid ibs=16 count=32 skip=134217728 | tail -c 16 | od -An -t u4 -j 4 -N 4 | sed -re 's|^ *||') 73 CBITPOS=$((EBX & 0x3f)) 74} 75 76trap exit_from_int SIGINT 77 78if [ `id -u` -ne 0 ]; then 79 echo "Must be run as root!" 80 exit 1 81fi 82 83while [ -n "$1" ]; do 84 case "$1" in 85 -sev-snp) SEV_SNP="1" 86 SEV_ES="1" 87 SEV="1" 88 ;; 89 -sev-es) SEV_ES="1" 90 SEV="1" 91 ;; 92 -sev) SEV="1" 93 ;; 94 -hda) HDA="$2" 95 shift 96 ;; 97 -cdrom) CDROM_FILE="$2" 98 shift 99 ;; 100 -mem) MEM="$2" 101 shift 102 ;; 103 -smp) SMP="$2" 104 shift 105 ;; 106 -vnc) VNC="$2" 107 shift 108 if [ "$VNC" = "" ]; then 109 usage 110 fi 111 ;; 112 -console) CONSOLE="$2" 113 shift 114 ;; 115 -bios) UEFI_PATH="$2" 116 shift 117 ;; 118 -allow-debug) ALLOW_DEBUG="1" 119 ;; 120 -novirtio) USE_VIRTIO="0" 121 ;; 122 -kernel) KERNEL_FILE=$2 123 shift 124 ;; 125 -initrd) INITRD_FILE=$2 126 shift 127 ;; 128 -append) APPEND="$2" 129 shift 130 ;; 131 *) echo "Calling usage, cannot understand argument $1"; usage 132 ;; 133 esac 134 135 shift 136done 137 138TMP="$EXEC_PATH/bin/qemu-system-x86_64" 139QEMU_EXE="$(readlink -e $TMP)" 140[ -z "$QEMU_EXE" ] && { 141 echo "Can't locate qemu executable [$TMP]" 142 usage 143} 144 145[ -n "$HDA" ] && { 146 TMP="$HDA" 147 HDA="$(readlink -e $TMP)" 148 [ -z "$HDA" ] && { 149 echo "Can't locate guest image file [$TMP]" 150 usage 151 } 152 153 GUEST_NAME="$(basename $TMP | sed -re 's|\.[^\.]+$||')" 154} 155 156[ -n "$CDROM_FILE" ] && { 157 TMP="$CDROM_FILE" 158 CDROM_FILE="$(readlink -e $TMP)" 159 [ -z "$CDROM_FILE" ] && { 160 echo "Can't locate CD-Rom file [$TMP]" 161 usage 162 } 163 164 [ -z "$GUEST_NAME" ] && GUEST_NAME="$(basename $TMP | sed -re 's|\.[^\.]+$||')" 165} 166 167setup_bridge_network() { 168 BRIDGE_DEV="virbr0" 169 # Get last tap device on host 170 TAP_NUM=`ifconfig | grep tap | tail -1 | cut -c4- | cut -f1 -d ' ' | cut -f1 -d:` 171 if [ "$TAP_NUM" = "" ]; then 172 TAP_NUM="1" 173 fi 174 TAP_NUM=`echo $(( TAP_NUM + 1 ))` 175 GUEST_TAP_NAME="tap${TAP_NUM}" 176 177 [ "$USE_VIRTIO" = "1" ] && PREFIX="52:54:00" || PREFIX="02:16:1e" 178 SUFFIX="$(ip address show dev ${BRIDGE_DEV} | grep link/ether | awk '{print $2}' | awk -F : '{print $4 ":" $5}')" 179 GUEST_MAC_ADDR="$(printf "%s:%s:%02x" $PREFIX $SUFFIX $TAP_NUM)" 180 181 echo "Starting network adapter '${GUEST_TAP_NAME}' MAC=$GUEST_MAC_ADDR" 182 run_cmd "ip tuntap add $GUEST_TAP_NAME mode tap user `whoami`" 183 run_cmd "ip link set $GUEST_TAP_NAME up" 184 run_cmd "ip link set $GUEST_TAP_NAME master ${BRIDGE_DEV}" 185 186 if [ "$USE_VIRTIO" = "1" ]; then 187 add_opts "-netdev type=tap,script=no,downscript=no,id=net0,ifname=$GUEST_TAP_NAME" 188 add_opts "-device virtio-net-pci,mac=${GUEST_MAC_ADDR},netdev=net0,disable-legacy=on,iommu_platform=true,romfile=" 189 else 190 add_opts "-netdev tap,id=net0,ifname=$GUEST_TAP_NAME,script=no,downscript=no" 191 add_opts "-device e1000,mac=${GUEST_MAC_ADDR},netdev=net0,romfile=" 192 fi 193} 194stop_network() { 195 if [ "$GUEST_TAP_NAME" = "" ]; then 196 return 197 fi 198 run_cmd "ip tuntap del ${GUEST_TAP_NAME} mode tap" 199} 200 201TMP="$UEFI_PATH/OVMF_CODE.fd" 202UEFI_CODE="$(readlink -e $TMP)" 203[ -z "$UEFI_CODE" ] && { 204 echo "Can't locate UEFI code file [$TMP]" 205 usage 206} 207 208[ -e "./$GUEST_NAME.fd" ] || { 209 TMP="$UEFI_PATH/OVMF_VARS.fd" 210 UEFI_VARS="$(readlink -e $TMP)" 211 [ -z "$UEFI_VARS" ] && { 212 echo "Can't locate UEFI variable file [$TMP]" 213 usage 214 } 215 216 run_cmd "cp $UEFI_VARS ./$GUEST_NAME.fd" 217} 218UEFI_VARS="$(readlink -e ./$GUEST_NAME.fd)" 219 220if [ "$ALLOW_DEBUG" = "1" ]; then 221 # This will dump all the VMCB on VM exit 222 echo 1 > /sys/module/kvm_amd/parameters/dump_all_vmcbs 223 224 # Enable some KVM tracing to the debug 225 #echo kvm: >/sys/kernel/debug/tracing/set_event 226 #echo kvm:* >/sys/kernel/debug/tracing/set_event 227 #echo kvm:kvm_page_fault >/sys/kernel/debug/tracing/set_event 228 #echo >/sys/kernel/debug/tracing/set_event 229 #echo > /sys/kernel/debug/tracing/trace 230 #echo 1 > /sys/kernel/debug/tracing/tracing_on 231fi 232 233# we add all the qemu command line options into a file 234QEMU_CMDLINE=/tmp/cmdline.$$ 235rm -rf $QEMU_CMDLINE 236 237add_opts "taskset --cpu-list 2 $QEMU_EXE" 238 239add_opts "-s" 240 241#add_opts "-device vfio-pci,host=00:01.0,id=net10" 242 243# Basic virtual machine property 244add_opts "-enable-kvm -cpu EPYC-v4 -machine q35" 245 246# add number of VCPUs 247[ -n "${SMP}" ] && add_opts "-smp ${SMP},maxcpus=8" 248 249# define guest memory 250add_opts "-m ${MEM}M,slots=5,maxmem=30G" 251 252# don't reboot for SEV-ES guest 253add_opts "-no-reboot" 254 255# The OVMF binary, including the non-volatile variable store, appears as a 256# "normal" qemu drive on the host side, and it is exposed to the guest as a 257# persistent flash device. 258add_opts "-drive if=pflash,format=raw,unit=0,file=${UEFI_CODE},readonly" 259add_opts "-drive if=pflash,format=raw,unit=1,file=${UEFI_VARS}" 260 261# add CDROM if specified 262[ -n "${CDROM_FILE}" ] && add_opts "-drive file=${CDROM_FILE},media=cdrom -boot d" 263 264# check if host has bridge network 265BR0_STATUS="$(ip link show virbr0 type bridge 2>/dev/null)" 266if [ -n "$BR0_STATUS" ]; then 267 setup_bridge_network 268else 269 # Louis: Added port forwarding 270 add_opts "-netdev user,id=vmnic,hostfwd=tcp::8000-:22 -device e1000,netdev=vmnic,romfile=" 271fi 272 273# add network support and fwd port 22 to 8000 274# echo "guest port 22 is fwd to host 8000..." 275# add_opts "-netdev user,id=vmnic,hostfwd=tcp::8000-:22 -device e1000,netdev=vmnic,romfile=" 276# add_opts "-netdev user,id=vmnic" 277# add_opts " -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile=" 278 279# If harddisk file is specified then add the HDD drive 280if [ -n "${HDA}" ]; then 281 if [ "$USE_VIRTIO" = "1" ]; then 282 if [[ ${HDA} = *"qcow2" ]]; then 283 add_opts "-drive file=${HDA},if=none,id=disk0,format=qcow2" 284 else 285 add_opts "-drive file=${HDA},if=none,id=disk0,format=raw" 286 fi 287 add_opts "-device virtio-scsi-pci,id=scsi0,disable-legacy=on,iommu_platform=true" 288 add_opts "-device scsi-hd,drive=disk0" 289 else 290 if [[ ${HDA} = *"qcow2" ]]; then 291 add_opts "-drive file=${HDA},format=qcow2" 292 else 293 add_opts "-drive file=${HDA},format=raw" 294 fi 295 fi 296fi 297 298# If this is SEV guest then add the encryption device objects to enable support 299if [ ${SEV} = "1" ]; then 300 add_opts "-machine memory-encryption=sev0,vmport=off" 301 get_cbitpos 302 303 if [ "${ALLOW_DEBUG}" = 1 -a "${SEV_SNP}" = 1 ]; then 304 POLICY=$(((1<<17)|(1<<16))) # smt enable 305 [ "${ALLOW_DEBUG}" = "1" ] && POLICY=$((POLICY | (1<<19))) 306 SNP_POLICY=$(printf ",policy=%#x" $POLICY) 307 elif [ "${ALLOW_DEBUG}" = "1" -o "${SEV_ES}" = "1" ]; then 308 POLICY=$((0x01)) 309 [ "${ALLOW_DEBUG}" = "1" ] && POLICY=$((POLICY & ~0x01)) 310 [ "${SEV_ES}" = "1" ] && POLICY=$((POLICY | 0x04)) 311 SEV_POLICY=$(printf ",policy=%#x" $POLICY) 312 fi 313 314 if [ "${SEV_SNP}" = 1 ]; then 315 add_opts "-object sev-snp-guest,id=sev0${SNP_POLICY},cbitpos=${CBITPOS},reduced-phys-bits=1" 316 else 317 add_opts "-object sev-guest,id=sev0${SEV_POLICY},cbitpos=${CBITPOS},reduced-phys-bits=1" 318 fi 319fi 320 321# if -kernel arg is specified then use the kernel provided in command line for boot 322if [ "${KERNEL_FILE}" != "" ]; then 323 add_opts "-kernel $KERNEL_FILE" 324 #add_opts "-append \"console=ttyS0 earlyprintk=serial root=/dev/sda2\"" 325 [ ! -z ${INITRD_FILE} ] && add_opts "-initrd ${INITRD_FILE}" 326 if [[ -n "${APPEND}" ]]; then 327 add_opts "-append \"${APPEND}\"" 328 fi 329fi 330 331# if console is serial then disable graphical interface 332if [ "${CONSOLE}" = "serial" ]; then 333 add_opts "-nographic" 334else 335 add_opts "-vga ${CONSOLE}" 336fi 337 338 339 340 341# start vnc server 342[ -n "${VNC}" ] && add_opts "-vnc :${VNC}" && echo "Starting VNC on port ${VNC}" 343 344 345# start monitor on pty and named socket 'monitor' 346add_opts "-monitor pty -monitor unix:monitor,server,nowait" 347 348# log the console output in stdout.log 349QEMU_CONSOLE_LOG=`pwd`/stdout.log 350 351# save the command line args into log file 352cat $QEMU_CMDLINE | tee ${QEMU_CONSOLE_LOG} 353echo | tee -a ${QEMU_CONSOLE_LOG} 354 355#touch /tmp/events 356#add_opts "-trace events=/tmp/events" 357 358# map CTRL-C to CTRL ] 359echo "Mapping CTRL-C to CTRL-]" 360stty intr ^] 361 362echo "Launching VM ..." 363echo " $QEMU_CMDLINE" 364sleep 1 365bash ${QEMU_CMDLINE} 2>&1 | tee -a ${QEMU_CONSOLE_LOG} 366 367# restore the mapping 368stty intr ^c 369 370rm -rf ${QEMU_CMDLINE} 371if [ -n "$BR0_STATUS" ]; then 372 stop_network 373fi