xref: /kvm-unit-tests/scripts/arch-run.bash (revision d50fa5a856a9ac1508cac9a923aad21abb593322)
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)
64a51bab13SRadim Krčmář		if [ -z "$(echo "$errors" | grep -vi warning)" ]; then
65b2a2aa5dSAndrew Jones			ret=0
66b2a2aa5dSAndrew Jones		fi
67b2a2aa5dSAndrew Jones	fi
68b2a2aa5dSAndrew Jones
69b2a2aa5dSAndrew Jones	return $ret
70b2a2aa5dSAndrew Jones}
71fd149358SAndrew Jones
72e0a8391eSRadim Krčmářrun_qemu_status ()
73e0a8391eSRadim Krčmář{
74e0a8391eSRadim Krčmář	local stdout ret
75e0a8391eSRadim Krčmář
76e0a8391eSRadim Krčmář	exec {stdout}>&1
77e0a8391eSRadim Krčmář	lines=$(run_qemu "$@" > >(tee /dev/fd/$stdout))
78e0a8391eSRadim Krčmář	ret=$?
79e0a8391eSRadim Krčmář	exec {stdout}>&-
80e0a8391eSRadim Krčmář
81e0a8391eSRadim Krčmář	if [ $ret -eq 1 ]; then
82a6e2b9e6SNicholas Piggin		testret=$(grep '^EXIT: ' <<<"$lines" | head -n1 | sed 's/.*STATUS=\([0-9][0-9]*\).*/\1/')
83e0a8391eSRadim Krčmář		if [ "$testret" ]; then
84e0a8391eSRadim Krčmář			if [ $testret -eq 1 ]; then
85e0a8391eSRadim Krčmář				ret=0
86e0a8391eSRadim Krčmář			else
87e0a8391eSRadim Krčmář				ret=$testret
88e0a8391eSRadim Krčmář			fi
89e0a8391eSRadim Krčmář		fi
90e0a8391eSRadim Krčmář	fi
91e0a8391eSRadim Krčmář
92e0a8391eSRadim Krčmář	return $ret
93e0a8391eSRadim Krčmář}
94e0a8391eSRadim Krčmář
95fd149358SAndrew Jonestimeout_cmd ()
96fd149358SAndrew Jones{
9715a12650SAndrew Jones	local s
9815a12650SAndrew Jones
99fd149358SAndrew Jones	if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then
10015a12650SAndrew Jones		if [ "$CONFIG_EFI" = 'y' ]; then
10115a12650SAndrew Jones			s=${TIMEOUT: -1}
10215a12650SAndrew Jones			if [ "$s" = 's' ]; then
10315a12650SAndrew Jones				TIMEOUT=${TIMEOUT:0:-1}
10415a12650SAndrew Jones				((TIMEOUT += 10)) # Add 10 seconds for booting UEFI
10515a12650SAndrew Jones				TIMEOUT="${TIMEOUT}s"
10615a12650SAndrew Jones			fi
10715a12650SAndrew Jones		fi
108fd149358SAndrew Jones		echo "timeout -k 1s --foreground $TIMEOUT"
109fd149358SAndrew Jones	fi
110fd149358SAndrew Jones}
11137abdda9SThomas Huth
11237abdda9SThomas Huthqmp ()
11337abdda9SThomas Huth{
114b508e114SJamie Iles	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | ncat -U $1
11537abdda9SThomas Huth}
11637abdda9SThomas Huth
1175f65d6f4SNico Boehrqmp_events ()
1185f65d6f4SNico Boehr{
1195f65d6f4SNico Boehr	while ! test -S "$1"; do sleep 0.1; done
1205f65d6f4SNico Boehr	echo '{ "execute": "qmp_capabilities" }{ "execute": "cont" }' |
1215f65d6f4SNico Boehr		ncat --no-shutdown -U $1 |
1225f65d6f4SNico Boehr		jq -c 'select(has("event"))'
1235f65d6f4SNico Boehr}
1245f65d6f4SNico Boehr
12537abdda9SThomas Huthrun_migration ()
12637abdda9SThomas Huth{
127b508e114SJamie Iles	if ! command -v ncat >/dev/null 2>&1; then
128b508e114SJamie Iles		echo "${FUNCNAME[0]} needs ncat (netcat)" >&2
1292176d963SThomas Huth		return 77
13037abdda9SThomas Huth	fi
13137abdda9SThomas Huth
13214ea7bdaSNicholas Piggin	migcmdline=$@
13314ea7bdaSNicholas Piggin
134af3484fcSNicholas Piggin	trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
135cd45aeb7SNicholas Piggin	trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} ${dst_incoming} ${src_qmp} ${dst_qmp} ${dst_infifo}' RETURN EXIT
136af3484fcSNicholas Piggin
137cd45aeb7SNicholas Piggin	dst_incoming=$(mktemp -u -t mig-helper-socket-incoming.XXXXXXXXXX)
138cd45aeb7SNicholas Piggin	src_out=$(mktemp -t mig-helper-stdout1.XXXXXXXXXX)
139cd45aeb7SNicholas Piggin	src_outfifo=$(mktemp -u -t mig-helper-fifo-stdout1.XXXXXXXXXX)
140cd45aeb7SNicholas Piggin	dst_out=$(mktemp -t mig-helper-stdout2.XXXXXXXXXX)
141cd45aeb7SNicholas Piggin	dst_outfifo=$(mktemp -u -t mig-helper-fifo-stdout2.XXXXXXXXXX)
142cd45aeb7SNicholas Piggin	src_qmp=$(mktemp -u -t mig-helper-qmp1.XXXXXXXXXX)
143cd45aeb7SNicholas Piggin	dst_qmp=$(mktemp -u -t mig-helper-qmp2.XXXXXXXXXX)
144cd45aeb7SNicholas Piggin	dst_infifo=$(mktemp -u -t mig-helper-fifo-stdin.XXXXXXXXXX)
145cd45aeb7SNicholas Piggin	src_qmpout=/dev/null
146cd45aeb7SNicholas Piggin	dst_qmpout=/dev/null
14737abdda9SThomas Huth
148cd45aeb7SNicholas Piggin	mkfifo ${src_outfifo}
149cd45aeb7SNicholas Piggin	mkfifo ${dst_outfifo}
15014ea7bdaSNicholas Piggin
15114ea7bdaSNicholas Piggin	eval "$migcmdline" \
152cd45aeb7SNicholas Piggin		-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
153cd45aeb7SNicholas Piggin		-mon chardev=mon,mode=control > ${src_outfifo} &
154659557c0SNicholas Piggin	live_pid=$!
15571e3516bSNicholas Piggin	cat ${src_outfifo} | tee ${src_out} | grep -v "Now migrate the VM (quiet)" &
15637abdda9SThomas Huth
15714ea7bdaSNicholas Piggin	# Start the first destination QEMU machine in advance of the test
15814ea7bdaSNicholas Piggin	# reaching the migration point, since we expect at least one migration.
15914ea7bdaSNicholas Piggin	# Then destination machines are started after the test outputs
16014ea7bdaSNicholas Piggin	# subsequent "Now migrate the VM" messages.
16114ea7bdaSNicholas Piggin	do_migration || return $?
16237abdda9SThomas Huth
16314ea7bdaSNicholas Piggin	while ps -p ${live_pid} > /dev/null ; do
16414ea7bdaSNicholas Piggin		# Wait for test exit or further migration messages.
165cd45aeb7SNicholas Piggin		if ! grep -q -i "Now migrate the VM" < ${src_out} ; then
16614ea7bdaSNicholas Piggin			sleep 0.1
16714ea7bdaSNicholas Piggin		else
16814ea7bdaSNicholas Piggin			do_migration || return $?
16914ea7bdaSNicholas Piggin		fi
17014ea7bdaSNicholas Piggin	done
17114ea7bdaSNicholas Piggin
17214ea7bdaSNicholas Piggin	wait ${live_pid}
17314ea7bdaSNicholas Piggin	ret=$?
17414ea7bdaSNicholas Piggin
17514ea7bdaSNicholas Piggin	while (( $(jobs -r | wc -l) > 0 )); do
17614ea7bdaSNicholas Piggin		sleep 0.1
17714ea7bdaSNicholas Piggin	done
17814ea7bdaSNicholas Piggin
17914ea7bdaSNicholas Piggin	return $ret
18014ea7bdaSNicholas Piggin}
18114ea7bdaSNicholas Piggin
18214ea7bdaSNicholas Piggindo_migration ()
18314ea7bdaSNicholas Piggin{
18414ea7bdaSNicholas Piggin	# We have to use cat to open the named FIFO, because named FIFO's,
18514ea7bdaSNicholas Piggin	# unlike pipes, will block on open() until the other end is also
18614ea7bdaSNicholas Piggin	# opened, and that totally breaks QEMU...
187cd45aeb7SNicholas Piggin	mkfifo ${dst_infifo}
18814ea7bdaSNicholas Piggin	eval "$migcmdline" \
189cd45aeb7SNicholas Piggin		-chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \
190cd45aeb7SNicholas Piggin		-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
191cd45aeb7SNicholas Piggin		< <(cat ${dst_infifo}) > ${dst_outfifo} &
19214ea7bdaSNicholas Piggin	incoming_pid=$!
19371e3516bSNicholas Piggin	cat ${dst_outfifo} | tee ${dst_out} | grep -v "Now migrate the VM (quiet)" &
19414ea7bdaSNicholas Piggin
19514ea7bdaSNicholas Piggin	# The test must prompt the user to migrate, so wait for the
19614ea7bdaSNicholas Piggin	# "Now migrate VM" console message.
197cd45aeb7SNicholas Piggin	while ! grep -q -i "Now migrate the VM" < ${src_out} ; do
198bfe5d7d0SNicholas Piggin		if ! ps -p ${live_pid} > /dev/null ; then
199bfe5d7d0SNicholas Piggin			echo "ERROR: Test exit before migration point." >&2
200cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
201cd45aeb7SNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
202cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
203bfe5d7d0SNicholas Piggin			return 3
204bfe5d7d0SNicholas Piggin		fi
20514ea7bdaSNicholas Piggin		sleep 0.1
20637abdda9SThomas Huth	done
20737abdda9SThomas Huth
208659557c0SNicholas Piggin	# Wait until the destination has created the incoming and qmp sockets
209cd45aeb7SNicholas Piggin	while ! [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
210cd45aeb7SNicholas Piggin	while ! [ -S ${dst_qmp} ] ; do sleep 0.1 ; done
211659557c0SNicholas Piggin
212cd45aeb7SNicholas Piggin	qmp ${src_qmp} '"migrate", "arguments": { "uri": "unix:'${dst_incoming}'" }' > ${src_qmpout}
21337abdda9SThomas Huth
21437abdda9SThomas Huth	# Wait for the migration to complete
215cd45aeb7SNicholas Piggin	migstatus=`qmp ${src_qmp} '"query-migrate"' | grep return`
21637abdda9SThomas Huth	while ! grep -q '"completed"' <<<"$migstatus" ; do
21714ea7bdaSNicholas Piggin		sleep 0.1
218cd45aeb7SNicholas Piggin		if ! migstatus=`qmp ${src_qmp} '"query-migrate"'`; then
21909e8c119SNico Boehr			echo "ERROR: Querying migration state failed." >&2
220cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
221cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
22209e8c119SNico Boehr			return 2
22309e8c119SNico Boehr		fi
22409e8c119SNico Boehr		migstatus=`grep return <<<"$migstatus"`
22537abdda9SThomas Huth		if grep -q '"failed"' <<<"$migstatus"; then
22637abdda9SThomas Huth			echo "ERROR: Migration failed." >&2
227cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
228cd45aeb7SNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
229cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
2309806f62dSAndrew Jones			return 2
23137abdda9SThomas Huth		fi
23237abdda9SThomas Huth	done
23314ea7bdaSNicholas Piggin
234cd45aeb7SNicholas Piggin	qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
23514ea7bdaSNicholas Piggin
23614ea7bdaSNicholas Piggin	# keypress to dst so getchar completes and test continues
237cd45aeb7SNicholas Piggin	echo > ${dst_infifo}
238cd45aeb7SNicholas Piggin	rm ${dst_infifo}
23914ea7bdaSNicholas Piggin
2404b54f4faSNico Boehr	# Wait for the incoming socket being removed, ready for next destination
2414b54f4faSNico Boehr	while [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
24214ea7bdaSNicholas Piggin
24314ea7bdaSNicholas Piggin	wait ${live_pid}
2449806f62dSAndrew Jones	ret=$?
245394d1421SAndrew Jones
246cd45aeb7SNicholas Piggin	# Now flip the variables because destination machine becomes source
247cd45aeb7SNicholas Piggin	# for the next migration.
24814ea7bdaSNicholas Piggin	live_pid=${incoming_pid}
249cd45aeb7SNicholas Piggin	tmp=${src_out}
250cd45aeb7SNicholas Piggin	src_out=${dst_out}
251cd45aeb7SNicholas Piggin	dst_out=${tmp}
252cd45aeb7SNicholas Piggin	tmp=${src_outfifo}
253cd45aeb7SNicholas Piggin	src_outfifo=${dst_outfifo}
254cd45aeb7SNicholas Piggin	dst_outfifo=${tmp}
255cd45aeb7SNicholas Piggin	tmp=${src_qmp}
256cd45aeb7SNicholas Piggin	src_qmp=${dst_qmp}
257cd45aeb7SNicholas Piggin	dst_qmp=${tmp}
258394d1421SAndrew Jones
2599806f62dSAndrew Jones	return $ret
26037abdda9SThomas Huth}
26137abdda9SThomas Huth
2625f65d6f4SNico Boehrrun_panic ()
2635f65d6f4SNico Boehr{
2645f65d6f4SNico Boehr	if ! command -v ncat >/dev/null 2>&1; then
2655f65d6f4SNico Boehr		echo "${FUNCNAME[0]} needs ncat (netcat)" >&2
2665f65d6f4SNico Boehr		return 77
2675f65d6f4SNico Boehr	fi
2685f65d6f4SNico Boehr
2695f65d6f4SNico Boehr	if ! command -v jq >/dev/null 2>&1; then
2705f65d6f4SNico Boehr		echo "${FUNCNAME[0]} needs jq" >&2
2715f65d6f4SNico Boehr		return 77
2725f65d6f4SNico Boehr	fi
2735f65d6f4SNico Boehr
274af3484fcSNicholas Piggin	trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
2755f65d6f4SNico Boehr	trap 'rm -f ${qmp}' RETURN EXIT
2765f65d6f4SNico Boehr
277af3484fcSNicholas Piggin	qmp=$(mktemp -u -t panic-qmp.XXXXXXXXXX)
278af3484fcSNicholas Piggin
2795f65d6f4SNico Boehr	# start VM stopped so we don't miss any events
280cd45aeb7SNicholas Piggin	eval "$@" -chardev socket,id=mon,path=${qmp},server=on,wait=off \
281cd45aeb7SNicholas Piggin		-mon chardev=mon,mode=control -S &
2825f65d6f4SNico Boehr
2835f65d6f4SNico Boehr	panic_event_count=$(qmp_events ${qmp} | jq -c 'select(.event == "GUEST_PANICKED")' | wc -l)
2845f65d6f4SNico Boehr	if [ "$panic_event_count" -lt 1 ]; then
2855f65d6f4SNico Boehr		echo "FAIL: guest did not panic"
2865f65d6f4SNico Boehr		ret=3
2875f65d6f4SNico Boehr	else
2885f65d6f4SNico Boehr		# some QEMU versions report multiple panic events
2895f65d6f4SNico Boehr		echo "PASS: guest panicked"
2905f65d6f4SNico Boehr		ret=1
2915f65d6f4SNico Boehr	fi
2925f65d6f4SNico Boehr
2935f65d6f4SNico Boehr	return $ret
2945f65d6f4SNico Boehr}
2955f65d6f4SNico Boehr
29637abdda9SThomas Huthmigration_cmd ()
29737abdda9SThomas Huth{
29837abdda9SThomas Huth	if [ "$MIGRATION" = "yes" ]; then
29937abdda9SThomas Huth		echo "run_migration"
30037abdda9SThomas Huth	fi
30137abdda9SThomas Huth}
302531326aeSBalamuruhan S
3035f65d6f4SNico Boehrpanic_cmd ()
3045f65d6f4SNico Boehr{
3055f65d6f4SNico Boehr	if [ "$PANIC" = "yes" ]; then
3065f65d6f4SNico Boehr		echo "run_panic"
3075f65d6f4SNico Boehr	fi
3085f65d6f4SNico Boehr}
3095f65d6f4SNico Boehr
310531326aeSBalamuruhan Ssearch_qemu_binary ()
311531326aeSBalamuruhan S{
312531326aeSBalamuruhan S	local save_path=$PATH
313232f404aSAndrew Jones	local qemucmd qemu
314232f404aSAndrew Jones
315ee5a8a1aSAndrew Jones	: "${QEMU_ARCH:=$ARCH_NAME}"
316ee5a8a1aSAndrew Jones
317531326aeSBalamuruhan S	export PATH=$PATH:/usr/libexec
318ee5a8a1aSAndrew Jones	for qemucmd in ${QEMU:-qemu-system-$QEMU_ARCH qemu-kvm}; do
319232f404aSAndrew Jones		if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then
320232f404aSAndrew Jones			qemu="$qemucmd"
321531326aeSBalamuruhan S			break
322531326aeSBalamuruhan S		fi
323531326aeSBalamuruhan S	done
324531326aeSBalamuruhan S
325232f404aSAndrew Jones	if [ -z "$qemu" ]; then
326fcf4e0d9SRadim Krčmář		echo "A QEMU binary was not found." >&2
327fcf4e0d9SRadim Krčmář		echo "You can set a custom location by using the QEMU=<path> environment variable." >&2
328fcf4e0d9SRadim Krčmář		return 2
329531326aeSBalamuruhan S	fi
330232f404aSAndrew Jones	command -v $qemu
331531326aeSBalamuruhan S	export PATH=$save_path
332531326aeSBalamuruhan S}
3334da0bc9aSAndrew Jones
334c8764266SNicholas Piggininitrd_cleanup ()
335c8764266SNicholas Piggin{
336c8764266SNicholas Piggin	rm -f $KVM_UNIT_TESTS_ENV
337c8764266SNicholas Piggin	if [ "$KVM_UNIT_TESTS_ENV_OLD" ]; then
338c8764266SNicholas Piggin		export KVM_UNIT_TESTS_ENV="$KVM_UNIT_TESTS_ENV_OLD"
339c8764266SNicholas Piggin	else
340c8764266SNicholas Piggin		unset KVM_UNIT_TESTS_ENV
341c8764266SNicholas Piggin	fi
342c8764266SNicholas Piggin	unset KVM_UNIT_TESTS_ENV_OLD
343c8764266SNicholas Piggin}
344c8764266SNicholas Piggin
3454da0bc9aSAndrew Jonesinitrd_create ()
3464da0bc9aSAndrew Jones{
347b16df9eeSAndrew Jones	if [ "$ENVIRON_DEFAULT" = "yes" ]; then
348c8764266SNicholas Piggin		trap_exit_push 'initrd_cleanup'
349b16df9eeSAndrew Jones		[ -f "$KVM_UNIT_TESTS_ENV" ] && export KVM_UNIT_TESTS_ENV_OLD="$KVM_UNIT_TESTS_ENV"
350b16df9eeSAndrew Jones		export KVM_UNIT_TESTS_ENV=$(mktemp)
351b16df9eeSAndrew Jones		env_params
352b16df9eeSAndrew Jones		env_file
353b16df9eeSAndrew Jones		env_errata || return $?
354b16df9eeSAndrew Jones	fi
3558b13a5b5SRadim Krčmář
3564da0bc9aSAndrew Jones	unset INITRD
35763dd93ecSAndrew Jones	[ -f "$KVM_UNIT_TESTS_ENV" ] && INITRD="-initrd $KVM_UNIT_TESTS_ENV"
3588b13a5b5SRadim Krčmář
359b16df9eeSAndrew Jones	return 0
3604da0bc9aSAndrew Jones}
3618ec99569SAndrew Jones
362b16df9eeSAndrew Jonesenv_add_params ()
3638ec99569SAndrew Jones{
364b16df9eeSAndrew Jones	local p
3658ec99569SAndrew Jones
366b16df9eeSAndrew Jones	for p in "$@"; do
367b16df9eeSAndrew Jones		if eval test -v $p; then
368b16df9eeSAndrew Jones			eval export "$p"
369b16df9eeSAndrew Jones		else
370b16df9eeSAndrew Jones			eval export "$p="
371b16df9eeSAndrew Jones		fi
372b16df9eeSAndrew Jones		grep "^$p=" <(env) >>$KVM_UNIT_TESTS_ENV
3738ec99569SAndrew Jones	done
374b16df9eeSAndrew Jones}
375b16df9eeSAndrew Jones
376b16df9eeSAndrew Jonesenv_params ()
377b16df9eeSAndrew Jones{
378b16df9eeSAndrew Jones	local qemu have_qemu
379b16df9eeSAndrew Jones	local _ rest
380b16df9eeSAndrew Jones
381b16df9eeSAndrew Jones	qemu=$(search_qemu_binary) && have_qemu=1
382b16df9eeSAndrew Jones
383b16df9eeSAndrew Jones	if [ "$have_qemu" ]; then
384b16df9eeSAndrew Jones		if [ -n "$ACCEL" ] || [ -n "$QEMU_ACCEL" ]; then
385b16df9eeSAndrew Jones			[ -n "$ACCEL" ] && QEMU_ACCEL=$ACCEL
386b16df9eeSAndrew Jones		fi
387b16df9eeSAndrew Jones		QEMU_VERSION_STRING="$($qemu -h | head -1)"
388b16df9eeSAndrew Jones		IFS='[ .]' read -r _ _ _ QEMU_MAJOR QEMU_MINOR QEMU_MICRO rest <<<"$QEMU_VERSION_STRING"
389b16df9eeSAndrew Jones	fi
390b16df9eeSAndrew Jones	env_add_params QEMU_ACCEL QEMU_VERSION_STRING QEMU_MAJOR QEMU_MINOR QEMU_MICRO
391b16df9eeSAndrew Jones
392b16df9eeSAndrew Jones	KERNEL_VERSION_STRING=$(uname -r)
393b16df9eeSAndrew Jones	IFS=. read -r KERNEL_VERSION KERNEL_PATCHLEVEL rest <<<"$KERNEL_VERSION_STRING"
394b16df9eeSAndrew Jones	IFS=- read -r KERNEL_SUBLEVEL KERNEL_EXTRAVERSION <<<"$rest"
395b16df9eeSAndrew Jones	KERNEL_SUBLEVEL=${KERNEL_SUBLEVEL%%[!0-9]*}
396b16df9eeSAndrew Jones	KERNEL_EXTRAVERSION=${KERNEL_EXTRAVERSION%%[!0-9]*}
397b16df9eeSAndrew Jones	! [[ $KERNEL_SUBLEVEL =~ ^[0-9]+$ ]] && unset $KERNEL_SUBLEVEL
398b16df9eeSAndrew Jones	! [[ $KERNEL_EXTRAVERSION =~ ^[0-9]+$ ]] && unset $KERNEL_EXTRAVERSION
399b16df9eeSAndrew Jones	env_add_params KERNEL_VERSION_STRING KERNEL_VERSION KERNEL_PATCHLEVEL KERNEL_SUBLEVEL KERNEL_EXTRAVERSION
400b16df9eeSAndrew Jones}
401b16df9eeSAndrew Jones
402b16df9eeSAndrew Jonesenv_file ()
403b16df9eeSAndrew Jones{
404b16df9eeSAndrew Jones	local line var
405b16df9eeSAndrew Jones
406b16df9eeSAndrew Jones	[ ! -f "$KVM_UNIT_TESTS_ENV_OLD" ] && return
407b16df9eeSAndrew Jones
408b16df9eeSAndrew Jones	for line in $(grep -E '^[[:blank:]]*[[:alpha:]_][[:alnum:]_]*=' "$KVM_UNIT_TESTS_ENV_OLD"); do
409b16df9eeSAndrew Jones		var=${line%%=*}
410b16df9eeSAndrew Jones		if ! grep -q "^$var=" $KVM_UNIT_TESTS_ENV; then
411b16df9eeSAndrew Jones			eval export "$line"
412b16df9eeSAndrew Jones			grep "^$var=" <(env) >>$KVM_UNIT_TESTS_ENV
413b16df9eeSAndrew Jones		fi
414b16df9eeSAndrew Jones	done
415b16df9eeSAndrew Jones}
416b16df9eeSAndrew Jones
417b16df9eeSAndrew Jonesenv_errata ()
418b16df9eeSAndrew Jones{
419*d50fa5a8SNicholas Piggin	local new_env
420*d50fa5a8SNicholas Piggin
421ec2f5147SAlex Bennée	if [ "$ACCEL" = "tcg" ]; then
422ec2f5147SAlex Bennée		export "ERRATA_FORCE=y"
423ec2f5147SAlex Bennée	elif [ "$ERRATATXT" ] && [ ! -f "$ERRATATXT" ]; then
424b16df9eeSAndrew Jones		echo "$ERRATATXT not found. (ERRATATXT=$ERRATATXT)" >&2
425b16df9eeSAndrew Jones		return 2
426b16df9eeSAndrew Jones	elif [ "$ERRATATXT" ]; then
42770fcb64bSAndrew Jones		env_generate_errata
4288ec99569SAndrew Jones	fi
429*d50fa5a8SNicholas Piggin	new_env=$(sort <(env | grep '^ERRATA_') <(grep '^ERRATA_' $KVM_UNIT_TESTS_ENV) | uniq -u)
430*d50fa5a8SNicholas Piggin	echo "$new_env" >>$KVM_UNIT_TESTS_ENV
4318ec99569SAndrew Jones}
4328ec99569SAndrew Jones
43370fcb64bSAndrew Jonesenv_generate_errata ()
43470fcb64bSAndrew Jones{
43512a4328eSAndrew Jones	local line commit minver errata rest v p s x have
43670fcb64bSAndrew Jones
4371ea4709cSAndrew Jones	for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do
43870fcb64bSAndrew Jones		commit=${line%:*}
43970fcb64bSAndrew Jones		minver=${line#*:}
44070fcb64bSAndrew Jones
441171aa3a2SPeter Shier		test -z "$commit" && continue
44270fcb64bSAndrew Jones		errata="ERRATA_$commit"
443d1bc9395SAndrew Jones		[ -n "${!errata}" ] && continue
44470fcb64bSAndrew Jones
445d38b111bSJim Mattson		IFS=. read -r v p rest <<<"$minver"
446d38b111bSJim Mattson		IFS=- read -r s x <<<"$rest"
44770fcb64bSAndrew Jones		s=${s%%[!0-9]*}
44812a4328eSAndrew Jones		x=${x%%[!0-9]*}
44912a4328eSAndrew Jones
45012a4328eSAndrew Jones		if ! [[ $v =~ ^[0-9]+$ ]] || ! [[ $p =~ ^[0-9]+$ ]]; then
45112a4328eSAndrew Jones			echo "Bad minimum kernel version in $ERRATATXT, $minver"
4529806f62dSAndrew Jones			return 2
45312a4328eSAndrew Jones		fi
45412a4328eSAndrew Jones		! [[ $s =~ ^[0-9]+$ ]] && unset $s
45512a4328eSAndrew Jones		! [[ $x =~ ^[0-9]+$ ]] && unset $x
45670fcb64bSAndrew Jones
457b16df9eeSAndrew Jones		if (( $KERNEL_VERSION > $v ||
458b16df9eeSAndrew Jones		      ($KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL > $p) )); then
45970fcb64bSAndrew Jones			have=y
460b16df9eeSAndrew Jones		elif (( $KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL == $p )); then
461b16df9eeSAndrew Jones			if [ "$KERNEL_SUBLEVEL" ] && [ "$s" ]; then
462b16df9eeSAndrew Jones				if (( $KERNEL_SUBLEVEL > $s )); then
46370fcb64bSAndrew Jones					have=y
464b16df9eeSAndrew Jones				elif (( $KERNEL_SUBLEVEL == $s )); then
465b16df9eeSAndrew Jones					if [ "$KERNEL_EXTRAVERSION" ] && [ "$x" ]; then
466b16df9eeSAndrew Jones						if (( $KERNEL_EXTRAVERSION >= $x )); then
46712a4328eSAndrew Jones							have=y
46812a4328eSAndrew Jones						else
46912a4328eSAndrew Jones							have=n
47012a4328eSAndrew Jones						fi
47112a4328eSAndrew Jones					elif [ "$x" ] && (( $x != 0 )); then
47212a4328eSAndrew Jones						have=n
47312a4328eSAndrew Jones					else
47412a4328eSAndrew Jones						have=y
47512a4328eSAndrew Jones					fi
47670fcb64bSAndrew Jones				else
47770fcb64bSAndrew Jones					have=n
47870fcb64bSAndrew Jones				fi
47970fcb64bSAndrew Jones			elif [ "$s" ] && (( $s != 0 )); then
48070fcb64bSAndrew Jones				have=n
48170fcb64bSAndrew Jones			else
48270fcb64bSAndrew Jones				have=y
48370fcb64bSAndrew Jones			fi
48470fcb64bSAndrew Jones		else
48570fcb64bSAndrew Jones			have=n
48670fcb64bSAndrew Jones		fi
48770fcb64bSAndrew Jones		eval export "$errata=$have"
48870fcb64bSAndrew Jones	done
48970fcb64bSAndrew Jones}
49070fcb64bSAndrew Jones
4918ec99569SAndrew Jonestrap_exit_push ()
4928ec99569SAndrew Jones{
4938ec99569SAndrew Jones	local old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//")
4948ec99569SAndrew Jones	trap -- "$1; $old_exit" EXIT
4958ec99569SAndrew Jones}
496f4d99928SRadim Krčmář
497f4d99928SRadim Krčmářkvm_available ()
498f4d99928SRadim Krčmář{
499f4d99928SRadim Krčmář	[ -c /dev/kvm ] ||
500f4d99928SRadim Krčmář		return 1
501f4d99928SRadim Krčmář
502f4d99928SRadim Krčmář	[ "$HOST" = "$ARCH_NAME" ] ||
503d76bf076SAndrew Jones		( [ "$HOST" = aarch64 ] && [ "$ARCH" = arm ] ) ||
504d76bf076SAndrew Jones		( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] )
505f4d99928SRadim Krčmář}
506f4d99928SRadim Krčmář
5077edd698eSRoman Bolshakovhvf_available ()
5087edd698eSRoman Bolshakov{
5097edd698eSRoman Bolshakov	[ "$(sysctl -n kern.hv_support 2>/dev/null)" = "1" ] || return 1
5107edd698eSRoman Bolshakov	[ "$HOST" = "$ARCH_NAME" ] ||
5117edd698eSRoman Bolshakov		( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] )
5127edd698eSRoman Bolshakov}
5137edd698eSRoman Bolshakov
51401e047d0SGavin Shanset_qemu_accelerator ()
515f4d99928SRadim Krčmář{
51601e047d0SGavin Shan	ACCEL_PROPS=${ACCEL#"${ACCEL%%,*}"}
51701e047d0SGavin Shan	ACCEL=${ACCEL%%,*}
51801e047d0SGavin Shan
519f4d99928SRadim Krčmář	if [ "$ACCEL" = "kvm" ] && ! kvm_available; then
520f4d99928SRadim Krčmář		echo "KVM is needed, but not available on this host" >&2
521f4d99928SRadim Krčmář		return 2
522f4d99928SRadim Krčmář	fi
5237edd698eSRoman Bolshakov	if [ "$ACCEL" = "hvf" ] && ! hvf_available; then
5247edd698eSRoman Bolshakov		echo "HVF is needed, but not available on this host" >&2
5257edd698eSRoman Bolshakov		return 2
5267edd698eSRoman Bolshakov	fi
527f4d99928SRadim Krčmář
52801e047d0SGavin Shan	if [ -z "$ACCEL" ]; then
52901e047d0SGavin Shan		if kvm_available; then
53001e047d0SGavin Shan			ACCEL="kvm"
5317edd698eSRoman Bolshakov		elif hvf_available; then
53201e047d0SGavin Shan			ACCEL="hvf"
533f4d99928SRadim Krčmář		else
53401e047d0SGavin Shan			ACCEL="tcg"
535f4d99928SRadim Krčmář		fi
53601e047d0SGavin Shan	fi
53701e047d0SGavin Shan
53801e047d0SGavin Shan	return 0
539f4d99928SRadim Krčmář}
540