Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 1 | /* |
Paul Beesley | 1fbc97b | 2019-01-11 18:26:51 +0000 | [diff] [blame] | 2 | * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 7 | #ifndef SDEI_PRIVATE_H |
| 8 | #define SDEI_PRIVATE_H |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 9 | |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 10 | #include <errno.h> |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 11 | #include <stdbool.h> |
Antonio Nino Diaz | 4b32e62 | 2018-08-16 16:52:57 +0100 | [diff] [blame] | 12 | #include <stdint.h> |
Antonio Nino Diaz | e0f9063 | 2018-12-14 00:18:21 +0000 | [diff] [blame] | 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> |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 24 | |
| 25 | #ifdef AARCH32 |
| 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. */ |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 41 | #define SDEI_STATE_UNREGISTERED 0U |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 42 | |
| 43 | /* SDE event status values in bit position */ |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 44 | #define SDEI_STATF_REGISTERED 0U |
| 45 | #define SDEI_STATF_ENABLED 1U |
| 46 | #define SDEI_STATF_RUNNING 2U |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 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 | * |
Paul Beesley | 1fbc97b | 2019-01-11 18:26:51 +0000 | [diff] [blame] | 57 | * Note that the SDEI v1.0 specification mistakenly enumerates the |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 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 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 67 | #define SDEI_PRIVATE_MAPPING() (&sdei_global_mappings[SDEI_MAP_IDX_PRIV_]) |
| 68 | #define SDEI_SHARED_MAPPING() (&sdei_global_mappings[SDEI_MAP_IDX_SHRD_]) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 69 | |
| 70 | #define for_each_mapping_type(_i, _mapping) \ |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 71 | for ((_i) = 0, (_mapping) = &sdei_global_mappings[(_i)]; \ |
| 72 | (_i) < SDEI_MAP_IDX_MAX_; \ |
| 73 | (_i)++, (_mapping) = &sdei_global_mappings[(_i)]) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 74 | |
| 75 | #define iterate_mapping(_mapping, _i, _map) \ |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 76 | for ((_map) = (_mapping)->map, (_i) = 0; \ |
| 77 | (_i) < (_mapping)->num_maps; \ |
| 78 | (_i)++, (_map)++) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 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 */ |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 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 |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 91 | #define FEATURE_BIND_SLOTS(_priv, _shrd) \ |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 92 | (((((uint64_t) (_priv)) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \ |
| 93 | ((((uint64_t) (_shrd)) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT)) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 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 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 98 | static inline bool is_event_private(sdei_ev_map_t *map) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 99 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 100 | return ((map->map_flags & BIT_32(SDEI_MAPF_PRIVATE_SHIFT_)) != 0U); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 101 | } |
| 102 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 103 | static inline bool is_event_shared(sdei_ev_map_t *map) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 104 | { |
| 105 | return !is_event_private(map); |
| 106 | } |
| 107 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 108 | static inline bool is_event_critical(sdei_ev_map_t *map) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 109 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 110 | return ((map->map_flags & BIT_32(SDEI_MAPF_CRITICAL_SHIFT_)) != 0U); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 111 | } |
| 112 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 113 | static inline bool is_event_normal(sdei_ev_map_t *map) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 114 | { |
| 115 | return !is_event_critical(map); |
| 116 | } |
| 117 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 118 | static inline bool is_event_signalable(sdei_ev_map_t *map) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 119 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 120 | return ((map->map_flags & BIT_32(SDEI_MAPF_SIGNALABLE_SHIFT_)) != 0U); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 121 | } |
| 122 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 123 | static inline bool is_map_dynamic(sdei_ev_map_t *map) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 124 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 125 | return ((map->map_flags & BIT_32(SDEI_MAPF_DYNAMIC_SHIFT_)) != 0U); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 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 | */ |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 134 | static inline bool is_map_bound(sdei_ev_map_t *map) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 135 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 136 | return ((map->map_flags & BIT_32(SDEI_MAPF_BOUND_SHIFT_)) != 0U); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 137 | } |
| 138 | |
| 139 | static inline void set_map_bound(sdei_ev_map_t *map) |
| 140 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 141 | map->map_flags |= BIT_32(SDEI_MAPF_BOUND_SHIFT_); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 142 | } |
| 143 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 144 | static inline bool is_map_explicit(sdei_ev_map_t *map) |
Jeenu Viswambharan | 3439230 | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 145 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 146 | return ((map->map_flags & BIT_32(SDEI_MAPF_EXPLICIT_SHIFT_)) != 0U); |
Jeenu Viswambharan | 3439230 | 2018-01-17 12:30:11 +0000 | [diff] [blame] | 147 | } |
| 148 | |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 149 | static inline void clr_map_bound(sdei_ev_map_t *map) |
| 150 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 151 | map->map_flags &= ~BIT_32(SDEI_MAPF_BOUND_SHIFT_); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 152 | } |
| 153 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 154 | static inline bool is_secure_sgi(unsigned int intr) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 155 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 156 | return ((plat_ic_is_sgi(intr) != 0) && |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 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 | { |
Jeenu Viswambharan | 061e9f5 | 2018-06-21 08:47:42 +0100 | [diff] [blame] | 166 | cpu_context_t *ns_ctx = cm_get_context(NON_SECURE); |
| 167 | el3_state_t *el3_ctx = get_el3state_ctx(ns_ctx); |
| 168 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 169 | return ((read_ctx_reg(el3_ctx, CTX_SCR_EL3) & SCR_HCE_BIT) != 0U) ? |
| 170 | MODE_EL2 : MODE_EL1; |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 171 | } |
| 172 | |
| 173 | static inline unsigned int sdei_event_priority(sdei_ev_map_t *map) |
| 174 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 175 | return (unsigned int) (is_event_critical(map) ? PLAT_SDEI_CRITICAL_PRI : |
| 176 | PLAT_SDEI_NORMAL_PRI); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 177 | } |
| 178 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 179 | static inline bool get_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 180 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 181 | return ((se->state & BIT_32(bit_no)) != 0U); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | static inline void clr_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) |
| 185 | { |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 186 | se->state &= ~BIT_32(bit_no); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 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 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 233 | sdei_ev_map_t *find_event_map_by_intr(unsigned int intr_num, bool shared); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 234 | sdei_ev_map_t *find_event_map(int ev_num); |
| 235 | sdei_entry_t *get_event_entry(sdei_ev_map_t *map); |
| 236 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 237 | int64_t sdei_event_context(void *handle, unsigned int param); |
| 238 | int sdei_event_complete(bool resume, uint64_t pc); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 239 | |
| 240 | void sdei_pe_unmask(void); |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 241 | int64_t sdei_pe_mask(void); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 242 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 243 | int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 244 | void *cookie); |
| 245 | bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act); |
Jeenu Viswambharan | 8b7e6bc | 2018-02-16 12:07:48 +0000 | [diff] [blame] | 246 | void begin_sdei_synchronous_dispatch(struct jmpbuf *buffer); |
Jeenu Viswambharan | 04e3a7f | 2017-10-16 08:43:14 +0100 | [diff] [blame] | 247 | |
Jeenu Viswambharan | 32ceef5 | 2018-08-02 10:14:12 +0100 | [diff] [blame] | 248 | #endif /* SDEI_PRIVATE_H */ |