summaryrefslogtreecommitdiffstats
path: root/plat/common/plat_spmd_manifest.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plat/common/plat_spmd_manifest.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/plat/common/plat_spmd_manifest.c b/plat/common/plat_spmd_manifest.c
new file mode 100644
index 0000000..b1fc13c
--- /dev/null
+++ b/plat/common/plat_spmd_manifest.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2020, 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);
+ 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;
+}