1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2020-2023, Arm Limited. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu #include <inttypes.h> 10*91f16700Schasinglulu #include <libfdt.h> 11*91f16700Schasinglulu #include <stdint.h> 12*91f16700Schasinglulu #include <string.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu #include <common/bl_common.h> 15*91f16700Schasinglulu #include <common/debug.h> 16*91f16700Schasinglulu #include <common/fdt_wrappers.h> 17*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h> 18*91f16700Schasinglulu #include <platform_def.h> 19*91f16700Schasinglulu #include <services/spm_core_manifest.h> 20*91f16700Schasinglulu 21*91f16700Schasinglulu #define ATTRIBUTE_ROOT_NODE_STR "attribute" 22*91f16700Schasinglulu 23*91f16700Schasinglulu /******************************************************************************* 24*91f16700Schasinglulu * SPMC attribute node parser 25*91f16700Schasinglulu ******************************************************************************/ 26*91f16700Schasinglulu static int manifest_parse_attribute(spmc_manifest_attribute_t *attr, 27*91f16700Schasinglulu const void *fdt, 28*91f16700Schasinglulu int node) 29*91f16700Schasinglulu { 30*91f16700Schasinglulu uint32_t val32; 31*91f16700Schasinglulu int rc; 32*91f16700Schasinglulu 33*91f16700Schasinglulu assert((attr != NULL) && (fdt != NULL)); 34*91f16700Schasinglulu 35*91f16700Schasinglulu rc = fdt_read_uint32(fdt, node, "maj_ver", &attr->major_version); 36*91f16700Schasinglulu if (rc != 0) { 37*91f16700Schasinglulu ERROR("Missing FFA %s version in SPM Core manifest.\n", 38*91f16700Schasinglulu "major"); 39*91f16700Schasinglulu return rc; 40*91f16700Schasinglulu } 41*91f16700Schasinglulu 42*91f16700Schasinglulu rc = fdt_read_uint32(fdt, node, "min_ver", &attr->minor_version); 43*91f16700Schasinglulu if (rc != 0) { 44*91f16700Schasinglulu ERROR("Missing FFA %s version in SPM Core manifest.\n", 45*91f16700Schasinglulu "minor"); 46*91f16700Schasinglulu return rc; 47*91f16700Schasinglulu } 48*91f16700Schasinglulu 49*91f16700Schasinglulu rc = fdt_read_uint32(fdt, node, "spmc_id", &val32); 50*91f16700Schasinglulu if (rc != 0) { 51*91f16700Schasinglulu ERROR("Missing SPMC ID in manifest.\n"); 52*91f16700Schasinglulu return rc; 53*91f16700Schasinglulu } 54*91f16700Schasinglulu 55*91f16700Schasinglulu attr->spmc_id = val32 & 0xffff; 56*91f16700Schasinglulu 57*91f16700Schasinglulu rc = fdt_read_uint32(fdt, node, "exec_state", &attr->exec_state); 58*91f16700Schasinglulu if (rc != 0) { 59*91f16700Schasinglulu NOTICE("%s not specified in SPM Core manifest.\n", 60*91f16700Schasinglulu "Execution state"); 61*91f16700Schasinglulu } 62*91f16700Schasinglulu 63*91f16700Schasinglulu rc = fdt_read_uint32(fdt, node, "binary_size", &attr->binary_size); 64*91f16700Schasinglulu if (rc != 0) { 65*91f16700Schasinglulu NOTICE("%s not specified in SPM Core manifest.\n", 66*91f16700Schasinglulu "Binary size"); 67*91f16700Schasinglulu } 68*91f16700Schasinglulu 69*91f16700Schasinglulu rc = fdt_read_uint64(fdt, node, "load_address", &attr->load_address); 70*91f16700Schasinglulu if (rc != 0) { 71*91f16700Schasinglulu NOTICE("%s not specified in SPM Core manifest.\n", 72*91f16700Schasinglulu "Load address"); 73*91f16700Schasinglulu } 74*91f16700Schasinglulu 75*91f16700Schasinglulu rc = fdt_read_uint64(fdt, node, "entrypoint", &attr->entrypoint); 76*91f16700Schasinglulu if (rc != 0) { 77*91f16700Schasinglulu NOTICE("%s not specified in SPM Core manifest.\n", 78*91f16700Schasinglulu "Entry point"); 79*91f16700Schasinglulu } 80*91f16700Schasinglulu 81*91f16700Schasinglulu VERBOSE("SPM Core manifest attribute section:\n"); 82*91f16700Schasinglulu VERBOSE(" version: %u.%u\n", attr->major_version, attr->minor_version); 83*91f16700Schasinglulu VERBOSE(" spmc_id: 0x%x\n", attr->spmc_id); 84*91f16700Schasinglulu VERBOSE(" binary_size: 0x%x\n", attr->binary_size); 85*91f16700Schasinglulu VERBOSE(" load_address: 0x%" PRIx64 "\n", attr->load_address); 86*91f16700Schasinglulu VERBOSE(" entrypoint: 0x%" PRIx64 "\n", attr->entrypoint); 87*91f16700Schasinglulu 88*91f16700Schasinglulu return 0; 89*91f16700Schasinglulu } 90*91f16700Schasinglulu 91*91f16700Schasinglulu /******************************************************************************* 92*91f16700Schasinglulu * Root node handler 93*91f16700Schasinglulu ******************************************************************************/ 94*91f16700Schasinglulu static int manifest_parse_root(spmc_manifest_attribute_t *manifest, 95*91f16700Schasinglulu const void *fdt, 96*91f16700Schasinglulu int root) 97*91f16700Schasinglulu { 98*91f16700Schasinglulu int node; 99*91f16700Schasinglulu 100*91f16700Schasinglulu assert(manifest != NULL); 101*91f16700Schasinglulu 102*91f16700Schasinglulu node = fdt_subnode_offset_namelen(fdt, root, ATTRIBUTE_ROOT_NODE_STR, 103*91f16700Schasinglulu sizeof(ATTRIBUTE_ROOT_NODE_STR) - 1); 104*91f16700Schasinglulu if (node < 0) { 105*91f16700Schasinglulu ERROR("Root node doesn't contain subnode '%s'\n", 106*91f16700Schasinglulu ATTRIBUTE_ROOT_NODE_STR); 107*91f16700Schasinglulu return node; 108*91f16700Schasinglulu } 109*91f16700Schasinglulu 110*91f16700Schasinglulu return manifest_parse_attribute(manifest, fdt, node); 111*91f16700Schasinglulu } 112*91f16700Schasinglulu 113*91f16700Schasinglulu /******************************************************************************* 114*91f16700Schasinglulu * Platform handler to parse a SPM Core manifest. 115*91f16700Schasinglulu ******************************************************************************/ 116*91f16700Schasinglulu int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest, 117*91f16700Schasinglulu const void *pm_addr) 118*91f16700Schasinglulu { 119*91f16700Schasinglulu int rc, unmap_ret; 120*91f16700Schasinglulu uintptr_t pm_base, pm_base_align; 121*91f16700Schasinglulu size_t mapped_size; 122*91f16700Schasinglulu 123*91f16700Schasinglulu assert(manifest != NULL); 124*91f16700Schasinglulu assert(pm_addr != NULL); 125*91f16700Schasinglulu 126*91f16700Schasinglulu /* 127*91f16700Schasinglulu * Assume TOS_FW_CONFIG is not necessarily aligned to a page 128*91f16700Schasinglulu * boundary, thus calculate the remaining space between SPMC 129*91f16700Schasinglulu * manifest start address and upper page limit. 130*91f16700Schasinglulu * 131*91f16700Schasinglulu */ 132*91f16700Schasinglulu pm_base = (uintptr_t)pm_addr; 133*91f16700Schasinglulu pm_base_align = page_align(pm_base, UP); 134*91f16700Schasinglulu 135*91f16700Schasinglulu if (pm_base == pm_base_align) { 136*91f16700Schasinglulu /* Page aligned */ 137*91f16700Schasinglulu mapped_size = PAGE_SIZE; 138*91f16700Schasinglulu } else { 139*91f16700Schasinglulu mapped_size = pm_base_align - pm_base; 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu /* Check space within the page at least maps the FDT header */ 143*91f16700Schasinglulu if (mapped_size < sizeof(struct fdt_header)) { 144*91f16700Schasinglulu ERROR("Error while mapping SPM Core manifest.\n"); 145*91f16700Schasinglulu return -EINVAL; 146*91f16700Schasinglulu } 147*91f16700Schasinglulu 148*91f16700Schasinglulu /* Map first SPMC manifest page in the SPMD translation regime */ 149*91f16700Schasinglulu pm_base_align = page_align(pm_base, DOWN); 150*91f16700Schasinglulu rc = mmap_add_dynamic_region((unsigned long long)pm_base_align, 151*91f16700Schasinglulu pm_base_align, 152*91f16700Schasinglulu PAGE_SIZE, 153*91f16700Schasinglulu MT_RO_DATA | EL3_PAS); 154*91f16700Schasinglulu if (rc != 0) { 155*91f16700Schasinglulu ERROR("Error while mapping SPM Core manifest (%d).\n", rc); 156*91f16700Schasinglulu return rc; 157*91f16700Schasinglulu } 158*91f16700Schasinglulu 159*91f16700Schasinglulu rc = fdt_check_header(pm_addr); 160*91f16700Schasinglulu if (rc != 0) { 161*91f16700Schasinglulu ERROR("Wrong format for SPM Core manifest (%d).\n", rc); 162*91f16700Schasinglulu goto exit_unmap; 163*91f16700Schasinglulu } 164*91f16700Schasinglulu 165*91f16700Schasinglulu /* Check SPMC manifest fits within the upper mapped page boundary */ 166*91f16700Schasinglulu if (mapped_size < fdt_totalsize(pm_addr)) { 167*91f16700Schasinglulu ERROR("SPM Core manifest too large.\n"); 168*91f16700Schasinglulu rc = -EINVAL; 169*91f16700Schasinglulu goto exit_unmap; 170*91f16700Schasinglulu } 171*91f16700Schasinglulu 172*91f16700Schasinglulu VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr); 173*91f16700Schasinglulu 174*91f16700Schasinglulu rc = fdt_node_offset_by_compatible(pm_addr, -1, 175*91f16700Schasinglulu "arm,ffa-core-manifest-1.0"); 176*91f16700Schasinglulu if (rc < 0) { 177*91f16700Schasinglulu ERROR("Unrecognized SPM Core manifest\n"); 178*91f16700Schasinglulu goto exit_unmap; 179*91f16700Schasinglulu } 180*91f16700Schasinglulu 181*91f16700Schasinglulu rc = manifest_parse_root(manifest, pm_addr, rc); 182*91f16700Schasinglulu 183*91f16700Schasinglulu exit_unmap: 184*91f16700Schasinglulu unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE); 185*91f16700Schasinglulu if (unmap_ret != 0) { 186*91f16700Schasinglulu ERROR("Error while unmapping SPM Core manifest (%d).\n", 187*91f16700Schasinglulu unmap_ret); 188*91f16700Schasinglulu if (rc == 0) { 189*91f16700Schasinglulu rc = unmap_ret; 190*91f16700Schasinglulu } 191*91f16700Schasinglulu } 192*91f16700Schasinglulu 193*91f16700Schasinglulu return rc; 194*91f16700Schasinglulu } 195