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