From a5566f65fd1be689ca5c63baa1f5b61b40960c8d Mon Sep 17 00:00:00 2001
From: Harrison Mutai <harrison.mutai@arm.com>
Date: Fri, 1 Dec 2023 15:50:00 +0000
Subject: [PATCH 1/6] feat(arm): support FW handoff b/w BL2 & BL31

Add support for the firmware handoff framework between BL2 and BL31.
Create a transfer list in trusted SRAM, leveraging the larger SRAM sizes
in recent models. Load the HW_CONFIG as a TE along with entry point
parameters for BL31 execution.

Change-Id: I7c4c6e8353ca978a13520fb3e15fb2803f0f1d0e
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
---
 include/plat/arm/common/plat_arm.h        | 16 ++++
 plat/arm/board/fvp/fvp_bl2_setup.c        | 57 +++++---------
 plat/arm/board/fvp/fvp_bl31_setup.c       | 10 ++-
 plat/arm/board/fvp/fvp_common.c           | 21 +++--
 plat/arm/board/fvp/include/platform_def.h | 16 +++-
 plat/arm/board/fvp/platform.mk            | 33 +++++---
 plat/arm/common/arm_bl2_setup.c           | 42 ++++++++++
 plat/arm/common/arm_bl31_setup.c          | 64 ++++++++++++++-
 plat/arm/common/arm_common.mk             |  6 +-
 plat/arm/common/arm_image_load.c          | 20 +++--
 plat/arm/common/arm_transfer_list.c       | 96 +++++++++++++++++++++++
 11 files changed, 316 insertions(+), 65 deletions(-)
 create mode 100644 plat/arm/common/arm_transfer_list.c

diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index a43e13c82..48d70688f 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -9,12 +9,14 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include <common/desc_image_load.h>
 #include <drivers/arm/tzc_common.h>
 #include <lib/bakery_lock.h>
 #include <lib/cassert.h>
 #include <lib/el3_runtime/cpu_data.h>
 #include <lib/gpt_rme/gpt_rme.h>
 #include <lib/spinlock.h>
+#include <lib/transfer_list.h>
 #include <lib/utils_def.h>
 #include <lib/xlat_tables/xlat_tables_compat.h>
 
@@ -254,6 +256,7 @@ uint32_t arm_get_spsr_for_bl33_entry(void);
 int arm_bl2_plat_handle_post_image_load(unsigned int image_id);
 int arm_bl2_handle_post_image_load(unsigned int image_id);
 struct bl_params *arm_get_next_bl_params(void);
+void arm_bl2_setup_next_ep_info(bl_mem_params_node_t *next_param_node);
 
 /* BL2 at EL3 functions */
 void arm_bl2_el3_early_platform_setup(void);
@@ -266,12 +269,25 @@ void arm_bl2u_platform_setup(void);
 void arm_bl2u_plat_arch_setup(void);
 
 /* BL31 utility functions */
+#if TRANSFER_LIST
+void arm_bl31_early_platform_setup(u_register_t arg0, u_register_t arg1,
+				   u_register_t arg2, u_register_t arg3);
+#else
 void arm_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config,
 				uintptr_t hw_config, void *plat_params_from_bl2);
+#endif
 void arm_bl31_platform_setup(void);
 void arm_bl31_plat_runtime_setup(void);
 void arm_bl31_plat_arch_setup(void);
 
+/* Firmware Handoff utility functions */
+void arm_transfer_list_dyn_cfg_init(struct transfer_list_header *secure_tl);
+void arm_transfer_list_populate_ep_info(bl_mem_params_node_t *next_param_node,
+					struct transfer_list_header *secure_tl,
+					struct transfer_list_header *ns_tl);
+void arm_transfer_list_copy_hw_config(struct transfer_list_header *secure_tl,
+				      struct transfer_list_header *ns_tl);
+
 /* TSP utility functions */
 void arm_tsp_early_platform_setup(void);
 
diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c
index 97d000e7f..58db4e84e 100644
--- a/plat/arm/board/fvp/fvp_bl2_setup.c
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -20,8 +20,6 @@
 
 #include "fvp_private.h"
 
-static struct transfer_list_header *ns_tl __unused;
-
 #if ENABLE_RME
 /*
  * The GPT library might modify the gpt regions structure to optimize
@@ -60,10 +58,6 @@ void bl2_platform_setup(void)
 {
 	arm_bl2_platform_setup();
 
-#if TRANSFER_LIST
-	ns_tl = transfer_list_init((void *)FW_NS_HANDOFF_BASE, FW_HANDOFF_SIZE);
-	assert(ns_tl != NULL);
-#endif
 	/* Initialize System level generic or SP804 timer */
 	fvp_timer_init();
 }
@@ -81,16 +75,15 @@ const arm_gpt_info_t *plat_arm_get_gpt_info(void)
 struct bl_params *plat_get_next_bl_params(void)
 {
 	struct bl_params *arm_bl_params;
-	const struct dyn_cfg_dtb_info_t *hw_config_info __unused;
-	struct transfer_list_entry *te __unused;
 	bl_mem_params_node_t *param_node __unused;
+	const struct dyn_cfg_dtb_info_t *fw_config_info __unused;
+	const struct dyn_cfg_dtb_info_t *hw_config_info __unused;
+	entry_point_info_t *ep __unused;
+	uint32_t next_exe_img_id __unused;
+	uintptr_t fw_config_base __unused;
 
 	arm_bl_params = arm_get_next_bl_params();
 
-#if !RESET_TO_BL2 && !EL3_PAYLOAD_BASE
-	const struct dyn_cfg_dtb_info_t *fw_config_info;
-	uintptr_t fw_config_base = 0UL;
-
 #if __aarch64__
 	/* Get BL31 image node */
 	param_node = get_bl_mem_params_node(BL31_IMAGE_ID);
@@ -100,6 +93,15 @@ struct bl_params *plat_get_next_bl_params(void)
 #endif /* __aarch64__ */
 	assert(param_node != NULL);
 
+#if TRANSFER_LIST
+	arm_bl_params->head = &param_node->params_node_mem;
+	arm_bl_params->head->ep_info = &param_node->ep_info;
+	arm_bl_params->head->image_id = param_node->image_id;
+
+	arm_bl2_setup_next_ep_info(param_node);
+#elif !RESET_TO_BL2 && !EL3_PAYLOAD_BASE
+	fw_config_base = 0UL;
+
 	/* Update the next image's ep info with the FW config address */
 	fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, FW_CONFIG_ID);
 	assert(fw_config_info != NULL);
