10cb64d01SAchin Gupta /* 2*8c829a92SManish V Badarkhe * Copyright (c) 2020-2023, 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> 94ce3e99aSScott Branden #include <inttypes.h> 100cb64d01SAchin Gupta #include <libfdt.h> 114ce3e99aSScott Branden #include <stdint.h> 124ce3e99aSScott Branden #include <string.h> 130cb64d01SAchin Gupta 14cb7b9db1SVarun Wadekar #include <common/bl_common.h> 150cb64d01SAchin Gupta #include <common/debug.h> 160cb64d01SAchin Gupta #include <common/fdt_wrappers.h> 1723d5ba86SOlivier Deprez #include <lib/xlat_tables/xlat_tables_v2.h> 180cb64d01SAchin Gupta #include <platform_def.h> 190cb64d01SAchin Gupta #include <services/spm_core_manifest.h> 200cb64d01SAchin Gupta 2152696946SOlivier Deprez #define ATTRIBUTE_ROOT_NODE_STR "attribute" 2252696946SOlivier Deprez 230cb64d01SAchin Gupta /******************************************************************************* 2452696946SOlivier Deprez * SPMC attribute node parser 250cb64d01SAchin Gupta ******************************************************************************/ 2652696946SOlivier Deprez static int manifest_parse_attribute(spmc_manifest_attribute_t *attr, 270cb64d01SAchin Gupta const void *fdt, 280cb64d01SAchin Gupta int node) 290cb64d01SAchin Gupta { 30ff4e6c35SAndre Przywara uint32_t val32; 3152696946SOlivier Deprez int rc; 320cb64d01SAchin Gupta 3352696946SOlivier Deprez assert((attr != NULL) && (fdt != NULL)); 340cb64d01SAchin Gupta 35ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version); 3652696946SOlivier Deprez if (rc != 0) { 37662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n", 3852696946SOlivier Deprez "major"); 3952696946SOlivier Deprez return rc; 400cb64d01SAchin Gupta } 410cb64d01SAchin Gupta 42ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version); 4352696946SOlivier Deprez if (rc != 0) { 44662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n", 4552696946SOlivier Deprez "minor"); 4652696946SOlivier Deprez return rc; 470cb64d01SAchin Gupta } 480cb64d01SAchin Gupta 49ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "spmc_id", &val32); 5052696946SOlivier Deprez if (rc != 0) { 51ac03ac5eSMax Shvetsov ERROR("Missing SPMC ID in manifest.\n"); 5252696946SOlivier Deprez return rc; 53ac03ac5eSMax Shvetsov } 5452696946SOlivier Deprez 5552696946SOlivier Deprez attr->spmc_id = val32 & 0xffff; 56ac03ac5eSMax Shvetsov 57ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state); 5852696946SOlivier Deprez if (rc != 0) { 5952696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 6052696946SOlivier Deprez "Execution state"); 6152696946SOlivier Deprez } 620cb64d01SAchin Gupta 63ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size); 6452696946SOlivier Deprez if (rc != 0) { 6552696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 6652696946SOlivier Deprez "Binary size"); 6752696946SOlivier Deprez } 680cb64d01SAchin Gupta 69ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address); 7052696946SOlivier Deprez if (rc != 0) { 7152696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 7252696946SOlivier Deprez "Load address"); 7352696946SOlivier Deprez } 740cb64d01SAchin Gupta 75ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint); 7652696946SOlivier Deprez if (rc != 0) { 7752696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 7852696946SOlivier Deprez "Entry point"); 7952696946SOlivier Deprez } 800cb64d01SAchin Gupta 8152696946SOlivier Deprez VERBOSE("SPM Core manifest attribute section:\n"); 8252696946SOlivier Deprez VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version); 8352696946SOlivier Deprez VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id); 840cb64d01SAchin Gupta VERBOSE(" binary_size: 0x%x\n", attr->binary_size); 854ce3e99aSScott Branden VERBOSE(" load_address: 0x%" PRIx64 "\n", attr->load_address); 864ce3e99aSScott Branden VERBOSE(" entrypoint: 0x%" PRIx64 "\n", attr->entrypoint); 870cb64d01SAchin Gupta 880cb64d01SAchin Gupta return 0; 890cb64d01SAchin Gupta } 900cb64d01SAchin Gupta 910cb64d01SAchin Gupta /******************************************************************************* 920cb64d01SAchin Gupta * Root node handler 930cb64d01SAchin Gupta ******************************************************************************/ 9452696946SOlivier Deprez static int manifest_parse_root(spmc_manifest_attribute_t *manifest, 950cb64d01SAchin Gupta const void *fdt, 960cb64d01SAchin Gupta int root) 970cb64d01SAchin Gupta { 980cb64d01SAchin Gupta int node; 990cb64d01SAchin Gupta 10052696946SOlivier Deprez assert(manifest != NULL); 10152696946SOlivier Deprez 10252696946SOlivier Deprez node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR, 10352696946SOlivier Deprez sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1); 1040cb64d01SAchin Gupta if (node < 0) { 10552696946SOlivier Deprez ERROR("Root node doesn't contain subnode '%s'\n", 10652696946SOlivier Deprez ATTRIBUTE_ROOT_NODE_STR); 10752696946SOlivier Deprez return node; 1080cb64d01SAchin Gupta } 1090cb64d01SAchin Gupta 1100cb64d01SAchin Gupta return manifest_parse_attribute(manifest, fdt, node); 1110cb64d01SAchin Gupta } 1120cb64d01SAchin Gupta 1130cb64d01SAchin Gupta /******************************************************************************* 11452696946SOlivier Deprez * Platform handler to parse a SPM Core manifest. 1150cb64d01SAchin Gupta ******************************************************************************/ 11652696946SOlivier Deprez int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest, 11723d5ba86SOlivier Deprez const void *pm_addr) 1180cb64d01SAchin Gupta { 11923d5ba86SOlivier Deprez int rc, unmap_ret; 12023d5ba86SOlivier Deprez uintptr_t pm_base, pm_base_align; 12123d5ba86SOlivier Deprez size_t mapped_size; 1220cb64d01SAchin Gupta 1230cb64d01SAchin Gupta assert(manifest != NULL); 12423d5ba86SOlivier Deprez assert(pm_addr != NULL); 1250cb64d01SAchin Gupta 12623d5ba86SOlivier Deprez /* 12723d5ba86SOlivier Deprez * Assume TOS_FW_CONFIG is not necessarily aligned to a page 12823d5ba86SOlivier Deprez * boundary, thus calculate the remaining space between SPMC 12923d5ba86SOlivier Deprez * manifest start address and upper page limit. 13023d5ba86SOlivier Deprez * 13123d5ba86SOlivier Deprez */ 13223d5ba86SOlivier Deprez pm_base = (uintptr_t)pm_addr; 13323d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, UP); 134fdd5f9e6SManish Pandey 135fdd5f9e6SManish Pandey if (pm_base == pm_base_align) { 136fdd5f9e6SManish Pandey /* Page aligned */ 137fdd5f9e6SManish Pandey mapped_size = PAGE_SIZE; 138fdd5f9e6SManish Pandey } else { 13923d5ba86SOlivier Deprez mapped_size = pm_base_align - pm_base; 140fdd5f9e6SManish Pandey } 1410cb64d01SAchin Gupta 14223d5ba86SOlivier Deprez /* Check space within the page at least maps the FDT header */ 14323d5ba86SOlivier Deprez if (mapped_size < sizeof(struct fdt_header)) { 14423d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest.\n"); 14523d5ba86SOlivier Deprez return -EINVAL; 14623d5ba86SOlivier Deprez } 14723d5ba86SOlivier Deprez 14823d5ba86SOlivier Deprez /* Map first SPMC manifest page in the SPMD translation regime */ 14923d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, DOWN); 15023d5ba86SOlivier Deprez rc = mmap_add_dynamic_region((unsigned long long)pm_base_align, 15123d5ba86SOlivier Deprez pm_base_align, 15223d5ba86SOlivier Deprez PAGE_SIZE, 153*8c829a92SManish V Badarkhe MT_RO_DATA | EL3_PAS); 1540cb64d01SAchin Gupta if (rc != 0) { 15523d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest (%d).\n", rc); 15652696946SOlivier Deprez return rc; 1570cb64d01SAchin Gupta } 1580cb64d01SAchin Gupta 15923d5ba86SOlivier Deprez rc = fdt_check_header(pm_addr); 16023d5ba86SOlivier Deprez if (rc != 0) { 16123d5ba86SOlivier Deprez ERROR("Wrong format for SPM Core manifest (%d).\n", rc); 16223d5ba86SOlivier Deprez goto exit_unmap; 16323d5ba86SOlivier Deprez } 16423d5ba86SOlivier Deprez 16523d5ba86SOlivier Deprez /* Check SPMC manifest fits within the upper mapped page boundary */ 16623d5ba86SOlivier Deprez if (mapped_size < fdt_totalsize(pm_addr)) { 16723d5ba86SOlivier Deprez ERROR("SPM Core manifest too large.\n"); 16823d5ba86SOlivier Deprez rc = -EINVAL; 16923d5ba86SOlivier Deprez goto exit_unmap; 17023d5ba86SOlivier Deprez } 17123d5ba86SOlivier Deprez 17223d5ba86SOlivier Deprez VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr); 17323d5ba86SOlivier Deprez 17423d5ba86SOlivier Deprez rc = fdt_node_offset_by_compatible(pm_addr, -1, 175662af36dSJ-Alves "arm,ffa-core-manifest-1.0"); 17652696946SOlivier Deprez if (rc < 0) { 17752696946SOlivier Deprez ERROR("Unrecognized SPM Core manifest\n"); 17823d5ba86SOlivier Deprez goto exit_unmap; 1790cb64d01SAchin Gupta } 1800cb64d01SAchin Gupta 18123d5ba86SOlivier Deprez rc = manifest_parse_root(manifest, pm_addr, rc); 18223d5ba86SOlivier Deprez 18323d5ba86SOlivier Deprez exit_unmap: 18423d5ba86SOlivier Deprez unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE); 18523d5ba86SOlivier Deprez if (unmap_ret != 0) { 18623d5ba86SOlivier Deprez ERROR("Error while unmapping SPM Core manifest (%d).\n", 18723d5ba86SOlivier Deprez unmap_ret); 18823d5ba86SOlivier Deprez if (rc == 0) { 18923d5ba86SOlivier Deprez rc = unmap_ret; 19023d5ba86SOlivier Deprez } 19123d5ba86SOlivier Deprez } 19223d5ba86SOlivier Deprez 19323d5ba86SOlivier Deprez return rc; 1940cb64d01SAchin Gupta } 195