ARM Platforms: Load HW_CONFIG in BL2

The patch adds the necessary changes to load HW_CONFIG in BL2 for
ARM Platforms :

1. The load address of HW_CONFIG is specified via the `hw_config_addr`
property in TB_FW_CONFIG is loaded by BL1. The `hw_config_max_size`
property defines the maximum size to be expected for the HW_CONFIG.
The `arm_dyn_cfg_helpers.c` and corresponding header implements
utility functions to parse these DT properties defined.
The `arm_dyn_cfg.c` implements wrappers to these helpers to enable
them to be invoked from ARM platform layer.

2. `HW_CONFIG` is added to the `bl2_mem_params_descs[]` array which is
the list of images to be loaded by BL2.

3. The `libfdt` sources are now included when BL2 is built

4. A new helper `populate_next_bl_params_config()` is introduced in
desc_image_load.c to populate the subsequent executable BL images
with the `hw_config` and the corresponding `fw_config` if available.
The `plat_get_next_bl_params()` API for ARM platforms is modified to
invoke this new helper.

5. The implementation of `bl2_early_platform_setup2()` is modified to
consider `arg0` as well in addition to `arg1` passed from BL1.

6. Bump up the BL2 size for Juno to accommodate the inclusion of libfdt.

Change-Id: I80f1554adec41753e0d179a5237364f04fe13a3f
Signed-off-by: Soby Mathew <soby.mathew@arm.com>
diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c
index 4315c1f..415de05 100644
--- a/plat/arm/board/fvp/fvp_bl2_setup.c
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -14,7 +14,7 @@
 
 void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
 {
-	arm_bl2_early_platform_setup((meminfo_t *)arg1);
+	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
 
 	/* Initialize the platform config for future decision making */
 	fvp_config_setup();
diff --git a/plat/arm/board/fvp/fvp_io_storage.c b/plat/arm/board/fvp/fvp_io_storage.c
index f18303f..11c7c3b 100644
--- a/plat/arm/board/fvp/fvp_io_storage.c
+++ b/plat/arm/board/fvp/fvp_io_storage.c
@@ -19,6 +19,7 @@
 #define BL32_IMAGE_NAME			"bl32.bin"
 #define BL33_IMAGE_NAME			"bl33.bin"
 #define TB_FW_CONFIG_NAME		"fvp_tb_fw_config.dtb"
+#define HW_CONFIG_NAME			"hw_config.dtb"
 
 #if TRUSTED_BOARD_BOOT
 #define TRUSTED_BOOT_FW_CERT_NAME	"tb_fw.crt"
@@ -56,6 +57,10 @@
 		.path = TB_FW_CONFIG_NAME,
 		.mode = FOPEN_MODE_RB
 	},
