1 /* 2 * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <string.h> 9 10 #include <arch.h> 11 #include <arch_helpers.h> 12 #include <common/debug.h> 13 #include <common/fdt_wrappers.h> 14 #include <context.h> 15 #include <lib/el3_runtime/context_mgmt.h> 16 #include <lib/utils.h> 17 #include <lib/xlat_tables/xlat_tables_v2.h> 18 #include <libfdt.h> 19 #include <plat/common/common_def.h> 20 #include <plat/common/platform.h> 21 #include <services/ffa_svc.h> 22 #include "spm_common.h" 23 #include "spmc.h" 24 #include <tools_share/firmware_image_package.h> 25 26 #include <platform_def.h> 27 28 /* 29 * Statically allocate a page of memory for passing boot information to an SP. 30 */ 31 static uint8_t ffa_boot_info_mem[PAGE_SIZE] __aligned(PAGE_SIZE); 32 33 /* 34 * This function creates a initialization descriptor in the memory reserved 35 * for passing boot information to an SP. It then copies the partition manifest 36 * into this region and ensures that its reference in the initialization 37 * descriptor is updated. 38 */ 39 static void spmc_create_boot_info(entry_point_info_t *ep_info, 40 struct secure_partition_desc *sp) 41 { 42 struct ffa_boot_info_header *boot_header; 43 struct ffa_boot_info_desc *boot_descriptor; 44 uintptr_t manifest_addr; 45 46 /* 47 * Calculate the maximum size of the manifest that can be accommodated 48 * in the boot information memory region. 49 */ 50 const unsigned int 51 max_manifest_sz = sizeof(ffa_boot_info_mem) - 52 (sizeof(struct ffa_boot_info_header) + 53 sizeof(struct ffa_boot_info_desc)); 54 55 /* 56 * The current implementation only supports the FF-A v1.1 57 * implementation of the boot protocol, therefore check 58 * that a v1.0 SP has not requested use of the protocol. 59 */ 60 if (sp->ffa_version == MAKE_FFA_VERSION(1, 0)) { 61 ERROR("FF-A boot protocol not supported for v1.0 clients\n"); 62 return; 63 } 64 65 /* 66 * Check if the manifest will fit into the boot info memory region else 67 * bail. 68 */ 69 if (ep_info->args.arg1 > max_manifest_sz) { 70 WARN("Unable to copy manifest into boot information. "); 71 WARN("Max sz = %u bytes. Manifest sz = %lu bytes\n", 72 max_manifest_sz, ep_info->args.arg1); 73 return; 74 } 75 76 /* Zero the memory region before populating. */ 77 memset(ffa_boot_info_mem, 0, PAGE_SIZE); 78 79 /* 80 * Populate the ffa_boot_info_header at the start of the boot info 81 * region. 82 */ 83 boot_header = (struct ffa_boot_info_header *) ffa_boot_info_mem; 84 85 /* Position the ffa_boot_info_desc after the ffa_boot_info_header. */ 86 boot_header->offset_boot_info_desc = 87 sizeof(struct ffa_boot_info_header); 88 boot_descriptor = (struct ffa_boot_info_desc *) 89 (ffa_boot_info_mem + 90 boot_header->offset_boot_info_desc); 91 92 /* 93 * We must use the FF-A version coresponding to the version implemented 94 * by the SP. Currently this can only be v1.1. 95 */ 96 boot_header->version = sp->ffa_version; 97 98 /* Populate the boot information header. */ 99 boot_header->size_boot_info_desc = sizeof(struct ffa_boot_info_desc); 100 101 /* Set the signature "0xFFA". */ 102 boot_header->signature = FFA_INIT_DESC_SIGNATURE; 103 104 /* Set the count. Currently 1 since only the manifest is specified. */ 105 boot_header->count_boot_info_desc = 1; 106 107 /* Populate the boot information descriptor for the manifest. */ 108 boot_descriptor->type = 109 FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) | 110 FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_FDT); 111 112 boot_descriptor->flags = 113 FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) | 114 FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR); 115 116 /* 117 * Copy the manifest into boot info region after the boot information 118 * descriptor. 119 */ 120 boot_descriptor->size_boot_info = (uint32_t) ep_info->args.arg1; 121 122 manifest_addr = (uintptr_t) (ffa_boot_info_mem + 123 boot_header->offset_boot_info_desc + 124 boot_header->size_boot_info_desc); 125 126 memcpy((void *) manifest_addr, (void *) ep_info->args.arg0, 127 boot_descriptor->size_boot_info); 128 129 boot_descriptor->content = manifest_addr; 130 131 /* Calculate the size of the total boot info blob. */ 132 boot_header->size_boot_info_blob = boot_header->offset_boot_info_desc + 133 boot_descriptor->size_boot_info + 134 (boot_header->count_boot_info_desc * 135 boot_header->size_boot_info_desc); 136 137 INFO("SP boot info @ 0x%lx, size: %u bytes.\n", 138 (uintptr_t) ffa_boot_info_mem, 139 boot_header->size_boot_info_blob); 140 INFO("SP manifest @ 0x%lx, size: %u bytes.\n", 141 boot_descriptor->content, 142 boot_descriptor->size_boot_info); 143 } 144 145 /* 146 * We are assuming that the index of the execution 147 * context used is the linear index of the current physical cpu. 148 */ 149 unsigned int get_ec_index(struct secure_partition_desc *sp) 150 { 151 return plat_my_core_pos(); 152 } 153 154 /* S-EL1 partition specific initialisation. */ 155 void spmc_el1_sp_setup(struct secure_partition_desc *sp, 156 entry_point_info_t *ep_info) 157 { 158 /* Sanity check input arguments. */ 159 assert(sp != NULL); 160 assert(ep_info != NULL); 161 162 /* Initialise the SPSR for S-EL1 SPs. */ 163 ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, 164 DISABLE_ALL_EXCEPTIONS); 165 166 /* 167 * TF-A Implementation defined behaviour to provide the linear 168 * core ID in the x4 register. 169 */ 170 ep_info->args.arg4 = (uintptr_t) plat_my_core_pos(); 171 172 /* 173 * Check whether setup is being performed for the primary or a secondary 174 * execution context. In the latter case, indicate to the SP that this 175 * is a warm boot. 176 * TODO: This check would need to be reworked if the same entry point is 177 * used for both primary and secondary initialisation. 178 */ 179 if (sp->secondary_ep != 0U) { 180 /* 181 * Sanity check that the secondary entry point is still what was 182 * originally set. 183 */ 184 assert(sp->secondary_ep == ep_info->pc); 185 ep_info->args.arg0 = FFA_WB_TYPE_S2RAM; 186 } 187 } 188 189 /* Common initialisation for all SPs. */ 190 void spmc_sp_common_setup(struct secure_partition_desc *sp, 191 entry_point_info_t *ep_info, 192 int32_t boot_info_reg) 193 { 194 uint16_t sp_id; 195 196 /* Assign FF-A Partition ID if not already assigned. */ 197 if (sp->sp_id == INV_SP_ID) { 198 sp_id = FFA_SP_ID_BASE + ACTIVE_SP_DESC_INDEX; 199 /* 200 * Ensure we don't clash with previously assigned partition 201 * IDs. 202 */ 203 while (!is_ffa_secure_id_valid(sp_id)) { 204 sp_id++; 205 206 if (sp_id == FFA_SWD_ID_LIMIT) { 207 ERROR("Unable to determine valid SP ID.\n"); 208 panic(); 209 } 210 } 211 sp->sp_id = sp_id; 212 } 213 214 /* 215 * We currently only support S-EL1 partitions so ensure this is the 216 * case. 217 */ 218 assert(sp->runtime_el == S_EL1); 219 220 /* Check if the SP wants to use the FF-A boot protocol. */ 221 if (boot_info_reg >= 0) { 222 /* 223 * Create a boot information descriptor and copy the partition 224 * manifest into the reserved memory region for consumption by 225 * the SP. 226 */ 227 spmc_create_boot_info(ep_info, sp); 228 229 /* 230 * We have consumed what we need from ep args so we can now 231 * zero them before we start populating with new information 232 * specifically for the SP. 233 */ 234 zeromem(&ep_info->args, sizeof(ep_info->args)); 235 236 /* 237 * Pass the address of the boot information in the 238 * boot_info_reg. 239 */ 240 switch (boot_info_reg) { 241 case 0: 242 ep_info->args.arg0 = (uintptr_t) ffa_boot_info_mem; 243 break; 244 case 1: 245 ep_info->args.arg1 = (uintptr_t) ffa_boot_info_mem; 246 break; 247 case 2: 248 ep_info->args.arg2 = (uintptr_t) ffa_boot_info_mem; 249 break; 250 case 3: 251 ep_info->args.arg3 = (uintptr_t) ffa_boot_info_mem; 252 break; 253 default: 254 ERROR("Invalid value for \"gp-register-num\" %d.\n", 255 boot_info_reg); 256 } 257 } else { 258 /* 259 * We don't need any of the information that was populated 260 * in ep_args so we can clear them. 261 */ 262 zeromem(&ep_info->args, sizeof(ep_info->args)); 263 } 264 } 265 266 /* 267 * Initialise the SP context now we have populated the common and EL specific 268 * entrypoint information. 269 */ 270 void spmc_sp_common_ep_commit(struct secure_partition_desc *sp, 271 entry_point_info_t *ep_info) 272 { 273 cpu_context_t *cpu_ctx; 274 275 cpu_ctx = &(spmc_get_sp_ec(sp)->cpu_ctx); 276 print_entry_point_info(ep_info); 277 cm_setup_context(cpu_ctx, ep_info); 278 } 279