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