The Pedigree Project  0.1
hosted/Processor.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 "pedigree/kernel/processor/Processor.h"
21 #include "InterruptManager.h"
22 #include "PhysicalMemoryManager.h"
23 #include "SyscallManager.h"
24 #include "VirtualAddressSpace.h"
25 #include "pedigree/kernel/process/Scheduler.h"
26 #include "pedigree/kernel/process/Thread.h"
27 #include "pedigree/kernel/process/initialiseMultitasking.h"
28 #include "pedigree/kernel/processor/PageFaultHandler.h"
29 
30 namespace __pedigree_hosted
31 {
32 };
33 using namespace __pedigree_hosted;
34 
35 #include <setjmp.h>
36 #include <signal.h>
37 
38 bool Processor::m_bInterrupts;
39 
40 typedef void (*jump_func_t)(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
41 
43 {
45 }
46 
48 {
53  setInterrupts(false);
54  m_Initialised = 1;
55 }
56 
58 {
59  initialiseMultitasking();
60  m_Initialised = 2;
61 }
62 
64 {
65 }
66 
68 {
69  str.clear();
70  str.append("Hosted Processor");
71 }
72 
74 {
75  return reinterpret_cast<uintptr_t>(__builtin_return_address(0));
76 }
77 
79 {
80  return 0;
81 }
82 
84 {
85  return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
86 }
87 
88 bool Processor::saveState(SchedulerState &state)
89 {
90  ERROR("Processor::saveState is NOT safe on HOSTED builds.");
91 
92  sigjmp_buf _state;
93  if (sigsetjmp(_state, 0) == 1)
94  return true;
95 
96  MemoryCopy(state.state, _state, sizeof(_state));
97  return false;
98 }
99 
100 void Processor::restoreState(SchedulerState &state, volatile uintptr_t *pLock)
101 {
102  NOTICE("hallo");
103  sigjmp_buf _state;
104  if (pLock)
105  *pLock = 1;
106  MemoryCopy(_state, state.state, sizeof(_state));
107  siglongjmp(_state, 1);
108  // Does not return.
109 }
110 
112  volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1,
113  uintptr_t p2, uintptr_t p3, uintptr_t p4)
114 {
115  // Same thing as jumping to kernel space.
116  jumpKernel(pLock, address, stack, p1, p2, p3, p4);
117 }
118 
119 #ifdef SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH
120 void Processor::switchState(
121  bool bInterrupts, SchedulerState &a, SchedulerState &b,
122  volatile uintptr_t *pLock)
123 {
124  sigjmp_buf _state;
125  if (sigsetjmp(_state, 0) == 1)
126  {
127  if (bInterrupts)
129  return;
130  }
131 
132  MemoryCopy(a.state, _state, sizeof(_state));
133  restoreState(b, pLock);
134 }
135 
136 void Processor::switchState(
137  bool bInterrupts, SchedulerState &a, SyscallState &b,
138  volatile uintptr_t *pLock)
139 {
140  sigjmp_buf _state;
141  if (sigsetjmp(_state, 0) == 1)
142  {
143  if (bInterrupts)
145  return;
146  }
147 
148  MemoryCopy(a.state, _state, sizeof(_state));
149  Processor::restoreState(b, pLock);
150 }
151 
152 void Processor::saveAndJumpKernel(
153  bool bInterrupts, SchedulerState &s, volatile uintptr_t *pLock,
154  uintptr_t address, uintptr_t stack, uintptr_t p1, uintptr_t p2,
155  uintptr_t p3, uintptr_t p4)
156 {
157  sigjmp_buf _state;
158  if (sigsetjmp(_state, 0) == 1)
159  {
160  if (bInterrupts)
162  return;
163  }
164 
165  MemoryCopy(s.state, _state, sizeof(_state));
166  Processor::jumpKernel(pLock, address, stack, p1, p2, p3, p4);
167 }
168 
169 void Processor::saveAndJumpUser(
170  bool bInterrupts, SchedulerState &s, volatile uintptr_t *pLock,
171  uintptr_t address, uintptr_t stack, uintptr_t p1, uintptr_t p2,
172  uintptr_t p3, uintptr_t p4)
173 {
174  Processor::saveAndJumpKernel(
175  bInterrupts, s, pLock, address, stack, p1, p2, p3, p4);
176 }
177 #endif // SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH
178 
180 {
181  ProcessorInformation &info = Processor::information();
182  if (&info.getVirtualAddressSpace() != &AddressSpace)
183  {
184  info.setVirtualAddressSpace(AddressSpace);
186  info.getVirtualAddressSpace(), AddressSpace);
187  }
188 }
189 
190 void Processor::setTlsBase(uintptr_t newBase)
191 {
192 }
193 
195 {
196  return 0;
197 }
198 
200  size_t nBpNumber, DebugFlags::FaultType &nFaultType, size_t &nLength,
201  bool &bEnabled)
202 {
203  // no-op on hosted
204  return 0;
205 }
206 
208  size_t nBpNumber, uintptr_t nLinearAddress,
209  DebugFlags::FaultType nFaultType, size_t nLength)
210 {
211  // no-op on hosted
212 }
213 
214 void Processor::disableDebugBreakpoint(size_t nBpNumber)
215 {
216  // no-op on hosted
217 }
218 
219 void Processor::setInterrupts(bool bEnable)
220 {
221  // Block signals to toggle "interrupts".
222  sigset_t set;
223  if (bEnable)
224  sigemptyset(&set);
225  else
226  {
227  sigemptyset(&set);
228 
229  // Only SIGUSR1 and SIGUSR2 are true "interrupts". The rest are all
230  // more like exceptions, which we are okay with triggering even if
231  // bEnable is false.
232  sigaddset(&set, SIGUSR1);
233  sigaddset(&set, SIGUSR2);
234  }
235 
236  // We must mark interrupts enabled before we unmask signals, as any pending
237  // signals may trigger immediately (and will cause problems if interrupts
238  // are marked as disabled)
239  if (bEnable)
240  {
241  m_bInterrupts = true;
242  }
243 
244  int r = sigprocmask(SIG_SETMASK, &set, 0);
245  if (r != 0)
246  {
247  ERROR("Processor::setInterrupts failed to set new mask");
248  }
249 
250  // We can only mark interrupts disabled after masking signals as during the
251  // mask operation signals may still come in. Setting the flag here means
252  // those signals are handled correctly.
253  if (!bEnable)
254  {
255  m_bInterrupts = false;
256  }
257 }
258 
260 {
261  return m_bInterrupts;
262 }
263 
264 void Processor::setSingleStep(bool bEnable, InterruptState &state)
265 {
266  // no-op on hosted
267 }
268 
269 void Processor::invalidate(void *pAddress)
270 {
271  // no-op on hosted
272 }
273 
274 namespace __processor_cc_hosted
275 {
276 #include <sched.h>
277 #include <signal.h>
278 #include <stdlib.h>
279 #include <unistd.h>
280 } // namespace __processor_cc_hosted
281 
282 using namespace __processor_cc_hosted;
283 
284 void Processor::_breakpoint()
285 {
286  sigset_t set;
287  sigset_t oset;
288  sigemptyset(&set);
289  sigemptyset(&oset);
290  sigaddset(&set, SIGTRAP);
291  sigprocmask(SIG_UNBLOCK, &set, &oset);
292  raise(SIGTRAP);
293  sigprocmask(SIG_SETMASK, &oset, 0);
294 }
295 
296 void Processor::_reset()
297 {
298  // Just exit.
299  exit(0);
300 }
301 
302 void Processor::_haltUntilInterrupt()
303 {
304  bool bOld = m_bInterrupts;
306  sigset_t set;
307  sigemptyset(&set);
308  sigsuspend(&set);
310 }
311 
313 {
314  Processor::_breakpoint();
315 }
316 
317 void Processor::halt()
318 {
319  // Abnormal exit.
320  __builtin_trap();
321 }
322 
323 void Processor::pause()
324 {
325  asm volatile("pause");
326 }
327 
328 void Processor::reset()
329 {
330  Processor::_reset();
331 }
332 
334 {
335  Processor::_haltUntilInterrupt();
336 }
Bootstrap structure passed to the kernel entry point.
static void restoreState(SchedulerState &state, volatile uintptr_t *pLock=0) NORETURN
static bool getInterrupts()
static void initialiseProcessor() INITIALISATION_ONLY
static void setTlsBase(uintptr_t newBase)
static void jumpKernel(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
static uintptr_t getDebugBreakpoint(size_t nBpNumber, DebugFlags::FaultType &nFaultType, size_t &nLength, bool &bEnabled)
static void initialise2(const BootstrapStruct_t &Info) INITIALISATION_ONLY
second/last stage in the initialisation of the processor-specific interface
static void initialiseProcessor() INITIALISATION_ONLY
static void pause()
static void initialisationDone()
static ProcessorInformation & information()
Definition: Processor.cc:45
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static void reset()
static void enableDebugBreakpoint(size_t nBpNumber, uintptr_t nLinearAddress, DebugFlags::FaultType nFaultType, size_t nLength)
static PageFaultHandler & instance()
static void setSingleStep(bool bEnable, InterruptState &state)
static void initialise1(const BootstrapStruct_t &Info) INITIALISATION_ONLY
first stage in the initialisation of the processor-specific interface
#define NOTICE(text)
Definition: Log.h:74
static bool saveState(SchedulerState &state)
static void jumpUser(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
void initialise(const BootstrapStruct_t &Info) INITIALISATION_ONLY
static void disableDebugBreakpoint(size_t nBpNumber)
static void haltUntilInterrupt()
static void deinitialise()
static void setInterrupts(bool bEnable)
static void identify(HugeStaticString &str)
static void halt()
static void breakpoint()
#define ERROR(text)
Definition: Log.h:82
static uintptr_t getStackPointer()
static size_t getDebugBreakpointCount()
static uintptr_t getInstructionPointer()
static void switchAddressSpace(VirtualAddressSpace &oldSpace, VirtualAddressSpace &newSpace)
static uintptr_t getBasePointer()
static void invalidate(void *pAddress)