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