feat(qemu): enable transfer list to BL31/32

Enable handoff to BL31 and BL32 using transfer list.
Encode TL_TAG_OPTEE_PAGABLE_PART as transfer entry.
Fallback to default handoff args when transfer list is disabled or
fails to archieve args from transfer entries.
Refactor handoff from BL2 to BL33.
Minor fixes of comment style.

Change-Id: I55d92ca7f5c4727bacc9725a7216c0ac70d16aec
Signed-off-by: Raymond Mao <raymond.mao@linaro.org>
diff --git a/plat/qemu/common/qemu_bl2_setup.c b/plat/qemu/common/qemu_bl2_setup.c
index 8c7518d..cd83a98 100644
--- a/plat/qemu/common/qemu_bl2_setup.c
+++ b/plat/qemu/common/qemu_bl2_setup.c
@@ -19,9 +19,7 @@
 #include <common/fdt_fixup.h>
 #include <common/fdt_wrappers.h>
 #include <lib/optee_utils.h>
-#if TRANSFER_LIST
 #include <lib/transfer_list.h>
-#endif
 #include <lib/utils.h>
 #include <plat/common/platform.h>
 #if ENABLE_RME
@@ -55,9 +53,7 @@
 
 /* Data structure which holds the extents of the trusted SRAM for BL2 */
 static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
-#if TRANSFER_LIST
 static struct transfer_list_header *bl2_tl;
-#endif
 
 void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
 			       u_register_t arg2, u_register_t arg3)
@@ -122,7 +118,7 @@
 		ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, ret);
 
 #if TRANSFER_LIST
-	// create a TE
+	/* create a TE */
 	te = transfer_list_add(bl2_tl, TL_TAG_FDT, fdt_totalsize(fdt), fdt);
 	if (!te) {
 		ERROR("Failed to add FDT entry to Transfer List\n");
@@ -321,6 +317,23 @@
 }
 #endif /*defined(SPD_spmd) && SPMD_SPM_AT_SEL2*/
 
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE) || defined(SPMC_OPTEE)
+static int handoff_pageable_part(uint64_t pagable_part)
+{
+#if TRANSFER_LIST
+	struct transfer_list_entry *te;
+
+	te = transfer_list_add(bl2_tl, TL_TAG_OPTEE_PAGABLE_PART,
+			       sizeof(pagable_part), &pagable_part);
+	if (!te) {
+		INFO("Cannot add TE for pageable part\n");
+		return -1;
+	}
+#endif
+	return 0;
+}
+#endif
+
 static int qemu_bl2_handle_post_image_load(unsigned int image_id)
 {
 	int err = 0;
@@ -334,12 +347,24 @@
 #endif
 #if TRANSFER_LIST
 	struct transfer_list_header *ns_tl = NULL;
-	struct transfer_list_entry *te = NULL;
 #endif
 
 	assert(bl_mem_params);
 
 	switch (image_id) {
+#if TRANSFER_LIST
+	case BL31_IMAGE_ID:
+		/*
+		 * arg0 is a bl_params_t reserved for bl31_early_platform_setup2
+		 * we just need arg1 and arg3 for BL31 to update th TL from S
+		 * to NS memory before it exits
+		 */
+		bl_mem_params->ep_info.args.arg1 =
+			TRANSFER_LIST_SIGNATURE |
+			REGISTER_CONVENTION_VERSION_MASK;
+		bl_mem_params->ep_info.args.arg3 = (uintptr_t)bl2_tl;
+		break;
+#endif
 	case BL32_IMAGE_ID:
 #if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE) || defined(SPMC_OPTEE)
 		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
@@ -354,8 +379,21 @@
 		if (err != 0) {
 			WARN("OPTEE header parse error.\n");
 		}
+
+		/* add TL_TAG_OPTEE_PAGABLE_PART entry to the TL */
+		if (handoff_pageable_part(bl_mem_params->ep_info.args.arg1)) {
+			return -1;
+		}
 #endif
 
+		INFO("Handoff to BL32\n");
+		bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl32_entry();
+		if (TRANSFER_LIST &&
+			transfer_list_set_handoff_args(bl2_tl,
+				&bl_mem_params->ep_info))
+			break;
+
+		INFO("Using default arguments\n");
 #if defined(SPMC_OPTEE)
 		/*
 		 * Explicit zeroes to unused registers since they may have
@@ -379,7 +417,6 @@
 		bl_mem_params->ep_info.args.arg2 = ARM_PRELOADED_DTB_BASE;
 		bl_mem_params->ep_info.args.arg3 = 0;
 #endif
-		bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl32_entry();
 		break;
 
 	case BL33_IMAGE_ID:
@@ -406,7 +443,7 @@
 		bl_mem_params->ep_info.args.arg3 = 0U;
 #elif TRANSFER_LIST
 		if (bl2_tl) {
-			// relocate the tl to pre-allocate NS memory
+			/* relocate the tl to pre-allocate NS memory */
 			ns_tl = transfer_list_relocate(bl2_tl,
 					(void *)(uintptr_t)FW_NS_HANDOFF_BASE,
 					bl2_tl->max_size);
@@ -415,37 +452,18 @@
 					(unsigned long)FW_NS_HANDOFF_BASE);
 				return -1;
 			}
