blob: bebb4b42306deecba025e08f7e8213ff0e7495a0 [file] [log] [blame]
julhal0137e1aea2021-02-09 15:22:20 +00001// SPDX-License-Identifier: BSD-3-Clause
2/*
Imre Kis2d4d29f2024-04-26 12:57:22 +02003 * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
julhal0137e1aea2021-02-09 15:22:20 +00004 */
5
Balint Dobszay286ff752022-03-04 15:57:19 +01006#include <common/fdt/fdt_helpers.h>
Julian Hall7048d302021-06-03 16:07:28 +01007#include <config/interface/config_store.h>
8#include <config/interface/config_blob.h>
julhal0137e1aea2021-02-09 15:22:20 +00009#include <platform/interface/device_region.h>
Balint Dobszay286ff752022-03-04 15:57:19 +010010#include <platform/interface/memory_region.h>
11#include <stdbool.h>
Balint Dobszay4f9d8e32023-04-13 13:55:08 +020012#include <stdint.h>
Balint Dobszay286ff752022-03-04 15:57:19 +010013#include <string.h>
14#include <trace.h>
15
julhal0137e1aea2021-02-09 15:22:20 +000016#include "sp_config_loader.h"
17
Balint Dobszay286ff752022-03-04 15:57:19 +010018/*
Balint Dobszay4f9d8e32023-04-13 13:55:08 +020019 * According to the FF-A spec: in the SP manifest the size of device and
Balint Dobszay286ff752022-03-04 15:57:19 +010020 * memory regions is expressed as a count of 4K pages.
21 */
Balint Dobszay4f9d8e32023-04-13 13:55:08 +020022#define FFA_SP_MANIFEST_PAGE_SIZE UINT32_C(0x1000)
julhal0137e1aea2021-02-09 15:22:20 +000023
Imre Kisfe6521e2021-10-27 20:20:37 +020024struct sp_param_region {
julhal0137e1aea2021-02-09 15:22:20 +000025 char name[16];
26 uintptr_t location;
27 size_t size;
28};
29
Balint Dobszay4f9d8e32023-04-13 13:55:08 +020030static bool load_device_regions(const struct ffa_name_value_pair_v1_0 *value_pair)
Julian Hall7048d302021-06-03 16:07:28 +010031{
Imre Kisfe6521e2021-10-27 20:20:37 +020032 struct sp_param_region *d = (struct sp_param_region *)value_pair->value;
Julian Hall7048d302021-06-03 16:07:28 +010033
34 /* Iterate over the device regions */
35 while ((uintptr_t)d < (value_pair->value + value_pair->size)) {
36
Imre Kis2d4d29f2024-04-26 12:57:22 +020037 struct device_region device_region = { 0 };
Imre Kis58cdf332024-06-04 11:52:05 +020038 size_t name_length = strlen(d->name) + 1;
Julian Hall7048d302021-06-03 16:07:28 +010039
Imre Kis58cdf332024-06-04 11:52:05 +020040 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);
Julian Hall7048d302021-06-03 16:07:28 +010046 device_region.dev_instance = 0;
47 device_region.base_addr = d->location;
48 device_region.io_region_size = d->size;
49
Imre Kis06360812022-07-05 16:28:00 +020050 if (!config_store_add(CONFIG_CLASSIFIER_DEVICE_REGION,
51 device_region.dev_class,
52 device_region.dev_instance,
53 &device_region, sizeof(device_region))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +020054 EMSG("failed to add device region to config store");
Imre Kis06360812022-07-05 16:28:00 +020055 return false;
56 }
Julian Hall7048d302021-06-03 16:07:28 +010057
58 ++d;
59 }
Imre Kis06360812022-07-05 16:28:00 +020060
61 return true;
Julian Hall7048d302021-06-03 16:07:28 +010062}
63
Balint Dobszay4f9d8e32023-04-13 13:55:08 +020064static bool load_memory_regions(const struct ffa_name_value_pair_v1_0 *value_pair)
Julian Hall7048d302021-06-03 16:07:28 +010065{
Imre Kisfe6521e2021-10-27 20:20:37 +020066 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
Imre Kis2d4d29f2024-04-26 12:57:22 +020071 struct memory_region memory_region = { 0 };
Imre Kis58cdf332024-06-04 11:52:05 +020072 size_t name_length = strlen(d->name) + 1;
Imre Kisfe6521e2021-10-27 20:20:37 +020073
Imre Kis58cdf332024-06-04 11:52:05 +020074 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);
Imre Kisfe6521e2021-10-27 20:20:37 +020080 memory_region.base_addr = d->location;
81 memory_region.region_size = d->size;
82
Imre Kis06360812022-07-05 16:28:00 +020083 if (!config_store_add(CONFIG_CLASSIFIER_MEMORY_REGION,
84 memory_region.region_name, 0,
85 &memory_region, sizeof(memory_region))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +020086 EMSG("failed to add memory region to config store");
Imre Kis06360812022-07-05 16:28:00 +020087 return false;
88 }
Imre Kisfe6521e2021-10-27 20:20:37 +020089
90 ++d;
91 }
Imre Kis06360812022-07-05 16:28:00 +020092
93 return true;
Julian Hall7048d302021-06-03 16:07:28 +010094}
95
Balint Dobszay4f9d8e32023-04-13 13:55:08 +020096static bool load_blob(const struct ffa_name_value_pair_v1_0 *value_pair)
Julian Hall7048d302021-06-03 16:07:28 +010097{
98 struct config_blob blob;
99
100 blob.data = (const void*)value_pair->value;
101 blob.data_len = value_pair->size;
102
Imre Kis06360812022-07-05 16:28:00 +0200103 if (!config_store_add(CONFIG_CLASSIFIER_BLOB, (const char *)value_pair->name, 0,
104 &blob, sizeof(blob))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200105 EMSG("failed to add blob to config store");
Imre Kis06360812022-07-05 16:28:00 +0200106 return false;
107 }
108
109 return true;
Julian Hall7048d302021-06-03 16:07:28 +0100110}
Balint Dobszay286ff752022-03-04 15:57:19 +0100111
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200112static bool load_fdt(const void *fdt, size_t fdt_size)
Balint Dobszay286ff752022-03-04 15:57:19 +0100113{
Balint Dobszay286ff752022-03-04 15:57:19 +0100114 int root = -1, node = -1, subnode = -1, rc = -1;
Imre Kis06360812022-07-05 16:28:00 +0200115 static const char *ffa_manifest_compatible = "arm,ffa-manifest-1.0";
Balint Dobszay286ff752022-03-04 15:57:19 +0100116
117 /* Sanity check */
118 if (!fdt) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200119 EMSG("fdt NULL pointer");
Balint Dobszay286ff752022-03-04 15:57:19 +0100120 return false;
121 }
122
123 rc = fdt_check_full(fdt, fdt_size);
124 if (rc) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200125 EMSG("fdt_check_full(): %d", rc);
Balint Dobszay286ff752022-03-04 15:57:19 +0100126 return false;
127 }
128
129 /* Find root node */
130 root = fdt_path_offset(fdt, "/");
131 if (root < 0) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200132 EMSG("fdt_path_offset(): %d", root);
Balint Dobszay286ff752022-03-04 15:57:19 +0100133 return false;
134 }
135
136 /* Check if it's a valid SP manifest */
Imre Kis06360812022-07-05 16:28:00 +0200137 rc = fdt_node_check_compatible(fdt, root, ffa_manifest_compatible);
Balint Dobszay286ff752022-03-04 15:57:19 +0100138 if (rc) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200139 EMSG("fdt_node_check_compatible(%s): %d", ffa_manifest_compatible, rc);
Balint Dobszay286ff752022-03-04 15:57:19 +0100140 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);
Imre Kis58cdf332024-06-04 11:52:05 +0200151 size_t name_length = 0;
Balint Dobszay286ff752022-03-04 15:57:19 +0100152
153 if (!subnode_name) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200154 EMSG("subnode name is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100155 return false;
156 }
157
158 if(!dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200159 EMSG("base-address is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100160 return false;
161 }
162
163 if(!dt_get_u32(fdt, subnode, "pages-count", &page_cnt)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200164 EMSG("pages-count is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100165 return false;
166 }
167
Imre Kis58cdf332024-06-04 11:52:05 +0200168 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);
Balint Dobszay286ff752022-03-04 15:57:19 +0100175 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))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200181 EMSG("failed to add memory region to config store");
Balint Dobszay286ff752022-03-04 15:57:19 +0100182 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);
Imre Kis58cdf332024-06-04 11:52:05 +0200195 size_t name_length = 0;
Balint Dobszay286ff752022-03-04 15:57:19 +0100196
197 if (!subnode_name) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200198 EMSG("subnode name is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100199 return false;
200 }
201
202 if(!dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200203 EMSG("base-address is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100204 return false;
205 }
206
207 if (!dt_get_u32(fdt, subnode, "pages-count", &page_cnt)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200208 EMSG("pages-count is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100209 return false;
210 }
211
Imre Kis58cdf332024-06-04 11:52:05 +0200212 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);
Balint Dobszay286ff752022-03-04 15:57:19 +0100219 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))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200226 EMSG("failed to add device region to config store");
Balint Dobszay286ff752022-03-04 15:57:19 +0100227 return false;
228 }
229 }
230 }
231
Imre Kisd40d6202022-03-22 19:20:14 +0100232 /* 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;
Imre Kise432e582022-07-07 16:35:45 +0200237 struct config_blob blob = { 0 };
Imre Kisd40d6202022-03-22 19:20:14 +0100238
Balint Dobszay43b7d982022-04-01 15:35:51 +0200239 if (!dt_get_u64(fdt, node, "tpm_event_log_addr", &tpm_event_log_addr)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200240 EMSG("tpm_event_log_addr is missing");
Imre Kisd40d6202022-03-22 19:20:14 +0100241 return false;
Balint Dobszay43b7d982022-04-01 15:35:51 +0200242 }
Imre Kisd40d6202022-03-22 19:20:14 +0100243
Balint Dobszay43b7d982022-04-01 15:35:51 +0200244 if (!dt_get_u32(fdt, node, "tpm_event_log_size", &tpm_event_log_size)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200245 EMSG("tpm_event_log_size is missing");
Imre Kisd40d6202022-03-22 19:20:14 +0100246 return false;
Balint Dobszay43b7d982022-04-01 15:35:51 +0200247 }
Imre Kisd40d6202022-03-22 19:20:14 +0100248
Imre Kise432e582022-07-07 16:35:45 +0200249 blob.data = (const void *)tpm_event_log_addr;
250 blob.data_len = tpm_event_log_size;
251
Imre Kisd40d6202022-03-22 19:20:14 +0100252 if (!config_store_add(CONFIG_CLASSIFIER_BLOB, "EVENT_LOG", 0,
Imre Kise432e582022-07-07 16:35:45 +0200253 (void *)&blob, sizeof(blob))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200254 EMSG("failed to add event log to config store");
Imre Kisd40d6202022-03-22 19:20:14 +0100255 return false;
256 }
257 }
258
Balint Dobszay9a747852023-04-18 18:08:49 +0200259 /* 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))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200275 EMSG("failed to add HW feature to config store");
Balint Dobszay9a747852023-04-18 18:08:49 +0200276 return false;
277 }
278 }
279 } else {
280 DMSG("arm,hw-features node not present in SP manifest");
281 }
282
Balint Dobszay286ff752022-03-04 15:57:19 +0100283 return true;
284}
Balint Dobszay8102ba72023-04-13 16:29:41 +0200285
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200286static bool sp_config_load_v1_0(struct ffa_boot_info_v1_0 *boot_info)
Balint Dobszay8102ba72023-04-13 16:29:41 +0200287{
288 /* Load deployment specific configuration */
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200289 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);
Balint Dobszay8102ba72023-04-13 16:29:41 +0200292
293 if (!strncmp(name, "DEVICE_REGIONS", name_max_size)) {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200294 if (!load_device_regions(&boot_info->nvp[param_index])) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200295 EMSG("Failed to load device regions");
296 return false;
297 }
298 } else if (!strncmp(name, "MEMORY_REGIONS", name_max_size)) {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200299 if (!load_memory_regions(&boot_info->nvp[param_index])) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200300 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)) {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200304 if (!load_fdt((void *)boot_info->nvp[param_index].value,
305 boot_info->nvp[param_index].size)) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200306 EMSG("Failed to load SP config from DT");
307 return false;
308 }
309 } else {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200310 if (!load_blob(&boot_info->nvp[param_index])) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200311 EMSG("Failed to load blob");
312 return false;
313 }
314 }
315 }
316
317 return true;
318}
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200319
Balint Dobszay0100ddd2023-05-09 14:39:08 +0200320static 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
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200369bool 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);
Balint Dobszay0100ddd2023-05-09 14:39:08 +0200377 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);
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200380 default:
381 EMSG("Invalid FF-A boot info signature");
382 return false;
383 }
384
385 return false;
386}