diff options
| author | Tom Rini <[email protected]> | 2025-11-04 10:59:50 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-11-04 10:59:50 -0600 |
| commit | 7babc31ddfdd4df89d2ad924833ac0173b1004bd (patch) | |
| tree | dd1998f53330e545ed70c458a045ffc5e13a3256 | |
| parent | 45b7857d3b5b4cb12a5cc0a121bc8ac4b57427fa (diff) | |
| parent | 915f0b232af756dcf7d8784781ed4a37a8028413 (diff) | |
Merge patch series "Enable Firmware Handoff CI test on qemu_arm64"
Raymond Mao <[email protected]> says:
This patch series enable Firmware Handoff [1] CI tests on qemu_arm64 by:
1. fetch MbedTLS (v3.6), OP-TEE (v4.7.0) and TF-A (v2.13.0);
2. build bl1 and fip with both Firmware Handoff and Measured Boot
enabled;
3. pytest to validate the Firmware Handoff feature via bloblist by
checking the existence of expected FDT nodes and TPM events generated
and handed over from TF-A/OP-TEE.
[1] https://github.com/FirmwareHandoff/firmware_handoff
Link: https://lore.kernel.org/r/[email protected]
| -rw-r--r-- | .azure-pipelines.yml | 18 | ||||
| -rw-r--r-- | .gitlab-ci.yml | 21 | ||||
| -rw-r--r-- | configs/qemu_arm64_defconfig | 1 | ||||
| -rw-r--r-- | doc/develop/pytest/test_fw_handoff.rst | 8 | ||||
| -rw-r--r-- | test/py/tests/test_fw_handoff.py | 108 | ||||
| -rw-r--r-- | tools/docker/Dockerfile | 40 |
6 files changed, 189 insertions, 7 deletions
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index fc55c8b2100..320f7567e6d 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -308,8 +308,18 @@ stages: /opt/coreboot/cbfstool \${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom add-flat-binary -f \${UBOOT_TRAVIS_BUILD_DIR}/u-boot.bin -n fallback/payload -c LZMA -l 0x1110000 -e 0x1110000; fi # If we have TF-A binaries, we need to use them. - if [[ -d /opt/tf-a/"\${TEST_PY_BD}" ]]; then - cp /opt/tf-a/"\${TEST_PY_BD}"/fip.bin /opt/tf-a/"\${TEST_PY_BD}"/bl1.bin /tmp; + tfa_dir="" + rm -f /tmp/fip.bin + rm -f /tmp/bl1.bin + if [[ -d /opt/tf-a/"\${TEST_PY_BD}\${TEST_PY_ID//--id /_}" ]]; then + tfa_dir="/opt/tf-a/\${TEST_PY_BD}\${TEST_PY_ID//--id /_}"; + elif [[ -d /opt/tf-a/"\${TEST_PY_BD}" ]]; then + tfa_dir="/opt/tf-a/\${TEST_PY_BD}"; + fi + if [[ -n "\$tfa_dir" ]]; then + cp "\$tfa_dir"/fip.bin "\$tfa_dir"/bl1.bin /tmp/; + fi + if [ -f /tmp/fip.bin ] && [ -f /tmp/bl1.bin ]; then export fip=/tmp/fip.bin; export bl1=/tmp/bl1.bin; export PATH=/opt/Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3:\${PATH}; @@ -467,6 +477,10 @@ stages: qemu_arm64_lwip: TEST_PY_BD: "qemu_arm64_lwip" TEST_PY_TEST_SPEC: "test_net_dhcp or test_net_ping or test_net_tftpboot" + qemu_arm64_tfa_fw_handoff: + TEST_PY_BD: "qemu_arm64" + TEST_PY_ID: "--id fw_handoff_tfa_optee" + TEST_PY_TEST_SPEC: "test_fw_handoff" qemu_arm_sbsa_ref: TEST_PY_BD: "qemu-arm-sbsa" TEST_PY_TEST_SPEC: "not sleep" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 73ff975e574..033d4f9f0af 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -97,8 +97,18 @@ stages: /opt/coreboot/cbfstool ${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom add-flat-binary -f ${UBOOT_TRAVIS_BUILD_DIR}/u-boot.bin -n fallback/payload -c LZMA -l 0x1110000 -e 0x1110000; fi # If we have TF-A binaries, we need to use them. - - if [[ -d /opt/tf-a/"${TEST_PY_BD}" ]]; then - cp /opt/tf-a/"${TEST_PY_BD}"/fip.bin /opt/tf-a/"${TEST_PY_BD}"/bl1.bin /tmp/; + - tfa_dir="" + - rm -f /tmp/fip.bin + - rm -f /tmp/bl1.bin + - if [[ -d /opt/tf-a/"${TEST_PY_BD}${TEST_PY_ID//--id /_}" ]]; then + tfa_dir="/opt/tf-a/${TEST_PY_BD}${TEST_PY_ID//--id /_}"; + elif [[ -d /opt/tf-a/"${TEST_PY_BD}" ]]; then + tfa_dir="/opt/tf-a/${TEST_PY_BD}"; + fi + - if [[ -n "$tfa_dir" ]]; then + cp "$tfa_dir"/fip.bin "$tfa_dir"/bl1.bin /tmp/; + fi + - if [ -f /tmp/fip.bin ] && [ -f /tmp/bl1.bin ]; then export fip=/tmp/fip.bin; export bl1=/tmp/bl1.bin; export PATH=/opt/Base_RevC_AEMvA_pkg/models/Linux64_GCC-9.3:${PATH}; @@ -399,6 +409,13 @@ qemu_arm64_lwip test.py: TEST_PY_TEST_SPEC: "test_net_dhcp or test_net_ping or test_net_tftpboot" <<: *buildman_and_testpy_dfn +qemu_arm64_tfa_fw_handoff test.py: + variables: + TEST_PY_BD: "qemu_arm64" + TEST_PY_ID: "--id fw_handoff_tfa_optee" + TEST_PY_TEST_SPEC: "test_fw_handoff" + <<: *buildman_and_testpy_dfn + qemu_arm_sbsa test.py: variables: TEST_PY_BD: "qemu-arm-sbsa" diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index 12ed6b61239..a09b107746d 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -31,6 +31,7 @@ CONFIG_CMD_SMBIOS=y CONFIG_CMD_BOOTZ=y CONFIG_CMD_BOOTEFI_SELFTEST=y CONFIG_CMD_NVEDIT_EFI=y +CONFIG_CMD_BLOBLIST=y CONFIG_CMD_DFU=y CONFIG_CMD_MTD=y CONFIG_CMD_PCI=y diff --git a/doc/develop/pytest/test_fw_handoff.rst b/doc/develop/pytest/test_fw_handoff.rst new file mode 100644 index 00000000000..af926f684c6 --- /dev/null +++ b/doc/develop/pytest/test_fw_handoff.rst @@ -0,0 +1,8 @@ +test_fw_handoff +=============== + +.. automodule:: test_fw_handoff + :synopsis: + :member-order: bysource + :members: + :undoc-members: diff --git a/test/py/tests/test_fw_handoff.py b/test/py/tests/test_fw_handoff.py new file mode 100644 index 00000000000..45f154665ef --- /dev/null +++ b/test/py/tests/test_fw_handoff.py @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2025 Linaro Limited +# Author: Raymond Mao <[email protected]> +# +# Validate Firmware Handoff from TF-A and OP-TEE + +""" +Note: This test relies on boardenv_* containing configuration values to define +whether Firmware Handoff is enabled for testing. Without this, this test +will be automatically skipped. + +For example: + +.. code-block:: python + + # Boolean indicating whether Firmware Handoff is enabled on this board. + # This variable may be omitted if its value is False. + env__firmware_handoff_enabled = True +""" + +import pytest +import re + +def _norm_ws(s: str) -> str: + """Normalize whitespace for robust comparisons.""" + return re.sub(r"\s+", " ", s).strip() + [email protected]("bloblist") [email protected]("cmd_bloblist") [email protected]("of_control") [email protected]("cmd_fdt") +def test_fw_handoff_dt(ubman): + """Validate FDT handoff via bloblist.""" + + fh_en = ubman.config.env.get('env__firmware_handoff_enabled', False) + if not fh_en: + pytest.skip('Firmware Handoff is disabled') + + bloblist = ubman.run_command("bloblist list") + blob_fdt = re.search(r"^([0-9a-fA-F]+)\s+[0-9a-fA-F]+\s+1\s+Control FDT\s*$", + bloblist, re.MULTILINE) + assert blob_fdt, "Control FDT entry not found in bloblist" + + blob_fdt_addr = int(blob_fdt.group(1), 16) + ubman.run_command(f"fdt addr {blob_fdt_addr:x}") + + reserved_a = ubman.run_command("fdt print /reserved-memory") + firmware_a = ubman.run_command("fdt print /firmware") + + fdt_addr_out = ubman.run_command("echo $fdt_addr") + fdt_addr_match = re.search(r"(?:0x)?([0-9a-fA-F]+)", fdt_addr_out) + assert fdt_addr_match, "Could not parse $fdt_addr" + + fdt_addr = int(fdt_addr_match.group(1), 16) + ubman.run_command(f"fdt addr {fdt_addr:x}") + + reserved_b = ubman.run_command("fdt print /reserved-memory") + firmware_b = ubman.run_command("fdt print /firmware") + + # Normalize whitespace & compare + assert _norm_ws(reserved_a) == _norm_ws(reserved_b), \ + "reserved-memory blocks differ between Control FDT and $fdt_addr FDT" + assert _norm_ws(firmware_a) == _norm_ws(firmware_b), \ + "firmware blocks differ between Control FDT and $fdt_addr FDT" + [email protected]("bloblist") [email protected]("cmd_bloblist") [email protected]("cmd_memory") +def test_fw_handoff_eventlog(ubman): + """Validate TPM event log handoff via bloblist.""" + + fh_en = ubman.config.env.get('env__firmware_handoff_enabled', False) + if not fh_en: + pytest.skip('Firmware Handoff is disabled') + + # Get the address and size of eventlog from the bloblist + bloblist_output = ubman.run_command("bloblist list") + evt_addr = None + evt_size = None + for line in bloblist_output.splitlines(): + if "TPM event log" in line: + parts = line.strip().split() + evt_addr = int(parts[0], 16) + evt_size = int(parts[1], 16) + break + + assert evt_addr is not None and evt_size is not None, \ + "TPM event log not found in bloblist" + + # Read byte from memory and extract printable ASCII from each line + md_output = ubman.run_command(f"md.b {evt_addr:x} {evt_size}") + ascii_log = "" + for line in md_output.splitlines(): + match = re.search(r'([0-9a-f]+:.*?)((?:\s[0-9a-f]{2}){1,16})\s+(.*)', line) + if match: + ascii_part = match.group(3).strip() + ascii_log += ascii_part + + # The events created by TF-A are expected + expected_keywords = [ + "SECURE_RT_EL3", + "SECURE_RT_EL1_OPTEE", + "SECURE_RT_EL1_OPTEE_EXTRA1" + ] + + for keyword in expected_keywords: + assert keyword in ascii_log, f"Missing expected event: {keyword}" diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 5b4c75f8400..a952df86372 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -122,8 +122,10 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ python-is-python3 \ python2.7 \ python3 \ + python3-cryptography \ python3-dev \ python3-pip \ + python3-pyelftools \ python3-sphinx \ python3-tomli \ python3-venv \ @@ -227,10 +229,24 @@ RUN git clone https://gitlab.com/qemu-project/qemu.git /tmp/qemu && \ make -j$(nproc) all install && \ rm -rf /tmp/qemu -# Build fiptool -RUN git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git /tmp/tf-a && \ +# Build OP-TEE for qemu_arm64 +RUN git clone --depth=1 https://github.com/OP-TEE/optee_os.git /tmp/optee_os \ + -b 4.7.0 && \ + cd /tmp/optee_os/ && \ + make CROSS_COMPILE32=/opt/gcc-${TCVER}-nolibc/arm-linux-gnueabi/bin/arm-linux-gnueabi- \ + CROSS_COMPILE64=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux- \ + CFG_TRANSFER_LIST=y CFG_MAP_EXT_DT_SECURE=y \ + PLATFORM=vexpress-qemu_armv8a CFG_RPMB_FS=y \ + CFG_RPMB_WRITE_KEY=y CFG_RPMB_TESTKEY=y \ + CFG_CORE_HEAP_SIZE=524288 \ + CFG_REE_FS=n CFG_CORE_ARM64_PA_BITS=48 \ + CFG_TEE_CORE_LOG_LEVEL=2 + +# Build fiptool, bl1 and fip for fvp and qemu_arm64 +RUN git clone --depth=1 -b mbedtls-3.6 https://github.com/ARMmbed/mbedtls.git /tmp/mbedtls +RUN git clone --depth=1 https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git /tmp/tf-a \ + -b v2.13.0 && \ cd /tmp/tf-a/ && \ - git checkout v2.12.0 && \ make CROSS_COMPILE=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux- \ PLAT=fvp BL33=/dev/null -j$(nproc) all fip && \ mkdir -p /usr/local/bin /opt/tf-a/vexpress_fvp && \ @@ -243,6 +259,24 @@ RUN git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git /tmp/t mkdir -p /opt/tf-a/vexpress_fvp_bloblist && \ cp build/fvp/release/fip.bin build/fvp/release/bl1.bin \ /opt/tf-a/vexpress_fvp_bloblist/ && \ + make CROSS_COMPILE=/opt/gcc-${TCVER}-nolibc/aarch64-linux/bin/aarch64-linux- \ + PLAT=qemu \ + BL33=/dev/null \ + BL32=/tmp/optee_os/out/arm-plat-vexpress/core/tee-header_v2.bin \ + BL32_EXTRA1=/tmp/optee_os/out/arm-plat-vexpress/core/tee-pager_v2.bin \ + BL32_EXTRA2=/tmp/optee_os/out/arm-plat-vexpress/core/tee-pageable_v2.bin \ + BL32_RAM_LOCATION=tdram SPD=opteed \ + TRANSFER_LIST=1 E=0 \ + MEASURED_BOOT=1 \ + EVENT_LOG_LEVEL=10 \ + MBOOT_EL_HASH_ALG=sha256 \ + MBEDTLS_DIR=/tmp/mbedtls \ + -j$(nproc) all fip && \ + mkdir -p /opt/tf-a/qemu_arm64_fw_handoff_tfa_optee && \ + cp build/qemu/release/fip.bin build/qemu/release/bl1.bin \ + /opt/tf-a/qemu_arm64_fw_handoff_tfa_optee/ && \ + rm -rf /tmp/optee_os && \ + rm -rf /tmp/mbedtls && \ rm -rf /tmp/tf-a # Download the Arm Architecture FVP platform. This file is double compressed. |
