xref: /rk3399_ARM-atf/bl31/ehf.c (revision 21b818c05fa4ec8cec468aad690267c5be930ccd)
1*21b818c0SJeenu Viswambharan /*
2*21b818c0SJeenu Viswambharan  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3*21b818c0SJeenu Viswambharan  *
4*21b818c0SJeenu Viswambharan  * SPDX-License-Identifier: BSD-3-Clause
5*21b818c0SJeenu Viswambharan  */
6*21b818c0SJeenu Viswambharan 
7*21b818c0SJeenu Viswambharan /*
8*21b818c0SJeenu Viswambharan  * Exception handlers at EL3, their priority levels, and management.
9*21b818c0SJeenu Viswambharan  */
10*21b818c0SJeenu Viswambharan 
11*21b818c0SJeenu Viswambharan #include <assert.h>
12*21b818c0SJeenu Viswambharan #include <cpu_data.h>
13*21b818c0SJeenu Viswambharan #include <debug.h>
14*21b818c0SJeenu Viswambharan #include <ehf.h>
15*21b818c0SJeenu Viswambharan #include <interrupt_mgmt.h>
16*21b818c0SJeenu Viswambharan #include <platform.h>
17*21b818c0SJeenu Viswambharan 
18*21b818c0SJeenu Viswambharan /* Output EHF logs as verbose */
19*21b818c0SJeenu Viswambharan #define EHF_LOG(...)	VERBOSE("EHF: " __VA_ARGS__)
20*21b818c0SJeenu Viswambharan 
21*21b818c0SJeenu Viswambharan #define EHF_INVALID_IDX	(-1)
22*21b818c0SJeenu Viswambharan 
23*21b818c0SJeenu Viswambharan /* For a valid handler, return the actual function pointer; otherwise, 0. */
24*21b818c0SJeenu Viswambharan #define RAW_HANDLER(h) \
25*21b818c0SJeenu Viswambharan 	((ehf_handler_t) ((h & _EHF_PRI_VALID) ? (h & ~_EHF_PRI_VALID) : 0))
26*21b818c0SJeenu Viswambharan 
27*21b818c0SJeenu Viswambharan #define PRI_BIT(idx)	(((ehf_pri_bits_t) 1) << idx)
28*21b818c0SJeenu Viswambharan 
29*21b818c0SJeenu Viswambharan /*
30*21b818c0SJeenu Viswambharan  * Convert index into secure priority using the platform-defined priority bits
31*21b818c0SJeenu Viswambharan  * field.
32*21b818c0SJeenu Viswambharan  */
33*21b818c0SJeenu Viswambharan #define IDX_TO_PRI(idx) \
34*21b818c0SJeenu Viswambharan 	((idx << (7 - exception_data.pri_bits)) & 0x7f)
35*21b818c0SJeenu Viswambharan 
36*21b818c0SJeenu Viswambharan /* Check whether a given index is valid */
37*21b818c0SJeenu Viswambharan #define IS_IDX_VALID(idx) \
38*21b818c0SJeenu Viswambharan 	((exception_data.ehf_priorities[idx].ehf_handler & _EHF_PRI_VALID) != 0)
39*21b818c0SJeenu Viswambharan 
40*21b818c0SJeenu Viswambharan /* Returns whether given priority is in secure priority range */
41*21b818c0SJeenu Viswambharan #define IS_PRI_SECURE(pri)	((pri & 0x80) == 0)
42*21b818c0SJeenu Viswambharan 
43*21b818c0SJeenu Viswambharan /* To be defined by the platform */
44*21b818c0SJeenu Viswambharan extern const ehf_priorities_t exception_data;
45*21b818c0SJeenu Viswambharan 
46*21b818c0SJeenu Viswambharan /* Translate priority to the index in the priority array */
47*21b818c0SJeenu Viswambharan static int pri_to_idx(unsigned int priority)
48*21b818c0SJeenu Viswambharan {
49*21b818c0SJeenu Viswambharan 	int idx;
50*21b818c0SJeenu Viswambharan 
51*21b818c0SJeenu Viswambharan 	idx = EHF_PRI_TO_IDX(priority, exception_data.pri_bits);
52*21b818c0SJeenu Viswambharan 	assert((idx >= 0) && (idx < exception_data.num_priorities));
53*21b818c0SJeenu Viswambharan 	assert(IS_IDX_VALID(idx));
54*21b818c0SJeenu Viswambharan 
55*21b818c0SJeenu Viswambharan 	return idx;
56*21b818c0SJeenu Viswambharan }
57*21b818c0SJeenu Viswambharan 
58*21b818c0SJeenu Viswambharan /* Return whether there are outstanding priority activation */
59*21b818c0SJeenu Viswambharan static int has_valid_pri_activations(pe_exc_data_t *pe_data)
60*21b818c0SJeenu Viswambharan {
61*21b818c0SJeenu Viswambharan 	return pe_data->active_pri_bits != 0;
62*21b818c0SJeenu Viswambharan }
63*21b818c0SJeenu Viswambharan 
64*21b818c0SJeenu Viswambharan static pe_exc_data_t *this_cpu_data(void)
65*21b818c0SJeenu Viswambharan {
66*21b818c0SJeenu Viswambharan 	return &get_cpu_data(ehf_data);
67*21b818c0SJeenu Viswambharan }
68*21b818c0SJeenu Viswambharan 
69*21b818c0SJeenu Viswambharan /*
70*21b818c0SJeenu Viswambharan  * Return the current priority index of this CPU. If no priority is active,
71*21b818c0SJeenu Viswambharan  * return EHF_INVALID_IDX.
72*21b818c0SJeenu Viswambharan  */
73*21b818c0SJeenu Viswambharan static int get_pe_highest_active_idx(pe_exc_data_t *pe_data)
74*21b818c0SJeenu Viswambharan {
75*21b818c0SJeenu Viswambharan 	if (!has_valid_pri_activations(pe_data))
76*21b818c0SJeenu Viswambharan 		return EHF_INVALID_IDX;
77*21b818c0SJeenu Viswambharan 
78*21b818c0SJeenu Viswambharan 	/* Current priority is the right-most bit */
79*21b818c0SJeenu Viswambharan 	return __builtin_ctz(pe_data->active_pri_bits);
80*21b818c0SJeenu Viswambharan }
81*21b818c0SJeenu Viswambharan 
82*21b818c0SJeenu Viswambharan /*
83*21b818c0SJeenu Viswambharan  * Mark priority active by setting the corresponding bit in active_pri_bits and
84*21b818c0SJeenu Viswambharan  * programming the priority mask.
85*21b818c0SJeenu Viswambharan  *
86*21b818c0SJeenu Viswambharan  * This API is to be used as part of delegating to lower ELs other than for
87*21b818c0SJeenu Viswambharan  * interrupts; e.g. while handling synchronous exceptions.
88*21b818c0SJeenu Viswambharan  *
89*21b818c0SJeenu Viswambharan  * This API is expected to be invoked before restoring context (Secure or
90*21b818c0SJeenu Viswambharan  * Non-secure) in preparation for the respective dispatch.
91*21b818c0SJeenu Viswambharan  */
92*21b818c0SJeenu Viswambharan void ehf_activate_priority(unsigned int priority)
93*21b818c0SJeenu Viswambharan {
94*21b818c0SJeenu Viswambharan 	int idx, cur_pri_idx;
95*21b818c0SJeenu Viswambharan 	unsigned int old_mask, run_pri;
96*21b818c0SJeenu Viswambharan 	pe_exc_data_t *pe_data = this_cpu_data();
97*21b818c0SJeenu Viswambharan 
98*21b818c0SJeenu Viswambharan 	/*
99*21b818c0SJeenu Viswambharan 	 * Query interrupt controller for the running priority, or idle priority
100*21b818c0SJeenu Viswambharan 	 * if no interrupts are being handled. The requested priority must be
101*21b818c0SJeenu Viswambharan 	 * less (higher priority) than the active running priority.
102*21b818c0SJeenu Viswambharan 	 */
103*21b818c0SJeenu Viswambharan 	run_pri = plat_ic_get_running_priority();
104*21b818c0SJeenu Viswambharan 	if (priority >= run_pri) {
105*21b818c0SJeenu Viswambharan 		ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
106*21b818c0SJeenu Viswambharan 				run_pri, priority);
107*21b818c0SJeenu Viswambharan 		panic();
108*21b818c0SJeenu Viswambharan 	}
109*21b818c0SJeenu Viswambharan 
110*21b818c0SJeenu Viswambharan 	/*
111*21b818c0SJeenu Viswambharan 	 * If there were priority activations already, the requested priority
112*21b818c0SJeenu Viswambharan 	 * must be less (higher priority) than the current highest priority
113*21b818c0SJeenu Viswambharan 	 * activation so far.
114*21b818c0SJeenu Viswambharan 	 */
115*21b818c0SJeenu Viswambharan 	cur_pri_idx = get_pe_highest_active_idx(pe_data);
116*21b818c0SJeenu Viswambharan 	idx = pri_to_idx(priority);
117*21b818c0SJeenu Viswambharan 	if ((cur_pri_idx != EHF_INVALID_IDX) && (idx >= cur_pri_idx)) {
118*21b818c0SJeenu Viswambharan 		ERROR("Activation priority mismatch: req=0x%x current=0x%x\n",
119*21b818c0SJeenu Viswambharan 				priority, IDX_TO_PRI(cur_pri_idx));
120*21b818c0SJeenu Viswambharan 		panic();
121*21b818c0SJeenu Viswambharan 	}
122*21b818c0SJeenu Viswambharan 
123*21b818c0SJeenu Viswambharan 	/* Set the bit corresponding to the requested priority */
124*21b818c0SJeenu Viswambharan 	pe_data->active_pri_bits |= PRI_BIT(idx);
125*21b818c0SJeenu Viswambharan 
126*21b818c0SJeenu Viswambharan 	/*
127*21b818c0SJeenu Viswambharan 	 * Program priority mask for the activated level. Check that the new
128*21b818c0SJeenu Viswambharan 	 * priority mask is setting a higher priority level than the existing
129*21b818c0SJeenu Viswambharan 	 * mask.
130*21b818c0SJeenu Viswambharan 	 */
131*21b818c0SJeenu Viswambharan 	old_mask = plat_ic_set_priority_mask(priority);
132*21b818c0SJeenu Viswambharan 	if (priority >= old_mask) {
133*21b818c0SJeenu Viswambharan 		ERROR("Requested priority (0x%x) lower than Priority Mask (0x%x)\n",
134*21b818c0SJeenu Viswambharan 				priority, old_mask);
135*21b818c0SJeenu Viswambharan 		panic();
136*21b818c0SJeenu Viswambharan 	}
137*21b818c0SJeenu Viswambharan 
138*21b818c0SJeenu Viswambharan 	/*
139*21b818c0SJeenu Viswambharan 	 * If this is the first activation, save the priority mask. This will be
140*21b818c0SJeenu Viswambharan 	 * restored after the last deactivation.
141*21b818c0SJeenu Viswambharan 	 */
142*21b818c0SJeenu Viswambharan 	if (cur_pri_idx == EHF_INVALID_IDX)
143*21b818c0SJeenu Viswambharan 		pe_data->init_pri_mask = old_mask;
144*21b818c0SJeenu Viswambharan 
145*21b818c0SJeenu Viswambharan 	EHF_LOG("activate prio=%d\n", get_pe_highest_active_idx(pe_data));
146*21b818c0SJeenu Viswambharan }
147*21b818c0SJeenu Viswambharan 
148*21b818c0SJeenu Viswambharan /*
149*21b818c0SJeenu Viswambharan  * Mark priority inactive by clearing the corresponding bit in active_pri_bits,
150*21b818c0SJeenu Viswambharan  * and programming the priority mask.
151*21b818c0SJeenu Viswambharan  *
152*21b818c0SJeenu Viswambharan  * This API is expected to be used as part of delegating to to lower ELs other
153*21b818c0SJeenu Viswambharan  * than for interrupts; e.g. while handling synchronous exceptions.
154*21b818c0SJeenu Viswambharan  *
155*21b818c0SJeenu Viswambharan  * This API is expected to be invoked after saving context (Secure or
156*21b818c0SJeenu Viswambharan  * Non-secure), having concluded the respective dispatch.
157*21b818c0SJeenu Viswambharan  */
158*21b818c0SJeenu Viswambharan void ehf_deactivate_priority(unsigned int priority)
159*21b818c0SJeenu Viswambharan {
160*21b818c0SJeenu Viswambharan 	int idx, cur_pri_idx;
161*21b818c0SJeenu Viswambharan 	pe_exc_data_t *pe_data = this_cpu_data();
162*21b818c0SJeenu Viswambharan 	unsigned int old_mask, run_pri;
163*21b818c0SJeenu Viswambharan 
164*21b818c0SJeenu Viswambharan 	/*
165*21b818c0SJeenu Viswambharan 	 * Query interrupt controller for the running priority, or idle priority
166*21b818c0SJeenu Viswambharan 	 * if no interrupts are being handled. The requested priority must be
167*21b818c0SJeenu Viswambharan 	 * less (higher priority) than the active running priority.
168*21b818c0SJeenu Viswambharan 	 */
169*21b818c0SJeenu Viswambharan 	run_pri = plat_ic_get_running_priority();
170*21b818c0SJeenu Viswambharan 	if (priority >= run_pri) {
171*21b818c0SJeenu Viswambharan 		ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
172*21b818c0SJeenu Viswambharan 				run_pri, priority);
173*21b818c0SJeenu Viswambharan 		panic();
174*21b818c0SJeenu Viswambharan 	}
175*21b818c0SJeenu Viswambharan 
176*21b818c0SJeenu Viswambharan 	/*
177*21b818c0SJeenu Viswambharan 	 * Deactivation is allowed only when there are priority activations, and
178*21b818c0SJeenu Viswambharan 	 * the deactivation priority level must match the current activated
179*21b818c0SJeenu Viswambharan 	 * priority.
180*21b818c0SJeenu Viswambharan 	 */
181*21b818c0SJeenu Viswambharan 	cur_pri_idx = get_pe_highest_active_idx(pe_data);
182*21b818c0SJeenu Viswambharan 	idx = pri_to_idx(priority);
183*21b818c0SJeenu Viswambharan 	if ((cur_pri_idx == EHF_INVALID_IDX) || (idx != cur_pri_idx)) {
184*21b818c0SJeenu Viswambharan 		ERROR("Deactivation priority mismatch: req=0x%x current=0x%x\n",
185*21b818c0SJeenu Viswambharan 				priority, IDX_TO_PRI(cur_pri_idx));
186*21b818c0SJeenu Viswambharan 		panic();
187*21b818c0SJeenu Viswambharan 	}
188*21b818c0SJeenu Viswambharan 
189*21b818c0SJeenu Viswambharan 	/* Clear bit corresponding to highest priority */
190*21b818c0SJeenu Viswambharan 	pe_data->active_pri_bits &= (pe_data->active_pri_bits - 1);
191*21b818c0SJeenu Viswambharan 
192*21b818c0SJeenu Viswambharan 	/*
193*21b818c0SJeenu Viswambharan 	 * Restore priority mask corresponding to the next priority, or the
194*21b818c0SJeenu Viswambharan 	 * one stashed earlier if there are no more to deactivate.
195*21b818c0SJeenu Viswambharan 	 */
196*21b818c0SJeenu Viswambharan 	idx = get_pe_highest_active_idx(pe_data);
197*21b818c0SJeenu Viswambharan 	if (idx == EHF_INVALID_IDX)
198*21b818c0SJeenu Viswambharan 		old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask);
199*21b818c0SJeenu Viswambharan 	else
200*21b818c0SJeenu Viswambharan 		old_mask = plat_ic_set_priority_mask(priority);
201*21b818c0SJeenu Viswambharan 
202*21b818c0SJeenu Viswambharan 	if (old_mask >= priority) {
203*21b818c0SJeenu Viswambharan 		ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n",
204*21b818c0SJeenu Viswambharan 				priority, old_mask);
205*21b818c0SJeenu Viswambharan 		panic();
206*21b818c0SJeenu Viswambharan 	}
207*21b818c0SJeenu Viswambharan 
208*21b818c0SJeenu Viswambharan 	EHF_LOG("deactivate prio=%d\n", get_pe_highest_active_idx(pe_data));
209*21b818c0SJeenu Viswambharan }
210*21b818c0SJeenu Viswambharan 
211*21b818c0SJeenu Viswambharan /*
212*21b818c0SJeenu Viswambharan  * Top-level EL3 interrupt handler.
213*21b818c0SJeenu Viswambharan  */
214*21b818c0SJeenu Viswambharan static uint64_t ehf_el3_interrupt_handler(uint32_t id, uint32_t flags,
215*21b818c0SJeenu Viswambharan 		void *handle, void *cookie)
216*21b818c0SJeenu Viswambharan {
217*21b818c0SJeenu Viswambharan 	int pri, idx, intr, intr_raw, ret = 0;
218*21b818c0SJeenu Viswambharan 	ehf_handler_t handler;
219*21b818c0SJeenu Viswambharan 
220*21b818c0SJeenu Viswambharan 	/*
221*21b818c0SJeenu Viswambharan 	 * Top-level interrupt type handler from Interrupt Management Framework
222*21b818c0SJeenu Viswambharan 	 * doesn't acknowledge the interrupt; so the interrupt ID must be
223*21b818c0SJeenu Viswambharan 	 * invalid.
224*21b818c0SJeenu Viswambharan 	 */
225*21b818c0SJeenu Viswambharan 	assert(id == INTR_ID_UNAVAILABLE);
226*21b818c0SJeenu Viswambharan 
227*21b818c0SJeenu Viswambharan 	/*
228*21b818c0SJeenu Viswambharan 	 * Acknowledge interrupt. Proceed with handling only for valid interrupt
229*21b818c0SJeenu Viswambharan 	 * IDs. This situation may arise because of Interrupt Management
230*21b818c0SJeenu Viswambharan 	 * Framework identifying an EL3 interrupt, but before it's been
231*21b818c0SJeenu Viswambharan 	 * acknowledged here, the interrupt was either deasserted, or there was
232*21b818c0SJeenu Viswambharan 	 * a higher-priority interrupt of another type.
233*21b818c0SJeenu Viswambharan 	 */
234*21b818c0SJeenu Viswambharan 	intr_raw = plat_ic_acknowledge_interrupt();
235*21b818c0SJeenu Viswambharan 	intr = plat_ic_get_interrupt_id(intr_raw);
236*21b818c0SJeenu Viswambharan 	if (intr == INTR_ID_UNAVAILABLE)
237*21b818c0SJeenu Viswambharan 		return 0;
238*21b818c0SJeenu Viswambharan 
239*21b818c0SJeenu Viswambharan 	/* Having acknowledged the interrupt, get the running priority */
240*21b818c0SJeenu Viswambharan 	pri = plat_ic_get_running_priority();
241*21b818c0SJeenu Viswambharan 
242*21b818c0SJeenu Viswambharan 	/* Check EL3 interrupt priority is in secure range */
243*21b818c0SJeenu Viswambharan 	assert(IS_PRI_SECURE(pri));
244*21b818c0SJeenu Viswambharan 
245*21b818c0SJeenu Viswambharan 	/*
246*21b818c0SJeenu Viswambharan 	 * Translate the priority to a descriptor index. We do this by masking
247*21b818c0SJeenu Viswambharan 	 * and shifting the running priority value (platform-supplied).
248*21b818c0SJeenu Viswambharan 	 */
249*21b818c0SJeenu Viswambharan 	idx = pri_to_idx(pri);
250*21b818c0SJeenu Viswambharan 
251*21b818c0SJeenu Viswambharan 	/* Validate priority */
252*21b818c0SJeenu Viswambharan 	assert(pri == IDX_TO_PRI(idx));
253*21b818c0SJeenu Viswambharan 
254*21b818c0SJeenu Viswambharan 	handler = RAW_HANDLER(exception_data.ehf_priorities[idx].ehf_handler);
255*21b818c0SJeenu Viswambharan 	if (!handler) {
256*21b818c0SJeenu Viswambharan 		ERROR("No EL3 exception handler for priority 0x%x\n",
257*21b818c0SJeenu Viswambharan 				IDX_TO_PRI(idx));
258*21b818c0SJeenu Viswambharan 		panic();
259*21b818c0SJeenu Viswambharan 	}
260*21b818c0SJeenu Viswambharan 
261*21b818c0SJeenu Viswambharan 	/*
262*21b818c0SJeenu Viswambharan 	 * Call registered handler. Pass the raw interrupt value to registered
263*21b818c0SJeenu Viswambharan 	 * handlers.
264*21b818c0SJeenu Viswambharan 	 */
265*21b818c0SJeenu Viswambharan 	ret = handler(intr_raw, flags, handle, cookie);
266*21b818c0SJeenu Viswambharan 
267*21b818c0SJeenu Viswambharan 	return ret;
268*21b818c0SJeenu Viswambharan }
269*21b818c0SJeenu Viswambharan 
270*21b818c0SJeenu Viswambharan /*
271*21b818c0SJeenu Viswambharan  * Initialize the EL3 exception handling.
272*21b818c0SJeenu Viswambharan  */
273*21b818c0SJeenu Viswambharan void ehf_init(void)
274*21b818c0SJeenu Viswambharan {
275*21b818c0SJeenu Viswambharan 	unsigned int flags = 0;
276*21b818c0SJeenu Viswambharan 	int ret __unused;
277*21b818c0SJeenu Viswambharan 
278*21b818c0SJeenu Viswambharan 	/* Ensure EL3 interrupts are supported */
279*21b818c0SJeenu Viswambharan 	assert(plat_ic_has_interrupt_type(INTR_TYPE_EL3));
280*21b818c0SJeenu Viswambharan 
281*21b818c0SJeenu Viswambharan 	/*
282*21b818c0SJeenu Viswambharan 	 * Make sure that priority water mark has enough bits to represent the
283*21b818c0SJeenu Viswambharan 	 * whole priority array.
284*21b818c0SJeenu Viswambharan 	 */
285*21b818c0SJeenu Viswambharan 	assert(exception_data.num_priorities <= (sizeof(ehf_pri_bits_t) * 8));
286*21b818c0SJeenu Viswambharan 
287*21b818c0SJeenu Viswambharan 	assert(exception_data.ehf_priorities);
288*21b818c0SJeenu Viswambharan 
289*21b818c0SJeenu Viswambharan 	/*
290*21b818c0SJeenu Viswambharan 	 * Bit 7 of GIC priority must be 0 for secure interrupts. This means
291*21b818c0SJeenu Viswambharan 	 * platforms must use at least 1 of the remaining 7 bits.
292*21b818c0SJeenu Viswambharan 	 */
293*21b818c0SJeenu Viswambharan 	assert((exception_data.pri_bits >= 1) || (exception_data.pri_bits < 8));
294*21b818c0SJeenu Viswambharan 
295*21b818c0SJeenu Viswambharan 	/* Route EL3 interrupts when in Secure and Non-secure. */
296*21b818c0SJeenu Viswambharan 	set_interrupt_rm_flag(flags, NON_SECURE);
297*21b818c0SJeenu Viswambharan 	set_interrupt_rm_flag(flags, SECURE);
298*21b818c0SJeenu Viswambharan 
299*21b818c0SJeenu Viswambharan 	/* Register handler for EL3 interrupts */
300*21b818c0SJeenu Viswambharan 	ret = register_interrupt_type_handler(INTR_TYPE_EL3,
301*21b818c0SJeenu Viswambharan 			ehf_el3_interrupt_handler, flags);
302*21b818c0SJeenu Viswambharan 	assert(ret == 0);
303*21b818c0SJeenu Viswambharan }
304*21b818c0SJeenu Viswambharan 
305*21b818c0SJeenu Viswambharan /*
306*21b818c0SJeenu Viswambharan  * Register a handler at the supplied priority. Registration is allowed only if
307*21b818c0SJeenu Viswambharan  * a handler hasn't been registered before, or one wasn't provided at build
308*21b818c0SJeenu Viswambharan  * time. The priority for which the handler is being registered must also accord
309*21b818c0SJeenu Viswambharan  * with the platform-supplied data.
310*21b818c0SJeenu Viswambharan  */
311*21b818c0SJeenu Viswambharan void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler)
312*21b818c0SJeenu Viswambharan {
313*21b818c0SJeenu Viswambharan 	int idx;
314*21b818c0SJeenu Viswambharan 
315*21b818c0SJeenu Viswambharan 	/* Sanity check for handler */
316*21b818c0SJeenu Viswambharan 	assert(handler != NULL);
317*21b818c0SJeenu Viswambharan 
318*21b818c0SJeenu Viswambharan 	/* Handler ought to be 4-byte aligned */
319*21b818c0SJeenu Viswambharan 	assert((((uintptr_t) handler) & 3) == 0);
320*21b818c0SJeenu Viswambharan 
321*21b818c0SJeenu Viswambharan 	/* Ensure we register for valid priority */
322*21b818c0SJeenu Viswambharan 	idx = pri_to_idx(pri);
323*21b818c0SJeenu Viswambharan 	assert(idx < exception_data.num_priorities);
324*21b818c0SJeenu Viswambharan 	assert(IDX_TO_PRI(idx) == pri);
325*21b818c0SJeenu Viswambharan 
326*21b818c0SJeenu Viswambharan 	/* Return failure if a handler was already registered */
327*21b818c0SJeenu Viswambharan 	if (exception_data.ehf_priorities[idx].ehf_handler != _EHF_NO_HANDLER) {
328*21b818c0SJeenu Viswambharan 		ERROR("Handler already registered for priority 0x%x\n", pri);
329*21b818c0SJeenu Viswambharan 		panic();
330*21b818c0SJeenu Viswambharan 	}
331*21b818c0SJeenu Viswambharan 
332*21b818c0SJeenu Viswambharan 	/*
333*21b818c0SJeenu Viswambharan 	 * Install handler, and retain the valid bit. We assume that the handler
334*21b818c0SJeenu Viswambharan 	 * is 4-byte aligned, which is usually the case.
335*21b818c0SJeenu Viswambharan 	 */
336*21b818c0SJeenu Viswambharan 	exception_data.ehf_priorities[idx].ehf_handler =
337*21b818c0SJeenu Viswambharan 		(((uintptr_t) handler) | _EHF_PRI_VALID);
338*21b818c0SJeenu Viswambharan 
339*21b818c0SJeenu Viswambharan 	EHF_LOG("register pri=0x%x handler=%p\n", pri, handler);
340*21b818c0SJeenu Viswambharan }
341