summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-11-04 10:59:50 -0600
committerTom Rini <[email protected]>2025-11-04 10:59:50 -0600
commit7babc31ddfdd4df89d2ad924833ac0173b1004bd (patch)
treedd1998f53330e545ed70c458a045ffc5e13a3256
parent45b7857d3b5b4cb12a5cc0a121bc8ac4b57427fa (diff)
parent915f0b232af756dcf7d8784781ed4a37a8028413 (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.yml18
-rw-r--r--.gitlab-ci.yml21
-rw-r--r--configs/qemu_arm64_defconfig1
-rw-r--r--doc/develop/pytest/test_fw_handoff.rst8
-rw-r--r--test/py/tests/test_fw_handoff.py108
-rw-r--r--tools/docker/Dockerfile40
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")
+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.