feat(arm): support FW handoff b/w BL1 & BL2

Leverage the framework between BL1 and BL2. Migrate all handoff
structures to the TL.

Change-Id: I79ff3a319596b5656184cde10b5204b10a4d03bb
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index c3a88e7..ec5f90b 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -411,6 +411,8 @@
 #define ARM_V2M_MAP_MEM_PROTECT		MAP_REGION_FLAT(PLAT_ARM_MEM_PROT_ADDR,	\
 						V2M_FLASH_BLOCK_SIZE,		\
 						MT_DEVICE | MT_RW | MT_SECURE)
+
+#if !TRANSFER_LIST
 /*
  * Map the region for device tree configuration with read and write permissions
  */
@@ -418,6 +420,8 @@
 						(ARM_FW_CONFIGS_LIMIT		\
 							- ARM_BL_RAM_BASE),	\
 						MT_MEMORY | MT_RW | EL3_PAS)
+#endif
+
 /*
  * Map L0_GPT with read and write permissions
  */
@@ -505,6 +509,14 @@
  */
 #define CACHE_WRITEBACK_GRANULE		(U(1) << ARM_CACHE_WRITEBACK_SHIFT)
 
+/* Define memory configuration for trusted boot device tree files. */
+#ifdef PLAT_ARM_TB_FW_CONFIG_SIZE
+#define ARM_TB_FW_CONFIG_MAX_SIZE	PLAT_ARM_TB_FW_CONFIG_SIZE
+#else
+#define ARM_TB_FW_CONFIG_MAX_SIZE	U(0x400)
+#endif
+
+#if !TRANSFER_LIST
 /*
  * To enable FW_CONFIG to be loaded by BL1, define the corresponding base
  * and limit. Leave enough space of BL2 meminfo.
@@ -526,6 +538,7 @@
  */
 #define ARM_FW_CONFIGS_SIZE		(PAGE_SIZE * 2)
 #define ARM_FW_CONFIGS_LIMIT		(ARM_BL_RAM_BASE + ARM_FW_CONFIGS_SIZE)
+#endif
 
 #if ENABLE_RME
 /*
diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c
index 58db4e8..ebdd80d 100644
--- a/plat/arm/board/fvp/fvp_bl2_setup.c
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -48,6 +48,11 @@
 
 void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
 {
+	struct transfer_list_entry *te __unused;
+
+#if TRANSFER_LIST
+	arg0 = arg3;
+#endif
 	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
 
 	/* Initialize the platform config for future decision making */
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 0860dd1..07e69e6 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -336,7 +336,6 @@
 
 # Add the FDT_SOURCES and options for Dynamic Config (only for Unix env)
 ifdef UNIX_MK
-FVP_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
 FVP_TB_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
 FVP_HW_CONFIG_DTS	:=	fdts/${FVP_DT_PREFIX}.dts
 
@@ -345,7 +344,6 @@
 
 ifeq (${TRANSFER_LIST}, 1)
 FDT_SOURCES		+=	$(addprefix plat/arm/board/fvp/fdts/,	\
-					${PLAT}_fw_config.dts		\
 					${PLAT}_tb_fw_config.dts	\
 				)
 else
@@ -356,7 +354,7 @@
 					${PLAT}_nt_fw_config.dts	\
 				)
 
-FVP_TB_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+FVP_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
 FVP_SOC_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_soc_fw_config.dtb
 FVP_NT_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb
 
@@ -381,14 +379,14 @@
 $(eval $(call TOOL_ADD_PAYLOAD,${FVP_TOS_FW_CONFIG},--tos-fw-config,${FVP_TOS_FW_CONFIG}))
 endif
 
+# Add the FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_FW_CONFIG},--fw-config,${FVP_FW_CONFIG}))
 # Add the SOC_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${FVP_SOC_FW_CONFIG},--soc-fw-config,${FVP_SOC_FW_CONFIG}))
 # Add the NT_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${FVP_NT_FW_CONFIG},--nt-fw-config,${FVP_NT_FW_CONFIG}))
 endif
 
-# Add the FW_CONFIG to FIP and specify the same to certtool
-$(eval $(call TOOL_ADD_PAYLOAD,${FVP_FW_CONFIG},--fw-config,${FVP_FW_CONFIG}))
 # Add the TB_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${FVP_TB_FW_CONFIG},--tb-fw-config,${FVP_TB_FW_CONFIG}))
 # Add the HW_CONFIG to FIP and specify the same to certtool
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index feff691..f043f59 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,6 +14,9 @@
 #include <common/debug.h>
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
+#if TRANSFER_LIST
+#include <lib/transfer_list.h>
+#endif
 #include <lib/utils.h>
 #include <lib/xlat_tables/xlat_tables_compat.h>
 #include <plat/arm/common/plat_arm.h>
