feat(qemu): load and run RMM image

When RME is enabled, jump to the RMM image before BL33. When using
semihosting rather than FIP, the image called "rmm.bin" is loaded from
the runtime directory.

Change-Id: I15863410b1e505aa502276b339b22a2ddcb0b745
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
diff --git a/plat/qemu/common/qemu_bl2_mem_params_desc.c b/plat/qemu/common/qemu_bl2_mem_params_desc.c
index bb1797d..c444be4 100644
--- a/plat/qemu/common/qemu_bl2_mem_params_desc.c
+++ b/plat/qemu/common/qemu_bl2_mem_params_desc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -67,11 +67,28 @@
 
 # ifdef QEMU_LOAD_BL32
 	  .next_handoff_image_id = BL32_IMAGE_ID,
+# elif ENABLE_RME
+	  .next_handoff_image_id = RMM_IMAGE_ID,
 # else
 	  .next_handoff_image_id = BL33_IMAGE_ID,
 # endif
 	},
 #endif /* __aarch64__ */
+
+#if ENABLE_RME
+	/* Fill RMM related information */
+	{ .image_id = RMM_IMAGE_ID,
+	  SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		VERSION_2, entry_point_info_t, EP_REALM | EXECUTABLE),
+	  .ep_info.pc = RMM_BASE,
+	  SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		VERSION_2, image_info_t, 0),
+	  .image_info.image_base = RMM_BASE,
+	  .image_info.image_max_size = RMM_LIMIT - RMM_BASE,
+	  .next_handoff_image_id = BL33_IMAGE_ID,
+	},
+#endif /* ENABLE_RME */
+
 # ifdef QEMU_LOAD_BL32
 
 #ifdef __aarch64__
@@ -95,7 +112,11 @@
 	  .image_info.image_base = BL32_BASE,
 	  .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
 
+#if ENABLE_RME
+	  .next_handoff_image_id = RMM_IMAGE_ID,
+#else
 	  .next_handoff_image_id = BL33_IMAGE_ID,
+#endif
 	},
 
 	/*
diff --git a/plat/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
index 228aff5..894b842 100644
--- a/plat/qemu/common/qemu_bl31_setup.c
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -41,6 +41,9 @@
  */
 static entry_point_info_t bl32_image_ep_info;
 static entry_point_info_t bl33_image_ep_info;
+#if ENABLE_RME
+static entry_point_info_t rmm_image_ep_info;
+#endif
 
 /*******************************************************************************
  * Perform any BL3-1 early platform setup.  Here is an opportunity to copy
@@ -73,13 +76,18 @@
 	bl_params_node_t *bl_params = params_from_bl2->head;
 
 	/*
-	 * Copy BL33 and BL32 (if present), entry point information.
+	 * Copy BL33, BL32 and RMM (if present), entry point information.
 	 * They are stored in Secure RAM, in BL2's address space.
 	 */
 	while (bl_params) {
 		if (bl_params->image_id == BL32_IMAGE_ID)
 			bl32_image_ep_info = *bl_params->ep_info;
 
+#if ENABLE_RME
+		if (bl_params->image_id == RMM_IMAGE_ID)
+			rmm_image_ep_info = *bl_params->ep_info;
+#endif
+
 		if (bl_params->image_id == BL33_IMAGE_ID)
 			bl33_image_ep_info = *bl_params->ep_info;
 
@@ -88,6 +96,10 @@
 
 	if (!bl33_image_ep_info.pc)
 		panic();
+#if ENABLE_RME
+	if (!rmm_image_ep_info.pc)
+		panic();
+#endif
 }
 
 void bl31_plat_arch_setup(void)
@@ -155,8 +167,18 @@
 	entry_point_info_t *next_image_info;
 
 	assert(sec_state_is_valid(type));
-	next_image_info = (type == NON_SECURE)
-			? &bl33_image_ep_info : &bl32_image_ep_info;
+	if (type == NON_SECURE) {
+		next_image_info = &bl33_image_ep_info;
+	}
+#if ENABLE_RME
+	else if (type == REALM) {
+		next_image_info = &rmm_image_ep_info;
+	}
+#endif
+	else {
+		next_image_info =  &bl32_image_ep_info;
+	}
+
 	/*
 	 * None of the images on the ARM development platforms can have 0x0
 	 * as the entrypoint
diff --git a/plat/qemu/common/qemu_common.c b/plat/qemu/common/qemu_common.c
index 860de71..f93cdc5 100644
--- a/plat/qemu/common/qemu_common.c
+++ b/plat/qemu/common/qemu_common.c
@@ -11,6 +11,9 @@
 #include <common/bl_common.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <services/el3_spmc_ffa_memory.h>
+#if ENABLE_RME
+#include <services/rmm_core_manifest.h>
+#endif
 
 #include <plat/common/platform.h>
 #include "qemu_private.h"
@@ -190,3 +193,76 @@
 	return -1;
 }
 #endif /*defined(SPD_spmd) && (SPMC_AT_EL3 == 0)*/
