1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #ifndef SDEI_PRIVATE_H 8*91f16700Schasinglulu #define SDEI_PRIVATE_H 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <errno.h> 11*91f16700Schasinglulu #include <stdbool.h> 12*91f16700Schasinglulu #include <stdint.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu #include <arch_helpers.h> 15*91f16700Schasinglulu #include <bl31/interrupt_mgmt.h> 16*91f16700Schasinglulu #include <common/debug.h> 17*91f16700Schasinglulu #include <context.h> 18*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h> 19*91f16700Schasinglulu #include <lib/spinlock.h> 20*91f16700Schasinglulu #include <lib/utils_def.h> 21*91f16700Schasinglulu #include <plat/common/platform.h> 22*91f16700Schasinglulu #include <services/sdei.h> 23*91f16700Schasinglulu #include <setjmp.h> 24*91f16700Schasinglulu 25*91f16700Schasinglulu #ifndef __aarch64__ 26*91f16700Schasinglulu # error SDEI is implemented only for AArch64 systems 27*91f16700Schasinglulu #endif 28*91f16700Schasinglulu 29*91f16700Schasinglulu #ifndef PLAT_SDEI_CRITICAL_PRI 30*91f16700Schasinglulu # error Platform must define SDEI critical priority value 31*91f16700Schasinglulu #endif 32*91f16700Schasinglulu 33*91f16700Schasinglulu #ifndef PLAT_SDEI_NORMAL_PRI 34*91f16700Schasinglulu # error Platform must define SDEI normal priority value 35*91f16700Schasinglulu #endif 36*91f16700Schasinglulu 37*91f16700Schasinglulu /* Output SDEI logs as verbose */ 38*91f16700Schasinglulu #define SDEI_LOG(...) VERBOSE("SDEI: " __VA_ARGS__) 39*91f16700Schasinglulu 40*91f16700Schasinglulu /* SDEI handler unregistered state. This is the default state. */ 41*91f16700Schasinglulu #define SDEI_STATE_UNREGISTERED 0U 42*91f16700Schasinglulu 43*91f16700Schasinglulu /* SDE event status values in bit position */ 44*91f16700Schasinglulu #define SDEI_STATF_REGISTERED 0U 45*91f16700Schasinglulu #define SDEI_STATF_ENABLED 1U 46*91f16700Schasinglulu #define SDEI_STATF_RUNNING 2U 47*91f16700Schasinglulu 48*91f16700Schasinglulu /* SDEI SMC error codes */ 49*91f16700Schasinglulu #define SDEI_EINVAL (-2) 50*91f16700Schasinglulu #define SDEI_EDENY (-3) 51*91f16700Schasinglulu #define SDEI_EPEND (-5) 52*91f16700Schasinglulu #define SDEI_ENOMEM (-10) 53*91f16700Schasinglulu 54*91f16700Schasinglulu /* 55*91f16700Schasinglulu * 'info' parameter to SDEI_EVENT_GET_INFO SMC. 56*91f16700Schasinglulu * 57*91f16700Schasinglulu * Note that the SDEI v1.0 specification mistakenly enumerates the 58*91f16700Schasinglulu * SDEI_INFO_EV_SIGNALED as SDEI_INFO_SIGNALED. This will be corrected in a 59*91f16700Schasinglulu * future version. 60*91f16700Schasinglulu */ 61*91f16700Schasinglulu #define SDEI_INFO_EV_TYPE 0 62*91f16700Schasinglulu #define SDEI_INFO_EV_NOT_SIGNALED 1 63*91f16700Schasinglulu #define SDEI_INFO_EV_PRIORITY 2 64*91f16700Schasinglulu #define SDEI_INFO_EV_ROUTING_MODE 3 65*91f16700Schasinglulu #define SDEI_INFO_EV_ROUTING_AFF 4 66*91f16700Schasinglulu 67*91f16700Schasinglulu #define SDEI_PRIVATE_MAPPING() (&sdei_global_mappings[SDEI_MAP_IDX_PRIV_]) 68*91f16700Schasinglulu #define SDEI_SHARED_MAPPING() (&sdei_global_mappings[SDEI_MAP_IDX_SHRD_]) 69*91f16700Schasinglulu 70*91f16700Schasinglulu #define for_each_mapping_type(_i, _mapping) \ 71*91f16700Schasinglulu for ((_i) = 0, (_mapping) = &sdei_global_mappings[(_i)]; \ 72*91f16700Schasinglulu (_i) < SDEI_MAP_IDX_MAX_; \ 73*91f16700Schasinglulu (_i)++, (_mapping) = &sdei_global_mappings[(_i)]) 74*91f16700Schasinglulu 75*91f16700Schasinglulu #define iterate_mapping(_mapping, _i, _map) \ 76*91f16700Schasinglulu for ((_map) = (_mapping)->map, (_i) = 0; \ 77*91f16700Schasinglulu (_i) < (_mapping)->num_maps; \ 78*91f16700Schasinglulu (_i)++, (_map)++) 79*91f16700Schasinglulu 80*91f16700Schasinglulu #define for_each_private_map(_i, _map) \ 81*91f16700Schasinglulu iterate_mapping(SDEI_PRIVATE_MAPPING(), _i, _map) 82*91f16700Schasinglulu 83*91f16700Schasinglulu #define for_each_shared_map(_i, _map) \ 84*91f16700Schasinglulu iterate_mapping(SDEI_SHARED_MAPPING(), _i, _map) 85*91f16700Schasinglulu 86*91f16700Schasinglulu /* SDEI_FEATURES */ 87*91f16700Schasinglulu #define SDEI_FEATURE_BIND_SLOTS 0U 88*91f16700Schasinglulu #define BIND_SLOTS_MASK 0xffffU 89*91f16700Schasinglulu #define FEATURES_SHARED_SLOTS_SHIFT 16U 90*91f16700Schasinglulu #define FEATURES_PRIVATE_SLOTS_SHIFT 0U 91*91f16700Schasinglulu #define FEATURE_BIND_SLOTS(_priv, _shrd) \ 92*91f16700Schasinglulu (((((uint64_t) (_priv)) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \ 93*91f16700Schasinglulu ((((uint64_t) (_shrd)) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT)) 94*91f16700Schasinglulu 95*91f16700Schasinglulu #define GET_EV_STATE(_e, _s) get_ev_state_bit(_e, SDEI_STATF_##_s) 96*91f16700Schasinglulu #define SET_EV_STATE(_e, _s) clr_ev_state_bit(_e->state, SDEI_STATF_##_s) 97*91f16700Schasinglulu 98*91f16700Schasinglulu static inline bool is_event_private(sdei_ev_map_t *map) 99*91f16700Schasinglulu { 100*91f16700Schasinglulu return ((map->map_flags & BIT_32(SDEI_MAPF_PRIVATE_SHIFT_)) != 0U); 101*91f16700Schasinglulu } 102*91f16700Schasinglulu 103*91f16700Schasinglulu static inline bool is_event_shared(sdei_ev_map_t *map) 104*91f16700Schasinglulu { 105*91f16700Schasinglulu return !is_event_private(map); 106*91f16700Schasinglulu } 107*91f16700Schasinglulu 108*91f16700Schasinglulu static inline bool is_event_critical(sdei_ev_map_t *map) 109*91f16700Schasinglulu { 110*91f16700Schasinglulu return ((map->map_flags & BIT_32(SDEI_MAPF_CRITICAL_SHIFT_)) != 0U); 111*91f16700Schasinglulu } 112*91f16700Schasinglulu 113*91f16700Schasinglulu static inline bool is_event_normal(sdei_ev_map_t *map) 114*91f16700Schasinglulu { 115*91f16700Schasinglulu return !is_event_critical(map); 116*91f16700Schasinglulu } 117*91f16700Schasinglulu 118*91f16700Schasinglulu static inline bool is_event_signalable(sdei_ev_map_t *map) 119*91f16700Schasinglulu { 120*91f16700Schasinglulu return ((map->map_flags & BIT_32(SDEI_MAPF_SIGNALABLE_SHIFT_)) != 0U); 121*91f16700Schasinglulu } 122*91f16700Schasinglulu 123*91f16700Schasinglulu static inline bool is_map_dynamic(sdei_ev_map_t *map) 124*91f16700Schasinglulu { 125*91f16700Schasinglulu return ((map->map_flags & BIT_32(SDEI_MAPF_DYNAMIC_SHIFT_)) != 0U); 126*91f16700Schasinglulu } 127*91f16700Schasinglulu 128*91f16700Schasinglulu /* 129*91f16700Schasinglulu * Checks whether an event is associated with an interrupt. Static events always 130*91f16700Schasinglulu * return true, and dynamic events return whether SDEI_INTERRUPT_BIND had been 131*91f16700Schasinglulu * called on them. This can be used on both static or dynamic events to check 132*91f16700Schasinglulu * for an associated interrupt. 133*91f16700Schasinglulu */ 134*91f16700Schasinglulu static inline bool is_map_bound(sdei_ev_map_t *map) 135*91f16700Schasinglulu { 136*91f16700Schasinglulu return ((map->map_flags & BIT_32(SDEI_MAPF_BOUND_SHIFT_)) != 0U); 137*91f16700Schasinglulu } 138*91f16700Schasinglulu 139*91f16700Schasinglulu static inline void set_map_bound(sdei_ev_map_t *map) 140*91f16700Schasinglulu { 141*91f16700Schasinglulu map->map_flags |= BIT_32(SDEI_MAPF_BOUND_SHIFT_); 142*91f16700Schasinglulu } 143*91f16700Schasinglulu 144*91f16700Schasinglulu static inline bool is_map_explicit(sdei_ev_map_t *map) 145*91f16700Schasinglulu { 146*91f16700Schasinglulu return ((map->map_flags & BIT_32(SDEI_MAPF_EXPLICIT_SHIFT_)) != 0U); 147*91f16700Schasinglulu } 148*91f16700Schasinglulu 149*91f16700Schasinglulu static inline void clr_map_bound(sdei_ev_map_t *map) 150*91f16700Schasinglulu { 151*91f16700Schasinglulu map->map_flags &= ~BIT_32(SDEI_MAPF_BOUND_SHIFT_); 152*91f16700Schasinglulu } 153*91f16700Schasinglulu 154*91f16700Schasinglulu static inline bool is_secure_sgi(unsigned int intr) 155*91f16700Schasinglulu { 156*91f16700Schasinglulu return ((plat_ic_is_sgi(intr) != 0) && 157*91f16700Schasinglulu (plat_ic_get_interrupt_type(intr) == INTR_TYPE_EL3)); 158*91f16700Schasinglulu } 159*91f16700Schasinglulu 160*91f16700Schasinglulu /* 161*91f16700Schasinglulu * Determine EL of the client. If EL2 is implemented (hence the enabled HCE 162*91f16700Schasinglulu * bit), deem EL2; otherwise, deem EL1. 163*91f16700Schasinglulu */ 164*91f16700Schasinglulu static inline unsigned int sdei_client_el(void) 165*91f16700Schasinglulu { 166*91f16700Schasinglulu cpu_context_t *ns_ctx = cm_get_context(NON_SECURE); 167*91f16700Schasinglulu el3_state_t *el3_ctx = get_el3state_ctx(ns_ctx); 168*91f16700Schasinglulu 169*91f16700Schasinglulu return ((read_ctx_reg(el3_ctx, CTX_SCR_EL3) & SCR_HCE_BIT) != 0U) ? 170*91f16700Schasinglulu MODE_EL2 : MODE_EL1; 171*91f16700Schasinglulu } 172*91f16700Schasinglulu 173*91f16700Schasinglulu static inline unsigned int sdei_event_priority(sdei_ev_map_t *map) 174*91f16700Schasinglulu { 175*91f16700Schasinglulu return (unsigned int) (is_event_critical(map) ? PLAT_SDEI_CRITICAL_PRI : 176*91f16700Schasinglulu PLAT_SDEI_NORMAL_PRI); 177*91f16700Schasinglulu } 178*91f16700Schasinglulu 179*91f16700Schasinglulu static inline bool get_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) 180*91f16700Schasinglulu { 181*91f16700Schasinglulu return ((se->state & BIT_32(bit_no)) != 0U); 182*91f16700Schasinglulu } 183*91f16700Schasinglulu 184*91f16700Schasinglulu static inline void clr_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) 185*91f16700Schasinglulu { 186*91f16700Schasinglulu se->state &= ~BIT_32(bit_no); 187*91f16700Schasinglulu } 188*91f16700Schasinglulu 189*91f16700Schasinglulu /* SDEI actions for state transition */ 190*91f16700Schasinglulu typedef enum { 191*91f16700Schasinglulu /* 192*91f16700Schasinglulu * Actions resulting from client requests. These directly map to SMC 193*91f16700Schasinglulu * calls. Note that the state table columns are listed in this order 194*91f16700Schasinglulu * too. 195*91f16700Schasinglulu */ 196*91f16700Schasinglulu DO_REGISTER = 0, 197*91f16700Schasinglulu DO_RELEASE = 1, 198*91f16700Schasinglulu DO_ENABLE = 2, 199*91f16700Schasinglulu DO_DISABLE = 3, 200*91f16700Schasinglulu DO_UNREGISTER = 4, 201*91f16700Schasinglulu DO_ROUTING = 5, 202*91f16700Schasinglulu DO_CONTEXT = 6, 203*91f16700Schasinglulu DO_COMPLETE = 7, 204*91f16700Schasinglulu DO_COMPLETE_RESUME = 8, 205*91f16700Schasinglulu 206*91f16700Schasinglulu /* Action for event dispatch */ 207*91f16700Schasinglulu DO_DISPATCH = 9, 208*91f16700Schasinglulu 209*91f16700Schasinglulu DO_MAX, 210*91f16700Schasinglulu } sdei_action_t; 211*91f16700Schasinglulu 212*91f16700Schasinglulu typedef enum { 213*91f16700Schasinglulu SDEI_NORMAL, 214*91f16700Schasinglulu SDEI_CRITICAL 215*91f16700Schasinglulu } sdei_class_t; 216*91f16700Schasinglulu 217*91f16700Schasinglulu static inline void sdei_map_lock(sdei_ev_map_t *map) 218*91f16700Schasinglulu { 219*91f16700Schasinglulu spin_lock(&map->lock); 220*91f16700Schasinglulu } 221*91f16700Schasinglulu 222*91f16700Schasinglulu static inline void sdei_map_unlock(sdei_ev_map_t *map) 223*91f16700Schasinglulu { 224*91f16700Schasinglulu spin_unlock(&map->lock); 225*91f16700Schasinglulu } 226*91f16700Schasinglulu 227*91f16700Schasinglulu extern const sdei_mapping_t sdei_global_mappings[]; 228*91f16700Schasinglulu extern sdei_entry_t sdei_private_event_table[]; 229*91f16700Schasinglulu extern sdei_entry_t sdei_shared_event_table[]; 230*91f16700Schasinglulu 231*91f16700Schasinglulu void init_sdei_state(void); 232*91f16700Schasinglulu 233*91f16700Schasinglulu sdei_ev_map_t *find_event_map_by_intr(unsigned int intr_num, bool shared); 234*91f16700Schasinglulu sdei_ev_map_t *find_event_map(int ev_num); 235*91f16700Schasinglulu sdei_entry_t *get_event_entry(sdei_ev_map_t *map); 236*91f16700Schasinglulu 237*91f16700Schasinglulu int64_t sdei_event_context(void *handle, unsigned int param); 238*91f16700Schasinglulu int sdei_event_complete(bool resume, uint64_t pc); 239*91f16700Schasinglulu 240*91f16700Schasinglulu void sdei_pe_unmask(void); 241*91f16700Schasinglulu int64_t sdei_pe_mask(void); 242*91f16700Schasinglulu 243*91f16700Schasinglulu int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, 244*91f16700Schasinglulu void *cookie); 245*91f16700Schasinglulu bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act); 246*91f16700Schasinglulu void begin_sdei_synchronous_dispatch(jmp_buf *buffer); 247*91f16700Schasinglulu 248*91f16700Schasinglulu #endif /* SDEI_PRIVATE_H */ 249