@@ -113,49 +115,29 @@ struct bl_params *plat_get_next_bl_params(void)
 	param_node = get_bl_mem_params_node(BL33_IMAGE_ID);
 	assert(param_node != NULL);
 
-#if TRANSFER_LIST
-	/* Update BL33's ep info with NS HW config address  */
-	te = transfer_list_find(ns_tl, TL_TAG_FDT);
-	assert(te != NULL);
-
-	param_node->ep_info.args.arg1 = TRANSFER_LIST_SIGNATURE |
-					REGISTER_CONVENTION_VERSION_MASK;
-	param_node->ep_info.args.arg2 = 0;
-	param_node->ep_info.args.arg3 = (uintptr_t)ns_tl;
-	param_node->ep_info.args.arg0 =
-		te ? (uintptr_t)transfer_list_entry_data(te) : 0;
-#else
 	hw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, HW_CONFIG_ID);
 	assert(hw_config_info != NULL);
 
 	param_node->ep_info.args.arg1 = hw_config_info->secondary_config_addr;
 #endif /* TRANSFER_LIST */
-#endif /* !RESET_TO_BL2 && !EL3_PAYLOAD_BASE */
 
 	return arm_bl_params;
 }
 
 int bl2_plat_handle_post_image_load(unsigned int image_id)
 {
-#if !RESET_TO_BL2 && !EL3_PAYLOAD_BASE
+#if !RESET_TO_BL2 && !EL3_PAYLOAD_BASE && !TRANSFER_LIST
 	if (image_id == HW_CONFIG_ID) {
-		const struct dyn_cfg_dtb_info_t *hw_config_info;
+		const struct dyn_cfg_dtb_info_t *hw_config_info __unused;
 		struct transfer_list_entry *te __unused;
+		bl_mem_params_node_t *param_node __unused;
 
-		const bl_mem_params_node_t *param_node =
-			get_bl_mem_params_node(image_id);
+		param_node = get_bl_mem_params_node(image_id);
 		assert(param_node != NULL);
 
 		hw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, HW_CONFIG_ID);
 		assert(hw_config_info != NULL);
 
-#if TRANSFER_LIST
-		/* Update BL33's ep info with NS HW config address  */
-		te = transfer_list_add(ns_tl, TL_TAG_FDT,
-				       param_node->image_info.image_size,
-				       (void *)hw_config_info->config_addr);
-		assert(te != NULL);
-#else
 		memcpy((void *)hw_config_info->secondary_config_addr,
 		       (void *)hw_config_info->config_addr,
 		       (size_t)param_node->image_info.image_size);
@@ -166,9 +148,8 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
 		 */
 		flush_dcache_range(hw_config_info->secondary_config_addr,
 				   param_node->image_info.image_size);
-#endif /* TRANSFER_LIST */
 	}
-#endif /* !RESET_TO_BL2 && !EL3_PAYLOAD_BASE */
+#endif /* !RESET_TO_BL2 && !EL3_PAYLOAD_BASE && !TRANSFER_LIST*/
 
 	return arm_bl2_plat_handle_post_image_load(image_id);
 }
diff --git a/plat/arm/board/fvp/fvp_bl31_setup.c b/plat/arm/board/fvp/fvp_bl31_setup.c
index 93289b6b5..e08756562 100644
--- a/plat/arm/board/fvp/fvp_bl31_setup.c
+++ b/plat/arm/board/fvp/fvp_bl31_setup.c
@@ -5,12 +5,15 @@
  */
 
 #include <assert.h>
+
+#include <common/bl_common.h>
 #include <common/debug.h>
 #include <drivers/arm/smmu_v3.h>
 #include <fconf_hw_config_getter.h>
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
 #include <lib/mmio.h>
+
 #include <plat/arm/common/arm_config.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
@@ -25,6 +28,9 @@ void __init bl31_early_platform_setup2(u_register_t arg0,
 	/* Initialize the console to provide early debug support */
 	arm_console_boot_init();
 
+#if TRANSFER_LIST
+	arm_bl31_early_platform_setup(arg0, arg1, arg2, arg3);
+#else
 #if !RESET_TO_BL31 && !RESET_TO_BL2
 	const struct dyn_cfg_dtb_info_t *soc_fw_config_info;
 
@@ -48,8 +54,8 @@ void __init bl31_early_platform_setup2(u_register_t arg0,
 	assert(hw_config_info->secondary_config_addr != 0UL);
 	arg2 = hw_config_info->secondary_config_addr;
 #endif /* !RESET_TO_BL31 && !RESET_TO_BL2 */
-
 	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+#endif /* TRANSFER_LIST */
 
 	/* Initialize the platform config for future decision making */
 	fvp_config_setup();
@@ -88,6 +94,7 @@ void __init bl31_early_platform_setup2(u_register_t arg0,
 	}
 }
 
+#if !TRANSFER_LIST
 void __init bl31_plat_arch_setup(void)
 {
 	int rc __unused;
@@ -142,6 +149,7 @@ void __init bl31_plat_arch_setup(void)
 	}
 #endif /* !RESET_TO_BL31 && !RESET_TO_BL2 && !ARM_XLAT_TABLES_LIB_V1 */
 }