+	[HW_CONFIG_ID] = {
+		.path = HW_CONFIG_NAME,
+		.mode = FOPEN_MODE_RB
+	},
 #if TRUSTED_BOARD_BOOT
 	[TRUSTED_BOOT_FW_CERT_ID] = {
 		.path = TRUSTED_BOOT_FW_CERT_NAME,
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index cac47f7..2e2fdd7 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -110,12 +110,12 @@
  */
 #if TRUSTED_BOARD_BOOT
 #if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
-# define PLAT_ARM_MAX_BL2_SIZE		0x1E000
+# define PLAT_ARM_MAX_BL2_SIZE		0x1F000
 #else
-# define PLAT_ARM_MAX_BL2_SIZE		0x1A000
+# define PLAT_ARM_MAX_BL2_SIZE		0x1B000
 #endif
 #else
-# define PLAT_ARM_MAX_BL2_SIZE		0xC000
+# define PLAT_ARM_MAX_BL2_SIZE		0xD000
 #endif
 
 /*
diff --git a/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c b/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
index 7fd42aa..890f2c9 100644
--- a/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
+++ b/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -54,7 +54,15 @@
 
 	    .next_handoff_image_id = BL33_IMAGE_ID,
     },
-
+	/* Fill HW_CONFIG related information if it exists */
+    {
+	    .image_id = HW_CONFIG_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE),
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
 	/* Fill BL33 related information */
     {
 	    .image_id = BL33_IMAGE_ID,
diff --git a/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
index d3490eb..fef01c9 100644
--- a/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
+++ b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -82,7 +82,15 @@
 	    .next_handoff_image_id = BL33_IMAGE_ID,
 # endif
     },
-
+	/* Fill HW_CONFIG related information */
+    {
+	    .image_id = HW_CONFIG_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE),
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
 # ifdef BL32_BASE
 	/* Fill BL32 related information */
     {
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 14da1fd..9a51012 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -181,7 +181,7 @@
  * in x0. This memory layout is sitting at the base of the free trusted SRAM.
  * Copy it to a safe location before its reclaimed by later BL2 functionality.
  ******************************************************************************/
-void arm_bl2_early_platform_setup(meminfo_t *mem_layout)
+void arm_bl2_early_platform_setup(uintptr_t tb_fw_config, meminfo_t *mem_layout)
 {
 	/* Initialize the console to provide early debug support */
 	console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ,
@@ -192,11 +192,17 @@
 
 	/* Initialise the IO layer and register platform IO devices */
 	plat_arm_io_setup();
+
+#if LOAD_IMAGE_V2
+	if (tb_fw_config != 0)
+		arm_bl2_set_tb_cfg_addr((void *)tb_fw_config);
+#endif
 }
 
 void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
 {
-	arm_bl2_early_platform_setup((meminfo_t *)arg1);
+	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
+
 	generic_delay_timer_init();
 }
 
@@ -205,6 +211,10 @@
  */
 void arm_bl2_platform_setup(void)
 {
+#if LOAD_IMAGE_V2
+	arm_bl2_dyn_cfg_init();
+#endif
+
 	/* Initialize the secure environment */
 	plat_arm_security_setup();
 
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 903b1e1..b3462ab 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -152,6 +152,13 @@
 				plat/arm/common/arm_bl2_setup.c			\
 				plat/arm/common/arm_io_storage.c
 
+# Add `libfdt` and Arm common helpers required for Dynamic Config
+include lib/libfdt/libfdt.mk
+BL2_SOURCES		+=	plat/arm/common/arm_dyn_cfg.c		\
+				plat/arm/common/arm_dyn_cfg_helpers.c	\
+				common/fdt_wrappers.c			\
+				${LIBFDT_SRCS}
+
 ifeq (${BL2_AT_EL3},1)
 BL2_SOURCES		+=	plat/arm/common/arm_bl2_el3_setup.c
 endif
diff --git a/plat/arm/common/arm_dyn_cfg.c b/plat/arm/common/arm_dyn_cfg.c
index 4325764..a6fafb8 100644
--- a/plat/arm/common/arm_dyn_cfg.c
+++ b/plat/arm/common/arm_dyn_cfg.c
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <arm_dyn_cfg_helpers.h>
 #include <assert.h>
 #include <debug.h>
 #include <desc_image_load.h>
@@ -14,6 +15,9 @@
 
 #if LOAD_IMAGE_V2
 
+/* Variable to store the address to TB_FW_CONFIG passed from BL1 */
+static void *tb_fw_cfg_dtb;
+
 /*
  * Helper function to load TB_FW_CONFIG and populate the load information to
  * arg0 of BL2 entrypoint info.
@@ -51,4 +55,54 @@
 			(void *) config_base);
 }
 
+/*
+ * BL2 utility function to set the address of TB_FW_CONFIG passed from BL1.
+ */
+void arm_bl2_set_tb_cfg_addr(void *dtb)
+{
+	assert(dtb);
+	tb_fw_cfg_dtb = dtb;
+}
+
+/*
+ * BL2 utility function to initialize dynamic configuration specified by
+ * TB_FW_CONFIG. Return early if TB_FW_CONFIG is not found or HW_CONFIG is
+ * not specified in TB_FW_CONFIG.
+ */
+void arm_bl2_dyn_cfg_init(void)
+{
+	int err = 0;
+	int tb_fw_node;
+	bl_mem_params_node_t *hw_cfg_mem_params = NULL;
+
+	if (tb_fw_cfg_dtb == NULL) {
+		VERBOSE("No TB_FW_CONFIG specified\n");
+		return;
+	}
+
+	err = arm_dyn_tb_fw_cfg_init((void *)tb_fw_cfg_dtb, &tb_fw_node);
+	if (err < 0) {
+		ERROR("Invalid TB_FW_CONFIG passed from BL1\n");
+		panic();
+	}
+
+	/* Get the hw_config load address and size from TB_FW_CONFIG */
+	hw_cfg_mem_params = get_bl_mem_params_node(HW_CONFIG_ID);
+	if (hw_cfg_mem_params == NULL) {
+		VERBOSE("Couldn't find HW_CONFIG in bl_mem_params_node\n");
+		return;
+	}
+
+	err = arm_dyn_get_hwconfig_info((void *)tb_fw_cfg_dtb, tb_fw_node,
+		(uint64_t *) &hw_cfg_mem_params->image_info.image_base,
+		&hw_cfg_mem_params->image_info.image_max_size);
+	if (err < 0) {
+		VERBOSE("Couldn't find HW_CONFIG load info in TB_FW_CONFIG\n");
+		return;
+	}
+
+	/* Remove the IMAGE_ATTRIB_SKIP_LOADING attribute from HW_CONFIG node */
+	hw_cfg_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
+}
+
 #endif /* LOAD_IMAGE_V2 */
diff --git a/plat/arm/common/arm_dyn_cfg_helpers.c b/plat/arm/common/arm_dyn_cfg_helpers.c
new file mode 100644
index 0000000..afe4453
--- /dev/null
+++ b/plat/arm/common/arm_dyn_cfg_helpers.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <desc_image_load.h>
+#include <fdt_wrappers.h>
+#include <libfdt.h>
+
+/*******************************************************************************
+ * Helper to read the `hw_config` property in config DTB. This function
+ * expects the following properties to be present in the config DTB.
+ *	name : hw_config_addr		size : 2 cells
+ *	name : hw_config_max_size	size : 1 cell
+ *
+ * Arguments:
+ *	void *dtb		 - pointer to the TB_FW_CONFIG in memory
+ *	int node		 - The node offset to appropriate node in the
+ *					 DTB.
+ *	uint64_t *hw_config_addr - Returns the `hw_config` load address if read
+ *					 is successful.
+ *	uint32_t *hw_config_size - Returns the `hw_config` size if read is
+ *					 successful.
+ *
+ * Returns 0 on success and -1 on error.
+ ******************************************************************************/
+int arm_dyn_get_hwconfig_info(void *dtb, int node,
+		uint64_t *hw_config_addr, uint32_t *hw_config_size)
+{
+	int err;
+
+	assert(dtb);
+	assert(hw_config_addr);
+	assert(hw_config_size);
+
+	/* Check if the pointer to DT is correct */
+	assert(fdt_check_header(dtb) == 0);
+
+	/* Assert the node offset point to "arm,tb_fw" compatible property */
+	assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"));
+
+	err = fdtw_read_cells(dtb, node, "hw_config_addr", 2,
+				(void *) hw_config_addr);
+	if (err < 0) {
+		WARN("Read cell failed for hw_config_addr\n");
+		return -1;
+	}
+
+	err = fdtw_read_cells(dtb, node, "hw_config_max_size", 1,
+				(void *) hw_config_size);
+	if (err < 0) {
+		WARN("Read cell failed for hw_config_max_size\n");
+		return -1;
+	}
+
+	VERBOSE("Dyn cfg: Read hw_config address from TB_FW_CONFIG 0x%p %p\n",
+				hw_config_addr, hw_config_size);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Validate the tb_fw_config is a valid DTB file and returns the node offset
+ * to "arm,tb_fw" property.
+ * Arguments:
+ *	void *dtb - pointer to the TB_FW_CONFIG in memory
+ *	int *node - Returns the node offset to "arm,tb_fw" property if found.
+ *
+ * Returns 0 on success and -1 on error.
+ ******************************************************************************/
+int arm_dyn_tb_fw_cfg_init(void *dtb, int *node)
+{
+	assert(dtb);
+	assert(node);
+
+	/* Check if the pointer to DT is correct */
+	if (fdt_check_header(dtb) != 0) {
+		WARN("Invalid DTB file passed as TB_FW_CONFIG\n");
+		return -1;
+	}
+
+	/* Assert the node offset point to "arm,tb_fw" compatible property */
+	*node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw");
+	if (*node < 0) {
+		WARN("The compatible property `arm,tb_fw` not found in the config\n");
+		return -1;
+	}
+
+	VERBOSE("Dyn cfg: Found \"arm,tb_fw\" in the config\n");
+	return 0;
+}
diff --git a/plat/arm/common/arm_image_load.c b/plat/arm/common/arm_image_load.c
index 03e4b4f..916fa8d 100644
--- a/plat/arm/common/arm_image_load.c
+++ b/plat/arm/common/arm_image_load.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,7 @@
 #include <arm_def.h>
 #include <bl_common.h>
 #include <desc_image_load.h>
+#include <plat_arm.h>
 #include <platform.h>
 
 
@@ -37,5 +38,8 @@
  ******************************************************************************/
 bl_params_t *plat_get_next_bl_params(void)
 {
-	return get_next_bl_params_from_mem_params_desc();
+	bl_params_t *next_bl_params = get_next_bl_params_from_mem_params_desc();
+
+	populate_next_bl_params_config(next_bl_params);
+	return next_bl_params;
 }
diff --git a/plat/arm/common/arm_io_storage.c b/plat/arm/common/arm_io_storage.c
index 6d8f209..5cabc54 100644
--- a/plat/arm/common/arm_io_storage.c
+++ b/plat/arm/common/arm_io_storage.c
@@ -57,6 +57,10 @@
 	.uuid = UUID_TB_FW_CONFIG,
 };
 
+static const io_uuid_spec_t hw_config_uuid_spec = {
+	.uuid = UUID_HW_CONFIG,
+};
+
 #if TRUSTED_BOARD_BOOT
 static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
 	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
@@ -156,6 +160,11 @@
 		(uintptr_t)&tb_fw_config_uuid_spec,
 		open_fip
 	},
+	[HW_CONFIG_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&hw_config_uuid_spec,
+		open_fip
+	},
 #if TRUSTED_BOARD_BOOT
 	[TRUSTED_BOOT_FW_CERT_ID] = {
 		&fip_dev_handle,