The Pedigree Project 0.1
arm64/InterruptManager.cc
1#include "InterruptManager.h"
2#include "pedigree/kernel/Log.h"
3#include "pedigree/kernel/panic.h"
4#include "pedigree/kernel/process/InterruptTimeAccounting.h"
5#include "pedigree/kernel/process/PerProcessorScheduler.h"
6#include "pedigree/kernel/process/Thread.h"
7#include "pedigree/kernel/processor/InterruptHandler.h"
8#include "pedigree/kernel/processor/PageFaultHandler.h"
9#include "pedigree/kernel/processor/Processor.h"
10#include "pedigree/kernel/processor/state.h"
11
12#include "SyscallManager.h"
13
14extern "C" void virtHandleIrq(InterruptState& state);
15
16namespace {
17void finishUserReturn(InterruptState& state) {
18 if (state.kernelMode()) {
19 return;
20 }
21 Thread* thread = Processor::information().getCurrentThread();
22 if (!thread) {
23 return;
24 }
25
26 PerProcessorScheduler& scheduler = Processor::information().getScheduler();
27 bool terminal = false;
29 while (true) {
30 terminal = scheduler.serviceUserReturnWork(state, UserReturnFrame::Origin::Interrupt);
31 if (terminal) {
32 break;
33 }
34 bool waited = false;
35 terminal = thread->completeAffinityAtSafePoint(&waited) == AffinityResult::Terminal;
36 if (terminal || !waited) {
37 break;
38 }
39 }
42 if (terminal) {
45 panic("ARM64: terminal user return unexpectedly resumed");
46 }
47}
48} // namespace
49
50Arm64InterruptManager::Arm64InterruptManager()
51 : m_Handlers{}
52#if DEBUGGER
53 ,
54 m_DebugHandlers{}
55#endif
56{
57}
58
59Arm64InterruptManager& Arm64InterruptManager::instance() {
60 static Arm64InterruptManager manager;
61 return manager;
62}
63
65 return Arm64InterruptManager::instance();
66}
67
69 if (number >= 32) {
70 return false;
71 }
72 InterruptHandler* expected = handler ? nullptr : m_Handlers[number];
73 if (!expected && !handler) {
74 return false;
75 }
76 return __atomic_compare_exchange_n(&m_Handlers[number], &expected, handler, false,
77 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
78}
79
80#if DEBUGGER
82 InterruptHandler* handler) {
83 if (number >= 32) {
84 return false;
85 }
86 InterruptHandler* expected = handler ? nullptr : m_DebugHandlers[number];
87 if (!expected && !handler) {
88 return false;
89 }
90 return __atomic_compare_exchange_n(&m_DebugHandlers[number], &expected, handler, false,
91 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
92}
93#endif
94
95void Arm64InterruptManager::dispatch(size_t number, InterruptState& state) {
96 if (number >= 32) {
97 ERROR("ARM64: exception class " << Hex << number << " vector " << state.vector << " ESR "
98 << state.esr << " FAR " << state.far << " ELR "
99 << state.getInstructionPointer());
100 panic("ARM64: invalid exception number");
101 }
102#if DEBUGGER
103 InterruptHandler* debugger = __atomic_load_n(&m_DebugHandlers[number], __ATOMIC_ACQUIRE);
104 if (debugger) {
105 debugger->interrupt(number, state);
106 }
107#endif
108 InterruptHandler* handler = __atomic_load_n(&m_Handlers[number], __ATOMIC_ACQUIRE);
109 if (handler) {
110 handler->interrupt(number, state);
111 return;
112 }
113 ERROR("ARM64: unhandled exception " << Dec << number << " at " << Hex
114 << state.getInstructionPointer() << " ESR " << state.esr);
115 panic("ARM64: unhandled exception");
116}
117
118extern "C" void arm64HandleException(InterruptState* state) {
119 if (!state->kernelMode()) {
120 Thread* thread = Processor::information().getCurrentThread();
121 if (thread) {
122 // EL0 may write TPIDR_EL0 directly, without a syscall to update Thread.
123 uintptr_t tls;
124 asm volatile("mrs %0, tpidr_el0" : "=r"(tls));
125 thread->setTlsBase(tls);
126 }
127 }
128 const size_t vector = state->vector;
129 const size_t exceptionClass = (state->esr >> 26) & 0x3f;
130 if ((vector & 3) == 0 && exceptionClass == 0x15 && !state->kernelMode()) {
131 Arm64SyscallManager::handle(*static_cast<SyscallState*>(state));
132 return;
133 }
134 {
135 InterruptTimeAccounting accounting(!state->kernelMode());
136 if ((vector & 3) == 1) {
137 virtHandleIrq(*state);
138 } else if (exceptionClass == 0x20 || exceptionClass == 0x21 || exceptionClass == 0x24 ||
139 exceptionClass == 0x25) {
140 Arm64InterruptManager::instance().dispatch(14, *state);
141 } else {
142 Arm64InterruptManager::instance().dispatch(exceptionClass, *state);
143 }
144 }
145 finishUserReturn(*state);
146}
bool registerInterruptHandlerDebugger(size_t number, InterruptHandler *handler) override
bool registerInterruptHandler(size_t number, InterruptHandler *handler) override
Abstract base class for interrupt-handlers.
virtual void interrupt(size_t nInterruptNumber, InterruptState &state)=0
Handles interrupts and interrupt registrations from kernel components.
static EXPORTED_PUBLIC InterruptManager & instance()
static void finishUserReturn(Thread *thread)
MUST_USE_RESULT bool serviceUserReturnWork(InterruptState &state, UserReturnFrame::Origin origin=UserReturnFrame::Origin::Interrupt, bool diagnosticSample=false)
static ProcessorInformation & information()
static void setInterrupts(bool bEnable)
void setTlsBase(uintptr_t base)
Definition Thread.cc:2674
AffinityResult completeAffinityAtSafePoint(bool *waited=nullptr)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:117
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124