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