1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
4  */
5 
6 #include <common/fdt/fdt_helpers.h>
7 #include <config/interface/config_store.h>
8 #include <config/interface/config_blob.h>
9 #include <platform/interface/device_region.h>
10 #include <platform/interface/memory_region.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <trace.h>
15 
16 #include "sp_config_loader.h"
17 
18 /*
19  * According to the FF-A spec: in the SP manifest the size of device and
20  * memory regions is expressed as a count of 4K pages.
21  */
22 #define FFA_SP_MANIFEST_PAGE_SIZE UINT32_C(0x1000)
23 
24 struct sp_param_region {
25 	char name[16];
26 	uintptr_t location;
27 	size_t size;
28 };
29 
load_device_regions(const struct ffa_name_value_pair_v1_0 * value_pair)30 static bool load_device_regions(const struct ffa_name_value_pair_v1_0 *value_pair)
31 {
32 	struct sp_param_region *d = (struct sp_param_region *)value_pair->value;
33 
34 	/* Iterate over the device regions */
35 	while ((uintptr_t)d < (value_pair->value + value_pair->size)) {
36 
37 		struct device_region device_region = { 0 };
38 		size_t name_length = strlen(d->name) + 1;
39 
40 		if (name_length > sizeof(device_region.dev_class)) {
41 			EMSG("name too long");
42 			return false;
43 		}
44 
45 		memcpy(device_region.dev_class, d->name, name_length);
46 		device_region.dev_instance = 0;
47 		device_region.base_addr = d->location;
48 		device_region.io_region_size = d->size;
49 
50 		if (!config_store_add(CONFIG_CLASSIFIER_DEVICE_REGION,
51 				      device_region.dev_class,
52 				      device_region.dev_instance,
53 				      &device_region, sizeof(device_region))) {
54 			EMSG("failed to add device region to config store");
55 			return false;
56 		}
57 
58 		++d;
59 	}
60 
61 	return true;
62 }
63 
load_memory_regions(const struct ffa_name_value_pair_v1_0 * value_pair)64 static bool load_memory_regions(const struct ffa_name_value_pair_v1_0 *value_pair)
65 {
66 	struct sp_param_region *d = (struct sp_param_region *)value_pair->value;
67 
68 	/* Iterate over the device regions */
69 	while ((uintptr_t)d < (value_pair->value + value_pair->size)) {
70 
71 		struct memory_region memory_region = { 0 };
72 		size_t name_length = strlen(d->name) + 1;
73 
74 		if (name_length > sizeof(memory_region.region_name)) {
75 			EMSG("name too long");
76 			return false;
77 		}
78 
79 		memcpy(memory_region.region_name, d->name, name_length);
80 		memory_region.base_addr = d->location;
81 		memory_region.region_size = d->size;
82 
83 		if (!config_store_add(CONFIG_CLASSIFIER_MEMORY_REGION,
84 				      memory_region.region_name, 0,
85 				      &memory_region, sizeof(memory_region))) {
86 			EMSG("failed to add memory region to config store");
87 			return false;
88 		}
89 
90 		++d;
91 	}
92 
93 	return true;
94 }
95 
load_blob(const struct ffa_name_value_pair_v1_0 * value_pair)96 static bool load_blob(const struct ffa_name_value_pair_v1_0 *value_pair)
97 {
98 	struct config_blob blob;
99 
100 	blob.data = (const void*)value_pair->value;
101 	blob.data_len = value_pair->size;
102 
103 	if (!config_store_add(CONFIG_CLASSIFIER_BLOB, (const char *)value_pair->name, 0,
104 			      &blob, sizeof(blob))) {
105 		EMSG("failed to add blob to config store");
106 		return false;
107 	}
108 
109 	return true;
110 }
111 
load_fdt(const void * fdt,size_t fdt_size)112 static bool load_fdt(const void *fdt, size_t fdt_size)
113 {
114 	int root = -1, node = -1, subnode = -1, rc = -1;
115 	static const char *ffa_manifest_compatible = "arm,ffa-manifest-1.0";
116 
117 	/* Sanity check */
118 	if (!fdt) {
119 		EMSG("fdt NULL pointer");
120 		return false;
121 	}
122 
123 	rc = fdt_check_full(fdt, fdt_size);
124 	if (rc) {
125 		EMSG("fdt_check_full(): %d", rc);
126 		return false;
127 	}
128 
129 	/* Find root node */
130 	root = fdt_path_offset(fdt, "/");
131 	if (root < 0) {
132 		EMSG("fdt_path_offset(): %d", root);
133 		return false;
134 	}
135 
136 	/* Check if it's a valid SP manifest */
137 	rc = fdt_node_check_compatible(fdt, root, ffa_manifest_compatible);
138 	if (rc) {
139 		EMSG("fdt_node_check_compatible(%s): %d", ffa_manifest_compatible, rc);
140 		return false;
141 	}
142 
143 	/* Find memory regions */
144 	node = fdt_node_offset_by_compatible(fdt, root, "arm,ffa-manifest-memory-regions");
145 	if (node >= 0) {
146 		fdt_for_each_subnode(subnode, fdt, node) {
147 			struct memory_region memory_region = {0};
148 			uint64_t base_addr = 0;
149 			uint32_t page_cnt = 0;
150 			const char *subnode_name = fdt_get_name(fdt, subnode, NULL);
151 			size_t name_length = 0;
152 
153 			if (!subnode_name) {
154 				EMSG("subnode name is missing");
155 				return false;
156 			}
157 
158 			if(!dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
159 				EMSG("base-address is missing");
160 				return false;
161 			}
162 
163 			if(!dt_get_u32(fdt, subnode, "pages-count", &page_cnt)) {
164 				EMSG("pages-count is missing");
165 				return false;
166 			}
167 
168 			name_length = strlen(subnode_name) + 1;
169 			if (name_length > sizeof(memory_region.region_name)) {
170 				EMSG("name too long");
171 				return false;
172 			}
173 
174 			memcpy(memory_region.region_name, subnode_name, name_length);
175 			memory_region.base_addr = (uintptr_t)base_addr;
176 			memory_region.region_size = page_cnt * FFA_SP_MANIFEST_PAGE_SIZE;
177 
178 			if (!config_store_add(CONFIG_CLASSIFIER_MEMORY_REGION,
179 					      memory_region.region_name, 0,
180 					      &memory_region, sizeof(memory_region))) {
181 				EMSG("failed to add memory region to config store");
182 				return false;
183 			}
184 		}
185 	}
186 
187 	/* Find device regions */
188 	node = fdt_node_offset_by_compatible(fdt, root, "arm,ffa-manifest-device-regions");
189 	if (node >= 0) {
190 		fdt_for_each_subnode(subnode, fdt, node) {
191 			struct device_region device_region = {0};
192 			uint64_t base_addr = 0;
193 			uint32_t page_cnt = 0;
194 			const char *subnode_name = fdt_get_name(fdt, subnode, NULL);
195 			size_t name_length = 0;
196 
197 			if (!subnode_name) {
198 				EMSG("subnode name is missing");
199 				return false;
200 			}
201 
202 			if(!dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
203 				EMSG("base-address is missing");
204 				return false;
205 			}
206 
207 			if (!dt_get_u32(fdt, subnode, "pages-count", &page_cnt)) {
208 				EMSG("pages-count is missing");
209 				return false;
210 			}
211 
212 			name_length = strlen(subnode_name) + 1;
213 			if (name_length > sizeof(device_region.dev_class)) {
214 				EMSG("name too long");
215 				return false;
216 			}
217 
218 			memcpy(device_region.dev_class, subnode_name, name_length);
219 			device_region.base_addr = base_addr;
220 			device_region.io_region_size = page_cnt * FFA_SP_MANIFEST_PAGE_SIZE;
221 			device_region.dev_instance = 0;
222 
223 			if (!config_store_add(CONFIG_CLASSIFIER_DEVICE_REGION,
224 					      device_region.dev_class, device_region.dev_instance,
225 					      &device_region, sizeof(device_region))) {
226 				EMSG("failed to add device region to config store");
227 				return false;
228 			}
229 		}
230 	}
231 
232 	/* Find TPM event log */
233 	node = fdt_node_offset_by_compatible(fdt, root, "arm,tpm_event_log");
234 	if (node >= 0) {
235 		uint64_t tpm_event_log_addr = 0;
236 		uint32_t tpm_event_log_size = 0;
237 		struct config_blob blob = { 0 };
238 
239 		if (!dt_get_u64(fdt, node, "tpm_event_log_addr", &tpm_event_log_addr)) {
240 			EMSG("tpm_event_log_addr is missing");
241 			return false;
242 		}
243 
244 		if (!dt_get_u32(fdt, node, "tpm_event_log_size", &tpm_event_log_size)) {
245 			EMSG("tpm_event_log_size is missing");
246 			return false;
247 		}
248 
249 		blob.data = (const void *)tpm_event_log_addr;
250 		blob.data_len = tpm_event_log_size;
251 
252 		if (!config_store_add(CONFIG_CLASSIFIER_BLOB, "EVENT_LOG", 0,
253 				      (void *)&blob, sizeof(blob))) {
254 			EMSG("failed to add event log to config store");
255 			return false;
256 		}
257 	}
258 
259 	/* Find hardware features */
260 	node = fdt_node_offset_by_compatible(fdt, root, "arm,hw-features");
261 	if (node >= 0) {
262 		const char *prop_name = NULL;
263 		uint32_t prop_value = 0;
264 		int prop_offset = 0;
265 
266 		fdt_for_each_property_offset(prop_offset, fdt, node) {
267 			if (!dt_get_u32_by_offset(fdt, prop_offset, &prop_name, &prop_value)) {
268 				/* skip other properties in the node, e.g. the compatible string */
269 				DMSG("skipping non-u32 property '%s' in hw-features", prop_name);
270 				continue;
271 			}
272 
273 			if (!config_store_add(CONFIG_CLASSIFIER_HW_FEATURE, prop_name, 0,
274 					      &prop_value, sizeof(prop_value))) {
275 				EMSG("failed to add HW feature to config store");
276 				return false;
277 			}
278 		}
279 	} else {
280 		DMSG("arm,hw-features node not present in SP manifest");
281 	}
282 
283 	return true;
284 }
285 
sp_config_load_v1_0(struct ffa_boot_info_v1_0 * boot_info)286 static bool sp_config_load_v1_0(struct ffa_boot_info_v1_0 *boot_info)
287 {
288 	/* Load deployment specific configuration */
289 	for (size_t param_index = 0; param_index < boot_info->count; param_index++) {
290 		const char *name = (const char *)boot_info->nvp[param_index].name;
291 		const size_t name_max_size = sizeof(boot_info->nvp[param_index].name);
292 
293 		if (!strncmp(name, "DEVICE_REGIONS", name_max_size)) {
294 			if (!load_device_regions(&boot_info->nvp[param_index])) {
295 				EMSG("Failed to load device regions");
296 				return false;
297 			}
298 		} else if (!strncmp(name, "MEMORY_REGIONS", name_max_size)) {
299 			if (!load_memory_regions(&boot_info->nvp[param_index])) {
300 				EMSG("Failed to load memory regions");
301 				return false;
302 			}
303 		} else if (!memcmp(name, "TYPE_DT\0\0\0\0\0\0\0\0", name_max_size)) {
304 			if (!load_fdt((void *)boot_info->nvp[param_index].value,
305 					boot_info->nvp[param_index].size)) {
306 				EMSG("Failed to load SP config from DT");
307 				return false;
308 			}
309 		} else {
310 			if (!load_blob(&boot_info->nvp[param_index])) {
311 				EMSG("Failed to load blob");
312 				return false;
313 			}
314 		}
315 	}
316 
317 	return true;
318 }
319 
sp_config_load_v1_1(struct ffa_boot_info_header_v1_1 * boot_info_header)320 static bool sp_config_load_v1_1(struct ffa_boot_info_header_v1_1 *boot_info_header)
321 {
322 	size_t desc_end = 0;
323 	size_t total_desc_size = 0;
324 	struct ffa_boot_info_desc_v1_1 *boot_info_desc = NULL;
325 	uint32_t expected_version = SHIFT_U32(1, FFA_VERSION_MAJOR_SHIFT) |
326 				    SHIFT_U32(1, FFA_VERSION_MINOR_SHIFT);
327 
328 	if (boot_info_header->version != expected_version) {
329 		EMSG("Invalid FF-A boot info version");
330 		return false;
331 	}
332 
333 	if (boot_info_header->desc_size != sizeof(struct ffa_boot_info_desc_v1_1)) {
334 		EMSG("Boot info descriptor size mismatch");
335 		return false;
336 	}
337 
338 	if (MUL_OVERFLOW(boot_info_header->desc_size, boot_info_header->desc_cnt,
339 			 &total_desc_size)) {
340 		EMSG("Boot info descriptor overflow");
341 		return false;
342 	}
343 
344 	if (ADD_OVERFLOW(boot_info_header->desc_offs, total_desc_size, &desc_end) ||
345 	    boot_info_header->size < desc_end) {
346 		EMSG("Boot info descriptor overflow");
347 		return false;
348 	}
349 
350 	boot_info_desc = (struct ffa_boot_info_desc_v1_1 *)((uintptr_t)boot_info_header +
351 							    boot_info_header->desc_offs);
352 
353 	for (unsigned int i = 0; i < boot_info_header->desc_cnt; i++) {
354 		uint16_t flags = FFA_BOOT_INFO_CONTENT_FMT_ADDR << FFA_BOOT_INFO_CONTENT_FMT_SHIFT;
355 		uint16_t type = FFA_BOOT_INFO_TYPE_STD << FFA_BOOT_INFO_TYPE_SHIFT |
356 				FFA_BOOT_INFO_ID_STD_FDT << FFA_BOOT_INFO_ID_SHIFT;
357 
358 		if (boot_info_desc[i].flags == flags && boot_info_desc[i].type == type) {
359 			if (!load_fdt((void *)boot_info_desc->contents, boot_info_desc->size)) {
360 				EMSG("Failed to load SP config FDT");
361 				return false;
362 			}
363 		}
364 	}
365 
366 	return true;
367 }
368 
sp_config_load(union ffa_boot_info * boot_info)369 bool sp_config_load(union ffa_boot_info *boot_info)
370 {
371 	if (!boot_info)
372 		return false;
373 
374 	switch (boot_info->signature) {
375 	case FFA_BOOT_INFO_SIGNATURE_V1_0:
376 		return sp_config_load_v1_0((struct ffa_boot_info_v1_0 *)&boot_info->boot_info_v1_0);
377 	case FFA_BOOT_INFO_SIGNATURE_V1_1:
378 		return sp_config_load_v1_1((struct ffa_boot_info_header_v1_1 *)
379 					   &boot_info->boot_info_v1_1);
380 	default:
381 		EMSG("Invalid FF-A boot info signature");
382 		return false;
383 	}
384 
385 	return false;
386 }
387