test_xen.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import os
  2. import pexpect
  3. import infra.basetest
  4. class TestXen(infra.basetest.BRTest):
  5. # We have a custom kernel config to reduce build time.
  6. # Our genimage.cfg is inspired from qemu_aarch64_ebbr_defconfig as we boot
  7. # Xen with UEFI. We run only in the initramfs; this allows to use a single
  8. # ramdisk image for both the host and the guest.
  9. # The Xen startup scripts need bash.
  10. config = \
  11. """
  12. BR2_aarch64=y
  13. BR2_TOOLCHAIN_EXTERNAL=y
  14. BR2_ROOTFS_OVERLAY="support/testing/tests/package/test_xen/overlay"
  15. BR2_ROOTFS_POST_BUILD_SCRIPT="support/testing/tests/package/test_xen/post-build.sh"
  16. BR2_ROOTFS_POST_IMAGE_SCRIPT="support/testing/tests/package/test_xen/post-image.sh support/scripts/genimage.sh"
  17. BR2_ROOTFS_POST_SCRIPT_ARGS="-c support/testing/tests/package/test_xen/genimage.cfg"
  18. BR2_LINUX_KERNEL=y
  19. BR2_LINUX_KERNEL_CUSTOM_VERSION=y
  20. BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.12.9"
  21. BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
  22. BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="support/testing/tests/package/test_xen/linux.config"
  23. BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
  24. BR2_PACKAGE_XEN=y
  25. BR2_PACKAGE_XEN_HYPERVISOR=y
  26. BR2_PACKAGE_XEN_TOOLS=y
  27. BR2_TARGET_ROOTFS_CPIO=y
  28. # BR2_TARGET_ROOTFS_TAR is not set
  29. BR2_TARGET_UBOOT=y
  30. BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
  31. BR2_TARGET_UBOOT_CUSTOM_VERSION=y
  32. BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2025.01"
  33. BR2_TARGET_UBOOT_BOARD_DEFCONFIG="qemu_arm64"
  34. BR2_TARGET_UBOOT_NEEDS_OPENSSL=y
  35. BR2_TARGET_UBOOT_NEEDS_GNUTLS=y
  36. BR2_PACKAGE_HOST_DOSFSTOOLS=y
  37. BR2_PACKAGE_HOST_GENIMAGE=y
  38. BR2_PACKAGE_HOST_MTOOLS=y
  39. """
  40. def get_dom_uuid(self) -> str:
  41. out, rc = self.emulator.run("cat /sys/hypervisor/uuid")
  42. self.assertEqual(rc, 0, "Failed to get domain UUID")
  43. return out[0]
  44. def assertNumVM(self, x: int) -> None:
  45. out, rc = self.emulator.run("xl vm-list")
  46. self.assertEqual(rc, 0, "Failed to get VM list")
  47. num_vm = len(out) - 1
  48. self.assertEqual(num_vm, x, f"Expected {x} VM(s) but found {num_vm}")
  49. def test_run(self):
  50. uboot_bin = os.path.join(self.builddir, "images", "u-boot.bin")
  51. disk_img = os.path.join(self.builddir, "images", "disk.img")
  52. # We need to run Qemu with virtualization to run Xen.
  53. qemu_opts = [
  54. "-bios", uboot_bin,
  55. "-cpu", "cortex-a53",
  56. "-device", "virtio-blk-device,drive=hd0",
  57. "-drive", f"file={disk_img},if=none,format=raw,id=hd0",
  58. "-m", "1G",
  59. "-machine", "virt,gic-version=3,virtualization=on,acpi=off",
  60. "-smp", "2"
  61. ]
  62. # Boot the emulator:
  63. # Qemu Devicetree -> U-Boot -> Xen UEFI -> Linux
  64. # We need to boot Xen in UEFI to read xen.cfg; we use U-Boot as our
  65. # UEFI firmware.
  66. self.emulator.boot(arch="aarch64", options=qemu_opts)
  67. self.emulator.login()
  68. # Avoid double-cooking the terminal, otherwise the test infrastructure
  69. # would not be able to retrieve e.g. return codes properly.
  70. self.assertRunOk("stty raw")
  71. # Verify that we are indeed running under Xen.
  72. self.assertRunOk("xl info")
  73. # Check that we are dom0.
  74. uuid = self.get_dom_uuid()
  75. dom0_uuid = "00000000-0000-0000-0000-000000000000"
  76. self.assertEqual(uuid, dom0_uuid, f"Unexpected dom UUID {uuid}")
  77. # Check that we have one VM running.
  78. self.assertNumVM(1)
  79. # Create dom1 with console attached and login.
  80. self.emulator.qemu.sendline("xl create -c /etc/xen/dom1.cfg")
  81. self.emulator.login()
  82. # Avoid double-cooking the terminal for dom1, too.
  83. self.assertRunOk("stty raw")
  84. # Check that we are not talking to dom0 anymore.
  85. uuid = self.get_dom_uuid()
  86. self.assertNotEqual(uuid, dom0_uuid, "Unexpected dom0 UUID")
  87. # Detach from dom1's console with CTRL-].
  88. # dom1 is still running in the background after that.
  89. self.emulator.qemu.send(chr(0x1d))
  90. mult = self.emulator.timeout_multiplier
  91. index = self.emulator.qemu.expect(["#", pexpect.TIMEOUT],
  92. timeout=2 * mult)
  93. self.assertEqual(index, 0, "Timeout exiting guest")
  94. # Check that we are talking to dom0 again.
  95. uuid = self.get_dom_uuid()
  96. self.assertEqual(uuid, dom0_uuid, f"Unexpected dom UUID {uuid}")
  97. # Check that we have two VMs running.
  98. self.assertNumVM(2)