The Pedigree Project  0.1
mips32/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/Log.h"
22 #include "pedigree/kernel/debugger/Debugger.h"
23 #include "pedigree/kernel/machine/Machine.h"
24 #include "pedigree/kernel/machine/types.h"
25 #include "pedigree/kernel/processor/Processor.h"
26 #include "pedigree/kernel/processor/TlbManager.h"
27 #include "pedigree/kernel/utilities/utility.h"
28 
29 #define SYSCALL_INTERRUPT_NUMBER 8
30 #define BREAKPOINT_INTERRUPT_NUMBER 9
31 
32 const char *g_ExceptionNames[32] = {
33  "Interrupt",
34  "TLB modification exception",
35  "TLB exception (load or instruction fetch)",
36  "TLB exception (store)",
37  "Address error exception (load or instruction fetch)",
38  "Address error exception (store)",
39  "Bus error exception (instruction fetch)",
40  "Bus error exception (data: load or store)",
41  "Syscall exception",
42  "Breakpoint exception",
43  "Reserved instruction exception",
44  "Coprocessor unusable exception",
45  "Arithmetic overflow exception",
46  "Trap exception",
47  "LDCz/SDCz to uncached address",
48  "Virtual coherency exception",
49  "Machine check exception",
50  "Floating point exception",
51  "Reserved",
52  "Reserved",
53  "Reserved",
54  "Reserved",
55  "Reserved",
56  "Watchpoint exception",
57  "Reserved",
58  "Reserved",
59  "Reserved",
60  "Reserved",
61  "Reserved",
62  "Reserved",
63  "Reserved",
64  "Reserved",
65 };
66 
68 
70 {
72 }
74 {
76 }
77 
79  size_t interruptNumber, InterruptHandler *handler)
80 {
81  // TODO: Needs locking
82  if (UNLIKELY(interruptNumber >= 256))
83  return false;
84  if (UNLIKELY(handler != 0 && m_Handler[interruptNumber] != 0))
85  return false;
86  if (UNLIKELY(handler == 0 && m_Handler[interruptNumber] == 0))
87  return false;
88 
89  m_Handler[interruptNumber] = handler;
90  return true;
91 }
92 
93 bool MIPS32InterruptManager::registerExternalInterruptHandler(
94  size_t interruptNumber, InterruptHandler *handler)
95 {
96  // TODO: Needs locking
97  if (UNLIKELY(interruptNumber >= 8))
98  return false;
99  if (UNLIKELY(handler != 0 && m_ExternalHandler[interruptNumber] != 0))
100  return false;
101  if (UNLIKELY(handler == 0 && m_ExternalHandler[interruptNumber] == 0))
102  return false;
103 
104  m_ExternalHandler[interruptNumber] = handler;
105  return true;
106 }
107 
108 #ifdef DEBUGGER
109 
111  size_t interruptNumber, InterruptHandler *handler)
112 {
113  // TODO: Needs locking
114  if (UNLIKELY(interruptNumber >= 256))
115  return false;
116  if (UNLIKELY(handler != 0 && m_DbgHandler[interruptNumber] != 0))
117  return false;
118  if (UNLIKELY(handler == 0 && m_DbgHandler[interruptNumber] == 0))
119  return false;
120 
121  m_DbgHandler[interruptNumber] = handler;
122  return true;
123 }
125 {
126  return 3;
127 }
129 {
130  return 1;
131 }
132 
133 #endif
134 
136  Service_t Service, SyscallHandler *handler)
137 {
138  // TODO: Needs locking
139 
140  if (UNLIKELY(Service >= serviceEnd))
141  return false;
142  if (UNLIKELY(handler != 0 && m_SyscallHandler[Service] != 0))
143  return false;
144  if (UNLIKELY(handler == 0 && m_SyscallHandler[Service] == 0))
145  return false;
146 
147  m_SyscallHandler[Service] = handler;
148  return true;
149 }
150 extern "C" void mips32_exception(void);
152 {
153  // Exception handler goes at 0x8000 0180
154  // Here we generate some exception handling code.
155  uint32_t pCode[4];
156 
157  // lui $k0, <upper 16 bits of exception handler>
158  pCode[0] =
159  0x3c1a0000 | (reinterpret_cast<uint32_t>(&mips32_exception) >> 16);
160  // ori $k0, $k0, <lower 16 bits of exception handler>
161  pCode[1] = 0x375a0000 |
162  (reinterpret_cast<uint32_t>(&mips32_exception) & 0x0000FFFF);
163  // jr $k0
164  pCode[2] = 0x03400008;
165  // nop (delay slot)
166  pCode[3] = 0x00000000;
167 
168  // Now poke that exception handling stub into memory.
169  MemoryCopy(
170  reinterpret_cast<void *>(KSEG1(0x80)), reinterpret_cast<void *>(pCode),
171  32 * 4);
172  MemoryCopy(
173  reinterpret_cast<void *>(KSEG1(0x100)), reinterpret_cast<void *>(pCode),
174  32 * 4);
175  MemoryCopy(
176  reinterpret_cast<void *>(KSEG1(0x180)), reinterpret_cast<void *>(pCode),
177  32 * 4);
178  MemoryCopy(
179  reinterpret_cast<void *>(KSEG1(0x200)), reinterpret_cast<void *>(pCode),
180  32 * 4);
181 
182  // Do the same for the TLB refill handler.
183 
184  // lui $k0, <upper 16 bits of exception handler>
185  pCode[0] = 0x3c1a0000 |
186  (reinterpret_cast<uint32_t>(&TlbManager::interruptAsm) >> 16);
187  // ori $k0, $k0, <lower 16 bits of exception handler>
188  pCode[1] =
189  0x375a0000 |
190  (reinterpret_cast<uint32_t>(&TlbManager::interruptAsm) & 0x0000FFFF);
191  // jr $k0
192  pCode[2] = 0x03400008;
193  // nop (delay slot)
194  pCode[3] = 0x00000000;
195 
196  MemoryCopy(
197  reinterpret_cast<void *>(KSEG1(0x0)), reinterpret_cast<void *>(pCode),
198  32 * 4);
199 
200  // Invalidate the instruction cache - force a reload of the exception
201  // handlers.
202  for (uintptr_t i = KSEG0(0); i < KSEG0(0x200); i += 0x80)
203  Processor::invalidateICache(i);
204 }
205 
206 void MIPS32InterruptManager::interrupt(InterruptState &interruptState)
207 {
208  // We don't want interrupts, but we don't need to be in the exception level.
209  uintptr_t sr = interruptState.m_Sr;
210  sr &= ~SR_IE; // Disable interrupts.
211  sr &= ~SR_EXL; // Remove us from being in exception privilege level.
212  // TODO set SE_KSU.
213  asm volatile("mtc0 %0, $12" ::"r"(sr));
214 
215  // Read the cause register.
216  uint32_t cause;
217  asm volatile("mtc0 %0, $13" : "=r"(cause));
218 
219  // Mask off interrupts not enabled.
220  cause &= interruptState.m_Sr;
221 
222  // Find the external interrupts pending - TODO mask off masked interrupts.
223  cause = (cause >> 8) & 0xFF;
224 
225  // Find the lowest numbered interrupt pending - we will handle this one.
226  uint32_t externalInt = 0xFF;
227  for (int i = 0; i < 8; i++)
228  {
229  if (cause & (1 << i))
230  {
231  externalInt = i;
232  break;
233  }
234  }
235 
236  // TODO: Needs locking
237  size_t intNumber = interruptState.getInterruptNumber();
238 
239 #ifdef DEBUGGER
240  // Call the kernel debugger's handler, if any
241  if (m_Instance.m_DbgHandler[intNumber] != 0)
242  m_Instance.m_DbgHandler[intNumber]->interrupt(
243  intNumber, interruptState);
244 #endif
245 
246  // Call the syscall handler, if it is the syscall interrupt
247  if (intNumber == SYSCALL_INTERRUPT_NUMBER)
248  {
249  size_t serviceNumber = interruptState.getSyscallService();
250  if (LIKELY(
251  serviceNumber < serviceEnd &&
252  m_Instance.m_SyscallHandler[serviceNumber] != 0))
253  m_Instance.m_SyscallHandler[serviceNumber]->syscall(interruptState);
254  }
255  // External interrupt, handled?
256  else if (intNumber == 0 && m_Instance.m_ExternalHandler[externalInt])
257  m_Instance.m_ExternalHandler[externalInt]->interrupt(
258  externalInt, interruptState);
259  // Call the normal interrupt handler, if any, otherwise
260  else if (m_Instance.m_Handler[intNumber] != 0)
261  m_Instance.m_Handler[intNumber]->interrupt(intNumber, interruptState);
262  else
263  {
264  // TODO:: Check for debugger initialisation.
265  static LargeStaticString e;
266  e.clear();
267  e.append("Exception #");
268  e.append(intNumber, 10);
269  e.append(": \"");
270  e.append(g_ExceptionNames[intNumber]);
271  e.append("\"");
272  Debugger::instance().start(interruptState, e);
273  }
274 
275  // If this was a trap or breakpoint instruction, we need to increase the
276  // program counter a bit.
277  if (intNumber == 9 || intNumber == 13)
278  {
279  // ...Unless we were in a branch delay slot!
280  if (!interruptState.branchDelay())
281  {
282  interruptState.m_Epc += 4;
283  }
284  }
285 }
286 
288 {
289  // Initialise the pointers to the interrupt handler
290  for (size_t i = 0; i < 64; i++)
291  {
292  m_Handler[i] = 0;
293  if (i < 8)
294  m_ExternalHandler[i] = 0;
295 #ifdef DEBUGGER
296  m_DbgHandler[i] = 0;
297 #endif
298  }
299 
300  // Initialise the pointers to the syscall handler
301  for (size_t i = 0; i < serviceEnd; i++)
302  m_SyscallHandler[i] = 0;
303 }
305 {
306 }
static EXPORTED_PUBLIC SyscallManager & instance()
static Debugger & instance()
Definition: Debugger.h:48
Handles interrupts and interrupt registrations from kernel components.
virtual size_t getDebugInterruptNumber() PURE
static void interrupt(InterruptState &interruptState)
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
virtual bool registerInterruptHandler(size_t interruptNumber, InterruptHandler *handler)
virtual bool registerInterruptHandlerDebugger(size_t interruptNumber, InterruptHandler *handler)
virtual size_t getBreakpointInterruptNumber() PURE
Abstract base class for interrupt-handlers.
virtual bool registerSyscallHandler(Service_t Service, SyscallHandler *handler)
static InterruptManager & instance()