Add Hello World test of CrosVM

Adds a minimal test of CrosVM. It uses the same rootfs as kvm-unit-tests
but the test script loads CrosVM from its ext4 image and runs a VM.
The VM uses the same kernel as the host, the same rootfs, and the test
script simply prints 'Hello World'.

Make targets added for all VHE/nVHE/pKVM configs. The test reuses
run_test.sh from kvm-unit-tests to avoid duplication/specialization.

Test: make test-crosvm-helloworld
Change-Id: I1f6d3f19f46f4ea4a0e680b36075599a7627b56a
diff --git a/Makefile b/Makefile
index 76aea9d..eadf682 100644
--- a/Makefile
+++ b/Makefile
@@ -290,6 +290,7 @@
 # kvm-unit-tests
 #
 
+KUT_RUN_TEST := $(SCRIPTS_DIR)/kvm-unit-tests/run_test.sh
 KUT_GEN_MAKEFILE := $(SCRIPTS_DIR)/kvm-unit-tests/gen_makefile.sh
 KUT_MAKEFILE := $(OUT_DIR)/Makefile.kvm-unit-tests
 KUT_TEST_DIR := $(KUT_OUT)/tests
@@ -309,3 +310,45 @@
 		> $@.tmp
 	@ mv $@.tmp $@
 include $(KUT_MAKEFILE)
+
+#
+# CrosVM Hello World test
+#
+
+CROSVM_HELLOWORLD_SCRIPT_DIR := $(SCRIPTS_DIR)/crosvm/helloworld/
+CROSVM_HELLOWORLD_LOG_DIR := $(OUT_DIR)/test/crosvm/helloworld/
+CROSVM_HELLOWORLD_TESTS := test-crosvm-vhe-helloworld \
+			   test-crosvm-nvhe-helloworld \
+			   test-crosvm-pkvm-helloworld
+
+define gen_crosvm_helloworld_test
+	$(KUT_RUN_TEST) -d $(1) $(2) \
+		-o $(CROSVM_HELLOWORLD_LOG_DIR)/$(1).log \
+		$(CROSVM_HELLOWORLD_SCRIPT_DIR)/host.sh -- \
+		-R $(CROSVM_HELLOWORLD_SCRIPT_DIR)/guest.sh \
+		-R $(KERNEL_IMAGE) \
+		-R $(PREBUILTS_ROOTFS_EXT4) \
+		-R $(PREBUILTS_CROSVM_EXT4)
+endef
+
+test: test-crosvm-helloworld
+test-list: test-list-crosvm-helloworld
+
+.PHONY: test-crosvm-helloworld
+test-crosvm-helloworld: $(CROSVM_HELLOWORLD_TESTS)
+
+.PHONY: test-list-crosvm-helloworld
+test-list-crosvm-helloworld:
+	@ for x in $(CROSVM_HELLOWORLD_TESTS); do echo $x; done
+
+.PHONY: test-crosvm-vhe-helloworld
+test-crosvm-vhe-helloworld: $(KERNEL_IMAGE)
+	@ $(call gen_crosvm_helloworld_test,$@,-V)
+
+.PHONY: test-crosvm-nvhe-helloworld
+test-crosvm-nvhe-helloworld: $(KERNEL_IMAGE)
+	@ $(call gen_crosvm_helloworld_test,$@,-N)
+
+.PHONY: test-crosvm-pkvm-helloworld
+test-crosvm-pkvm-helloworld: $(KERNEL_IMAGE)
+	@ $(call gen_crosvm_helloworld_test,$@,)
diff --git a/common.inc b/common.inc
index c26a706..3c2598e 100644
--- a/common.inc
+++ b/common.inc
@@ -29,6 +29,7 @@
 PREBUILTS_QEMU_ROM_DIR="${PREBUILTS_IMG_DIR}"
 
 PREBUILTS_KUT_ROOTFS="${PREBUILTS_IMG_DIR}/rootfs.ext4"
+PREBUILTS_CROSVM_FS="${PREBUILTS_IMG_DIR}/crosvm.ext4"
 
 TOOLCHAINS_DIR="${ROOT_DIR}/toolchains"
 TOOLCHAINS_GDB_BIN="${TOOLCHAINS_DIR}/linux-x86/gdb/bin/gdb"
diff --git a/crosvm/helloworld/guest.sh b/crosvm/helloworld/guest.sh
new file mode 100644
index 0000000..7048832
--- /dev/null
+++ b/crosvm/helloworld/guest.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+# Copyright 2021 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.
+
+echo "Hello World!"
diff --git a/crosvm/helloworld/host.sh b/crosvm/helloworld/host.sh
new file mode 100644
index 0000000..f569358
--- /dev/null
+++ b/crosvm/helloworld/host.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright 2021 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 -eufo pipefail
+
+PASS() { echo -e "\e[32mPASS\e[0m"; }
+FAIL() { echo -e "\e[31mFAIL\e[0m"; }
+
+CLIENT_SH=/dev/vdc
+KERNEL_IMAGE_GZ=/dev/vdd
+ROOT_FS=/dev/vde
+CROSVM_FS=/dev/vdf
+
+KERNEL_BIN=/tmp/kernel
+GUEST_LOG=/tmp/guest.log
+
+CROSVM_MOUNT=/mnt
+CROSVM=${CROSVM_MOUNT}/bin/crosvm
+
+mount ${CROSVM_FS} ${CROSVM_MOUNT}
+zcat ${KERNEL_IMAGE_GZ} > ${KERNEL_BIN}
+
+${CROSVM} run --disable-sandbox				\
+	-r ${ROOT_FS} -d ${CLIENT_SH}			\
+	--serial=type=stdout,hardware=virtio-console	\
+	${KERNEL_BIN} | tee ${GUEST_LOG}
+EXIT_STATUS=$?
+
+if [ ${EXIT_STATUS} -eq 0 ]; then
+	if grep 'Hello World!' ${GUEST_LOG} >/dev/null; then
+		PASS
+	else
+		FAIL
+		EXIT_STATUS=1
+	fi
+else
+	FAIL
+fi
+exit ${EXIT_STATUS}