The Pedigree Project  0.1
x86/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/panic.h"
23 #include "pedigree/kernel/processor/Processor.h"
24 #include "pedigree/kernel/utilities/StaticString.h"
25 #if defined(DEBUGGER)
26 #include "pedigree/kernel/debugger/Debugger.h"
27 #endif
28 
29 #ifdef THREADS
30 #include "pedigree/kernel/Subsystem.h"
31 #include "pedigree/kernel/process/Process.h"
32 #endif
33 
34 #include "pedigree/kernel/utilities/utility.h"
35 
36 #define SYSCALL_INTERRUPT_NUMBER 255
37 
38 const char *g_ExceptionNames[] = {
39  "Divide Error",
40  "Debug",
41  "NMI Interrupt",
42  "Breakpoint",
43  "Overflow",
44  "BOUND Range Exceeded",
45  "Invalid Opcode",
46  "Device Not Available",
47  "Double Fault",
48  "Coprocessor Segment Overrun", /* recent IA-32 processors don't generate
49  this */
50  "Invalid TSS",
51  "Segment Not Present",
52  "Stack Fault",
53  "General Protection Fault",
54  "Page Fault",
55  "Reserved: Interrupt 15",
56  "FPU Floating-Point Error",
57  "Alignment Check",
58  "Machine-Check",
59  "SIMD Floating-Point Exception",
60  "Reserved: Interrupt 20",
61  "Reserved: Interrupt 21",
62  "Reserved: Interrupt 22",
63  "Reserved: Interrupt 23",
64  "Reserved: Interrupt 24",
65  "Reserved: Interrupt 25",
66  "Reserved: Interrupt 26",
67  "Reserved: Interrupt 27",
68  "Reserved: Interrupt 28",
69  "Reserved: Interrupt 29",
70  "Reserved: Interrupt 30",
71  "Reserved: Interrupt 31"};
72 
74 
76 {
78 }
80 {
82 }
83 
85  size_t nInterruptNumber, InterruptHandler *pHandler)
86 {
87  LockGuard<Spinlock> lockGuard(m_Lock);
88 
89  if (UNLIKELY(
90  nInterruptNumber >= 256 ||
91  nInterruptNumber == SYSCALL_INTERRUPT_NUMBER))
92  return false;
93  if (UNLIKELY(pHandler != 0 && m_pHandler[nInterruptNumber] != 0))
94  return false;
95  if (UNLIKELY(pHandler == 0 && m_pHandler[nInterruptNumber] == 0))
96  return false;
97 
98  m_pHandler[nInterruptNumber] = pHandler;
99  return true;
100 }
101 
102 #ifdef DEBUGGER
103 
105  size_t nInterruptNumber, InterruptHandler *pHandler)
106 {
107  LockGuard<Spinlock> lockGuard(m_Lock);
108 
109  if (UNLIKELY(
110  nInterruptNumber >= 256 ||
111  nInterruptNumber == SYSCALL_INTERRUPT_NUMBER))
112  return false;
113  if (UNLIKELY(pHandler != 0 && m_pDbgHandler[nInterruptNumber] != 0))
114  return false;
115  if (UNLIKELY(pHandler == 0 && m_pDbgHandler[nInterruptNumber] == 0))
116  return false;
117 
118  m_pDbgHandler[nInterruptNumber] = pHandler;
119  return true;
120 }
122 {
123  return 3;
124 }
126 {
127  return 1;
128 }
129 
130 #endif
131 
133  Service_t Service, SyscallHandler *pHandler)
134 {
135  LockGuard<Spinlock> lockGuard(m_Lock);
136 
137  if (UNLIKELY(Service >= serviceEnd))
138  return false;
139  if (UNLIKELY(pHandler != 0 && m_pSyscallHandler[Service] != 0))
140  return false;
141  if (UNLIKELY(pHandler == 0 && m_pSyscallHandler[Service] == 0))
142  return false;
143 
144  m_pSyscallHandler[Service] = pHandler;
145  return true;
146 }
147 
148 void X86InterruptManager::interrupt(InterruptState &interruptState)
149 {
150  size_t nIntNumber = interruptState.getInterruptNumber();
151 
152  // Trigger the next value in the PRNG sequence, so interrupt jitter improves
153  // randomness.
154  random_next();
155 
156 #if defined(DEBUGGER)
157  {
158  InterruptHandler *pHandler;
159 
160  // Get the debugger handler
161  {
162  LockGuard<Spinlock> lockGuard(m_Instance.m_Lock);
163  pHandler = m_Instance.m_pDbgHandler[nIntNumber];
164  }
165 
166  // Call the kernel debugger's handler, if any
167  if (pHandler != 0)
168  pHandler->interrupt(nIntNumber, interruptState);
169  }
170 #endif
171 
172  // Call the syscall handler, if it is the syscall interrupt
173  if (nIntNumber == SYSCALL_INTERRUPT_NUMBER)
174  {
175  size_t serviceNumber = interruptState.getSyscallService();
176 
177  if (UNLIKELY(serviceNumber >= serviceEnd))
178  {
179  // TODO: We should return an error here
180  return;
181  }
182 
183  SyscallHandler *pHandler;
184 
185  // Get the syscall handler
186  {
187  LockGuard<Spinlock> lockGuard(m_Instance.m_Lock);
188  pHandler = m_Instance.m_pSyscallHandler[serviceNumber];
189  }
190 
191  if (LIKELY(pHandler != 0))
192  {
193  interruptState.m_Eax = pHandler->syscall(interruptState);
194  interruptState.m_Ebx =
195  Processor::information().getCurrentThread()->getErrno();
196  if (Processor::information().getCurrentThread()->getUnwindState() ==
197  Thread::Exit)
198  {
199  NOTICE("Unwind state exit, in interrupt handler");
201  .getCurrentThread()
202  ->getParent()
203  ->getSubsystem()
204  ->exit(0);
205  }
206  }
207  return;
208  }
209 
210  InterruptHandler *pHandler;
211 
212  // Get the interrupt handler
213  {
214  LockGuard<Spinlock> lockGuard(m_Instance.m_Lock);
215  pHandler = m_Instance.m_pHandler[nIntNumber];
216  }
217 
218  // Call the normal interrupt handler, if any
219  if (LIKELY(pHandler != 0))
220  {
221  pHandler->interrupt(nIntNumber, interruptState);
222  return;
223  }
224 
225 // Check for exceptions we can kill threads with
226 #ifdef THREADS
227  Thread *pThread = Processor::information().getCurrentThread();
228  Process *pProcess = pThread->getParent();
229  Subsystem *pSubsystem = pProcess->getSubsystem();
230  if (pSubsystem)
231  {
232  if (UNLIKELY(nIntNumber == 0))
233  {
234  pSubsystem->threadException(
235  pThread, Subsystem::DivideByZero, interruptState);
236  return;
237  }
238  else if (UNLIKELY(nIntNumber == 6))
239  {
240  pSubsystem->threadException(
241  pThread, Subsystem::InvalidOpcode, interruptState);
242  return;
243  }
244  else if (UNLIKELY(nIntNumber == 13))
245  {
246  pSubsystem->threadException(
247  pThread, Subsystem::GeneralProtectionFault, interruptState);
248  return;
249  }
250  else if (UNLIKELY(nIntNumber == 16))
251  {
252  pSubsystem->threadException(
253  pThread, Subsystem::FpuError, interruptState);
254  return;
255  }
256  else if (UNLIKELY(nIntNumber == 19))
257  {
258  pSubsystem->threadException(
259  pThread, Subsystem::SpecialFpuError, interruptState);
260  return;
261  }
262  }
263 #endif
264 
265  // unhandled interrupt, check for an exception (interrupts 0-31 inclusive
266  // are reserved, not for use by system programmers)
267  // TODO: Rework this
268  if (LIKELY(nIntNumber < 32 && nIntNumber != 1 && nIntNumber != 3))
269  {
270  // TODO:: Check for debugger initialisation.
271  // TODO: register dump, maybe a breakpoint so the deubbger can take
272  // over? for now just print out the exception name and number
273  static LargeStaticString e;
274  e.clear();
275  e.append("Exception #");
276  e.append(nIntNumber, 10);
277  e.append(": \"");
278  e.append(g_ExceptionNames[nIntNumber]);
279  e.append("\"");
280  if (nIntNumber == 14)
281  {
282  uint32_t cr2;
283  asm volatile("mov %%cr2, %%eax" : "=a"(cr2));
284  e.append(" at 0x");
285  e.append(cr2, 16, 8, '0');
286  e.append(", errorcode 0x");
287  e.append(interruptState.m_Errorcode, 16, 8, '0');
288  }
289 
290  if (nIntNumber == 8)
291  {
292  X86TaskStateSegment *tss = reinterpret_cast<X86TaskStateSegment *>(
293  Processor::information().getTss());
294  ERROR_NOLOCK("");
295  ERROR_NOLOCK("");
296  ERROR_NOLOCK("");
297  ERROR_NOLOCK("--------------------------- DOUBLE FAULT "
298  "---------------------------");
299  ERROR_NOLOCK("");
300  ERROR_NOLOCK("EIP was: " << tss->eip << ".");
301  ERROR_NOLOCK("ESP/EBP: " << tss->esp << ", " << tss->ebp << ".");
302  ERROR_NOLOCK("");
303  ERROR_NOLOCK("GPs:");
304  ERROR_NOLOCK(
305  "EAX: " << tss->eax << ", EBX: " << tss->ebx
306  << ", ECX: " << tss->ecx << ".");
307  ERROR_NOLOCK(
308  "EDX: " << tss->edx << ", ESI: " << tss->esi
309  << ", EDI: " << tss->edi << ".");
310  ERROR_NOLOCK("");
311  ERROR_NOLOCK("Segments:");
312  ERROR_NOLOCK(
313  "CS: " << tss->cs << ", DS: " << tss->ds << ", ES: " << tss->es
314  << ".");
315  ERROR_NOLOCK(
316  "FS: " << tss->fs << ", GS: " << tss->gs << ", SS: " << tss->ss
317  << ".");
318 
319  uint32_t cr2;
320  asm volatile("mov %%cr2, %%eax" : "=a"(cr2));
321  NOTICE_NOLOCK("Possible #PF at address " << cr2 << ".");
322 
323  // Unrecoverable fault
324  interruptState.setInstructionPointer(tss->eip);
325  interruptState.setBasePointer(tss->ebp);
326  interruptState.setFlags(tss->eflags);
327  }
328 #if defined(DEBUGGER)
329  Debugger::instance().start(interruptState, e);
330  if (nIntNumber == 8)
331  panic("Can't return from a #DF");
332 #else
333  panic(e);
334 #endif
335  }
336 }
337 
339  Service_t service, uintptr_t function, uintptr_t p1, uintptr_t p2,
340  uintptr_t p3, uintptr_t p4, uintptr_t p5)
341 {
342  uint32_t eax = ((service & 0xFFFF) << 16) | (function & 0xFFFF);
343  uintptr_t ret;
344  asm volatile("int $255"
345  : "=a"(ret)
346  : "0"(eax), "b"(p1), "c"(p2), "d"(p3), "S"(p4), "D"(p5));
347  return ret;
348 }
349 
350 //
351 // Functions only usable in the kernel initialisation phase
352 //
353 
355 {
356  // Load the IDT
357  struct
358  {
359  uint16_t size;
360  uint32_t idt;
361  } PACKED idtr = {2047, reinterpret_cast<uintptr_t>(&m_Instance.m_IDT)};
362 
363  asm volatile("lidt %0" ::"m"(idtr));
364 }
365 
367  size_t nInterruptNumber, uintptr_t interruptHandler, bool bUserspace)
368 {
369  m_IDT[nInterruptNumber].offset0 = interruptHandler & 0xFFFF;
370  m_IDT[nInterruptNumber].selector = 0x08;
371  m_IDT[nInterruptNumber].res = 0;
372  m_IDT[nInterruptNumber].flags = bUserspace ? 0xEE : 0x8E;
373  m_IDT[nInterruptNumber].offset1 = (interruptHandler >> 16) & 0xFFFF;
374 }
375 
376 void X86InterruptManager::setTaskGate(size_t nInterruptNumber, uint16_t tssSeg)
377 {
378  m_IDT[nInterruptNumber].offset0 = 0;
379  m_IDT[nInterruptNumber].selector = tssSeg;
380  m_IDT[nInterruptNumber].res = 0;
381  m_IDT[nInterruptNumber].flags = 0xE5;
382  m_IDT[nInterruptNumber].offset1 = 0;
383 }
384 
386 {
387  // Initialise the pointers to the interrupt handler
388  for (size_t i = 0; i < 256; i++)
389  {
390  m_pHandler[i] = 0;
391 #if defined(DEBUGGER)
392  m_pDbgHandler[i] = 0;
393 #endif
394  }
395 
396  // Initialise the pointers to the syscall handler
397  for (size_t i = 0; i < serviceEnd; i++)
398  m_pSyscallHandler[i] = 0;
399 
400  // Initialise the IDT
401  extern uintptr_t interrupt_handler_array[];
402  for (size_t i = 0; i < 256; i++)
404  i, interrupt_handler_array[i],
405  (i == SYSCALL_INTERRUPT_NUMBER || i == 3 /* Interrupt number */) ?
406  true :
407  false);
408 
409  // Overwrite the double fault handler
410  setTaskGate(8, 0x30);
411 }
413 {
414 }
virtual bool registerSyscallHandler(Service_t Service, SyscallHandler *pHandler)
static EXPORTED_PUBLIC SyscallManager & instance()
static Debugger & instance()
Definition: Debugger.h:48
Handles interrupts and interrupt registrations from kernel components.
virtual uintptr_t syscall(SyscallState &State)=0
virtual void threadException(Thread *pThread, ExceptionType eType)
Definition: Subsystem.cc:35
static ProcessorInformation & information()
Definition: Processor.cc:45
void setTaskGate(size_t nInterruptNumber, uint16_t tssSeg) INITIALISATION_ONLY
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
#define NOTICE(text)
Definition: Log.h:74
virtual void interrupt(size_t nInterruptNumber, InterruptState &state)=0
static void initialiseProcessor() INITIALISATION_ONLY
SyscallHandler * m_pSyscallHandler[serviceEnd]
virtual size_t getDebugInterruptNumber() PURE
Process * getParent() const
Definition: Thread.h:181
X86InterruptManager() INITIALISATION_ONLY
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)
Definition: Thread.h:54
virtual size_t getBreakpointInterruptNumber() PURE
Abstract base class for interrupt-handlers.
static void interrupt(InterruptState &interruptState)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
static X86InterruptManager & instance()
void setInterruptGate(size_t nInterruptNumber, uintptr_t interruptHandler, bool bUserspace) INITIALISATION_ONLY
(b) below.
Definition: Thread.h:245
virtual bool registerInterruptHandlerDebugger(size_t nInterruptNumber, InterruptHandler *pHandler)
static InterruptManager & instance()
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)