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