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