+#endif /* TRANSFER_LIST */
 
 unsigned int plat_get_syscnt_freq2(void)
 {
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 8cbf10eb1..5557d5991 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -81,9 +81,14 @@ arm_config_t arm_config;
 
 #if TRANSFER_LIST
 #ifdef FW_NS_HANDOFF_BASE
-#define MAP_FW_NS_HANDOFF MAP_REGION_FLAT(FW_NS_HANDOFF_BASE, \
-					  FW_HANDOFF_SIZE,    \
-					  MT_MEMORY | MT_RW | MT_NS)
+#define MAP_FW_NS_HANDOFF                                             \
+	MAP_REGION_FLAT(FW_NS_HANDOFF_BASE, PLAT_ARM_FW_HANDOFF_SIZE, \
+			MT_MEMORY | MT_RW | MT_NS)
+#endif
+#ifdef PLAT_ARM_EL3_FW_HANDOFF_BASE
+#define MAP_EL3_FW_HANDOFF                            \
+	MAP_REGION_FLAT(PLAT_ARM_EL3_FW_HANDOFF_BASE, \
+			PLAT_ARM_FW_HANDOFF_SIZE, MT_MEMORY | MT_RW | EL3_PAS)
 #endif
 #endif
 
@@ -165,7 +170,10 @@ defined(SPD_spmd))
 	ARM_MAP_OPTEE_CORE_MEM,
 	ARM_OPTEE_PAGEABLE_LOAD_MEM,
 #endif
-	{0}
+#ifdef MAP_EL3_FW_HANDOFF
+	MAP_EL3_FW_HANDOFF,
+#endif
+	{ 0 }
 };
 #endif
 #ifdef IMAGE_BL2U
@@ -202,7 +210,10 @@ const mmap_region_t plat_arm_mmap[] = {
 #ifdef MAP_FW_NS_HANDOFF
 	MAP_FW_NS_HANDOFF,
 #endif
-	{0}
+#ifdef MAP_EL3_FW_HANDOFF
+	MAP_EL3_FW_HANDOFF,
+#endif
+	{ 0 }
 };
 
 #if defined(IMAGE_BL31) && SPM_MM
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index ab1b07f82..56de8b8ef 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -143,8 +143,14 @@
 #define PLAT_ARM_NS_IMAGE_BASE		(ARM_DRAM1_BASE + UL(0x8000000))
 
 #if TRANSFER_LIST
-#define FW_HANDOFF_SIZE			0x4000
-#define FW_NS_HANDOFF_BASE		(PLAT_ARM_NS_IMAGE_BASE - FW_HANDOFF_SIZE)
+#define PLAT_ARM_FW_HANDOFF_SIZE	U(0x5000)
+
+#define FW_NS_HANDOFF_BASE		(PLAT_ARM_NS_IMAGE_BASE - PLAT_ARM_FW_HANDOFF_SIZE)
+#define PLAT_ARM_EL3_FW_HANDOFF_BASE	ARM_BL_RAM_BASE
+#define PLAT_ARM_EL3_FW_HANDOFF_LIMIT	PLAT_ARM_EL3_FW_HANDOFF_BASE + PLAT_ARM_FW_HANDOFF_SIZE
+
+#else
+#define PLAT_ARM_FW_HANDOFF_SIZE	U(0)
 #endif
 
 /*
@@ -269,9 +275,15 @@ defined(IMAGE_BL2) && MEASURED_BOOT
  * BL2 and BL1-RW.
  * Size of the BL31 PROGBITS increases as the SRAM size increases.
  */
+#if TRANSFER_LIST
+#define PLAT_ARM_MAX_BL31_SIZE                              \
+	(PLAT_ARM_TRUSTED_SRAM_SIZE - ARM_SHARED_RAM_SIZE - \
+	 PLAT_ARM_FW_HANDOFF_SIZE - ARM_L0_GPT_SIZE)
+#else
 #define PLAT_ARM_MAX_BL31_SIZE		(PLAT_ARM_TRUSTED_SRAM_SIZE - \
 					 ARM_SHARED_RAM_SIZE - \
 					 ARM_FW_CONFIGS_SIZE - ARM_L0_GPT_SIZE)
+#endif /* TRANSFER_LIST */
 #endif /* RESET_TO_BL31 */
 
 #ifndef __aarch64__
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 8fa01ffe5..0860dd1c1 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -330,9 +330,25 @@ else
 BL31_SOURCES		+=	drivers/delay_timer/generic_delay_timer.c
 endif
 
+ifeq (${TRANSFER_LIST}, 1)
+include lib/transfer_list/transfer_list.mk
+endif
+
 # 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
