xref: /rk3399_ARM-atf/plat/common/plat_spmd_manifest.c (revision 662af36d9ca38eec53eed8613b916d12f8442e3e)
10cb64d01SAchin Gupta /*
20cb64d01SAchin Gupta  * Copyright (c) 2020, Arm Limited. All rights reserved.
30cb64d01SAchin Gupta  *
40cb64d01SAchin Gupta  * SPDX-License-Identifier: BSD-3-Clause
50cb64d01SAchin Gupta  */
60cb64d01SAchin Gupta 
70cb64d01SAchin Gupta #include <assert.h>
852696946SOlivier Deprez #include <errno.h>
90cb64d01SAchin Gupta #include <string.h>
100cb64d01SAchin Gupta #include <libfdt.h>
110cb64d01SAchin Gupta 
120cb64d01SAchin Gupta #include <common/debug.h>
130cb64d01SAchin Gupta #include <common/fdt_wrappers.h>
1423d5ba86SOlivier Deprez #include <lib/xlat_tables/xlat_tables_v2.h>
150cb64d01SAchin Gupta #include <platform_def.h>
160cb64d01SAchin Gupta #include <services/spm_core_manifest.h>
170cb64d01SAchin Gupta 
1852696946SOlivier Deprez #define ATTRIBUTE_ROOT_NODE_STR "attribute"
1952696946SOlivier Deprez 
200cb64d01SAchin Gupta /*******************************************************************************
2152696946SOlivier Deprez  * SPMC attribute node parser
220cb64d01SAchin Gupta  ******************************************************************************/
2352696946SOlivier Deprez static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
240cb64d01SAchin Gupta 				    const void *fdt,
250cb64d01SAchin Gupta 				    int node)
260cb64d01SAchin Gupta {
27ff4e6c35SAndre Przywara 	uint32_t val32;
2852696946SOlivier Deprez 	int rc;
290cb64d01SAchin Gupta 
3052696946SOlivier Deprez 	assert((attr != NULL) && (fdt != NULL));
310cb64d01SAchin Gupta 
32ff4e6c35SAndre Przywara 	rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
3352696946SOlivier Deprez 	if (rc != 0) {
34*662af36dSJ-Alves 		ERROR("Missing FFA %s version in SPM Core manifest.\n",
3552696946SOlivier Deprez 			"major");
3652696946SOlivier Deprez 		return rc;
370cb64d01SAchin Gupta 	}
380cb64d01SAchin Gupta 
39ff4e6c35SAndre Przywara 	rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
4052696946SOlivier Deprez 	if (rc != 0) {
41*662af36dSJ-Alves 		ERROR("Missing FFA %s version in SPM Core manifest.\n",
4252696946SOlivier Deprez 			"minor");
4352696946SOlivier Deprez 		return rc;
440cb64d01SAchin Gupta 	}
450cb64d01SAchin Gupta 
46ff4e6c35SAndre Przywara 	rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
4752696946SOlivier Deprez 	if (rc != 0) {
48ac03ac5eSMax Shvetsov 		ERROR("Missing SPMC ID in manifest.\n");
4952696946SOlivier Deprez 		return rc;
50ac03ac5eSMax Shvetsov 	}
5152696946SOlivier Deprez 
5252696946SOlivier Deprez 	attr->spmc_id = val32 & 0xffff;
53ac03ac5eSMax Shvetsov 
54ff4e6c35SAndre Przywara 	rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
5552696946SOlivier Deprez 	if (rc != 0) {
5652696946SOlivier Deprez 		NOTICE("%s not specified in SPM Core manifest.\n",
5752696946SOlivier Deprez 			"Execution state");
5852696946SOlivier Deprez 	}
590cb64d01SAchin Gupta 
60ff4e6c35SAndre Przywara 	rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
6152696946SOlivier Deprez 	if (rc != 0) {
6252696946SOlivier Deprez 		NOTICE("%s not specified in SPM Core manifest.\n",
6352696946SOlivier Deprez 			"Binary size");
6452696946SOlivier Deprez 	}
650cb64d01SAchin Gupta 
66ff4e6c35SAndre Przywara 	rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
6752696946SOlivier Deprez 	if (rc != 0) {
6852696946SOlivier Deprez 		NOTICE("%s not specified in SPM Core manifest.\n",
6952696946SOlivier Deprez 			"Load address");
7052696946SOlivier Deprez 	}
710cb64d01SAchin Gupta 
72ff4e6c35SAndre Przywara 	rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
7352696946SOlivier Deprez 	if (rc != 0) {
7452696946SOlivier Deprez 		NOTICE("%s not specified in SPM Core manifest.\n",
7552696946SOlivier Deprez 			"Entry point");
7652696946SOlivier Deprez 	}
770cb64d01SAchin Gupta 
7852696946SOlivier Deprez 	VERBOSE("SPM Core manifest attribute section:\n");
7952696946SOlivier Deprez 	VERBOSE("  version: %u.%u\n", attr->major_version, attr->minor_version);
8052696946SOlivier Deprez 	VERBOSE("  spmc_id: 0x%x\n", attr->spmc_id);
810cb64d01SAchin Gupta 	VERBOSE("  binary_size: 0x%x\n", attr->binary_size);
820cb64d01SAchin Gupta 	VERBOSE("  load_address: 0x%llx\n", attr->load_address);
830cb64d01SAchin Gupta 	VERBOSE("  entrypoint: 0x%llx\n", attr->entrypoint);
840cb64d01SAchin Gupta 
850cb64d01SAchin Gupta 	return 0;
860cb64d01SAchin Gupta }
870cb64d01SAchin Gupta 
880cb64d01SAchin Gupta /*******************************************************************************
890cb64d01SAchin Gupta  * Root node handler
900cb64d01SAchin Gupta  ******************************************************************************/
9152696946SOlivier Deprez static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
920cb64d01SAchin Gupta 			       const void *fdt,
930cb64d01SAchin Gupta 			       int root)
940cb64d01SAchin Gupta {
950cb64d01SAchin Gupta 	int node;
960cb64d01SAchin Gupta 
9752696946SOlivier Deprez 	assert(manifest != NULL);
9852696946SOlivier Deprez 
9952696946SOlivier Deprez 	node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
10052696946SOlivier Deprez 		sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
1010cb64d01SAchin Gupta 	if (node < 0) {
10252696946SOlivier Deprez 		ERROR("Root node doesn't contain subnode '%s'\n",
10352696946SOlivier Deprez 			ATTRIBUTE_ROOT_NODE_STR);
10452696946SOlivier Deprez 		return node;
1050cb64d01SAchin Gupta 	}
1060cb64d01SAchin Gupta 
1070cb64d01SAchin Gupta 	return manifest_parse_attribute(manifest, fdt, node);
1080cb64d01SAchin Gupta }
1090cb64d01SAchin Gupta 
1100cb64d01SAchin Gupta /*******************************************************************************
11152696946SOlivier Deprez  * Platform handler to parse a SPM Core manifest.
1120cb64d01SAchin Gupta  ******************************************************************************/
11352696946SOlivier Deprez int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
11423d5ba86SOlivier Deprez 				const void *pm_addr)
1150cb64d01SAchin Gupta {
11623d5ba86SOlivier Deprez 	int rc, unmap_ret;
11723d5ba86SOlivier Deprez 	uintptr_t pm_base, pm_base_align;
11823d5ba86SOlivier Deprez 	size_t mapped_size;
1190cb64d01SAchin Gupta 
1200cb64d01SAchin Gupta 	assert(manifest != NULL);
12123d5ba86SOlivier Deprez 	assert(pm_addr != NULL);
1220cb64d01SAchin Gupta 
12323d5ba86SOlivier Deprez 	/*
12423d5ba86SOlivier Deprez 	 * Assume TOS_FW_CONFIG is not necessarily aligned to a page
12523d5ba86SOlivier Deprez 	 * boundary, thus calculate the remaining space between SPMC
12623d5ba86SOlivier Deprez 	 * manifest start address and upper page limit.
12723d5ba86SOlivier Deprez 	 *
12823d5ba86SOlivier Deprez 	 */
12923d5ba86SOlivier Deprez 	pm_base = (uintptr_t)pm_addr;
13023d5ba86SOlivier Deprez 	pm_base_align = page_align(pm_base, UP);
13123d5ba86SOlivier Deprez 	mapped_size = pm_base_align - pm_base;
1320cb64d01SAchin Gupta 
13323d5ba86SOlivier Deprez 	/* Check space within the page at least maps the FDT header */
13423d5ba86SOlivier Deprez 	if (mapped_size < sizeof(struct fdt_header)) {
13523d5ba86SOlivier Deprez 		ERROR("Error while mapping SPM Core manifest.\n");
13623d5ba86SOlivier Deprez 		return -EINVAL;
13723d5ba86SOlivier Deprez 	}
13823d5ba86SOlivier Deprez 
13923d5ba86SOlivier Deprez 	/* Map first SPMC manifest page in the SPMD translation regime */
14023d5ba86SOlivier Deprez 	pm_base_align = page_align(pm_base, DOWN);
14123d5ba86SOlivier Deprez 	rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
14223d5ba86SOlivier Deprez 				     pm_base_align,
14323d5ba86SOlivier Deprez 				     PAGE_SIZE,
14423d5ba86SOlivier Deprez 				     MT_RO_DATA);
1450cb64d01SAchin Gupta 	if (rc != 0) {
14623d5ba86SOlivier Deprez 		ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
14752696946SOlivier Deprez 		return rc;
1480cb64d01SAchin Gupta 	}
1490cb64d01SAchin Gupta 
15023d5ba86SOlivier Deprez 	rc = fdt_check_header(pm_addr);
15123d5ba86SOlivier Deprez 	if (rc != 0) {
15223d5ba86SOlivier Deprez 		ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
15323d5ba86SOlivier Deprez 		goto exit_unmap;
15423d5ba86SOlivier Deprez 	}
15523d5ba86SOlivier Deprez 
15623d5ba86SOlivier Deprez 	/* Check SPMC manifest fits within the upper mapped page boundary */
15723d5ba86SOlivier Deprez 	if (mapped_size < fdt_totalsize(pm_addr)) {
15823d5ba86SOlivier Deprez 		ERROR("SPM Core manifest too large.\n");
15923d5ba86SOlivier Deprez 		rc = -EINVAL;
16023d5ba86SOlivier Deprez 		goto exit_unmap;
16123d5ba86SOlivier Deprez 	}
16223d5ba86SOlivier Deprez 
16323d5ba86SOlivier Deprez 	VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
16423d5ba86SOlivier Deprez 
16523d5ba86SOlivier Deprez 	rc = fdt_node_offset_by_compatible(pm_addr, -1,
166*662af36dSJ-Alves 				"arm,ffa-core-manifest-1.0");
16752696946SOlivier Deprez 	if (rc < 0) {
16852696946SOlivier Deprez 		ERROR("Unrecognized SPM Core manifest\n");
16923d5ba86SOlivier Deprez 		goto exit_unmap;
1700cb64d01SAchin Gupta 	}
1710cb64d01SAchin Gupta 
17223d5ba86SOlivier Deprez 	rc = manifest_parse_root(manifest, pm_addr, rc);
17323d5ba86SOlivier Deprez 
17423d5ba86SOlivier Deprez exit_unmap:
17523d5ba86SOlivier Deprez 	unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
17623d5ba86SOlivier Deprez 	if (unmap_ret != 0) {
17723d5ba86SOlivier Deprez 		ERROR("Error while unmapping SPM Core manifest (%d).\n",
17823d5ba86SOlivier Deprez 			unmap_ret);
17923d5ba86SOlivier Deprez 		if (rc == 0) {
18023d5ba86SOlivier Deprez 			rc = unmap_ret;
18123d5ba86SOlivier Deprez 		}
18223d5ba86SOlivier Deprez 	}
18323d5ba86SOlivier Deprez 
18423d5ba86SOlivier Deprez 	return rc;
1850cb64d01SAchin Gupta }
186