The Pedigree Project  0.1
armv7/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/machine/Machine.h"
22 #include "pedigree/kernel/machine/types.h"
23 #include "pedigree/kernel/panic.h"
24 #include "pedigree/kernel/processor/Processor.h"
25 #include "pedigree/kernel/utilities/utility.h"
26 #ifdef DEBUGGER
27 #include "pedigree/kernel/debugger/Debugger.h"
28 #endif
29 #include "pedigree/kernel/Log.h"
30 
31 #define SYSCALL_INTERRUPT_NUMBER 8
32 #define BREAKPOINT_INTERRUPT_NUMBER 9
33 
34 const char *g_ExceptionNames[32] = {
35  "Interrupt",
36  "TLB modification exception",
37  "TLB exception (load or instruction fetch)",
38  "TLB exception (store)",
39  "Address error exception (load or instruction fetch)",
40  "Address error exception (store)",
41  "Bus error exception (instruction fetch)",
42  "Bus error exception (data: load or store)",
43  "Syscall exception",
44  "Breakpoint exception",
45  "Reserved instruction exception",
46  "Coprocessor unusable exception",
47  "Arithmetic overflow exception",
48  "Trap exception",
49  "LDCz/SDCz to uncached address",
50  "Virtual coherency exception",
51  "Machine check exception",
52  "Floating point exception",
53  "Reserved",
54  "Reserved",
55  "Reserved",
56  "Reserved",
57  "Reserved",
58  "Watchpoint exception",
59  "Reserved",
60  "Reserved",
61  "Reserved",
62  "Reserved",
63  "Reserved",
64  "Reserved",
65  "Reserved",
66  "Reserved",
67 };
68 
70 
72 
74 {
76 }
78 {
80 }
81 
83  size_t interruptNumber, InterruptHandler *handler)
84 {
86  volatile uint32_t *mpuIntcRegisters = reinterpret_cast<volatile uint32_t *>(
88  if (!mpuIntcRegisters)
89  return false;
90 
92  if (UNLIKELY(interruptNumber >= 96))
93  return false;
94  if (UNLIKELY(handler != 0 && m_Handler[interruptNumber] != 0))
95  return false;
96  if (UNLIKELY(handler == 0 && m_Handler[interruptNumber] == 0))
97  return false;
98 
99  // Unmask this interrupt
100  size_t n = (interruptNumber % 96) / 32;
101  mpuIntcRegisters[INTCPS_MIR_CLEAR + (n * 8)] = 1 << (interruptNumber % 32);
102 
103  m_Handler[interruptNumber] = handler;
104  return true;
105 }
106 
107 #ifdef DEBUGGER
108 
110  size_t interruptNumber, InterruptHandler *handler)
111 {
112  volatile uint32_t *mpuIntcRegisters = reinterpret_cast<volatile uint32_t *>(
114  if (!mpuIntcRegisters)
115  return false;
116 
118  if (UNLIKELY(interruptNumber >= 96))
119  return false;
120  if (UNLIKELY(handler != 0 && m_DbgHandler[interruptNumber] != 0))
121  return false;
122  if (UNLIKELY(handler == 0 && m_DbgHandler[interruptNumber] == 0))
123  return false;
124 
125  // Unmask this interrupt
126  size_t n = (interruptNumber % 96) / 32;
127  mpuIntcRegisters[INTCPS_MIR_CLEAR + (n * 8)] = 1 << (interruptNumber % 32);
128 
129  m_DbgHandler[interruptNumber] = handler;
130  return true;
131 }
133 {
134  return 3;
135 }
137 {
138  return 1;
139 }
140 
141 #endif
142 
144  Service_t Service, SyscallHandler *handler)
145 {
146  // TODO: Needs locking
147 
148  if (UNLIKELY(Service >= serviceEnd))
149  return false;
150  if (UNLIKELY(handler != 0 && m_SyscallHandler[Service] != 0))
151  return false;
152  if (UNLIKELY(handler == 0 && m_SyscallHandler[Service] == 0))
153  return false;
154 
155  m_SyscallHandler[Service] = handler;
156  return true;
157 }
158 
160  Service_t service, uintptr_t function, uintptr_t p1, uintptr_t p2,
161  uintptr_t p3, uintptr_t p4, uintptr_t p5)
162 {
164  return 0;
165 }
166 
167 // Handles data aborts, but with a stack frame.
168 void kdata_abort(InterruptState &state) NORETURN;
169 void kdata_abort(InterruptState &state)
170 {
171 #ifdef DEBUGGER
172  // Grab the aborted address.
173  uintptr_t dfar = 0;
174  uintptr_t dfsr = 0;
175  asm volatile("MRC p15,0,%0,c6,c0,0" : "=r"(dfar));
176  asm volatile("MRC p15,0,%0,c5,c0,0" : "=r"(dfsr));
177 
178  // Status.
179  bool bWrite = !!(dfsr & (1 << 11));
180  uint32_t status = (dfsr & (1 << 10) ? 1 << 4 : 0) | (dfsr & 0xF);
181 
182  static LargeStaticString sError;
183  sError.clear();
184  sError.append("Data Abort: ");
185  if (bWrite)
186  sError.append("W ");
187  else
188  sError.append("R ");
189  sError.append("0x");
190  sError.append(dfar, 16, 8, '0');
191  sError.append(" @ 0x");
192  sError.append(state.getInstructionPointer(), 16, 8, '0');
193  sError.append("\n");
194 
195  switch (status)
196  {
197  case 0b00001:
198  sError.append("Alignment fault");
199  break;
200  case 0b00101:
201  case 0b00111:
202  sError.append("Translation fault");
203  break;
204  case 0b00011:
205  case 0b00110:
206  sError.append("Access flag fault");
207  break;
208  case 0b01001:
209  case 0b01011:
210  {
211  uint32_t domain = (dfsr >> 4) & 0xF;
212  sError.append("Domain fault for domain 0x");
213  sError.append(domain, 16, 8, '0');
214  break;
215  }
216  case 0b01101:
217  case 0b01111:
218  sError.append("Permission fault");
219  break;
220  case 0b00010:
221  sError.append("Debug event");
222  break;
223  case 0b01000:
224  sError.append("Sync external abort");
225  break;
226  case 0b10110:
227  sError.append("Async external abort");
228  break;
229  default:
230  sError.append("Unknown fault");
231  }
232 
233  ERROR_NOLOCK(static_cast<const char *>(sError));
234  Debugger::instance().start(state, sError);
235 #else
236  panic("data abort");
237 #endif
238 
239  while (1)
240  ;
241 }
242 
243 void kprefetch_abort(InterruptState &state) NORETURN;
244 void kprefetch_abort(InterruptState &state)
245 {
246 #ifdef DEBUGGER
247  static LargeStaticString sError;
248  sError.clear();
249  sError.append("Prefetch Abort at 0x");
250  sError.append(state.getInstructionPointer(), 16, 8, '0');
251  Debugger::instance().start(state, sError);
252 #endif
253 
254  while (1)
255  ;
256 }
257 
258 void kswi_handler(InterruptState &state)
259 {
260  // Grab SWI number.
261  const uint32_t *at =
262  reinterpret_cast<const uint32_t *>(state.getInstructionPointer() - 4);
263  uint32_t swi = (*at) & 0xFFFFFFUL;
264 
265  NOTICE("swi #" << Hex << swi);
266  if (swi == 0xdeee)
267  {
268  // Dump state.
269  for (size_t i = 0; i < state.getRegisterCount(); ++i)
270  {
271  NOTICE(
272  state.getRegisterName(i) << "=" << Hex << state.getRegister(i));
273  }
274  }
275 #ifdef DEBUGGER
276  else if (swi == 0xdeb16)
277  {
278  static LargeStaticString sError;
279  sError.clear();
280  sError.append("Debugger Trap at 0x");
281  sError.append(state.getInstructionPointer(), 16, 8, '0');
282  Debugger::instance().start(state, sError);
283  return;
284  }
285 #endif
286 }
287 
290 extern "C" void arm_swint_handler(InterruptState &state);
291 extern "C" void arm_instundef_handler() __attribute__((naked));
292 extern "C" void arm_fiq_handler() __attribute__((interrupt("FIQ"))) NORETURN;
293 extern "C" void arm_irq_handler(InterruptState &state);
294 extern "C" void arm_reset_handler() __attribute__((naked));
295 extern "C" void arm_prefetch_abort_handler(InterruptState &state)
296  __attribute__((naked));
297 extern "C" void arm_data_abort_handler(InterruptState &state)
298  __attribute__((naked));
299 extern "C" void arm_addrexcept_handler() __attribute__((naked));
300 
301 extern "C" void arm_swint_handler(InterruptState &state)
302 {
303  kswi_handler(state);
304 }
305 
306 extern "C" void arm_instundef_handler()
307 {
308  NOTICE_NOLOCK("undefined instruction");
309  while (1)
310  ;
311 }
312 
313 extern "C" void arm_fiq_handler()
314 {
315  NOTICE_NOLOCK("FIQ");
316  while (1)
317  ;
318 }
319 
320 extern "C" void arm_irq_handler(InterruptState &state)
321 {
323 }
324 
325 extern "C" void arm_reset_handler()
326 {
327  NOTICE_NOLOCK("reset");
328  while (1)
329  ;
330 }
331 
332 extern "C" void arm_prefetch_abort_handler(InterruptState &state)
333 {
334  kprefetch_abort(state);
335  while (1)
336  ;
337 }
338 
339 extern "C" void arm_data_abort_handler(InterruptState &state)
340 {
341  kdata_abort(state);
342 }
343 
344 extern "C" void arm_addrexcept_handler()
345 {
346  NOTICE_NOLOCK("address exception");
347  while (1)
348  ;
349 }
350 
351 extern uint32_t __arm_vector_table;
352 extern uint32_t __end_arm_vector_table;
354 {
355  // Map in the MPU interrupt controller
356  if (!PhysicalMemoryManager::instance().allocateRegion(
360  0x48200000))
361  return;
362 
363  // Map in the ARM vector table to 0xFFFF0000
365  reinterpret_cast<physical_uintptr_t>(&__arm_vector_table),
366  reinterpret_cast<void *>(0xFFFF0000),
368  return;
369 
370  // Switch to the high vector for the exception base
371  uint32_t sctlr = 0;
372  asm volatile("MRC p15,0,%0,c1,c0,0" : "=r"(sctlr));
373  if (!(sctlr & 0x2000))
374  sctlr |= 0x2000;
375  asm volatile("MCR p15,0,%0,c1,c0,0" : : "r"(sctlr));
376 
377  // Initialise the MPU INTC
378  volatile uint32_t *mpuIntcRegisters = reinterpret_cast<volatile uint32_t *>(
380 
381  // Perform a reset of the MPU INTC
382  mpuIntcRegisters[INTCPS_SYSCONFIG] = 2;
383  while ((mpuIntcRegisters[INTCPS_SYSSTATUS] & 1) == 0)
384  ;
385 
386  // Write the MMIO address and hardware revisio to the console
387  uint32_t revision = mpuIntcRegisters[0];
388  NOTICE(
389  "MPU interrupt controller at "
390  << Hex
391  << reinterpret_cast<uintptr_t>(
393  << " - revision " << Dec << ((revision >> 4) & 0xF) << "."
394  << (revision & 0xF) << Hex);
395 
396  // Set up the functional clock auto-idle and the synchronizer clock
397  // auto-gating
398  mpuIntcRegisters[INTCPS_IDLE] = 0;
399 
400  // Program the base priority and enable FIQs where necessary for all IRQs
401  for (size_t m = 0; m < 96; m++)
402  {
403  // Priority: 0 (highest), route to IRQ (not FIQ)
404  mpuIntcRegisters[INTCPS_ILR + m] = 0;
405  }
406 
407  // Mask all interrupts (when an interrupt line is registered, it will be
408  // unmasked)
409  for (size_t n = 0; n < 3; n++)
410  {
411  mpuIntcRegisters[INTCPS_MIR_SET + (n * 8)] = 0xFFFFFFFF;
412  mpuIntcRegisters[INTCPS_ISR_CLEAR + (n * 8)] = 0xFFFFFFFF;
413  }
414 
415  // Disable the priority threshold
416  mpuIntcRegisters[INTCPS_THRESHOLD] = 0xFF;
417 
418  // Reset IRQ and FIQ output in case any are pending
419  mpuIntcRegisters[INTCPS_CONTROL] = 3;
420 }
421 
422 void ARMV7InterruptManager::interrupt(InterruptState &interruptState)
423 {
424  volatile uint32_t *mpuIntcRegisters = reinterpret_cast<volatile uint32_t *>(
426  if (!mpuIntcRegisters)
427  return;
428 
429  // Grab the interrupt number
430  size_t intNumber = mpuIntcRegisters[INTCPS_SIR_IRQ] & 0x7F;
431 
432 #ifdef DEBUGGER
433  // Call the kernel debugger's handler, if any
434  if (m_Instance.m_DbgHandler[intNumber] != 0)
435  m_Instance.m_DbgHandler[intNumber]->interrupt(
436  intNumber, interruptState);
437 #endif
438 
439  // Call the interrupt handler if one exists
440  if (m_Instance.m_Handler[intNumber] != 0)
441  m_Instance.m_Handler[intNumber]->interrupt(intNumber, interruptState);
442 
443  // Ack the interrupt
444  mpuIntcRegisters[INTCPS_CONTROL] =
445  1; // Reset IRQ output and enable new IRQs
446 }
447 
449 {
450  // Initialise the pointers to the interrupt handler
451  for (size_t i = 0; i < 256; i++)
452  {
453  m_Handler[i] = 0;
454 #ifdef DEBUGGER
455  m_DbgHandler[i] = 0;
456 #endif
457  }
458 
459  // Initialise the pointers to the syscall handler
460  for (size_t i = 0; i < serviceEnd; i++)
461  m_SyscallHandler[i] = 0;
462 }
464 {
465 }
virtual size_t getBreakpointInterruptNumber() PURE
static PhysicalMemoryManager & instance()
virtual bool registerInterruptHandlerDebugger(size_t interruptNumber, InterruptHandler *handler)
static EXPORTED_PUBLIC SyscallManager & instance()
static Debugger & instance()
Definition: Debugger.h:48
virtual bool registerInterruptHandler(size_t interruptNumber, InterruptHandler *handler)
Handles interrupts and interrupt registrations from kernel components.
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static void interrupt(InterruptState &interruptState)
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
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)
#define NOTICE(text)
Definition: Log.h:74
Special memory entity in the kernel&#39;s virtual address space.
Definition: MemoryRegion.h:35
Definition: Log.h:136
void * virtualAddress() const
Definition: MemoryRegion.cc:39
Abstract base class for interrupt-handlers.
Definition: Log.h:138
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
static InterruptManager & instance()
virtual bool registerSyscallHandler(Service_t Service, SyscallHandler *handler)
virtual size_t getDebugInterruptNumber() PURE