123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /*
- * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <assert.h>
- #include <errno.h>
- #include <inttypes.h>
- #include <libfdt.h>
- #include <stdint.h>
- #include <string.h>
- #include <common/bl_common.h>
- #include <common/debug.h>
- #include <common/fdt_wrappers.h>
- #include <lib/xlat_tables/xlat_tables_v2.h>
- #include <platform_def.h>
- #include <services/spm_core_manifest.h>
- #define ATTRIBUTE_ROOT_NODE_STR "attribute"
- /*******************************************************************************
- * SPMC attribute node parser
- ******************************************************************************/
- static int manifest_parse_attribute(spmc_manifest_attribute_t *attr,
- const void *fdt,
- int node)
- {
- uint32_t val32;
- int rc;
- assert((attr != NULL) && (fdt != NULL));
- rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version);
- if (rc != 0) {
- ERROR("Missing FFA %s version in SPM Core manifest.\n",
- "major");
- return rc;
- }
- rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version);
- if (rc != 0) {
- ERROR("Missing FFA %s version in SPM Core manifest.\n",
- "minor");
- return rc;
- }
- rc = fdt_read_uint32(fdt, node, "spmc_id", &val32);
- if (rc != 0) {
- ERROR("Missing SPMC ID in manifest.\n");
- return rc;
- }
- attr->spmc_id = val32 & 0xffff;
- rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state);
- if (rc != 0) {
- NOTICE("%s not specified in SPM Core manifest.\n",
- "Execution state");
- }
- rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size);
- if (rc != 0) {
- NOTICE("%s not specified in SPM Core manifest.\n",
- "Binary size");
- }
- rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address);
- if (rc != 0) {
- NOTICE("%s not specified in SPM Core manifest.\n",
- "Load address");
- }
- rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint);
- if (rc != 0) {
- NOTICE("%s not specified in SPM Core manifest.\n",
- "Entry point");
- }
- VERBOSE("SPM Core manifest attribute section:\n");
- VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version);
- VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id);
- VERBOSE(" binary_size: 0x%x\n", attr->binary_size);
- VERBOSE(" load_address: 0x%" PRIx64 "\n", attr->load_address);
- VERBOSE(" entrypoint: 0x%" PRIx64 "\n", attr->entrypoint);
- return 0;
- }
- /*******************************************************************************
- * Root node handler
- ******************************************************************************/
- static int manifest_parse_root(spmc_manifest_attribute_t *manifest,
- const void *fdt,
- int root)
- {
- int node;
- assert(manifest != NULL);
- node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR,
- sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1);
- if (node < 0) {
- ERROR("Root node doesn't contain subnode '%s'\n",
- ATTRIBUTE_ROOT_NODE_STR);
- return node;
- }
- return manifest_parse_attribute(manifest, fdt, node);
- }
- /*******************************************************************************
- * Platform handler to parse a SPM Core manifest.
- ******************************************************************************/
- int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
- const void *pm_addr)
- {
- int rc, unmap_ret;
- uintptr_t pm_base, pm_base_align;
- size_t mapped_size;
- assert(manifest != NULL);
- assert(pm_addr != NULL);
- /*
- * Assume TOS_FW_CONFIG is not necessarily aligned to a page
- * boundary, thus calculate the remaining space between SPMC
- * manifest start address and upper page limit.
- *
- */
- pm_base = (uintptr_t)pm_addr;
- pm_base_align = page_align(pm_base, UP);
- if (pm_base == pm_base_align) {
- /* Page aligned */
- mapped_size = PAGE_SIZE;
- } else {
- mapped_size = pm_base_align - pm_base;
- }
- /* Check space within the page at least maps the FDT header */
- if (mapped_size < sizeof(struct fdt_header)) {
- ERROR("Error while mapping SPM Core manifest.\n");
- return -EINVAL;
- }
- /* Map first SPMC manifest page in the SPMD translation regime */
- pm_base_align = page_align(pm_base, DOWN);
- rc = mmap_add_dynamic_region((unsigned long long)pm_base_align,
- pm_base_align,
- PAGE_SIZE,
- MT_RO_DATA | EL3_PAS);
- if (rc != 0) {
- ERROR("Error while mapping SPM Core manifest (%d).\n", rc);
- return rc;
- }
- rc = fdt_check_header(pm_addr);
- if (rc != 0) {
- ERROR("Wrong format for SPM Core manifest (%d).\n", rc);
- goto exit_unmap;
- }
- /* Check SPMC manifest fits within the upper mapped page boundary */
- if (mapped_size < fdt_totalsize(pm_addr)) {
- ERROR("SPM Core manifest too large.\n");
- rc = -EINVAL;
- goto exit_unmap;
- }
- VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr);
- rc = fdt_node_offset_by_compatible(pm_addr, -1,
- "arm,ffa-core-manifest-1.0");
- if (rc < 0) {
- ERROR("Unrecognized SPM Core manifest\n");
- goto exit_unmap;
- }
- rc = manifest_parse_root(manifest, pm_addr, rc);
- exit_unmap:
- unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE);
- if (unmap_ret != 0) {
- ERROR("Error while unmapping SPM Core manifest (%d).\n",
- unmap_ret);
- if (rc == 0) {
- rc = unmap_ret;
- }
- }
- return rc;
- }
|