@@ -61,6 +64,10 @@
 /* Boolean variable to hold condition whether firmware update needed or not */
 static bool is_fwu_needed;
 
+#if TRANSFER_LIST
+static struct transfer_list_header *secure_tl;
+#endif
+
 struct meminfo *bl1_plat_sec_mem_layout(void)
 {
 	return &bl1_tzram_layout;
@@ -144,9 +151,13 @@
  */
 void arm_bl1_platform_setup(void)
 {
-	const struct dyn_cfg_dtb_info_t *fw_config_info;
+	const struct dyn_cfg_dtb_info_t *config_info __unused;
+	uint32_t fw_config_max_size __unused;
+	image_info_t config_image_info __unused;
+	struct transfer_list_entry *te __unused;
+
 	image_desc_t *desc;
-	uint32_t fw_config_max_size;
+
 	int err = -1;
 
 	/* Initialise the IO layer and register platform IO devices */
@@ -159,6 +170,37 @@
 		return;
 	}
 
+#if TRANSFER_LIST
+	secure_tl = transfer_list_init((void *)PLAT_ARM_EL3_FW_HANDOFF_BASE,
+				       PLAT_ARM_FW_HANDOFF_SIZE);
+
+	if (secure_tl == NULL) {
+		ERROR("Secure transfer list initialisation failed!\n");
+		panic();
+	}
+
+	te = transfer_list_add(secure_tl, TL_TAG_TB_FW_CONFIG,
+			       ARM_TB_FW_CONFIG_MAX_SIZE, NULL);
+	assert(te != NULL);
+
+	/*
+	 * Set the load address of TB_FW_CONFIG in the data section of the TE just
+	 * allocated in the secure transfer list.
+	 */
+	SET_PARAM_HEAD(&config_image_info, PARAM_IMAGE_BINARY, VERSION_2, 0);
+	config_image_info.image_base = (uintptr_t)transfer_list_entry_data(te);
+	config_image_info.image_max_size = te->data_size;
+
+	VERBOSE("FCONF: Loading config with image ID: %u\n", TB_FW_CONFIG_ID);
+	err = load_auth_image(TB_FW_CONFIG_ID, &config_image_info);
+	if (err != 0) {
+		VERBOSE("Failed to load config %u\n", TB_FW_CONFIG_ID);
+		plat_error_handler(err);
+	}
+
+	transfer_list_update_checksum(secure_tl);
+	fconf_populate("TB_FW", (uintptr_t)transfer_list_entry_data(te));
+#else
 	/* Set global DTB info for fixed fw_config information */
 	fw_config_max_size = ARM_FW_CONFIG_LIMIT - ARM_FW_CONFIG_BASE;
 	set_config_info(ARM_FW_CONFIG_BASE, ~0UL, fw_config_max_size, FW_CONFIG_ID);
@@ -174,13 +216,14 @@
 	 * FW_CONFIG loaded successfully. If FW_CONFIG device tree parsing
 	 * is successful then load TB_FW_CONFIG device tree.
 	 */
-	fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
-	if (fw_config_info != NULL) {
-		err = fconf_populate_dtb_registry(fw_config_info->config_addr);
+	config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
+	if (config_info != NULL) {
+		err = fconf_populate_dtb_registry(config_info->config_addr);
 		if (err < 0) {
 			ERROR("Parsing of FW_CONFIG failed %d\n", err);
 			plat_error_handler(err);
 		}
+
 		/* load TB_FW_CONFIG */
 		err = fconf_load_config(TB_FW_CONFIG_ID);
 		if (err < 0) {
@@ -191,11 +234,17 @@
 		ERROR("Invalid FW_CONFIG address\n");
 		plat_error_handler(err);
 	}
+#endif /* TRANSFER_LIST */
 
-	/* The BL2 ep_info arg0 is modified to point to FW_CONFIG */
 	desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+
+#if TRANSFER_LIST
+	transfer_list_set_handoff_args(secure_tl, &desc->ep_info);
+#else
+	/* The BL2 ep_info arg0 is modified to point to FW_CONFIG */
 	assert(desc != NULL);
-	desc->ep_info.args.arg0 = fw_config_info->config_addr;
+	desc->ep_info.args.arg0 = config_info->config_addr;
+#endif /* TRANSFER_LIST */
 
 #if CRYPTO_SUPPORT
 	/* Share the Mbed TLS heap info with other images */
@@ -250,3 +299,32 @@
 {
 	return  is_fwu_needed ? NS_BL1U_IMAGE_ID : BL2_IMAGE_ID;
 }
+
+// Use the default implementation of this function when Firmware Handoff is
+// disabled to avoid duplicating its logic.
+#if TRANSFER_LIST
+int bl1_plat_handle_post_image_load(unsigned int image_id)
+{
+	image_desc_t *image_desc __unused;
+
+	assert(image_id == BL2_IMAGE_ID);
+	struct transfer_list_entry *te;
+
+	/* Convey this information to BL2 via its TL. */
+	te = transfer_list_add(secure_tl, TL_TAG_SRAM_LAYOUT64,
+			       sizeof(meminfo_t), NULL);
+	assert(te != NULL);
+
+	bl1_plat_calc_bl2_layout(&bl1_tzram_layout,
+				 (meminfo_t *)transfer_list_entry_data(te));
+
+	transfer_list_update_checksum(secure_tl);
+
+	/**
+	 * Before exiting make sure the contents of the TL are flushed in case there's no
+	 * support for hardware cache coherency.
+	 */
+	flush_dcache_range((uintptr_t)secure_tl, secure_tl->size);
+	return 0;
+}
+#endif /* TRANSFER_LIST*/
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 85c0a16..3e7c73a 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -33,13 +33,18 @@
 static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
 
 /* Base address of fw_config received from BL1 */
-static uintptr_t config_base;
+static uintptr_t config_base __unused;
 
 /*
  * Check that BL2_BASE is above ARM_FW_CONFIG_LIMIT. This reserved page is
  * for `meminfo_t` data structure and fw_configs passed from BL1.
  */
+#if TRANSFER_LIST
+CASSERT(BL2_BASE >= PLAT_ARM_EL3_FW_HANDOFF_BASE + PLAT_ARM_FW_HANDOFF_SIZE,
+	assert_bl2_base_overflows);
+#else
 CASSERT(BL2_BASE >= ARM_FW_CONFIG_LIMIT, assert_bl2_base_overflows);
+#endif /* TRANSFER_LIST */
 
 /* Weak definitions may be overridden in specific ARM standard platform */
 #pragma weak bl2_early_platform_setup2
@@ -72,16 +77,28 @@
 void arm_bl2_early_platform_setup(uintptr_t fw_config,
 				  struct meminfo *mem_layout)
 {
+	struct transfer_list_entry *te __unused;
 	int __maybe_unused ret;
 
 	/* Initialize the console to provide early debug support */
 	arm_console_boot_init();
 
-	/* Setup the BL2 memory layout */
-	bl2_tzram_layout = *mem_layout;
+#if TRANSFER_LIST
+	// TODO: modify the prototype of this function fw_config != bl2_tl
+	secure_tl = (struct transfer_list_header *)fw_config;
 
+	te = transfer_list_find(secure_tl, TL_TAG_SRAM_LAYOUT64);
+	assert(te != NULL);
+
+	bl2_tzram_layout = *(meminfo_t *)transfer_list_entry_data(te);
+	transfer_list_rem(secure_tl, te);
+#else
 	config_base = fw_config;
 
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+#endif
+
 	/* Initialise the IO layer and register platform IO devices */
 	plat_arm_io_setup();
 
@@ -110,13 +127,6 @@
 void bl2_plat_preload_setup(void)
 {
 #if TRANSFER_LIST
-	secure_tl = transfer_list_init((void *)PLAT_ARM_EL3_FW_HANDOFF_BASE,
-				       PLAT_ARM_FW_HANDOFF_SIZE);
-	if (secure_tl == NULL) {
-		ERROR("Initialisation of secure transfer list failed!\n");
-		panic();
-	}
-
 	arm_transfer_list_dyn_cfg_init(secure_tl);
 #else
 	arm_bl2_dyn_cfg_init();
@@ -178,11 +188,13 @@
 		ARM_MAP_ROMLIB_CODE,
 		ARM_MAP_ROMLIB_DATA,
 #endif
+#if !TRANSFER_LIST
 		ARM_MAP_BL_CONFIG_REGION,
+#endif /* TRANSFER_LIST */
 #if ENABLE_RME
 		ARM_MAP_L0_GPT_REGION,
 #endif
-		{0}
+		{ 0 }
 	};
 
 #if ENABLE_RME
@@ -211,10 +223,17 @@
 
 void bl2_plat_arch_setup(void)
 {
-	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
-
+	const struct dyn_cfg_dtb_info_t *tb_fw_config_info __unused;
+	struct transfer_list_entry *te __unused;
 	arm_bl2_plat_arch_setup();
 
+#if TRANSFER_LIST
+	te = transfer_list_find(secure_tl, TL_TAG_TB_FW_CONFIG);
+	assert(te != NULL);
+
+	fconf_populate("TB_FW", (uintptr_t)transfer_list_entry_data(te));
+	transfer_list_rem(secure_tl, te);
+#else
 	/* Fill the properties struct with the info from the config dtb */
 	fconf_populate("FW_CONFIG", config_base);
 
@@ -223,6 +242,7 @@
 	assert(tb_fw_config_info != NULL);
 
 	fconf_populate("TB_FW", tb_fw_config_info->config_addr);
+#endif
 }
 
 int arm_bl2_handle_post_image_load(unsigned int image_id)