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