1b2a2aa5dSAndrew Jones############################################################################## 2b2a2aa5dSAndrew Jones# run_qemu translates the ambiguous exit status in Table1 to that in Table2. 3b2a2aa5dSAndrew Jones# Table3 simply documents the complete status table. 4b2a2aa5dSAndrew Jones# 5b2a2aa5dSAndrew Jones# Table1: Before fixup 6b2a2aa5dSAndrew Jones# -------------------- 7b2a2aa5dSAndrew Jones# 0 - Unexpected exit from QEMU (possible signal), or the unittest did 8b2a2aa5dSAndrew Jones# not use debug-exit 9b2a2aa5dSAndrew Jones# 1 - most likely unittest succeeded, or QEMU failed 10b2a2aa5dSAndrew Jones# 11b2a2aa5dSAndrew Jones# Table2: After fixup 12b2a2aa5dSAndrew Jones# ------------------- 13b2a2aa5dSAndrew Jones# 0 - Everything succeeded 14b2a2aa5dSAndrew Jones# 1 - most likely QEMU failed 15b2a2aa5dSAndrew Jones# 16b2a2aa5dSAndrew Jones# Table3: Complete table 17b2a2aa5dSAndrew Jones# ---------------------- 18b2a2aa5dSAndrew Jones# 0 - SUCCESS 19b2a2aa5dSAndrew Jones# 1 - most likely QEMU failed 20b2a2aa5dSAndrew Jones# 2 - most likely a run script failed 21b2a2aa5dSAndrew Jones# 3 - most likely the unittest failed 22fd149358SAndrew Jones# 124 - most likely the unittest timed out 23b2a2aa5dSAndrew Jones# 127 - most likely the unittest called abort() 24b2a2aa5dSAndrew Jones# 1..127 - FAILURE (could be QEMU, a run script, or the unittest) 25b2a2aa5dSAndrew Jones# >= 128 - Signal (signum = status - 128) 26b2a2aa5dSAndrew Jones############################################################################## 27b2a2aa5dSAndrew Jonesrun_qemu () 28b2a2aa5dSAndrew Jones{ 298c3f0d96SAndrew Jones local stdout errors ret sig 30b2a2aa5dSAndrew Jones 31b16df9eeSAndrew Jones initrd_create || return $? 32d76bf076SAndrew Jones echo -n "$@" 33b16df9eeSAndrew Jones [ "$ENVIRON_DEFAULT" = "yes" ] && echo -n " #" 348b13a5b5SRadim Krčmář echo " $INITRD" 358b13a5b5SRadim Krčmář 36f0ca153cSRadim Krčmář # stdout to {stdout}, stderr to $errors and stderr 37b2a2aa5dSAndrew Jones exec {stdout}>&1 388b13a5b5SRadim Krčmář errors=$("${@}" $INITRD </dev/null 2> >(tee /dev/stderr) > /dev/fd/$stdout) 39b2a2aa5dSAndrew Jones ret=$? 40b2a2aa5dSAndrew Jones exec {stdout}>&- 418727c886SAndrew Jones 428727c886SAndrew Jones [ $ret -eq 134 ] && echo "QEMU Aborted" >&2 43b2a2aa5dSAndrew Jones 44b2a2aa5dSAndrew Jones if [ "$errors" ]; then 45b2a2aa5dSAndrew Jones sig=$(grep 'terminating on signal' <<<"$errors") 46b2a2aa5dSAndrew Jones if [ "$sig" ]; then 47*3df129a6SNicholas Piggin # This is too complex for ${var/search/replace} 48*3df129a6SNicholas Piggin # shellcheck disable=SC2001 49b2a2aa5dSAndrew Jones sig=$(sed 's/.*terminating on signal \([0-9][0-9]*\).*/\1/' <<<"$sig") 50b2a2aa5dSAndrew Jones fi 51b2a2aa5dSAndrew Jones fi 52b2a2aa5dSAndrew Jones 53b2a2aa5dSAndrew Jones if [ $ret -eq 0 ]; then 54b2a2aa5dSAndrew Jones # Some signals result in a zero return status, but the 55b2a2aa5dSAndrew Jones # error log tells the truth. 56b2a2aa5dSAndrew Jones if [ "$sig" ]; then 57b2a2aa5dSAndrew Jones ((ret=sig+128)) 58b2a2aa5dSAndrew Jones else 59b2a2aa5dSAndrew Jones # Exiting with zero (non-debugexit) is an error 60b2a2aa5dSAndrew Jones ret=1 61b2a2aa5dSAndrew Jones fi 62b2a2aa5dSAndrew Jones elif [ $ret -eq 1 ]; then 63b2a2aa5dSAndrew Jones # Even when ret==1 (unittest success) if we also got stderr 64b2a2aa5dSAndrew Jones # logs, then we assume a QEMU failure. Otherwise we translate 65b2a2aa5dSAndrew Jones # status of 1 to 0 (SUCCESS) 665bf124ffSNicholas Piggin if [ "$errors" ]; then 675bf124ffSNicholas Piggin if ! grep -qvi warning <<<"$errors" ; then 685bf124ffSNicholas Piggin ret=0 695bf124ffSNicholas Piggin fi 705bf124ffSNicholas Piggin else 71b2a2aa5dSAndrew Jones ret=0 72b2a2aa5dSAndrew Jones fi 73b2a2aa5dSAndrew Jones fi 74b2a2aa5dSAndrew Jones 75b2a2aa5dSAndrew Jones return $ret 76b2a2aa5dSAndrew Jones} 77fd149358SAndrew Jones 78e0a8391eSRadim Krčmářrun_qemu_status () 79e0a8391eSRadim Krčmář{ 80e0a8391eSRadim Krčmář local stdout ret 81e0a8391eSRadim Krčmář 82e0a8391eSRadim Krčmář exec {stdout}>&1 83e0a8391eSRadim Krčmář lines=$(run_qemu "$@" > >(tee /dev/fd/$stdout)) 84e0a8391eSRadim Krčmář ret=$? 85e0a8391eSRadim Krčmář exec {stdout}>&- 86e0a8391eSRadim Krčmář 87e0a8391eSRadim Krčmář if [ $ret -eq 1 ]; then 88a6e2b9e6SNicholas Piggin testret=$(grep '^EXIT: ' <<<"$lines" | head -n1 | sed 's/.*STATUS=\([0-9][0-9]*\).*/\1/') 89e0a8391eSRadim Krčmář if [ "$testret" ]; then 90e0a8391eSRadim Krčmář if [ $testret -eq 1 ]; then 91e0a8391eSRadim Krčmář ret=0 92e0a8391eSRadim Krčmář else 93e0a8391eSRadim Krčmář ret=$testret 94e0a8391eSRadim Krčmář fi 95e0a8391eSRadim Krčmář fi 96e0a8391eSRadim Krčmář fi 97e0a8391eSRadim Krčmář 98e0a8391eSRadim Krčmář return $ret 99e0a8391eSRadim Krčmář} 100e0a8391eSRadim Krčmář 101fd149358SAndrew Jonestimeout_cmd () 102fd149358SAndrew Jones{ 10315a12650SAndrew Jones local s 10415a12650SAndrew Jones 105fd149358SAndrew Jones if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then 10615a12650SAndrew Jones if [ "$CONFIG_EFI" = 'y' ]; then 10715a12650SAndrew Jones s=${TIMEOUT: -1} 10815a12650SAndrew Jones if [ "$s" = 's' ]; then 10915a12650SAndrew Jones TIMEOUT=${TIMEOUT:0:-1} 11015a12650SAndrew Jones ((TIMEOUT += 10)) # Add 10 seconds for booting UEFI 11115a12650SAndrew Jones TIMEOUT="${TIMEOUT}s" 11215a12650SAndrew Jones fi 11315a12650SAndrew Jones fi 114fd149358SAndrew Jones echo "timeout -k 1s --foreground $TIMEOUT" 115fd149358SAndrew Jones fi 116fd149358SAndrew Jones} 11737abdda9SThomas Huth 11837abdda9SThomas Huthqmp () 11937abdda9SThomas Huth{ 120b508e114SJamie Iles echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | ncat -U $1 12137abdda9SThomas Huth} 12237abdda9SThomas Huth 1235f65d6f4SNico Boehrqmp_events () 1245f65d6f4SNico Boehr{ 1255f65d6f4SNico Boehr while ! test -S "$1"; do sleep 0.1; done 1265f65d6f4SNico Boehr echo '{ "execute": "qmp_capabilities" }{ "execute": "cont" }' | 1275f65d6f4SNico Boehr ncat --no-shutdown -U $1 | 1285f65d6f4SNico Boehr jq -c 'select(has("event"))' 1295f65d6f4SNico Boehr} 1305f65d6f4SNico Boehr 1314aadd216SNicholas Pigginfilter_quiet_msgs () 1324aadd216SNicholas Piggin{ 133fa8914bcSNicholas Piggin grep -v "Now migrate the VM (quiet)" | 134956004acSNicholas Piggin grep -v "Begin continuous migration (quiet)" | 135956004acSNicholas Piggin grep -v "End continuous migration (quiet)" | 136fa8914bcSNicholas Piggin grep -v "Skipped VM migration (quiet)" 1374aadd216SNicholas Piggin} 1384aadd216SNicholas Piggin 1394aadd216SNicholas Pigginseen_migrate_msg () 1404aadd216SNicholas Piggin{ 141fa8914bcSNicholas Piggin if [ $skip_migration -eq 1 ]; then 142956004acSNicholas Piggin grep -q -e "Now migrate the VM" -e "Begin continuous migration" < $1 143fa8914bcSNicholas Piggin else 144956004acSNicholas Piggin grep -q -e "Now migrate the VM" -e "Begin continuous migration" -e "Skipped VM migration" < $1 145fa8914bcSNicholas Piggin fi 1464aadd216SNicholas Piggin} 1474aadd216SNicholas Piggin 14837abdda9SThomas Huthrun_migration () 14937abdda9SThomas Huth{ 150b508e114SJamie Iles if ! command -v ncat >/dev/null 2>&1; then 151b508e114SJamie Iles echo "${FUNCNAME[0]} needs ncat (netcat)" >&2 1522176d963SThomas Huth return 77 15337abdda9SThomas Huth fi 15437abdda9SThomas Huth 155a8d9d8dcSNicholas Piggin migcmdline=("$@") 15614ea7bdaSNicholas Piggin 157af3484fcSNicholas Piggin trap 'trap - TERM ; kill 0 ; exit 2' INT TERM 158fa8914bcSNicholas Piggin trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} ${dst_incoming} ${src_qmp} ${dst_qmp} ${src_infifo} ${dst_infifo}' RETURN EXIT 159af3484fcSNicholas Piggin 160cd45aeb7SNicholas Piggin dst_incoming=$(mktemp -u -t mig-helper-socket-incoming.XXXXXXXXXX) 161cd45aeb7SNicholas Piggin src_out=$(mktemp -t mig-helper-stdout1.XXXXXXXXXX) 162cd45aeb7SNicholas Piggin src_outfifo=$(mktemp -u -t mig-helper-fifo-stdout1.XXXXXXXXXX) 163cd45aeb7SNicholas Piggin dst_out=$(mktemp -t mig-helper-stdout2.XXXXXXXXXX) 164cd45aeb7SNicholas Piggin dst_outfifo=$(mktemp -u -t mig-helper-fifo-stdout2.XXXXXXXXXX) 165cd45aeb7SNicholas Piggin src_qmp=$(mktemp -u -t mig-helper-qmp1.XXXXXXXXXX) 166cd45aeb7SNicholas Piggin dst_qmp=$(mktemp -u -t mig-helper-qmp2.XXXXXXXXXX) 167fa8914bcSNicholas Piggin src_infifo=$(mktemp -u -t mig-helper-fifo-stdin1.XXXXXXXXXX) 168fa8914bcSNicholas Piggin dst_infifo=$(mktemp -u -t mig-helper-fifo-stdin2.XXXXXXXXXX) 169cd45aeb7SNicholas Piggin src_qmpout=/dev/null 170cd45aeb7SNicholas Piggin dst_qmpout=/dev/null 171fa8914bcSNicholas Piggin skip_migration=0 172956004acSNicholas Piggin continuous_migration=0 17337abdda9SThomas Huth 174cd45aeb7SNicholas Piggin mkfifo ${src_outfifo} 175cd45aeb7SNicholas Piggin mkfifo ${dst_outfifo} 17614ea7bdaSNicholas Piggin 17749bbfc65SNicholas Piggin # Holding both ends of the input fifo open prevents opens from 17849bbfc65SNicholas Piggin # blocking and readers getting EOF when a writer closes it. 179*3df129a6SNicholas Piggin # These fds appear to be unused to shellcheck so quieten the warning. 180fa8914bcSNicholas Piggin mkfifo ${src_infifo} 18149bbfc65SNicholas Piggin mkfifo ${dst_infifo} 182*3df129a6SNicholas Piggin # shellcheck disable=SC2034 183fa8914bcSNicholas Piggin exec {src_infifo_fd}<>${src_infifo} 184*3df129a6SNicholas Piggin # shellcheck disable=SC2034 18549bbfc65SNicholas Piggin exec {dst_infifo_fd}<>${dst_infifo} 18649bbfc65SNicholas Piggin 187b3a1827eSNicholas Piggin "${migcmdline[@]}" \ 188cd45aeb7SNicholas Piggin -chardev socket,id=mon,path=${src_qmp},server=on,wait=off \ 189fa8914bcSNicholas Piggin -mon chardev=mon,mode=control \ 190fa8914bcSNicholas Piggin < ${src_infifo} > ${src_outfifo} & 191659557c0SNicholas Piggin live_pid=$! 192*3df129a6SNicholas Piggin # Shellcheck complains about useless cat but it is clearer than a 193*3df129a6SNicholas Piggin # redirect in this case. 194*3df129a6SNicholas Piggin # shellcheck disable=SC2002 1954aadd216SNicholas Piggin cat ${src_outfifo} | tee ${src_out} | filter_quiet_msgs & 19637abdda9SThomas Huth 19714ea7bdaSNicholas Piggin # Start the first destination QEMU machine in advance of the test 19814ea7bdaSNicholas Piggin # reaching the migration point, since we expect at least one migration. 19914ea7bdaSNicholas Piggin # Then destination machines are started after the test outputs 20014ea7bdaSNicholas Piggin # subsequent "Now migrate the VM" messages. 20114ea7bdaSNicholas Piggin do_migration || return $? 20237abdda9SThomas Huth 20314ea7bdaSNicholas Piggin while ps -p ${live_pid} > /dev/null ; do 204956004acSNicholas Piggin if [ ${continuous_migration} -eq 1 ] ; then 205956004acSNicholas Piggin do_migration || return $? 206956004acSNicholas Piggin elif ! seen_migrate_msg ${src_out} ; then 20714ea7bdaSNicholas Piggin sleep 0.1 208956004acSNicholas Piggin elif grep -q "Begin continuous migration" < ${src_out} ; then 209956004acSNicholas Piggin do_migration || return $? 210fa8914bcSNicholas Piggin elif grep -q "Now migrate the VM" < ${src_out} ; then 21114ea7bdaSNicholas Piggin do_migration || return $? 212fa8914bcSNicholas Piggin elif [ $skip_migration -eq 0 ] && grep -q "Skipped VM migration" < ${src_out} ; then 213fa8914bcSNicholas Piggin echo > ${src_infifo} # Resume src and carry on. 214fa8914bcSNicholas Piggin break; 21514ea7bdaSNicholas Piggin fi 21614ea7bdaSNicholas Piggin done 21714ea7bdaSNicholas Piggin 21814ea7bdaSNicholas Piggin wait ${live_pid} 21914ea7bdaSNicholas Piggin ret=$? 22014ea7bdaSNicholas Piggin 22114ea7bdaSNicholas Piggin while (( $(jobs -r | wc -l) > 0 )); do 22214ea7bdaSNicholas Piggin sleep 0.1 22314ea7bdaSNicholas Piggin done 22414ea7bdaSNicholas Piggin 22514ea7bdaSNicholas Piggin return $ret 22614ea7bdaSNicholas Piggin} 22714ea7bdaSNicholas Piggin 22814ea7bdaSNicholas Piggindo_migration () 22914ea7bdaSNicholas Piggin{ 230b3a1827eSNicholas Piggin "${migcmdline[@]}" \ 231cd45aeb7SNicholas Piggin -chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \ 232cd45aeb7SNicholas Piggin -mon chardev=mon,mode=control -incoming unix:${dst_incoming} \ 23349bbfc65SNicholas Piggin < ${dst_infifo} > ${dst_outfifo} & 23414ea7bdaSNicholas Piggin incoming_pid=$! 235*3df129a6SNicholas Piggin # Shellcheck complains about useless cat but it is clearer than a 236*3df129a6SNicholas Piggin # redirect in this case. 237*3df129a6SNicholas Piggin # shellcheck disable=SC2002 2384aadd216SNicholas Piggin cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs & 23914ea7bdaSNicholas Piggin 24014ea7bdaSNicholas Piggin # The test must prompt the user to migrate, so wait for the 2414aadd216SNicholas Piggin # "Now migrate VM" or similar console message. 242956004acSNicholas Piggin while [ ${continuous_migration} -eq 0 ] && ! seen_migrate_msg ${src_out} ; do 243bfe5d7d0SNicholas Piggin if ! ps -p ${live_pid} > /dev/null ; then 244cd45aeb7SNicholas Piggin echo > ${dst_infifo} 245cd45aeb7SNicholas Piggin qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null 246fa8914bcSNicholas Piggin echo "ERROR: Test exit before migration point." >&2 247fa8914bcSNicholas Piggin qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null 248bfe5d7d0SNicholas Piggin return 3 249bfe5d7d0SNicholas Piggin fi 25014ea7bdaSNicholas Piggin sleep 0.1 25137abdda9SThomas Huth done 25237abdda9SThomas Huth 253956004acSNicholas Piggin if grep -q "Begin continuous migration" < ${src_out} ; then 254956004acSNicholas Piggin if [ ${continuous_migration} -eq 1 ] ; then 255956004acSNicholas Piggin echo > ${dst_infifo} 256956004acSNicholas Piggin qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null 257956004acSNicholas Piggin echo "ERROR: Continuous migration already begun." >&2 258956004acSNicholas Piggin qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null 259956004acSNicholas Piggin return 3 260956004acSNicholas Piggin fi 261956004acSNicholas Piggin continuous_migration=1 262956004acSNicholas Piggin echo > ${src_infifo} 263956004acSNicholas Piggin fi 264956004acSNicholas Piggin 265659557c0SNicholas Piggin # Wait until the destination has created the incoming and qmp sockets 266cd45aeb7SNicholas Piggin while ! [ -S ${dst_incoming} ] ; do sleep 0.1 ; done 267cd45aeb7SNicholas Piggin while ! [ -S ${dst_qmp} ] ; do sleep 0.1 ; done 268659557c0SNicholas Piggin 269fa8914bcSNicholas Piggin if [ $skip_migration -eq 0 ] && grep -q "Skipped VM migration" < ${src_out} ; then 270fa8914bcSNicholas Piggin # May not get any migrations, exit to main loop for now... 271956004acSNicholas Piggin # No migrations today, shut down dst in an orderly manner... 272956004acSNicholas Piggin if [ ${continuous_migration} -eq 1 ] ; then 273956004acSNicholas Piggin echo > ${dst_infifo} 274956004acSNicholas Piggin qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null 275956004acSNicholas Piggin echo "ERROR: Can't skip in continuous migration." >&2 276956004acSNicholas Piggin qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null 277956004acSNicholas Piggin return 3 278956004acSNicholas Piggin fi 279fa8914bcSNicholas Piggin echo > ${dst_infifo} 280fa8914bcSNicholas Piggin qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null 281fa8914bcSNicholas Piggin echo > ${src_infifo} # Resume src and carry on. 282fa8914bcSNicholas Piggin skip_migration=1 283fa8914bcSNicholas Piggin return 0 284fa8914bcSNicholas Piggin fi 285fa8914bcSNicholas Piggin 286cd45aeb7SNicholas Piggin qmp ${src_qmp} '"migrate", "arguments": { "uri": "unix:'${dst_incoming}'" }' > ${src_qmpout} 28737abdda9SThomas Huth 28837abdda9SThomas Huth # Wait for the migration to complete 28909e55926SNicholas Piggin migstatus=$(qmp ${src_qmp} '"query-migrate"' | grep return) 29037abdda9SThomas Huth while ! grep -q '"completed"' <<<"$migstatus" ; do 29114ea7bdaSNicholas Piggin sleep 0.1 29209e55926SNicholas Piggin if ! migstatus=$(qmp ${src_qmp} '"query-migrate"'); then 29309e8c119SNico Boehr echo "ERROR: Querying migration state failed." >&2 294cd45aeb7SNicholas Piggin echo > ${dst_infifo} 295cd45aeb7SNicholas Piggin qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null 29609e8c119SNico Boehr return 2 29709e8c119SNico Boehr fi 29809e55926SNicholas Piggin migstatus=$(grep return <<<"$migstatus") 29937abdda9SThomas Huth if grep -q '"failed"' <<<"$migstatus"; then 30037abdda9SThomas Huth echo "ERROR: Migration failed." >&2 301cd45aeb7SNicholas Piggin echo > ${dst_infifo} 302cd45aeb7SNicholas Piggin qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null 303cd45aeb7SNicholas Piggin qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null 3049806f62dSAndrew Jones return 2 30537abdda9SThomas Huth fi 30637abdda9SThomas Huth done 30714ea7bdaSNicholas Piggin 308cd45aeb7SNicholas Piggin qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null 30914ea7bdaSNicholas Piggin 310956004acSNicholas Piggin # Should we end continuous migration? 311956004acSNicholas Piggin if grep -q "End continuous migration" < ${src_out} ; then 312956004acSNicholas Piggin if [ ${continuous_migration} -eq 0 ] ; then 313956004acSNicholas Piggin echo "ERROR: Can't end continuous migration when not started." >&2 314956004acSNicholas Piggin echo > ${dst_infifo} 315956004acSNicholas Piggin qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null 316956004acSNicholas Piggin qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null 317956004acSNicholas Piggin return 3 318956004acSNicholas Piggin fi 319956004acSNicholas Piggin continuous_migration=0 320956004acSNicholas Piggin echo > ${src_infifo} 321956004acSNicholas Piggin fi 322956004acSNicholas Piggin 323956004acSNicholas Piggin if [ ${continuous_migration} -eq 0 ]; then 32414ea7bdaSNicholas Piggin # keypress to dst so getchar completes and test continues 325cd45aeb7SNicholas Piggin echo > ${dst_infifo} 326956004acSNicholas Piggin fi 32714ea7bdaSNicholas Piggin 3284b54f4faSNico Boehr # Wait for the incoming socket being removed, ready for next destination 3294b54f4faSNico Boehr while [ -S ${dst_incoming} ] ; do sleep 0.1 ; done 33014ea7bdaSNicholas Piggin 33114ea7bdaSNicholas Piggin wait ${live_pid} 3329806f62dSAndrew Jones ret=$? 333394d1421SAndrew Jones 334cd45aeb7SNicholas Piggin # Now flip the variables because destination machine becomes source 335cd45aeb7SNicholas Piggin # for the next migration. 33614ea7bdaSNicholas Piggin live_pid=${incoming_pid} 337cd45aeb7SNicholas Piggin tmp=${src_out} 338cd45aeb7SNicholas Piggin src_out=${dst_out} 339cd45aeb7SNicholas Piggin dst_out=${tmp} 340fa8914bcSNicholas Piggin tmp=${src_infifo} 341fa8914bcSNicholas Piggin src_infifo=${dst_infifo} 342fa8914bcSNicholas Piggin dst_infifo=${tmp} 343cd45aeb7SNicholas Piggin tmp=${src_outfifo} 344cd45aeb7SNicholas Piggin src_outfifo=${dst_outfifo} 345cd45aeb7SNicholas Piggin dst_outfifo=${tmp} 346cd45aeb7SNicholas Piggin tmp=${src_qmp} 347cd45aeb7SNicholas Piggin src_qmp=${dst_qmp} 348cd45aeb7SNicholas Piggin dst_qmp=${tmp} 349394d1421SAndrew Jones 3509806f62dSAndrew Jones return $ret 35137abdda9SThomas Huth} 35237abdda9SThomas Huth 3535f65d6f4SNico Boehrrun_panic () 3545f65d6f4SNico Boehr{ 3555f65d6f4SNico Boehr if ! command -v ncat >/dev/null 2>&1; then 3565f65d6f4SNico Boehr echo "${FUNCNAME[0]} needs ncat (netcat)" >&2 3575f65d6f4SNico Boehr return 77 3585f65d6f4SNico Boehr fi 3595f65d6f4SNico Boehr 3605f65d6f4SNico Boehr if ! command -v jq >/dev/null 2>&1; then 3615f65d6f4SNico Boehr echo "${FUNCNAME[0]} needs jq" >&2 3625f65d6f4SNico Boehr return 77 3635f65d6f4SNico Boehr fi 3645f65d6f4SNico Boehr 365af3484fcSNicholas Piggin trap 'trap - TERM ; kill 0 ; exit 2' INT TERM 3665f65d6f4SNico Boehr trap 'rm -f ${qmp}' RETURN EXIT 3675f65d6f4SNico Boehr 368af3484fcSNicholas Piggin qmp=$(mktemp -u -t panic-qmp.XXXXXXXXXX) 369af3484fcSNicholas Piggin 3705f65d6f4SNico Boehr # start VM stopped so we don't miss any events 371b3a1827eSNicholas Piggin "$@" -chardev socket,id=mon,path=${qmp},server=on,wait=off \ 372cd45aeb7SNicholas Piggin -mon chardev=mon,mode=control -S & 3735f65d6f4SNico Boehr 3745f65d6f4SNico Boehr panic_event_count=$(qmp_events ${qmp} | jq -c 'select(.event == "GUEST_PANICKED")' | wc -l) 3755f65d6f4SNico Boehr if [ "$panic_event_count" -lt 1 ]; then 3765f65d6f4SNico Boehr echo "FAIL: guest did not panic" 3775f65d6f4SNico Boehr ret=3 3785f65d6f4SNico Boehr else 3795f65d6f4SNico Boehr # some QEMU versions report multiple panic events 3805f65d6f4SNico Boehr echo "PASS: guest panicked" 3815f65d6f4SNico Boehr ret=1 3825f65d6f4SNico Boehr fi 3835f65d6f4SNico Boehr 3845f65d6f4SNico Boehr return $ret 3855f65d6f4SNico Boehr} 3865f65d6f4SNico Boehr 38737abdda9SThomas Huthmigration_cmd () 38837abdda9SThomas Huth{ 38937abdda9SThomas Huth if [ "$MIGRATION" = "yes" ]; then 39037abdda9SThomas Huth echo "run_migration" 39137abdda9SThomas Huth fi 39237abdda9SThomas Huth} 393531326aeSBalamuruhan S 3945f65d6f4SNico Boehrpanic_cmd () 3955f65d6f4SNico Boehr{ 3965f65d6f4SNico Boehr if [ "$PANIC" = "yes" ]; then 3975f65d6f4SNico Boehr echo "run_panic" 3985f65d6f4SNico Boehr fi 3995f65d6f4SNico Boehr} 4005f65d6f4SNico Boehr 401531326aeSBalamuruhan Ssearch_qemu_binary () 402531326aeSBalamuruhan S{ 403531326aeSBalamuruhan S local save_path=$PATH 404232f404aSAndrew Jones local qemucmd qemu 405232f404aSAndrew Jones 406ee5a8a1aSAndrew Jones : "${QEMU_ARCH:=$ARCH_NAME}" 407ee5a8a1aSAndrew Jones 408531326aeSBalamuruhan S export PATH=$PATH:/usr/libexec 409ee5a8a1aSAndrew Jones for qemucmd in ${QEMU:-qemu-system-$QEMU_ARCH qemu-kvm}; do 410232f404aSAndrew Jones if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then 411232f404aSAndrew Jones qemu="$qemucmd" 412531326aeSBalamuruhan S break 413531326aeSBalamuruhan S fi 414531326aeSBalamuruhan S done 415531326aeSBalamuruhan S 416232f404aSAndrew Jones if [ -z "$qemu" ]; then 417fcf4e0d9SRadim Krčmář echo "A QEMU binary was not found." >&2 418fcf4e0d9SRadim Krčmář echo "You can set a custom location by using the QEMU=<path> environment variable." >&2 419fcf4e0d9SRadim Krčmář return 2 420531326aeSBalamuruhan S fi 421232f404aSAndrew Jones command -v $qemu 422531326aeSBalamuruhan S export PATH=$save_path 423531326aeSBalamuruhan S} 4244da0bc9aSAndrew Jones 425c8764266SNicholas Piggininitrd_cleanup () 426c8764266SNicholas Piggin{ 427c8764266SNicholas Piggin rm -f $KVM_UNIT_TESTS_ENV 428c8764266SNicholas Piggin if [ "$KVM_UNIT_TESTS_ENV_OLD" ]; then 429b7e5dfd3SNicholas Piggin export KVM_UNIT_TESTS_ENV 430b7e5dfd3SNicholas Piggin KVM_UNIT_TESTS_ENV="$KVM_UNIT_TESTS_ENV_OLD" 431c8764266SNicholas Piggin else 432c8764266SNicholas Piggin unset KVM_UNIT_TESTS_ENV 433c8764266SNicholas Piggin fi 434c8764266SNicholas Piggin unset KVM_UNIT_TESTS_ENV_OLD 435c8764266SNicholas Piggin} 436c8764266SNicholas Piggin 4374da0bc9aSAndrew Jonesinitrd_create () 4384da0bc9aSAndrew Jones{ 439b16df9eeSAndrew Jones if [ "$ENVIRON_DEFAULT" = "yes" ]; then 440c8764266SNicholas Piggin trap_exit_push 'initrd_cleanup' 441b16df9eeSAndrew Jones [ -f "$KVM_UNIT_TESTS_ENV" ] && export KVM_UNIT_TESTS_ENV_OLD="$KVM_UNIT_TESTS_ENV" 442b7e5dfd3SNicholas Piggin export KVM_UNIT_TESTS_ENV 443b7e5dfd3SNicholas Piggin KVM_UNIT_TESTS_ENV=$(mktemp) 444b16df9eeSAndrew Jones env_params 445b16df9eeSAndrew Jones env_file 446b16df9eeSAndrew Jones env_errata || return $? 447b16df9eeSAndrew Jones fi 4488b13a5b5SRadim Krčmář 4494da0bc9aSAndrew Jones unset INITRD 45063dd93ecSAndrew Jones [ -f "$KVM_UNIT_TESTS_ENV" ] && INITRD="-initrd $KVM_UNIT_TESTS_ENV" 4518b13a5b5SRadim Krčmář 452b16df9eeSAndrew Jones return 0 4534da0bc9aSAndrew Jones} 4548ec99569SAndrew Jones 455b16df9eeSAndrew Jonesenv_add_params () 4568ec99569SAndrew Jones{ 457b16df9eeSAndrew Jones local p 4588ec99569SAndrew Jones 459b16df9eeSAndrew Jones for p in "$@"; do 460b16df9eeSAndrew Jones if eval test -v $p; then 461b16df9eeSAndrew Jones eval export "$p" 462b16df9eeSAndrew Jones else 463b16df9eeSAndrew Jones eval export "$p=" 464b16df9eeSAndrew Jones fi 465b16df9eeSAndrew Jones grep "^$p=" <(env) >>$KVM_UNIT_TESTS_ENV 4668ec99569SAndrew Jones done 467b16df9eeSAndrew Jones} 468b16df9eeSAndrew Jones 469b16df9eeSAndrew Jonesenv_params () 470b16df9eeSAndrew Jones{ 471b16df9eeSAndrew Jones local qemu have_qemu 472b16df9eeSAndrew Jones local _ rest 473b16df9eeSAndrew Jones 474b16df9eeSAndrew Jones qemu=$(search_qemu_binary) && have_qemu=1 475b16df9eeSAndrew Jones 476b16df9eeSAndrew Jones if [ "$have_qemu" ]; then 477b16df9eeSAndrew Jones if [ -n "$ACCEL" ] || [ -n "$QEMU_ACCEL" ]; then 478b16df9eeSAndrew Jones [ -n "$ACCEL" ] && QEMU_ACCEL=$ACCEL 479b16df9eeSAndrew Jones fi 480b16df9eeSAndrew Jones QEMU_VERSION_STRING="$($qemu -h | head -1)" 481*3df129a6SNicholas Piggin # Shellcheck does not see QEMU_MAJOR|MINOR|MICRO are used 482*3df129a6SNicholas Piggin # shellcheck disable=SC2034 483b16df9eeSAndrew Jones IFS='[ .]' read -r _ _ _ QEMU_MAJOR QEMU_MINOR QEMU_MICRO rest <<<"$QEMU_VERSION_STRING" 484b16df9eeSAndrew Jones fi 485b16df9eeSAndrew Jones env_add_params QEMU_ACCEL QEMU_VERSION_STRING QEMU_MAJOR QEMU_MINOR QEMU_MICRO 486b16df9eeSAndrew Jones 487b16df9eeSAndrew Jones KERNEL_VERSION_STRING=$(uname -r) 488b16df9eeSAndrew Jones IFS=. read -r KERNEL_VERSION KERNEL_PATCHLEVEL rest <<<"$KERNEL_VERSION_STRING" 489b16df9eeSAndrew Jones IFS=- read -r KERNEL_SUBLEVEL KERNEL_EXTRAVERSION <<<"$rest" 490b16df9eeSAndrew Jones KERNEL_SUBLEVEL=${KERNEL_SUBLEVEL%%[!0-9]*} 491b16df9eeSAndrew Jones KERNEL_EXTRAVERSION=${KERNEL_EXTRAVERSION%%[!0-9]*} 492b16df9eeSAndrew Jones ! [[ $KERNEL_SUBLEVEL =~ ^[0-9]+$ ]] && unset $KERNEL_SUBLEVEL 493b16df9eeSAndrew Jones ! [[ $KERNEL_EXTRAVERSION =~ ^[0-9]+$ ]] && unset $KERNEL_EXTRAVERSION 494b16df9eeSAndrew Jones env_add_params KERNEL_VERSION_STRING KERNEL_VERSION KERNEL_PATCHLEVEL KERNEL_SUBLEVEL KERNEL_EXTRAVERSION 495b16df9eeSAndrew Jones} 496b16df9eeSAndrew Jones 497b16df9eeSAndrew Jonesenv_file () 498b16df9eeSAndrew Jones{ 499b16df9eeSAndrew Jones local line var 500b16df9eeSAndrew Jones 501b16df9eeSAndrew Jones [ ! -f "$KVM_UNIT_TESTS_ENV_OLD" ] && return 502b16df9eeSAndrew Jones 503ec11048dSNicholas Piggin grep -E '^[[:blank:]]*[[:alpha:]_][[:alnum:]_]*=' "$KVM_UNIT_TESTS_ENV_OLD" | while IFS= read -r line ; do 504b16df9eeSAndrew Jones var=${line%%=*} 505b16df9eeSAndrew Jones if ! grep -q "^$var=" $KVM_UNIT_TESTS_ENV; then 506b16df9eeSAndrew Jones eval export "$line" 507b16df9eeSAndrew Jones grep "^$var=" <(env) >>$KVM_UNIT_TESTS_ENV 508b16df9eeSAndrew Jones fi 509b16df9eeSAndrew Jones done 510b16df9eeSAndrew Jones} 511b16df9eeSAndrew Jones 512b16df9eeSAndrew Jonesenv_errata () 513b16df9eeSAndrew Jones{ 514d50fa5a8SNicholas Piggin local new_env 515d50fa5a8SNicholas Piggin 516ec2f5147SAlex Bennée if [ "$ACCEL" = "tcg" ]; then 517ec2f5147SAlex Bennée export "ERRATA_FORCE=y" 518ec2f5147SAlex Bennée elif [ "$ERRATATXT" ] && [ ! -f "$ERRATATXT" ]; then 519b16df9eeSAndrew Jones echo "$ERRATATXT not found. (ERRATATXT=$ERRATATXT)" >&2 520b16df9eeSAndrew Jones return 2 521b16df9eeSAndrew Jones elif [ "$ERRATATXT" ]; then 52270fcb64bSAndrew Jones env_generate_errata 5238ec99569SAndrew Jones fi 524d50fa5a8SNicholas Piggin new_env=$(sort <(env | grep '^ERRATA_') <(grep '^ERRATA_' $KVM_UNIT_TESTS_ENV) | uniq -u) 525d50fa5a8SNicholas Piggin echo "$new_env" >>$KVM_UNIT_TESTS_ENV 5268ec99569SAndrew Jones} 5278ec99569SAndrew Jones 52870fcb64bSAndrew Jonesenv_generate_errata () 52970fcb64bSAndrew Jones{ 53012a4328eSAndrew Jones local line commit minver errata rest v p s x have 53170fcb64bSAndrew Jones 5321ea4709cSAndrew Jones for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do 53370fcb64bSAndrew Jones commit=${line%:*} 53470fcb64bSAndrew Jones minver=${line#*:} 53570fcb64bSAndrew Jones 536171aa3a2SPeter Shier test -z "$commit" && continue 53770fcb64bSAndrew Jones errata="ERRATA_$commit" 538d1bc9395SAndrew Jones [ -n "${!errata}" ] && continue 53970fcb64bSAndrew Jones 540d38b111bSJim Mattson IFS=. read -r v p rest <<<"$minver" 541d38b111bSJim Mattson IFS=- read -r s x <<<"$rest" 54270fcb64bSAndrew Jones s=${s%%[!0-9]*} 54312a4328eSAndrew Jones x=${x%%[!0-9]*} 54412a4328eSAndrew Jones 54512a4328eSAndrew Jones if ! [[ $v =~ ^[0-9]+$ ]] || ! [[ $p =~ ^[0-9]+$ ]]; then 54612a4328eSAndrew Jones echo "Bad minimum kernel version in $ERRATATXT, $minver" 5479806f62dSAndrew Jones return 2 54812a4328eSAndrew Jones fi 54912a4328eSAndrew Jones ! [[ $s =~ ^[0-9]+$ ]] && unset $s 55012a4328eSAndrew Jones ! [[ $x =~ ^[0-9]+$ ]] && unset $x 55170fcb64bSAndrew Jones 552b16df9eeSAndrew Jones if (( $KERNEL_VERSION > $v || 553b16df9eeSAndrew Jones ($KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL > $p) )); then 55470fcb64bSAndrew Jones have=y 555b16df9eeSAndrew Jones elif (( $KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL == $p )); then 556b16df9eeSAndrew Jones if [ "$KERNEL_SUBLEVEL" ] && [ "$s" ]; then 557b16df9eeSAndrew Jones if (( $KERNEL_SUBLEVEL > $s )); then 55870fcb64bSAndrew Jones have=y 559b16df9eeSAndrew Jones elif (( $KERNEL_SUBLEVEL == $s )); then 560b16df9eeSAndrew Jones if [ "$KERNEL_EXTRAVERSION" ] && [ "$x" ]; then 561b16df9eeSAndrew Jones if (( $KERNEL_EXTRAVERSION >= $x )); then 56212a4328eSAndrew Jones have=y 56312a4328eSAndrew Jones else 56412a4328eSAndrew Jones have=n 56512a4328eSAndrew Jones fi 56612a4328eSAndrew Jones elif [ "$x" ] && (( $x != 0 )); then 56712a4328eSAndrew Jones have=n 56812a4328eSAndrew Jones else 56912a4328eSAndrew Jones have=y 57012a4328eSAndrew Jones fi 57170fcb64bSAndrew Jones else 57270fcb64bSAndrew Jones have=n 57370fcb64bSAndrew Jones fi 57470fcb64bSAndrew Jones elif [ "$s" ] && (( $s != 0 )); then 57570fcb64bSAndrew Jones have=n 57670fcb64bSAndrew Jones else 57770fcb64bSAndrew Jones have=y 57870fcb64bSAndrew Jones fi 57970fcb64bSAndrew Jones else 58070fcb64bSAndrew Jones have=n 58170fcb64bSAndrew Jones fi 58270fcb64bSAndrew Jones eval export "$errata=$have" 58370fcb64bSAndrew Jones done 58470fcb64bSAndrew Jones} 58570fcb64bSAndrew Jones 5868ec99569SAndrew Jonestrap_exit_push () 5878ec99569SAndrew Jones{ 588b7e5dfd3SNicholas Piggin local old_exit 589b7e5dfd3SNicholas Piggin 590b7e5dfd3SNicholas Piggin old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//") 5918ec99569SAndrew Jones trap -- "$1; $old_exit" EXIT 5928ec99569SAndrew Jones} 593f4d99928SRadim Krčmář 594f4d99928SRadim Krčmářkvm_available () 595f4d99928SRadim Krčmář{ 596f4d99928SRadim Krčmář [ -c /dev/kvm ] || 597f4d99928SRadim Krčmář return 1 598f4d99928SRadim Krčmář 599f4d99928SRadim Krčmář [ "$HOST" = "$ARCH_NAME" ] || 600d76bf076SAndrew Jones ( [ "$HOST" = aarch64 ] && [ "$ARCH" = arm ] ) || 601d76bf076SAndrew Jones ( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] ) 602f4d99928SRadim Krčmář} 603f4d99928SRadim Krčmář 6047edd698eSRoman Bolshakovhvf_available () 6057edd698eSRoman Bolshakov{ 6067edd698eSRoman Bolshakov [ "$(sysctl -n kern.hv_support 2>/dev/null)" = "1" ] || return 1 6077edd698eSRoman Bolshakov [ "$HOST" = "$ARCH_NAME" ] || 6087edd698eSRoman Bolshakov ( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] ) 6097edd698eSRoman Bolshakov} 6107edd698eSRoman Bolshakov 61101e047d0SGavin Shanset_qemu_accelerator () 612f4d99928SRadim Krčmář{ 613*3df129a6SNicholas Piggin # Shellcheck does not see ACCEL_PROPS is used 614*3df129a6SNicholas Piggin # shellcheck disable=SC2034 61501e047d0SGavin Shan ACCEL_PROPS=${ACCEL#"${ACCEL%%,*}"} 61601e047d0SGavin Shan ACCEL=${ACCEL%%,*} 61701e047d0SGavin Shan 618f4d99928SRadim Krčmář if [ "$ACCEL" = "kvm" ] && ! kvm_available; then 619f4d99928SRadim Krčmář echo "KVM is needed, but not available on this host" >&2 620f4d99928SRadim Krčmář return 2 621f4d99928SRadim Krčmář fi 6227edd698eSRoman Bolshakov if [ "$ACCEL" = "hvf" ] && ! hvf_available; then 6237edd698eSRoman Bolshakov echo "HVF is needed, but not available on this host" >&2 6247edd698eSRoman Bolshakov return 2 6257edd698eSRoman Bolshakov fi 626f4d99928SRadim Krčmář 62701e047d0SGavin Shan if [ -z "$ACCEL" ]; then 62801e047d0SGavin Shan if kvm_available; then 62901e047d0SGavin Shan ACCEL="kvm" 6307edd698eSRoman Bolshakov elif hvf_available; then 63101e047d0SGavin Shan ACCEL="hvf" 632f4d99928SRadim Krčmář else 63301e047d0SGavin Shan ACCEL="tcg" 634f4d99928SRadim Krčmář fi 63501e047d0SGavin Shan fi 63601e047d0SGavin Shan 63701e047d0SGavin Shan return 0 638f4d99928SRadim Krčmář} 639