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