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