blob: 4d9da9f3eaa5d7bc845ac52660ee1b35608e190b [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;
Michael Zhaoccd689a2025-04-03 22:40:39 +0100193 uint64_t phys_addr = 0;
Balint Dobszay286ff752022-03-04 15:57:19 +0100194 uint32_t page_cnt = 0;
195 const char *subnode_name = fdt_get_name(fdt, subnode, NULL);
Imre Kis58cdf332024-06-04 11:52:05 +0200196 size_t name_length = 0;
Balint Dobszay286ff752022-03-04 15:57:19 +0100197
198 if (!subnode_name) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200199 EMSG("subnode name is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100200 return false;
201 }
202
203 if(!dt_get_u64(fdt, subnode, "base-address", &base_addr)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200204 EMSG("base-address is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100205 return false;
206 }
207
Michael Zhaoccd689a2025-04-03 22:40:39 +0100208 if(!dt_get_u64(fdt, subnode, "physical-address", &phys_addr)) {
209 DMSG("physical-address is not configured");
210 }
211
Balint Dobszay286ff752022-03-04 15:57:19 +0100212 if (!dt_get_u32(fdt, subnode, "pages-count", &page_cnt)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200213 EMSG("pages-count is missing");
Balint Dobszay286ff752022-03-04 15:57:19 +0100214 return false;
215 }
216
Imre Kis58cdf332024-06-04 11:52:05 +0200217 name_length = strlen(subnode_name) + 1;
218 if (name_length > sizeof(device_region.dev_class)) {
219 EMSG("name too long");
220 return false;
221 }
222
223 memcpy(device_region.dev_class, subnode_name, name_length);
Balint Dobszay286ff752022-03-04 15:57:19 +0100224 device_region.base_addr = base_addr;
Michael Zhaoccd689a2025-04-03 22:40:39 +0100225 device_region.phys_addr = phys_addr;
Balint Dobszay286ff752022-03-04 15:57:19 +0100226 device_region.io_region_size = page_cnt * FFA_SP_MANIFEST_PAGE_SIZE;
227 device_region.dev_instance = 0;
228
229 if (!config_store_add(CONFIG_CLASSIFIER_DEVICE_REGION,
230 device_region.dev_class, device_region.dev_instance,
231 &device_region, sizeof(device_region))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200232 EMSG("failed to add device region to config store");
Balint Dobszay286ff752022-03-04 15:57:19 +0100233 return false;
234 }
235 }
236 }
237
Imre Kisd40d6202022-03-22 19:20:14 +0100238 /* Find TPM event log */
239 node = fdt_node_offset_by_compatible(fdt, root, "arm,tpm_event_log");
240 if (node >= 0) {
241 uint64_t tpm_event_log_addr = 0;
242 uint32_t tpm_event_log_size = 0;
Imre Kise432e582022-07-07 16:35:45 +0200243 struct config_blob blob = { 0 };
Imre Kisd40d6202022-03-22 19:20:14 +0100244
Balint Dobszay43b7d982022-04-01 15:35:51 +0200245 if (!dt_get_u64(fdt, node, "tpm_event_log_addr", &tpm_event_log_addr)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200246 EMSG("tpm_event_log_addr is missing");
Imre Kisd40d6202022-03-22 19:20:14 +0100247 return false;
Balint Dobszay43b7d982022-04-01 15:35:51 +0200248 }
Imre Kisd40d6202022-03-22 19:20:14 +0100249
Balint Dobszay43b7d982022-04-01 15:35:51 +0200250 if (!dt_get_u32(fdt, node, "tpm_event_log_size", &tpm_event_log_size)) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200251 EMSG("tpm_event_log_size is missing");
Imre Kisd40d6202022-03-22 19:20:14 +0100252 return false;
Balint Dobszay43b7d982022-04-01 15:35:51 +0200253 }
Imre Kisd40d6202022-03-22 19:20:14 +0100254
Imre Kise432e582022-07-07 16:35:45 +0200255 blob.data = (const void *)tpm_event_log_addr;
256 blob.data_len = tpm_event_log_size;
257
Imre Kisd40d6202022-03-22 19:20:14 +0100258 if (!config_store_add(CONFIG_CLASSIFIER_BLOB, "EVENT_LOG", 0,
Imre Kise432e582022-07-07 16:35:45 +0200259 (void *)&blob, sizeof(blob))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200260 EMSG("failed to add event log to config store");
Imre Kisd40d6202022-03-22 19:20:14 +0100261 return false;
262 }
263 }
264
Balint Dobszay9a747852023-04-18 18:08:49 +0200265 /* Find hardware features */
266 node = fdt_node_offset_by_compatible(fdt, root, "arm,hw-features");
267 if (node >= 0) {
268 const char *prop_name = NULL;
269 uint32_t prop_value = 0;
270 int prop_offset = 0;
271
272 fdt_for_each_property_offset(prop_offset, fdt, node) {
273 if (!dt_get_u32_by_offset(fdt, prop_offset, &prop_name, &prop_value)) {
274 /* skip other properties in the node, e.g. the compatible string */
275 DMSG("skipping non-u32 property '%s' in hw-features", prop_name);
276 continue;
277 }
278
279 if (!config_store_add(CONFIG_CLASSIFIER_HW_FEATURE, prop_name, 0,
280 &prop_value, sizeof(prop_value))) {
Balint Dobszay3d1c5742023-04-24 10:40:26 +0200281 EMSG("failed to add HW feature to config store");
Balint Dobszay9a747852023-04-18 18:08:49 +0200282 return false;
283 }
284 }
285 } else {
286 DMSG("arm,hw-features node not present in SP manifest");
287 }
288
Balint Dobszay286ff752022-03-04 15:57:19 +0100289 return true;
290}
Balint Dobszay8102ba72023-04-13 16:29:41 +0200291
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200292static bool sp_config_load_v1_0(struct ffa_boot_info_v1_0 *boot_info)
Balint Dobszay8102ba72023-04-13 16:29:41 +0200293{
294 /* Load deployment specific configuration */
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200295 for (size_t param_index = 0; param_index < boot_info->count; param_index++) {
296 const char *name = (const char *)boot_info->nvp[param_index].name;
297 const size_t name_max_size = sizeof(boot_info->nvp[param_index].name);
Balint Dobszay8102ba72023-04-13 16:29:41 +0200298
299 if (!strncmp(name, "DEVICE_REGIONS", name_max_size)) {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200300 if (!load_device_regions(&boot_info->nvp[param_index])) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200301 EMSG("Failed to load device regions");
302 return false;
303 }
304 } else if (!strncmp(name, "MEMORY_REGIONS", name_max_size)) {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200305 if (!load_memory_regions(&boot_info->nvp[param_index])) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200306 EMSG("Failed to load memory regions");
307 return false;
308 }
309 } else if (!memcmp(name, "TYPE_DT\0\0\0\0\0\0\0\0", name_max_size)) {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200310 if (!load_fdt((void *)boot_info->nvp[param_index].value,
311 boot_info->nvp[param_index].size)) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200312 EMSG("Failed to load SP config from DT");
313 return false;
314 }
315 } else {
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200316 if (!load_blob(&boot_info->nvp[param_index])) {
Balint Dobszay8102ba72023-04-13 16:29:41 +0200317 EMSG("Failed to load blob");
318 return false;
319 }
320 }
321 }
322
323 return true;
324}
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200325
Balint Dobszay0100ddd2023-05-09 14:39:08 +0200326static bool sp_config_load_v1_1(struct ffa_boot_info_header_v1_1 *boot_info_header)
327{
328 size_t desc_end = 0;
329 size_t total_desc_size = 0;
330 struct ffa_boot_info_desc_v1_1 *boot_info_desc = NULL;
331 uint32_t expected_version = SHIFT_U32(1, FFA_VERSION_MAJOR_SHIFT) |
332 SHIFT_U32(1, FFA_VERSION_MINOR_SHIFT);
333
334 if (boot_info_header->version != expected_version) {
335 EMSG("Invalid FF-A boot info version");
336 return false;
337 }
338
339 if (boot_info_header->desc_size != sizeof(struct ffa_boot_info_desc_v1_1)) {
340 EMSG("Boot info descriptor size mismatch");
341 return false;
342 }
343
344 if (MUL_OVERFLOW(boot_info_header->desc_size, boot_info_header->desc_cnt,
345 &total_desc_size)) {
346 EMSG("Boot info descriptor overflow");
347 return false;
348 }
349
350 if (ADD_OVERFLOW(boot_info_header->desc_offs, total_desc_size, &desc_end) ||
351 boot_info_header->size < desc_end) {
352 EMSG("Boot info descriptor overflow");
353 return false;
354 }
355
356 boot_info_desc = (struct ffa_boot_info_desc_v1_1 *)((uintptr_t)boot_info_header +
357 boot_info_header->desc_offs);
358
359 for (unsigned int i = 0; i < boot_info_header->desc_cnt; i++) {
360 uint16_t flags = FFA_BOOT_INFO_CONTENT_FMT_ADDR << FFA_BOOT_INFO_CONTENT_FMT_SHIFT;
361 uint16_t type = FFA_BOOT_INFO_TYPE_STD << FFA_BOOT_INFO_TYPE_SHIFT |
362 FFA_BOOT_INFO_ID_STD_FDT << FFA_BOOT_INFO_ID_SHIFT;
363
364 if (boot_info_desc[i].flags == flags && boot_info_desc[i].type == type) {
365 if (!load_fdt((void *)boot_info_desc->contents, boot_info_desc->size)) {
366 EMSG("Failed to load SP config FDT");
367 return false;
368 }
369 }
370 }
371
372 return true;
373}
374
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200375bool sp_config_load(union ffa_boot_info *boot_info)
376{
377 if (!boot_info)
378 return false;
379
380 switch (boot_info->signature) {
381 case FFA_BOOT_INFO_SIGNATURE_V1_0:
382 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 +0200383 case FFA_BOOT_INFO_SIGNATURE_V1_1:
384 return sp_config_load_v1_1((struct ffa_boot_info_header_v1_1 *)
385 &boot_info->boot_info_v1_1);
Balint Dobszay4f9d8e32023-04-13 13:55:08 +0200386 default:
387 EMSG("Invalid FF-A boot info signature");
388 return false;
389 }
390
391 return false;
392}