+
+FDT_SOURCES		+=	${FVP_HW_CONFIG_DTS}
+$(eval FVP_HW_CONFIG	:=	${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(FVP_HW_CONFIG_DTS)))
+
+ifeq (${TRANSFER_LIST}, 1)
+FDT_SOURCES		+=	$(addprefix plat/arm/board/fvp/fdts/,	\
+					${PLAT}_fw_config.dts		\
+					${PLAT}_tb_fw_config.dts	\
+				)
+else
 FDT_SOURCES		+=	$(addprefix plat/arm/board/fvp/fdts/,	\
 					${PLAT}_fw_config.dts		\
 					${PLAT}_tb_fw_config.dts	\
@@ -340,7 +356,6 @@ FDT_SOURCES		+=	$(addprefix plat/arm/board/fvp/fdts/,	\
 					${PLAT}_nt_fw_config.dts	\
 				)
 
-FVP_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_fw_config.dtb
 FVP_TB_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_tb_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
@@ -353,10 +368,6 @@ FVP_TOS_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_tsp_fw_config.dtb
 $(eval $(call TOOL_ADD_PAYLOAD,${FVP_TOS_FW_CONFIG},--tos-fw-config,${FVP_TOS_FW_CONFIG}))
 endif
 
-ifeq (${TRANSFER_LIST}, 1)
-include lib/transfer_list/transfer_list.mk
-endif
-
 ifeq (${SPD},spmd)
 
 ifeq ($(ARM_SPMC_MANIFEST_DTS),)
@@ -370,18 +381,16 @@ FVP_TOS_FW_CONFIG	:=	${BUILD_PLAT}/fdts/$(notdir $(basename ${ARM_SPMC_MANIFEST_
 $(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 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 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
 
-FDT_SOURCES		+=	${FVP_HW_CONFIG_DTS}
-$(eval FVP_HW_CONFIG	:=	${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(FVP_HW_CONFIG_DTS)))
-
+# 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
 $(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config,${FVP_HW_CONFIG}))
 endif
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 30d064791..85c0a1683 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -19,6 +19,9 @@
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
 #include <lib/gpt_rme/gpt_rme.h>
+#if TRANSFER_LIST
+#include <lib/transfer_list.h>
+#endif
 #ifdef SPD_opteed
 #include <lib/optee_utils.h>
 #endif
@@ -58,6 +61,9 @@ CASSERT(BL2_BASE >= ARM_FW_CONFIG_LIMIT, assert_bl2_base_overflows);
 
 #pragma weak arm_bl2_plat_handle_post_image_load
 
+static struct transfer_list_header *secure_tl __unused;
+static struct transfer_list_header *ns_tl __unused;
+
 /*******************************************************************************
  * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
  * in x0. This memory layout is sitting at the base of the free trusted SRAM.
@@ -103,7 +109,18 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_
  */
 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();
+#endif
 
 #if ARM_GPT_SUPPORT && !PSA_FWU_SUPPORT
 	/* Always use the FIP from bank 0 */
@@ -124,6 +141,16 @@ void arm_bl2_platform_setup(void)
 #if defined(PLAT_ARM_MEM_PROT_ADDR)
 	arm_nor_psci_do_static_mem_protect();
 #endif
+
+#if TRANSFER_LIST
+	ns_tl = transfer_list_init((void *)FW_NS_HANDOFF_BASE,
+				   PLAT_ARM_FW_HANDOFF_SIZE);
+
+	if (ns_tl == NULL) {
+		ERROR("Non-secure transfer list initialisation failed!");
+		panic();
+	}
+#endif
 }
 
 void bl2_platform_setup(void)
@@ -265,5 +292,20 @@ int arm_bl2_plat_handle_post_image_load(unsigned int image_id)
 		return 0;
 	}
 #endif
+
+#if TRANSFER_LIST
+	if (image_id == HW_CONFIG_ID) {
+		arm_transfer_list_copy_hw_config(secure_tl, ns_tl);
+	}
+#endif /* TRANSFER_LIST */
+
 	return arm_bl2_handle_post_image_load(image_id);
 }
+
+void arm_bl2_setup_next_ep_info(bl_mem_params_node_t *next_param_node)
+{
+	assert(transfer_list_set_handoff_args(
+		       secure_tl, &next_param_node->ep_info) != NULL);
+
+	arm_transfer_list_populate_ep_info(next_param_node, secure_tl, ns_tl);
+}
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 33043b7b1..206f4a5b2 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -13,13 +13,18 @@
 #include <drivers/console.h>
 #include <lib/debugfs.h>
 #include <lib/extensions/ras.h>
+#include <lib/fconf/fconf.h>
 #include <lib/gpt_rme/gpt_rme.h>
 #include <lib/mmio.h>
+#if TRANSFER_LIST
+#include <lib/transfer_list.h>
+#endif
 #include <lib/xlat_tables/xlat_tables_compat.h>
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
 #include <platform_def.h>
 
+static struct transfer_list_header *secure_tl __unused;
 /*
  * Placeholder variables for copying the arguments that have been passed to
  * BL31 from BL2.
@@ -35,8 +40,12 @@ static entry_point_info_t rmm_image_ep_info;
  * Check that BL31_BASE is above ARM_FW_CONFIG_LIMIT. The reserved page
  * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2.
  */
+#if TRANSFER_LIST
+CASSERT(BL31_BASE >= PLAT_ARM_EL3_FW_HANDOFF_LIMIT, assert_bl31_base_overflows);
+#else
 CASSERT(BL31_BASE >= ARM_FW_CONFIG_LIMIT, assert_bl31_base_overflows);
-#endif
+#endif /* TRANSFER_LIST */
+#endif /* RESET_TO_BL31 */
 
 /* Weak definitions may be overridden in specific ARM standard platform */
 #pragma weak bl31_early_platform_setup2
@@ -115,6 +124,44 @@ struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type)
  * while creating page tables. BL2 has flushed this information to memory, so
  * we are guaranteed to pick up good data.
  ******************************************************************************/
+#if TRANSFER_LIST
+void __init arm_bl31_early_platform_setup(u_register_t arg0, u_register_t arg1,
+					  u_register_t arg2, u_register_t arg3)
+{
+	struct transfer_list_entry *te = NULL;
+	struct entry_point_info *ep;
+
+	secure_tl = (struct transfer_list_header *)arg3;
+
+	/*
+	 * Populate the global entry point structures used to execute subsequent
+	 * images.
+	 */
+	while ((te = transfer_list_next(secure_tl, te)) != NULL) {
+		ep = transfer_list_entry_data(te);
+
+		if (te->tag_id == TL_TAG_EXEC_EP_INFO64) {
+			switch (GET_SECURITY_STATE(ep->h.attr)) {
+			case NON_SECURE:
+				bl33_image_ep_info = *ep;
+				break;
+#if ENABLE_RME
+			case REALM:
+				rmm_image_ep_info = *ep;
+				break;
+#endif
+			case SECURE:
+				bl32_image_ep_info = *ep;
+				break;
+			default:
+				ERROR("Unrecognized Image Security State %lu\n",
+				      GET_SECURITY_STATE(ep->h.attr));
+				panic();
+			}
+		}
+	}
+}
+#else
 void __init arm_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config,
 				uintptr_t hw_config, void *plat_params_from_bl2)
 {
@@ -258,11 +305,16 @@ void __init arm_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_confi
 	bl33_image_ep_info.args.arg3 = 0U;
 # endif
 }
