blob: 3d6d674bf66a3f9a867cbb6a05b8117c4d9ab775 [file] [log] [blame]
Jeenu Viswambharan10a67272017-09-22 08:32:10 +01001/*
Jeenu Viswambharan7addf622018-02-05 11:20:37 +00002 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
Jeenu Viswambharan10a67272017-09-22 08:32:10 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*
8 * Exception handlers at EL3, their priority levels, and management.
9 */
10
11#include <assert.h>
Jeenu Viswambharaneeb353c2018-01-22 12:29:12 +000012#include <context.h>
13#include <context_mgmt.h>
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010014#include <cpu_data.h>
15#include <debug.h>
16#include <ehf.h>
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +010017#include <gic_common.h>
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010018#include <interrupt_mgmt.h>
19#include <platform.h>
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +010020#include <pubsub_events.h>
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010021#include <stdbool.h>
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010022
23/* Output EHF logs as verbose */
24#define EHF_LOG(...) VERBOSE("EHF: " __VA_ARGS__)
25
26#define EHF_INVALID_IDX (-1)
27
28/* For a valid handler, return the actual function pointer; otherwise, 0. */
29#define RAW_HANDLER(h) \
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010030 ((ehf_handler_t) ((((h) & EHF_PRI_VALID_) != 0U) ? \
31 ((h) & ~EHF_PRI_VALID_) : 0U))
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010032
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010033#define PRI_BIT(idx) (((ehf_pri_bits_t) 1u) << (idx))
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010034
35/*
36 * Convert index into secure priority using the platform-defined priority bits
37 * field.
38 */
39#define IDX_TO_PRI(idx) \
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010040 ((((unsigned) idx) << (7u - exception_data.pri_bits)) & 0x7fU)
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010041
42/* Check whether a given index is valid */
43#define IS_IDX_VALID(idx) \
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010044 ((exception_data.ehf_priorities[idx].ehf_handler & EHF_PRI_VALID_) != 0U)
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010045
46/* Returns whether given priority is in secure priority range */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010047#define IS_PRI_SECURE(pri) (((pri) & 0x80U) == 0U)
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010048
49/* To be defined by the platform */
50extern const ehf_priorities_t exception_data;
51
52/* Translate priority to the index in the priority array */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010053static unsigned int pri_to_idx(unsigned int priority)
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010054{
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010055 unsigned int idx;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010056
57 idx = EHF_PRI_TO_IDX(priority, exception_data.pri_bits);
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010058 assert(idx < exception_data.num_priorities);
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010059 assert(IS_IDX_VALID(idx));
60
61 return idx;
62}
63
64/* Return whether there are outstanding priority activation */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010065static bool has_valid_pri_activations(pe_exc_data_t *pe_data)
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010066{
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010067 return pe_data->active_pri_bits != 0U;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010068}
69
70static pe_exc_data_t *this_cpu_data(void)
71{
72 return &get_cpu_data(ehf_data);
73}
74
75/*
76 * Return the current priority index of this CPU. If no priority is active,
77 * return EHF_INVALID_IDX.
78 */
79static int get_pe_highest_active_idx(pe_exc_data_t *pe_data)
80{
81 if (!has_valid_pri_activations(pe_data))
82 return EHF_INVALID_IDX;
83
84 /* Current priority is the right-most bit */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +010085 return (int) __builtin_ctz(pe_data->active_pri_bits);
Jeenu Viswambharan10a67272017-09-22 08:32:10 +010086}
87
88/*
89 * Mark priority active by setting the corresponding bit in active_pri_bits and
90 * programming the priority mask.
91 *
92 * This API is to be used as part of delegating to lower ELs other than for
93 * interrupts; e.g. while handling synchronous exceptions.
94 *
95 * This API is expected to be invoked before restoring context (Secure or
96 * Non-secure) in preparation for the respective dispatch.
97 */
98void ehf_activate_priority(unsigned int priority)
99{
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100100 int cur_pri_idx;
101 unsigned int old_mask, run_pri, idx;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100102 pe_exc_data_t *pe_data = this_cpu_data();
103
104 /*
105 * Query interrupt controller for the running priority, or idle priority
106 * if no interrupts are being handled. The requested priority must be
107 * less (higher priority) than the active running priority.
108 */
109 run_pri = plat_ic_get_running_priority();
110 if (priority >= run_pri) {
111 ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
112 run_pri, priority);
113 panic();
114 }
115
116 /*
117 * If there were priority activations already, the requested priority
118 * must be less (higher priority) than the current highest priority
119 * activation so far.
120 */
121 cur_pri_idx = get_pe_highest_active_idx(pe_data);
122 idx = pri_to_idx(priority);
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100123 if ((cur_pri_idx != EHF_INVALID_IDX) &&
124 (idx >= ((unsigned int) cur_pri_idx))) {
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100125 ERROR("Activation priority mismatch: req=0x%x current=0x%x\n",
126 priority, IDX_TO_PRI(cur_pri_idx));
127 panic();
128 }
129
130 /* Set the bit corresponding to the requested priority */
131 pe_data->active_pri_bits |= PRI_BIT(idx);
132
133 /*
134 * Program priority mask for the activated level. Check that the new
135 * priority mask is setting a higher priority level than the existing
136 * mask.
137 */
138 old_mask = plat_ic_set_priority_mask(priority);
139 if (priority >= old_mask) {
140 ERROR("Requested priority (0x%x) lower than Priority Mask (0x%x)\n",
141 priority, old_mask);
142 panic();
143 }
144
145 /*
146 * If this is the first activation, save the priority mask. This will be
147 * restored after the last deactivation.
148 */
149 if (cur_pri_idx == EHF_INVALID_IDX)
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100150 pe_data->init_pri_mask = (uint8_t) old_mask;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100151
152 EHF_LOG("activate prio=%d\n", get_pe_highest_active_idx(pe_data));
153}
154
155/*
156 * Mark priority inactive by clearing the corresponding bit in active_pri_bits,
157 * and programming the priority mask.
158 *
159 * This API is expected to be used as part of delegating to to lower ELs other
160 * than for interrupts; e.g. while handling synchronous exceptions.
161 *
162 * This API is expected to be invoked after saving context (Secure or
163 * Non-secure), having concluded the respective dispatch.
164 */
165void ehf_deactivate_priority(unsigned int priority)
166{
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100167 int cur_pri_idx;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100168 pe_exc_data_t *pe_data = this_cpu_data();
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100169 unsigned int old_mask, run_pri, idx;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100170
171 /*
172 * Query interrupt controller for the running priority, or idle priority
173 * if no interrupts are being handled. The requested priority must be
174 * less (higher priority) than the active running priority.
175 */
176 run_pri = plat_ic_get_running_priority();
177 if (priority >= run_pri) {
178 ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
179 run_pri, priority);
180 panic();
181 }
182
183 /*
184 * Deactivation is allowed only when there are priority activations, and
185 * the deactivation priority level must match the current activated
186 * priority.
187 */
188 cur_pri_idx = get_pe_highest_active_idx(pe_data);
189 idx = pri_to_idx(priority);
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100190 if ((cur_pri_idx == EHF_INVALID_IDX) ||
191 (idx != ((unsigned int) cur_pri_idx))) {
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100192 ERROR("Deactivation priority mismatch: req=0x%x current=0x%x\n",
193 priority, IDX_TO_PRI(cur_pri_idx));
194 panic();
195 }
196
197 /* Clear bit corresponding to highest priority */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100198 pe_data->active_pri_bits &= (pe_data->active_pri_bits - 1u);
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100199
200 /*
201 * Restore priority mask corresponding to the next priority, or the
202 * one stashed earlier if there are no more to deactivate.
203 */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100204 cur_pri_idx = get_pe_highest_active_idx(pe_data);
205 if (cur_pri_idx == EHF_INVALID_IDX)
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100206 old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask);
207 else
208 old_mask = plat_ic_set_priority_mask(priority);
209
Jeenu Viswambharan7addf622018-02-05 11:20:37 +0000210 if (old_mask > priority) {
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100211 ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n",
212 priority, old_mask);
213 panic();
214 }
215
216 EHF_LOG("deactivate prio=%d\n", get_pe_highest_active_idx(pe_data));
217}
218
219/*
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100220 * After leaving Non-secure world, stash current Non-secure Priority Mask, and
221 * set Priority Mask to the highest Non-secure priority so that Non-secure
222 * interrupts cannot preempt Secure execution.
223 *
224 * If the current running priority is in the secure range, or if there are
225 * outstanding priority activations, this function does nothing.
226 *
227 * This function subscribes to the 'cm_exited_normal_world' event published by
228 * the Context Management Library.
229 */
230static void *ehf_exited_normal_world(const void *arg)
231{
232 unsigned int run_pri;
233 pe_exc_data_t *pe_data = this_cpu_data();
234
235 /* If the running priority is in the secure range, do nothing */
236 run_pri = plat_ic_get_running_priority();
237 if (IS_PRI_SECURE(run_pri))
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100238 return NULL;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100239
240 /* Do nothing if there are explicit activations */
241 if (has_valid_pri_activations(pe_data))
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100242 return NULL;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100243
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100244 assert(pe_data->ns_pri_mask == 0u);
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100245
246 pe_data->ns_pri_mask =
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100247 (uint8_t) plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY);
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100248
249 /* The previous Priority Mask is not expected to be in secure range */
250 if (IS_PRI_SECURE(pe_data->ns_pri_mask)) {
251 ERROR("Priority Mask (0x%x) already in secure range\n",
252 pe_data->ns_pri_mask);
253 panic();
254 }
255
256 EHF_LOG("Priority Mask: 0x%x => 0x%x\n", pe_data->ns_pri_mask,
257 GIC_HIGHEST_NS_PRIORITY);
258
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100259 return NULL;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100260}
261
262/*
263 * Conclude Secure execution and prepare for return to Non-secure world. Restore
264 * the Non-secure Priority Mask previously stashed upon leaving Non-secure
265 * world.
266 *
267 * If there the current running priority is in the secure range, or if there are
268 * outstanding priority activations, this function does nothing.
269 *
270 * This function subscribes to the 'cm_entering_normal_world' event published by
271 * the Context Management Library.
272 */
273static void *ehf_entering_normal_world(const void *arg)
274{
275 unsigned int old_pmr, run_pri;
276 pe_exc_data_t *pe_data = this_cpu_data();
277
278 /* If the running priority is in the secure range, do nothing */
279 run_pri = plat_ic_get_running_priority();
280 if (IS_PRI_SECURE(run_pri))
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100281 return NULL;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100282
283 /*
284 * If there are explicit activations, do nothing. The Priority Mask will
285 * be restored upon the last deactivation.
286 */
287 if (has_valid_pri_activations(pe_data))
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100288 return NULL;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100289
290 /* Do nothing if we don't have a valid Priority Mask to restore */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100291 if (pe_data->ns_pri_mask == 0U)
292 return NULL;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100293
294 old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
295
296 /*
297 * When exiting secure world, the current Priority Mask must be
298 * GIC_HIGHEST_NS_PRIORITY (as set during entry), or the Non-secure
299 * priority mask set upon calling ehf_allow_ns_preemption()
300 */
301 if ((old_pmr != GIC_HIGHEST_NS_PRIORITY) &&
302 (old_pmr != pe_data->ns_pri_mask)) {
303 ERROR("Invalid Priority Mask (0x%x) restored\n", old_pmr);
304 panic();
305 }
306
307 EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
308
309 pe_data->ns_pri_mask = 0;
310
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100311 return NULL;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100312}
313
314/*
315 * Program Priority Mask to the original Non-secure priority such that
316 * Non-secure interrupts may preempt Secure execution, viz. during Yielding SMC
Jeenu Viswambharaneeb353c2018-01-22 12:29:12 +0000317 * calls. The 'preempt_ret_code' parameter indicates the Yielding SMC's return
318 * value in case the call was preempted.
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100319 *
320 * This API is expected to be invoked before delegating a yielding SMC to Secure
321 * EL1. I.e. within the window of secure execution after Non-secure context is
322 * saved (after entry into EL3) and Secure context is restored (before entering
323 * Secure EL1).
324 */
Jeenu Viswambharaneeb353c2018-01-22 12:29:12 +0000325void ehf_allow_ns_preemption(uint64_t preempt_ret_code)
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100326{
Jeenu Viswambharaneeb353c2018-01-22 12:29:12 +0000327 cpu_context_t *ns_ctx;
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100328 unsigned int old_pmr __unused;
329 pe_exc_data_t *pe_data = this_cpu_data();
330
331 /*
332 * We should have been notified earlier of entering secure world, and
333 * therefore have stashed the Non-secure priority mask.
334 */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100335 assert(pe_data->ns_pri_mask != 0U);
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100336
337 /* Make sure no priority levels are active when requesting this */
338 if (has_valid_pri_activations(pe_data)) {
339 ERROR("PE %lx has priority activations: 0x%x\n",
340 read_mpidr_el1(), pe_data->active_pri_bits);
341 panic();
342 }
343
Jeenu Viswambharaneeb353c2018-01-22 12:29:12 +0000344 /*
345 * Program preempted return code to x0 right away so that, if the
346 * Yielding SMC was indeed preempted before a dispatcher gets a chance
347 * to populate it, the caller would find the correct return value.
348 */
349 ns_ctx = cm_get_context(NON_SECURE);
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100350 assert(ns_ctx != NULL);
Jeenu Viswambharaneeb353c2018-01-22 12:29:12 +0000351 write_ctx_reg(get_gpregs_ctx(ns_ctx), CTX_GPREG_X0, preempt_ret_code);
352
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100353 old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
354
355 EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
356
357 pe_data->ns_pri_mask = 0;
358}
359
360/*
361 * Return whether Secure execution has explicitly allowed Non-secure interrupts
362 * to preempt itself, viz. during Yielding SMC calls.
363 */
364unsigned int ehf_is_ns_preemption_allowed(void)
365{
366 unsigned int run_pri;
367 pe_exc_data_t *pe_data = this_cpu_data();
368
369 /* If running priority is in secure range, return false */
370 run_pri = plat_ic_get_running_priority();
371 if (IS_PRI_SECURE(run_pri))
372 return 0;
373
374 /*
375 * If Non-secure preemption was permitted by calling
376 * ehf_allow_ns_preemption() earlier:
377 *
378 * - There wouldn't have been priority activations;
379 * - We would have cleared the stashed the Non-secure Priority Mask.
380 */
381 if (has_valid_pri_activations(pe_data))
382 return 0;
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100383 if (pe_data->ns_pri_mask != 0U)
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100384 return 0;
385
386 return 1;
387}
388
389/*
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100390 * Top-level EL3 interrupt handler.
391 */
392static uint64_t ehf_el3_interrupt_handler(uint32_t id, uint32_t flags,
393 void *handle, void *cookie)
394{
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100395 int ret = 0;
396 uint32_t intr_raw;
397 unsigned int intr, pri, idx;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100398 ehf_handler_t handler;
399
400 /*
401 * Top-level interrupt type handler from Interrupt Management Framework
402 * doesn't acknowledge the interrupt; so the interrupt ID must be
403 * invalid.
404 */
405 assert(id == INTR_ID_UNAVAILABLE);
406
407 /*
408 * Acknowledge interrupt. Proceed with handling only for valid interrupt
409 * IDs. This situation may arise because of Interrupt Management
410 * Framework identifying an EL3 interrupt, but before it's been
411 * acknowledged here, the interrupt was either deasserted, or there was
412 * a higher-priority interrupt of another type.
413 */
414 intr_raw = plat_ic_acknowledge_interrupt();
415 intr = plat_ic_get_interrupt_id(intr_raw);
416 if (intr == INTR_ID_UNAVAILABLE)
417 return 0;
418
419 /* Having acknowledged the interrupt, get the running priority */
420 pri = plat_ic_get_running_priority();
421
422 /* Check EL3 interrupt priority is in secure range */
423 assert(IS_PRI_SECURE(pri));
424
425 /*
426 * Translate the priority to a descriptor index. We do this by masking
427 * and shifting the running priority value (platform-supplied).
428 */
429 idx = pri_to_idx(pri);
430
431 /* Validate priority */
432 assert(pri == IDX_TO_PRI(idx));
433
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100434 handler = (ehf_handler_t) RAW_HANDLER(
435 exception_data.ehf_priorities[idx].ehf_handler);
436 if (handler == NULL) {
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100437 ERROR("No EL3 exception handler for priority 0x%x\n",
438 IDX_TO_PRI(idx));
439 panic();
440 }
441
442 /*
443 * Call registered handler. Pass the raw interrupt value to registered
444 * handlers.
445 */
446 ret = handler(intr_raw, flags, handle, cookie);
447
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100448 return (uint64_t) ret;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100449}
450
451/*
452 * Initialize the EL3 exception handling.
453 */
454void ehf_init(void)
455{
456 unsigned int flags = 0;
457 int ret __unused;
458
459 /* Ensure EL3 interrupts are supported */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100460 assert(plat_ic_has_interrupt_type(INTR_TYPE_EL3) != 0);
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100461
462 /*
463 * Make sure that priority water mark has enough bits to represent the
464 * whole priority array.
465 */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100466 assert(exception_data.num_priorities <= (sizeof(ehf_pri_bits_t) * 8U));
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100467
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100468 assert(exception_data.ehf_priorities != NULL);
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100469
470 /*
471 * Bit 7 of GIC priority must be 0 for secure interrupts. This means
472 * platforms must use at least 1 of the remaining 7 bits.
473 */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100474 assert((exception_data.pri_bits >= 1U) ||
475 (exception_data.pri_bits < 8U));
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100476
477 /* Route EL3 interrupts when in Secure and Non-secure. */
478 set_interrupt_rm_flag(flags, NON_SECURE);
479 set_interrupt_rm_flag(flags, SECURE);
480
481 /* Register handler for EL3 interrupts */
482 ret = register_interrupt_type_handler(INTR_TYPE_EL3,
483 ehf_el3_interrupt_handler, flags);
484 assert(ret == 0);
485}
486
487/*
488 * Register a handler at the supplied priority. Registration is allowed only if
489 * a handler hasn't been registered before, or one wasn't provided at build
490 * time. The priority for which the handler is being registered must also accord
491 * with the platform-supplied data.
492 */
493void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler)
494{
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100495 unsigned int idx;
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100496
497 /* Sanity check for handler */
498 assert(handler != NULL);
499
500 /* Handler ought to be 4-byte aligned */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100501 assert((((uintptr_t) handler) & 3U) == 0U);
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100502
503 /* Ensure we register for valid priority */
504 idx = pri_to_idx(pri);
505 assert(idx < exception_data.num_priorities);
506 assert(IDX_TO_PRI(idx) == pri);
507
508 /* Return failure if a handler was already registered */
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100509 if (exception_data.ehf_priorities[idx].ehf_handler != EHF_NO_HANDLER_) {
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100510 ERROR("Handler already registered for priority 0x%x\n", pri);
511 panic();
512 }
513
514 /*
515 * Install handler, and retain the valid bit. We assume that the handler
516 * is 4-byte aligned, which is usually the case.
517 */
518 exception_data.ehf_priorities[idx].ehf_handler =
Jeenu Viswambharan837cc9c2018-08-02 10:14:12 +0100519 (((uintptr_t) handler) | EHF_PRI_VALID_);
Jeenu Viswambharan10a67272017-09-22 08:32:10 +0100520
521 EHF_LOG("register pri=0x%x handler=%p\n", pri, handler);
522}
Jeenu Viswambharan6c6f24d2017-10-04 12:21:34 +0100523
524SUBSCRIBE_TO_EVENT(cm_entering_normal_world, ehf_entering_normal_world);
525SUBSCRIBE_TO_EVENT(cm_exited_normal_world, ehf_exited_normal_world);