Extract invoking QEMU to own script

Currently QEMU is only invoked by the kvm-unit-tests driver. So as to
facilitate invoking QEMU for other purposes, e.g. simply booting a
kernel, extract the logic into its own script.

Change-Id: Ied1b81fa55bb3432f2f96c40d3511de7ef5b89a4
diff --git a/aarch64-unit-tests/run_emu.sh b/aarch64-unit-tests/run_emu.sh
index 33f678c..22f2d49 100755
--- a/aarch64-unit-tests/run_emu.sh
+++ b/aarch64-unit-tests/run_emu.sh
@@ -15,6 +15,7 @@
 # limitations under the License.
 
 TIMEOUT=180s
+RUN_QEMU_SCRIPT="$(dirname "${BASH_SOURCE[0]}")/../aarch64/run_qemu.sh"
 
 # QEMU CPUs to use for VHE and nVHE runs
 VHE_CPU="max"
@@ -29,9 +30,6 @@
 TEST_NAME=$7
 CPU=""
 
-# Assume that the roms are located with the disk image.
-ROM_PATH=$(dirname "${ROOTFS}")
-
 if [ ! -f "${TEST_FILE}" ]; then
     echo "Standalone kvmunittest file not found"
     echo "Run make standalone first to generate the standalone test files."
@@ -59,20 +57,14 @@
     CPU=${NVHE_CPU}
 fi
 
-timeout -k 1s --foreground "${TIMEOUT}" "${QEMU}" \
-   -M virt \
-   -machine virtualization=true -machine virt,gic-version=3  \
-   -cpu "${CPU}" \
-   -nographic -nodefaults -serial stdio \
-   -smp 2 \
-   -m 512 \
-   -kernel "${LINUX_KERNEL}" \
-   -L "${ROM_PATH}" \
-   -append "rootwait root=/dev/vda" \
-   -drive file="${ROOTFS}",readonly,if=virtio,format=raw \
-   -drive file="${TEST_FILE}",readonly,if=virtio,format=raw \
-   -object rng-random,filename=/dev/urandom,id=rng0      \
-   -device virtio-rng-pci,rng=rng0 &> "${LOG_FILE}"
+"${RUN_QEMU_SCRIPT}"		\
+	-e "${QEMU}"		\
+	-k "${LINUX_KERNEL}"	\
+	-r "${ROOTFS}"		\
+	-R "${TEST_FILE}"	\
+	-c "${CPU}"		\
+	-t "${TIMEOUT}"		\
+	&> "${LOG_FILE}"
 EXIT_STATUS=$?
 
 RESULT=$(grep -E -h --color=never "[^ ](PASS|FAIL|SKIP)[^:]" "${LOG_FILE}")
