The Pedigree Project  0.1
x64/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/process/Thread.h"
24 #include "pedigree/kernel/processor/InterruptHandler.h"
25 #include "pedigree/kernel/processor/Processor.h"
26 #include "pedigree/kernel/processor/ProcessorInformation.h"
27 #include "pedigree/kernel/processor/state.h"
28 #include "pedigree/kernel/utilities/StaticString.h"
29 
30 #if defined(DEBUGGER)
31 #include "pedigree/kernel/debugger/Debugger.h"
32 #endif
33 
34 #ifdef THREADS
35 #include "pedigree/kernel/Subsystem.h"
36 #include "pedigree/kernel/process/Process.h"
37 #include "pedigree/kernel/process/TimeTracker.h"
38 #endif
39 
40 static const char *g_ExceptionNames[] = {
41  "Divide Error",
42  "Debug",
43  "NMI Interrupt",
44  "Breakpoint",
45  "Overflow",
46  "BOUND Range Exceeded",
47  "Invalid Opcode",
48  "Device Not Available",
49  "Double Fault",
50  "Coprocessor Segment Overrun", /* recent IA-32 processors don't generate
51  this */
52  "Invalid TSS",
53  "Segment Not Present",
54  "Stack Fault",
55  "General Protection Fault",
56  "Page Fault",
57  "FPU Floating-Point Error",
58  "Alignment Check",
59  "Machine-Check",
60  "SIMD Floating-Point Exception",
61  "Reserved: Interrupt 19",
62  "Reserved: Interrupt 20",
63  "Reserved: Interrupt 21",
64  "Reserved: Interrupt 22",
65  "Reserved: Interrupt 23",
66  "Reserved: Interrupt 24",
67  "Reserved: Interrupt 25",
68  "Reserved: Interrupt 26",
69  "Reserved: Interrupt 27",
70  "Reserved: Interrupt 28",
71  "Reserved: Interrupt 29",
72  "Reserved: Interrupt 30",
73  "Reserved: Interrupt 31"};
74 
76 
78 {
80 }
81 
83  size_t nInterruptNumber, InterruptHandler *pHandler)
84 {
85  // Lock the class until the end of the function
86  LockGuard<Spinlock> lock(m_Lock);
87 
88  // Sanity checks
89  if (UNLIKELY(nInterruptNumber >= 256))
90  return false;
91  if (UNLIKELY(pHandler != 0 && m_pHandler[nInterruptNumber] != 0))
92  return false;
93  if (UNLIKELY(pHandler == 0 && m_pHandler[nInterruptNumber] == 0))
94  return false;
95 
96  // Change the pHandler
97  m_pHandler[nInterruptNumber] = pHandler;
98 
99  return true;
100 }
101 
102 #if defined(DEBUGGER)
103 
105  size_t nInterruptNumber, InterruptHandler *pHandler)
106 {
107  // Lock the class until the end of the function
108  LockGuard<Spinlock> lock(m_Lock);
109 
110  // Sanity checks
111  if (UNLIKELY(nInterruptNumber >= 256))
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  // Change the pHandler
119  m_pDbgHandler[nInterruptNumber] = pHandler;
120 
121  return true;
122 }
124 {
125  return 3;
126 }
128 {
129  return 1;
130 }
131 
132 #endif
133 
134 void X64InterruptManager::interrupt(InterruptState &interruptState)
135 {
136  TimeTracker tracker(0, !interruptState.kernelMode());
137  size_t nIntNumber = interruptState.getInterruptNumber();
138 
139 #if defined(DEBUGGER)
140  {
141  InterruptHandler *pHandler;
142 
143  // Get the debugger handler
144  {
145  LockGuard<Spinlock> lockGuard(m_Instance.m_Lock);
146  pHandler = m_Instance.m_pDbgHandler[nIntNumber];
147  }
148 
149  // Call the kernel debugger's handler, if any
150  if (pHandler != 0)
151  pHandler->interrupt(nIntNumber, interruptState);
152  }
153 #endif
154 
155  InterruptHandler *pHandler;
156 
157  // Get the interrupt handler
158  {
159  LockGuard<Spinlock> lockGuard(m_Instance.m_Lock);
160  pHandler = m_Instance.m_pHandler[nIntNumber];
161  }
162 
163  // Call the normal interrupt handler, if any
164  if (LIKELY(pHandler != 0))
165  {
166  pHandler->interrupt(nIntNumber, interruptState);
167  return;
168  }
169 
170 // Were we running in the kernel, or user space?
171 // User space processes have a subsystem, kernel ones do not.
172 #ifdef THREADS
173  Thread *pThread = Processor::information().getCurrentThread();
174  if (pThread)
175  {
176  Process *pProcess = pThread->getParent();
177  if (pProcess)
178  {
179  Subsystem *pSubsystem = pProcess->getSubsystem();
180  if (pSubsystem && !interruptState.kernelMode())
181  {
182  if (UNLIKELY(nIntNumber == 0))
183  {
184  pSubsystem->threadException(
185  pThread, Subsystem::DivideByZero);
186  return;
187  }
188  else if (UNLIKELY(nIntNumber == 6))
189  {
190  pSubsystem->threadException(
191  pThread, Subsystem::InvalidOpcode);
192  return;
193  }
194  else if (UNLIKELY(nIntNumber == 13))
195  {
196  pSubsystem->threadException(
197  pThread, Subsystem::GeneralProtectionFault);
198  return;
199  }
200  else if (UNLIKELY(nIntNumber == 16))
201  {
202  pSubsystem->threadException(pThread, Subsystem::FpuError);
203  return;
204  }
205  else if (UNLIKELY(nIntNumber == 19))
206  {
207  pSubsystem->threadException(
208  pThread, Subsystem::SpecialFpuError);
209  return;
210  }
211  }
212  }
213  }
214 #endif
215 
216  // unhandled interrupt, check for an exception (interrupts 0-31 inclusive
217  // are reserved, not for use by system programmers)
218  if (LIKELY(nIntNumber < 32 && nIntNumber != 1 && nIntNumber != 3))
219  {
220  // TODO:: Check for debugger initialisation.
221  // TODO: register dump, maybe a breakpoint so the deubbger can take
222  // over?
223  // TODO: Rework this
224  // for now just print out the exception name and number
225  static LargeStaticString e;
226  e.clear();
227  e.append("Exception #0x");
228  e.append(nIntNumber, 16);
229  e.append(": \"");
230  e.append(g_ExceptionNames[nIntNumber]);
231  e.append("\"");
232 
233 #ifdef THREADS
234  e.append(" CPU=");
235  e.append(Processor::id());
236  if (pThread)
237  {
238  Process *pParent = pThread->getParent();
239  if (pParent)
240  {
241  e.append(" PID=");
242  e.append(pParent->getId());
243  }
244  e.append(" TID=");
245  e.append(pThread->getId());
246  }
247 #endif
248 
249  if (nIntNumber == 14)
250  {
251  uint64_t cr2;
252  asm volatile("mov %%cr2, %%rax" : "=a"(cr2));
253  e.append(" at 0x");
254  e.append(cr2, 16, 16, '0');
255  e.append(", errorcode 0x");
256  e.append(interruptState.m_Errorcode, 16, 8, '0');
257  }
258 
259  if (nIntNumber == 13)
260  {
261  // GPF
262  if (interruptState.m_Errorcode)
263  {
264  e.append(" errorcode 0x");
265  e.append(interruptState.m_Errorcode, 16, 8, '0');
266  }
267  e.append(" RIP 0x");
268  e.append(interruptState.getInstructionPointer(), 16, 16, '0');
269  }
270 
271  if (nIntNumber == 8)
272  {
273  // On amd64, we actually have a functional InterruptState.
274  ERROR_NOLOCK("(double fault, system is very unhappy)");
275 
276  uint64_t cr2;
277  asm volatile("mov %%cr2, %%rax" : "=a"(cr2));
278  NOTICE_NOLOCK(
279  " -> #DF possibly caused by #PF at " << Hex << cr2 << ".");
280  }
281 
282  // Write the failure into the kernel log before launching the debugger.
283  ERROR(static_cast<const char *>(e));
284 
285 #if defined(DEBUGGER)
286  Debugger::instance().start(interruptState, e);
287 #else
288  panic(e);
289 #endif
290  }
291 }
292 
293 //
294 // Functions only usable in the kernel initialisation phase
295 //
296 
298 {
299  // Load the IDT
300  struct
301  {
302  uint16_t size;
303  uint64_t idt;
304  } PACKED idtr = {4095, reinterpret_cast<uintptr_t>(&m_Instance.m_IDT)};
305 
306  asm volatile("lidt %0" ::"m"(idtr));
307 }
308 
310  size_t nInterruptNumber, uintptr_t interruptHandler)
311 {
312  m_IDT[nInterruptNumber].offset0 = interruptHandler & 0xFFFF;
313  m_IDT[nInterruptNumber].selector = 0x08;
314  m_IDT[nInterruptNumber].ist = 0;
315  m_IDT[nInterruptNumber].flags = 0xEE /*0x8E*/;
316  m_IDT[nInterruptNumber].offset1 = (interruptHandler >> 16) & 0xFFFF;
317  m_IDT[nInterruptNumber].offset2 = (interruptHandler >> 32) & 0xFFFFFFFF;
318  m_IDT[nInterruptNumber].res = 0;
319 }
320 
321 void X64InterruptManager::setIst(size_t nInterruptNumber, size_t ist)
322 {
323  if (ist > 7)
324  return;
325  m_IDT[nInterruptNumber].ist = ist;
326 }
327 
329 {
330  // Initialise the pointers to the pHandler
331  for (size_t i = 0; i < 256; i++)
332  {
333  m_pHandler[i] = 0;
334 #ifdef DEBUGGER
335  m_pDbgHandler[i] = 0;
336 #endif
337  }
338 
339  // Initialise the IDT
340  extern uintptr_t interrupt_handler_array[];
341  for (size_t i = 0; i < 256; i++)
342  setInterruptGate(i, interrupt_handler_array[i]);
343 
344  // Set double fault handler IST entry.
345  setIst(8, 1);
346 }
348 {
349 }
size_t getId()
Definition: Process.h:108
static Debugger & instance()
Definition: Debugger.h:48
Handles interrupts and interrupt registrations from kernel components.
X64InterruptManager() INITIALISATION_ONLY
virtual void threadException(Thread *pThread, ExceptionType eType)
Definition: Subsystem.cc:35
virtual size_t getBreakpointInterruptNumber() PURE
static ProcessorInformation & information()
Definition: Processor.cc:45
static void interrupt(InterruptState &interruptState) USED
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
virtual size_t getDebugInterruptNumber() PURE
virtual void interrupt(size_t nInterruptNumber, InterruptState &state)=0
Definition: Log.h:136
virtual bool registerInterruptHandlerDebugger(size_t nInterruptNumber, InterruptHandler *pHandler)
void setInterruptGate(size_t nInterruptNumber, uintptr_t interruptHandler) INITIALISATION_ONLY
static void initialiseProcessor() INITIALISATION_ONLY
Process * getParent() const
Definition: Thread.h:181
static ProcessorId id()
Definition: Processor.cc:40
Definition: Thread.h:54
#define ERROR(text)
Definition: Log.h:82
Abstract base class for interrupt-handlers.
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
size_t getId()
Definition: Thread.h:210
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)
static InterruptManager & instance()
void setIst(size_t nInterruptNumber, size_t ist)
static X64InterruptManager & instance()