+#endif
 
 void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 		u_register_t arg2, u_register_t arg3)
 {
+#if TRANSFER_LIST
+	arm_bl31_early_platform_setup(arg0, arg1, arg2, arg3);
+#else
 	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+#endif
 
 	/*
 	 * Initialize Interconnect for this cluster during cold boot.
@@ -448,5 +500,15 @@ void __init arm_bl31_plat_arch_setup(void)
 
 void __init bl31_plat_arch_setup(void)
 {
+	struct transfer_list_entry *te __unused;
+
 	arm_bl31_plat_arch_setup();
+
+#if TRANSFER_LIST
+	te = transfer_list_find(secure_tl, TL_TAG_FDT);
+	assert(te != NULL);
+
+	/* Populate HW_CONFIG device tree with the mapped address */
+	fconf_populate("HW_CONFIG", (uintptr_t)transfer_list_entry_data(te));
+#endif
 }
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 5084ea95e..7ab39eb28 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -299,6 +299,10 @@ BL31_SOURCES		+=	plat/arm/common/arm_bl31_setup.c		\
 				plat/arm/common/arm_topology.c			\
 				plat/common/plat_psci_common.c
 
+ifeq (${TRANSFER_LIST}, 1)
+	TRANSFER_LIST_SOURCES += plat/arm/common/arm_transfer_list.c
+endif
+
 ifneq ($(filter 1,${ENABLE_PMF} ${ETHOSN_NPU_DRIVER}),)
 ARM_SVC_HANDLER_SRCS :=
 
diff --git a/plat/arm/common/arm_image_load.c b/plat/arm/common/arm_image_load.c
index c411c6cbb..25252666f 100644
--- a/plat/arm/common/arm_image_load.c
+++ b/plat/arm/common/arm_image_load.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,7 +17,10 @@
 #pragma weak plat_get_bl_image_load_info
 #pragma weak plat_get_next_bl_params
 
-static bl_params_t *next_bl_params_cpy_ptr;
+#if TRANSFER_LIST
+static bl_params_t next_bl_params_cpy;
+#endif
+bl_params_t *next_bl_params_cpy_ptr;
 
 /*******************************************************************************
  * This function flushes the data structures so that they are visible
@@ -96,9 +99,15 @@ struct bl_load_info *plat_get_bl_image_load_info(void)
  ******************************************************************************/
 struct bl_params *arm_get_next_bl_params(void)
 {
-	bl_mem_params_node_t *bl2_mem_params_descs_cpy
-			= (bl_mem_params_node_t *)ARM_BL2_MEM_DESC_BASE;
-	const bl_params_t *next_bl_params;
+	bl_mem_params_node_t *bl2_mem_params_descs_cpy __unused;
+	const bl_params_t *next_bl_params __unused;
+
+#if TRANSFER_LIST
+	next_bl_params_cpy_ptr = &next_bl_params_cpy;
+	SET_PARAM_HEAD(next_bl_params_cpy_ptr, PARAM_BL_PARAMS, VERSION_2, 0U);
+#else
+	bl2_mem_params_descs_cpy =
+		(bl_mem_params_node_t *)ARM_BL2_MEM_DESC_BASE;
 
 	next_bl_params_cpy_ptr =
 		(bl_params_t *)(ARM_BL2_MEM_DESC_BASE +
@@ -127,6 +136,7 @@ struct bl_params *arm_get_next_bl_params(void)
 						(sizeof(bl_params_t)));
 
 	populate_next_bl_params_config(next_bl_params_cpy_ptr);
+#endif /* TRANSFER_LIST */
 
 	return next_bl_params_cpy_ptr;
 }
diff --git a/plat/arm/common/arm_transfer_list.c b/plat/arm/common/arm_transfer_list.c
new file mode 100644
index 000000000..d144bbb5b
--- /dev/null
+++ b/plat/arm/common/arm_transfer_list.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+void arm_transfer_list_dyn_cfg_init(struct transfer_list_header *secure_tl)
+{
+	struct transfer_list_entry *te;
+	bl_mem_params_node_t *next_param_node =
+		get_bl_mem_params_node(HW_CONFIG_ID);
+	assert(next_param_node != NULL);
+
+	/*
+	 * The HW_CONFIG needs to be authenticated via the normal loading
+	 * mechanism. Pre-allocate a TE for the configuration and update the
+	 * load information so the configuration is loaded directly into the TE.
+	 */
+	te = transfer_list_add(secure_tl, TL_TAG_FDT, PLAT_ARM_HW_CONFIG_SIZE,
+			       NULL);
+	assert(te != NULL);
+
+	next_param_node->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
+	next_param_node->image_info.image_max_size = PLAT_ARM_HW_CONFIG_SIZE;
+	next_param_node->image_info.image_base =
+		(uintptr_t)transfer_list_entry_data(te);
+}
+
+void arm_transfer_list_populate_ep_info(bl_mem_params_node_t *next_param_node,
+					struct transfer_list_header *secure_tl,
+					struct transfer_list_header *ns_tl)
+{
+	uint32_t next_exe_img_id;
+	entry_point_info_t *ep;
+	struct transfer_list_entry *te;
+
+	assert(next_param_node != NULL);
+
+	while ((next_exe_img_id = next_param_node->next_handoff_image_id) !=
+	       INVALID_IMAGE_ID) {
+		next_param_node =
+			&bl_mem_params_desc_ptr[get_bl_params_node_index(
+				next_exe_img_id)];
+		assert(next_param_node != NULL);
+
+		te = transfer_list_add(secure_tl, TL_TAG_EXEC_EP_INFO64,
+				       sizeof(entry_point_info_t),
+				       &next_param_node->ep_info);
+		assert(te != NULL);
+
+		ep = transfer_list_entry_data(te);
+
+		if (next_exe_img_id == BL33_IMAGE_ID) {
+			ep = transfer_list_set_handoff_args(ns_tl, ep);
+			assert(ep != NULL);
+		} else if ((next_exe_img_id == BL32_IMAGE_ID) && SPMC_AT_EL3) {
+			/*
+			 * Populate the BL32 image base, size and max limit in
+			 * the entry point information, since there is no
+			 * platform function to retrieve them in generic
+			 * code. We choose arg2, arg3 and arg4 since the generic
+			 * code uses arg1 for stashing the SP manifest size. The
+			 * SPMC setup uses these arguments to update SP manifest
+			 * with actual SP's base address and it size.
+			 */
+			ep->args.arg2 = next_param_node->image_info.image_base;
+			ep->args.arg3 = next_param_node->image_info.image_size;
+			ep->args.arg4 =
+				next_param_node->image_info.image_base +
+				next_param_node->image_info.image_max_size;
+		}
+
+		next_exe_img_id = next_param_node->next_handoff_image_id;
+	}
+
+	flush_dcache_range((uintptr_t)secure_tl, secure_tl->size);
+}
+
+void arm_transfer_list_copy_hw_config(struct transfer_list_header *secure_tl,
+				      struct transfer_list_header *ns_tl)
+{
+	struct transfer_list_entry *te =
+		transfer_list_find(secure_tl, TL_TAG_FDT);
+	assert(te != NULL);
+
+	/* Refresh the now stale checksum following loading of HW_CONFIG into the TL. */
+	transfer_list_update_checksum(secure_tl);
+
+	/* Copy the hardware configuration to the non-secure TL. */
+	te = transfer_list_add(ns_tl, TL_TAG_FDT, te->data_size,
+			       transfer_list_entry_data(te));
+	assert(te != NULL);
+}

