xref: /aosp_15_r20/external/arm-trusted-firmware/bl31/ehf.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park /*
8*54fd6939SJiyong Park  * Exception handlers at EL3, their priority levels, and management.
9*54fd6939SJiyong Park  */
10*54fd6939SJiyong Park 
11*54fd6939SJiyong Park #include <assert.h>
12*54fd6939SJiyong Park #include <stdbool.h>
13*54fd6939SJiyong Park 
14*54fd6939SJiyong Park #include <bl31/ehf.h>
15*54fd6939SJiyong Park #include <bl31/interrupt_mgmt.h>
16*54fd6939SJiyong Park #include <context.h>
17*54fd6939SJiyong Park #include <common/debug.h>
18*54fd6939SJiyong Park #include <drivers/arm/gic_common.h>
19*54fd6939SJiyong Park #include <lib/el3_runtime/context_mgmt.h>
20*54fd6939SJiyong Park #include <lib/el3_runtime/cpu_data.h>
21*54fd6939SJiyong Park #include <lib/el3_runtime/pubsub_events.h>
22*54fd6939SJiyong Park #include <plat/common/platform.h>
23*54fd6939SJiyong Park 
24*54fd6939SJiyong Park /* Output EHF logs as verbose */
25*54fd6939SJiyong Park #define EHF_LOG(...)	VERBOSE("EHF: " __VA_ARGS__)
26*54fd6939SJiyong Park 
27*54fd6939SJiyong Park #define EHF_INVALID_IDX	(-1)
28*54fd6939SJiyong Park 
29*54fd6939SJiyong Park /* For a valid handler, return the actual function pointer; otherwise, 0. */
30*54fd6939SJiyong Park #define RAW_HANDLER(h) \
31*54fd6939SJiyong Park 	((ehf_handler_t) ((((h) & EHF_PRI_VALID_) != 0U) ? \
32*54fd6939SJiyong Park 		((h) & ~EHF_PRI_VALID_) : 0U))
33*54fd6939SJiyong Park 
34*54fd6939SJiyong Park #define PRI_BIT(idx)	(((ehf_pri_bits_t) 1u) << (idx))
35*54fd6939SJiyong Park 
36*54fd6939SJiyong Park /*
37*54fd6939SJiyong Park  * Convert index into secure priority using the platform-defined priority bits
38*54fd6939SJiyong Park  * field.
39*54fd6939SJiyong Park  */
40*54fd6939SJiyong Park #define IDX_TO_PRI(idx) \
41*54fd6939SJiyong Park 	((((unsigned) idx) << (7u - exception_data.pri_bits)) & 0x7fU)
42*54fd6939SJiyong Park 
43*54fd6939SJiyong Park /* Check whether a given index is valid */
44*54fd6939SJiyong Park #define IS_IDX_VALID(idx) \
45*54fd6939SJiyong Park 	((exception_data.ehf_priorities[idx].ehf_handler & EHF_PRI_VALID_) != 0U)
46*54fd6939SJiyong Park 
47*54fd6939SJiyong Park /* Returns whether given priority is in secure priority range */
48*54fd6939SJiyong Park #define IS_PRI_SECURE(pri)	(((pri) & 0x80U) == 0U)
49*54fd6939SJiyong Park 
50*54fd6939SJiyong Park /* To be defined by the platform */
51*54fd6939SJiyong Park extern const ehf_priorities_t exception_data;
52*54fd6939SJiyong Park 
53*54fd6939SJiyong Park /* Translate priority to the index in the priority array */
pri_to_idx(unsigned int priority)54*54fd6939SJiyong Park static unsigned int pri_to_idx(unsigned int priority)
55*54fd6939SJiyong Park {
56*54fd6939SJiyong Park 	unsigned int idx;
57*54fd6939SJiyong Park 
58*54fd6939SJiyong Park 	idx = EHF_PRI_TO_IDX(priority, exception_data.pri_bits);
59*54fd6939SJiyong Park 	assert(idx < exception_data.num_priorities);
60*54fd6939SJiyong Park 	assert(IS_IDX_VALID(idx));
61*54fd6939SJiyong Park 
62*54fd6939SJiyong Park 	return idx;
63*54fd6939SJiyong Park }
64*54fd6939SJiyong Park 
65*54fd6939SJiyong Park /* Return whether there are outstanding priority activation */
has_valid_pri_activations(pe_exc_data_t * pe_data)66*54fd6939SJiyong Park static bool has_valid_pri_activations(pe_exc_data_t *pe_data)
67*54fd6939SJiyong Park {
68*54fd6939SJiyong Park 	return pe_data->active_pri_bits != 0U;
69*54fd6939SJiyong Park }
70*54fd6939SJiyong Park 
this_cpu_data(void)71*54fd6939SJiyong Park static pe_exc_data_t *this_cpu_data(void)
72*54fd6939SJiyong Park {
73*54fd6939SJiyong Park 	return &get_cpu_data(ehf_data);
74*54fd6939SJiyong Park }
75*54fd6939SJiyong Park 
76*54fd6939SJiyong Park /*
77*54fd6939SJiyong Park  * Return the current priority index of this CPU. If no priority is active,
78*54fd6939SJiyong Park  * return EHF_INVALID_IDX.
79*54fd6939SJiyong Park  */
get_pe_highest_active_idx(pe_exc_data_t * pe_data)80*54fd6939SJiyong Park static int get_pe_highest_active_idx(pe_exc_data_t *pe_data)
81*54fd6939SJiyong Park {
82*54fd6939SJiyong Park 	if (!has_valid_pri_activations(pe_data))
83*54fd6939SJiyong Park 		return EHF_INVALID_IDX;
84*54fd6939SJiyong Park 
85*54fd6939SJiyong Park 	/* Current priority is the right-most bit */
86*54fd6939SJiyong Park 	return (int) __builtin_ctz(pe_data->active_pri_bits);
87*54fd6939SJiyong Park }
88*54fd6939SJiyong Park 
89*54fd6939SJiyong Park /*
90*54fd6939SJiyong Park  * Mark priority active by setting the corresponding bit in active_pri_bits and
91*54fd6939SJiyong Park  * programming the priority mask.
92*54fd6939SJiyong Park  *
93*54fd6939SJiyong Park  * This API is to be used as part of delegating to lower ELs other than for
94*54fd6939SJiyong Park  * interrupts; e.g. while handling synchronous exceptions.
95*54fd6939SJiyong Park  *
96*54fd6939SJiyong Park  * This API is expected to be invoked before restoring context (Secure or
97*54fd6939SJiyong Park  * Non-secure) in preparation for the respective dispatch.
98*54fd6939SJiyong Park  */
ehf_activate_priority(unsigned int priority)99*54fd6939SJiyong Park void ehf_activate_priority(unsigned int priority)
100*54fd6939SJiyong Park {
101*54fd6939SJiyong Park 	int cur_pri_idx;
102*54fd6939SJiyong Park 	unsigned int old_mask, run_pri, idx;
103*54fd6939SJiyong Park 	pe_exc_data_t *pe_data = this_cpu_data();
104*54fd6939SJiyong Park 
105*54fd6939SJiyong Park 	/*
106*54fd6939SJiyong Park 	 * Query interrupt controller for the running priority, or idle priority
107*54fd6939SJiyong Park 	 * if no interrupts are being handled. The requested priority must be
108*54fd6939SJiyong Park 	 * less (higher priority) than the active running priority.
109*54fd6939SJiyong Park 	 */
110*54fd6939SJiyong Park 	run_pri = plat_ic_get_running_priority();
111*54fd6939SJiyong Park 	if (priority >= run_pri) {
112*54fd6939SJiyong Park 		ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
113*54fd6939SJiyong Park 				run_pri, priority);
114*54fd6939SJiyong Park 		panic();
115*54fd6939SJiyong Park 	}
116*54fd6939SJiyong Park 
117*54fd6939SJiyong Park 	/*
118*54fd6939SJiyong Park 	 * If there were priority activations already, the requested priority
119*54fd6939SJiyong Park 	 * must be less (higher priority) than the current highest priority
120*54fd6939SJiyong Park 	 * activation so far.
121*54fd6939SJiyong Park 	 */
122*54fd6939SJiyong Park 	cur_pri_idx = get_pe_highest_active_idx(pe_data);
123*54fd6939SJiyong Park 	idx = pri_to_idx(priority);
124*54fd6939SJiyong Park 	if ((cur_pri_idx != EHF_INVALID_IDX) &&
125*54fd6939SJiyong Park 			(idx >= ((unsigned int) cur_pri_idx))) {
126*54fd6939SJiyong Park 		ERROR("Activation priority mismatch: req=0x%x current=0x%x\n",
127*54fd6939SJiyong Park 				priority, IDX_TO_PRI(cur_pri_idx));
128*54fd6939SJiyong Park 		panic();
129*54fd6939SJiyong Park 	}
130*54fd6939SJiyong Park 
131*54fd6939SJiyong Park 	/* Set the bit corresponding to the requested priority */
132*54fd6939SJiyong Park 	pe_data->active_pri_bits |= PRI_BIT(idx);
133*54fd6939SJiyong Park 
134*54fd6939SJiyong Park 	/*
135*54fd6939SJiyong Park 	 * Program priority mask for the activated level. Check that the new
136*54fd6939SJiyong Park 	 * priority mask is setting a higher priority level than the existing
137*54fd6939SJiyong Park 	 * mask.
138*54fd6939SJiyong Park 	 */
139*54fd6939SJiyong Park 	old_mask = plat_ic_set_priority_mask(priority);
140*54fd6939SJiyong Park 	if (priority >= old_mask) {
141*54fd6939SJiyong Park 		ERROR("Requested priority (0x%x) lower than Priority Mask (0x%x)\n",
142*54fd6939SJiyong Park 				priority, old_mask);
143*54fd6939SJiyong Park 		panic();
144*54fd6939SJiyong Park 	}
145*54fd6939SJiyong Park 
146*54fd6939SJiyong Park 	/*
147*54fd6939SJiyong Park 	 * If this is the first activation, save the priority mask. This will be
148*54fd6939SJiyong Park 	 * restored after the last deactivation.
149*54fd6939SJiyong Park 	 */
150*54fd6939SJiyong Park 	if (cur_pri_idx == EHF_INVALID_IDX)
151*54fd6939SJiyong Park 		pe_data->init_pri_mask = (uint8_t) old_mask;
152*54fd6939SJiyong Park 
153*54fd6939SJiyong Park 	EHF_LOG("activate prio=%d\n", get_pe_highest_active_idx(pe_data));
154*54fd6939SJiyong Park }
155*54fd6939SJiyong Park 
156*54fd6939SJiyong Park /*
157*54fd6939SJiyong Park  * Mark priority inactive by clearing the corresponding bit in active_pri_bits,
158*54fd6939SJiyong Park  * and programming the priority mask.
159*54fd6939SJiyong Park  *
160*54fd6939SJiyong Park  * This API is expected to be used as part of delegating to to lower ELs other
161*54fd6939SJiyong Park  * than for interrupts; e.g. while handling synchronous exceptions.
162*54fd6939SJiyong Park  *
163*54fd6939SJiyong Park  * This API is expected to be invoked after saving context (Secure or
164*54fd6939SJiyong Park  * Non-secure), having concluded the respective dispatch.
165*54fd6939SJiyong Park  */
ehf_deactivate_priority(unsigned int priority)166*54fd6939SJiyong Park void ehf_deactivate_priority(unsigned int priority)
167*54fd6939SJiyong Park {
168*54fd6939SJiyong Park 	int cur_pri_idx;
169*54fd6939SJiyong Park 	pe_exc_data_t *pe_data = this_cpu_data();
170*54fd6939SJiyong Park 	unsigned int old_mask, run_pri, idx;
171*54fd6939SJiyong Park 
172*54fd6939SJiyong Park 	/*
173*54fd6939SJiyong Park 	 * Query interrupt controller for the running priority, or idle priority
174*54fd6939SJiyong Park 	 * if no interrupts are being handled. The requested priority must be
175*54fd6939SJiyong Park 	 * less (higher priority) than the active running priority.
176*54fd6939SJiyong Park 	 */
177*54fd6939SJiyong Park 	run_pri = plat_ic_get_running_priority();
178*54fd6939SJiyong Park 	if (priority >= run_pri) {
179*54fd6939SJiyong Park 		ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
180*54fd6939SJiyong Park 				run_pri, priority);
181*54fd6939SJiyong Park 		panic();
182*54fd6939SJiyong Park 	}
183*54fd6939SJiyong Park 
184*54fd6939SJiyong Park 	/*
185*54fd6939SJiyong Park 	 * Deactivation is allowed only when there are priority activations, and
186*54fd6939SJiyong Park 	 * the deactivation priority level must match the current activated
187*54fd6939SJiyong Park 	 * priority.
188*54fd6939SJiyong Park 	 */
189*54fd6939SJiyong Park 	cur_pri_idx = get_pe_highest_active_idx(pe_data);
190*54fd6939SJiyong Park 	idx = pri_to_idx(priority);
191*54fd6939SJiyong Park 	if ((cur_pri_idx == EHF_INVALID_IDX) ||
192*54fd6939SJiyong Park 			(idx != ((unsigned int) cur_pri_idx))) {
193*54fd6939SJiyong Park 		ERROR("Deactivation priority mismatch: req=0x%x current=0x%x\n",
194*54fd6939SJiyong Park 				priority, IDX_TO_PRI(cur_pri_idx));
195*54fd6939SJiyong Park 		panic();
196*54fd6939SJiyong Park 	}
197*54fd6939SJiyong Park 
198*54fd6939SJiyong Park 	/* Clear bit corresponding to highest priority */
199*54fd6939SJiyong Park 	pe_data->active_pri_bits &= (pe_data->active_pri_bits - 1u);
200*54fd6939SJiyong Park 
201*54fd6939SJiyong Park 	/*
202*54fd6939SJiyong Park 	 * Restore priority mask corresponding to the next priority, or the
203*54fd6939SJiyong Park 	 * one stashed earlier if there are no more to deactivate.
204*54fd6939SJiyong Park 	 */
205*54fd6939SJiyong Park 	cur_pri_idx = get_pe_highest_active_idx(pe_data);
206*54fd6939SJiyong Park 	if (cur_pri_idx == EHF_INVALID_IDX)
207*54fd6939SJiyong Park 		old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask);
208*54fd6939SJiyong Park 	else
209*54fd6939SJiyong Park 		old_mask = plat_ic_set_priority_mask(priority);
210*54fd6939SJiyong Park 
211*54fd6939SJiyong Park 	if (old_mask > priority) {
212*54fd6939SJiyong Park 		ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n",
213*54fd6939SJiyong Park 				priority, old_mask);
214*54fd6939SJiyong Park 		panic();
215*54fd6939SJiyong Park 	}
216*54fd6939SJiyong Park 
217*54fd6939SJiyong Park 	EHF_LOG("deactivate prio=%d\n", get_pe_highest_active_idx(pe_data));
218*54fd6939SJiyong Park }
219*54fd6939SJiyong Park 
220*54fd6939SJiyong Park /*
221*54fd6939SJiyong Park  * After leaving Non-secure world, stash current Non-secure Priority Mask, and
222*54fd6939SJiyong Park  * set Priority Mask to the highest Non-secure priority so that Non-secure
223*54fd6939SJiyong Park  * interrupts cannot preempt Secure execution.
224*54fd6939SJiyong Park  *
225*54fd6939SJiyong Park  * If the current running priority is in the secure range, or if there are
226*54fd6939SJiyong Park  * outstanding priority activations, this function does nothing.
227*54fd6939SJiyong Park  *
228*54fd6939SJiyong Park  * This function subscribes to the 'cm_exited_normal_world' event published by
229*54fd6939SJiyong Park  * the Context Management Library.
230*54fd6939SJiyong Park  */
ehf_exited_normal_world(const void * arg)231*54fd6939SJiyong Park static void *ehf_exited_normal_world(const void *arg)
232*54fd6939SJiyong Park {
233*54fd6939SJiyong Park 	unsigned int run_pri;
234*54fd6939SJiyong Park 	pe_exc_data_t *pe_data = this_cpu_data();
235*54fd6939SJiyong Park 
236*54fd6939SJiyong Park 	/* If the running priority is in the secure range, do nothing */
237*54fd6939SJiyong Park 	run_pri = plat_ic_get_running_priority();
238*54fd6939SJiyong Park 	if (IS_PRI_SECURE(run_pri))
239*54fd6939SJiyong Park 		return NULL;
240*54fd6939SJiyong Park 
241*54fd6939SJiyong Park 	/* Do nothing if there are explicit activations */
242*54fd6939SJiyong Park 	if (has_valid_pri_activations(pe_data))
243*54fd6939SJiyong Park 		return NULL;
244*54fd6939SJiyong Park 
245*54fd6939SJiyong Park 	assert(pe_data->ns_pri_mask == 0u);
246*54fd6939SJiyong Park 
247*54fd6939SJiyong Park 	pe_data->ns_pri_mask =
248*54fd6939SJiyong Park 		(uint8_t) plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY);
249*54fd6939SJiyong Park 
250*54fd6939SJiyong Park 	/* The previous Priority Mask is not expected to be in secure range */
251*54fd6939SJiyong Park 	if (IS_PRI_SECURE(pe_data->ns_pri_mask)) {
252*54fd6939SJiyong Park 		ERROR("Priority Mask (0x%x) already in secure range\n",
253*54fd6939SJiyong Park 				pe_data->ns_pri_mask);
254*54fd6939SJiyong Park 		panic();
255*54fd6939SJiyong Park 	}
256*54fd6939SJiyong Park 
257*54fd6939SJiyong Park 	EHF_LOG("Priority Mask: 0x%x => 0x%x\n", pe_data->ns_pri_mask,
258*54fd6939SJiyong Park 			GIC_HIGHEST_NS_PRIORITY);
259*54fd6939SJiyong Park 
260*54fd6939SJiyong Park 	return NULL;
261*54fd6939SJiyong Park }
262*54fd6939SJiyong Park 
263*54fd6939SJiyong Park /*
264*54fd6939SJiyong Park  * Conclude Secure execution and prepare for return to Non-secure world. Restore
265*54fd6939SJiyong Park  * the Non-secure Priority Mask previously stashed upon leaving Non-secure
266*54fd6939SJiyong Park  * world.
267*54fd6939SJiyong Park  *
268*54fd6939SJiyong Park  * If there the current running priority is in the secure range, or if there are
269*54fd6939SJiyong Park  * outstanding priority activations, this function does nothing.
270*54fd6939SJiyong Park  *
271*54fd6939SJiyong Park  * This function subscribes to the 'cm_entering_normal_world' event published by
272*54fd6939SJiyong Park  * the Context Management Library.
273*54fd6939SJiyong Park  */
ehf_entering_normal_world(const void * arg)274*54fd6939SJiyong Park static void *ehf_entering_normal_world(const void *arg)
275*54fd6939SJiyong Park {
276*54fd6939SJiyong Park 	unsigned int old_pmr, run_pri;
277*54fd6939SJiyong Park 	pe_exc_data_t *pe_data = this_cpu_data();
278*54fd6939SJiyong Park 
279*54fd6939SJiyong Park 	/* If the running priority is in the secure range, do nothing */
280*54fd6939SJiyong Park 	run_pri = plat_ic_get_running_priority();
281*54fd6939SJiyong Park 	if (IS_PRI_SECURE(run_pri))
282*54fd6939SJiyong Park 		return NULL;
283*54fd6939SJiyong Park 
284*54fd6939SJiyong Park 	/*
285*54fd6939SJiyong Park 	 * If there are explicit activations, do nothing. The Priority Mask will
286*54fd6939SJiyong Park 	 * be restored upon the last deactivation.
287*54fd6939SJiyong Park 	 */
288*54fd6939SJiyong Park 	if (has_valid_pri_activations(pe_data))
289*54fd6939SJiyong Park 		return NULL;
290*54fd6939SJiyong Park 
291*54fd6939SJiyong Park 	/* Do nothing if we don't have a valid Priority Mask to restore */
292*54fd6939SJiyong Park 	if (pe_data->ns_pri_mask == 0U)
293*54fd6939SJiyong Park 		return NULL;
294*54fd6939SJiyong Park 
295*54fd6939SJiyong Park 	old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
296*54fd6939SJiyong Park 
297*54fd6939SJiyong Park 	/*
298*54fd6939SJiyong Park 	 * When exiting secure world, the current Priority Mask must be
299*54fd6939SJiyong Park 	 * GIC_HIGHEST_NS_PRIORITY (as set during entry), or the Non-secure
300*54fd6939SJiyong Park 	 * priority mask set upon calling ehf_allow_ns_preemption()
301*54fd6939SJiyong Park 	 */
302*54fd6939SJiyong Park 	if ((old_pmr != GIC_HIGHEST_NS_PRIORITY) &&
303*54fd6939SJiyong Park 			(old_pmr != pe_data->ns_pri_mask)) {
304*54fd6939SJiyong Park 		ERROR("Invalid Priority Mask (0x%x) restored\n", old_pmr);
305*54fd6939SJiyong Park 		panic();
306*54fd6939SJiyong Park 	}
307*54fd6939SJiyong Park 
308*54fd6939SJiyong Park 	EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
309*54fd6939SJiyong Park 
310*54fd6939SJiyong Park 	pe_data->ns_pri_mask = 0;
311*54fd6939SJiyong Park 
312*54fd6939SJiyong Park 	return NULL;
313*54fd6939SJiyong Park }
314*54fd6939SJiyong Park 
315*54fd6939SJiyong Park /*
316*54fd6939SJiyong Park  * Program Priority Mask to the original Non-secure priority such that
317*54fd6939SJiyong Park  * Non-secure interrupts may preempt Secure execution (for example, during
318*54fd6939SJiyong Park  * Yielding SMC calls). The 'preempt_ret_code' parameter indicates the Yielding
319*54fd6939SJiyong Park  * SMC's return value in case the call was preempted.
320*54fd6939SJiyong Park  *
321*54fd6939SJiyong Park  * This API is expected to be invoked before delegating a yielding SMC to Secure
322*54fd6939SJiyong Park  * EL1. I.e. within the window of secure execution after Non-secure context is
323*54fd6939SJiyong Park  * saved (after entry into EL3) and Secure context is restored (before entering
324*54fd6939SJiyong Park  * Secure EL1).
325*54fd6939SJiyong Park  */
ehf_allow_ns_preemption(uint64_t preempt_ret_code)326*54fd6939SJiyong Park void ehf_allow_ns_preemption(uint64_t preempt_ret_code)
327*54fd6939SJiyong Park {
328*54fd6939SJiyong Park 	cpu_context_t *ns_ctx;
329*54fd6939SJiyong Park 	unsigned int old_pmr __unused;
330*54fd6939SJiyong Park 	pe_exc_data_t *pe_data = this_cpu_data();
331*54fd6939SJiyong Park 
332*54fd6939SJiyong Park 	/*
333*54fd6939SJiyong Park 	 * We should have been notified earlier of entering secure world, and
334*54fd6939SJiyong Park 	 * therefore have stashed the Non-secure priority mask.
335*54fd6939SJiyong Park 	 */
336*54fd6939SJiyong Park 	assert(pe_data->ns_pri_mask != 0U);
337*54fd6939SJiyong Park 
338*54fd6939SJiyong Park 	/* Make sure no priority levels are active when requesting this */
339*54fd6939SJiyong Park 	if (has_valid_pri_activations(pe_data)) {
340*54fd6939SJiyong Park 		ERROR("PE %lx has priority activations: 0x%x\n",
341*54fd6939SJiyong Park 				read_mpidr_el1(), pe_data->active_pri_bits);
342*54fd6939SJiyong Park 		panic();
343*54fd6939SJiyong Park 	}
344*54fd6939SJiyong Park 
345*54fd6939SJiyong Park 	/*
346*54fd6939SJiyong Park 	 * Program preempted return code to x0 right away so that, if the
347*54fd6939SJiyong Park 	 * Yielding SMC was indeed preempted before a dispatcher gets a chance
348*54fd6939SJiyong Park 	 * to populate it, the caller would find the correct return value.
349*54fd6939SJiyong Park 	 */
350*54fd6939SJiyong Park 	ns_ctx = cm_get_context(NON_SECURE);
351*54fd6939SJiyong Park 	assert(ns_ctx != NULL);
352*54fd6939SJiyong Park 	write_ctx_reg(get_gpregs_ctx(ns_ctx), CTX_GPREG_X0, preempt_ret_code);
353*54fd6939SJiyong Park 
354*54fd6939SJiyong Park 	old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
355*54fd6939SJiyong Park 
356*54fd6939SJiyong Park 	EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
357*54fd6939SJiyong Park 
358*54fd6939SJiyong Park 	pe_data->ns_pri_mask = 0;
359*54fd6939SJiyong Park }
360*54fd6939SJiyong Park 
361*54fd6939SJiyong Park /*
362*54fd6939SJiyong Park  * Return whether Secure execution has explicitly allowed Non-secure interrupts
363*54fd6939SJiyong Park  * to preempt itself (for example, during Yielding SMC calls).
364*54fd6939SJiyong Park  */
ehf_is_ns_preemption_allowed(void)365*54fd6939SJiyong Park unsigned int ehf_is_ns_preemption_allowed(void)
366*54fd6939SJiyong Park {
367*54fd6939SJiyong Park 	unsigned int run_pri;
368*54fd6939SJiyong Park 	pe_exc_data_t *pe_data = this_cpu_data();
369*54fd6939SJiyong Park 
370*54fd6939SJiyong Park 	/* If running priority is in secure range, return false */
371*54fd6939SJiyong Park 	run_pri = plat_ic_get_running_priority();
372*54fd6939SJiyong Park 	if (IS_PRI_SECURE(run_pri))
373*54fd6939SJiyong Park 		return 0;
374*54fd6939SJiyong Park 
375*54fd6939SJiyong Park 	/*
376*54fd6939SJiyong Park 	 * If Non-secure preemption was permitted by calling
377*54fd6939SJiyong Park 	 * ehf_allow_ns_preemption() earlier:
378*54fd6939SJiyong Park 	 *
379*54fd6939SJiyong Park 	 * - There wouldn't have been priority activations;
380*54fd6939SJiyong Park 	 * - We would have cleared the stashed the Non-secure Priority Mask.
381*54fd6939SJiyong Park 	 */
382*54fd6939SJiyong Park 	if (has_valid_pri_activations(pe_data))
383*54fd6939SJiyong Park 		return 0;
384*54fd6939SJiyong Park 	if (pe_data->ns_pri_mask != 0U)
385*54fd6939SJiyong Park 		return 0;
386*54fd6939SJiyong Park 
387*54fd6939SJiyong Park 	return 1;
388*54fd6939SJiyong Park }
389*54fd6939SJiyong Park 
390*54fd6939SJiyong Park /*
391*54fd6939SJiyong Park  * Top-level EL3 interrupt handler.
392*54fd6939SJiyong Park  */
ehf_el3_interrupt_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)393*54fd6939SJiyong Park static uint64_t ehf_el3_interrupt_handler(uint32_t id, uint32_t flags,
394*54fd6939SJiyong Park 		void *handle, void *cookie)
395*54fd6939SJiyong Park {
396*54fd6939SJiyong Park 	int ret = 0;
397*54fd6939SJiyong Park 	uint32_t intr_raw;
398*54fd6939SJiyong Park 	unsigned int intr, pri, idx;
399*54fd6939SJiyong Park 	ehf_handler_t handler;
400*54fd6939SJiyong Park 
401*54fd6939SJiyong Park 	/*
402*54fd6939SJiyong Park 	 * Top-level interrupt type handler from Interrupt Management Framework
403*54fd6939SJiyong Park 	 * doesn't acknowledge the interrupt; so the interrupt ID must be
404*54fd6939SJiyong Park 	 * invalid.
405*54fd6939SJiyong Park 	 */
406*54fd6939SJiyong Park 	assert(id == INTR_ID_UNAVAILABLE);
407*54fd6939SJiyong Park 
408*54fd6939SJiyong Park 	/*
409*54fd6939SJiyong Park 	 * Acknowledge interrupt. Proceed with handling only for valid interrupt
410*54fd6939SJiyong Park 	 * IDs. This situation may arise because of Interrupt Management
411*54fd6939SJiyong Park 	 * Framework identifying an EL3 interrupt, but before it's been
412*54fd6939SJiyong Park 	 * acknowledged here, the interrupt was either deasserted, or there was
413*54fd6939SJiyong Park 	 * a higher-priority interrupt of another type.
414*54fd6939SJiyong Park 	 */
415*54fd6939SJiyong Park 	intr_raw = plat_ic_acknowledge_interrupt();
416*54fd6939SJiyong Park 	intr = plat_ic_get_interrupt_id(intr_raw);
417*54fd6939SJiyong Park 	if (intr == INTR_ID_UNAVAILABLE)
418*54fd6939SJiyong Park 		return 0;
419*54fd6939SJiyong Park 
420*54fd6939SJiyong Park 	/* Having acknowledged the interrupt, get the running priority */
421*54fd6939SJiyong Park 	pri = plat_ic_get_running_priority();
422*54fd6939SJiyong Park 
423*54fd6939SJiyong Park 	/* Check EL3 interrupt priority is in secure range */
424*54fd6939SJiyong Park 	assert(IS_PRI_SECURE(pri));
425*54fd6939SJiyong Park 
426*54fd6939SJiyong Park 	/*
427*54fd6939SJiyong Park 	 * Translate the priority to a descriptor index. We do this by masking
428*54fd6939SJiyong Park 	 * and shifting the running priority value (platform-supplied).
429*54fd6939SJiyong Park 	 */
430*54fd6939SJiyong Park 	idx = pri_to_idx(pri);
431*54fd6939SJiyong Park 
432*54fd6939SJiyong Park 	/* Validate priority */
433*54fd6939SJiyong Park 	assert(pri == IDX_TO_PRI(idx));
434*54fd6939SJiyong Park 
435*54fd6939SJiyong Park 	handler = (ehf_handler_t) RAW_HANDLER(
436*54fd6939SJiyong Park 			exception_data.ehf_priorities[idx].ehf_handler);
437*54fd6939SJiyong Park 	if (handler == NULL) {
438*54fd6939SJiyong Park 		ERROR("No EL3 exception handler for priority 0x%x\n",
439*54fd6939SJiyong Park 				IDX_TO_PRI(idx));
440*54fd6939SJiyong Park 		panic();
441*54fd6939SJiyong Park 	}
442*54fd6939SJiyong Park 
443*54fd6939SJiyong Park 	/*
444*54fd6939SJiyong Park 	 * Call registered handler. Pass the raw interrupt value to registered
445*54fd6939SJiyong Park 	 * handlers.
446*54fd6939SJiyong Park 	 */
447*54fd6939SJiyong Park 	ret = handler(intr_raw, flags, handle, cookie);
448*54fd6939SJiyong Park 
449*54fd6939SJiyong Park 	return (uint64_t) ret;
450*54fd6939SJiyong Park }
451*54fd6939SJiyong Park 
452*54fd6939SJiyong Park /*
453*54fd6939SJiyong Park  * Initialize the EL3 exception handling.
454*54fd6939SJiyong Park  */
ehf_init(void)455*54fd6939SJiyong Park void __init ehf_init(void)
456*54fd6939SJiyong Park {
457*54fd6939SJiyong Park 	unsigned int flags = 0;
458*54fd6939SJiyong Park 	int ret __unused;
459*54fd6939SJiyong Park 
460*54fd6939SJiyong Park 	/* Ensure EL3 interrupts are supported */
461*54fd6939SJiyong Park 	assert(plat_ic_has_interrupt_type(INTR_TYPE_EL3) != 0);
462*54fd6939SJiyong Park 
463*54fd6939SJiyong Park 	/*
464*54fd6939SJiyong Park 	 * Make sure that priority water mark has enough bits to represent the
465*54fd6939SJiyong Park 	 * whole priority array.
466*54fd6939SJiyong Park 	 */
467*54fd6939SJiyong Park 	assert(exception_data.num_priorities <= (sizeof(ehf_pri_bits_t) * 8U));
468*54fd6939SJiyong Park 
469*54fd6939SJiyong Park 	assert(exception_data.ehf_priorities != NULL);
470*54fd6939SJiyong Park 
471*54fd6939SJiyong Park 	/*
472*54fd6939SJiyong Park 	 * Bit 7 of GIC priority must be 0 for secure interrupts. This means
473*54fd6939SJiyong Park 	 * platforms must use at least 1 of the remaining 7 bits.
474*54fd6939SJiyong Park 	 */
475*54fd6939SJiyong Park 	assert((exception_data.pri_bits >= 1U) ||
476*54fd6939SJiyong Park 			(exception_data.pri_bits < 8U));
477*54fd6939SJiyong Park 
478*54fd6939SJiyong Park 	/* Route EL3 interrupts when in Secure and Non-secure. */
479*54fd6939SJiyong Park 	set_interrupt_rm_flag(flags, NON_SECURE);
480*54fd6939SJiyong Park 	set_interrupt_rm_flag(flags, SECURE);
481*54fd6939SJiyong Park 
482*54fd6939SJiyong Park 	/* Register handler for EL3 interrupts */
483*54fd6939SJiyong Park 	ret = register_interrupt_type_handler(INTR_TYPE_EL3,
484*54fd6939SJiyong Park 			ehf_el3_interrupt_handler, flags);
485*54fd6939SJiyong Park 	assert(ret == 0);
486*54fd6939SJiyong Park }
487*54fd6939SJiyong Park 
488*54fd6939SJiyong Park /*
489*54fd6939SJiyong Park  * Register a handler at the supplied priority. Registration is allowed only if
490*54fd6939SJiyong Park  * a handler hasn't been registered before, or one wasn't provided at build
491*54fd6939SJiyong Park  * time. The priority for which the handler is being registered must also accord
492*54fd6939SJiyong Park  * with the platform-supplied data.
493*54fd6939SJiyong Park  */
ehf_register_priority_handler(unsigned int pri,ehf_handler_t handler)494*54fd6939SJiyong Park void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler)
495*54fd6939SJiyong Park {
496*54fd6939SJiyong Park 	unsigned int idx;
497*54fd6939SJiyong Park 
498*54fd6939SJiyong Park 	/* Sanity check for handler */
499*54fd6939SJiyong Park 	assert(handler != NULL);
500*54fd6939SJiyong Park 
501*54fd6939SJiyong Park 	/* Handler ought to be 4-byte aligned */
502*54fd6939SJiyong Park 	assert((((uintptr_t) handler) & 3U) == 0U);
503*54fd6939SJiyong Park 
504*54fd6939SJiyong Park 	/* Ensure we register for valid priority */
505*54fd6939SJiyong Park 	idx = pri_to_idx(pri);
506*54fd6939SJiyong Park 	assert(idx < exception_data.num_priorities);
507*54fd6939SJiyong Park 	assert(IDX_TO_PRI(idx) == pri);
508*54fd6939SJiyong Park 
509*54fd6939SJiyong Park 	/* Return failure if a handler was already registered */
510*54fd6939SJiyong Park 	if (exception_data.ehf_priorities[idx].ehf_handler != EHF_NO_HANDLER_) {
511*54fd6939SJiyong Park 		ERROR("Handler already registered for priority 0x%x\n", pri);
512*54fd6939SJiyong Park 		panic();
513*54fd6939SJiyong Park 	}
514*54fd6939SJiyong Park 
515*54fd6939SJiyong Park 	/*
516*54fd6939SJiyong Park 	 * Install handler, and retain the valid bit. We assume that the handler
517*54fd6939SJiyong Park 	 * is 4-byte aligned, which is usually the case.
518*54fd6939SJiyong Park 	 */
519*54fd6939SJiyong Park 	exception_data.ehf_priorities[idx].ehf_handler =
520*54fd6939SJiyong Park 		(((uintptr_t) handler) | EHF_PRI_VALID_);
521*54fd6939SJiyong Park 
522*54fd6939SJiyong Park 	EHF_LOG("register pri=0x%x handler=%p\n", pri, handler);
523*54fd6939SJiyong Park }
524*54fd6939SJiyong Park 
525*54fd6939SJiyong Park SUBSCRIBE_TO_EVENT(cm_entering_normal_world, ehf_entering_normal_world);
526*54fd6939SJiyong Park SUBSCRIBE_TO_EVENT(cm_exited_normal_world, ehf_exited_normal_world);
527