1*77c27753SZelalem Aweke /* 2*77c27753SZelalem Aweke * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. 3*77c27753SZelalem Aweke * 4*77c27753SZelalem Aweke * SPDX-License-Identifier: BSD-3-Clause 5*77c27753SZelalem Aweke */ 6*77c27753SZelalem Aweke 7*77c27753SZelalem Aweke #include <assert.h> 8*77c27753SZelalem Aweke #include <errno.h> 9*77c27753SZelalem Aweke #include <string.h> 10*77c27753SZelalem Aweke 11*77c27753SZelalem Aweke #include <arch_helpers.h> 12*77c27753SZelalem Aweke #include <arch_features.h> 13*77c27753SZelalem Aweke #include <bl31/bl31.h> 14*77c27753SZelalem Aweke #include <common/debug.h> 15*77c27753SZelalem Aweke #include <common/runtime_svc.h> 16*77c27753SZelalem Aweke #include <context.h> 17*77c27753SZelalem Aweke #include <lib/el3_runtime/context_mgmt.h> 18*77c27753SZelalem Aweke #include <lib/el3_runtime/pubsub.h> 19*77c27753SZelalem Aweke #include <lib/gpt/gpt_defs.h> 20*77c27753SZelalem Aweke 21*77c27753SZelalem Aweke #include <lib/spinlock.h> 22*77c27753SZelalem Aweke #include <lib/utils.h> 23*77c27753SZelalem Aweke #include <lib/xlat_tables/xlat_tables_v2.h> 24*77c27753SZelalem Aweke #include <plat/common/common_def.h> 25*77c27753SZelalem Aweke #include <plat/common/platform.h> 26*77c27753SZelalem Aweke #include <platform_def.h> 27*77c27753SZelalem Aweke #include <services/gtsi_svc.h> 28*77c27753SZelalem Aweke #include <services/rmi_svc.h> 29*77c27753SZelalem Aweke #include <services/rmmd_svc.h> 30*77c27753SZelalem Aweke #include <smccc_helpers.h> 31*77c27753SZelalem Aweke #include "rmmd_initial_context.h" 32*77c27753SZelalem Aweke #include "rmmd_private.h" 33*77c27753SZelalem Aweke 34*77c27753SZelalem Aweke /******************************************************************************* 35*77c27753SZelalem Aweke * RMM context information. 36*77c27753SZelalem Aweke ******************************************************************************/ 37*77c27753SZelalem Aweke rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT]; 38*77c27753SZelalem Aweke 39*77c27753SZelalem Aweke /******************************************************************************* 40*77c27753SZelalem Aweke * RMM entry point information. Discovered on the primary core and reused 41*77c27753SZelalem Aweke * on secondary cores. 42*77c27753SZelalem Aweke ******************************************************************************/ 43*77c27753SZelalem Aweke static entry_point_info_t *rmm_ep_info; 44*77c27753SZelalem Aweke 45*77c27753SZelalem Aweke /******************************************************************************* 46*77c27753SZelalem Aweke * Static function declaration. 47*77c27753SZelalem Aweke ******************************************************************************/ 48*77c27753SZelalem Aweke static int32_t rmm_init(void); 49*77c27753SZelalem Aweke static uint64_t rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state, 50*77c27753SZelalem Aweke uint32_t dst_sec_state, uint64_t x1, 51*77c27753SZelalem Aweke uint64_t x2, uint64_t x3, uint64_t x4, 52*77c27753SZelalem Aweke void *handle); 53*77c27753SZelalem Aweke 54*77c27753SZelalem Aweke /******************************************************************************* 55*77c27753SZelalem Aweke * This function takes an RMM context pointer and performs a synchronous entry 56*77c27753SZelalem Aweke * into it. 57*77c27753SZelalem Aweke ******************************************************************************/ 58*77c27753SZelalem Aweke uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *rmm_ctx) 59*77c27753SZelalem Aweke { 60*77c27753SZelalem Aweke uint64_t rc; 61*77c27753SZelalem Aweke 62*77c27753SZelalem Aweke assert(rmm_ctx != NULL); 63*77c27753SZelalem Aweke 64*77c27753SZelalem Aweke cm_set_context(&(rmm_ctx->cpu_ctx), REALM); 65*77c27753SZelalem Aweke 66*77c27753SZelalem Aweke /* Save the current el1/el2 context before loading realm context. */ 67*77c27753SZelalem Aweke cm_el1_sysregs_context_save(NON_SECURE); 68*77c27753SZelalem Aweke cm_el2_sysregs_context_save(NON_SECURE); 69*77c27753SZelalem Aweke 70*77c27753SZelalem Aweke /* Restore the realm context assigned above */ 71*77c27753SZelalem Aweke cm_el1_sysregs_context_restore(REALM); 72*77c27753SZelalem Aweke cm_el2_sysregs_context_restore(REALM); 73*77c27753SZelalem Aweke cm_set_next_eret_context(REALM); 74*77c27753SZelalem Aweke 75*77c27753SZelalem Aweke /* Enter RMM */ 76*77c27753SZelalem Aweke rc = rmmd_rmm_enter(&rmm_ctx->c_rt_ctx); 77*77c27753SZelalem Aweke 78*77c27753SZelalem Aweke /* Save realm context */ 79*77c27753SZelalem Aweke cm_el1_sysregs_context_save(REALM); 80*77c27753SZelalem Aweke cm_el2_sysregs_context_save(REALM); 81*77c27753SZelalem Aweke 82*77c27753SZelalem Aweke /* Restore the el1/el2 context again. */ 83*77c27753SZelalem Aweke cm_el1_sysregs_context_restore(NON_SECURE); 84*77c27753SZelalem Aweke cm_el2_sysregs_context_restore(NON_SECURE); 85*77c27753SZelalem Aweke 86*77c27753SZelalem Aweke return rc; 87*77c27753SZelalem Aweke } 88*77c27753SZelalem Aweke 89*77c27753SZelalem Aweke /******************************************************************************* 90*77c27753SZelalem Aweke * This function returns to the place where rmmd_rmm_sync_entry() was 91*77c27753SZelalem Aweke * called originally. 92*77c27753SZelalem Aweke ******************************************************************************/ 93*77c27753SZelalem Aweke __dead2 void rmmd_rmm_sync_exit(uint64_t rc) 94*77c27753SZelalem Aweke { 95*77c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; 96*77c27753SZelalem Aweke 97*77c27753SZelalem Aweke /* Get context of the RMM in use by this CPU. */ 98*77c27753SZelalem Aweke assert(cm_get_context(REALM) == &(ctx->cpu_ctx)); 99*77c27753SZelalem Aweke 100*77c27753SZelalem Aweke /* 101*77c27753SZelalem Aweke * The RMMD must have initiated the original request through a 102*77c27753SZelalem Aweke * synchronous entry into RMM. Jump back to the original C runtime 103*77c27753SZelalem Aweke * context with the value of rc in x0; 104*77c27753SZelalem Aweke */ 105*77c27753SZelalem Aweke rmmd_rmm_exit(ctx->c_rt_ctx, rc); 106*77c27753SZelalem Aweke 107*77c27753SZelalem Aweke panic(); 108*77c27753SZelalem Aweke } 109*77c27753SZelalem Aweke 110*77c27753SZelalem Aweke static void rmm_el2_context_init(el2_sysregs_t *regs) 111*77c27753SZelalem Aweke { 112*77c27753SZelalem Aweke regs->ctx_regs[CTX_SPSR_EL2 >> 3] = REALM_SPSR_EL2; 113*77c27753SZelalem Aweke regs->ctx_regs[CTX_SCTLR_EL2 >> 3] = SCTLR_EL2_RES1; 114*77c27753SZelalem Aweke } 115*77c27753SZelalem Aweke 116*77c27753SZelalem Aweke /******************************************************************************* 117*77c27753SZelalem Aweke * Jump to the RMM for the first time. 118*77c27753SZelalem Aweke ******************************************************************************/ 119*77c27753SZelalem Aweke static int32_t rmm_init(void) 120*77c27753SZelalem Aweke { 121*77c27753SZelalem Aweke 122*77c27753SZelalem Aweke uint64_t rc; 123*77c27753SZelalem Aweke 124*77c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; 125*77c27753SZelalem Aweke 126*77c27753SZelalem Aweke INFO("RMM init start.\n"); 127*77c27753SZelalem Aweke ctx->state = RMM_STATE_RESET; 128*77c27753SZelalem Aweke 129*77c27753SZelalem Aweke /* Initialize RMM EL2 context. */ 130*77c27753SZelalem Aweke rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); 131*77c27753SZelalem Aweke 132*77c27753SZelalem Aweke rc = rmmd_rmm_sync_entry(ctx); 133*77c27753SZelalem Aweke if (rc != 0ULL) { 134*77c27753SZelalem Aweke ERROR("RMM initialisation failed 0x%llx\n", rc); 135*77c27753SZelalem Aweke panic(); 136*77c27753SZelalem Aweke } 137*77c27753SZelalem Aweke 138*77c27753SZelalem Aweke ctx->state = RMM_STATE_IDLE; 139*77c27753SZelalem Aweke INFO("RMM init end.\n"); 140*77c27753SZelalem Aweke 141*77c27753SZelalem Aweke return 1; 142*77c27753SZelalem Aweke } 143*77c27753SZelalem Aweke 144*77c27753SZelalem Aweke /******************************************************************************* 145*77c27753SZelalem Aweke * Load and read RMM manifest, setup RMM. 146*77c27753SZelalem Aweke ******************************************************************************/ 147*77c27753SZelalem Aweke int rmmd_setup(void) 148*77c27753SZelalem Aweke { 149*77c27753SZelalem Aweke uint32_t ep_attr; 150*77c27753SZelalem Aweke unsigned int linear_id = plat_my_core_pos(); 151*77c27753SZelalem Aweke rmmd_rmm_context_t *rmm_ctx = &rmm_context[linear_id]; 152*77c27753SZelalem Aweke 153*77c27753SZelalem Aweke /* Make sure RME is supported. */ 154*77c27753SZelalem Aweke assert(get_armv9_2_feat_rme_support() != 0U); 155*77c27753SZelalem Aweke 156*77c27753SZelalem Aweke rmm_ep_info = bl31_plat_get_next_image_ep_info(REALM); 157*77c27753SZelalem Aweke if (rmm_ep_info == NULL) { 158*77c27753SZelalem Aweke WARN("No RMM image provided by BL2 boot loader, Booting " 159*77c27753SZelalem Aweke "device without RMM initialization. SMCs destined for " 160*77c27753SZelalem Aweke "RMM will return SMC_UNK\n"); 161*77c27753SZelalem Aweke return -ENOENT; 162*77c27753SZelalem Aweke } 163*77c27753SZelalem Aweke 164*77c27753SZelalem Aweke /* Under no circumstances will this parameter be 0 */ 165*77c27753SZelalem Aweke assert(rmm_ep_info->pc == RMM_BASE); 166*77c27753SZelalem Aweke 167*77c27753SZelalem Aweke /* Initialise an entrypoint to set up the CPU context */ 168*77c27753SZelalem Aweke ep_attr = EP_REALM; 169*77c27753SZelalem Aweke if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0U) { 170*77c27753SZelalem Aweke ep_attr |= EP_EE_BIG; 171*77c27753SZelalem Aweke } 172*77c27753SZelalem Aweke 173*77c27753SZelalem Aweke SET_PARAM_HEAD(rmm_ep_info, PARAM_EP, VERSION_1, ep_attr); 174*77c27753SZelalem Aweke rmm_ep_info->spsr = SPSR_64(MODE_EL2, 175*77c27753SZelalem Aweke MODE_SP_ELX, 176*77c27753SZelalem Aweke DISABLE_ALL_EXCEPTIONS); 177*77c27753SZelalem Aweke 178*77c27753SZelalem Aweke /* Initialise RMM context with this entry point information */ 179*77c27753SZelalem Aweke cm_setup_context(&rmm_ctx->cpu_ctx, rmm_ep_info); 180*77c27753SZelalem Aweke 181*77c27753SZelalem Aweke INFO("RMM setup done.\n"); 182*77c27753SZelalem Aweke 183*77c27753SZelalem Aweke /* Register init function for deferred init. */ 184*77c27753SZelalem Aweke bl31_register_rmm_init(&rmm_init); 185*77c27753SZelalem Aweke 186*77c27753SZelalem Aweke return 0; 187*77c27753SZelalem Aweke } 188*77c27753SZelalem Aweke 189*77c27753SZelalem Aweke /******************************************************************************* 190*77c27753SZelalem Aweke * Forward SMC to the other security state 191*77c27753SZelalem Aweke ******************************************************************************/ 192*77c27753SZelalem Aweke static uint64_t rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state, 193*77c27753SZelalem Aweke uint32_t dst_sec_state, uint64_t x1, 194*77c27753SZelalem Aweke uint64_t x2, uint64_t x3, uint64_t x4, 195*77c27753SZelalem Aweke void *handle) 196*77c27753SZelalem Aweke { 197*77c27753SZelalem Aweke /* Save incoming security state */ 198*77c27753SZelalem Aweke cm_el1_sysregs_context_save(src_sec_state); 199*77c27753SZelalem Aweke cm_el2_sysregs_context_save(src_sec_state); 200*77c27753SZelalem Aweke 201*77c27753SZelalem Aweke /* Restore outgoing security state */ 202*77c27753SZelalem Aweke cm_el1_sysregs_context_restore(dst_sec_state); 203*77c27753SZelalem Aweke cm_el2_sysregs_context_restore(dst_sec_state); 204*77c27753SZelalem Aweke cm_set_next_eret_context(dst_sec_state); 205*77c27753SZelalem Aweke 206*77c27753SZelalem Aweke SMC_RET8(cm_get_context(dst_sec_state), smc_fid, x1, x2, x3, x4, 207*77c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X5), 208*77c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X6), 209*77c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X7)); 210*77c27753SZelalem Aweke } 211*77c27753SZelalem Aweke 212*77c27753SZelalem Aweke /******************************************************************************* 213*77c27753SZelalem Aweke * This function handles all SMCs in the range reserved for RMI. Each call is 214*77c27753SZelalem Aweke * either forwarded to the other security state or handled by the RMM dispatcher 215*77c27753SZelalem Aweke ******************************************************************************/ 216*77c27753SZelalem Aweke uint64_t rmmd_rmi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, 217*77c27753SZelalem Aweke uint64_t x3, uint64_t x4, void *cookie, 218*77c27753SZelalem Aweke void *handle, uint64_t flags) 219*77c27753SZelalem Aweke { 220*77c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; 221*77c27753SZelalem Aweke uint32_t src_sec_state; 222*77c27753SZelalem Aweke 223*77c27753SZelalem Aweke /* Determine which security state this SMC originated from */ 224*77c27753SZelalem Aweke src_sec_state = caller_sec_state(flags); 225*77c27753SZelalem Aweke 226*77c27753SZelalem Aweke /* RMI must not be invoked by the Secure world */ 227*77c27753SZelalem Aweke if (src_sec_state == SMC_FROM_SECURE) { 228*77c27753SZelalem Aweke WARN("RMM: RMI invoked by secure world.\n"); 229*77c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 230*77c27753SZelalem Aweke } 231*77c27753SZelalem Aweke 232*77c27753SZelalem Aweke /* 233*77c27753SZelalem Aweke * Forward an RMI call from the Normal world to the Realm world as it 234*77c27753SZelalem Aweke * is. 235*77c27753SZelalem Aweke */ 236*77c27753SZelalem Aweke if (src_sec_state == SMC_FROM_NON_SECURE) { 237*77c27753SZelalem Aweke VERBOSE("RMM: RMI call from non-secure world.\n"); 238*77c27753SZelalem Aweke return rmmd_smc_forward(smc_fid, NON_SECURE, REALM, 239*77c27753SZelalem Aweke x1, x2, x3, x4, handle); 240*77c27753SZelalem Aweke } 241*77c27753SZelalem Aweke 242*77c27753SZelalem Aweke assert(src_sec_state == SMC_FROM_REALM); 243*77c27753SZelalem Aweke 244*77c27753SZelalem Aweke switch (smc_fid) { 245*77c27753SZelalem Aweke case RMI_RMM_REQ_COMPLETE: 246*77c27753SZelalem Aweke if (ctx->state == RMM_STATE_RESET) { 247*77c27753SZelalem Aweke VERBOSE("RMM: running rmmd_rmm_sync_exit\n"); 248*77c27753SZelalem Aweke rmmd_rmm_sync_exit(x1); 249*77c27753SZelalem Aweke } 250*77c27753SZelalem Aweke 251*77c27753SZelalem Aweke return rmmd_smc_forward(x1, REALM, NON_SECURE, 252*77c27753SZelalem Aweke x2, x3, x4, 0, handle); 253*77c27753SZelalem Aweke 254*77c27753SZelalem Aweke default: 255*77c27753SZelalem Aweke WARN("RMM: Unsupported RMM call 0x%08x\n", smc_fid); 256*77c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 257*77c27753SZelalem Aweke } 258*77c27753SZelalem Aweke } 259*77c27753SZelalem Aweke 260*77c27753SZelalem Aweke /******************************************************************************* 261*77c27753SZelalem Aweke * This cpu has been turned on. Enter RMM to initialise R-EL2. Entry into RMM 262*77c27753SZelalem Aweke * is done after initialising minimal architectural state that guarantees safe 263*77c27753SZelalem Aweke * execution. 264*77c27753SZelalem Aweke ******************************************************************************/ 265*77c27753SZelalem Aweke static void *rmmd_cpu_on_finish_handler(const void *arg) 266*77c27753SZelalem Aweke { 267*77c27753SZelalem Aweke int32_t rc; 268*77c27753SZelalem Aweke uint32_t linear_id = plat_my_core_pos(); 269*77c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[linear_id]; 270*77c27753SZelalem Aweke 271*77c27753SZelalem Aweke ctx->state = RMM_STATE_RESET; 272*77c27753SZelalem Aweke 273*77c27753SZelalem Aweke /* Initialise RMM context with this entry point information */ 274*77c27753SZelalem Aweke cm_setup_context(&ctx->cpu_ctx, rmm_ep_info); 275*77c27753SZelalem Aweke 276*77c27753SZelalem Aweke /* Initialize RMM EL2 context. */ 277*77c27753SZelalem Aweke rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); 278*77c27753SZelalem Aweke 279*77c27753SZelalem Aweke rc = rmmd_rmm_sync_entry(ctx); 280*77c27753SZelalem Aweke if (rc != 0) { 281*77c27753SZelalem Aweke ERROR("RMM initialisation failed (%d) on CPU%d\n", rc, 282*77c27753SZelalem Aweke linear_id); 283*77c27753SZelalem Aweke panic(); 284*77c27753SZelalem Aweke } 285*77c27753SZelalem Aweke 286*77c27753SZelalem Aweke ctx->state = RMM_STATE_IDLE; 287*77c27753SZelalem Aweke return NULL; 288*77c27753SZelalem Aweke } 289*77c27753SZelalem Aweke 290*77c27753SZelalem Aweke /* Subscribe to PSCI CPU on to initialize RMM on secondary */ 291*77c27753SZelalem Aweke SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler); 292*77c27753SZelalem Aweke 293*77c27753SZelalem Aweke static int gtsi_transition_granule(uint64_t pa, 294*77c27753SZelalem Aweke unsigned int src_sec_state, 295*77c27753SZelalem Aweke unsigned int target_pas) 296*77c27753SZelalem Aweke { 297*77c27753SZelalem Aweke int ret; 298*77c27753SZelalem Aweke 299*77c27753SZelalem Aweke ret = gpt_transition_pas(pa, src_sec_state, target_pas); 300*77c27753SZelalem Aweke 301*77c27753SZelalem Aweke /* Convert TF-A error codes into GTSI error codes */ 302*77c27753SZelalem Aweke if (ret == -EINVAL) { 303*77c27753SZelalem Aweke ret = GRAN_TRANS_RET_BAD_ADDR; 304*77c27753SZelalem Aweke } else if (ret == -EPERM) { 305*77c27753SZelalem Aweke ret = GRAN_TRANS_RET_BAD_PAS; 306*77c27753SZelalem Aweke } 307*77c27753SZelalem Aweke 308*77c27753SZelalem Aweke return ret; 309*77c27753SZelalem Aweke } 310*77c27753SZelalem Aweke 311*77c27753SZelalem Aweke /******************************************************************************* 312*77c27753SZelalem Aweke * This function handles all SMCs in the range reserved for GTF. 313*77c27753SZelalem Aweke ******************************************************************************/ 314*77c27753SZelalem Aweke uint64_t rmmd_gtsi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, 315*77c27753SZelalem Aweke uint64_t x3, uint64_t x4, void *cookie, 316*77c27753SZelalem Aweke void *handle, uint64_t flags) 317*77c27753SZelalem Aweke { 318*77c27753SZelalem Aweke uint32_t src_sec_state; 319*77c27753SZelalem Aweke 320*77c27753SZelalem Aweke /* Determine which security state this SMC originated from */ 321*77c27753SZelalem Aweke src_sec_state = caller_sec_state(flags); 322*77c27753SZelalem Aweke 323*77c27753SZelalem Aweke if (src_sec_state != SMC_FROM_REALM) { 324*77c27753SZelalem Aweke WARN("RMM: GTF call originated from secure or normal world\n"); 325*77c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 326*77c27753SZelalem Aweke } 327*77c27753SZelalem Aweke 328*77c27753SZelalem Aweke switch (smc_fid) { 329*77c27753SZelalem Aweke case SMC_ASC_MARK_REALM: 330*77c27753SZelalem Aweke SMC_RET1(handle, gtsi_transition_granule(x1, SMC_FROM_REALM, 331*77c27753SZelalem Aweke GPI_REALM)); 332*77c27753SZelalem Aweke break; 333*77c27753SZelalem Aweke case SMC_ASC_MARK_NONSECURE: 334*77c27753SZelalem Aweke SMC_RET1(handle, gtsi_transition_granule(x1, SMC_FROM_REALM, 335*77c27753SZelalem Aweke GPI_NS)); 336*77c27753SZelalem Aweke break; 337*77c27753SZelalem Aweke default: 338*77c27753SZelalem Aweke WARN("RMM: Unsupported GTF call 0x%08x\n", smc_fid); 339*77c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 340*77c27753SZelalem Aweke } 341*77c27753SZelalem Aweke } 342