xref: /arm-trusted-firmware/services/std_svc/sdei/sdei_private.h (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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