The Pedigree Project  0.1
x64/SyscallManager.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 "SyscallManager.h"
21 #include "pedigree/kernel/LockGuard.h"
22 #include "pedigree/kernel/Log.h"
23 #include "pedigree/kernel/Subsystem.h"
24 #include "pedigree/kernel/compiler.h"
25 #include "pedigree/kernel/process/Process.h"
26 #include "pedigree/kernel/process/Thread.h"
27 #include "pedigree/kernel/process/TimeTracker.h"
28 #include "pedigree/kernel/processor/Processor.h"
29 #include "pedigree/kernel/processor/ProcessorInformation.h"
30 #include "pedigree/kernel/processor/SyscallHandler.h"
31 #include "pedigree/kernel/processor/state.h"
32 
34 
35 #define TIME_SYSCALLS 0
36 
38 {
40 }
41 
43  Service_t Service, SyscallHandler *pHandler)
44 {
45  // Lock the class until the end of the function
46  LockGuard<Spinlock> lock(m_Lock);
47 
48  if (UNLIKELY(Service >= serviceEnd))
49  return false;
50  if (UNLIKELY(pHandler != 0 && m_pHandler[Service] != 0))
51  return false;
52  if (UNLIKELY(pHandler == 0 && m_pHandler[Service] == 0))
53  return false;
54 
55  m_pHandler[Service] = pHandler;
56  return true;
57 }
58 
59 void X64SyscallManager::syscall(SyscallState &syscallState)
60 {
61  SyscallHandler *pHandler;
62  TimeTracker tracker(0, true);
63 #if TIME_SYSCALLS
64  Process *pProcess =
65  Processor::information().getCurrentThread()->getParent();
66  Time::Stopwatch syscallTimer(true);
67  size_t syscallNumber = syscallState.getSyscallNumber();
68 #endif
69 
70  // Enable IRQs - stack switching and such are done now and it's now safe to
71  // start processing interrupts elsewhere.
73 
74  size_t serviceNumber = syscallState.getSyscallService();
75 
76  if (UNLIKELY(serviceNumber >= serviceEnd))
77  {
78  // TODO: We should return an error here
79  return;
80  }
81 
82  // Get the syscall handler
83  {
84  LockGuard<Spinlock> lock(m_Instance.m_Lock);
85  pHandler = m_Instance.m_pHandler[serviceNumber];
86  }
87 
88  if (LIKELY(pHandler != 0))
89  {
90  uint64_t result = pHandler->syscall(syscallState);
91  uint64_t errno =
92  Processor::information().getCurrentThread()->getErrno();
96  if (serviceNumber == linuxCompat)
97  {
98  if (errno != 0)
99  {
100  syscallState.setSyscallReturnValue(-errno);
101  }
102  else
103  {
104  syscallState.setSyscallReturnValue(result);
105  }
106  }
107  else
108  {
109  syscallState.setSyscallReturnValue(result);
110  syscallState.setSyscallErrno(errno);
111  }
112  // Reset error number now that we've extracted it.
113  Processor::information().getCurrentThread()->setErrno(0);
114 
115  if (Processor::information().getCurrentThread()->getUnwindState() ==
116  Thread::Exit)
117  {
118  NOTICE("Unwind state exit, in interrupt handler");
120  .getCurrentThread()
121  ->getParent()
122  ->getSubsystem()
123  ->exit(0);
124  }
125  }
126 
127  // Make sure we come back out with interrupts enabled at all times.
128  if ((syscallState.m_RFlagsR11 & 0x200) != 0x200)
129  {
130  syscallState.m_RFlagsR11 |= 0x200;
131  }
132 
133 #if TIME_SYSCALLS
134  syscallTimer.stop();
135  Time::Timestamp value = syscallTimer.value();
136  NOTICE(
137  "SYSCALL pid=" << Dec << pProcess->getId()
138  << " service=" << serviceNumber
139  << " num=" << syscallNumber << " ns=" << value << Hex);
140 #endif
141 }
142 
144  Service_t service, uintptr_t function, uintptr_t p1, uintptr_t p2,
145  uintptr_t p3, uintptr_t p4, uintptr_t p5)
146 {
147  uint64_t rax = (static_cast<uint64_t>(service) << 16) | function;
148  uint64_t ret;
149  asm volatile("mov %6, %%r8; \
150  syscall"
151  : "=a"(ret)
152  : "0"(rax), "b"(p1), "d"(p2), "S"(p3), "D"(p4), "m"(p5)
153  : "rcx", "r11");
154  return ret;
155 }
156 
157 //
158 // Functions only usable in the kernel initialisation phase
159 //
160 
161 extern "C" void syscall_handler();
163 {
164  // Enable SCE (= System Call Extensions)
165  // Set IA32_EFER/EFER.SCE
167  0xC0000080, Processor::readMachineSpecificRegister(0xC0000080) |
168  0x0000000000000001);
169 
170  // Setup SYSCALL/SYSRET
171  // Set the IA32_STAR/STAR (CS/SS segment selectors)
172  Processor::writeMachineSpecificRegister(0xC0000081, 0x001B000800000000LL);
173  // Set the IA32_LSTAR/LSTAR (RIP)
175  0xC0000082, reinterpret_cast<uint64_t>(syscall_handler));
176  // Set the IA32_FMASK/SF_MASK (RFLAGS mask, RFLAGS.IF,TF cleared after
177  // syscall)
178  Processor::writeMachineSpecificRegister(0xC0000084, 0x0000000000000300LL);
179 }
180 
182 {
183  // Initialise the pointers to the handler
184  for (size_t i = 0; i < serviceEnd; i++)
185  m_pHandler[i] = 0;
186 }
188 {
189 }
static uint64_t readMachineSpecificRegister(uint32_t index)
size_t getId()
Definition: Process.h:108
static EXPORTED_PUBLIC SyscallManager & instance()
virtual bool registerSyscallHandler(Service_t Service, SyscallHandler *pHandler)
X64SyscallManager() INITIALISATION_ONLY
virtual uintptr_t syscall(SyscallState &State)=0
static ProcessorInformation & information()
Definition: Processor.cc:45
Timestamp value()
Read the stopwatch value in nanoseconds.
Definition: Stopwatch.cc:62
static void writeMachineSpecificRegister(uint32_t index, uint64_t value)
void stop()
Stop the stopwatch if it is not already stopped.
Definition: Stopwatch.cc:47
SyscallHandler * m_pHandler[serviceEnd]
#define NOTICE(text)
Definition: Log.h:74
static X64SyscallManager & instance()
Definition: Log.h:136
uintptr_t syscall(Service_t service, uintptr_t function, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5)
static void setInterrupts(bool bEnable)
static void initialiseProcessor() INITIALISATION_ONLY
Definition: Log.h:138
(b) below.
Definition: Thread.h:245