10cb64d01SAchin Gupta /* 20cb64d01SAchin Gupta * Copyright (c) 2020, Arm Limited. All rights reserved. 30cb64d01SAchin Gupta * 40cb64d01SAchin Gupta * SPDX-License-Identifier: BSD-3-Clause 50cb64d01SAchin Gupta */ 60cb64d01SAchin Gupta 70cb64d01SAchin Gupta #include <assert.h> 852696946SOlivier Deprez #include <errno.h> 90cb64d01SAchin Gupta #include <string.h> 100cb64d01SAchin Gupta #include <libfdt.h> 110cb64d01SAchin Gupta 120cb64d01SAchin Gupta #include <common/debug.h> 130cb64d01SAchin Gupta #include <common/fdt_wrappers.h> 1423d5ba86SOlivier Deprez #include <lib/xlat_tables/xlat_tables_v2.h> 150cb64d01SAchin Gupta #include <platform_def.h> 160cb64d01SAchin Gupta #include <services/spm_core_manifest.h> 170cb64d01SAchin Gupta 1852696946SOlivier Deprez #define ATTRIBUTE_ROOT_NODE_STR "attribute" 1952696946SOlivier Deprez 200cb64d01SAchin Gupta /******************************************************************************* 2152696946SOlivier Deprez * SPMC attribute node parser 220cb64d01SAchin Gupta ******************************************************************************/ 2352696946SOlivier Deprez static int manifest_parse_attribute(spmc_manifest_attribute_t *attr, 240cb64d01SAchin Gupta const void *fdt, 250cb64d01SAchin Gupta int node) 260cb64d01SAchin Gupta { 27ff4e6c35SAndre Przywara uint32_t val32; 2852696946SOlivier Deprez int rc; 290cb64d01SAchin Gupta 3052696946SOlivier Deprez assert((attr != NULL) && (fdt != NULL)); 310cb64d01SAchin Gupta 32ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version); 3352696946SOlivier Deprez if (rc != 0) { 34*662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n", 3552696946SOlivier Deprez "major"); 3652696946SOlivier Deprez return rc; 370cb64d01SAchin Gupta } 380cb64d01SAchin Gupta 39ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version); 4052696946SOlivier Deprez if (rc != 0) { 41*662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n", 4252696946SOlivier Deprez "minor"); 4352696946SOlivier Deprez return rc; 440cb64d01SAchin Gupta } 450cb64d01SAchin Gupta 46ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "spmc_id", &val32); 4752696946SOlivier Deprez if (rc != 0) { 48ac03ac5eSMax Shvetsov ERROR("Missing SPMC ID in manifest.\n"); 4952696946SOlivier Deprez return rc; 50ac03ac5eSMax Shvetsov } 5152696946SOlivier Deprez 5252696946SOlivier Deprez attr->spmc_id = val32 & 0xffff; 53ac03ac5eSMax Shvetsov 54ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state); 5552696946SOlivier Deprez if (rc != 0) { 5652696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 5752696946SOlivier Deprez "Execution state"); 5852696946SOlivier Deprez } 590cb64d01SAchin Gupta 60ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size); 6152696946SOlivier Deprez if (rc != 0) { 6252696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 6352696946SOlivier Deprez "Binary size"); 6452696946SOlivier Deprez } 650cb64d01SAchin Gupta 66ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address); 6752696946SOlivier Deprez if (rc != 0) { 6852696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 6952696946SOlivier Deprez "Load address"); 7052696946SOlivier Deprez } 710cb64d01SAchin Gupta 72ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint); 7352696946SOlivier Deprez if (rc != 0) { 7452696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 7552696946SOlivier Deprez "Entry point"); 7652696946SOlivier Deprez } 770cb64d01SAchin Gupta 7852696946SOlivier Deprez VERBOSE("SPM Core manifest attribute section:\n"); 7952696946SOlivier Deprez VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version); 8052696946SOlivier Deprez VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id); 810cb64d01SAchin Gupta VERBOSE(" binary_size: 0x%x\n", attr->binary_size); 820cb64d01SAchin Gupta VERBOSE(" load_address: 0x%llx\n", attr->load_address); 830cb64d01SAchin Gupta VERBOSE(" entrypoint: 0x%llx\n", attr->entrypoint); 840cb64d01SAchin Gupta 850cb64d01SAchin Gupta return 0; 860cb64d01SAchin Gupta } 870cb64d01SAchin Gupta 880cb64d01SAchin Gupta /******************************************************************************* 890cb64d01SAchin Gupta * Root node handler 900cb64d01SAchin Gupta ******************************************************************************/ 9152696946SOlivier Deprez static int manifest_parse_root(spmc_manifest_attribute_t *manifest, 920cb64d01SAchin Gupta const void *fdt, 930cb64d01SAchin Gupta int root) 940cb64d01SAchin Gupta { 950cb64d01SAchin Gupta int node; 960cb64d01SAchin Gupta 9752696946SOlivier Deprez assert(manifest != NULL); 9852696946SOlivier Deprez 9952696946SOlivier Deprez node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR, 10052696946SOlivier Deprez sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1); 1010cb64d01SAchin Gupta if (node < 0) { 10252696946SOlivier Deprez ERROR("Root node doesn't contain subnode '%s'\n", 10352696946SOlivier Deprez ATTRIBUTE_ROOT_NODE_STR); 10452696946SOlivier Deprez return node; 1050cb64d01SAchin Gupta } 1060cb64d01SAchin Gupta 1070cb64d01SAchin Gupta return manifest_parse_attribute(manifest, fdt, node); 1080cb64d01SAchin Gupta } 1090cb64d01SAchin Gupta 1100cb64d01SAchin Gupta /******************************************************************************* 11152696946SOlivier Deprez * Platform handler to parse a SPM Core manifest. 1120cb64d01SAchin Gupta ******************************************************************************/ 11352696946SOlivier Deprez int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest, 11423d5ba86SOlivier Deprez const void *pm_addr) 1150cb64d01SAchin Gupta { 11623d5ba86SOlivier Deprez int rc, unmap_ret; 11723d5ba86SOlivier Deprez uintptr_t pm_base, pm_base_align; 11823d5ba86SOlivier Deprez size_t mapped_size; 1190cb64d01SAchin Gupta 1200cb64d01SAchin Gupta assert(manifest != NULL); 12123d5ba86SOlivier Deprez assert(pm_addr != NULL); 1220cb64d01SAchin Gupta 12323d5ba86SOlivier Deprez /* 12423d5ba86SOlivier Deprez * Assume TOS_FW_CONFIG is not necessarily aligned to a page 12523d5ba86SOlivier Deprez * boundary, thus calculate the remaining space between SPMC 12623d5ba86SOlivier Deprez * manifest start address and upper page limit. 12723d5ba86SOlivier Deprez * 12823d5ba86SOlivier Deprez */ 12923d5ba86SOlivier Deprez pm_base = (uintptr_t)pm_addr; 13023d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, UP); 13123d5ba86SOlivier Deprez mapped_size = pm_base_align - pm_base; 1320cb64d01SAchin Gupta 13323d5ba86SOlivier Deprez /* Check space within the page at least maps the FDT header */ 13423d5ba86SOlivier Deprez if (mapped_size < sizeof(struct fdt_header)) { 13523d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest.\n"); 13623d5ba86SOlivier Deprez return -EINVAL; 13723d5ba86SOlivier Deprez } 13823d5ba86SOlivier Deprez 13923d5ba86SOlivier Deprez /* Map first SPMC manifest page in the SPMD translation regime */ 14023d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, DOWN); 14123d5ba86SOlivier Deprez rc = mmap_add_dynamic_region((unsigned long long)pm_base_align, 14223d5ba86SOlivier Deprez pm_base_align, 14323d5ba86SOlivier Deprez PAGE_SIZE, 14423d5ba86SOlivier Deprez MT_RO_DATA); 1450cb64d01SAchin Gupta if (rc != 0) { 14623d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest (%d).\n", rc); 14752696946SOlivier Deprez return rc; 1480cb64d01SAchin Gupta } 1490cb64d01SAchin Gupta 15023d5ba86SOlivier Deprez rc = fdt_check_header(pm_addr); 15123d5ba86SOlivier Deprez if (rc != 0) { 15223d5ba86SOlivier Deprez ERROR("Wrong format for SPM Core manifest (%d).\n", rc); 15323d5ba86SOlivier Deprez goto exit_unmap; 15423d5ba86SOlivier Deprez } 15523d5ba86SOlivier Deprez 15623d5ba86SOlivier Deprez /* Check SPMC manifest fits within the upper mapped page boundary */ 15723d5ba86SOlivier Deprez if (mapped_size < fdt_totalsize(pm_addr)) { 15823d5ba86SOlivier Deprez ERROR("SPM Core manifest too large.\n"); 15923d5ba86SOlivier Deprez rc = -EINVAL; 16023d5ba86SOlivier Deprez goto exit_unmap; 16123d5ba86SOlivier Deprez } 16223d5ba86SOlivier Deprez 16323d5ba86SOlivier Deprez VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr); 16423d5ba86SOlivier Deprez 16523d5ba86SOlivier Deprez rc = fdt_node_offset_by_compatible(pm_addr, -1, 166*662af36dSJ-Alves "arm,ffa-core-manifest-1.0"); 16752696946SOlivier Deprez if (rc < 0) { 16852696946SOlivier Deprez ERROR("Unrecognized SPM Core manifest\n"); 16923d5ba86SOlivier Deprez goto exit_unmap; 1700cb64d01SAchin Gupta } 1710cb64d01SAchin Gupta 17223d5ba86SOlivier Deprez rc = manifest_parse_root(manifest, pm_addr, rc); 17323d5ba86SOlivier Deprez 17423d5ba86SOlivier Deprez exit_unmap: 17523d5ba86SOlivier Deprez unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE); 17623d5ba86SOlivier Deprez if (unmap_ret != 0) { 17723d5ba86SOlivier Deprez ERROR("Error while unmapping SPM Core manifest (%d).\n", 17823d5ba86SOlivier Deprez unmap_ret); 17923d5ba86SOlivier Deprez if (rc == 0) { 18023d5ba86SOlivier Deprez rc = unmap_ret; 18123d5ba86SOlivier Deprez } 18223d5ba86SOlivier Deprez } 18323d5ba86SOlivier Deprez 18423d5ba86SOlivier Deprez return rc; 1850cb64d01SAchin Gupta } 186