xref: /arm-trusted-firmware/plat/common/plat_spmd_manifest.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <inttypes.h>
10*91f16700Schasinglulu #include <libfdt.h>
11*91f16700Schasinglulu #include <stdint.h>
12*91f16700Schasinglulu #include <string.h>
13*91f16700Schasinglulu 
14*91f16700Schasinglulu #include <common/bl_common.h>
15*91f16700Schasinglulu #include <common/debug.h>
16*91f16700Schasinglulu #include <common/fdt_wrappers.h>
17*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h>
18*91f16700Schasinglulu #include <platform_def.h>
19*91f16700Schasinglulu #include <services/spm_core_manifest.h>
20*91f16700Schasinglulu 
21*91f16700Schasinglulu #define ATTRIBUTE_ROOT_NODE_STR "attribute"
22*91f16700Schasinglulu 
23*91f16700Schasinglulu /*******************************************************************************
24*91f16700Schasinglulu  * SPMC attribute node parser
25*91f16700Schasinglulu  ******************************************************************************/
26*91f16700Schasinglulu static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
27*91f16700Schasinglulu 				    const void *fdt,
28*91f16700Schasinglulu 				    int node)
29*91f16700Schasinglulu {
30*91f16700Schasinglulu 	uint32_t val32;
31*91f16700Schasinglulu 	int rc;
32*91f16700Schasinglulu 
33*91f16700Schasinglulu 	assert((attr != NULL) && (fdt != NULL));
34*91f16700Schasinglulu 
35*91f16700Schasinglulu 	rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
36*91f16700Schasinglulu 	if (rc != 0) {
37*91f16700Schasinglulu 		ERROR("Missing FFA %s version in SPM Core manifest.\n",
38*91f16700Schasinglulu 			"major");
39*91f16700Schasinglulu 		return rc;
40*91f16700Schasinglulu 	}
41*91f16700Schasinglulu 
42*91f16700Schasinglulu 	rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
43*91f16700Schasinglulu 	if (rc != 0) {
44*91f16700Schasinglulu 		ERROR("Missing FFA %s version in SPM Core manifest.\n",
45*91f16700Schasinglulu 			"minor");
46*91f16700Schasinglulu 		return rc;
47*91f16700Schasinglulu 	}
48*91f16700Schasinglulu 
49*91f16700Schasinglulu 	rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
50*91f16700Schasinglulu 	if (rc != 0) {
51*91f16700Schasinglulu 		ERROR("Missing SPMC ID in manifest.\n");
52*91f16700Schasinglulu 		return rc;
53*91f16700Schasinglulu 	}
54*91f16700Schasinglulu 
55*91f16700Schasinglulu 	attr->spmc_id = val32 & 0xffff;
56*91f16700Schasinglulu 
57*91f16700Schasinglulu 	rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
58*91f16700Schasinglulu 	if (rc != 0) {
59*91f16700Schasinglulu 		NOTICE("%s not specified in SPM Core manifest.\n",
60*91f16700Schasinglulu 			"Execution state");
61*91f16700Schasinglulu 	}
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 	rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
64*91f16700Schasinglulu 	if (rc != 0) {
65*91f16700Schasinglulu 		NOTICE("%s not specified in SPM Core manifest.\n",
66*91f16700Schasinglulu 			"Binary size");
67*91f16700Schasinglulu 	}
68*91f16700Schasinglulu 
69*91f16700Schasinglulu 	rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
70*91f16700Schasinglulu 	if (rc != 0) {
71*91f16700Schasinglulu 		NOTICE("%s not specified in SPM Core manifest.\n",
72*91f16700Schasinglulu 			"Load address");
73*91f16700Schasinglulu 	}
74*91f16700Schasinglulu 
75*91f16700Schasinglulu 	rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
76*91f16700Schasinglulu 	if (rc != 0) {
77*91f16700Schasinglulu 		NOTICE("%s not specified in SPM Core manifest.\n",
78*91f16700Schasinglulu 			"Entry point");
79*91f16700Schasinglulu 	}
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	VERBOSE("SPM Core manifest attribute section:\n");
82*91f16700Schasinglulu 	VERBOSE("  version: %u.%u\n", attr->major_version, attr->minor_version);
83*91f16700Schasinglulu 	VERBOSE("  spmc_id: 0x%x\n", attr->spmc_id);
84*91f16700Schasinglulu 	VERBOSE("  binary_size: 0x%x\n", attr->binary_size);
85*91f16700Schasinglulu 	VERBOSE("  load_address: 0x%" PRIx64 "\n", attr->load_address);
86*91f16700Schasinglulu 	VERBOSE("  entrypoint: 0x%" PRIx64 "\n", attr->entrypoint);
87*91f16700Schasinglulu 
88*91f16700Schasinglulu 	return 0;
89*91f16700Schasinglulu }
90*91f16700Schasinglulu 
91*91f16700Schasinglulu /*******************************************************************************
92*91f16700Schasinglulu  * Root node handler
93*91f16700Schasinglulu  ******************************************************************************/
94*91f16700Schasinglulu static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
95*91f16700Schasinglulu 			       const void *fdt,
96*91f16700Schasinglulu 			       int root)
97*91f16700Schasinglulu {
98*91f16700Schasinglulu 	int node;
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 	assert(manifest != NULL);
101*91f16700Schasinglulu 
102*91f16700Schasinglulu 	node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
103*91f16700Schasinglulu 		sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
104*91f16700Schasinglulu 	if (node < 0) {
105*91f16700Schasinglulu 		ERROR("Root node doesn't contain subnode '%s'\n",
106*91f16700Schasinglulu 			ATTRIBUTE_ROOT_NODE_STR);
107*91f16700Schasinglulu 		return node;
108*91f16700Schasinglulu 	}
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 	return manifest_parse_attribute(manifest, fdt, node);
111*91f16700Schasinglulu }
112*91f16700Schasinglulu 
113*91f16700Schasinglulu /*******************************************************************************
114*91f16700Schasinglulu  * Platform handler to parse a SPM Core manifest.
115*91f16700Schasinglulu  ******************************************************************************/
116*91f16700Schasinglulu int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
117*91f16700Schasinglulu 				const void *pm_addr)
118*91f16700Schasinglulu {
119*91f16700Schasinglulu 	int rc, unmap_ret;
120*91f16700Schasinglulu 	uintptr_t pm_base, pm_base_align;
121*91f16700Schasinglulu 	size_t mapped_size;
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 	assert(manifest != NULL);
124*91f16700Schasinglulu 	assert(pm_addr != NULL);
125*91f16700Schasinglulu 
126*91f16700Schasinglulu 	/*
127*91f16700Schasinglulu 	 * Assume TOS_FW_CONFIG is not necessarily aligned to a page
128*91f16700Schasinglulu 	 * boundary, thus calculate the remaining space between SPMC
129*91f16700Schasinglulu 	 * manifest start address and upper page limit.
130*91f16700Schasinglulu 	 *
131*91f16700Schasinglulu 	 */
132*91f16700Schasinglulu 	pm_base = (uintptr_t)pm_addr;
133*91f16700Schasinglulu 	pm_base_align = page_align(pm_base, UP);
134*91f16700Schasinglulu 
135*91f16700Schasinglulu 	if (pm_base == pm_base_align) {
136*91f16700Schasinglulu 		/* Page aligned */
137*91f16700Schasinglulu 		mapped_size = PAGE_SIZE;
138*91f16700Schasinglulu 	} else {
139*91f16700Schasinglulu 		mapped_size = pm_base_align - pm_base;
140*91f16700Schasinglulu 	}
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	/* Check space within the page at least maps the FDT header */
143*91f16700Schasinglulu 	if (mapped_size < sizeof(struct fdt_header)) {
144*91f16700Schasinglulu 		ERROR("Error while mapping SPM Core manifest.\n");
145*91f16700Schasinglulu 		return -EINVAL;
146*91f16700Schasinglulu 	}
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	/* Map first SPMC manifest page in the SPMD translation regime */
149*91f16700Schasinglulu 	pm_base_align = page_align(pm_base, DOWN);
150*91f16700Schasinglulu 	rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
151*91f16700Schasinglulu 				     pm_base_align,
152*91f16700Schasinglulu 				     PAGE_SIZE,
153*91f16700Schasinglulu 				     MT_RO_DATA | EL3_PAS);
154*91f16700Schasinglulu 	if (rc != 0) {
155*91f16700Schasinglulu 		ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
156*91f16700Schasinglulu 		return rc;
157*91f16700Schasinglulu 	}
158*91f16700Schasinglulu 
159*91f16700Schasinglulu 	rc = fdt_check_header(pm_addr);
160*91f16700Schasinglulu 	if (rc != 0) {
161*91f16700Schasinglulu 		ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
162*91f16700Schasinglulu 		goto exit_unmap;
163*91f16700Schasinglulu 	}
164*91f16700Schasinglulu 
165*91f16700Schasinglulu 	/* Check SPMC manifest fits within the upper mapped page boundary */
166*91f16700Schasinglulu 	if (mapped_size < fdt_totalsize(pm_addr)) {
167*91f16700Schasinglulu 		ERROR("SPM Core manifest too large.\n");
168*91f16700Schasinglulu 		rc = -EINVAL;
169*91f16700Schasinglulu 		goto exit_unmap;
170*91f16700Schasinglulu 	}
171*91f16700Schasinglulu 
172*91f16700Schasinglulu 	VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 	rc = fdt_node_offset_by_compatible(pm_addr, -1,
175*91f16700Schasinglulu 				"arm,ffa-core-manifest-1.0");
176*91f16700Schasinglulu 	if (rc < 0) {
177*91f16700Schasinglulu 		ERROR("Unrecognized SPM Core manifest\n");
178*91f16700Schasinglulu 		goto exit_unmap;
179*91f16700Schasinglulu 	}
180*91f16700Schasinglulu 
181*91f16700Schasinglulu 	rc = manifest_parse_root(manifest, pm_addr, rc);
182*91f16700Schasinglulu 
183*91f16700Schasinglulu exit_unmap:
184*91f16700Schasinglulu 	unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
185*91f16700Schasinglulu 	if (unmap_ret != 0) {
186*91f16700Schasinglulu 		ERROR("Error while unmapping SPM Core manifest (%d).\n",
187*91f16700Schasinglulu 			unmap_ret);
188*91f16700Schasinglulu 		if (rc == 0) {
189*91f16700Schasinglulu 			rc = unmap_ret;
190*91f16700Schasinglulu 		}
191*91f16700Schasinglulu 	}
192*91f16700Schasinglulu 
193*91f16700Schasinglulu 	return rc;
194*91f16700Schasinglulu }
195