-			NOTICE("Transfer list handoff to BL33\n");
-			transfer_list_dump(ns_tl);
-
-			te = transfer_list_find(ns_tl, TL_TAG_FDT);
-
-			bl_mem_params->ep_info.args.arg1 =
-				TRANSFER_LIST_SIGNATURE |
-				REGISTER_CONVENTION_VERSION_MASK;
-			bl_mem_params->ep_info.args.arg3 = (uintptr_t)ns_tl;
+		}
 
-			if (GET_RW(bl_mem_params->ep_info.spsr) == MODE_RW_32) {
-				// aarch32
-				bl_mem_params->ep_info.args.arg0 = 0;
-				bl_mem_params->ep_info.args.arg2 = te ?
-					(uintptr_t)transfer_list_entry_data(te)
-					: 0;
-			} else {
-				// aarch64
-				bl_mem_params->ep_info.args.arg0 = te ?
-					(uintptr_t)transfer_list_entry_data(te)
-					: 0;
-				bl_mem_params->ep_info.args.arg2 = 0;
-			}
-		} else {
-			// Legacy handoff
+		INFO("Handoff to BL33\n");
+		if (!transfer_list_set_handoff_args(ns_tl,
+						    &bl_mem_params->ep_info)) {
+			INFO("Invalid TL, fallback to default arguments\n");
 			bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
 		}
 #else
 		/* BL33 expects to receive the primary CPU MPID (through r0) */
 		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
-#endif // ARM_LINUX_KERNEL_AS_BL33
+#endif /* ARM_LINUX_KERNEL_AS_BL33 */
 
 		break;
 #ifdef SPD_spmd
diff --git a/plat/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
index 894b842..eb88b12 100644
--- a/plat/qemu/common/qemu_bl31_setup.c
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -9,6 +9,7 @@
 #include <common/bl_common.h>
 #include <drivers/arm/pl061_gpio.h>
 #include <lib/gpt_rme/gpt_rme.h>
+#include <lib/transfer_list.h>
 #include <plat/common/platform.h>
 
 #include "qemu_private.h"
@@ -44,6 +45,7 @@
 #if ENABLE_RME
 static entry_point_info_t rmm_image_ep_info;
 #endif
+static struct transfer_list_header *bl31_tl;
 
 /*******************************************************************************
  * Perform any BL3-1 early platform setup.  Here is an opportunity to copy
@@ -100,6 +102,12 @@
 	if (!rmm_image_ep_info.pc)
 		panic();
 #endif
+
+	if (TRANSFER_LIST && arg1 == (TRANSFER_LIST_SIGNATURE |
+				      REGISTER_CONVENTION_VERSION_MASK) &&
+	    transfer_list_check_header((void *)arg3) != TL_OPS_NON) {
+		bl31_tl = (void *)arg3; /* saved TL address from BL2 */
+	}
 }
 
 void bl31_plat_arch_setup(void)
@@ -188,3 +196,18 @@
 	else
 		return NULL;
 }
+
+void bl31_plat_runtime_setup(void)
+{
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
+
+#if TRANSFER_LIST
+	if (bl31_tl) {
+		/*
+		 * update the TL from S to NS memory before jump to BL33
+		 * to reflect all changes in TL done by BL32
+		 */
+		memcpy((void *)FW_NS_HANDOFF_BASE, bl31_tl, bl31_tl->max_size);
+	}
+#endif
+}