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 12*cb7b9db1SVarun Wadekar #include <common/bl_common.h> 130cb64d01SAchin Gupta #include <common/debug.h> 140cb64d01SAchin Gupta #include <common/fdt_wrappers.h> 1523d5ba86SOlivier Deprez #include <lib/xlat_tables/xlat_tables_v2.h> 160cb64d01SAchin Gupta #include <platform_def.h> 170cb64d01SAchin Gupta #include <services/spm_core_manifest.h> 180cb64d01SAchin Gupta 1952696946SOlivier Deprez #define ATTRIBUTE_ROOT_NODE_STR "attribute" 2052696946SOlivier Deprez 210cb64d01SAchin Gupta /******************************************************************************* 2252696946SOlivier Deprez * SPMC attribute node parser 230cb64d01SAchin Gupta ******************************************************************************/ 2452696946SOlivier Deprez static int manifest_parse_attribute(spmc_manifest_attribute_t *attr, 250cb64d01SAchin Gupta const void *fdt, 260cb64d01SAchin Gupta int node) 270cb64d01SAchin Gupta { 28ff4e6c35SAndre Przywara uint32_t val32; 2952696946SOlivier Deprez int rc; 300cb64d01SAchin Gupta 3152696946SOlivier Deprez assert((attr != NULL) && (fdt != NULL)); 320cb64d01SAchin Gupta 33ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version); 3452696946SOlivier Deprez if (rc != 0) { 35662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n", 3652696946SOlivier Deprez "major"); 3752696946SOlivier Deprez return rc; 380cb64d01SAchin Gupta } 390cb64d01SAchin Gupta 40ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version); 4152696946SOlivier Deprez if (rc != 0) { 42662af36dSJ-Alves ERROR("Missing FFA %s version in SPM Core manifest.\n", 4352696946SOlivier Deprez "minor"); 4452696946SOlivier Deprez return rc; 450cb64d01SAchin Gupta } 460cb64d01SAchin Gupta 47ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "spmc_id", &val32); 4852696946SOlivier Deprez if (rc != 0) { 49ac03ac5eSMax Shvetsov ERROR("Missing SPMC ID in manifest.\n"); 5052696946SOlivier Deprez return rc; 51ac03ac5eSMax Shvetsov } 5252696946SOlivier Deprez 5352696946SOlivier Deprez attr->spmc_id = val32 & 0xffff; 54ac03ac5eSMax Shvetsov 55ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state); 5652696946SOlivier Deprez if (rc != 0) { 5752696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 5852696946SOlivier Deprez "Execution state"); 5952696946SOlivier Deprez } 600cb64d01SAchin Gupta 61ff4e6c35SAndre Przywara rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size); 6252696946SOlivier Deprez if (rc != 0) { 6352696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 6452696946SOlivier Deprez "Binary size"); 6552696946SOlivier Deprez } 660cb64d01SAchin Gupta 67ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address); 6852696946SOlivier Deprez if (rc != 0) { 6952696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 7052696946SOlivier Deprez "Load address"); 7152696946SOlivier Deprez } 720cb64d01SAchin Gupta 73ff4e6c35SAndre Przywara rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint); 7452696946SOlivier Deprez if (rc != 0) { 7552696946SOlivier Deprez NOTICE("%s not specified in SPM Core manifest.\n", 7652696946SOlivier Deprez "Entry point"); 7752696946SOlivier Deprez } 780cb64d01SAchin Gupta 7952696946SOlivier Deprez VERBOSE("SPM Core manifest attribute section:\n"); 8052696946SOlivier Deprez VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version); 8152696946SOlivier Deprez VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id); 820cb64d01SAchin Gupta VERBOSE(" binary_size: 0x%x\n", attr->binary_size); 830cb64d01SAchin Gupta VERBOSE(" load_address: 0x%llx\n", attr->load_address); 840cb64d01SAchin Gupta VERBOSE(" entrypoint: 0x%llx\n", attr->entrypoint); 850cb64d01SAchin Gupta 860cb64d01SAchin Gupta return 0; 870cb64d01SAchin Gupta } 880cb64d01SAchin Gupta 890cb64d01SAchin Gupta /******************************************************************************* 900cb64d01SAchin Gupta * Root node handler 910cb64d01SAchin Gupta ******************************************************************************/ 9252696946SOlivier Deprez static int manifest_parse_root(spmc_manifest_attribute_t *manifest, 930cb64d01SAchin Gupta const void *fdt, 940cb64d01SAchin Gupta int root) 950cb64d01SAchin Gupta { 960cb64d01SAchin Gupta int node; 970cb64d01SAchin Gupta 9852696946SOlivier Deprez assert(manifest != NULL); 9952696946SOlivier Deprez 10052696946SOlivier Deprez node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR, 10152696946SOlivier Deprez sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1); 1020cb64d01SAchin Gupta if (node < 0) { 10352696946SOlivier Deprez ERROR("Root node doesn't contain subnode '%s'\n", 10452696946SOlivier Deprez ATTRIBUTE_ROOT_NODE_STR); 10552696946SOlivier Deprez return node; 1060cb64d01SAchin Gupta } 1070cb64d01SAchin Gupta 1080cb64d01SAchin Gupta return manifest_parse_attribute(manifest, fdt, node); 1090cb64d01SAchin Gupta } 1100cb64d01SAchin Gupta 1110cb64d01SAchin Gupta /******************************************************************************* 11252696946SOlivier Deprez * Platform handler to parse a SPM Core manifest. 1130cb64d01SAchin Gupta ******************************************************************************/ 11452696946SOlivier Deprez int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest, 11523d5ba86SOlivier Deprez const void *pm_addr) 1160cb64d01SAchin Gupta { 11723d5ba86SOlivier Deprez int rc, unmap_ret; 11823d5ba86SOlivier Deprez uintptr_t pm_base, pm_base_align; 11923d5ba86SOlivier Deprez size_t mapped_size; 1200cb64d01SAchin Gupta 1210cb64d01SAchin Gupta assert(manifest != NULL); 12223d5ba86SOlivier Deprez assert(pm_addr != NULL); 1230cb64d01SAchin Gupta 12423d5ba86SOlivier Deprez /* 12523d5ba86SOlivier Deprez * Assume TOS_FW_CONFIG is not necessarily aligned to a page 12623d5ba86SOlivier Deprez * boundary, thus calculate the remaining space between SPMC 12723d5ba86SOlivier Deprez * manifest start address and upper page limit. 12823d5ba86SOlivier Deprez * 12923d5ba86SOlivier Deprez */ 13023d5ba86SOlivier Deprez pm_base = (uintptr_t)pm_addr; 13123d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, UP); 132fdd5f9e6SManish Pandey 133fdd5f9e6SManish Pandey if (pm_base == pm_base_align) { 134fdd5f9e6SManish Pandey /* Page aligned */ 135fdd5f9e6SManish Pandey mapped_size = PAGE_SIZE; 136fdd5f9e6SManish Pandey } else { 13723d5ba86SOlivier Deprez mapped_size = pm_base_align - pm_base; 138fdd5f9e6SManish Pandey } 1390cb64d01SAchin Gupta 14023d5ba86SOlivier Deprez /* Check space within the page at least maps the FDT header */ 14123d5ba86SOlivier Deprez if (mapped_size < sizeof(struct fdt_header)) { 14223d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest.\n"); 14323d5ba86SOlivier Deprez return -EINVAL; 14423d5ba86SOlivier Deprez } 14523d5ba86SOlivier Deprez 14623d5ba86SOlivier Deprez /* Map first SPMC manifest page in the SPMD translation regime */ 14723d5ba86SOlivier Deprez pm_base_align = page_align(pm_base, DOWN); 14823d5ba86SOlivier Deprez rc = mmap_add_dynamic_region((unsigned long long)pm_base_align, 14923d5ba86SOlivier Deprez pm_base_align, 15023d5ba86SOlivier Deprez PAGE_SIZE, 15123d5ba86SOlivier Deprez MT_RO_DATA); 1520cb64d01SAchin Gupta if (rc != 0) { 15323d5ba86SOlivier Deprez ERROR("Error while mapping SPM Core manifest (%d).\n", rc); 15452696946SOlivier Deprez return rc; 1550cb64d01SAchin Gupta } 1560cb64d01SAchin Gupta 15723d5ba86SOlivier Deprez rc = fdt_check_header(pm_addr); 15823d5ba86SOlivier Deprez if (rc != 0) { 15923d5ba86SOlivier Deprez ERROR("Wrong format for SPM Core manifest (%d).\n", rc); 16023d5ba86SOlivier Deprez goto exit_unmap; 16123d5ba86SOlivier Deprez } 16223d5ba86SOlivier Deprez 16323d5ba86SOlivier Deprez /* Check SPMC manifest fits within the upper mapped page boundary */ 16423d5ba86SOlivier Deprez if (mapped_size < fdt_totalsize(pm_addr)) { 16523d5ba86SOlivier Deprez ERROR("SPM Core manifest too large.\n"); 16623d5ba86SOlivier Deprez rc = -EINVAL; 16723d5ba86SOlivier Deprez goto exit_unmap; 16823d5ba86SOlivier Deprez } 16923d5ba86SOlivier Deprez 17023d5ba86SOlivier Deprez VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr); 17123d5ba86SOlivier Deprez 17223d5ba86SOlivier Deprez rc = fdt_node_offset_by_compatible(pm_addr, -1, 173662af36dSJ-Alves "arm,ffa-core-manifest-1.0"); 17452696946SOlivier Deprez if (rc < 0) { 17552696946SOlivier Deprez ERROR("Unrecognized SPM Core manifest\n"); 17623d5ba86SOlivier Deprez goto exit_unmap; 1770cb64d01SAchin Gupta } 1780cb64d01SAchin Gupta 17923d5ba86SOlivier Deprez rc = manifest_parse_root(manifest, pm_addr, rc); 18023d5ba86SOlivier Deprez 18123d5ba86SOlivier Deprez exit_unmap: 18223d5ba86SOlivier Deprez unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE); 18323d5ba86SOlivier Deprez if (unmap_ret != 0) { 18423d5ba86SOlivier Deprez ERROR("Error while unmapping SPM Core manifest (%d).\n", 18523d5ba86SOlivier Deprez unmap_ret); 18623d5ba86SOlivier Deprez if (rc == 0) { 18723d5ba86SOlivier Deprez rc = unmap_ret; 18823d5ba86SOlivier Deprez } 18923d5ba86SOlivier Deprez } 19023d5ba86SOlivier Deprez 19123d5ba86SOlivier Deprez return rc; 1920cb64d01SAchin Gupta } 193