1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017-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 <arch_helpers.h> 8*91f16700Schasinglulu #include <assert.h> 9*91f16700Schasinglulu #include <errno.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <bl31/bl31.h> 12*91f16700Schasinglulu #include <bl31/ehf.h> 13*91f16700Schasinglulu #include <common/debug.h> 14*91f16700Schasinglulu #include <common/runtime_svc.h> 15*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h> 16*91f16700Schasinglulu #include <lib/smccc.h> 17*91f16700Schasinglulu #include <lib/spinlock.h> 18*91f16700Schasinglulu #include <lib/utils.h> 19*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h> 20*91f16700Schasinglulu #include <plat/common/platform.h> 21*91f16700Schasinglulu #include <services/spm_mm_partition.h> 22*91f16700Schasinglulu #include <services/spm_mm_svc.h> 23*91f16700Schasinglulu #include <smccc_helpers.h> 24*91f16700Schasinglulu 25*91f16700Schasinglulu #include "spm_common.h" 26*91f16700Schasinglulu #include "spm_mm_private.h" 27*91f16700Schasinglulu 28*91f16700Schasinglulu /******************************************************************************* 29*91f16700Schasinglulu * Secure Partition context information. 30*91f16700Schasinglulu ******************************************************************************/ 31*91f16700Schasinglulu static sp_context_t sp_ctx; 32*91f16700Schasinglulu 33*91f16700Schasinglulu /******************************************************************************* 34*91f16700Schasinglulu * Set state of a Secure Partition context. 35*91f16700Schasinglulu ******************************************************************************/ 36*91f16700Schasinglulu void sp_state_set(sp_context_t *sp_ptr, sp_state_t state) 37*91f16700Schasinglulu { 38*91f16700Schasinglulu spin_lock(&(sp_ptr->state_lock)); 39*91f16700Schasinglulu sp_ptr->state = state; 40*91f16700Schasinglulu spin_unlock(&(sp_ptr->state_lock)); 41*91f16700Schasinglulu } 42*91f16700Schasinglulu 43*91f16700Schasinglulu /******************************************************************************* 44*91f16700Schasinglulu * Wait until the state of a Secure Partition is the specified one and change it 45*91f16700Schasinglulu * to the desired state. 46*91f16700Schasinglulu ******************************************************************************/ 47*91f16700Schasinglulu void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) 48*91f16700Schasinglulu { 49*91f16700Schasinglulu int success = 0; 50*91f16700Schasinglulu 51*91f16700Schasinglulu while (success == 0) { 52*91f16700Schasinglulu spin_lock(&(sp_ptr->state_lock)); 53*91f16700Schasinglulu 54*91f16700Schasinglulu if (sp_ptr->state == from) { 55*91f16700Schasinglulu sp_ptr->state = to; 56*91f16700Schasinglulu 57*91f16700Schasinglulu success = 1; 58*91f16700Schasinglulu } 59*91f16700Schasinglulu 60*91f16700Schasinglulu spin_unlock(&(sp_ptr->state_lock)); 61*91f16700Schasinglulu } 62*91f16700Schasinglulu } 63*91f16700Schasinglulu 64*91f16700Schasinglulu /******************************************************************************* 65*91f16700Schasinglulu * Check if the state of a Secure Partition is the specified one and, if so, 66*91f16700Schasinglulu * change it to the desired state. Returns 0 on success, -1 on error. 67*91f16700Schasinglulu ******************************************************************************/ 68*91f16700Schasinglulu int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) 69*91f16700Schasinglulu { 70*91f16700Schasinglulu int ret = -1; 71*91f16700Schasinglulu 72*91f16700Schasinglulu spin_lock(&(sp_ptr->state_lock)); 73*91f16700Schasinglulu 74*91f16700Schasinglulu if (sp_ptr->state == from) { 75*91f16700Schasinglulu sp_ptr->state = to; 76*91f16700Schasinglulu 77*91f16700Schasinglulu ret = 0; 78*91f16700Schasinglulu } 79*91f16700Schasinglulu 80*91f16700Schasinglulu spin_unlock(&(sp_ptr->state_lock)); 81*91f16700Schasinglulu 82*91f16700Schasinglulu return ret; 83*91f16700Schasinglulu } 84*91f16700Schasinglulu 85*91f16700Schasinglulu /******************************************************************************* 86*91f16700Schasinglulu * This function takes an SP context pointer and performs a synchronous entry 87*91f16700Schasinglulu * into it. 88*91f16700Schasinglulu ******************************************************************************/ 89*91f16700Schasinglulu static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx) 90*91f16700Schasinglulu { 91*91f16700Schasinglulu uint64_t rc; 92*91f16700Schasinglulu 93*91f16700Schasinglulu assert(ctx != NULL); 94*91f16700Schasinglulu 95*91f16700Schasinglulu /* Assign the context of the SP to this CPU */ 96*91f16700Schasinglulu cm_set_context(&(ctx->cpu_ctx), SECURE); 97*91f16700Schasinglulu 98*91f16700Schasinglulu /* Restore the context assigned above */ 99*91f16700Schasinglulu cm_el1_sysregs_context_restore(SECURE); 100*91f16700Schasinglulu cm_set_next_eret_context(SECURE); 101*91f16700Schasinglulu 102*91f16700Schasinglulu /* Invalidate TLBs at EL1. */ 103*91f16700Schasinglulu tlbivmalle1(); 104*91f16700Schasinglulu dsbish(); 105*91f16700Schasinglulu 106*91f16700Schasinglulu /* Enter Secure Partition */ 107*91f16700Schasinglulu rc = spm_secure_partition_enter(&ctx->c_rt_ctx); 108*91f16700Schasinglulu 109*91f16700Schasinglulu /* Save secure state */ 110*91f16700Schasinglulu cm_el1_sysregs_context_save(SECURE); 111*91f16700Schasinglulu 112*91f16700Schasinglulu return rc; 113*91f16700Schasinglulu } 114*91f16700Schasinglulu 115*91f16700Schasinglulu /******************************************************************************* 116*91f16700Schasinglulu * This function returns to the place where spm_sp_synchronous_entry() was 117*91f16700Schasinglulu * called originally. 118*91f16700Schasinglulu ******************************************************************************/ 119*91f16700Schasinglulu __dead2 static void spm_sp_synchronous_exit(uint64_t rc) 120*91f16700Schasinglulu { 121*91f16700Schasinglulu sp_context_t *ctx = &sp_ctx; 122*91f16700Schasinglulu 123*91f16700Schasinglulu /* 124*91f16700Schasinglulu * The SPM must have initiated the original request through a 125*91f16700Schasinglulu * synchronous entry into the secure partition. Jump back to the 126*91f16700Schasinglulu * original C runtime context with the value of rc in x0; 127*91f16700Schasinglulu */ 128*91f16700Schasinglulu spm_secure_partition_exit(ctx->c_rt_ctx, rc); 129*91f16700Schasinglulu 130*91f16700Schasinglulu panic(); 131*91f16700Schasinglulu } 132*91f16700Schasinglulu 133*91f16700Schasinglulu /******************************************************************************* 134*91f16700Schasinglulu * Jump to each Secure Partition for the first time. 135*91f16700Schasinglulu ******************************************************************************/ 136*91f16700Schasinglulu static int32_t spm_init(void) 137*91f16700Schasinglulu { 138*91f16700Schasinglulu uint64_t rc; 139*91f16700Schasinglulu sp_context_t *ctx; 140*91f16700Schasinglulu 141*91f16700Schasinglulu INFO("Secure Partition init...\n"); 142*91f16700Schasinglulu 143*91f16700Schasinglulu ctx = &sp_ctx; 144*91f16700Schasinglulu 145*91f16700Schasinglulu ctx->state = SP_STATE_RESET; 146*91f16700Schasinglulu 147*91f16700Schasinglulu rc = spm_sp_synchronous_entry(ctx); 148*91f16700Schasinglulu assert(rc == 0); 149*91f16700Schasinglulu 150*91f16700Schasinglulu ctx->state = SP_STATE_IDLE; 151*91f16700Schasinglulu 152*91f16700Schasinglulu INFO("Secure Partition initialized.\n"); 153*91f16700Schasinglulu 154*91f16700Schasinglulu return !rc; 155*91f16700Schasinglulu } 156*91f16700Schasinglulu 157*91f16700Schasinglulu /******************************************************************************* 158*91f16700Schasinglulu * Initialize contexts of all Secure Partitions. 159*91f16700Schasinglulu ******************************************************************************/ 160*91f16700Schasinglulu int32_t spm_mm_setup(void) 161*91f16700Schasinglulu { 162*91f16700Schasinglulu sp_context_t *ctx; 163*91f16700Schasinglulu 164*91f16700Schasinglulu /* Disable MMU at EL1 (initialized by BL2) */ 165*91f16700Schasinglulu disable_mmu_icache_el1(); 166*91f16700Schasinglulu 167*91f16700Schasinglulu /* Initialize context of the SP */ 168*91f16700Schasinglulu INFO("Secure Partition context setup start...\n"); 169*91f16700Schasinglulu 170*91f16700Schasinglulu ctx = &sp_ctx; 171*91f16700Schasinglulu 172*91f16700Schasinglulu /* Assign translation tables context. */ 173*91f16700Schasinglulu ctx->xlat_ctx_handle = spm_get_sp_xlat_context(); 174*91f16700Schasinglulu 175*91f16700Schasinglulu spm_sp_setup(ctx); 176*91f16700Schasinglulu 177*91f16700Schasinglulu /* Register init function for deferred init. */ 178*91f16700Schasinglulu bl31_register_bl32_init(&spm_init); 179*91f16700Schasinglulu 180*91f16700Schasinglulu INFO("Secure Partition setup done.\n"); 181*91f16700Schasinglulu 182*91f16700Schasinglulu return 0; 183*91f16700Schasinglulu } 184*91f16700Schasinglulu 185*91f16700Schasinglulu /******************************************************************************* 186*91f16700Schasinglulu * Function to perform a call to a Secure Partition. 187*91f16700Schasinglulu ******************************************************************************/ 188*91f16700Schasinglulu uint64_t spm_mm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3) 189*91f16700Schasinglulu { 190*91f16700Schasinglulu uint64_t rc; 191*91f16700Schasinglulu sp_context_t *sp_ptr = &sp_ctx; 192*91f16700Schasinglulu 193*91f16700Schasinglulu #if CTX_INCLUDE_FPREGS 194*91f16700Schasinglulu /* 195*91f16700Schasinglulu * SP runs to completion, no need to restore FP registers of secure context. 196*91f16700Schasinglulu * Save FP registers only for non secure context. 197*91f16700Schasinglulu */ 198*91f16700Schasinglulu fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE))); 199*91f16700Schasinglulu #endif 200*91f16700Schasinglulu 201*91f16700Schasinglulu /* Wait until the Secure Partition is idle and set it to busy. */ 202*91f16700Schasinglulu sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY); 203*91f16700Schasinglulu 204*91f16700Schasinglulu /* Set values for registers on SP entry */ 205*91f16700Schasinglulu cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx); 206*91f16700Schasinglulu 207*91f16700Schasinglulu write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid); 208*91f16700Schasinglulu write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1); 209*91f16700Schasinglulu write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2); 210*91f16700Schasinglulu write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3); 211*91f16700Schasinglulu 212*91f16700Schasinglulu /* Jump to the Secure Partition. */ 213*91f16700Schasinglulu rc = spm_sp_synchronous_entry(sp_ptr); 214*91f16700Schasinglulu 215*91f16700Schasinglulu /* Flag Secure Partition as idle. */ 216*91f16700Schasinglulu assert(sp_ptr->state == SP_STATE_BUSY); 217*91f16700Schasinglulu sp_state_set(sp_ptr, SP_STATE_IDLE); 218*91f16700Schasinglulu 219*91f16700Schasinglulu #if CTX_INCLUDE_FPREGS 220*91f16700Schasinglulu /* 221*91f16700Schasinglulu * SP runs to completion, no need to save FP registers of secure context. 222*91f16700Schasinglulu * Restore only non secure world FP registers. 223*91f16700Schasinglulu */ 224*91f16700Schasinglulu fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE))); 225*91f16700Schasinglulu #endif 226*91f16700Schasinglulu 227*91f16700Schasinglulu return rc; 228*91f16700Schasinglulu } 229*91f16700Schasinglulu 230*91f16700Schasinglulu /******************************************************************************* 231*91f16700Schasinglulu * MM_COMMUNICATE handler 232*91f16700Schasinglulu ******************************************************************************/ 233*91f16700Schasinglulu static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie, 234*91f16700Schasinglulu uint64_t comm_buffer_address, 235*91f16700Schasinglulu uint64_t comm_size_address, void *handle) 236*91f16700Schasinglulu { 237*91f16700Schasinglulu uint64_t rc; 238*91f16700Schasinglulu 239*91f16700Schasinglulu /* Cookie. Reserved for future use. It must be zero. */ 240*91f16700Schasinglulu if (mm_cookie != 0U) { 241*91f16700Schasinglulu ERROR("MM_COMMUNICATE: cookie is not zero\n"); 242*91f16700Schasinglulu SMC_RET1(handle, SPM_MM_INVALID_PARAMETER); 243*91f16700Schasinglulu } 244*91f16700Schasinglulu 245*91f16700Schasinglulu if (comm_buffer_address == 0U) { 246*91f16700Schasinglulu ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n"); 247*91f16700Schasinglulu SMC_RET1(handle, SPM_MM_INVALID_PARAMETER); 248*91f16700Schasinglulu } 249*91f16700Schasinglulu 250*91f16700Schasinglulu if (comm_size_address != 0U) { 251*91f16700Schasinglulu VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n"); 252*91f16700Schasinglulu } 253*91f16700Schasinglulu 254*91f16700Schasinglulu /* 255*91f16700Schasinglulu * The current secure partition design mandates 256*91f16700Schasinglulu * - at any point, only a single core can be 257*91f16700Schasinglulu * executing in the secure partition. 258*91f16700Schasinglulu * - a core cannot be preempted by an interrupt 259*91f16700Schasinglulu * while executing in secure partition. 260*91f16700Schasinglulu * Raise the running priority of the core to the 261*91f16700Schasinglulu * interrupt level configured for secure partition 262*91f16700Schasinglulu * so as to block any interrupt from preempting this 263*91f16700Schasinglulu * core. 264*91f16700Schasinglulu */ 265*91f16700Schasinglulu ehf_activate_priority(PLAT_SP_PRI); 266*91f16700Schasinglulu 267*91f16700Schasinglulu /* Save the Normal world context */ 268*91f16700Schasinglulu cm_el1_sysregs_context_save(NON_SECURE); 269*91f16700Schasinglulu 270*91f16700Schasinglulu rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address, 271*91f16700Schasinglulu plat_my_core_pos()); 272*91f16700Schasinglulu 273*91f16700Schasinglulu /* Restore non-secure state */ 274*91f16700Schasinglulu cm_el1_sysregs_context_restore(NON_SECURE); 275*91f16700Schasinglulu cm_set_next_eret_context(NON_SECURE); 276*91f16700Schasinglulu 277*91f16700Schasinglulu /* 278*91f16700Schasinglulu * Exited from secure partition. This core can take 279*91f16700Schasinglulu * interrupts now. 280*91f16700Schasinglulu */ 281*91f16700Schasinglulu ehf_deactivate_priority(PLAT_SP_PRI); 282*91f16700Schasinglulu 283*91f16700Schasinglulu SMC_RET1(handle, rc); 284*91f16700Schasinglulu } 285*91f16700Schasinglulu 286*91f16700Schasinglulu /******************************************************************************* 287*91f16700Schasinglulu * Secure Partition Manager SMC handler. 288*91f16700Schasinglulu ******************************************************************************/ 289*91f16700Schasinglulu uint64_t spm_mm_smc_handler(uint32_t smc_fid, 290*91f16700Schasinglulu uint64_t x1, 291*91f16700Schasinglulu uint64_t x2, 292*91f16700Schasinglulu uint64_t x3, 293*91f16700Schasinglulu uint64_t x4, 294*91f16700Schasinglulu void *cookie, 295*91f16700Schasinglulu void *handle, 296*91f16700Schasinglulu uint64_t flags) 297*91f16700Schasinglulu { 298*91f16700Schasinglulu unsigned int ns; 299*91f16700Schasinglulu 300*91f16700Schasinglulu /* Determine which security state this SMC originated from */ 301*91f16700Schasinglulu ns = is_caller_non_secure(flags); 302*91f16700Schasinglulu 303*91f16700Schasinglulu if (ns == SMC_FROM_SECURE) { 304*91f16700Schasinglulu 305*91f16700Schasinglulu /* Handle SMCs from Secure world. */ 306*91f16700Schasinglulu 307*91f16700Schasinglulu assert(handle == cm_get_context(SECURE)); 308*91f16700Schasinglulu 309*91f16700Schasinglulu /* Make next ERET jump to S-EL0 instead of S-EL1. */ 310*91f16700Schasinglulu cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1()); 311*91f16700Schasinglulu 312*91f16700Schasinglulu switch (smc_fid) { 313*91f16700Schasinglulu 314*91f16700Schasinglulu case SPM_MM_VERSION_AARCH32: 315*91f16700Schasinglulu SMC_RET1(handle, SPM_MM_VERSION_COMPILED); 316*91f16700Schasinglulu 317*91f16700Schasinglulu case MM_SP_EVENT_COMPLETE_AARCH64: 318*91f16700Schasinglulu spm_sp_synchronous_exit(x1); 319*91f16700Schasinglulu 320*91f16700Schasinglulu case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64: 321*91f16700Schasinglulu INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n"); 322*91f16700Schasinglulu 323*91f16700Schasinglulu if (sp_ctx.state != SP_STATE_RESET) { 324*91f16700Schasinglulu WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n"); 325*91f16700Schasinglulu SMC_RET1(handle, SPM_MM_NOT_SUPPORTED); 326*91f16700Schasinglulu } 327*91f16700Schasinglulu SMC_RET1(handle, 328*91f16700Schasinglulu spm_memory_attributes_get_smc_handler( 329*91f16700Schasinglulu &sp_ctx, x1)); 330*91f16700Schasinglulu 331*91f16700Schasinglulu case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64: 332*91f16700Schasinglulu INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n"); 333*91f16700Schasinglulu 334*91f16700Schasinglulu if (sp_ctx.state != SP_STATE_RESET) { 335*91f16700Schasinglulu WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n"); 336*91f16700Schasinglulu SMC_RET1(handle, SPM_MM_NOT_SUPPORTED); 337*91f16700Schasinglulu } 338*91f16700Schasinglulu SMC_RET1(handle, 339*91f16700Schasinglulu spm_memory_attributes_set_smc_handler( 340*91f16700Schasinglulu &sp_ctx, x1, x2, x3)); 341*91f16700Schasinglulu default: 342*91f16700Schasinglulu break; 343*91f16700Schasinglulu } 344*91f16700Schasinglulu } else { 345*91f16700Schasinglulu 346*91f16700Schasinglulu /* Handle SMCs from Non-secure world. */ 347*91f16700Schasinglulu 348*91f16700Schasinglulu assert(handle == cm_get_context(NON_SECURE)); 349*91f16700Schasinglulu 350*91f16700Schasinglulu switch (smc_fid) { 351*91f16700Schasinglulu 352*91f16700Schasinglulu case MM_VERSION_AARCH32: 353*91f16700Schasinglulu SMC_RET1(handle, MM_VERSION_COMPILED); 354*91f16700Schasinglulu 355*91f16700Schasinglulu case MM_COMMUNICATE_AARCH32: 356*91f16700Schasinglulu case MM_COMMUNICATE_AARCH64: 357*91f16700Schasinglulu return mm_communicate(smc_fid, x1, x2, x3, handle); 358*91f16700Schasinglulu 359*91f16700Schasinglulu case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64: 360*91f16700Schasinglulu case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64: 361*91f16700Schasinglulu /* SMC interfaces reserved for secure callers. */ 362*91f16700Schasinglulu SMC_RET1(handle, SPM_MM_NOT_SUPPORTED); 363*91f16700Schasinglulu 364*91f16700Schasinglulu default: 365*91f16700Schasinglulu break; 366*91f16700Schasinglulu } 367*91f16700Schasinglulu } 368*91f16700Schasinglulu 369*91f16700Schasinglulu SMC_RET1(handle, SMC_UNK); 370*91f16700Schasinglulu } 371