From 6a4da2905872c3087f0fdc4696ab1969ca3ff472 Mon Sep 17 00:00:00 2001
From: Harrison Mutai <harrison.mutai@arm.com>
Date: Thu, 4 Jan 2024 16:18:47 +0000
Subject: [PATCH 2/6] refactor(bl1): clean up bl2 layout calculation

Layout calculation is spread out between core BL1 logic and common
platform code. Relocate these into common platform code so they are
organised logically.

Change-Id: I8b05403e41b800957a0367316cecd373d10bb1a4
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
---
 bl1/bl1_main.c                         | 23 +-----------
 docs/porting-guide.rst                 | 12 +++++++
 include/bl1/bl1.h                      |  6 +---
 include/plat/common/platform.h         |  6 +++-
 plat/arm/board/fvp_r/fvp_r_bl1_main.c  | 21 -----------
 plat/arm/board/fvp_r/fvp_r_bl1_setup.c |  4 +--
 plat/common/plat_bl1_common.c          | 49 ++++++++++++++++----------
 7 files changed, 52 insertions(+), 69 deletions(-)

diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
index 6fe551188..1dfdc459b 100644
--- a/bl1/bl1_main.c
+++ b/bl1/bl1_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -38,27 +38,6 @@ uint64_t bl1_apiakey[2];
 		BL_TOTAL_IDS, PMF_DUMP_ENABLE)
 #endif
 
-/*******************************************************************************
- * Helper utility to calculate the BL2 memory layout taking into consideration
- * the BL1 RW data assuming that it is at the top of the memory layout.
- ******************************************************************************/
-void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout,
-			meminfo_t *bl2_mem_layout)
-{
-	assert(bl1_mem_layout != NULL);
-	assert(bl2_mem_layout != NULL);
-
-	/*
-	 * Remove BL1 RW data from the scope of memory visible to BL2.
-	 * This is assuming BL1 RW data is at the top of bl1_mem_layout.
-	 */
-	assert(BL1_RW_BASE > bl1_mem_layout->total_base);
-	bl2_mem_layout->total_base = bl1_mem_layout->total_base;
-	bl2_mem_layout->total_size = BL1_RW_BASE - bl1_mem_layout->total_base;
-
-	flush_dcache_range((uintptr_t)bl2_mem_layout, sizeof(meminfo_t));
-}
-
 /*******************************************************************************
  * Setup function for BL1.
  ******************************************************************************/
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 7c66d1118..5d9840aab 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -1712,6 +1712,18 @@ This function can be used by the platforms to update/use image information
 corresponding to ``image_id``. This function is invoked in BL1, both in cold
 boot and FWU code path, before loading the image.
 
+Function : bl1_plat_calc_bl2_layout() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : const meminfo_t *bl1_mem_layout, meminfo_t *bl2_mem_layout
+    Return   : void
+
+This utility function calculates the memory layout of BL2, representing it in a
+`meminfo_t` structure. The default implementation derives this layout from the
+positioning of BL1’s RW data at the top of the memory layout.
+
 Function : bl1_plat_handle_post_image_load() [optional]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/include/bl1/bl1.h b/include/bl1/bl1.h
index 7cd7e727c..3ab88de96 100644
--- a/include/bl1/bl1.h
+++ b/include/bl1/bl1.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -94,9 +94,5 @@ CASSERT(FWU_NUM_SMC_CALLS ==
 		(FWU_SMC_FID_END - FWU_SMC_FID_START + 1),
 		assert_FWU_NUM_SMC_CALLS_mismatch);
 
-/* Utility functions */
-void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout,
-			meminfo_t *bl2_mem_layout);
-
 #endif /* __ASSEMBLER__ */
 #endif /* BL1_H */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index 4fe362005..2af49a93e 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -243,7 +243,11 @@ __dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved);
 int bl1_plat_handle_pre_image_load(unsigned int image_id);
 int bl1_plat_handle_post_image_load(unsigned int image_id);
 
-#if (MEASURED_BOOT || DICE_PROTECTION_ENVIRONMENT)
+/* Utility functions */
+void bl1_plat_calc_bl2_layout(const meminfo_t *bl1_mem_layout,
+			      meminfo_t *bl2_mem_layout);
+
+#if MEASURED_BOOT
 void bl1_plat_mboot_init(void);
 void bl1_plat_mboot_finish(void);
 #else
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_main.c b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
index 252fc31fb..29495cfcb 100644
--- a/plat/arm/board/fvp_r/fvp_r_bl1_main.c
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_main.c
@@ -91,27 +91,6 @@ void bl1_load_bl33(void)
 	NOTICE("BL1: Booting BL33\n");
 }
 
