diff --git a/support/testing/tests/package/test_xen.py b/support/testing/tests/package/test_xen.py index 875ba19e70..f680187db0 100644 --- a/support/testing/tests/package/test_xen.py +++ b/support/testing/tests/package/test_xen.py @@ -1,15 +1,20 @@ import os +import pexpect import infra.basetest class TestXen(infra.basetest.BRTest): # We have a custom kernel config to reduce build time. # Our genimage.cfg is inspired from qemu_aarch64_ebbr_defconfig as we boot - # Xen with UEFI. + # Xen with UEFI. We run only in the initramfs; this allows to use a single + # ramdisk image for both the host and the guest. + # The Xen startup scripts need bash. config = \ """ BR2_aarch64=y BR2_TOOLCHAIN_EXTERNAL=y + BR2_ROOTFS_OVERLAY="support/testing/tests/package/test_xen/overlay" + BR2_ROOTFS_POST_BUILD_SCRIPT="support/testing/tests/package/test_xen/post-build.sh" BR2_ROOTFS_POST_IMAGE_SCRIPT="support/testing/tests/package/test_xen/post-image.sh support/scripts/genimage.sh" BR2_ROOTFS_POST_SCRIPT_ARGS="-c support/testing/tests/package/test_xen/genimage.cfg" BR2_LINUX_KERNEL=y @@ -21,9 +26,7 @@ class TestXen(infra.basetest.BRTest): BR2_PACKAGE_XEN=y BR2_PACKAGE_XEN_HYPERVISOR=y BR2_PACKAGE_XEN_TOOLS=y - BR2_TARGET_ROOTFS_EXT2=y - BR2_TARGET_ROOTFS_EXT2_4=y - BR2_TARGET_ROOTFS_EXT2_SIZE="128M" + BR2_TARGET_ROOTFS_CPIO=y # BR2_TARGET_ROOTFS_TAR is not set BR2_TARGET_UBOOT=y BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y @@ -37,24 +40,37 @@ class TestXen(infra.basetest.BRTest): BR2_PACKAGE_HOST_MTOOLS=y """ + def get_dom_uuid(self) -> str: + out, rc = self.emulator.run("cat /sys/hypervisor/uuid") + self.assertEqual(rc, 0, "Failed to get domain UUID") + return out[0] + + def assertNumVM(self, x: int) -> None: + out, rc = self.emulator.run("xl vm-list") + self.assertEqual(rc, 0, "Failed to get VM list") + num_vm = len(out) - 1 + self.assertEqual(num_vm, x, f"Expected {x} VM(s) but found {num_vm}") + def test_run(self): uboot_bin = os.path.join(self.builddir, "images", "u-boot.bin") disk_img = os.path.join(self.builddir, "images", "disk.img") + # We need to run Qemu with virtualization to run Xen. qemu_opts = [ "-bios", uboot_bin, "-cpu", "cortex-a53", "-device", "virtio-blk-device,drive=hd0", "-drive", f"file={disk_img},if=none,format=raw,id=hd0", - "-m", "2G", + "-m", "1G", "-machine", "virt,gic-version=3,virtualization=on,acpi=off", "-smp", "2" ] # Boot the emulator: # Qemu Devicetree -> U-Boot -> Xen UEFI -> Linux - self.emulator.boot(arch="aarch64", - options=qemu_opts) + # We need to boot Xen in UEFI to read xen.cfg; we use U-Boot as our + # UEFI firmware. + self.emulator.boot(arch="aarch64", options=qemu_opts) self.emulator.login() # Avoid double-cooking the terminal, otherwise the test infrastructure @@ -63,3 +79,37 @@ class TestXen(infra.basetest.BRTest): # Verify that we are indeed running under Xen. self.assertRunOk("xl info") + + # Check that we are dom0. + uuid = self.get_dom_uuid() + dom0_uuid = "00000000-0000-0000-0000-000000000000" + self.assertEqual(uuid, dom0_uuid, f"Unexpected dom UUID {uuid}") + + # Check that we have one VM running. + self.assertNumVM(1) + + # Create dom1 with console attached and login. + self.emulator.qemu.sendline("xl create -c /etc/xen/dom1.cfg") + self.emulator.login() + + # Avoid double-cooking the terminal for dom1, too. + self.assertRunOk("stty raw") + + # Check that we are not talking to dom0 anymore. + uuid = self.get_dom_uuid() + self.assertNotEqual(uuid, dom0_uuid, "Unexpected dom0 UUID") + + # Detach from dom1's console with CTRL-]. + # dom1 is still running in the background after that. + self.emulator.qemu.send(chr(0x1d)) + mult = self.emulator.timeout_multiplier + index = self.emulator.qemu.expect(["#", pexpect.TIMEOUT], + timeout=2 * mult) + self.assertEqual(index, 0, "Timeout exiting guest") + + # Check that we are talking to dom0 again. + uuid = self.get_dom_uuid() + self.assertEqual(uuid, dom0_uuid, f"Unexpected dom UUID {uuid}") + + # Check that we have two VMs running. + self.assertNumVM(2) diff --git a/support/testing/tests/package/test_xen/genimage.cfg b/support/testing/tests/package/test_xen/genimage.cfg index 6d8ec8ad8e..7d7a83d6b6 100644 --- a/support/testing/tests/package/test_xen/genimage.cfg +++ b/support/testing/tests/package/test_xen/genimage.cfg @@ -10,10 +10,11 @@ image efi-part.vfat { files = { "Image", + "rootfs.cpio" } } - size = 16M + size = 128M } image disk.img { @@ -27,9 +28,4 @@ image disk.img { offset = 32K bootable = true } - - partition root { - partition-type-uuid = root-arm64 - image = "rootfs.ext2" - } } diff --git a/support/testing/tests/package/test_xen/linux.config b/support/testing/tests/package/test_xen/linux.config index e0323d0325..4afab3c171 100644 --- a/support/testing/tests/package/test_xen/linux.config +++ b/support/testing/tests/package/test_xen/linux.config @@ -71,6 +71,9 @@ CONFIG_IOSCHED_BFQ=y # CONFIG_SWAP is not set # CONFIG_COMPAT_BRK is not set CONFIG_KSM=y +CONFIG_NET=y +CONFIG_UNIX=y +CONFIG_INET=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_FW_LOADER_USER_HELPER=y diff --git a/support/testing/tests/package/test_xen/overlay/etc/init.d/S99custom b/support/testing/tests/package/test_xen/overlay/etc/init.d/S99custom new file mode 100755 index 0000000000..889350725e --- /dev/null +++ b/support/testing/tests/package/test_xen/overlay/etc/init.d/S99custom @@ -0,0 +1,61 @@ +#!/bin/sh +# +# Custom script for test_xen.py +# This will run both in dom0 and in dom1. +# When we detect that we are in dom0 we mount the boot partition under /mnt, +# to see the kernel image and the initramfs. +# + +DAEMON="custom" + +start() { + printf 'Starting %s: ' "$DAEMON" + case $(cat /sys/hypervisor/uuid) in + 00000000-0000-0000-0000-000000000000) + printf "dom0 " + mount /dev/vda1 /mnt -o ro + ;; + *) printf "domU " ;; + esac + status=$? + if [ "$status" -eq 0 ]; then + echo "OK" + else + echo "FAIL" + fi + return "$status" +} + +stop() { + printf 'Stopping %s: ' "$DAEMON" + case $(cat /sys/hypervisor/uuid) in + 00000000-0000-0000-0000-000000000000) + printf "dom0 " + umount /mnt + ;; + *) printf "domU " ;; + esac + status=$? + if [ "$status" -eq 0 ]; then + echo "OK" + else + echo "FAIL" + fi + return "$status" +} + +restart() { + stop + start +} + +case "$1" in + start|stop|restart) + "$1";; + reload) + # Restart, since there is no true "reload" feature. + restart;; + *) + echo "Usage: $0 {start|stop|restart|reload}" + exit 1 +esac diff --git a/support/testing/tests/package/test_xen/overlay/etc/xen/dom1.cfg b/support/testing/tests/package/test_xen/overlay/etc/xen/dom1.cfg new file mode 100644 index 0000000000..869c12beb8 --- /dev/null +++ b/support/testing/tests/package/test_xen/overlay/etc/xen/dom1.cfg @@ -0,0 +1,5 @@ +name="dom1" +kernel="/mnt/Image" +ramdisk="/mnt/rootfs.cpio" +memory=256 +cmdline="console=hvc0" diff --git a/support/testing/tests/package/test_xen/post-build.sh b/support/testing/tests/package/test_xen/post-build.sh new file mode 100755 index 0000000000..67b726cf3a --- /dev/null +++ b/support/testing/tests/package/test_xen/post-build.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu + +# Remove unnecessary Xen binaries to spare ramdisk size. +for ext in bin fd rom; do + rm -vf "${TARGET_DIR}/usr/share/qemu-xen/qemu/"*."$ext" +done diff --git a/support/testing/tests/package/test_xen/xen.cfg b/support/testing/tests/package/test_xen/xen.cfg index 41b3ed3ee5..8007ba725c 100644 --- a/support/testing/tests/package/test_xen/xen.cfg +++ b/support/testing/tests/package/test_xen/xen.cfg @@ -1,2 +1,3 @@ -options=dom0_mem=128M loglvl=all guest_loglvl=all -kernel=\Image root=PARTLABEL=root rootwait console=hvc0 +options=dom0_mem=256M loglvl=all guest_loglvl=all +kernel=\Image console=hvc0 +ramdisk=\rootfs.cpio