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 #if TRANSFER_LIST && !RESET_TO_BL31 120 int rc; 121 122 assert(manifest != NULL); 123 assert(pm_addr != NULL); 124 125 /* 126 * NOTE: 127 * If spmc_manifest is delivered via TRANSFER_LIST, 128 * the spmc_manifest address is already mapped. 129 * So, @pm_addr can be accessed directly. 130 */ 131 132 rc = fdt_check_header(pm_addr); 133 if (rc != 0) { 134 ERROR("Wrong format for SPM Core manifest (%d).\n", rc); 135 return rc; 136 } 137 138 VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr); 139 140 rc = fdt_node_offset_by_compatible(pm_addr, -1, 141 "arm,ffa-core-manifest-1.0"); 142 if (rc < 0) { 143 ERROR("Unrecognized SPM Core manifest\n"); 144 return rc; 145 } 146 147 rc = manifest_parse_root(manifest, pm_addr, rc); 148 149 return rc; 150 #else 151 int rc, unmap_ret; 152 uintptr_t pm_base, pm_base_align; 153 size_t mapped_size; 154 155 assert(manifest != NULL); 156 assert(pm_addr != NULL); 157 158 /* 159 * Assume TOS_FW_CONFIG is not necessarily aligned to a page 160 * boundary, thus calculate the remaining space between SPMC 161 * manifest start address and upper page limit. 162 * 163 */ 164 pm_base = (uintptr_t)pm_addr; 165 pm_base_align = page_align(pm_base, UP); 166 167 if (pm_base == pm_base_align) { 168 /* Page aligned */ 169 mapped_size = PAGE_SIZE; 170 } else { 171 mapped_size = pm_base_align - pm_base; 172 } 173 174 /* Check space within the page at least maps the FDT header */ 175 if (mapped_size < sizeof(struct fdt_header)) { 176 ERROR("Error while mapping SPM Core manifest.\n"); 177 return -EINVAL; 178 } 179 180 /* Map first SPMC manifest page in the SPMD translation regime */ 181 pm_base_align = page_align(pm_base, DOWN); 182 rc = mmap_add_dynamic_region((unsigned long long)pm_base_align, 183 pm_base_align, 184 PAGE_SIZE, 185 MT_RO_DATA | EL3_PAS); 186 if (rc != 0) { 187 ERROR("Error while mapping SPM Core manifest (%d).\n", rc); 188 return rc; 189 } 190 191 rc = fdt_check_header(pm_addr); 192 if (rc != 0) { 193 ERROR("Wrong format for SPM Core manifest (%d).\n", rc); 194 goto exit_unmap; 195 } 196 197 /* Check SPMC manifest fits within the upper mapped page boundary */ 198 if (mapped_size < fdt_totalsize(pm_addr)) { 199 ERROR("SPM Core manifest too large.\n"); 200 rc = -EINVAL; 201 goto exit_unmap; 202 } 203 204 VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr); 205 206 rc = fdt_node_offset_by_compatible(pm_addr, -1, 207 "arm,ffa-core-manifest-1.0"); 208 if (rc < 0) { 209 ERROR("Unrecognized SPM Core manifest\n"); 210 goto exit_unmap; 211 } 212 213 rc = manifest_parse_root(manifest, pm_addr, rc); 214 215 exit_unmap: 216 unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE); 217 if (unmap_ret != 0) { 218 ERROR("Error while unmapping SPM Core manifest (%d).\n", 219 unmap_ret); 220 if (rc == 0) { 221 rc = unmap_ret; 222 } 223 } 224 225 return rc; 226 #endif 227 } 228