-/*******************************************************************************
- * Helper utility to calculate the BL2 memory layout taking into consideration
- * the BL1 RW data assuming that it is at the top of the memory layout.
- ******************************************************************************/
-void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout,
-			meminfo_t *bl2_mem_layout)
-{
-	assert(bl1_mem_layout != NULL);
-	assert(bl2_mem_layout != NULL);
-
-	/*
-	 * Remove BL1 RW data from the scope of memory visible to BL2.
-	 * This is assuming BL1 RW data is at the top of bl1_mem_layout.
-	 */
-	assert(bl1_mem_layout->total_base < BL1_RW_BASE);
-	bl2_mem_layout->total_base = bl1_mem_layout->total_base;
-	bl2_mem_layout->total_size = BL1_RW_BASE - bl1_mem_layout->total_base;
-
-	flush_dcache_range((uintptr_t)bl2_mem_layout, sizeof(meminfo_t));
-}
-
 /*******************************************************************************
  * This function prepares for entry to BL33
  ******************************************************************************/
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_setup.c b/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
index 6a7c0c808..dcf5e0465 100644
--- a/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -235,7 +235,7 @@ int bl1_plat_handle_post_image_load(unsigned int image_id)
 	 */
 	bl33_secram_layout = (meminfo_t *) bl1_secram_layout->total_base;
 
-	bl1_calc_bl2_mem_layout(bl1_secram_layout, bl33_secram_layout);
+	bl1_plat_calc_bl2_layout(bl1_secram_layout, bl33_secram_layout);
 
 	ep_info->args.arg1 = (uintptr_t)bl33_secram_layout;
 
diff --git a/plat/common/plat_bl1_common.c b/plat/common/plat_bl1_common.c
index bcf9f8956..ff0e0828c 100644
--- a/plat/common/plat_bl1_common.c
+++ b/plat/common/plat_bl1_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -80,10 +80,8 @@ int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size,
  */
 int bl1_plat_handle_post_image_load(unsigned int image_id)
 {
-	meminfo_t *bl2_secram_layout;
-	meminfo_t *bl1_secram_layout;
+	meminfo_t *bl1_tzram_layout;
 	image_desc_t *image_desc;
-	entry_point_info_t *ep_info;
 
 	if (image_id != BL2_IMAGE_ID)
 		return 0;
@@ -92,26 +90,41 @@ int bl1_plat_handle_post_image_load(unsigned int image_id)
 	image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
 	assert(image_desc != NULL);
 
-	/* Get the entry point info */
-	ep_info = &image_desc->ep_info;
-
 	/* Find out how much free trusted ram remains after BL1 load */
-	bl1_secram_layout = bl1_plat_sec_mem_layout();
+	bl1_tzram_layout = bl1_plat_sec_mem_layout();
 
 	/*
-	 * Create a new layout of memory for BL2 as seen by BL1 i.e.
-	 * tell it the amount of total and free memory available.
-	 * This layout is created at the first free address visible
-	 * to BL2. BL2 will read the memory layout before using its
-	 * memory for other purposes.
+	 * Convey this information to BL2 by storing the layout at the first free
+	 * address visible to BL2.
 	 */
-	bl2_secram_layout = (meminfo_t *) bl1_secram_layout->total_base;
+	bl1_plat_calc_bl2_layout(bl1_tzram_layout,
+				 (meminfo_t *)bl1_tzram_layout->total_base);
 
-	bl1_calc_bl2_mem_layout(bl1_secram_layout, bl2_secram_layout);
-
-	ep_info->args.arg1 = (uintptr_t)bl2_secram_layout;
+	image_desc->ep_info.args.arg1 = (uintptr_t)bl1_tzram_layout->total_base;
 
 	VERBOSE("BL1: BL2 memory layout address = %p\n",
-		(void *) bl2_secram_layout);
+		(void *)image_desc->ep_info.args.arg1);
+
 	return 0;
 }
+
+/*******************************************************************************
+ * Helper utility to calculate the BL2 memory layout taking into consideration
+ * the BL1 RW data assuming that it is at the top of the memory layout.
+ ******************************************************************************/
+void bl1_plat_calc_bl2_layout(const meminfo_t *bl1_mem_layout,
+			      meminfo_t *bl2_mem_layout)
+{
+	assert(bl1_mem_layout != NULL);
+	assert(bl2_mem_layout != NULL);
+
+	/*
+	 * Remove BL1 RW data from the scope of memory visible to BL2.
+	 * This is assuming BL1 RW data is at the top of bl1_mem_layout.
+	 */
+	assert(BL1_RW_BASE > bl1_mem_layout->total_base);
+	bl2_mem_layout->total_base = bl1_mem_layout->total_base;
+	bl2_mem_layout->total_size = BL1_RW_BASE - bl1_mem_layout->total_base;
+
+	flush_dcache_range((uintptr_t)bl2_mem_layout, sizeof(meminfo_t));
+}

From 0646c9b293a2d8cdfd4626d15395385b5c1c2a6c Mon Sep 17 00:00:00 2001
From: Harrison Mutai <harrison.mutai@arm.com>
Date: Thu, 4 Jan 2024 16:25:47 +0000
Subject: [PATCH 3/6] feat(handoff): add TE's for BL1 handoff interface

`TL_TAG_RW_MEM_LAYOUT64` encapsulates a structure used to represent the
layout of a region of memory on 64-bit platforms [2]. In TF-A this is
used to represent the `meminfo_t` structure passed between BL1 and BL2,
which provides BL2 with information about the space it has available in
BL2. The `TL_TAG_TB_FW_CONFIG` entry type encapsulates the trusted
bootloader firmware configuration [1].

[1] https://github.com/FirmwareHandoff/firmware_handoff/pull/37
[2] https://github.com/FirmwareHandoff/firmware_handoff/pull/36

Change-Id: I1e0eeec2ec204e469896490d42a9dce9b1b2f209
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
---
 include/lib/transfer_list.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/lib/transfer_list.h b/include/lib/transfer_list.h
