1 /*
2  * Copyright 2018 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include "hf/arch/vm/interrupts.h"
10 
11 #include <stdint.h>
12 
13 #include "hf/dlog.h"
14 
15 #include "msr.h"
16 #include "test/hftest.h"
17 
18 extern uint8_t vector_table_el1;
19 static void (*irq_callback)(void);
20 static bool (*exception_callback)(void);
21 
22 /**
23  * Handles an IRQ at the current exception level.
24  *
25  * Returns false so that the value of elr_el1 is restored from the stack, in
26  * case there are nested exceptions.
27  */
irq_current(void)28 bool irq_current(void)
29 {
30 	if (irq_callback != NULL) {
31 		irq_callback();
32 	} else {
33 		FAIL("Got unexpected interrupt.\n");
34 	}
35 
36 	return false;
37 }
38 
default_sync_current_exception(void)39 noreturn static bool default_sync_current_exception(void)
40 {
41 	uintreg_t esr = read_msr(esr_el1);
42 	uintreg_t elr = read_msr(elr_el1);
43 
44 	switch (esr >> 26) {
45 	case 0x25: /* EC = 100101, Data abort. */
46 		dlog("Data abort: pc=%#x, esr=%#x, ec=%#x", elr, esr,
47 		     esr >> 26);
48 		if (!(esr & (1U << 10))) { /* Check FnV bit. */
49 			dlog(", far=%#x", read_msr(far_el1));
50 		} else {
51 			dlog(", far=invalid");
52 		}
53 
54 		dlog("\n");
55 		break;
56 
57 	default:
58 		dlog("Unknown current sync exception pc=%#x, esr=%#x, "
59 		     "ec=%#x\n",
60 		     elr, esr, esr >> 26);
61 	}
62 
63 	for (;;) {
64 		/* do nothing */
65 	}
66 }
67 
68 /**
69  * Handles a synchronous exception at the current exception level.
70  *
71  * Returns true if the value of elr_el1 should be kept as-is rather than
72  * restored from the stack. This enables exception handlers to indicate whether
73  * they have changed the value of elr_el1 (e.g., to skip the faulting
74  * instruction).
75  */
sync_exception_current(void)76 bool sync_exception_current(void)
77 {
78 	if (exception_callback != NULL) {
79 		return exception_callback();
80 	}
81 	return default_sync_current_exception();
82 }
83 
exception_setup(void (* irq)(void),bool (* exception)(void))84 void exception_setup(void (*irq)(void), bool (*exception)(void))
85 {
86 	irq_callback = irq;
87 	exception_callback = exception;
88 
89 	/* Set exception vector table. */
90 	write_msr(VBAR_EL1, &vector_table_el1);
91 }
92 
interrupt_wait(void)93 void interrupt_wait(void)
94 {
95 	__asm__ volatile("wfi");
96 }
97