1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017-2021, 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 <inttypes.h> 9*91f16700Schasinglulu #include <stdint.h> 10*91f16700Schasinglulu #include <string.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <arch_helpers.h> 13*91f16700Schasinglulu #include <arch_features.h> 14*91f16700Schasinglulu #include <bl31/ehf.h> 15*91f16700Schasinglulu #include <bl31/interrupt_mgmt.h> 16*91f16700Schasinglulu #include <common/bl_common.h> 17*91f16700Schasinglulu #include <common/debug.h> 18*91f16700Schasinglulu #include <common/runtime_svc.h> 19*91f16700Schasinglulu #include <lib/cassert.h> 20*91f16700Schasinglulu #include <services/sdei.h> 21*91f16700Schasinglulu 22*91f16700Schasinglulu #include "sdei_private.h" 23*91f16700Schasinglulu 24*91f16700Schasinglulu /* x0-x17 GPREGS context */ 25*91f16700Schasinglulu #define SDEI_SAVED_GPREGS 18U 26*91f16700Schasinglulu 27*91f16700Schasinglulu /* Maximum preemption nesting levels: Critical priority and Normal priority */ 28*91f16700Schasinglulu #define MAX_EVENT_NESTING 2U 29*91f16700Schasinglulu 30*91f16700Schasinglulu /* Per-CPU SDEI state access macro */ 31*91f16700Schasinglulu #define sdei_get_this_pe_state() (&cpu_state[plat_my_core_pos()]) 32*91f16700Schasinglulu 33*91f16700Schasinglulu /* Structure to store information about an outstanding dispatch */ 34*91f16700Schasinglulu typedef struct sdei_dispatch_context { 35*91f16700Schasinglulu sdei_ev_map_t *map; 36*91f16700Schasinglulu uint64_t x[SDEI_SAVED_GPREGS]; 37*91f16700Schasinglulu jmp_buf *dispatch_jmp; 38*91f16700Schasinglulu 39*91f16700Schasinglulu /* Exception state registers */ 40*91f16700Schasinglulu uint64_t elr_el3; 41*91f16700Schasinglulu uint64_t spsr_el3; 42*91f16700Schasinglulu 43*91f16700Schasinglulu #if DYNAMIC_WORKAROUND_CVE_2018_3639 44*91f16700Schasinglulu /* CVE-2018-3639 mitigation state */ 45*91f16700Schasinglulu uint64_t disable_cve_2018_3639; 46*91f16700Schasinglulu #endif 47*91f16700Schasinglulu } sdei_dispatch_context_t; 48*91f16700Schasinglulu 49*91f16700Schasinglulu /* Per-CPU SDEI state data */ 50*91f16700Schasinglulu typedef struct sdei_cpu_state { 51*91f16700Schasinglulu sdei_dispatch_context_t dispatch_stack[MAX_EVENT_NESTING]; 52*91f16700Schasinglulu unsigned short stack_top; /* Empty ascending */ 53*91f16700Schasinglulu bool pe_masked; 54*91f16700Schasinglulu bool pending_enables; 55*91f16700Schasinglulu } sdei_cpu_state_t; 56*91f16700Schasinglulu 57*91f16700Schasinglulu /* SDEI states for all cores in the system */ 58*91f16700Schasinglulu static sdei_cpu_state_t cpu_state[PLATFORM_CORE_COUNT]; 59*91f16700Schasinglulu 60*91f16700Schasinglulu int64_t sdei_pe_mask(void) 61*91f16700Schasinglulu { 62*91f16700Schasinglulu int64_t ret = 0; 63*91f16700Schasinglulu sdei_cpu_state_t *state = sdei_get_this_pe_state(); 64*91f16700Schasinglulu 65*91f16700Schasinglulu /* 66*91f16700Schasinglulu * Return value indicates whether this call had any effect in the mask 67*91f16700Schasinglulu * status of this PE. 68*91f16700Schasinglulu */ 69*91f16700Schasinglulu if (!state->pe_masked) { 70*91f16700Schasinglulu state->pe_masked = true; 71*91f16700Schasinglulu ret = 1; 72*91f16700Schasinglulu } 73*91f16700Schasinglulu 74*91f16700Schasinglulu return ret; 75*91f16700Schasinglulu } 76*91f16700Schasinglulu 77*91f16700Schasinglulu void sdei_pe_unmask(void) 78*91f16700Schasinglulu { 79*91f16700Schasinglulu unsigned int i; 80*91f16700Schasinglulu sdei_ev_map_t *map; 81*91f16700Schasinglulu sdei_entry_t *se; 82*91f16700Schasinglulu sdei_cpu_state_t *state = sdei_get_this_pe_state(); 83*91f16700Schasinglulu uint64_t my_mpidr = read_mpidr_el1() & MPIDR_AFFINITY_MASK; 84*91f16700Schasinglulu 85*91f16700Schasinglulu /* 86*91f16700Schasinglulu * If there are pending enables, iterate through the private mappings 87*91f16700Schasinglulu * and enable those bound maps that are in enabled state. Also, iterate 88*91f16700Schasinglulu * through shared mappings and enable interrupts of events that are 89*91f16700Schasinglulu * targeted to this PE. 90*91f16700Schasinglulu */ 91*91f16700Schasinglulu if (state->pending_enables) { 92*91f16700Schasinglulu for_each_private_map(i, map) { 93*91f16700Schasinglulu se = get_event_entry(map); 94*91f16700Schasinglulu if (is_map_bound(map) && GET_EV_STATE(se, ENABLED)) 95*91f16700Schasinglulu plat_ic_enable_interrupt(map->intr); 96*91f16700Schasinglulu } 97*91f16700Schasinglulu 98*91f16700Schasinglulu for_each_shared_map(i, map) { 99*91f16700Schasinglulu se = get_event_entry(map); 100*91f16700Schasinglulu 101*91f16700Schasinglulu sdei_map_lock(map); 102*91f16700Schasinglulu if (is_map_bound(map) && GET_EV_STATE(se, ENABLED) && 103*91f16700Schasinglulu (se->reg_flags == SDEI_REGF_RM_PE) && 104*91f16700Schasinglulu (se->affinity == my_mpidr)) { 105*91f16700Schasinglulu plat_ic_enable_interrupt(map->intr); 106*91f16700Schasinglulu } 107*91f16700Schasinglulu sdei_map_unlock(map); 108*91f16700Schasinglulu } 109*91f16700Schasinglulu } 110*91f16700Schasinglulu 111*91f16700Schasinglulu state->pending_enables = false; 112*91f16700Schasinglulu state->pe_masked = false; 113*91f16700Schasinglulu } 114*91f16700Schasinglulu 115*91f16700Schasinglulu /* Push a dispatch context to the dispatch stack */ 116*91f16700Schasinglulu static sdei_dispatch_context_t *push_dispatch(void) 117*91f16700Schasinglulu { 118*91f16700Schasinglulu sdei_cpu_state_t *state = sdei_get_this_pe_state(); 119*91f16700Schasinglulu sdei_dispatch_context_t *disp_ctx; 120*91f16700Schasinglulu 121*91f16700Schasinglulu /* Cannot have more than max events */ 122*91f16700Schasinglulu assert(state->stack_top < MAX_EVENT_NESTING); 123*91f16700Schasinglulu 124*91f16700Schasinglulu disp_ctx = &state->dispatch_stack[state->stack_top]; 125*91f16700Schasinglulu state->stack_top++; 126*91f16700Schasinglulu 127*91f16700Schasinglulu return disp_ctx; 128*91f16700Schasinglulu } 129*91f16700Schasinglulu 130*91f16700Schasinglulu /* Pop a dispatch context to the dispatch stack */ 131*91f16700Schasinglulu static sdei_dispatch_context_t *pop_dispatch(void) 132*91f16700Schasinglulu { 133*91f16700Schasinglulu sdei_cpu_state_t *state = sdei_get_this_pe_state(); 134*91f16700Schasinglulu 135*91f16700Schasinglulu if (state->stack_top == 0U) 136*91f16700Schasinglulu return NULL; 137*91f16700Schasinglulu 138*91f16700Schasinglulu assert(state->stack_top <= MAX_EVENT_NESTING); 139*91f16700Schasinglulu 140*91f16700Schasinglulu state->stack_top--; 141*91f16700Schasinglulu 142*91f16700Schasinglulu return &state->dispatch_stack[state->stack_top]; 143*91f16700Schasinglulu } 144*91f16700Schasinglulu 145*91f16700Schasinglulu /* Retrieve the context at the top of dispatch stack */ 146*91f16700Schasinglulu static sdei_dispatch_context_t *get_outstanding_dispatch(void) 147*91f16700Schasinglulu { 148*91f16700Schasinglulu sdei_cpu_state_t *state = sdei_get_this_pe_state(); 149*91f16700Schasinglulu 150*91f16700Schasinglulu if (state->stack_top == 0U) 151*91f16700Schasinglulu return NULL; 152*91f16700Schasinglulu 153*91f16700Schasinglulu assert(state->stack_top <= MAX_EVENT_NESTING); 154*91f16700Schasinglulu 155*91f16700Schasinglulu return &state->dispatch_stack[state->stack_top - 1U]; 156*91f16700Schasinglulu } 157*91f16700Schasinglulu 158*91f16700Schasinglulu static sdei_dispatch_context_t *save_event_ctx(sdei_ev_map_t *map, 159*91f16700Schasinglulu void *tgt_ctx) 160*91f16700Schasinglulu { 161*91f16700Schasinglulu sdei_dispatch_context_t *disp_ctx; 162*91f16700Schasinglulu const gp_regs_t *tgt_gpregs; 163*91f16700Schasinglulu const el3_state_t *tgt_el3; 164*91f16700Schasinglulu 165*91f16700Schasinglulu assert(tgt_ctx != NULL); 166*91f16700Schasinglulu tgt_gpregs = get_gpregs_ctx(tgt_ctx); 167*91f16700Schasinglulu tgt_el3 = get_el3state_ctx(tgt_ctx); 168*91f16700Schasinglulu 169*91f16700Schasinglulu disp_ctx = push_dispatch(); 170*91f16700Schasinglulu assert(disp_ctx != NULL); 171*91f16700Schasinglulu disp_ctx->map = map; 172*91f16700Schasinglulu 173*91f16700Schasinglulu /* Save general purpose and exception registers */ 174*91f16700Schasinglulu memcpy(disp_ctx->x, tgt_gpregs, sizeof(disp_ctx->x)); 175*91f16700Schasinglulu disp_ctx->spsr_el3 = read_ctx_reg(tgt_el3, CTX_SPSR_EL3); 176*91f16700Schasinglulu disp_ctx->elr_el3 = read_ctx_reg(tgt_el3, CTX_ELR_EL3); 177*91f16700Schasinglulu 178*91f16700Schasinglulu return disp_ctx; 179*91f16700Schasinglulu } 180*91f16700Schasinglulu 181*91f16700Schasinglulu static void restore_event_ctx(const sdei_dispatch_context_t *disp_ctx, void *tgt_ctx) 182*91f16700Schasinglulu { 183*91f16700Schasinglulu gp_regs_t *tgt_gpregs; 184*91f16700Schasinglulu el3_state_t *tgt_el3; 185*91f16700Schasinglulu 186*91f16700Schasinglulu assert(tgt_ctx != NULL); 187*91f16700Schasinglulu tgt_gpregs = get_gpregs_ctx(tgt_ctx); 188*91f16700Schasinglulu tgt_el3 = get_el3state_ctx(tgt_ctx); 189*91f16700Schasinglulu 190*91f16700Schasinglulu CASSERT(sizeof(disp_ctx->x) == (SDEI_SAVED_GPREGS * sizeof(uint64_t)), 191*91f16700Schasinglulu foo); 192*91f16700Schasinglulu 193*91f16700Schasinglulu /* Restore general purpose and exception registers */ 194*91f16700Schasinglulu memcpy(tgt_gpregs, disp_ctx->x, sizeof(disp_ctx->x)); 195*91f16700Schasinglulu write_ctx_reg(tgt_el3, CTX_SPSR_EL3, disp_ctx->spsr_el3); 196*91f16700Schasinglulu write_ctx_reg(tgt_el3, CTX_ELR_EL3, disp_ctx->elr_el3); 197*91f16700Schasinglulu 198*91f16700Schasinglulu #if DYNAMIC_WORKAROUND_CVE_2018_3639 199*91f16700Schasinglulu cve_2018_3639_t *tgt_cve_2018_3639; 200*91f16700Schasinglulu tgt_cve_2018_3639 = get_cve_2018_3639_ctx(tgt_ctx); 201*91f16700Schasinglulu 202*91f16700Schasinglulu /* Restore CVE-2018-3639 mitigation state */ 203*91f16700Schasinglulu write_ctx_reg(tgt_cve_2018_3639, CTX_CVE_2018_3639_DISABLE, 204*91f16700Schasinglulu disp_ctx->disable_cve_2018_3639); 205*91f16700Schasinglulu #endif 206*91f16700Schasinglulu } 207*91f16700Schasinglulu 208*91f16700Schasinglulu static void save_secure_context(void) 209*91f16700Schasinglulu { 210*91f16700Schasinglulu cm_el1_sysregs_context_save(SECURE); 211*91f16700Schasinglulu } 212*91f16700Schasinglulu 213*91f16700Schasinglulu /* Restore Secure context and arrange to resume it at the next ERET */ 214*91f16700Schasinglulu static void restore_and_resume_secure_context(void) 215*91f16700Schasinglulu { 216*91f16700Schasinglulu cm_el1_sysregs_context_restore(SECURE); 217*91f16700Schasinglulu cm_set_next_eret_context(SECURE); 218*91f16700Schasinglulu } 219*91f16700Schasinglulu 220*91f16700Schasinglulu /* 221*91f16700Schasinglulu * Restore Non-secure context and arrange to resume it at the next ERET. Return 222*91f16700Schasinglulu * pointer to the Non-secure context. 223*91f16700Schasinglulu */ 224*91f16700Schasinglulu static cpu_context_t *restore_and_resume_ns_context(void) 225*91f16700Schasinglulu { 226*91f16700Schasinglulu cpu_context_t *ns_ctx; 227*91f16700Schasinglulu 228*91f16700Schasinglulu cm_el1_sysregs_context_restore(NON_SECURE); 229*91f16700Schasinglulu cm_set_next_eret_context(NON_SECURE); 230*91f16700Schasinglulu 231*91f16700Schasinglulu ns_ctx = cm_get_context(NON_SECURE); 232*91f16700Schasinglulu assert(ns_ctx != NULL); 233*91f16700Schasinglulu 234*91f16700Schasinglulu return ns_ctx; 235*91f16700Schasinglulu } 236*91f16700Schasinglulu 237*91f16700Schasinglulu /* 238*91f16700Schasinglulu * Prepare for ERET: 239*91f16700Schasinglulu * - Set the ELR to the registered handler address 240*91f16700Schasinglulu * - Set the SPSR register as described in the SDEI documentation and 241*91f16700Schasinglulu * the AArch64.TakeException() pseudocode function in 242*91f16700Schasinglulu * ARM DDI 0487F.c page J1-7635 243*91f16700Schasinglulu */ 244*91f16700Schasinglulu 245*91f16700Schasinglulu static void sdei_set_elr_spsr(sdei_entry_t *se, sdei_dispatch_context_t *disp_ctx) 246*91f16700Schasinglulu { 247*91f16700Schasinglulu unsigned int client_el = sdei_client_el(); 248*91f16700Schasinglulu u_register_t sdei_spsr = SPSR_64(client_el, MODE_SP_ELX, 249*91f16700Schasinglulu DISABLE_ALL_EXCEPTIONS); 250*91f16700Schasinglulu 251*91f16700Schasinglulu u_register_t interrupted_pstate = disp_ctx->spsr_el3; 252*91f16700Schasinglulu 253*91f16700Schasinglulu /* Check the SPAN bit in the client el SCTLR */ 254*91f16700Schasinglulu u_register_t client_el_sctlr; 255*91f16700Schasinglulu 256*91f16700Schasinglulu if (client_el == MODE_EL2) { 257*91f16700Schasinglulu client_el_sctlr = read_sctlr_el2(); 258*91f16700Schasinglulu } else { 259*91f16700Schasinglulu client_el_sctlr = read_sctlr_el1(); 260*91f16700Schasinglulu } 261*91f16700Schasinglulu 262*91f16700Schasinglulu /* 263*91f16700Schasinglulu * Check whether to force the PAN bit or use the value in the 264*91f16700Schasinglulu * interrupted EL according to the check described in 265*91f16700Schasinglulu * TakeException. Since the client can only be Non-Secure 266*91f16700Schasinglulu * EL2 or El1 some of the conditions in ElIsInHost() we know 267*91f16700Schasinglulu * will always be True. 268*91f16700Schasinglulu * When the client_el is EL2 we know that there will be a SPAN 269*91f16700Schasinglulu * bit in SCTLR_EL2 as we have already checked for the condition 270*91f16700Schasinglulu * HCR_EL2.E2H = 1 and HCR_EL2.TGE = 1 271*91f16700Schasinglulu */ 272*91f16700Schasinglulu u_register_t hcr_el2 = read_hcr(); 273*91f16700Schasinglulu bool el_is_in_host = (read_feat_vhe_id_field() != 0U) && 274*91f16700Schasinglulu (hcr_el2 & HCR_TGE_BIT) && 275*91f16700Schasinglulu (hcr_el2 & HCR_E2H_BIT); 276*91f16700Schasinglulu 277*91f16700Schasinglulu if (is_feat_pan_supported() && 278*91f16700Schasinglulu ((client_el == MODE_EL1) || 279*91f16700Schasinglulu (client_el == MODE_EL2 && el_is_in_host)) && 280*91f16700Schasinglulu ((client_el_sctlr & SCTLR_SPAN_BIT) == 0U)) { 281*91f16700Schasinglulu sdei_spsr |= SPSR_PAN_BIT; 282*91f16700Schasinglulu } else { 283*91f16700Schasinglulu sdei_spsr |= (interrupted_pstate & SPSR_PAN_BIT); 284*91f16700Schasinglulu } 285*91f16700Schasinglulu 286*91f16700Schasinglulu /* If SSBS is implemented, take the value from the client el SCTLR */ 287*91f16700Schasinglulu u_register_t ssbs_enabled = (read_id_aa64pfr1_el1() 288*91f16700Schasinglulu >> ID_AA64PFR1_EL1_SSBS_SHIFT) 289*91f16700Schasinglulu & ID_AA64PFR1_EL1_SSBS_MASK; 290*91f16700Schasinglulu if (ssbs_enabled != SSBS_UNAVAILABLE) { 291*91f16700Schasinglulu u_register_t ssbs_bit = ((client_el_sctlr & SCTLR_DSSBS_BIT) 292*91f16700Schasinglulu >> SCTLR_DSSBS_SHIFT) 293*91f16700Schasinglulu << SPSR_SSBS_SHIFT_AARCH64; 294*91f16700Schasinglulu sdei_spsr |= ssbs_bit; 295*91f16700Schasinglulu } 296*91f16700Schasinglulu 297*91f16700Schasinglulu /* If MTE is implemented in the client el set the TCO bit */ 298*91f16700Schasinglulu if (get_armv8_5_mte_support() >= MTE_IMPLEMENTED_ELX) { 299*91f16700Schasinglulu sdei_spsr |= SPSR_TCO_BIT_AARCH64; 300*91f16700Schasinglulu } 301*91f16700Schasinglulu 302*91f16700Schasinglulu /* Take the DIT field from the pstate of the interrupted el */ 303*91f16700Schasinglulu sdei_spsr |= (interrupted_pstate & SPSR_DIT_BIT); 304*91f16700Schasinglulu 305*91f16700Schasinglulu cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep, sdei_spsr); 306*91f16700Schasinglulu } 307*91f16700Schasinglulu 308*91f16700Schasinglulu /* 309*91f16700Schasinglulu * Populate the Non-secure context so that the next ERET will dispatch to the 310*91f16700Schasinglulu * SDEI client. 311*91f16700Schasinglulu */ 312*91f16700Schasinglulu static void setup_ns_dispatch(sdei_ev_map_t *map, sdei_entry_t *se, 313*91f16700Schasinglulu cpu_context_t *ctx, jmp_buf *dispatch_jmp) 314*91f16700Schasinglulu { 315*91f16700Schasinglulu sdei_dispatch_context_t *disp_ctx; 316*91f16700Schasinglulu 317*91f16700Schasinglulu /* Push the event and context */ 318*91f16700Schasinglulu disp_ctx = save_event_ctx(map, ctx); 319*91f16700Schasinglulu 320*91f16700Schasinglulu /* 321*91f16700Schasinglulu * Setup handler arguments: 322*91f16700Schasinglulu * 323*91f16700Schasinglulu * - x0: Event number 324*91f16700Schasinglulu * - x1: Handler argument supplied at the time of event registration 325*91f16700Schasinglulu * - x2: Interrupted PC 326*91f16700Schasinglulu * - x3: Interrupted SPSR 327*91f16700Schasinglulu */ 328*91f16700Schasinglulu SMC_SET_GP(ctx, CTX_GPREG_X0, (uint64_t) map->ev_num); 329*91f16700Schasinglulu SMC_SET_GP(ctx, CTX_GPREG_X1, se->arg); 330*91f16700Schasinglulu SMC_SET_GP(ctx, CTX_GPREG_X2, disp_ctx->elr_el3); 331*91f16700Schasinglulu SMC_SET_GP(ctx, CTX_GPREG_X3, disp_ctx->spsr_el3); 332*91f16700Schasinglulu 333*91f16700Schasinglulu /* Setup the elr and spsr register to prepare for ERET */ 334*91f16700Schasinglulu sdei_set_elr_spsr(se, disp_ctx); 335*91f16700Schasinglulu 336*91f16700Schasinglulu #if DYNAMIC_WORKAROUND_CVE_2018_3639 337*91f16700Schasinglulu cve_2018_3639_t *tgt_cve_2018_3639; 338*91f16700Schasinglulu tgt_cve_2018_3639 = get_cve_2018_3639_ctx(ctx); 339*91f16700Schasinglulu 340*91f16700Schasinglulu /* Save CVE-2018-3639 mitigation state */ 341*91f16700Schasinglulu disp_ctx->disable_cve_2018_3639 = read_ctx_reg(tgt_cve_2018_3639, 342*91f16700Schasinglulu CTX_CVE_2018_3639_DISABLE); 343*91f16700Schasinglulu 344*91f16700Schasinglulu /* Force SDEI handler to execute with mitigation enabled by default */ 345*91f16700Schasinglulu write_ctx_reg(tgt_cve_2018_3639, CTX_CVE_2018_3639_DISABLE, 0); 346*91f16700Schasinglulu #endif 347*91f16700Schasinglulu 348*91f16700Schasinglulu disp_ctx->dispatch_jmp = dispatch_jmp; 349*91f16700Schasinglulu } 350*91f16700Schasinglulu 351*91f16700Schasinglulu /* Handle a triggered SDEI interrupt while events were masked on this PE */ 352*91f16700Schasinglulu static void handle_masked_trigger(sdei_ev_map_t *map, sdei_entry_t *se, 353*91f16700Schasinglulu sdei_cpu_state_t *state, unsigned int intr_raw) 354*91f16700Schasinglulu { 355*91f16700Schasinglulu uint64_t my_mpidr __unused = (read_mpidr_el1() & MPIDR_AFFINITY_MASK); 356*91f16700Schasinglulu bool disable = false; 357*91f16700Schasinglulu 358*91f16700Schasinglulu /* Nothing to do for event 0 */ 359*91f16700Schasinglulu if (map->ev_num == SDEI_EVENT_0) 360*91f16700Schasinglulu return; 361*91f16700Schasinglulu 362*91f16700Schasinglulu /* 363*91f16700Schasinglulu * For a private event, or for a shared event specifically routed to 364*91f16700Schasinglulu * this CPU, we disable interrupt, leave the interrupt pending, and do 365*91f16700Schasinglulu * EOI. 366*91f16700Schasinglulu */ 367*91f16700Schasinglulu if (is_event_private(map) || (se->reg_flags == SDEI_REGF_RM_PE)) 368*91f16700Schasinglulu disable = true; 369*91f16700Schasinglulu 370*91f16700Schasinglulu if (se->reg_flags == SDEI_REGF_RM_PE) 371*91f16700Schasinglulu assert(se->affinity == my_mpidr); 372*91f16700Schasinglulu 373*91f16700Schasinglulu if (disable) { 374*91f16700Schasinglulu plat_ic_disable_interrupt(map->intr); 375*91f16700Schasinglulu plat_ic_set_interrupt_pending(map->intr); 376*91f16700Schasinglulu plat_ic_end_of_interrupt(intr_raw); 377*91f16700Schasinglulu state->pending_enables = true; 378*91f16700Schasinglulu 379*91f16700Schasinglulu return; 380*91f16700Schasinglulu } 381*91f16700Schasinglulu 382*91f16700Schasinglulu /* 383*91f16700Schasinglulu * We just received a shared event with routing set to ANY PE. The 384*91f16700Schasinglulu * interrupt can't be delegated on this PE as SDEI events are masked. 385*91f16700Schasinglulu * However, because its routing mode is ANY, it is possible that the 386*91f16700Schasinglulu * event can be delegated on any other PE that hasn't masked events. 387*91f16700Schasinglulu * Therefore, we set the interrupt back pending so as to give other 388*91f16700Schasinglulu * suitable PEs a chance of handling it. 389*91f16700Schasinglulu */ 390*91f16700Schasinglulu assert(plat_ic_is_spi(map->intr) != 0); 391*91f16700Schasinglulu plat_ic_set_interrupt_pending(map->intr); 392*91f16700Schasinglulu 393*91f16700Schasinglulu /* 394*91f16700Schasinglulu * Leaving the same interrupt pending also means that the same interrupt 395*91f16700Schasinglulu * can target this PE again as soon as this PE leaves EL3. Whether and 396*91f16700Schasinglulu * how often that happens depends on the implementation of GIC. 397*91f16700Schasinglulu * 398*91f16700Schasinglulu * We therefore call a platform handler to resolve this situation. 399*91f16700Schasinglulu */ 400*91f16700Schasinglulu plat_sdei_handle_masked_trigger(my_mpidr, map->intr); 401*91f16700Schasinglulu 402*91f16700Schasinglulu /* This PE is masked. We EOI the interrupt, as it can't be delegated */ 403*91f16700Schasinglulu plat_ic_end_of_interrupt(intr_raw); 404*91f16700Schasinglulu } 405*91f16700Schasinglulu 406*91f16700Schasinglulu /* SDEI main interrupt handler */ 407*91f16700Schasinglulu int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, 408*91f16700Schasinglulu void *cookie) 409*91f16700Schasinglulu { 410*91f16700Schasinglulu sdei_entry_t *se; 411*91f16700Schasinglulu cpu_context_t *ctx; 412*91f16700Schasinglulu sdei_ev_map_t *map; 413*91f16700Schasinglulu const sdei_dispatch_context_t *disp_ctx; 414*91f16700Schasinglulu unsigned int sec_state; 415*91f16700Schasinglulu sdei_cpu_state_t *state; 416*91f16700Schasinglulu uint32_t intr; 417*91f16700Schasinglulu jmp_buf dispatch_jmp; 418*91f16700Schasinglulu const uint64_t mpidr = read_mpidr_el1(); 419*91f16700Schasinglulu 420*91f16700Schasinglulu /* 421*91f16700Schasinglulu * To handle an event, the following conditions must be true: 422*91f16700Schasinglulu * 423*91f16700Schasinglulu * 1. Event must be signalled 424*91f16700Schasinglulu * 2. Event must be enabled 425*91f16700Schasinglulu * 3. This PE must be a target PE for the event 426*91f16700Schasinglulu * 4. PE must be unmasked for SDEI 427*91f16700Schasinglulu * 5. If this is a normal event, no event must be running 428*91f16700Schasinglulu * 6. If this is a critical event, no critical event must be running 429*91f16700Schasinglulu * 430*91f16700Schasinglulu * (1) and (2) are true when this function is running 431*91f16700Schasinglulu * (3) is enforced in GIC by selecting the appropriate routing option 432*91f16700Schasinglulu * (4) is satisfied by client calling PE_UNMASK 433*91f16700Schasinglulu * (5) and (6) is enforced using interrupt priority, the RPR, in GIC: 434*91f16700Schasinglulu * - Normal SDEI events belong to Normal SDE priority class 435*91f16700Schasinglulu * - Critical SDEI events belong to Critical CSDE priority class 436*91f16700Schasinglulu * 437*91f16700Schasinglulu * The interrupt has already been acknowledged, and therefore is active, 438*91f16700Schasinglulu * so no other PE can handle this event while we are at it. 439*91f16700Schasinglulu * 440*91f16700Schasinglulu * Find if this is an SDEI interrupt. There must be an event mapped to 441*91f16700Schasinglulu * this interrupt 442*91f16700Schasinglulu */ 443*91f16700Schasinglulu intr = plat_ic_get_interrupt_id(intr_raw); 444*91f16700Schasinglulu map = find_event_map_by_intr(intr, (plat_ic_is_spi(intr) != 0)); 445*91f16700Schasinglulu if (map == NULL) { 446*91f16700Schasinglulu ERROR("No SDEI map for interrupt %u\n", intr); 447*91f16700Schasinglulu panic(); 448*91f16700Schasinglulu } 449*91f16700Schasinglulu 450*91f16700Schasinglulu /* 451*91f16700Schasinglulu * Received interrupt number must either correspond to event 0, or must 452*91f16700Schasinglulu * be bound interrupt. 453*91f16700Schasinglulu */ 454*91f16700Schasinglulu assert((map->ev_num == SDEI_EVENT_0) || is_map_bound(map)); 455*91f16700Schasinglulu 456*91f16700Schasinglulu se = get_event_entry(map); 457*91f16700Schasinglulu state = sdei_get_this_pe_state(); 458*91f16700Schasinglulu 459*91f16700Schasinglulu if (state->pe_masked) { 460*91f16700Schasinglulu /* 461*91f16700Schasinglulu * Interrupts received while this PE was masked can't be 462*91f16700Schasinglulu * dispatched. 463*91f16700Schasinglulu */ 464*91f16700Schasinglulu SDEI_LOG("interrupt %u on %" PRIx64 " while PE masked\n", 465*91f16700Schasinglulu map->intr, mpidr); 466*91f16700Schasinglulu if (is_event_shared(map)) 467*91f16700Schasinglulu sdei_map_lock(map); 468*91f16700Schasinglulu 469*91f16700Schasinglulu handle_masked_trigger(map, se, state, intr_raw); 470*91f16700Schasinglulu 471*91f16700Schasinglulu if (is_event_shared(map)) 472*91f16700Schasinglulu sdei_map_unlock(map); 473*91f16700Schasinglulu 474*91f16700Schasinglulu return 0; 475*91f16700Schasinglulu } 476*91f16700Schasinglulu 477*91f16700Schasinglulu /* Insert load barrier for signalled SDEI event */ 478*91f16700Schasinglulu if (map->ev_num == SDEI_EVENT_0) 479*91f16700Schasinglulu dmbld(); 480*91f16700Schasinglulu 481*91f16700Schasinglulu if (is_event_shared(map)) 482*91f16700Schasinglulu sdei_map_lock(map); 483*91f16700Schasinglulu 484*91f16700Schasinglulu /* Assert shared event routed to this PE had been configured so */ 485*91f16700Schasinglulu if (is_event_shared(map) && (se->reg_flags == SDEI_REGF_RM_PE)) { 486*91f16700Schasinglulu assert(se->affinity == (mpidr & MPIDR_AFFINITY_MASK)); 487*91f16700Schasinglulu } 488*91f16700Schasinglulu 489*91f16700Schasinglulu if (!can_sdei_state_trans(se, DO_DISPATCH)) { 490*91f16700Schasinglulu SDEI_LOG("SDEI event 0x%x can't be dispatched; state=0x%x\n", 491*91f16700Schasinglulu map->ev_num, se->state); 492*91f16700Schasinglulu 493*91f16700Schasinglulu /* 494*91f16700Schasinglulu * If the event is registered, leave the interrupt pending so 495*91f16700Schasinglulu * that it's delivered when the event is enabled. 496*91f16700Schasinglulu */ 497*91f16700Schasinglulu if (GET_EV_STATE(se, REGISTERED)) 498*91f16700Schasinglulu plat_ic_set_interrupt_pending(map->intr); 499*91f16700Schasinglulu 500*91f16700Schasinglulu /* 501*91f16700Schasinglulu * The interrupt was disabled or unregistered after the handler 502*91f16700Schasinglulu * started to execute, which means now the interrupt is already 503*91f16700Schasinglulu * disabled and we just need to EOI the interrupt. 504*91f16700Schasinglulu */ 505*91f16700Schasinglulu plat_ic_end_of_interrupt(intr_raw); 506*91f16700Schasinglulu 507*91f16700Schasinglulu if (is_event_shared(map)) 508*91f16700Schasinglulu sdei_map_unlock(map); 509*91f16700Schasinglulu 510*91f16700Schasinglulu return 0; 511*91f16700Schasinglulu } 512*91f16700Schasinglulu 513*91f16700Schasinglulu disp_ctx = get_outstanding_dispatch(); 514*91f16700Schasinglulu if (is_event_critical(map)) { 515*91f16700Schasinglulu /* 516*91f16700Schasinglulu * If this event is Critical, and if there's an outstanding 517*91f16700Schasinglulu * dispatch, assert the latter is a Normal dispatch. Critical 518*91f16700Schasinglulu * events can preempt an outstanding Normal event dispatch. 519*91f16700Schasinglulu */ 520*91f16700Schasinglulu if (disp_ctx != NULL) 521*91f16700Schasinglulu assert(is_event_normal(disp_ctx->map)); 522*91f16700Schasinglulu } else { 523*91f16700Schasinglulu /* 524*91f16700Schasinglulu * If this event is Normal, assert that there are no outstanding 525*91f16700Schasinglulu * dispatches. Normal events can't preempt any outstanding event 526*91f16700Schasinglulu * dispatches. 527*91f16700Schasinglulu */ 528*91f16700Schasinglulu assert(disp_ctx == NULL); 529*91f16700Schasinglulu } 530*91f16700Schasinglulu 531*91f16700Schasinglulu sec_state = get_interrupt_src_ss(flags); 532*91f16700Schasinglulu 533*91f16700Schasinglulu if (is_event_shared(map)) 534*91f16700Schasinglulu sdei_map_unlock(map); 535*91f16700Schasinglulu 536*91f16700Schasinglulu SDEI_LOG("ACK %" PRIx64 ", ev:0x%x ss:%d spsr:%lx ELR:%lx\n", 537*91f16700Schasinglulu mpidr, map->ev_num, sec_state, read_spsr_el3(), read_elr_el3()); 538*91f16700Schasinglulu 539*91f16700Schasinglulu ctx = handle; 540*91f16700Schasinglulu 541*91f16700Schasinglulu /* 542*91f16700Schasinglulu * Check if we interrupted secure state. Perform a context switch so 543*91f16700Schasinglulu * that we can delegate to NS. 544*91f16700Schasinglulu */ 545*91f16700Schasinglulu if (sec_state == SECURE) { 546*91f16700Schasinglulu save_secure_context(); 547*91f16700Schasinglulu ctx = restore_and_resume_ns_context(); 548*91f16700Schasinglulu } 549*91f16700Schasinglulu 550*91f16700Schasinglulu /* Synchronously dispatch event */ 551*91f16700Schasinglulu setup_ns_dispatch(map, se, ctx, &dispatch_jmp); 552*91f16700Schasinglulu begin_sdei_synchronous_dispatch(&dispatch_jmp); 553*91f16700Schasinglulu 554*91f16700Schasinglulu /* 555*91f16700Schasinglulu * We reach here when client completes the event. 556*91f16700Schasinglulu * 557*91f16700Schasinglulu * If the cause of dispatch originally interrupted the Secure world, 558*91f16700Schasinglulu * resume Secure. 559*91f16700Schasinglulu * 560*91f16700Schasinglulu * No need to save the Non-secure context ahead of a world switch: the 561*91f16700Schasinglulu * Non-secure context was fully saved before dispatch, and has been 562*91f16700Schasinglulu * returned to its pre-dispatch state. 563*91f16700Schasinglulu */ 564*91f16700Schasinglulu if (sec_state == SECURE) 565*91f16700Schasinglulu restore_and_resume_secure_context(); 566*91f16700Schasinglulu 567*91f16700Schasinglulu /* 568*91f16700Schasinglulu * The event was dispatched after receiving SDEI interrupt. With 569*91f16700Schasinglulu * the event handling completed, EOI the corresponding 570*91f16700Schasinglulu * interrupt. 571*91f16700Schasinglulu */ 572*91f16700Schasinglulu if ((map->ev_num != SDEI_EVENT_0) && !is_map_bound(map)) { 573*91f16700Schasinglulu ERROR("Invalid SDEI mapping: ev=0x%x\n", map->ev_num); 574*91f16700Schasinglulu panic(); 575*91f16700Schasinglulu } 576*91f16700Schasinglulu plat_ic_end_of_interrupt(intr_raw); 577*91f16700Schasinglulu 578*91f16700Schasinglulu return 0; 579*91f16700Schasinglulu } 580*91f16700Schasinglulu 581*91f16700Schasinglulu /* 582*91f16700Schasinglulu * Explicitly dispatch the given SDEI event. 583*91f16700Schasinglulu * 584*91f16700Schasinglulu * When calling this API, the caller must be prepared for the SDEI dispatcher to 585*91f16700Schasinglulu * restore and make Non-secure context as active. This call returns only after 586*91f16700Schasinglulu * the client has completed the dispatch. Then, the Non-secure context will be 587*91f16700Schasinglulu * active, and the following ERET will return to Non-secure. 588*91f16700Schasinglulu * 589*91f16700Schasinglulu * Should the caller require re-entry to Secure, it must restore the Secure 590*91f16700Schasinglulu * context and program registers for ERET. 591*91f16700Schasinglulu */ 592*91f16700Schasinglulu int sdei_dispatch_event(int ev_num) 593*91f16700Schasinglulu { 594*91f16700Schasinglulu sdei_entry_t *se; 595*91f16700Schasinglulu sdei_ev_map_t *map; 596*91f16700Schasinglulu cpu_context_t *ns_ctx; 597*91f16700Schasinglulu sdei_dispatch_context_t *disp_ctx; 598*91f16700Schasinglulu sdei_cpu_state_t *state; 599*91f16700Schasinglulu jmp_buf dispatch_jmp; 600*91f16700Schasinglulu 601*91f16700Schasinglulu /* Can't dispatch if events are masked on this PE */ 602*91f16700Schasinglulu state = sdei_get_this_pe_state(); 603*91f16700Schasinglulu if (state->pe_masked) 604*91f16700Schasinglulu return -1; 605*91f16700Schasinglulu 606*91f16700Schasinglulu /* Event 0 can't be dispatched */ 607*91f16700Schasinglulu if (ev_num == SDEI_EVENT_0) 608*91f16700Schasinglulu return -1; 609*91f16700Schasinglulu 610*91f16700Schasinglulu /* Locate mapping corresponding to this event */ 611*91f16700Schasinglulu map = find_event_map(ev_num); 612*91f16700Schasinglulu if (map == NULL) 613*91f16700Schasinglulu return -1; 614*91f16700Schasinglulu 615*91f16700Schasinglulu /* Only explicit events can be dispatched */ 616*91f16700Schasinglulu if (!is_map_explicit(map)) 617*91f16700Schasinglulu return -1; 618*91f16700Schasinglulu 619*91f16700Schasinglulu /* Examine state of dispatch stack */ 620*91f16700Schasinglulu disp_ctx = get_outstanding_dispatch(); 621*91f16700Schasinglulu if (disp_ctx != NULL) { 622*91f16700Schasinglulu /* 623*91f16700Schasinglulu * There's an outstanding dispatch. If the outstanding dispatch 624*91f16700Schasinglulu * is critical, no more dispatches are possible. 625*91f16700Schasinglulu */ 626*91f16700Schasinglulu if (is_event_critical(disp_ctx->map)) 627*91f16700Schasinglulu return -1; 628*91f16700Schasinglulu 629*91f16700Schasinglulu /* 630*91f16700Schasinglulu * If the outstanding dispatch is Normal, only critical events 631*91f16700Schasinglulu * can be dispatched. 632*91f16700Schasinglulu */ 633*91f16700Schasinglulu if (is_event_normal(map)) 634*91f16700Schasinglulu return -1; 635*91f16700Schasinglulu } 636*91f16700Schasinglulu 637*91f16700Schasinglulu se = get_event_entry(map); 638*91f16700Schasinglulu if (!can_sdei_state_trans(se, DO_DISPATCH)) 639*91f16700Schasinglulu return -1; 640*91f16700Schasinglulu 641*91f16700Schasinglulu /* 642*91f16700Schasinglulu * Prepare for NS dispatch by restoring the Non-secure context and 643*91f16700Schasinglulu * marking that as active. 644*91f16700Schasinglulu */ 645*91f16700Schasinglulu ns_ctx = restore_and_resume_ns_context(); 646*91f16700Schasinglulu 647*91f16700Schasinglulu /* Activate the priority corresponding to the event being dispatched */ 648*91f16700Schasinglulu ehf_activate_priority(sdei_event_priority(map)); 649*91f16700Schasinglulu 650*91f16700Schasinglulu /* Dispatch event synchronously */ 651*91f16700Schasinglulu setup_ns_dispatch(map, se, ns_ctx, &dispatch_jmp); 652*91f16700Schasinglulu begin_sdei_synchronous_dispatch(&dispatch_jmp); 653*91f16700Schasinglulu 654*91f16700Schasinglulu /* 655*91f16700Schasinglulu * We reach here when client completes the event. 656*91f16700Schasinglulu * 657*91f16700Schasinglulu * Deactivate the priority level that was activated at the time of 658*91f16700Schasinglulu * explicit dispatch. 659*91f16700Schasinglulu */ 660*91f16700Schasinglulu ehf_deactivate_priority(sdei_event_priority(map)); 661*91f16700Schasinglulu 662*91f16700Schasinglulu return 0; 663*91f16700Schasinglulu } 664*91f16700Schasinglulu 665*91f16700Schasinglulu static void end_sdei_synchronous_dispatch(jmp_buf *buffer) 666*91f16700Schasinglulu { 667*91f16700Schasinglulu longjmp(*buffer, 1); 668*91f16700Schasinglulu } 669*91f16700Schasinglulu 670*91f16700Schasinglulu int sdei_event_complete(bool resume, uint64_t pc) 671*91f16700Schasinglulu { 672*91f16700Schasinglulu sdei_dispatch_context_t *disp_ctx; 673*91f16700Schasinglulu sdei_entry_t *se; 674*91f16700Schasinglulu sdei_ev_map_t *map; 675*91f16700Schasinglulu cpu_context_t *ctx; 676*91f16700Schasinglulu sdei_action_t act; 677*91f16700Schasinglulu unsigned int client_el = sdei_client_el(); 678*91f16700Schasinglulu 679*91f16700Schasinglulu /* Return error if called without an active event */ 680*91f16700Schasinglulu disp_ctx = get_outstanding_dispatch(); 681*91f16700Schasinglulu if (disp_ctx == NULL) 682*91f16700Schasinglulu return SDEI_EDENY; 683*91f16700Schasinglulu 684*91f16700Schasinglulu /* Validate resumption point */ 685*91f16700Schasinglulu if (resume && (plat_sdei_validate_entry_point(pc, client_el) != 0)) 686*91f16700Schasinglulu return SDEI_EDENY; 687*91f16700Schasinglulu 688*91f16700Schasinglulu map = disp_ctx->map; 689*91f16700Schasinglulu assert(map != NULL); 690*91f16700Schasinglulu se = get_event_entry(map); 691*91f16700Schasinglulu 692*91f16700Schasinglulu if (is_event_shared(map)) 693*91f16700Schasinglulu sdei_map_lock(map); 694*91f16700Schasinglulu 695*91f16700Schasinglulu act = resume ? DO_COMPLETE_RESUME : DO_COMPLETE; 696*91f16700Schasinglulu if (!can_sdei_state_trans(se, act)) { 697*91f16700Schasinglulu if (is_event_shared(map)) 698*91f16700Schasinglulu sdei_map_unlock(map); 699*91f16700Schasinglulu return SDEI_EDENY; 700*91f16700Schasinglulu } 701*91f16700Schasinglulu 702*91f16700Schasinglulu if (is_event_shared(map)) 703*91f16700Schasinglulu sdei_map_unlock(map); 704*91f16700Schasinglulu 705*91f16700Schasinglulu /* Having done sanity checks, pop dispatch */ 706*91f16700Schasinglulu (void) pop_dispatch(); 707*91f16700Schasinglulu 708*91f16700Schasinglulu SDEI_LOG("EOI:%lx, %d spsr:%lx elr:%lx\n", read_mpidr_el1(), 709*91f16700Schasinglulu map->ev_num, read_spsr_el3(), read_elr_el3()); 710*91f16700Schasinglulu 711*91f16700Schasinglulu /* 712*91f16700Schasinglulu * Restore Non-secure to how it was originally interrupted. Once done, 713*91f16700Schasinglulu * it's up-to-date with the saved copy. 714*91f16700Schasinglulu */ 715*91f16700Schasinglulu ctx = cm_get_context(NON_SECURE); 716*91f16700Schasinglulu restore_event_ctx(disp_ctx, ctx); 717*91f16700Schasinglulu 718*91f16700Schasinglulu if (resume) { 719*91f16700Schasinglulu /* 720*91f16700Schasinglulu * Complete-and-resume call. Prepare the Non-secure context 721*91f16700Schasinglulu * (currently active) for complete and resume. 722*91f16700Schasinglulu */ 723*91f16700Schasinglulu cm_set_elr_spsr_el3(NON_SECURE, pc, SPSR_64(client_el, 724*91f16700Schasinglulu MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); 725*91f16700Schasinglulu 726*91f16700Schasinglulu /* 727*91f16700Schasinglulu * Make it look as if a synchronous exception were taken at the 728*91f16700Schasinglulu * supplied Non-secure resumption point. Populate SPSR and 729*91f16700Schasinglulu * ELR_ELx so that an ERET from there works as expected. 730*91f16700Schasinglulu * 731*91f16700Schasinglulu * The assumption is that the client, if necessary, would have 732*91f16700Schasinglulu * saved any live content in these registers before making this 733*91f16700Schasinglulu * call. 734*91f16700Schasinglulu */ 735*91f16700Schasinglulu if (client_el == MODE_EL2) { 736*91f16700Schasinglulu write_elr_el2(disp_ctx->elr_el3); 737*91f16700Schasinglulu write_spsr_el2(disp_ctx->spsr_el3); 738*91f16700Schasinglulu } else { 739*91f16700Schasinglulu /* EL1 */ 740*91f16700Schasinglulu write_elr_el1(disp_ctx->elr_el3); 741*91f16700Schasinglulu write_spsr_el1(disp_ctx->spsr_el3); 742*91f16700Schasinglulu } 743*91f16700Schasinglulu } 744*91f16700Schasinglulu 745*91f16700Schasinglulu /* End the outstanding dispatch */ 746*91f16700Schasinglulu end_sdei_synchronous_dispatch(disp_ctx->dispatch_jmp); 747*91f16700Schasinglulu 748*91f16700Schasinglulu return 0; 749*91f16700Schasinglulu } 750*91f16700Schasinglulu 751*91f16700Schasinglulu int64_t sdei_event_context(void *handle, unsigned int param) 752*91f16700Schasinglulu { 753*91f16700Schasinglulu sdei_dispatch_context_t *disp_ctx; 754*91f16700Schasinglulu 755*91f16700Schasinglulu if (param >= SDEI_SAVED_GPREGS) 756*91f16700Schasinglulu return SDEI_EINVAL; 757*91f16700Schasinglulu 758*91f16700Schasinglulu /* Get outstanding dispatch on this CPU */ 759*91f16700Schasinglulu disp_ctx = get_outstanding_dispatch(); 760*91f16700Schasinglulu if (disp_ctx == NULL) 761*91f16700Schasinglulu return SDEI_EDENY; 762*91f16700Schasinglulu 763*91f16700Schasinglulu assert(disp_ctx->map != NULL); 764*91f16700Schasinglulu 765*91f16700Schasinglulu if (!can_sdei_state_trans(get_event_entry(disp_ctx->map), DO_CONTEXT)) 766*91f16700Schasinglulu return SDEI_EDENY; 767*91f16700Schasinglulu 768*91f16700Schasinglulu /* 769*91f16700Schasinglulu * No locking is required for the Running status as this is the only CPU 770*91f16700Schasinglulu * which can complete the event 771*91f16700Schasinglulu */ 772*91f16700Schasinglulu 773*91f16700Schasinglulu return (int64_t) disp_ctx->x[param]; 774*91f16700Schasinglulu } 775