xref: /kvm-unit-tests/scripts/arch-run.bash (revision 956004acda727b12b14ef0b5283984754ee7616d)
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
47b2a2aa5dSAndrew Jones			sig=$(sed 's/.*terminating on signal \([0-9][0-9]*\).*/\1/' <<<"$sig")
48b2a2aa5dSAndrew Jones		fi
49b2a2aa5dSAndrew Jones	fi
50b2a2aa5dSAndrew Jones
51b2a2aa5dSAndrew Jones	if [ $ret -eq 0 ]; then
52b2a2aa5dSAndrew Jones		# Some signals result in a zero return status, but the
53b2a2aa5dSAndrew Jones		# error log tells the truth.
54b2a2aa5dSAndrew Jones		if [ "$sig" ]; then
55b2a2aa5dSAndrew Jones			((ret=sig+128))
56b2a2aa5dSAndrew Jones		else
57b2a2aa5dSAndrew Jones			# Exiting with zero (non-debugexit) is an error
58b2a2aa5dSAndrew Jones			ret=1
59b2a2aa5dSAndrew Jones		fi
60b2a2aa5dSAndrew Jones	elif [ $ret -eq 1 ]; then
61b2a2aa5dSAndrew Jones		# Even when ret==1 (unittest success) if we also got stderr
62b2a2aa5dSAndrew Jones		# logs, then we assume a QEMU failure. Otherwise we translate
63b2a2aa5dSAndrew Jones		# status of 1 to 0 (SUCCESS)
645bf124ffSNicholas Piggin	        if [ "$errors" ]; then
655bf124ffSNicholas Piggin			if ! grep -qvi warning <<<"$errors" ; then
665bf124ffSNicholas Piggin				ret=0
675bf124ffSNicholas Piggin			fi
685bf124ffSNicholas Piggin		else
69b2a2aa5dSAndrew Jones			ret=0
70b2a2aa5dSAndrew Jones		fi
71b2a2aa5dSAndrew Jones	fi
72b2a2aa5dSAndrew Jones
73b2a2aa5dSAndrew Jones	return $ret
74b2a2aa5dSAndrew Jones}
75fd149358SAndrew Jones
76e0a8391eSRadim Krčmářrun_qemu_status ()
77e0a8391eSRadim Krčmář{
78e0a8391eSRadim Krčmář	local stdout ret
79e0a8391eSRadim Krčmář
80e0a8391eSRadim Krčmář	exec {stdout}>&1
81e0a8391eSRadim Krčmář	lines=$(run_qemu "$@" > >(tee /dev/fd/$stdout))
82e0a8391eSRadim Krčmář	ret=$?
83e0a8391eSRadim Krčmář	exec {stdout}>&-
84e0a8391eSRadim Krčmář
85e0a8391eSRadim Krčmář	if [ $ret -eq 1 ]; then
86a6e2b9e6SNicholas Piggin		testret=$(grep '^EXIT: ' <<<"$lines" | head -n1 | sed 's/.*STATUS=\([0-9][0-9]*\).*/\1/')
87e0a8391eSRadim Krčmář		if [ "$testret" ]; then
88e0a8391eSRadim Krčmář			if [ $testret -eq 1 ]; then
89e0a8391eSRadim Krčmář				ret=0
90e0a8391eSRadim Krčmář			else
91e0a8391eSRadim Krčmář				ret=$testret
92e0a8391eSRadim Krčmář			fi
93e0a8391eSRadim Krčmář		fi
94e0a8391eSRadim Krčmář	fi
95e0a8391eSRadim Krčmář
96e0a8391eSRadim Krčmář	return $ret
97e0a8391eSRadim Krčmář}
98e0a8391eSRadim Krčmář
99fd149358SAndrew Jonestimeout_cmd ()
100fd149358SAndrew Jones{
10115a12650SAndrew Jones	local s
10215a12650SAndrew Jones
103fd149358SAndrew Jones	if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then
10415a12650SAndrew Jones		if [ "$CONFIG_EFI" = 'y' ]; then
10515a12650SAndrew Jones			s=${TIMEOUT: -1}
10615a12650SAndrew Jones			if [ "$s" = 's' ]; then
10715a12650SAndrew Jones				TIMEOUT=${TIMEOUT:0:-1}
10815a12650SAndrew Jones				((TIMEOUT += 10)) # Add 10 seconds for booting UEFI
10915a12650SAndrew Jones				TIMEOUT="${TIMEOUT}s"
11015a12650SAndrew Jones			fi
11115a12650SAndrew Jones		fi
112fd149358SAndrew Jones		echo "timeout -k 1s --foreground $TIMEOUT"
113fd149358SAndrew Jones	fi
114fd149358SAndrew Jones}
11537abdda9SThomas Huth
11637abdda9SThomas Huthqmp ()
11737abdda9SThomas Huth{
118b508e114SJamie Iles	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | ncat -U $1
11937abdda9SThomas Huth}
12037abdda9SThomas Huth
1215f65d6f4SNico Boehrqmp_events ()
1225f65d6f4SNico Boehr{
1235f65d6f4SNico Boehr	while ! test -S "$1"; do sleep 0.1; done
1245f65d6f4SNico Boehr	echo '{ "execute": "qmp_capabilities" }{ "execute": "cont" }' |
1255f65d6f4SNico Boehr		ncat --no-shutdown -U $1 |
1265f65d6f4SNico Boehr		jq -c 'select(has("event"))'
1275f65d6f4SNico Boehr}
1285f65d6f4SNico Boehr
1294aadd216SNicholas Pigginfilter_quiet_msgs ()
1304aadd216SNicholas Piggin{
131fa8914bcSNicholas Piggin	grep -v "Now migrate the VM (quiet)" |
132*956004acSNicholas Piggin	grep -v "Begin continuous migration (quiet)" |
133*956004acSNicholas Piggin	grep -v "End continuous migration (quiet)" |
134fa8914bcSNicholas Piggin	grep -v "Skipped VM migration (quiet)"
1354aadd216SNicholas Piggin}
1364aadd216SNicholas Piggin
1374aadd216SNicholas Pigginseen_migrate_msg ()
1384aadd216SNicholas Piggin{
139fa8914bcSNicholas Piggin	if [ $skip_migration -eq 1 ]; then
140*956004acSNicholas Piggin	        grep -q -e "Now migrate the VM" -e "Begin continuous migration" < $1
141fa8914bcSNicholas Piggin	else
142*956004acSNicholas Piggin	        grep -q -e "Now migrate the VM" -e "Begin continuous migration" -e "Skipped VM migration" < $1
143fa8914bcSNicholas Piggin	fi
1444aadd216SNicholas Piggin}
1454aadd216SNicholas Piggin
14637abdda9SThomas Huthrun_migration ()
14737abdda9SThomas Huth{
148b508e114SJamie Iles	if ! command -v ncat >/dev/null 2>&1; then
149b508e114SJamie Iles		echo "${FUNCNAME[0]} needs ncat (netcat)" >&2
1502176d963SThomas Huth		return 77
15137abdda9SThomas Huth	fi
15237abdda9SThomas Huth
15314ea7bdaSNicholas Piggin	migcmdline=$@
15414ea7bdaSNicholas Piggin
155af3484fcSNicholas Piggin	trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
156fa8914bcSNicholas Piggin	trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} ${dst_incoming} ${src_qmp} ${dst_qmp} ${src_infifo} ${dst_infifo}' RETURN EXIT
157af3484fcSNicholas Piggin
158cd45aeb7SNicholas Piggin	dst_incoming=$(mktemp -u -t mig-helper-socket-incoming.XXXXXXXXXX)
159cd45aeb7SNicholas Piggin	src_out=$(mktemp -t mig-helper-stdout1.XXXXXXXXXX)
160cd45aeb7SNicholas Piggin	src_outfifo=$(mktemp -u -t mig-helper-fifo-stdout1.XXXXXXXXXX)
161cd45aeb7SNicholas Piggin	dst_out=$(mktemp -t mig-helper-stdout2.XXXXXXXXXX)
162cd45aeb7SNicholas Piggin	dst_outfifo=$(mktemp -u -t mig-helper-fifo-stdout2.XXXXXXXXXX)
163cd45aeb7SNicholas Piggin	src_qmp=$(mktemp -u -t mig-helper-qmp1.XXXXXXXXXX)
164cd45aeb7SNicholas Piggin	dst_qmp=$(mktemp -u -t mig-helper-qmp2.XXXXXXXXXX)
165fa8914bcSNicholas Piggin	src_infifo=$(mktemp -u -t mig-helper-fifo-stdin1.XXXXXXXXXX)
166fa8914bcSNicholas Piggin	dst_infifo=$(mktemp -u -t mig-helper-fifo-stdin2.XXXXXXXXXX)
167cd45aeb7SNicholas Piggin	src_qmpout=/dev/null
168cd45aeb7SNicholas Piggin	dst_qmpout=/dev/null
169fa8914bcSNicholas Piggin	skip_migration=0
170*956004acSNicholas Piggin	continuous_migration=0
17137abdda9SThomas Huth
172cd45aeb7SNicholas Piggin	mkfifo ${src_outfifo}
173cd45aeb7SNicholas Piggin	mkfifo ${dst_outfifo}
17414ea7bdaSNicholas Piggin
17549bbfc65SNicholas Piggin	# Holding both ends of the input fifo open prevents opens from
17649bbfc65SNicholas Piggin	# blocking and readers getting EOF when a writer closes it.
177fa8914bcSNicholas Piggin	mkfifo ${src_infifo}
17849bbfc65SNicholas Piggin	mkfifo ${dst_infifo}
179fa8914bcSNicholas Piggin	exec {src_infifo_fd}<>${src_infifo}
18049bbfc65SNicholas Piggin	exec {dst_infifo_fd}<>${dst_infifo}
18149bbfc65SNicholas Piggin
18214ea7bdaSNicholas Piggin	eval "$migcmdline" \
183cd45aeb7SNicholas Piggin		-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
184fa8914bcSNicholas Piggin		-mon chardev=mon,mode=control \
185fa8914bcSNicholas Piggin		< ${src_infifo} > ${src_outfifo} &
186659557c0SNicholas Piggin	live_pid=$!
1874aadd216SNicholas Piggin	cat ${src_outfifo} | tee ${src_out} | filter_quiet_msgs &
18837abdda9SThomas Huth
18914ea7bdaSNicholas Piggin	# Start the first destination QEMU machine in advance of the test
19014ea7bdaSNicholas Piggin	# reaching the migration point, since we expect at least one migration.
19114ea7bdaSNicholas Piggin	# Then destination machines are started after the test outputs
19214ea7bdaSNicholas Piggin	# subsequent "Now migrate the VM" messages.
19314ea7bdaSNicholas Piggin	do_migration || return $?
19437abdda9SThomas Huth
19514ea7bdaSNicholas Piggin	while ps -p ${live_pid} > /dev/null ; do
196*956004acSNicholas Piggin		if [ ${continuous_migration} -eq 1 ] ; then
197*956004acSNicholas Piggin			do_migration || return $?
198*956004acSNicholas Piggin		elif ! seen_migrate_msg ${src_out} ;  then
19914ea7bdaSNicholas Piggin			sleep 0.1
200*956004acSNicholas Piggin		elif grep -q "Begin continuous migration" < ${src_out} ; then
201*956004acSNicholas Piggin			do_migration || return $?
202fa8914bcSNicholas Piggin		elif grep -q "Now migrate the VM" < ${src_out} ; then
20314ea7bdaSNicholas Piggin			do_migration || return $?
204fa8914bcSNicholas Piggin		elif [ $skip_migration -eq 0 ] && grep -q "Skipped VM migration" < ${src_out} ; then
205fa8914bcSNicholas Piggin			echo > ${src_infifo} # Resume src and carry on.
206fa8914bcSNicholas Piggin			break;
20714ea7bdaSNicholas Piggin		fi
20814ea7bdaSNicholas Piggin	done
20914ea7bdaSNicholas Piggin
21014ea7bdaSNicholas Piggin	wait ${live_pid}
21114ea7bdaSNicholas Piggin	ret=$?
21214ea7bdaSNicholas Piggin
21314ea7bdaSNicholas Piggin	while (( $(jobs -r | wc -l) > 0 )); do
21414ea7bdaSNicholas Piggin		sleep 0.1
21514ea7bdaSNicholas Piggin	done
21614ea7bdaSNicholas Piggin
21714ea7bdaSNicholas Piggin	return $ret
21814ea7bdaSNicholas Piggin}
21914ea7bdaSNicholas Piggin
22014ea7bdaSNicholas Piggindo_migration ()
22114ea7bdaSNicholas Piggin{
22214ea7bdaSNicholas Piggin	eval "$migcmdline" \
223cd45aeb7SNicholas Piggin		-chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \
224cd45aeb7SNicholas Piggin		-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
22549bbfc65SNicholas Piggin		< ${dst_infifo} > ${dst_outfifo} &
22614ea7bdaSNicholas Piggin	incoming_pid=$!
2274aadd216SNicholas Piggin	cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
22814ea7bdaSNicholas Piggin
22914ea7bdaSNicholas Piggin	# The test must prompt the user to migrate, so wait for the
2304aadd216SNicholas Piggin	# "Now migrate VM" or similar console message.
231*956004acSNicholas Piggin	while [ ${continuous_migration} -eq 0 ] && ! seen_migrate_msg ${src_out} ; do
232bfe5d7d0SNicholas Piggin		if ! ps -p ${live_pid} > /dev/null ; then
233cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
234cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
235fa8914bcSNicholas Piggin			echo "ERROR: Test exit before migration point." >&2
236fa8914bcSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
237bfe5d7d0SNicholas Piggin			return 3
238bfe5d7d0SNicholas Piggin		fi
23914ea7bdaSNicholas Piggin		sleep 0.1
24037abdda9SThomas Huth	done
24137abdda9SThomas Huth
242*956004acSNicholas Piggin	if grep -q "Begin continuous migration" < ${src_out} ; then
243*956004acSNicholas Piggin		if [ ${continuous_migration} -eq 1 ] ; then
244*956004acSNicholas Piggin			echo > ${dst_infifo}
245*956004acSNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
246*956004acSNicholas Piggin			echo "ERROR: Continuous migration already begun." >&2
247*956004acSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
248*956004acSNicholas Piggin			return 3
249*956004acSNicholas Piggin		fi
250*956004acSNicholas Piggin		continuous_migration=1
251*956004acSNicholas Piggin		echo > ${src_infifo}
252*956004acSNicholas Piggin	fi
253*956004acSNicholas Piggin
254659557c0SNicholas Piggin	# Wait until the destination has created the incoming and qmp sockets
255cd45aeb7SNicholas Piggin	while ! [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
256cd45aeb7SNicholas Piggin	while ! [ -S ${dst_qmp} ] ; do sleep 0.1 ; done
257659557c0SNicholas Piggin
258fa8914bcSNicholas Piggin	if [ $skip_migration -eq 0 ] && grep -q "Skipped VM migration" < ${src_out} ; then
259fa8914bcSNicholas Piggin		# May not get any migrations, exit to main loop for now...
260*956004acSNicholas Piggin		# No migrations today, shut down dst in an orderly manner...
261*956004acSNicholas Piggin		if [ ${continuous_migration} -eq 1 ] ; then
262*956004acSNicholas Piggin			echo > ${dst_infifo}
263*956004acSNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
264*956004acSNicholas Piggin			echo "ERROR: Can't skip in continuous migration." >&2
265*956004acSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
266*956004acSNicholas Piggin			return 3
267*956004acSNicholas Piggin		fi
268fa8914bcSNicholas Piggin		echo > ${dst_infifo}
269fa8914bcSNicholas Piggin		qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
270fa8914bcSNicholas Piggin		echo > ${src_infifo} # Resume src and carry on.
271fa8914bcSNicholas Piggin		skip_migration=1
272fa8914bcSNicholas Piggin		return 0
273fa8914bcSNicholas Piggin	fi
274fa8914bcSNicholas Piggin
275cd45aeb7SNicholas Piggin	qmp ${src_qmp} '"migrate", "arguments": { "uri": "unix:'${dst_incoming}'" }' > ${src_qmpout}
27637abdda9SThomas Huth
27737abdda9SThomas Huth	# Wait for the migration to complete
27809e55926SNicholas Piggin	migstatus=$(qmp ${src_qmp} '"query-migrate"' | grep return)
27937abdda9SThomas Huth	while ! grep -q '"completed"' <<<"$migstatus" ; do
28014ea7bdaSNicholas Piggin		sleep 0.1
28109e55926SNicholas Piggin		if ! migstatus=$(qmp ${src_qmp} '"query-migrate"'); then
28209e8c119SNico Boehr			echo "ERROR: Querying migration state failed." >&2
283cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
284cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
28509e8c119SNico Boehr			return 2
28609e8c119SNico Boehr		fi
28709e55926SNicholas Piggin		migstatus=$(grep return <<<"$migstatus")
28837abdda9SThomas Huth		if grep -q '"failed"' <<<"$migstatus"; then
28937abdda9SThomas Huth			echo "ERROR: Migration failed." >&2
290cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
291cd45aeb7SNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
292cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
2939806f62dSAndrew Jones			return 2
29437abdda9SThomas Huth		fi
29537abdda9SThomas Huth	done
29614ea7bdaSNicholas Piggin
297cd45aeb7SNicholas Piggin	qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
29814ea7bdaSNicholas Piggin
299*956004acSNicholas Piggin	# Should we end continuous migration?
300*956004acSNicholas Piggin	if grep -q "End continuous migration" < ${src_out} ; then
301*956004acSNicholas Piggin		if [ ${continuous_migration} -eq 0 ] ; then
302*956004acSNicholas Piggin			echo "ERROR: Can't end continuous migration when not started." >&2
303*956004acSNicholas Piggin			echo > ${dst_infifo}
304*956004acSNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
305*956004acSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
306*956004acSNicholas Piggin			return 3
307*956004acSNicholas Piggin		fi
308*956004acSNicholas Piggin		continuous_migration=0
309*956004acSNicholas Piggin		echo > ${src_infifo}
310*956004acSNicholas Piggin	fi
311*956004acSNicholas Piggin
312*956004acSNicholas Piggin	if [ ${continuous_migration} -eq 0 ]; then
31314ea7bdaSNicholas Piggin		# keypress to dst so getchar completes and test continues
314cd45aeb7SNicholas Piggin		echo > ${dst_infifo}
315*956004acSNicholas Piggin	fi
31614ea7bdaSNicholas Piggin
3174b54f4faSNico Boehr	# Wait for the incoming socket being removed, ready for next destination
3184b54f4faSNico Boehr	while [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
31914ea7bdaSNicholas Piggin
32014ea7bdaSNicholas Piggin	wait ${live_pid}
3219806f62dSAndrew Jones	ret=$?
322394d1421SAndrew Jones
323cd45aeb7SNicholas Piggin	# Now flip the variables because destination machine becomes source
324cd45aeb7SNicholas Piggin	# for the next migration.
32514ea7bdaSNicholas Piggin	live_pid=${incoming_pid}
326cd45aeb7SNicholas Piggin	tmp=${src_out}
327cd45aeb7SNicholas Piggin	src_out=${dst_out}
328cd45aeb7SNicholas Piggin	dst_out=${tmp}
329fa8914bcSNicholas Piggin	tmp=${src_infifo}
330fa8914bcSNicholas Piggin	src_infifo=${dst_infifo}
331fa8914bcSNicholas Piggin	dst_infifo=${tmp}
332cd45aeb7SNicholas Piggin	tmp=${src_outfifo}
333cd45aeb7SNicholas Piggin	src_outfifo=${dst_outfifo}
334cd45aeb7SNicholas Piggin	dst_outfifo=${tmp}
335cd45aeb7SNicholas Piggin	tmp=${src_qmp}
336cd45aeb7SNicholas Piggin	src_qmp=${dst_qmp}
337cd45aeb7SNicholas Piggin	dst_qmp=${tmp}
338394d1421SAndrew Jones
3399806f62dSAndrew Jones	return $ret
34037abdda9SThomas Huth}
34137abdda9SThomas Huth
3425f65d6f4SNico Boehrrun_panic ()
3435f65d6f4SNico Boehr{
3445f65d6f4SNico Boehr	if ! command -v ncat >/dev/null 2>&1; then
3455f65d6f4SNico Boehr		echo "${FUNCNAME[0]} needs ncat (netcat)" >&2
3465f65d6f4SNico Boehr		return 77
3475f65d6f4SNico Boehr	fi
3485f65d6f4SNico Boehr
3495f65d6f4SNico Boehr	if ! command -v jq >/dev/null 2>&1; then
3505f65d6f4SNico Boehr		echo "${FUNCNAME[0]} needs jq" >&2
3515f65d6f4SNico Boehr		return 77
3525f65d6f4SNico Boehr	fi
3535f65d6f4SNico Boehr
354af3484fcSNicholas Piggin	trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
3555f65d6f4SNico Boehr	trap 'rm -f ${qmp}' RETURN EXIT
3565f65d6f4SNico Boehr
357af3484fcSNicholas Piggin	qmp=$(mktemp -u -t panic-qmp.XXXXXXXXXX)
358af3484fcSNicholas Piggin
3595f65d6f4SNico Boehr	# start VM stopped so we don't miss any events
360cd45aeb7SNicholas Piggin	eval "$@" -chardev socket,id=mon,path=${qmp},server=on,wait=off \
361cd45aeb7SNicholas Piggin		-mon chardev=mon,mode=control -S &
3625f65d6f4SNico Boehr
3635f65d6f4SNico Boehr	panic_event_count=$(qmp_events ${qmp} | jq -c 'select(.event == "GUEST_PANICKED")' | wc -l)
3645f65d6f4SNico Boehr	if [ "$panic_event_count" -lt 1 ]; then
3655f65d6f4SNico Boehr		echo "FAIL: guest did not panic"
3665f65d6f4SNico Boehr		ret=3
3675f65d6f4SNico Boehr	else
3685f65d6f4SNico Boehr		# some QEMU versions report multiple panic events
3695f65d6f4SNico Boehr		echo "PASS: guest panicked"
3705f65d6f4SNico Boehr		ret=1
3715f65d6f4SNico Boehr	fi
3725f65d6f4SNico Boehr
3735f65d6f4SNico Boehr	return $ret
3745f65d6f4SNico Boehr}
3755f65d6f4SNico Boehr
37637abdda9SThomas Huthmigration_cmd ()
37737abdda9SThomas Huth{
37837abdda9SThomas Huth	if [ "$MIGRATION" = "yes" ]; then
37937abdda9SThomas Huth		echo "run_migration"
38037abdda9SThomas Huth	fi
38137abdda9SThomas Huth}
382531326aeSBalamuruhan S
3835f65d6f4SNico Boehrpanic_cmd ()
3845f65d6f4SNico Boehr{
3855f65d6f4SNico Boehr	if [ "$PANIC" = "yes" ]; then
3865f65d6f4SNico Boehr		echo "run_panic"
3875f65d6f4SNico Boehr	fi
3885f65d6f4SNico Boehr}
3895f65d6f4SNico Boehr
390531326aeSBalamuruhan Ssearch_qemu_binary ()
391531326aeSBalamuruhan S{
392531326aeSBalamuruhan S	local save_path=$PATH
393232f404aSAndrew Jones	local qemucmd qemu
394232f404aSAndrew Jones
395ee5a8a1aSAndrew Jones	: "${QEMU_ARCH:=$ARCH_NAME}"
396ee5a8a1aSAndrew Jones
397531326aeSBalamuruhan S	export PATH=$PATH:/usr/libexec
398ee5a8a1aSAndrew Jones	for qemucmd in ${QEMU:-qemu-system-$QEMU_ARCH qemu-kvm}; do
399232f404aSAndrew Jones		if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then
400232f404aSAndrew Jones			qemu="$qemucmd"
401531326aeSBalamuruhan S			break
402531326aeSBalamuruhan S		fi
403531326aeSBalamuruhan S	done
404531326aeSBalamuruhan S
405232f404aSAndrew Jones	if [ -z "$qemu" ]; then
406fcf4e0d9SRadim Krčmář		echo "A QEMU binary was not found." >&2
407fcf4e0d9SRadim Krčmář		echo "You can set a custom location by using the QEMU=<path> environment variable." >&2
408fcf4e0d9SRadim Krčmář		return 2
409531326aeSBalamuruhan S	fi
410232f404aSAndrew Jones	command -v $qemu
411531326aeSBalamuruhan S	export PATH=$save_path
412531326aeSBalamuruhan S}
4134da0bc9aSAndrew Jones
414c8764266SNicholas Piggininitrd_cleanup ()
415c8764266SNicholas Piggin{
416c8764266SNicholas Piggin	rm -f $KVM_UNIT_TESTS_ENV
417c8764266SNicholas Piggin	if [ "$KVM_UNIT_TESTS_ENV_OLD" ]; then
418c8764266SNicholas Piggin		export KVM_UNIT_TESTS_ENV="$KVM_UNIT_TESTS_ENV_OLD"
419c8764266SNicholas Piggin	else
420c8764266SNicholas Piggin		unset KVM_UNIT_TESTS_ENV
421c8764266SNicholas Piggin	fi
422c8764266SNicholas Piggin	unset KVM_UNIT_TESTS_ENV_OLD
423c8764266SNicholas Piggin}
424c8764266SNicholas Piggin
4254da0bc9aSAndrew Jonesinitrd_create ()
4264da0bc9aSAndrew Jones{
427b16df9eeSAndrew Jones	if [ "$ENVIRON_DEFAULT" = "yes" ]; then
428c8764266SNicholas Piggin		trap_exit_push 'initrd_cleanup'
429b16df9eeSAndrew Jones		[ -f "$KVM_UNIT_TESTS_ENV" ] && export KVM_UNIT_TESTS_ENV_OLD="$KVM_UNIT_TESTS_ENV"
430b16df9eeSAndrew Jones		export KVM_UNIT_TESTS_ENV=$(mktemp)
431b16df9eeSAndrew Jones		env_params
432b16df9eeSAndrew Jones		env_file
433b16df9eeSAndrew Jones		env_errata || return $?
434b16df9eeSAndrew Jones	fi
4358b13a5b5SRadim Krčmář
4364da0bc9aSAndrew Jones	unset INITRD
43763dd93ecSAndrew Jones	[ -f "$KVM_UNIT_TESTS_ENV" ] && INITRD="-initrd $KVM_UNIT_TESTS_ENV"
4388b13a5b5SRadim Krčmář
439b16df9eeSAndrew Jones	return 0
4404da0bc9aSAndrew Jones}
4418ec99569SAndrew Jones
442b16df9eeSAndrew Jonesenv_add_params ()
4438ec99569SAndrew Jones{
444b16df9eeSAndrew Jones	local p
4458ec99569SAndrew Jones
446b16df9eeSAndrew Jones	for p in "$@"; do
447b16df9eeSAndrew Jones		if eval test -v $p; then
448b16df9eeSAndrew Jones			eval export "$p"
449b16df9eeSAndrew Jones		else
450b16df9eeSAndrew Jones			eval export "$p="
451b16df9eeSAndrew Jones		fi
452b16df9eeSAndrew Jones		grep "^$p=" <(env) >>$KVM_UNIT_TESTS_ENV
4538ec99569SAndrew Jones	done
454b16df9eeSAndrew Jones}
455b16df9eeSAndrew Jones
456b16df9eeSAndrew Jonesenv_params ()
457b16df9eeSAndrew Jones{
458b16df9eeSAndrew Jones	local qemu have_qemu
459b16df9eeSAndrew Jones	local _ rest
460b16df9eeSAndrew Jones
461b16df9eeSAndrew Jones	qemu=$(search_qemu_binary) && have_qemu=1
462b16df9eeSAndrew Jones
463b16df9eeSAndrew Jones	if [ "$have_qemu" ]; then
464b16df9eeSAndrew Jones		if [ -n "$ACCEL" ] || [ -n "$QEMU_ACCEL" ]; then
465b16df9eeSAndrew Jones			[ -n "$ACCEL" ] && QEMU_ACCEL=$ACCEL
466b16df9eeSAndrew Jones		fi
467b16df9eeSAndrew Jones		QEMU_VERSION_STRING="$($qemu -h | head -1)"
468b16df9eeSAndrew Jones		IFS='[ .]' read -r _ _ _ QEMU_MAJOR QEMU_MINOR QEMU_MICRO rest <<<"$QEMU_VERSION_STRING"
469b16df9eeSAndrew Jones	fi
470b16df9eeSAndrew Jones	env_add_params QEMU_ACCEL QEMU_VERSION_STRING QEMU_MAJOR QEMU_MINOR QEMU_MICRO
471b16df9eeSAndrew Jones
472b16df9eeSAndrew Jones	KERNEL_VERSION_STRING=$(uname -r)
473b16df9eeSAndrew Jones	IFS=. read -r KERNEL_VERSION KERNEL_PATCHLEVEL rest <<<"$KERNEL_VERSION_STRING"
474b16df9eeSAndrew Jones	IFS=- read -r KERNEL_SUBLEVEL KERNEL_EXTRAVERSION <<<"$rest"
475b16df9eeSAndrew Jones	KERNEL_SUBLEVEL=${KERNEL_SUBLEVEL%%[!0-9]*}
476b16df9eeSAndrew Jones	KERNEL_EXTRAVERSION=${KERNEL_EXTRAVERSION%%[!0-9]*}
477b16df9eeSAndrew Jones	! [[ $KERNEL_SUBLEVEL =~ ^[0-9]+$ ]] && unset $KERNEL_SUBLEVEL
478b16df9eeSAndrew Jones	! [[ $KERNEL_EXTRAVERSION =~ ^[0-9]+$ ]] && unset $KERNEL_EXTRAVERSION
479b16df9eeSAndrew Jones	env_add_params KERNEL_VERSION_STRING KERNEL_VERSION KERNEL_PATCHLEVEL KERNEL_SUBLEVEL KERNEL_EXTRAVERSION
480b16df9eeSAndrew Jones}
481b16df9eeSAndrew Jones
482b16df9eeSAndrew Jonesenv_file ()
483b16df9eeSAndrew Jones{
484b16df9eeSAndrew Jones	local line var
485b16df9eeSAndrew Jones
486b16df9eeSAndrew Jones	[ ! -f "$KVM_UNIT_TESTS_ENV_OLD" ] && return
487b16df9eeSAndrew Jones
488ec11048dSNicholas Piggin	grep -E '^[[:blank:]]*[[:alpha:]_][[:alnum:]_]*=' "$KVM_UNIT_TESTS_ENV_OLD" | while IFS= read -r line ; do
489b16df9eeSAndrew Jones		var=${line%%=*}
490b16df9eeSAndrew Jones		if ! grep -q "^$var=" $KVM_UNIT_TESTS_ENV; then
491b16df9eeSAndrew Jones			eval export "$line"
492b16df9eeSAndrew Jones			grep "^$var=" <(env) >>$KVM_UNIT_TESTS_ENV
493b16df9eeSAndrew Jones		fi
494b16df9eeSAndrew Jones	done
495b16df9eeSAndrew Jones}
496b16df9eeSAndrew Jones
497b16df9eeSAndrew Jonesenv_errata ()
498b16df9eeSAndrew Jones{
499d50fa5a8SNicholas Piggin	local new_env
500d50fa5a8SNicholas Piggin
501ec2f5147SAlex Bennée	if [ "$ACCEL" = "tcg" ]; then
502ec2f5147SAlex Bennée		export "ERRATA_FORCE=y"
503ec2f5147SAlex Bennée	elif [ "$ERRATATXT" ] && [ ! -f "$ERRATATXT" ]; then
504b16df9eeSAndrew Jones		echo "$ERRATATXT not found. (ERRATATXT=$ERRATATXT)" >&2
505b16df9eeSAndrew Jones		return 2
506b16df9eeSAndrew Jones	elif [ "$ERRATATXT" ]; then
50770fcb64bSAndrew Jones		env_generate_errata
5088ec99569SAndrew Jones	fi
509d50fa5a8SNicholas Piggin	new_env=$(sort <(env | grep '^ERRATA_') <(grep '^ERRATA_' $KVM_UNIT_TESTS_ENV) | uniq -u)
510d50fa5a8SNicholas Piggin	echo "$new_env" >>$KVM_UNIT_TESTS_ENV
5118ec99569SAndrew Jones}
5128ec99569SAndrew Jones
51370fcb64bSAndrew Jonesenv_generate_errata ()
51470fcb64bSAndrew Jones{
51512a4328eSAndrew Jones	local line commit minver errata rest v p s x have
51670fcb64bSAndrew Jones
5171ea4709cSAndrew Jones	for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do
51870fcb64bSAndrew Jones		commit=${line%:*}
51970fcb64bSAndrew Jones		minver=${line#*:}
52070fcb64bSAndrew Jones
521171aa3a2SPeter Shier		test -z "$commit" && continue
52270fcb64bSAndrew Jones		errata="ERRATA_$commit"
523d1bc9395SAndrew Jones		[ -n "${!errata}" ] && continue
52470fcb64bSAndrew Jones
525d38b111bSJim Mattson		IFS=. read -r v p rest <<<"$minver"
526d38b111bSJim Mattson		IFS=- read -r s x <<<"$rest"
52770fcb64bSAndrew Jones		s=${s%%[!0-9]*}
52812a4328eSAndrew Jones		x=${x%%[!0-9]*}
52912a4328eSAndrew Jones
53012a4328eSAndrew Jones		if ! [[ $v =~ ^[0-9]+$ ]] || ! [[ $p =~ ^[0-9]+$ ]]; then
53112a4328eSAndrew Jones			echo "Bad minimum kernel version in $ERRATATXT, $minver"
5329806f62dSAndrew Jones			return 2
53312a4328eSAndrew Jones		fi
53412a4328eSAndrew Jones		! [[ $s =~ ^[0-9]+$ ]] && unset $s
53512a4328eSAndrew Jones		! [[ $x =~ ^[0-9]+$ ]] && unset $x
53670fcb64bSAndrew Jones
537b16df9eeSAndrew Jones		if (( $KERNEL_VERSION > $v ||
538b16df9eeSAndrew Jones		      ($KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL > $p) )); then
53970fcb64bSAndrew Jones			have=y
540b16df9eeSAndrew Jones		elif (( $KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL == $p )); then
541b16df9eeSAndrew Jones			if [ "$KERNEL_SUBLEVEL" ] && [ "$s" ]; then
542b16df9eeSAndrew Jones				if (( $KERNEL_SUBLEVEL > $s )); then
54370fcb64bSAndrew Jones					have=y
544b16df9eeSAndrew Jones				elif (( $KERNEL_SUBLEVEL == $s )); then
545b16df9eeSAndrew Jones					if [ "$KERNEL_EXTRAVERSION" ] && [ "$x" ]; then
546b16df9eeSAndrew Jones						if (( $KERNEL_EXTRAVERSION >= $x )); then
54712a4328eSAndrew Jones							have=y
54812a4328eSAndrew Jones						else
54912a4328eSAndrew Jones							have=n
55012a4328eSAndrew Jones						fi
55112a4328eSAndrew Jones					elif [ "$x" ] && (( $x != 0 )); then
55212a4328eSAndrew Jones						have=n
55312a4328eSAndrew Jones					else
55412a4328eSAndrew Jones						have=y
55512a4328eSAndrew Jones					fi
55670fcb64bSAndrew Jones				else
55770fcb64bSAndrew Jones					have=n
55870fcb64bSAndrew Jones				fi
55970fcb64bSAndrew Jones			elif [ "$s" ] && (( $s != 0 )); then
56070fcb64bSAndrew Jones				have=n
56170fcb64bSAndrew Jones			else
56270fcb64bSAndrew Jones				have=y
56370fcb64bSAndrew Jones			fi
56470fcb64bSAndrew Jones		else
56570fcb64bSAndrew Jones			have=n
56670fcb64bSAndrew Jones		fi
56770fcb64bSAndrew Jones		eval export "$errata=$have"
56870fcb64bSAndrew Jones	done
56970fcb64bSAndrew Jones}
57070fcb64bSAndrew Jones
5718ec99569SAndrew Jonestrap_exit_push ()
5728ec99569SAndrew Jones{
5738ec99569SAndrew Jones	local old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//")
5748ec99569SAndrew Jones	trap -- "$1; $old_exit" EXIT
5758ec99569SAndrew Jones}
576f4d99928SRadim Krčmář
577f4d99928SRadim Krčmářkvm_available ()
578f4d99928SRadim Krčmář{
579f4d99928SRadim Krčmář	[ -c /dev/kvm ] ||
580f4d99928SRadim Krčmář		return 1
581f4d99928SRadim Krčmář
582f4d99928SRadim Krčmář	[ "$HOST" = "$ARCH_NAME" ] ||
583d76bf076SAndrew Jones		( [ "$HOST" = aarch64 ] && [ "$ARCH" = arm ] ) ||
584d76bf076SAndrew Jones		( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] )
585f4d99928SRadim Krčmář}
586f4d99928SRadim Krčmář
5877edd698eSRoman Bolshakovhvf_available ()
5887edd698eSRoman Bolshakov{
5897edd698eSRoman Bolshakov	[ "$(sysctl -n kern.hv_support 2>/dev/null)" = "1" ] || return 1
5907edd698eSRoman Bolshakov	[ "$HOST" = "$ARCH_NAME" ] ||
5917edd698eSRoman Bolshakov		( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] )
5927edd698eSRoman Bolshakov}
5937edd698eSRoman Bolshakov
59401e047d0SGavin Shanset_qemu_accelerator ()
595f4d99928SRadim Krčmář{
59601e047d0SGavin Shan	ACCEL_PROPS=${ACCEL#"${ACCEL%%,*}"}
59701e047d0SGavin Shan	ACCEL=${ACCEL%%,*}
59801e047d0SGavin Shan
599f4d99928SRadim Krčmář	if [ "$ACCEL" = "kvm" ] && ! kvm_available; then
600f4d99928SRadim Krčmář		echo "KVM is needed, but not available on this host" >&2
601f4d99928SRadim Krčmář		return 2
602f4d99928SRadim Krčmář	fi
6037edd698eSRoman Bolshakov	if [ "$ACCEL" = "hvf" ] && ! hvf_available; then
6047edd698eSRoman Bolshakov		echo "HVF is needed, but not available on this host" >&2
6057edd698eSRoman Bolshakov		return 2
6067edd698eSRoman Bolshakov	fi
607f4d99928SRadim Krčmář
60801e047d0SGavin Shan	if [ -z "$ACCEL" ]; then
60901e047d0SGavin Shan		if kvm_available; then
61001e047d0SGavin Shan			ACCEL="kvm"
6117edd698eSRoman Bolshakov		elif hvf_available; then
61201e047d0SGavin Shan			ACCEL="hvf"
613f4d99928SRadim Krčmář		else
61401e047d0SGavin Shan			ACCEL="tcg"
615f4d99928SRadim Krčmář		fi
61601e047d0SGavin Shan	fi
61701e047d0SGavin Shan
61801e047d0SGavin Shan	return 0
619f4d99928SRadim Krčmář}
620