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