feat(qemu): support s-el2 spmc

Supports S-EL2 SPMC + S-EL1 SP on qemu. S-EL1 SPs packaged in .pkg files
are added to the FIP as blob with an UUID. BL2 parses TB_FW_CONFIG to
know which SP blobs to load into memory.

Co-developed-by: Olivier Deprez <olivier.deprez@arm.com>
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Change-Id: I4b61c4c048f31540d4f1ef9e05f0b12deb341e06
diff --git a/plat/qemu/common/qemu_io_storage.c b/plat/qemu/common/qemu_io_storage.c
index e2d4932..4c61b14 100644
--- a/plat/qemu/common/qemu_io_storage.c
+++ b/plat/qemu/common/qemu_io_storage.c
@@ -11,6 +11,8 @@
 
 #include <common/bl_common.h>
 #include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/uuid.h>
 #include <drivers/io/io_driver.h>
 #include <drivers/io/io_encrypted.h>
 #include <drivers/io/io_fip.h>
@@ -20,10 +22,13 @@
 #include <lib/semihosting.h>
 #include <tools_share/firmware_image_package.h>
 
+#include "qemu_private.h"
+
 /* Semihosting filenames */
 #define BL2_IMAGE_NAME			"bl2.bin"
 #define BL31_IMAGE_NAME			"bl31.bin"
 #define BL32_IMAGE_NAME			"bl32.bin"
+#define TB_FW_CONFIG_NAME		"tb_fw_config.dtb"
 #define TOS_FW_CONFIG_NAME		"tos_fw_config.dtb"
 #define BL32_EXTRA1_IMAGE_NAME		"bl32_extra1.bin"
 #define BL32_EXTRA2_IMAGE_NAME		"bl32_extra2.bin"
@@ -79,6 +84,10 @@
 	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
 };
 
+static const io_uuid_spec_t tb_fw_config_uuid_spec = {
+	.uuid = UUID_TB_FW_CONFIG,
+};
+
 static const io_uuid_spec_t tos_fw_config_uuid_spec = {
 	.uuid = UUID_TOS_FW_CONFIG,
 };
@@ -142,6 +151,10 @@
 		.path = BL32_EXTRA2_IMAGE_NAME,
 		.mode = FOPEN_MODE_RB
 	},
+	[TB_FW_CONFIG_ID] = {
+		.path = TB_FW_CONFIG_NAME,
+		.mode = FOPEN_MODE_RB
+	},
 	[TOS_FW_CONFIG_ID] = {
 		.path = TOS_FW_CONFIG_NAME,
 		.mode = FOPEN_MODE_RB
@@ -261,6 +274,11 @@
 		open_fip
 	},
 #endif
+	[TB_FW_CONFIG_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tb_fw_config_uuid_spec,
+		open_fip
+	},
 	[TOS_FW_CONFIG_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&tos_fw_config_uuid_spec,
@@ -315,6 +333,80 @@
 #endif /* TRUSTED_BOARD_BOOT */
 };
 
+#if defined(SPD_spmd)
+static struct sp_pkg {
+	struct plat_io_policy policy;
+	io_file_spec_t sh_file_spec;
+	uint8_t uuid[UUID_BYTES_LENGTH];
+	char path[80];
+} sp_pkgs[MAX_SP_IDS];
+static unsigned int sp_pkg_count;
+
+int qemu_io_register_sp_pkg(const char *name, const char *uuid,
+			    uintptr_t load_addr)
+{
+	struct sp_pkg *pkg;
+	bl_mem_params_node_t *mem_params;
+
+	if (sp_pkg_count == MAX_SP_IDS) {
+		INFO("Reached Max number of SPs\n");
+		return -1;
+	}
+	mem_params = get_bl_mem_params_node(SP_PKG1_ID + sp_pkg_count);
+	if (mem_params == NULL) {
+		ERROR("Can't find SP_PKG ID %u (SP_PKG%u_ID)\n",
+		      SP_PKG1_ID + sp_pkg_count, sp_pkg_count);
+		return -1;
+	}
+	pkg = sp_pkgs + sp_pkg_count;
+
+	if (read_uuid(pkg->uuid, (char *)uuid)) {
+		return -1;
+	}
+
+	strlcpy(pkg->path, name, sizeof(pkg->path));
+	strlcat(pkg->path, ".pkg", sizeof(pkg->path));
+
+	pkg->policy.dev_handle = &fip_dev_handle;
+	pkg->policy.image_spec = (uintptr_t)&pkg->uuid;
+	pkg->policy.check = open_fip;
+	pkg->sh_file_spec.path = pkg->path;
+	pkg->sh_file_spec.mode = FOPEN_MODE_RB;
+
+	mem_params->image_info.image_base = load_addr;
+	mem_params->image_info.image_max_size = SZ_4M;
+	mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
+
+	sp_pkg_count++;
+
+	return 0;
+}
+#endif /*SPD_spmd*/
+
+static const io_file_spec_t *get_io_file_spec(unsigned int image_id)
+{
+#if defined(SPD_spmd)
+	if (image_id >= SP_PKG1_ID && image_id <= SP_PKG8_ID) {
+		return &sp_pkgs[image_id - SP_PKG1_ID].sh_file_spec;
+	}
+#endif
+
+	assert(image_id < ARRAY_SIZE(sh_file_spec));
+	return &sh_file_spec[image_id];
+}
+
+static const struct plat_io_policy *get_io_policy(unsigned int image_id)
+{
+#if defined(SPD_spmd)
+	if (image_id >= SP_PKG1_ID && image_id <= SP_PKG8_ID) {
+		return &sp_pkgs[image_id - SP_PKG1_ID].policy;
+	}
+#endif
+
+	assert(image_id < ARRAY_SIZE(policies));
+	return &policies[image_id];
+}
+
 static int open_fip(const uintptr_t spec)
 {
 	int result;
@@ -427,11 +519,13 @@
 static int get_alt_image_source(unsigned int image_id, uintptr_t *dev_handle,
 				  uintptr_t *image_spec)
 {
-	int result = open_semihosting((const uintptr_t)&sh_file_spec[image_id]);
+	const io_file_spec_t *spec = get_io_file_spec(image_id);
+	int result;
 
+	result = open_semihosting((const uintptr_t)spec);
 	if (result == 0) {
 		*dev_handle = sh_dev_handle;
-		*image_spec = (uintptr_t)&sh_file_spec[image_id];
+		*image_spec = (uintptr_t)spec;
 	}
 
 	return result;
@@ -444,12 +538,9 @@
 int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
 			  uintptr_t *image_spec)
 {
+	const struct plat_io_policy *policy = get_io_policy(image_id);
 	int result;
-	const struct plat_io_policy *policy;
 
-	assert(image_id < ARRAY_SIZE(policies));
-
-	policy = &policies[image_id];
 	result = policy->check(policy->image_spec);
 	if (result == 0) {
 		*image_spec = policy->image_spec;