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