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 mapped_size = pm_base_align - pm_base; 132 133 /* Check space within the page at least maps the FDT header */ 134 if (mapped_size < sizeof(struct fdt_header)) { 135 ERROR("Error while mapping SPM Core manifest.\n"); 136 return -EINVAL; 137 } 138 139 /* Map first SPMC manifest page in the SPMD translation regime */ 140 pm_base_align = page_align(pm_base, DOWN); 141 rc = mmap_add_dynamic_region((unsigned long long)pm_base_align, 142 pm_base_align, 143 PAGE_SIZE, 144 MT_RO_DATA); 145 if (rc != 0) { 146 ERROR("Error while mapping SPM Core manifest (%d).\n", rc); 147 return rc; 148 } 149 150 rc = fdt_check_header(pm_addr); 151 if (rc != 0) { 152 ERROR("Wrong format for SPM Core manifest (%d).\n", rc); 153 goto exit_unmap; 154 } 155 156 /* Check SPMC manifest fits within the upper mapped page boundary */ 157 if (mapped_size < fdt_totalsize(pm_addr)) { 158 ERROR("SPM Core manifest too large.\n"); 159 rc = -EINVAL; 160 goto exit_unmap; 161 } 162 163 VERBOSE("Reading SPM Core manifest at address %p\n", pm_addr); 164 165 rc = fdt_node_offset_by_compatible(pm_addr, -1, 166 "arm,ffa-core-manifest-1.0"); 167 if (rc < 0) { 168 ERROR("Unrecognized SPM Core manifest\n"); 169 goto exit_unmap; 170 } 171 172 rc = manifest_parse_root(manifest, pm_addr, rc); 173 174 exit_unmap: 175 unmap_ret = mmap_remove_dynamic_region(pm_base_align, PAGE_SIZE); 176 if (unmap_ret != 0) { 177 ERROR("Error while unmapping SPM Core manifest (%d).\n", 178 unmap_ret); 179 if (rc == 0) { 180 rc = unmap_ret; 181 } 182 } 183 184 return rc; 185 } 186