The Pedigree Project 0.1
armv7/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/Processor.h"
9#include "pedigree/kernel/processor/state.h"
10
11#include "SyscallManager.h"
12
13extern "C" void virtHandleIrq(InterruptState& state);
14
15namespace {
16void finishUserReturn(InterruptState& state) {
17 if (state.kernelMode()) {
18 return;
19 }
20 Thread* thread = Processor::information().getCurrentThread();
21 if (!thread) {
22 return;
23 }
24 PerProcessorScheduler& scheduler = Processor::information().getScheduler();
25 bool terminal = false;
27 while (true) {
28 terminal = scheduler.serviceUserReturnWork(state, UserReturnFrame::Origin::Interrupt);
29 if (terminal) {
30 break;
31 }
32 bool waited = false;
33 terminal = thread->completeAffinityAtSafePoint(&waited) == AffinityResult::Terminal;
34 if (terminal || !waited) {
35 break;
36 }
37 }
40 if (terminal) {
43 panic("ARMv7: terminal user return unexpectedly resumed");
44 }
45}
46} // namespace
47
48Armv7InterruptManager::Armv7InterruptManager()
49 : m_Handlers{}
50#if DEBUGGER
51 ,
52 m_DebugHandlers{}
53#endif
54{
55}
56
57Armv7InterruptManager& Armv7InterruptManager::instance() {
58 static Armv7InterruptManager manager;
59 return manager;
60}
61
63 return Armv7InterruptManager::instance();
64}
65
67 if (number >= 32) {
68 return false;
69 }
70 InterruptHandler* expected = handler ? nullptr : m_Handlers[number];
71 if (!expected && !handler) {
72 return false;
73 }
74 return __atomic_compare_exchange_n(&m_Handlers[number], &expected, handler, false,
75 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
76}
77
78#if DEBUGGER
80 InterruptHandler* handler) {
81 if (number >= 32) {
82 return false;
83 }
84 InterruptHandler* expected = handler ? nullptr : m_DebugHandlers[number];
85 if (!expected && !handler) {
86 return false;
87 }
88 return __atomic_compare_exchange_n(&m_DebugHandlers[number], &expected, handler, false,
89 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
90}
91#endif
92
93void Armv7InterruptManager::dispatch(size_t number, InterruptState& state) {
94 if (number >= 32) {
95 panic("ARMv7: invalid exception number");
96 }
97#if DEBUGGER
98 InterruptHandler* debugger = __atomic_load_n(&m_DebugHandlers[number], __ATOMIC_ACQUIRE);
99 if (debugger) {
100 debugger->interrupt(number, state);
101 }
102#endif
103 InterruptHandler* handler = __atomic_load_n(&m_Handlers[number], __ATOMIC_ACQUIRE);
104 if (handler) {
105 handler->interrupt(number, state);
106 return;
107 }
108 ERROR("ARMv7: unhandled exception " << Dec << number << " at " << Hex << state.pc);
109 panic("ARMv7: unhandled exception");
110}
111
112extern "C" void armv7HandleException(InterruptState* state) {
113 if (!state->kernelMode()) {
114 Thread* thread = Processor::information().getCurrentThread();
115 if (thread) {
116 uintptr_t tls;
117 asm volatile("mrc p15, 0, %0, c13, c0, 2" : "=r"(tls));
118 thread->setTlsBase(tls);
119 }
120 }
121 if (state->vector == 2) {
122 Armv7SyscallManager::handle(*static_cast<SyscallState*>(state));
123 return;
124 }
125 {
126 InterruptTimeAccounting accounting(!state->kernelMode());
127 if (state->vector == 5) {
128 virtHandleIrq(*state);
129 } else if (state->vector == 3 || state->vector == 4) {
130 Armv7InterruptManager::instance().dispatch(14, *state);
131 } else {
132 Armv7InterruptManager::instance().dispatch(state->vector, *state);
133 }
134 }
135 finishUserReturn(*state);
136}
bool registerInterruptHandler(size_t number, InterruptHandler *handler) override
bool registerInterruptHandlerDebugger(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:2722
AffinityResult completeAffinityAtSafePoint(bool *waited=nullptr)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124