feat(handoff): add basic firmware handoff tests
Add tests to sanity check information shared between BL31 and NS world
using the firmware handoff framework.
Change-Id: I9d00292db7732157d0815e6159438c0db08551ad
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/Makefile b/Makefile
index 54293b5..64bac58 100644
--- a/Makefile
+++ b/Makefile
@@ -168,6 +168,7 @@
$(eval $(call assert_boolean,USE_NVM))
$(eval $(call assert_numeric,BRANCH_PROTECTION))
$(eval $(call assert_boolean,ENABLE_REALM_PAYLOAD_TESTS))
+$(eval $(call assert_boolean,TRANSFER_LIST))
################################################################################
# Process build options
@@ -193,6 +194,7 @@
$(eval $(call add_define,TFTF_DEFINES,PLAT_${PLAT}))
$(eval $(call add_define,TFTF_DEFINES,USE_NVM))
$(eval $(call add_define,TFTF_DEFINES,ENABLE_REALM_PAYLOAD_TESTS))
+$(eval $(call add_define,TFTF_DEFINES,TRANSFER_LIST))
################################################################################
diff --git a/include/lib/transfer_list.h b/include/lib/transfer_list.h
new file mode 100644
index 0000000..9ee1f55
--- /dev/null
+++ b/include/lib/transfer_list.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2023, Linaro Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __TRANSFER_LIST_H
+#define __TRANSFER_LIST_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define TRANSFER_LIST_SIGNATURE U(0x006ed0ff)
+#define TRANSFER_LIST_VERSION U(0x0001)
+
+// Init value of maximum alignment required by any TE data in the TL
+// specified as a power of two
+#define TRANSFER_LIST_INIT_MAX_ALIGN U(3)
+
+// alignment required by TE header start address, in bytes
+#define TRANSFER_LIST_GRANULE U(8)
+
+// version of the register convention used.
+// Set to 1 for both AArch64 and AArch32 according to fw handoff spec v0.9
+#define REGISTER_CONVENTION_VERSION_MASK (1 << 24)
+
+#ifndef __ASSEMBLER__
+
+enum transfer_list_tag_id {
+ TL_TAG_EMPTY = 0,
+ TL_TAG_FDT = 1,
+ TL_TAG_HOB_BLOCK = 2,
+ TL_TAG_HOB_LIST = 3,
+ TL_TAG_ACPI_TABLE_AGGREGATE = 4,
+};
+
+enum transfer_list_ops {
+ TL_OPS_NON, // invalid for any operation
+ TL_OPS_ALL, // valid for all operations
+};
+
+struct transfer_list_header {
+ uint32_t signature;
+ uint8_t checksum;
+ uint8_t version;
+ uint8_t hdr_size;
+ uint8_t alignment; // max alignment of TE data
+ uint32_t size; // TL header + all TEs
+ uint32_t max_size;
+ /*
+ * Commented out element used to visualize dynamic part of the
+ * data structure.
+ *
+ * Note that struct transfer_list_entry also is dynamic in size
+ * so the elements can't be indexed directly but instead must be
+ * traversed in order
+ *
+ * struct transfer_list_entry entries[];
+ */
+};
+
+struct transfer_list_entry {
+ uint16_t tag_id;
+ uint8_t reserved0; // place holder
+ uint8_t hdr_size;
+ uint32_t data_size;
+ /*
+ * Commented out element used to visualize dynamic part of the
+ * data structure.
+ *
+ * Note that padding is added at the end of @data to make to reach
+ * a 8-byte boundary.
+ *
+ * uint8_t data[ROUNDUP(data_size, 8)];
+ */
+};
+
+bool transfer_list_verify_checksum(const struct transfer_list_header *tl);
+
+void *transfer_list_entry_data(struct transfer_list_entry *entry);
+
+struct transfer_list_entry *transfer_list_find(struct transfer_list_header *tl,
+ uint16_t tag_id);
+
+enum transfer_list_ops
+transfer_list_check_header(const struct transfer_list_header *tl);
+
+#endif /*__ASSEMBLER__*/
+#endif /*__TRANSFER_LIST_H*/
diff --git a/lib/transfer_list/transfer_list.c b/lib/transfer_list/transfer_list.c
new file mode 100644
index 0000000..c83b0b3
--- /dev/null
+++ b/lib/transfer_list/transfer_list.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <transfer_list.h>
+
+struct transfer_list_entry *transfer_list_find(struct transfer_list_header *tl,
+ uint16_t tag_id)
+{
+ struct transfer_list_entry *te = (void *)tl + tl->hdr_size;
+
+ while (te->tag_id != tag_id) {
+ te += round_up(te->hdr_size + te->data_size, tl->alignment);
+ }
+
+ return te;
+}
+
+void *transfer_list_entry_data(struct transfer_list_entry *entry)
+{
+ return (uint8_t *)entry + entry->hdr_size;
+}
+
+/*******************************************************************************
+ * Verifying the header of a transfer list
+ * Compliant to 2.4.1 of Firmware handoff specification (v0.9)
+ * Return transfer list operation status code
+ ******************************************************************************/
+enum transfer_list_ops
+transfer_list_check_header(const struct transfer_list_header *tl)
+{
+ uint8_t byte_sum = 0U;
+ uint8_t *b = (uint8_t *)tl;
+
+ if (tl == NULL) {
+ return TL_OPS_NON;
+ }
+
+ if (tl->signature != TRANSFER_LIST_SIGNATURE ||
+ tl->size > tl->max_size) {
+ return TL_OPS_NON;
+ }
+
+ for (size_t i = 0; i < tl->size; i++) {
+ byte_sum += b[i];
+ }
+
+ if (byte_sum - tl->checksum == tl->checksum) {
+ return TL_OPS_NON;
+ }
+
+ return TL_OPS_ALL;
+}
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 3605d01..d26ec06 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -51,3 +51,7 @@
# Build RME stack
ENABLE_REALM_PAYLOAD_TESTS := 0
+
+# Use the Firmware Handoff framework to receive configurations from preceding
+# bootloader.
+TRANSFER_LIST := 0
diff --git a/tftf/framework/aarch64/entrypoint.S b/tftf/framework/aarch64/entrypoint.S
index 6aa5645..7937b88 100644
--- a/tftf/framework/aarch64/entrypoint.S
+++ b/tftf/framework/aarch64/entrypoint.S
@@ -18,11 +18,13 @@
*/
func tftf_entrypoint
/* --------------------------------------------------------------------
- * Save arguments x0, x1 from the previous Boot loader
+ * Save arguments x0-x3 from the previous bootloader.
* --------------------------------------------------------------------
*/
mov x20, x0
mov x21, x1
+ mov x22, x2
+ mov x23, x3
bl arch_init
@@ -79,13 +81,15 @@
bl platform_set_stack
/* --------------------------------------------------------------------
- * Save fw_config and hw_config addresses passed in x0, x1 from the
- * previous boot loader
+ * Save the fw_config or transfer list and hw_config addresses passed
+ * in registers x0 to x3 from the previous bootloader.
* --------------------------------------------------------------------
*/
mov x0, x20
mov x1, x21
- bl save_fw_hw_configs
+ mov x2, x22
+ mov x3, x23
+ bl save_handoff_params
/* --------------------------------------------------------------------
* tftf_cold_boot_main() will perform the remaining architectural and
@@ -204,10 +208,22 @@
ret
endfunc arch_init
-/* Set fw_config and hw_config addresses passed in x0, x1 */
-func save_fw_hw_configs
+
+/* ----------------------------------------------------------------------------
+ * Save fw_config or transfer list and hw_config addresses passed in registers
+ * x0 to x3 from the previous bootloader.
+ * ----------------------------------------------------------------------------
+ */
+func save_handoff_params
+#if TRANSFER_LIST
+ adrp x4, ns_tl
+ str x3, [x4, :lo12:ns_tl]
+ str x1, [x4, :lo12:tl_signature]
+ str x0, [x4, :lo12:hw_config_base]
+#else
adrp x2, fw_config_base
str x0, [x2, :lo12:fw_config_base]
str x1, [x2, :lo12:hw_config_base]
+#endif
ret
-endfunc save_fw_hw_configs
+endfunc save_handoff_params
diff --git a/tftf/framework/framework.mk b/tftf/framework/framework.mk
index ef59502..f57572c 100644
--- a/tftf/framework/framework.mk
+++ b/tftf/framework/framework.mk
@@ -65,6 +65,7 @@
lib/smc/${ARCH}/smc.c \
lib/trng/trng.c \
lib/errata_abi/errata_abi.c \
+ lib/transfer_list/transfer_list.c \
lib/trusted_os/trusted_os.c \
lib/utils/mp_printf.c \
lib/utils/uuid.c \
diff --git a/tftf/framework/main.c b/tftf/framework/main.c
index a203bd2..0701e28 100644
--- a/tftf/framework/main.c
+++ b/tftf/framework/main.c
@@ -24,6 +24,9 @@
#include <tftf.h>
#include <tftf_lib.h>
#include <timer.h>
+#if TRANSFER_LIST
+#include <transfer_list.h>
+#endif
#define MIN_RETRY_TO_POWER_ON_LEAD_CPU 10
@@ -44,7 +47,12 @@
static unsigned int test_is_rebooting;
/* Parameters arg0 and arg1 passed from BL31 */
+#if TRANSFER_LIST
+u_register_t ns_tl;
+u_register_t tl_signature;
+#else
u_register_t fw_config_base;
+#endif
u_register_t hw_config_base;
static inline const test_suite_t *current_testsuite(void)
diff --git a/tftf/tests/misc_tests/test_firmware_handoff.c b/tftf/tests/misc_tests/test_firmware_handoff.c
new file mode 100644
index 0000000..bd565ae
--- /dev/null
+++ b/tftf/tests/misc_tests/test_firmware_handoff.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <transfer_list.h>
+
+extern u_register_t hw_config_base;
+extern u_register_t ns_tl;
+extern u_register_t tl_signature;
+
+#define DTB_PREAMBLE U(0xedfe0dd0)
+
+test_result_t test_handoff_header(void)
+{
+ struct transfer_list_header *tl = (struct transfer_list_header *)ns_tl;
+
+ assert((uint32_t)tl_signature ==
+ (REGISTER_CONVENTION_VERSION_MASK | TRANSFER_LIST_SIGNATURE));
+
+ if (transfer_list_check_header(tl) == TL_OPS_NON) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+test_result_t test_handoff_dtb_payload(void)
+{
+ tftf_testcase_printf("Validating HW_CONFIG from transfer list.\n");
+ struct transfer_list_header *tl = (struct transfer_list_header *)ns_tl;
+ struct transfer_list_entry *te = (void *)tl + tl->hdr_size;
+ uintptr_t dtb_ptr;
+
+ te = transfer_list_find(tl, TL_TAG_FDT);
+
+ if (te == NULL) {
+ tftf_testcase_printf(
+ "Failed to find HW CONFIG TE in transfer list!");
+ return TEST_RESULT_FAIL;
+ }
+
+ dtb_ptr = (unsigned long)transfer_list_entry_data(te);
+
+ if ((dtb_ptr != hw_config_base) &&
+ (*(uint32_t *)dtb_ptr != DTB_PREAMBLE)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-firmware-handoff.mk b/tftf/tests/tests-firmware-handoff.mk
new file mode 100644
index 0000000..515188a
--- /dev/null
+++ b/tftf/tests/tests-firmware-handoff.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${TRANSFER_LIST}, 1)
+
+TESTS_SOURCES += $(addprefix tftf/tests/misc_tests/, \
+ test_firmware_handoff.c \
+)
+
+endif
diff --git a/tftf/tests/tests-firmware-handoff.xml b/tftf/tests/tests-firmware-handoff.xml
new file mode 100644
index 0000000..2761626
--- /dev/null
+++ b/tftf/tests/tests-firmware-handoff.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (c) 2023, Arm Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+ <testsuite name="Firmware Handoff" description="Validate transfer list managed by firmware hanoff framework">
+ <testcase name="Validate transfer list header" function="test_handoff_header" />
+ <testcase name="Validate HW_CONFIG in transfer list" function="test_handoff_dtb_payload" />
+ </testsuite>
+</testsuites>