diff --git a/aarch64/run_qemu.sh b/aarch64/run_qemu.sh
new file mode 100755
index 0000000..19a54ac
--- /dev/null
+++ b/aarch64/run_qemu.sh
@@ -0,0 +1,123 @@
+#!/usr/bin/env bash
+
+# Copyright 2020 The Android KVM Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source "$(dirname "${BASH_SOURCE[0]}")/../common.inc"
+
+default_var QEMU	"${PREBUILTS_QEMU_BIN}"
+default_var ROM_DIR	"${PREBUILTS_QEMU_ROM_DIR}"
+default_var KERNEL	"${LINUX_OUT_IMAGE}"
+default_var ROOTFS	"${PREBUILTS_KUT_ROOTFS}"
+default_var CPU		"max"
+default_var SMP		2
+default_var RAM		512
+default_var GIC		3
+default_var GDB		0
+default_var VERBOSE	0
+default_var TIMEOUT	""
+
+function usage() {
+	cat <<EOF
+
+Usage: $0 [-h] [-v]
+       [-e QEMU] [-L ROM_DIR] [-k KERNEL] [-r ROOTFS] [-R DRIVE]
+       [-c CPU] [-s NUM_CPUS] [-m MEM] [-g GIC] [-G]
+       [-t TIMEOUT]
+
+    -h    output this help text
+    -v    print invoked command
+    -e    QEMU emulator binary
+    -L    directory where QEMU should look for BIOS image
+    -k    kernel image
+    -r    root filesystem image
+    -R    additional drive image(s) to mount as read-only
+    -c    CPU model (defaults to "${DEFAULT_CPU}")
+    -s    number of CPU cores (defaults to ${DEFAULT_SMP})
+    -m    amount of memory in MB (defaults to ${DEFAULT_RAM})
+    -g    version of GIC (defaults to ${DEFAULT_GIC})
+    -G    enable debugging of emulated system with GDB
+    -t    kill QEMU after given number of seconds
+EOF
+}
+
+CMD=()
+EXTRA_ARGS=()
+EXTRA_RO_MOUNTS=()
+
+while getopts ":e:L:k:r:R:c:s:m:g:t:vGh" OPT; do
+	case "${OPT}" in
+	e)	QEMU="${OPTARG}"		;;
+	L)	ROM_DIR="${OPTARG}"		;;
+	k)	KERNEL="${OPTARG}"		;;
+	r)	ROOTFS="${OPTARG}"		;;
+	R)	EXTRA_RO_MOUNTS+=("${OPTARG}")	;;
+	c)	CPU="${OPTARG}"			;;
+	s)	SMP="${OPTARG}"			;;
+	m)	RAM="${OPTARG}"			;;
+	g)	GIC="${OPTARG}"			;;
+	t)	TIMEOUT="${OPTARG}"		;;
+	v)	VERBOSE=1			;;
+	G)	GDB=1				;;
+	h)
+		usage
+		exit 0
+		;;
+	\?)
+		echo "Invalid option: ${!OPTIND}" 1>&2
+		usage 1>&2
+		exit 1
+		;;
+	:)
+		echo "Invalid option: -${OPTARG} requires an argument" 1>&2
+		usage 1>&2
+		exit 1
+		;;
+    esac
+done
+shift $((OPTIND -1))
+if [ $# -ne 0 ]; then
+	echo "Unrecognized options: $@" 1>&2
+	usage 1>&2
+	exit 1
+fi
+
+if [ "${TIMEOUT}" != "" ]; then
+	CMD+=(timeout -k 1s --foreground "${TIMEOUT}")
+fi
+CMD+=("${QEMU}")
+
+for MOUNT in "${EXTRA_RO_MOUNTS[@]}"; do
+	EXTRA_ARGS+=(-drive "file=${MOUNT},readonly,if=virtio,format=raw")
+done
+
+if [ "${GDB}" -eq 1 ]; then
+	EXTRA_ARGS+=(-S -s)
+fi
+
+if [ "${VERBOSE}" -eq 1 ]; then
+	set -x
+fi
+
+exec "${CMD[@]}"							\
+	-M virt								\
+	-machine virtualization=true -machine virt,gic-version=${GIC}	\
+	-cpu "${CPU}" -smp "${SMP}" -m "${RAM}"				\
+	-L "${ROM_DIR}" -kernel "${KERNEL}"				\
+	-drive file="${ROOTFS}",readonly,if=virtio,format=raw		\
+	-object rng-random,filename=/dev/urandom,id=rng0		\
+	-device virtio-rng-pci,rng=rng0					\
+	-nographic -nodefaults -serial stdio				\
+	-append "rootwait root=/dev/vda"				\
+	"${EXTRA_ARGS[@]}"						\
diff --git a/common.inc b/common.inc
new file mode 100644
index 0000000..7c7415a
--- /dev/null
+++ b/common.inc
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+# Copyright 2020 The Android KVM Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
+ROOT_DIR="$(dirname "${SCRIPT_DIR}")"
+
+PREBUILTS_DIR="${ROOT_DIR}/prebuilts"
+PREBUILTS_IMG_DIR="${PREBUILTS_DIR}/linux-aarch64/images"
+
+PREBUILTS_QEMU_BIN="${PREBUILTS_DIR}/linux-x86/qemu/bin/qemu-system-aarch64.sh"
+PREBUILTS_QEMU_ROM_DIR="${PREBUILTS_IMG_DIR}"
+
+PREBUILTS_KUT_ROOTFS="${PREBUILTS_IMG_DIR}/rootfs.ext4"
+
+OUT_DIR="${ROOT_DIR}/out"
+
+LINUX_OUT="${OUT_DIR}/linux"
+LINUX_OUT_IMAGE="${LINUX_OUT}/arch/arm64/boot/Image.gz"
+
+# Define a variable with a given default value. Also defines
+# variable DEFAULT_<name> with the default value.
+# Args:
+#   1) variable name to be defined
+#   2) default value of the variable
+function default_var {
+	local var_name="$1"
+	local value="$2"
+	local default_var_name="DEFAULT_${var_name}"
+	declare -g ${var_name}="${value}"
+	declare -g "${default_var_name}=${value}"
+}