index c5df22bb2..5bea2705c 100644
--- a/include/lib/transfer_list.h
+++ b/include/lib/transfer_list.h
@@ -44,6 +44,8 @@ enum transfer_list_tag_id {
 	TL_TAG_OPTEE_PAGABLE_PART = 0x100,
 	TL_TAG_DT_SPMC_MANIFEST = 0x101,
 	TL_TAG_EXEC_EP_INFO64 = 0x102,
+	TL_TAG_TB_FW_CONFIG = 0x103,
+	TL_TAG_SRAM_LAYOUT64 = 0x104,
 };
 
 enum transfer_list_ops {

From 469b1d8412a748819f8c1bf51f695f2cb9f20489 Mon Sep 17 00:00:00 2001
From: Harrison Mutai <harrison.mutai@arm.com>
Date: Fri, 26 Apr 2024 08:55:47 +0000
Subject: [PATCH 4/6] feat(handoff): add TL source files to BL1

Change-Id: Id9843ba0ccfb448cf17e09e0659b743741ae01ac
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
---
 lib/transfer_list/transfer_list.mk | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/transfer_list/transfer_list.mk b/lib/transfer_list/transfer_list.mk
index 42574e85d..3ec4df236 100644
--- a/lib/transfer_list/transfer_list.mk
+++ b/lib/transfer_list/transfer_list.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -15,6 +15,7 @@ TRANSFER_LIST_SOURCES	+=	$(addprefix lib/transfer_list/,	\
 
 BL31_SOURCES	+=	$(TRANSFER_LIST_SOURCES)
 BL2_SOURCES	+=	$(TRANSFER_LIST_SOURCES)
+BL1_SOURCES	+=	$(TRANSFER_LIST_SOURCES)
 
 endif	# TRANSFER_LIST
 

From 9c11ed7e3e5536ad1fcb9190560e0368da9c5ab5 Mon Sep 17 00:00:00 2001
From: Harrison Mutai <harrison.mutai@arm.com>
Date: Fri, 22 Dec 2023 18:42:27 +0000
Subject: [PATCH 5/6] 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>
---
 include/plat/arm/common/arm_def.h  | 13 +++++
 plat/arm/board/fvp/fvp_bl2_setup.c |  5 ++
 plat/arm/board/fvp/platform.mk     |  8 +--
 plat/arm/common/arm_bl1_setup.c    | 94 +++++++++++++++++++++++++++---
 plat/arm/common/arm_bl2_setup.c    | 46 ++++++++++-----
 5 files changed, 140 insertions(+), 26 deletions(-)

diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index c3a88e7cb..ec5f90bf1 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -411,6 +411,8 @@ MEASURED_BOOT
 #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 @@ MEASURED_BOOT
 						(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 @@ MEASURED_BOOT
  */
 #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 @@ MEASURED_BOOT
  */
 #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 58db4e84e..ebdd80d45 100644
--- a/plat/arm/board/fvp/fvp_bl2_setup.c
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -48,6 +48,11 @@ static const arm_gpt_info_t arm_gpt_info = {
 
 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 0860dd1c1..07e69e69a 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -336,7 +336,6 @@ endif
 
 # 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 @@ $(eval FVP_HW_CONFIG	:=	${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(FVP_HW_CONFIG_DTS
 
 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 @@ FDT_SOURCES		+=	$(addprefix plat/arm/board/fvp/fdts/,	\
 					${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 @@ FVP_TOS_FW_CONFIG	:=	${BUILD_PLAT}/fdts/$(notdir $(basename ${ARM_SPMC_MANIFEST_
 $(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 feff6913d..f043f59dd 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 @@ static meminfo_t bl1_tzram_layout;
 /* 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 bl1_plat_arch_setup(void)
  */
 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 @@ void arm_bl1_platform_setup(void)
 		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 @@ void arm_bl1_platform_setup(void)
 	 * 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 @@ void arm_bl1_platform_setup(void)
 		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 @@ unsigned int bl1_plat_get_next_image_id(void)
 {
 	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 85c0a1683..3e7c73a76 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,15 +77,27 @@ static struct transfer_list_header *ns_tl __unused;
 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();
 
+#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;
-
-	config_base = fw_config;
+#endif
 
 	/* Initialise the IO layer and register platform IO devices */
 	plat_arm_io_setup();
@@ -110,13 +127,6 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_
 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 @@ void arm_bl2_plat_arch_setup(void)
 		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 arm_bl2_plat_arch_setup(void)
 
 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 @@ void bl2_plat_arch_setup(void)
 	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)

From f019c8013e9c5efeb85eec7792fe901543a5832c Mon Sep 17 00:00:00 2001
From: Harrison Mutai <harrison.mutai@arm.com>
Date: Tue, 23 Apr 2024 10:31:36 +0000
Subject: [PATCH 6/6] feat(handoff): add support for RESET_TO_BL2

When BL2 is enabled as the entrypoint in the reset vector, none of the
TL initialisation ordinarily performed in BL1 will have been done. This
change ensures that BL2 has a secure TL to pass information onto BL31
through.

Change-Id: I553b0b7aac9390cd6a2d63471b81ddc72cc40a60
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
---
 plat/arm/common/arm_bl2_setup.c  | 11 +++++++++++
 plat/arm/common/arm_bl31_setup.c |  2 +-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 3e7c73a76..877ae8f51 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -127,6 +127,17 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_
 void bl2_plat_preload_setup(void)
 {
 #if TRANSFER_LIST
+/* Assume the secure TL hasn't been initialised if BL2 is running at EL3. */
+#if RESET_TO_BL2
+	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();
+	}
+#endif
+
 	arm_transfer_list_dyn_cfg_init(secure_tl);
 #else
 	arm_bl2_dyn_cfg_init();
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 206f4a5b2..414ac40ca 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -504,7 +504,7 @@ void __init bl31_plat_arch_setup(void)
 
 	arm_bl31_plat_arch_setup();
 
-#if TRANSFER_LIST
+#if TRANSFER_LIST && !RESET_TO_BL2
 	te = transfer_list_find(secure_tl, TL_TAG_FDT);
 	assert(te != NULL);