xref: /kvm-unit-tests/scripts/arch-run.bash (revision 171aa3a27b24f5314c20f32b337e743f4cd2616d)
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
31d76bf076SAndrew Jones	echo -n "$@"
328b13a5b5SRadim Krčmář	initrd_create &&
338b13a5b5SRadim Krčmář		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
82e0a8391eSRadim Krčmář		testret=$(grep '^EXIT: ' <<<"$lines" | 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{
97fd149358SAndrew Jones	if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then
98fd149358SAndrew Jones		echo "timeout -k 1s --foreground $TIMEOUT"
99fd149358SAndrew Jones	fi
100fd149358SAndrew Jones}
10137abdda9SThomas Huth
10237abdda9SThomas Huthqmp ()
10337abdda9SThomas Huth{
10437abdda9SThomas Huth	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
10537abdda9SThomas Huth}
10637abdda9SThomas Huth
10737abdda9SThomas Huthrun_migration ()
10837abdda9SThomas Huth{
10937abdda9SThomas Huth	if ! command -v nc >/dev/null 2>&1; then
110d76bf076SAndrew Jones		echo "${FUNCNAME[0]} needs nc (netcat)" >&2
1119806f62dSAndrew Jones		return 2
11237abdda9SThomas Huth	fi
11337abdda9SThomas Huth
11437abdda9SThomas Huth	migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX`
11537abdda9SThomas Huth	migout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX`
11637abdda9SThomas Huth	qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX`
11737abdda9SThomas Huth	qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX`
118ffd9da55SAndrew Jones	fifo=`mktemp -u -t mig-helper-fifo.XXXXXXXXXX`
11937abdda9SThomas Huth	qmpout1=/dev/null
12037abdda9SThomas Huth	qmpout2=/dev/null
12137abdda9SThomas Huth
1229806f62dSAndrew Jones	trap 'kill 0; exit 2' INT TERM
123ffd9da55SAndrew Jones	trap 'rm -f ${migout1} ${migsock} ${qmp1} ${qmp2} ${fifo}' RETURN EXIT
12437abdda9SThomas Huth
1259806f62dSAndrew Jones	eval "$@" -chardev socket,id=mon1,path=${qmp1},server,nowait \
12637abdda9SThomas Huth		-mon chardev=mon1,mode=control | tee ${migout1} &
12737abdda9SThomas Huth
128ffd9da55SAndrew Jones	# We have to use cat to open the named FIFO, because named FIFO's, unlike
129ffd9da55SAndrew Jones	# pipes, will block on open() until the other end is also opened, and that
130ffd9da55SAndrew Jones	# totally breaks QEMU...
131ffd9da55SAndrew Jones	mkfifo ${fifo}
1329806f62dSAndrew Jones	eval "$@" -chardev socket,id=mon2,path=${qmp2},server,nowait \
133ffd9da55SAndrew Jones		-mon chardev=mon2,mode=control -incoming unix:${migsock} < <(cat ${fifo}) &
1349806f62dSAndrew Jones	incoming_pid=`jobs -l %+ | awk '{print$2}'`
13537abdda9SThomas Huth
13637abdda9SThomas Huth	# The test must prompt the user to migrate, so wait for the "migrate" keyword
13737abdda9SThomas Huth	while ! grep -q -i "migrate" < ${migout1} ; do
13837abdda9SThomas Huth		sleep 1
13937abdda9SThomas Huth	done
14037abdda9SThomas Huth
14137abdda9SThomas Huth	qmp ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1}
14237abdda9SThomas Huth
14337abdda9SThomas Huth	# Wait for the migration to complete
14437abdda9SThomas Huth	migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
14537abdda9SThomas Huth	while ! grep -q '"completed"' <<<"$migstatus" ; do
14637abdda9SThomas Huth		sleep 1
14737abdda9SThomas Huth		migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
14837abdda9SThomas Huth		if grep -q '"failed"' <<<"$migstatus" ; then
14937abdda9SThomas Huth			echo "ERROR: Migration failed." >&2
15037abdda9SThomas Huth			qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
15137abdda9SThomas Huth			qmp ${qmp2} '"quit"'> ${qmpout2} 2>/dev/null
1529806f62dSAndrew Jones			return 2
15337abdda9SThomas Huth		fi
15437abdda9SThomas Huth	done
15537abdda9SThomas Huth	qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
156ffd9da55SAndrew Jones	echo > ${fifo}
1579806f62dSAndrew Jones	wait $incoming_pid
1589806f62dSAndrew Jones	ret=$?
15937abdda9SThomas Huth	wait
1609806f62dSAndrew Jones	return $ret
16137abdda9SThomas Huth}
16237abdda9SThomas Huth
16337abdda9SThomas Huthmigration_cmd ()
16437abdda9SThomas Huth{
16537abdda9SThomas Huth	if [ "$MIGRATION" = "yes" ]; then
16637abdda9SThomas Huth		echo "run_migration"
16737abdda9SThomas Huth	fi
16837abdda9SThomas Huth}
169531326aeSBalamuruhan S
170531326aeSBalamuruhan Ssearch_qemu_binary ()
171531326aeSBalamuruhan S{
172531326aeSBalamuruhan S	local save_path=$PATH
173232f404aSAndrew Jones	local qemucmd qemu
174232f404aSAndrew Jones
175531326aeSBalamuruhan S	export PATH=$PATH:/usr/libexec
176232f404aSAndrew Jones	for qemucmd in ${QEMU:-qemu-system-$ARCH_NAME qemu-kvm}; do
177232f404aSAndrew Jones		if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then
178232f404aSAndrew Jones			qemu="$qemucmd"
179531326aeSBalamuruhan S			break
180531326aeSBalamuruhan S		fi
181531326aeSBalamuruhan S	done
182531326aeSBalamuruhan S
183232f404aSAndrew Jones	if [ -z "$qemu" ]; then
184fcf4e0d9SRadim Krčmář		echo "A QEMU binary was not found." >&2
185fcf4e0d9SRadim Krčmář		echo "You can set a custom location by using the QEMU=<path> environment variable." >&2
186fcf4e0d9SRadim Krčmář		return 2
187531326aeSBalamuruhan S	fi
188232f404aSAndrew Jones	command -v $qemu
189531326aeSBalamuruhan S	export PATH=$save_path
190531326aeSBalamuruhan S}
1914da0bc9aSAndrew Jones
1924da0bc9aSAndrew Jonesinitrd_create ()
1934da0bc9aSAndrew Jones{
1948b13a5b5SRadim Krčmář	local ret
1958b13a5b5SRadim Krčmář
1968ec99569SAndrew Jones	env_add_errata
1978b13a5b5SRadim Krčmář	ret=$?
1988b13a5b5SRadim Krčmář
1994da0bc9aSAndrew Jones	unset INITRD
2004da0bc9aSAndrew Jones	[ -f "$ENV" ] && INITRD="-initrd $ENV"
2018b13a5b5SRadim Krčmář
2028b13a5b5SRadim Krčmář	return $ret
2034da0bc9aSAndrew Jones}
2048ec99569SAndrew Jones
2058ec99569SAndrew Jonesenv_add_errata ()
2068ec99569SAndrew Jones{
2078b13a5b5SRadim Krčmář	local line errata ret=1
2088ec99569SAndrew Jones
2098ec99569SAndrew Jones	if [ -f "$ENV" ] && grep -q '^ERRATA_' <(env); then
2108ec99569SAndrew Jones		for line in $(grep '^ERRATA_' "$ENV"); do
2118ec99569SAndrew Jones			errata=${line%%=*}
2128ec99569SAndrew Jones			test -v $errata && continue
2138ec99569SAndrew Jones			eval export "$line"
2148ec99569SAndrew Jones		done
21570fcb64bSAndrew Jones	elif [ ! -f "$ENV" ]; then
21670fcb64bSAndrew Jones		env_generate_errata
2178ec99569SAndrew Jones	fi
2188ec99569SAndrew Jones
2198ec99569SAndrew Jones	if grep -q '^ERRATA_' <(env); then
2208ec99569SAndrew Jones		export ENV_OLD="$ENV"
2218ec99569SAndrew Jones		export ENV=$(mktemp)
2228ec99569SAndrew Jones		trap_exit_push 'rm -f $ENV; [ "$ENV_OLD" ] && export ENV="$ENV_OLD" || unset ENV; unset ENV_OLD'
2238ec99569SAndrew Jones		[ -f "$ENV_OLD" ] && grep -v '^ERRATA_' "$ENV_OLD" > $ENV
2248ec99569SAndrew Jones		grep '^ERRATA_' <(env) >> $ENV
2258b13a5b5SRadim Krčmář		ret=0
2268ec99569SAndrew Jones	fi
2278b13a5b5SRadim Krčmář
2288b13a5b5SRadim Krčmář	return $ret
2298ec99569SAndrew Jones}
2308ec99569SAndrew Jones
23170fcb64bSAndrew Jonesenv_generate_errata ()
23270fcb64bSAndrew Jones{
23370fcb64bSAndrew Jones	local kernel_version_string=$(uname -r)
23412a4328eSAndrew Jones	local kernel_version kernel_patchlevel kernel_sublevel kernel_extraversion
23512a4328eSAndrew Jones	local line commit minver errata rest v p s x have
23670fcb64bSAndrew Jones
237*171aa3a2SPeter Shier	IFS=. read -r kernel_version kernel_patchlevel rest <<<"$kernel_version_string"
238*171aa3a2SPeter Shier	IFS=- read -r kernel_sublevel kernel_extraversion <<<"$rest"
23970fcb64bSAndrew Jones	kernel_sublevel=${kernel_sublevel%%[!0-9]*}
24012a4328eSAndrew Jones	kernel_extraversion=${kernel_extraversion%%[!0-9]*}
24112a4328eSAndrew Jones
24212a4328eSAndrew Jones	! [[ $kernel_sublevel =~ ^[0-9]+$ ]] && unset $kernel_sublevel
24312a4328eSAndrew Jones	! [[ $kernel_extraversion =~ ^[0-9]+$ ]] && unset $kernel_extraversion
24470fcb64bSAndrew Jones
24570fcb64bSAndrew Jones	[ "$ENVIRON_DEFAULT" != "yes" ] && return
2461ea4709cSAndrew Jones	[ ! -f "$ERRATATXT" ] && return
24770fcb64bSAndrew Jones
2481ea4709cSAndrew Jones	for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do
24970fcb64bSAndrew Jones		commit=${line%:*}
25070fcb64bSAndrew Jones		minver=${line#*:}
25170fcb64bSAndrew Jones
252*171aa3a2SPeter Shier		test -z "$commit" && continue
25370fcb64bSAndrew Jones		errata="ERRATA_$commit"
25470fcb64bSAndrew Jones
255d38b111bSJim Mattson		IFS=. read -r v p rest <<<"$minver"
256d38b111bSJim Mattson		IFS=- read -r s x <<<"$rest"
25770fcb64bSAndrew Jones		s=${s%%[!0-9]*}
25812a4328eSAndrew Jones		x=${x%%[!0-9]*}
25912a4328eSAndrew Jones
26012a4328eSAndrew Jones		if ! [[ $v =~ ^[0-9]+$ ]] || ! [[ $p =~ ^[0-9]+$ ]]; then
26112a4328eSAndrew Jones			echo "Bad minimum kernel version in $ERRATATXT, $minver"
2629806f62dSAndrew Jones			return 2
26312a4328eSAndrew Jones		fi
26412a4328eSAndrew Jones		! [[ $s =~ ^[0-9]+$ ]] && unset $s
26512a4328eSAndrew Jones		! [[ $x =~ ^[0-9]+$ ]] && unset $x
26670fcb64bSAndrew Jones
26770fcb64bSAndrew Jones		if (( $kernel_version > $v ||
26870fcb64bSAndrew Jones		      ($kernel_version == $v && $kernel_patchlevel > $p) )); then
26970fcb64bSAndrew Jones			have=y
27070fcb64bSAndrew Jones		elif (( $kernel_version == $v && $kernel_patchlevel == $p )); then
27170fcb64bSAndrew Jones			if [ "$kernel_sublevel" ] && [ "$s" ]; then
27212a4328eSAndrew Jones				if (( $kernel_sublevel > $s )); then
27370fcb64bSAndrew Jones					have=y
27412a4328eSAndrew Jones				elif (( $kernel_sublevel == $s )); then
27512a4328eSAndrew Jones					if [ "$kernel_extraversion" ] && [ "$x" ]; then
27612a4328eSAndrew Jones						if (( $kernel_extraversion >= $x )); then
27712a4328eSAndrew Jones							have=y
27812a4328eSAndrew Jones						else
27912a4328eSAndrew Jones							have=n
28012a4328eSAndrew Jones						fi
28112a4328eSAndrew Jones					elif [ "$x" ] && (( $x != 0 )); then
28212a4328eSAndrew Jones						have=n
28312a4328eSAndrew Jones					else
28412a4328eSAndrew Jones						have=y
28512a4328eSAndrew Jones					fi
28670fcb64bSAndrew Jones				else
28770fcb64bSAndrew Jones					have=n
28870fcb64bSAndrew Jones				fi
28970fcb64bSAndrew Jones			elif [ "$s" ] && (( $s != 0 )); then
29070fcb64bSAndrew Jones				have=n
29170fcb64bSAndrew Jones			else
29270fcb64bSAndrew Jones				have=y
29370fcb64bSAndrew Jones			fi
29470fcb64bSAndrew Jones		else
29570fcb64bSAndrew Jones			have=n
29670fcb64bSAndrew Jones		fi
29770fcb64bSAndrew Jones		eval export "$errata=$have"
29870fcb64bSAndrew Jones	done
29970fcb64bSAndrew Jones}
30070fcb64bSAndrew Jones
3018ec99569SAndrew Jonestrap_exit_push ()
3028ec99569SAndrew Jones{
3038ec99569SAndrew Jones	local old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//")
3048ec99569SAndrew Jones	trap -- "$1; $old_exit" EXIT
3058ec99569SAndrew Jones}
306f4d99928SRadim Krčmář
307f4d99928SRadim Krčmářkvm_available ()
308f4d99928SRadim Krčmář{
309f4d99928SRadim Krčmář	[ -c /dev/kvm ] ||
310f4d99928SRadim Krčmář		return 1
311f4d99928SRadim Krčmář
312f4d99928SRadim Krčmář	[ "$HOST" = "$ARCH_NAME" ] ||
313d76bf076SAndrew Jones		( [ "$HOST" = aarch64 ] && [ "$ARCH" = arm ] ) ||
314d76bf076SAndrew Jones		( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] )
315f4d99928SRadim Krčmář}
316f4d99928SRadim Krčmář
317f4d99928SRadim Krčmářget_qemu_accelerator ()
318f4d99928SRadim Krčmář{
319f4d99928SRadim Krčmář	if [ "$ACCEL" = "kvm" ] && ! kvm_available; then
320f4d99928SRadim Krčmář		echo "KVM is needed, but not available on this host" >&2
321f4d99928SRadim Krčmář		return 2
322f4d99928SRadim Krčmář	fi
323f4d99928SRadim Krčmář
324f4d99928SRadim Krčmář	if [ "$ACCEL" ]; then
325f4d99928SRadim Krčmář		echo $ACCEL
326f4d99928SRadim Krčmář	elif kvm_available; then
327f4d99928SRadim Krčmář		echo kvm
328f4d99928SRadim Krčmář	else
329f4d99928SRadim Krčmář		echo tcg
330f4d99928SRadim Krčmář	fi
331f4d99928SRadim Krčmář}
332