The Pedigree Project  0.1
ppc32/InterruptManager.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "InterruptManager.h"
21 #include "pedigree/kernel/LockGuard.h"
22 #include "pedigree/kernel/Log.h"
23 #include "pedigree/kernel/debugger/Debugger.h"
24 #include "pedigree/kernel/machine/Machine.h"
25 #include "pedigree/kernel/machine/openfirmware/Device.h"
26 #include "pedigree/kernel/machine/openfirmware/OpenFirmware.h"
27 #include "pedigree/kernel/machine/types.h"
28 #include "pedigree/kernel/panic.h"
29 #include "pedigree/kernel/processor/Processor.h"
30 #include "pedigree/kernel/utilities/utility.h"
31 
32 extern "C" int isr_reset;
33 extern "C" int isr_machine_check;
34 extern "C" int isr_dsi;
35 extern "C" int isr_isi;
36 extern "C" int isr_interrupt;
37 extern "C" int isr_alignment;
38 extern "C" int isr_program;
39 extern "C" int isr_fpu;
40 extern "C" int isr_decrementer;
41 extern "C" int isr_sc;
42 extern "C" int isr_trace;
43 extern "C" int isr_perf_mon;
44 extern "C" int isr_instr_breakpoint;
45 extern "C" int isr_system_management;
46 extern "C" int isr_thermal_management;
47 
48 const char *g_pExceptions[] = {"System reset",
49  "Machine check",
50  "DSI",
51  "ISI",
52  "External interrupt",
53  "Alignment",
54  "Program",
55  "Floating-point unavailable",
56  "Decrementer",
57  "System call",
58  "Trace",
59  "Performance monitor",
60  "Instruction address breakpoint",
61  "System management interrupt",
62  "Thermal management interrupt"};
63 
65 
67 {
69 }
71 {
73 }
74 
76  size_t interruptNumber, InterruptHandler *pHandler)
77 {
78  LockGuard<Spinlock> lockGuard(m_Lock);
79 
80  if (UNLIKELY(
81  interruptNumber >= 256 ||
82  interruptNumber == SYSCALL_INTERRUPT_NUMBER))
83  return false;
84  if (UNLIKELY(pHandler != 0 && m_pHandler[interruptNumber] != 0))
85  return false;
86  if (UNLIKELY(pHandler == 0 && m_pHandler[interruptNumber] == 0))
87  return false;
88 
89  m_pHandler[interruptNumber] = pHandler;
90  return true;
91 }
92 
93 #ifdef DEBUGGER
95  size_t interruptNumber, InterruptHandler *pHandler)
96 {
97  LockGuard<Spinlock> lockGuard(m_Lock);
98 
99  if (UNLIKELY(
100  interruptNumber >= 256 ||
101  interruptNumber == SYSCALL_INTERRUPT_NUMBER))
102  return false;
103  if (UNLIKELY(pHandler != 0 && m_pDbgHandler[interruptNumber] != 0))
104  return false;
105  if (UNLIKELY(pHandler == 0 && m_pDbgHandler[interruptNumber] == 0))
106  return false;
107 
108  m_pDbgHandler[interruptNumber] = pHandler;
109  return true;
110 }
112 {
113  return TRAP_INTERRUPT_NUMBER;
114 }
116 {
117  return TRACE_INTERRUPT_NUMBER;
118 }
119 #endif
120 
122  Service_t Service, SyscallHandler *pHandler)
123 {
124  LockGuard<Spinlock> lockGuard(m_Lock);
125 
126  if (UNLIKELY(Service >= serviceEnd))
127  return false;
128  if (UNLIKELY(pHandler != 0 && m_pSyscallHandler[Service] != 0))
129  return false;
130  if (UNLIKELY(pHandler == 0 && m_pSyscallHandler[Service] == 0))
131  return false;
132 
133  m_pSyscallHandler[Service] = pHandler;
134  return true;
135 }
136 
138  Service_t service, uintptr_t function, uintptr_t p1, uintptr_t p2,
139  uintptr_t p3, uintptr_t p4, uintptr_t p5)
140 {
141  register uint32_t r3 __asm__("r3") =
142  ((service & 0xFFFF) << 16) | (function & 0xFFFF);
143  register uint32_t r4 __asm__("r6") = p1;
144  register uint32_t r5 __asm__("r7") = p2;
145  register uint32_t r6 __asm__("r8") = p3;
146  register uint32_t r7 __asm__("r9") = p4;
147  register uint32_t r8 __asm__("r10") = p5;
148 
149  asm volatile("sc"
150  : "=r"(r3)
151  : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8));
152  return r3;
153 }
154 
156 {
157  // We know that we get called before the virtual address space is
158  // initialised, so we'll have to do the identity mapping ourselves. How
159  // crude!
160  OFDevice chosen(OpenFirmware::instance().findDevice("/chosen"));
161  OFDevice mmu(chosen.getProperty("mmu"));
162 
163  // Identity map the lower area of memory.
164  mmu.executeMethod(
165  "map", 4, reinterpret_cast<OFParam>(-1),
166  reinterpret_cast<OFParam>(0x3000), reinterpret_cast<OFParam>(0x0),
167  reinterpret_cast<OFParam>(0x0));
168  // Copy the interrupt handlers into lower memory.
169  MemoryCopy(reinterpret_cast<void *>(0x0100), &isr_reset, 0x100);
170  MemoryCopy(reinterpret_cast<void *>(0x0200), &isr_machine_check, 0x100);
171  MemoryCopy(reinterpret_cast<void *>(0x0300), &isr_dsi, 0x100);
172  MemoryCopy(reinterpret_cast<void *>(0x0400), &isr_isi, 0x100);
173  MemoryCopy(reinterpret_cast<void *>(0x0500), &isr_interrupt, 0x100);
174  MemoryCopy(reinterpret_cast<void *>(0x0600), &isr_alignment, 0x100);
175  MemoryCopy(reinterpret_cast<void *>(0x0700), &isr_program, 0x100);
176  MemoryCopy(reinterpret_cast<void *>(0x0800), &isr_fpu, 0x100);
177  MemoryCopy(reinterpret_cast<void *>(0x0900), &isr_decrementer, 0x100);
178  MemoryCopy(reinterpret_cast<void *>(0x0C00), &isr_sc, 0x100);
179  MemoryCopy(reinterpret_cast<void *>(0x0D00), &isr_trace, 0x100);
180  MemoryCopy(reinterpret_cast<void *>(0x0F00), &isr_perf_mon, 0x100);
181  MemoryCopy(reinterpret_cast<void *>(0x1300), &isr_instr_breakpoint, 0x100);
182  MemoryCopy(reinterpret_cast<void *>(0x1400), &isr_system_management, 0x100);
183  MemoryCopy(
184  reinterpret_cast<void *>(0x1700), &isr_thermal_management, 0x100);
185 
186  for (uintptr_t i = 0x0; i < 0x1800; i += 4)
187  Processor::flushDCache(i);
188 
189  asm volatile("sync");
190 
191  for (uintptr_t i = 0; i < 0x1800; i += 4)
192  Processor::invalidateICache(i);
193 
194  asm volatile("sync");
195  asm volatile("isync");
196 }
197 
198 void PPC32InterruptManager::interrupt(InterruptState &interruptState)
199 {
200  // TODO: Needs locking
201  size_t intNumber = interruptState.getInterruptNumber();
202 
203 #ifdef DEBUGGER
204  // Call the kernel debugger's handler, if any
205  if (m_Instance.m_pDbgHandler[intNumber] != 0)
206  {
207  m_Instance.m_pDbgHandler[intNumber]->interrupt(
208  intNumber, interruptState);
209  }
210 #endif
211 
212  // Call the syscall handler, if it is the syscall interrupt
213  if (intNumber == SYSCALL_INTERRUPT_NUMBER)
214  {
215  size_t serviceNumber = interruptState.getSyscallService();
216  if (LIKELY(
217  serviceNumber < serviceEnd &&
218  m_Instance.m_pSyscallHandler[serviceNumber] != 0))
219  interruptState.m_R3 =
220  m_Instance.m_pSyscallHandler[serviceNumber]->syscall(
221  interruptState);
222  }
223  else if (m_Instance.m_pHandler[intNumber] != 0)
224  m_Instance.m_pHandler[intNumber]->interrupt(intNumber, interruptState);
225  else if (intNumber != 6 && intNumber != 10)
226  {
227  // TODO:: Check for debugger initialisation.
228  static LargeStaticString e;
229  e.clear();
230  e.append("Exception #");
231  e.append(interruptState.m_IntNumber, 10);
232  e.append(": \"");
233  e.append(g_pExceptions[intNumber]);
234  e.append("\"");
235 #ifdef DEBUGGER
236  Debugger::instance().start(interruptState, e);
237 #else
238  FATAL(
239  "SRR0: " << Hex << interruptState.m_Srr0
240  << ", SRR1: " << interruptState.m_Srr1);
241  FATAL(
242  "DAR: " << interruptState.m_Dar
243  << ", DSISR: " << interruptState.m_Dsisr);
244  panic(e);
245 #endif
246  }
247 
248  // Some interrupts (like Program) require the PC to be advanced before
249  // returning.
250  if (intNumber == TRAP_INTERRUPT_NUMBER)
251  {
252  interruptState.m_Srr0 += 4;
253  }
254 }
255 
257 {
258 }
260 {
261 }
virtual size_t getDebugInterruptNumber() PURE
virtual bool registerInterruptHandlerDebugger(size_t interruptNumber, InterruptHandler *handler)
static OpenFirmware & instance()
Definition: OpenFirmware.h:45
static EXPORTED_PUBLIC SyscallManager & instance()
static Debugger & instance()
Definition: Debugger.h:48
virtual bool registerSyscallHandler(Service_t Service, SyscallHandler *handler)
Handles interrupts and interrupt registrations from kernel components.
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
Definition: Log.h:136
static void interrupt(InterruptState &interruptState)
Abstract base class for interrupt-handlers.
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
#define FATAL(text)
Definition: Log.h:89
static InterruptManager & instance()
virtual bool registerInterruptHandler(size_t interruptNumber, InterruptHandler *handler)
virtual uintptr_t syscall(Service_t service, uintptr_t function, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0, uintptr_t p5=0)
virtual size_t getBreakpointInterruptNumber() PURE