about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile13
-rw-r--r--src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py78
2 files changed, 74 insertions, 17 deletions
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 0bddffa3436..7c09e3a582f 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -19,11 +19,18 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins
   wget \
   patch \
   ovmf \
+  qemu-efi-aarch64 \
+  qemu-system-arm \
   qemu-system-x86
 
 RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \
   tar -xJ
 
+# Install 32-bit OVMF files for the i686-unknown-uefi test. This package
+# is not available in ubuntu 20.04, so download a 22.04 package.
+RUN curl -sL --output ovmf-ia32.deb http://mirrors.kernel.org/ubuntu/pool/universe/e/edk2/ovmf-ia32_2022.02-3_all.deb
+RUN dpkg -i ovmf-ia32.deb && rm ovmf-ia32.deb
+
 WORKDIR /build/
 COPY scripts/musl-patch-configure.diff /build/
 COPY scripts/musl-toolchain.sh /build/
@@ -68,7 +75,11 @@ ENV MUSL_TARGETS=x86_64-unknown-linux-musl \
 ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS
 
 COPY host-x86_64/test-various/uefi_qemu_test /uefi_qemu_test
-ENV UEFI_TARGETS=x86_64-unknown-uefi \
+ENV UEFI_TARGETS=aarch64-unknown-uefi,i686-unknown-uefi,x86_64-unknown-uefi \
+    CC_aarch64_unknown_uefi=clang-11 \
+    CXX_aarch64_unknown_uefi=clang++-11 \
+    CC_i686_unknown_uefi=clang-11 \
+    CXX_i686_unknown_uefi=clang++-11 \
     CC_x86_64_unknown_uefi=clang-11 \
     CXX_x86_64_unknown_uefi=clang++-11
 ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_TARGETS && \
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py
index 46793ce3afa..ffae7b0d4ac 100644
--- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py
+++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/run.py
@@ -8,8 +8,11 @@ import tempfile
 
 from pathlib import Path
 
+TARGET_AARCH64 = 'aarch64-unknown-uefi'
+TARGET_I686 = 'i686-unknown-uefi'
+TARGET_X86_64 = 'x86_64-unknown-uefi'
 
-def run(*cmd, capture=False, check=True, env=None):
+def run(*cmd, capture=False, check=True, env=None, timeout=None):
     """Print and run a command, optionally capturing the output."""
     cmd = [str(p) for p in cmd]
     print(' '.join(cmd))
@@ -17,10 +20,39 @@ def run(*cmd, capture=False, check=True, env=None):
                           capture_output=capture,
                           check=check,
                           env=env,
-                          text=True)
-
+                          text=True,
+                          timeout=timeout)
+
+def build_and_run(tmp_dir, target):
+    if target == TARGET_AARCH64:
+        boot_file_name = 'bootaa64.efi'
+        ovmf_dir = Path('/usr/share/AAVMF')
+        ovmf_code = 'AAVMF_CODE.fd'
+        ovmf_vars = 'AAVMF_VARS.fd'
+        qemu = 'qemu-system-aarch64'
+        machine = 'virt'
+        cpu = 'cortex-a72'
+    elif target == TARGET_I686:
+        boot_file_name = 'bootia32.efi'
+        ovmf_dir = Path('/usr/share/OVMF')
+        ovmf_code = 'OVMF32_CODE_4M.secboot.fd'
+        ovmf_vars = 'OVMF32_VARS_4M.fd'
+        # The i686 target intentionally uses 64-bit qemu; the important
+        # difference is that the OVMF code provides a 32-bit environment.
+        qemu = 'qemu-system-x86_64'
+        machine = 'q35'
+        cpu = 'qemu64'
+    elif target == TARGET_X86_64:
+        boot_file_name = 'bootx64.efi'
+        ovmf_dir = Path('/usr/share/OVMF')
+        ovmf_code = 'OVMF_CODE.fd'
+        ovmf_vars = 'OVMF_VARS.fd'
+        qemu = 'qemu-system-x86_64'
+        machine = 'q35'
+        cpu = 'qemu64'
+    else:
+        raise KeyError('invalid target')
 
-def build_and_run(tmp_dir):
     host_artifacts = Path('/checkout/obj/build/x86_64-unknown-linux-gnu')
     stage0 = host_artifacts / 'stage0/bin'
     stage2 = host_artifacts / 'stage2/bin'
@@ -33,7 +65,6 @@ def build_and_run(tmp_dir):
     shutil.copytree('/uefi_qemu_test', test_crate)
 
     # Build the UEFI executable.
-    target = 'x86_64-unknown-uefi'
     run('cargo',
         'build',
         '--manifest-path',
@@ -49,14 +80,24 @@ def build_and_run(tmp_dir):
 
     # Copy the executable into the ESP.
     src_exe_path = test_crate / 'target' / target / 'debug/uefi_qemu_test.efi'
-    shutil.copy(src_exe_path, boot / 'bootx64.efi')
+    shutil.copy(src_exe_path, boot / boot_file_name)
+    print(src_exe_path, boot / boot_file_name)
+
+    # Select the appropriate EDK2 build.
+    ovmf_code = ovmf_dir / ovmf_code
+    ovmf_vars = ovmf_dir / ovmf_vars
+
+    # Make a writable copy of the vars file. aarch64 doesn't boot
+    # correctly with read-only vars.
+    ovmf_rw_vars = Path(tmp_dir) / 'vars.fd'
+    shutil.copy(ovmf_vars, ovmf_rw_vars)
 
     # Run the executable in QEMU and capture the output.
-    qemu = 'qemu-system-x86_64'
-    ovmf_dir = Path('/usr/share/OVMF')
-    ovmf_code = ovmf_dir / 'OVMF_CODE.fd'
-    ovmf_vars = ovmf_dir / 'OVMF_VARS.fd'
     output = run(qemu,
+                 '-machine',
+                 machine,
+                 '-cpu',
+                 cpu,
                  '-display',
                  'none',
                  '-serial',
@@ -64,7 +105,7 @@ def build_and_run(tmp_dir):
                  '-drive',
                  f'if=pflash,format=raw,readonly=on,file={ovmf_code}',
                  '-drive',
-                 f'if=pflash,format=raw,readonly=on,file={ovmf_vars}',
+                 f'if=pflash,format=raw,readonly=off,file={ovmf_rw_vars}',
                  '-drive',
                  f'format=raw,file=fat:rw:{esp}',
                  capture=True,
@@ -73,7 +114,9 @@ def build_and_run(tmp_dir):
                  # shutdown under some circumstances. That has been
                  # fixed in newer versions of QEMU, but for now just
                  # don't check the exit status.
-                 check=False).stdout
+                 check=False,
+                 # Set a timeout to kill the VM in case something goes wrong.
+                 timeout=60).stdout
 
     if 'Hello World!' in output:
         print('VM produced expected output')
@@ -86,10 +129,13 @@ def build_and_run(tmp_dir):
 
 
 def main():
-    # Create a temporary directory so that we have a writeable
-    # workspace.
-    with tempfile.TemporaryDirectory() as tmp_dir:
-        build_and_run(tmp_dir)
+    targets = [TARGET_AARCH64, TARGET_I686, TARGET_X86_64]
+
+    for target in targets:
+        # Create a temporary directory so that we have a writeable
+        # workspace.
+        with tempfile.TemporaryDirectory() as tmp_dir:
+            build_and_run(tmp_dir, target)
 
 
 if __name__ == "__main__":