The Pedigree Project  0.1
hosted/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/utilities/StaticString.h"
24 #if defined(DEBUGGER)
25 #include "pedigree/kernel/debugger/Debugger.h"
26 #endif
27 
28 #ifdef THREADS
29 #include "pedigree/kernel/Subsystem.h"
30 #include "pedigree/kernel/process/Process.h"
31 #endif
32 
33 namespace __pedigree_hosted
34 {
35 };
36 using namespace __pedigree_hosted;
37 
38 #include <errno.h>
39 #include <signal.h>
40 #include <stdio.h>
41 
43 {
44 #include <string.h>
45 }
46 
48 
50 {
52 }
53 
55  size_t nInterruptNumber, InterruptHandler *pHandler)
56 {
57  // Lock the class until the end of the function
58  LockGuard<Spinlock> lock(m_Lock);
59 
60  // Sanity checks
61  if (UNLIKELY(nInterruptNumber >= MAX_SIGNAL))
62  return false;
63  if (UNLIKELY(pHandler != 0 && m_pHandler[nInterruptNumber] != 0))
64  return false;
65  if (UNLIKELY(pHandler == 0 && m_pHandler[nInterruptNumber] == 0))
66  return false;
67 
68  // Change the pHandler
69  m_pHandler[nInterruptNumber] = pHandler;
70 
71  return true;
72 }
73 
74 #if defined(DEBUGGER)
75 
77  size_t nInterruptNumber, InterruptHandler *pHandler)
78 {
79  // Lock the class until the end of the function
80  LockGuard<Spinlock> lock(m_Lock);
81 
82  // Sanity checks
83  if (UNLIKELY(nInterruptNumber >= MAX_SIGNAL))
84  return false;
85  if (UNLIKELY(pHandler != 0 && m_pDbgHandler[nInterruptNumber] != 0))
86  return false;
87  if (UNLIKELY(pHandler == 0 && m_pDbgHandler[nInterruptNumber] == 0))
88  return false;
89 
90  // Change the pHandler
91  m_pDbgHandler[nInterruptNumber] = pHandler;
92 
93  return true;
94 }
96 {
97  return SIGTRAP;
98 }
100 {
101  return SIGTRAP;
102 }
103 
104 #endif
105 
106 void HostedInterruptManager::interrupt(InterruptState &interruptState)
107 {
108  size_t nIntNumber = interruptState.getInterruptNumber();
109 
110 #if defined(DEBUGGER)
111  {
112  InterruptHandler *pHandler;
113 
114  // Get the debugger handler
115  {
116  LockGuard<Spinlock> lockGuard(m_Instance.m_Lock);
117  pHandler = m_Instance.m_pDbgHandler[nIntNumber];
118  }
119 
120  // Call the kernel debugger's handler, if any
121  if (pHandler != 0)
122  {
123  pHandler->interrupt(nIntNumber, interruptState);
124  }
125  }
126 #endif
127 
128  InterruptHandler *pHandler;
129 
130  // Get the interrupt handler
131  {
132  LockGuard<Spinlock> lockGuard(m_Instance.m_Lock);
133  pHandler = m_Instance.m_pHandler[nIntNumber];
134  }
135 
136  // Call the normal interrupt handler, if any
137  if (LIKELY(pHandler != 0))
138  {
139  pHandler->interrupt(nIntNumber, interruptState);
140  return;
141  }
142 
143  if (UNLIKELY(nIntNumber == SIGINT || nIntNumber == SIGTERM))
144  {
145  // Shut down (uncleanly for now).
148  panic("shutdown failed");
149  }
150 
151 // Were we running in the kernel, or user space?
152 // User space processes have a subsystem, kernel ones do not.
153 #ifdef THREADS
154  Thread *pThread = Processor::information().getCurrentThread();
155  Process *pProcess = pThread->getParent();
156  Subsystem *pSubsystem = pProcess->getSubsystem();
157  if (pSubsystem)
158  {
159  if (UNLIKELY(nIntNumber == SIGILL))
160  {
161  pSubsystem->threadException(pThread, Subsystem::InvalidOpcode);
162  return;
163  }
164  else if (UNLIKELY(nIntNumber == SIGFPE))
165  {
166  pSubsystem->threadException(pThread, Subsystem::FpuError);
167  return;
168  }
169  }
170 #endif
171 
172  // unhandled interrupt, check for an exception
173  if (LIKELY(nIntNumber != SIGTRAP))
174  {
175  // TODO:: Check for debugger initialisation.
176  // TODO: register dump, maybe a breakpoint so the deubbger can take
177  // over?
178  // TODO: Rework this
179  // for now just print out the exception name and number
180  static LargeStaticString e;
181  e.clear();
182  e.append("Signal #0x");
183  e.append(nIntNumber, 16);
184 #if defined(DEBUGGER)
185  Debugger::instance().start(interruptState, e);
186 #else
187  panic(e);
188 #endif
189  }
190 }
191 
192 //
193 // Functions only usable in the kernel initialisation phase
194 //
195 
196 static void handler(int which, siginfo_t *info, void *ptr)
197 {
198  HostedInterruptManager::instance().signalShim(which, info, ptr);
199 }
200 
201 void HostedInterruptManager::signalShim(int which, void *siginfo, void *meta)
202 {
204  {
205  if (which == SIGUSR1 || which == SIGUSR2)
206  {
207  FATAL_NOLOCK("interrupts disabled but interrupts are firing");
208  }
209  }
210 
211  siginfo_t *info = reinterpret_cast<siginfo_t *>(siginfo);
212 
213  InterruptState state;
214  state.which = which;
215  state.extra = reinterpret_cast<uint64_t>(info);
216  state.state = reinterpret_cast<uint64_t>(info->si_value.sival_ptr);
217  state.meta = reinterpret_cast<uint64_t>(meta);
218  interrupt(state);
219 
220  // Update return signal mask.
221  ucontext_t *ctx = reinterpret_cast<ucontext_t *>(meta);
222  sigprocmask(0, 0, &ctx->uc_sigmask);
223 }
224 
226 {
227  // Set up our handler for every signal we want to trap.
228  for (int i = 1; i < MAX_SIGNAL; ++i)
229  {
230  struct sigaction act;
231  ByteSet(&act, 0, sizeof(act));
232  act.sa_sigaction = handler;
233  sigemptyset(&act.sa_mask);
234  act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
235 
236  sigaction(i, &act, 0);
237  }
238 }
239 
241 {
242  // Initialise the pointers to the pHandler
243  for (size_t i = 0; i < MAX_SIGNAL; i++)
244  {
245  m_pHandler[i] = 0;
246 #ifdef DEBUGGER
247  m_pDbgHandler[i] = 0;
248 #endif
249  }
250 }
251 
253 {
254 }
static bool getInterrupts()
void signalShim(int which, void *siginfo, void *meta)
static void initialiseProcessor() INITIALISATION_ONLY
static Debugger & instance()
Definition: Debugger.h:48
Handles interrupts and interrupt registrations from kernel components.
virtual void threadException(Thread *pThread, ExceptionType eType)
Definition: Subsystem.cc:35
static ProcessorInformation & information()
Definition: Processor.cc:45
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)
static void reset()
virtual bool registerInterruptHandlerDebugger(size_t nInterruptNumber, InterruptHandler *pHandler)
virtual size_t getDebugInterruptNumber() PURE
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
virtual size_t getBreakpointInterruptNumber() PURE
virtual void interrupt(size_t nInterruptNumber, InterruptState &state)=0
Process * getParent() const
Definition: Thread.h:181
Definition: Thread.h:54
Abstract base class for interrupt-handlers.
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
static InterruptManager & instance()
static void interrupt(InterruptState &interruptState)
HostedInterruptManager() INITIALISATION_ONLY