+
+#if ENABLE_RME
+/*
+ * Get a pointer to the RMM-EL3 Shared buffer and return it
+ * through the pointer passed as parameter.
+ *
+ * This function returns the size of the shared buffer.
+ */
+size_t plat_rmmd_get_el3_rmm_shared_mem(uintptr_t *shared)
+{
+	*shared = (uintptr_t)RMM_SHARED_BASE;
+
+	return (size_t)RMM_SHARED_SIZE;
+}
+
+int plat_rmmd_load_manifest(struct rmm_manifest *manifest)
+{
+	uint64_t checksum;
+	uintptr_t base;
+	uint64_t size;
+	struct ns_dram_bank *bank_ptr;
+
+	assert(manifest != NULL);
+
+	manifest->version = RMMD_MANIFEST_VERSION;
+	manifest->padding = 0U; /* RES0 */
+	manifest->plat_data = (uintptr_t)NULL;
+	manifest->plat_dram.num_banks = 1;
+
+	/*
+	 * Array ns_dram_banks[] follows ns_dram_info structure:
+	 *
+	 * +-----------------------------------+
+	 * |  offset  |   field   |  comment   |
+	 * +----------+-----------+------------+
+	 * |    0     |  version  | 0x00000002 |
+	 * +----------+-----------+------------+
+	 * |    4     |  padding  | 0x00000000 |
+	 * +----------+-----------+------------+
+	 * |    8     | plat_data |    NULL    |
+	 * +----------+-----------+------------+
+	 * |    16    | num_banks |            |
+	 * +----------+-----------+            |
+	 * |    24    |   banks   | plat_dram  |
+	 * +----------+-----------+            |
+	 * |    32    | checksum  |            |
+	 * +----------+-----------+------------+
+	 * |    40    |  base 0   |            |
+	 * +----------+-----------+   bank[0]  |
+	 * |    48    |  size 0   |            |
+	 * +----------+-----------+------------+
+	 */
+	bank_ptr = (struct ns_dram_bank *)
+			((uintptr_t)&manifest->plat_dram.checksum +
+			sizeof(manifest->plat_dram.checksum));
+
+	manifest->plat_dram.banks = bank_ptr;
+
+	/* Calculate checksum of plat_dram structure */
+	checksum = 1 + (uint64_t)bank_ptr;
+
+	base = NS_DRAM0_BASE;
+	size = NS_DRAM0_SIZE;
+	bank_ptr[0].base = base;
+	bank_ptr[0].size = size;
+	checksum += base + size;
+
+	/* Checksum must be 0 */
+	manifest->plat_dram.checksum = ~checksum + 1UL;
+
+	return 0;
+}
+#endif  /* ENABLE_RME */
diff --git a/plat/qemu/common/qemu_io_storage.c b/plat/qemu/common/qemu_io_storage.c
index 4c61b14..59bba86 100644
--- a/plat/qemu/common/qemu_io_storage.c
+++ b/plat/qemu/common/qemu_io_storage.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
  */
@@ -33,6 +33,7 @@
 #define BL32_EXTRA1_IMAGE_NAME		"bl32_extra1.bin"
 #define BL32_EXTRA2_IMAGE_NAME		"bl32_extra2.bin"
 #define BL33_IMAGE_NAME			"bl33.bin"
+#define RMM_IMAGE_NAME			"rmm.bin"
 
 #if TRUSTED_BOARD_BOOT
 #define TRUSTED_BOOT_FW_CERT_NAME	"tb_fw.crt"
@@ -96,6 +97,10 @@
 	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
 };
 
+static const io_uuid_spec_t rmm_uuid_spec = {
+	.uuid = UUID_REALM_MONITOR_MGMT_FIRMWARE,
+};
+
 #if TRUSTED_BOARD_BOOT
 static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
 	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
@@ -163,6 +168,10 @@
 		.path = BL33_IMAGE_NAME,
 		.mode = FOPEN_MODE_RB
 	},
+	[RMM_IMAGE_ID] = {
+		.path = RMM_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
 #if TRUSTED_BOARD_BOOT
 	[TRUSTED_BOOT_FW_CERT_ID] = {
 		.path = TRUSTED_BOOT_FW_CERT_NAME,
@@ -289,6 +298,12 @@
 		(uintptr_t)&bl33_uuid_spec,
 		open_fip
 	},
+	[RMM_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&rmm_uuid_spec,
+		open_fip
+	},
+
 #if TRUSTED_BOARD_BOOT
 	[TRUSTED_BOOT_FW_CERT_ID] = {
 		&fip_dev_handle,