blob: 30fee4e4693ff792648c3bc57d331f62284e789d [file] [log] [blame]
David Brazdil7a462ec2019-08-15 12:27:47 +01001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "hf/manifest.h"
18
19#include "hf/addr.h"
20#include "hf/check.h"
Andrew Scullae9962e2019-10-03 16:51:16 +010021#include "hf/dlog.h"
David Brazdil7a462ec2019-08-15 12:27:47 +010022#include "hf/fdt.h"
23#include "hf/static_assert.h"
24#include "hf/std.h"
25
26#define TRY(expr) \
27 do { \
28 enum manifest_return_code ret_code = (expr); \
29 if (ret_code != MANIFEST_SUCCESS) { \
30 return ret_code; \
31 } \
32 } while (0)
33
David Brazdilb856be62020-03-25 10:14:55 +000034#define VM_ID_MAX (HF_VM_ID_OFFSET + MAX_VMS - 1)
35#define VM_ID_MAX_DIGITS (5)
36#define VM_NAME_EXTRA_CHARS (3) /* "vm" + number + '\0' */
37#define VM_NAME_MAX_SIZE (VM_ID_MAX_DIGITS + VM_NAME_EXTRA_CHARS)
38static_assert(VM_NAME_MAX_SIZE <= STRING_MAX_SIZE,
39 "VM name does not fit into a struct string.");
40static_assert(VM_ID_MAX <= 99999, "Insufficient VM_NAME_BUF_SIZE");
41static_assert(HF_TEE_VM_ID > VM_ID_MAX,
Andrew Walbran9daa57e2019-09-27 13:33:20 +010042 "TrustZone VM ID clashes with normal VM range.");
David Brazdil7a462ec2019-08-15 12:27:47 +010043
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010044static inline size_t count_digits(ffa_vm_id_t vm_id)
David Brazdilb856be62020-03-25 10:14:55 +000045{
46 size_t digits = 0;
47
48 do {
49 digits++;
50 vm_id /= 10;
51 } while (vm_id);
52 return digits;
53}
54
David Brazdil7a462ec2019-08-15 12:27:47 +010055/**
56 * Generates a string with the two letters "vm" followed by an integer.
57 * Assumes `buf` is of size VM_NAME_BUF_SIZE.
58 */
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010059static void generate_vm_node_name(struct string *str, ffa_vm_id_t vm_id)
David Brazdil7a462ec2019-08-15 12:27:47 +010060{
61 static const char *digits = "0123456789";
David Brazdilb856be62020-03-25 10:14:55 +000062 size_t vm_id_digits = count_digits(vm_id);
63 char *base = str->data;
64 char *ptr = base + (VM_NAME_EXTRA_CHARS + vm_id_digits);
David Brazdil7a462ec2019-08-15 12:27:47 +010065
David Brazdilb856be62020-03-25 10:14:55 +000066 CHECK(vm_id_digits <= VM_ID_MAX_DIGITS);
David Brazdil7a462ec2019-08-15 12:27:47 +010067 *(--ptr) = '\0';
68 do {
69 *(--ptr) = digits[vm_id % 10];
70 vm_id /= 10;
71 } while (vm_id);
72 *(--ptr) = 'm';
73 *(--ptr) = 'v';
David Brazdilb856be62020-03-25 10:14:55 +000074 CHECK(ptr == base);
David Brazdil7a462ec2019-08-15 12:27:47 +010075}
76
Andrew Scullae9962e2019-10-03 16:51:16 +010077/**
Andrew Scullb2c3a242019-11-04 13:52:36 +000078 * Read a boolean property: true if present; false if not. If present, the value
79 * of the property must be empty else it is considered malformed.
Andrew Scullae9962e2019-10-03 16:51:16 +010080 */
Andrew Scullb2c3a242019-11-04 13:52:36 +000081static enum manifest_return_code read_bool(const struct fdt_node *node,
82 const char *property, bool *out)
Andrew Scullae9962e2019-10-03 16:51:16 +010083{
David Brazdilb856be62020-03-25 10:14:55 +000084 struct memiter data;
85 bool present = fdt_read_property(node, property, &data);
Andrew Scullae9962e2019-10-03 16:51:16 +010086
David Brazdilb856be62020-03-25 10:14:55 +000087 if (present && memiter_size(&data) != 0) {
Andrew Scullb2c3a242019-11-04 13:52:36 +000088 return MANIFEST_ERROR_MALFORMED_BOOLEAN;
89 }
90
91 *out = present;
92 return MANIFEST_SUCCESS;
Andrew Scullae9962e2019-10-03 16:51:16 +010093}
94
Andrew Scull72b43c02019-09-18 13:53:45 +010095static enum manifest_return_code read_string(const struct fdt_node *node,
David Brazdil136f2942019-09-23 14:11:03 +010096 const char *property,
97 struct string *out)
Andrew Scull72b43c02019-09-18 13:53:45 +010098{
David Brazdilb856be62020-03-25 10:14:55 +000099 struct memiter data;
Andrew Scull72b43c02019-09-18 13:53:45 +0100100
David Brazdilb856be62020-03-25 10:14:55 +0000101 if (!fdt_read_property(node, property, &data)) {
Andrew Scull72b43c02019-09-18 13:53:45 +0100102 return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
103 }
104
David Brazdilb856be62020-03-25 10:14:55 +0000105 switch (string_init(out, &data)) {
David Brazdil136f2942019-09-23 14:11:03 +0100106 case STRING_SUCCESS:
107 return MANIFEST_SUCCESS;
108 case STRING_ERROR_INVALID_INPUT:
109 return MANIFEST_ERROR_MALFORMED_STRING;
110 case STRING_ERROR_TOO_LONG:
111 return MANIFEST_ERROR_STRING_TOO_LONG;
112 }
Andrew Scull72b43c02019-09-18 13:53:45 +0100113}
114
115static enum manifest_return_code read_optional_string(
David Brazdil136f2942019-09-23 14:11:03 +0100116 const struct fdt_node *node, const char *property, struct string *out)
Andrew Scull72b43c02019-09-18 13:53:45 +0100117{
David Brazdil136f2942019-09-23 14:11:03 +0100118 enum manifest_return_code ret;
Andrew Scull72b43c02019-09-18 13:53:45 +0100119
David Brazdil136f2942019-09-23 14:11:03 +0100120 ret = read_string(node, property, out);
121 if (ret == MANIFEST_ERROR_PROPERTY_NOT_FOUND) {
122 string_init_empty(out);
123 ret = MANIFEST_SUCCESS;
Andrew Scull72b43c02019-09-18 13:53:45 +0100124 }
David Brazdil136f2942019-09-23 14:11:03 +0100125 return ret;
Andrew Scull72b43c02019-09-18 13:53:45 +0100126}
127
David Brazdil7a462ec2019-08-15 12:27:47 +0100128static enum manifest_return_code read_uint64(const struct fdt_node *node,
129 const char *property,
130 uint64_t *out)
131{
David Brazdilb856be62020-03-25 10:14:55 +0000132 struct memiter data;
David Brazdil7a462ec2019-08-15 12:27:47 +0100133
David Brazdilb856be62020-03-25 10:14:55 +0000134 if (!fdt_read_property(node, property, &data)) {
David Brazdil7a462ec2019-08-15 12:27:47 +0100135 return MANIFEST_ERROR_PROPERTY_NOT_FOUND;
136 }
137
David Brazdilb856be62020-03-25 10:14:55 +0000138 if (!fdt_parse_number(&data, memiter_size(&data), out)) {
David Brazdil7a462ec2019-08-15 12:27:47 +0100139 return MANIFEST_ERROR_MALFORMED_INTEGER;
140 }
141
142 return MANIFEST_SUCCESS;
143}
144
David Brazdil080ee312020-02-25 15:30:30 -0800145static enum manifest_return_code read_optional_uint64(
146 const struct fdt_node *node, const char *property,
147 uint64_t default_value, uint64_t *out)
148{
149 enum manifest_return_code ret;
150
151 ret = read_uint64(node, property, out);
152 if (ret == MANIFEST_ERROR_PROPERTY_NOT_FOUND) {
153 *out = default_value;
154 return MANIFEST_SUCCESS;
155 }
156 return ret;
157}
158
Olivier Deprez62d99e32020-01-09 15:58:07 +0100159static enum manifest_return_code read_uint32(const struct fdt_node *node,
160 const char *property,
161 uint32_t *out)
162{
163 uint64_t value;
164
165 TRY(read_uint64(node, property, &value));
166
167 if (value > UINT32_MAX) {
168 return MANIFEST_ERROR_INTEGER_OVERFLOW;
169 }
170
171 *out = (uint32_t)value;
172 return MANIFEST_SUCCESS;
173}
174
David Brazdil7a462ec2019-08-15 12:27:47 +0100175static enum manifest_return_code read_uint16(const struct fdt_node *node,
176 const char *property,
177 uint16_t *out)
178{
179 uint64_t value;
180
181 TRY(read_uint64(node, property, &value));
182
183 if (value > UINT16_MAX) {
184 return MANIFEST_ERROR_INTEGER_OVERFLOW;
185 }
186
187 *out = (uint16_t)value;
188 return MANIFEST_SUCCESS;
189}
190
Olivier Deprez62d99e32020-01-09 15:58:07 +0100191static enum manifest_return_code read_uint8(const struct fdt_node *node,
192 const char *property, uint8_t *out)
193{
194 uint64_t value;
195
196 TRY(read_uint64(node, property, &value));
197
198 if (value > UINT8_MAX) {
199 return MANIFEST_ERROR_INTEGER_OVERFLOW;
200 }
201
202 *out = (uint8_t)value;
203 return MANIFEST_SUCCESS;
204}
205
Andrew Scullae9962e2019-10-03 16:51:16 +0100206struct uint32list_iter {
207 struct memiter mem_it;
208};
209
210static enum manifest_return_code read_optional_uint32list(
211 const struct fdt_node *node, const char *property,
212 struct uint32list_iter *out)
213{
David Brazdilb856be62020-03-25 10:14:55 +0000214 struct memiter data;
Andrew Scullae9962e2019-10-03 16:51:16 +0100215
David Brazdilb856be62020-03-25 10:14:55 +0000216 if (!fdt_read_property(node, property, &data)) {
Andrew Scullae9962e2019-10-03 16:51:16 +0100217 memiter_init(&out->mem_it, NULL, 0);
218 return MANIFEST_SUCCESS;
219 }
220
David Brazdilb856be62020-03-25 10:14:55 +0000221 if ((memiter_size(&data) % sizeof(uint32_t)) != 0) {
Andrew Scullae9962e2019-10-03 16:51:16 +0100222 return MANIFEST_ERROR_MALFORMED_INTEGER_LIST;
223 }
224
David Brazdilb856be62020-03-25 10:14:55 +0000225 out->mem_it = data;
Andrew Scullae9962e2019-10-03 16:51:16 +0100226 return MANIFEST_SUCCESS;
227}
228
Andrew Scullae9962e2019-10-03 16:51:16 +0100229static bool uint32list_has_next(const struct uint32list_iter *list)
230{
231 return memiter_size(&list->mem_it) > 0;
232}
233
David Brazdil5ea99462020-03-25 13:01:47 +0000234static enum manifest_return_code uint32list_get_next(
235 struct uint32list_iter *list, uint32_t *out)
Andrew Scullae9962e2019-10-03 16:51:16 +0100236{
Andrew Scullae9962e2019-10-03 16:51:16 +0100237 uint64_t num;
238
239 CHECK(uint32list_has_next(list));
David Brazdilb856be62020-03-25 10:14:55 +0000240 if (!fdt_parse_number(&list->mem_it, sizeof(uint32_t), &num)) {
Andrew Scullae9962e2019-10-03 16:51:16 +0100241 return MANIFEST_ERROR_MALFORMED_INTEGER;
242 }
243
David Brazdil5ea99462020-03-25 13:01:47 +0000244 *out = (uint32_t)num;
245 return MANIFEST_SUCCESS;
Andrew Scullae9962e2019-10-03 16:51:16 +0100246}
247
Olivier Deprez62d99e32020-01-09 15:58:07 +0100248static enum manifest_return_code parse_vm_common(const struct fdt_node *node,
249 struct manifest_vm *vm,
250 ffa_vm_id_t vm_id)
David Brazdil7a462ec2019-08-15 12:27:47 +0100251{
Andrew Scullae9962e2019-10-03 16:51:16 +0100252 struct uint32list_iter smcs;
David Brazdil5ea99462020-03-25 13:01:47 +0000253 size_t idx;
Andrew Scullae9962e2019-10-03 16:51:16 +0100254
Olivier Deprez62d99e32020-01-09 15:58:07 +0100255 TRY(read_bool(node, "is_ffa_partition", &vm->is_ffa_partition));
256
David Brazdil136f2942019-09-23 14:11:03 +0100257 TRY(read_string(node, "debug_name", &vm->debug_name));
Andrew Scullae9962e2019-10-03 16:51:16 +0100258
259 TRY(read_optional_uint32list(node, "smc_whitelist", &smcs));
260 while (uint32list_has_next(&smcs) &&
261 vm->smc_whitelist.smc_count < MAX_SMCS) {
David Brazdil5ea99462020-03-25 13:01:47 +0000262 idx = vm->smc_whitelist.smc_count++;
263 TRY(uint32list_get_next(&smcs, &vm->smc_whitelist.smcs[idx]));
Andrew Scullae9962e2019-10-03 16:51:16 +0100264 }
265
266 if (uint32list_has_next(&smcs)) {
Andrew Walbran17eebf92020-02-05 16:35:49 +0000267 dlog_warning("%s SMC whitelist too long.\n", vm->debug_name);
Andrew Scullae9962e2019-10-03 16:51:16 +0100268 }
269
Andrew Scullb2c3a242019-11-04 13:52:36 +0000270 TRY(read_bool(node, "smc_whitelist_permissive",
271 &vm->smc_whitelist.permissive));
Andrew Scullae9962e2019-10-03 16:51:16 +0100272
Olivier Deprez62d99e32020-01-09 15:58:07 +0100273 if (vm_id != HF_PRIMARY_VM_ID) {
274 TRY(read_uint64(node, "mem_size", &vm->secondary.mem_size));
275 TRY(read_uint16(node, "vcpu_count", &vm->secondary.vcpu_count));
276 }
277
278 return MANIFEST_SUCCESS;
279}
280
281static enum manifest_return_code parse_vm(struct fdt_node *node,
282 struct manifest_vm *vm,
283 ffa_vm_id_t vm_id)
284{
285 TRY(read_optional_string(node, "kernel_filename",
286 &vm->kernel_filename));
287
David Brazdile6f83222019-09-23 14:47:37 +0100288 if (vm_id == HF_PRIMARY_VM_ID) {
289 TRY(read_optional_string(node, "ramdisk_filename",
290 &vm->primary.ramdisk_filename));
David Brazdil080ee312020-02-25 15:30:30 -0800291 TRY(read_optional_uint64(node, "boot_address",
292 MANIFEST_INVALID_ADDRESS,
293 &vm->primary.boot_address));
David Brazdil7a462ec2019-08-15 12:27:47 +0100294 }
Olivier Deprez62d99e32020-01-09 15:58:07 +0100295
David Brazdil7a462ec2019-08-15 12:27:47 +0100296 return MANIFEST_SUCCESS;
297}
298
Olivier Deprez62d99e32020-01-09 15:58:07 +0100299static enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
300 struct manifest_vm *vm)
301{
302 unsigned int i = 0;
303 struct uint32list_iter uuid;
304 uint32_t uuid_word;
305 struct fdt_node root;
306 struct fdt_node ffa_node;
307 struct string rxtx_node_name = STRING_INIT("rx_tx-info");
308
309 if (!fdt_find_node(fdt, "/", &root)) {
310 return MANIFEST_ERROR_NO_ROOT_NODE;
311 }
312
313 /* Check "compatible" property. */
314 if (!fdt_is_compatible(&root, "arm,ffa-manifest-1.0")) {
315 return MANIFEST_ERROR_NOT_COMPATIBLE;
316 }
317
318 TRY(read_uint32(&root, "ffa-version", &vm->sp.ffa_version));
319 dlog_verbose(" SP expected FF-A version %d.%d\n",
320 vm->sp.ffa_version >> 16, vm->sp.ffa_version & 0xffff);
321
322 TRY(read_optional_uint32list(&root, "uuid", &uuid));
323
324 while (uint32list_has_next(&uuid) && i < 4) {
325 TRY(uint32list_get_next(&uuid, &uuid_word));
326 vm->sp.uuid[i] = uuid_word;
327 i++;
328 }
329 dlog_verbose(" SP UUID %#x-%x-%x_%x\n", vm->sp.uuid[0], vm->sp.uuid[1],
330 vm->sp.uuid[2], vm->sp.uuid[3]);
331
332 TRY(read_uint16(&root, "execution-ctx-count",
333 &vm->sp.execution_ctx_count));
334 dlog_verbose(" SP number of execution context %d\n",
335 vm->sp.execution_ctx_count);
336
337 TRY(read_uint8(&root, "exception-level",
338 (uint8_t *)&vm->sp.run_time_el));
339 dlog_verbose(" SP run-time EL %d\n", vm->sp.run_time_el);
340
341 TRY(read_uint8(&root, "execution-state",
342 (uint8_t *)&vm->sp.execution_state));
343 dlog_verbose(" SP execution state %d\n", vm->sp.execution_state);
344
345 TRY(read_uint64(&root, "load-address", &vm->sp.load_addr));
346 dlog_verbose(" SP load address %#x\n", vm->sp.load_addr);
347
348 TRY(read_uint64(&root, "entrypoint-offset", &vm->sp.ep_offset));
349 dlog_verbose(" SP entry point offset %#x\n", vm->sp.ep_offset);
350
351 TRY(read_uint8(&root, "xlat-granule", (uint8_t *)&vm->sp.xlat_granule));
352 dlog_verbose(" SP translation granule %d\n", vm->sp.xlat_granule);
353
354 ffa_node = root;
355 if (fdt_find_child(&ffa_node, &rxtx_node_name)) {
356 if (!fdt_is_compatible(&ffa_node,
357 "arm,ffa-manifest-rx_tx-buffer")) {
358 return MANIFEST_ERROR_NOT_COMPATIBLE;
359 }
360
361 TRY(read_uint64(&ffa_node, "base-address",
362 &vm->sp.rxtx.base_address));
363
364 TRY(read_uint16(&ffa_node, "pages-count",
365 &vm->sp.rxtx.pages_count));
366
367 TRY(read_uint16(&ffa_node, "attributes",
368 &vm->sp.rxtx.attributes));
369
370 vm->sp.rxtx.rxtx_found = true;
371 }
372
373 TRY(read_uint8(&root, "messaging-method",
374 (uint8_t *)&vm->sp.messaging_method));
375 dlog_verbose(" SP messaging method %d\n", vm->sp.messaging_method);
376
377 return MANIFEST_SUCCESS;
378}
379
380static enum manifest_return_code sanity_check_ffa_manifest(
381 struct manifest_vm *vm)
382{
383 uint16_t ffa_version_major;
384 uint16_t ffa_version_minor;
385 enum manifest_return_code ret_code = MANIFEST_SUCCESS;
386 const char *error_string = "specified in manifest is unsupported";
387
388 /* ensure that the SPM version is compatible */
389 ffa_version_major =
390 (vm->sp.ffa_version & 0xffff0000) >> FFA_VERSION_MAJOR_OFFSET;
391 ffa_version_minor = vm->sp.ffa_version & 0xffff;
392
393 if (ffa_version_major != FFA_VERSION_MAJOR ||
394 ffa_version_minor > FFA_VERSION_MINOR) {
395 dlog_error("FF-A partition manifest version %s: %d.%d\n",
396 error_string, ffa_version_major, ffa_version_minor);
397 ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
398 }
399
400 if (vm->sp.xlat_granule != PAGE_4KB) {
401 dlog_error("Translation granule %s: %d\n", error_string,
402 vm->sp.xlat_granule);
403 ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
404 }
405
406 if (vm->sp.execution_state != AARCH64) {
407 dlog_error("Execution state %s: %d\n", error_string,
408 vm->sp.execution_state);
409 ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
410 }
411
412 if (vm->sp.run_time_el != EL1 && vm->sp.run_time_el != S_EL1) {
413 dlog_error("Exception level %s: %d\n", error_string,
414 vm->sp.run_time_el);
415 ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
416 }
417
418 if (vm->sp.messaging_method != INDIRECT_MESSAGING) {
419 dlog_error("Messaging method %s: %x\n", error_string,
420 vm->sp.messaging_method);
421 ret_code = MANIFEST_ERROR_NOT_COMPATIBLE;
422 }
423
424 return ret_code;
425}
426
427static enum manifest_return_code parse_ffa_partition_package(
428 struct mm_stage1_locked stage1_locked, struct fdt_node *node,
429 struct manifest_vm *vm, ffa_vm_id_t vm_id, struct mpool *ppool)
430{
431 enum manifest_return_code ret = MANIFEST_ERROR_NOT_COMPATIBLE;
432 uintpaddr_t sp_pkg_addr;
433 paddr_t sp_pkg_start;
434 paddr_t sp_pkg_end;
435 struct sp_pkg_header *sp_pkg;
436 size_t sp_header_dtb_size;
437 paddr_t sp_dtb_addr;
438 struct fdt sp_fdt;
439
440 /*
441 * This must have been hinted as being an FF-A partition,
442 * return straight with failure if this is not the case.
443 */
444 if (!vm->is_ffa_partition) {
445 return MANIFEST_ERROR_NOT_COMPATIBLE;
446 }
447
448 TRY(read_uint64(node, "load_address", &sp_pkg_addr));
449 if (!is_aligned(sp_pkg_addr, PAGE_SIZE)) {
450 return MANIFEST_ERROR_NOT_COMPATIBLE;
451 }
452
453 /* Map top of SP package as a single page to extract the header */
454 sp_pkg_start = pa_init(sp_pkg_addr);
455 sp_pkg_end = pa_add(sp_pkg_start, PAGE_SIZE);
456 sp_pkg = mm_identity_map(stage1_locked, sp_pkg_start,
457 pa_add(sp_pkg_start, PAGE_SIZE), MM_MODE_R,
458 ppool);
459 CHECK(sp_pkg != NULL);
460
461 dlog_verbose("SP package load address %#x\n", sp_pkg_addr);
462
463 if (sp_pkg->magic != SP_PKG_HEADER_MAGIC) {
464 dlog_error("Invalid SP package magic.\n");
465 goto exit_unmap;
466 }
467
468 if (sp_pkg->version != SP_PKG_HEADER_VERSION) {
469 dlog_error("Invalid SP package version.\n");
470 goto exit_unmap;
471 }
472
473 /* Expect SP DTB to immediately follow header */
474 if (sp_pkg->pm_offset != sizeof(struct sp_pkg_header)) {
475 dlog_error("Invalid SP package manifest offset.\n");
476 goto exit_unmap;
477 }
478
479 sp_header_dtb_size = align_up(
480 sp_pkg->pm_size + sizeof(struct sp_pkg_header), PAGE_SIZE);
481 if ((vm_id != HF_PRIMARY_VM_ID) &&
482 (sp_header_dtb_size >= vm->secondary.mem_size)) {
483 dlog_error("Invalid SP package header or DT size.\n");
484 goto exit_unmap;
485 }
486
487 if (sp_header_dtb_size > PAGE_SIZE) {
488 /* Map remainder of header + DTB */
489 sp_pkg_end = pa_add(sp_pkg_start, sp_header_dtb_size);
490
491 sp_pkg = mm_identity_map(stage1_locked, sp_pkg_start,
492 sp_pkg_end, MM_MODE_R, ppool);
493 CHECK(sp_pkg != NULL);
494 }
495
496 sp_dtb_addr = pa_add(sp_pkg_start, sp_pkg->pm_offset);
497 if (!fdt_init_from_ptr(&sp_fdt, (void *)sp_dtb_addr.pa,
498 sp_pkg->pm_size)) {
499 dlog_error("FDT failed validation.\n");
500 goto exit_unmap;
501 }
502
503 ret = parse_ffa_manifest(&sp_fdt, vm);
504 if (ret != MANIFEST_SUCCESS) {
505 goto exit_unmap;
506 }
507
508 ret = sanity_check_ffa_manifest(vm);
509
510exit_unmap:
511 CHECK(mm_unmap(stage1_locked, sp_pkg_start, sp_pkg_end, ppool));
512
513 return ret;
514}
515
David Brazdil7a462ec2019-08-15 12:27:47 +0100516/**
517 * Parse manifest from FDT.
518 */
Olivier Deprez62d99e32020-01-09 15:58:07 +0100519enum manifest_return_code manifest_init(struct mm_stage1_locked stage1_locked,
520 struct manifest *manifest,
521 struct memiter *manifest_fdt,
522 struct mpool *ppool)
David Brazdil7a462ec2019-08-15 12:27:47 +0100523{
David Brazdilb856be62020-03-25 10:14:55 +0000524 struct string vm_name;
525 struct fdt fdt;
David Brazdil7a462ec2019-08-15 12:27:47 +0100526 struct fdt_node hyp_node;
527 size_t i = 0;
528 bool found_primary_vm = false;
529
530 memset_s(manifest, sizeof(*manifest), 0, sizeof(*manifest));
531
David Brazdilb856be62020-03-25 10:14:55 +0000532 if (!fdt_init_from_memiter(&fdt, manifest_fdt)) {
533 return MANIFEST_ERROR_FILE_SIZE; /* TODO */
David Brazdila2358d42020-01-27 18:51:38 +0000534 }
535
David Brazdil7a462ec2019-08-15 12:27:47 +0100536 /* Find hypervisor node. */
David Brazdilb856be62020-03-25 10:14:55 +0000537 if (!fdt_find_node(&fdt, "/hypervisor", &hyp_node)) {
David Brazdil7a462ec2019-08-15 12:27:47 +0100538 return MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE;
539 }
540
David Brazdil74e9c3b2019-08-28 11:09:08 +0100541 /* Check "compatible" property. */
David Brazdilf4925382020-03-25 13:33:51 +0000542 if (!fdt_is_compatible(&hyp_node, "hafnium,hafnium")) {
David Brazdil74e9c3b2019-08-28 11:09:08 +0100543 return MANIFEST_ERROR_NOT_COMPATIBLE;
544 }
545
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100546 TRY(read_bool(&hyp_node, "ffa_tee", &manifest->ffa_tee_enabled));
Andrew Walbran41a49d82020-01-10 17:46:38 +0000547
David Brazdil7a462ec2019-08-15 12:27:47 +0100548 /* Iterate over reserved VM IDs and check no such nodes exist. */
549 for (i = 0; i < HF_VM_ID_OFFSET; i++) {
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100550 ffa_vm_id_t vm_id = (ffa_vm_id_t)i;
David Brazdil7a462ec2019-08-15 12:27:47 +0100551 struct fdt_node vm_node = hyp_node;
David Brazdil7a462ec2019-08-15 12:27:47 +0100552
David Brazdilb856be62020-03-25 10:14:55 +0000553 generate_vm_node_name(&vm_name, vm_id);
554 if (fdt_find_child(&vm_node, &vm_name)) {
David Brazdil7a462ec2019-08-15 12:27:47 +0100555 return MANIFEST_ERROR_RESERVED_VM_ID;
556 }
557 }
558
559 /* Iterate over VM nodes until we find one that does not exist. */
560 for (i = 0; i <= MAX_VMS; ++i) {
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100561 ffa_vm_id_t vm_id = HF_VM_ID_OFFSET + i;
David Brazdil7a462ec2019-08-15 12:27:47 +0100562 struct fdt_node vm_node = hyp_node;
David Brazdil7a462ec2019-08-15 12:27:47 +0100563
David Brazdilb856be62020-03-25 10:14:55 +0000564 generate_vm_node_name(&vm_name, vm_id);
565 if (!fdt_find_child(&vm_node, &vm_name)) {
David Brazdil7a462ec2019-08-15 12:27:47 +0100566 break;
567 }
568
569 if (i == MAX_VMS) {
570 return MANIFEST_ERROR_TOO_MANY_VMS;
571 }
572
573 if (vm_id == HF_PRIMARY_VM_ID) {
574 CHECK(found_primary_vm == false); /* sanity check */
575 found_primary_vm = true;
576 }
577
David Brazdil0251b942019-09-10 15:59:50 +0100578 manifest->vm_count = i + 1;
Olivier Deprez62d99e32020-01-09 15:58:07 +0100579
580 TRY(parse_vm_common(&vm_node, &manifest->vm[i], vm_id));
581
582 if (manifest->vm[i].is_ffa_partition) {
583 TRY(parse_ffa_partition_package(stage1_locked, &vm_node,
584 &manifest->vm[i], vm_id,
585 ppool));
586 } else {
587 TRY(parse_vm(&vm_node, &manifest->vm[i], vm_id));
588 }
David Brazdil7a462ec2019-08-15 12:27:47 +0100589 }
590
591 if (!found_primary_vm) {
592 return MANIFEST_ERROR_NO_PRIMARY_VM;
593 }
594
595 return MANIFEST_SUCCESS;
596}
597
598const char *manifest_strerror(enum manifest_return_code ret_code)
599{
600 switch (ret_code) {
601 case MANIFEST_SUCCESS:
602 return "Success";
David Brazdila2358d42020-01-27 18:51:38 +0000603 case MANIFEST_ERROR_FILE_SIZE:
604 return "Total size in header does not match file size";
Olivier Deprez62d99e32020-01-09 15:58:07 +0100605 case MANIFEST_ERROR_MALFORMED_DTB:
606 return "Malformed device tree blob";
David Brazdila2358d42020-01-27 18:51:38 +0000607 case MANIFEST_ERROR_NO_ROOT_NODE:
608 return "Could not find root node in manifest";
David Brazdil7a462ec2019-08-15 12:27:47 +0100609 case MANIFEST_ERROR_NO_HYPERVISOR_FDT_NODE:
610 return "Could not find \"hypervisor\" node in manifest";
David Brazdil74e9c3b2019-08-28 11:09:08 +0100611 case MANIFEST_ERROR_NOT_COMPATIBLE:
612 return "Hypervisor manifest entry not compatible with Hafnium";
David Brazdil7a462ec2019-08-15 12:27:47 +0100613 case MANIFEST_ERROR_RESERVED_VM_ID:
614 return "Manifest defines a VM with a reserved ID";
615 case MANIFEST_ERROR_NO_PRIMARY_VM:
616 return "Manifest does not contain a primary VM entry";
617 case MANIFEST_ERROR_TOO_MANY_VMS:
618 return "Manifest specifies more VMs than Hafnium has "
619 "statically allocated space for";
620 case MANIFEST_ERROR_PROPERTY_NOT_FOUND:
621 return "Property not found";
622 case MANIFEST_ERROR_MALFORMED_STRING:
623 return "Malformed string property";
David Brazdil0dbb41f2019-09-09 18:03:35 +0100624 case MANIFEST_ERROR_STRING_TOO_LONG:
625 return "String too long";
David Brazdil7a462ec2019-08-15 12:27:47 +0100626 case MANIFEST_ERROR_MALFORMED_INTEGER:
627 return "Malformed integer property";
628 case MANIFEST_ERROR_INTEGER_OVERFLOW:
629 return "Integer overflow";
Andrew Scullae9962e2019-10-03 16:51:16 +0100630 case MANIFEST_ERROR_MALFORMED_INTEGER_LIST:
631 return "Malformed integer list property";
Andrew Scullb2c3a242019-11-04 13:52:36 +0000632 case MANIFEST_ERROR_MALFORMED_BOOLEAN:
633 return "Malformed boolean property";
David Brazdil7a462ec2019-08-15 12:27:47 +0100634 }
635
636 panic("Unexpected manifest return code.");
637}