The Pedigree Project 0.1
hosted/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/compiler.h"
22#include "pedigree/kernel/process/PerProcessorScheduler.h"
23#include "pedigree/kernel/process/Process.h"
24#include "pedigree/kernel/process/TerminationDeferral.h"
25#include "pedigree/kernel/process/Thread.h"
26#include "pedigree/kernel/process/TimeTracker.h"
27#include "pedigree/kernel/processor/Processor.h"
28#include "pedigree/kernel/processor/ProcessorInformation.h"
29#include "pedigree/kernel/processor/SyscallHandler.h"
30#include "pedigree/kernel/processor/state.h"
31
33
34extern void system_reboot(Machine::ShutdownType type);
35
38}
39
41 Registration& registration, FastEntry entry) {
42 return registerHandler(Service, pHandler, registration, entry);
43}
44
45void HostedSyscallManager::syscall(SyscallState& syscallState) {
46 bool commitThreadExit = false;
47 bool exitCurrentProcess = false;
48 bool rebootSystem = false;
49 Machine::ShutdownType shutdownType = Machine::ShutdownType::Halt;
50 bool userReturnTerminal = false;
51 int processExitCode = 0;
52 Subsystem::ExitCause processExitCause = Subsystem::ExitCause::Normal;
53 {
54 Thread* entryThread = Processor::information().getCurrentThread();
55 const bool fromUserspace =
56 entryThread && entryThread->currentTimeAccountingMode() == CpuTimeMode::User;
57 TimeTracker tracker(0, fromUserspace);
58 if (fromUserspace) {
60 }
61
62 const size_t serviceNumber = syscallState.getSyscallService();
63#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
64 if (fromUserspace && serviceNumber == linuxCompat) {
65 tracker.attributeSyscall(syscallState.getSyscallNumber());
66 }
67#endif
68 bool handled = false;
69 PostSyscallAction action;
70 if (LIKELY(serviceNumber < serviceEnd)) {
71 HandlerLease handler;
72 if (m_Instance.acquireHandler(static_cast<Service_t>(serviceNumber), handler, action)) {
73 handled = true;
74 Thread* thread = Processor::information().getCurrentThread();
75 syscallState.setSyscallReturnValue(m_Instance.dispatchHandler(handler, syscallState));
76 syscallState.setSyscallErrno(thread->getErrno());
77 thread->setErrno(0);
78 }
79 }
80
81#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
82 if (handled && action.kind != NoPostSyscallAction &&
83 m_Instance.postSyscallHookHandled(action)) {
84 return;
85 }
86#endif
87 PerProcessorScheduler& scheduler = Processor::information().getScheduler();
88 if (!handled) {
89 if (fromUserspace) {
90 userReturnTerminal = scheduler.serviceUserReturnWork(syscallState);
91 }
92 } else {
93 const bool directUserTransition =
94 action.kind == ReturnFromEvent || action.kind == PopEventState ||
95 action.kind == RestoreProcessorState || action.kind == JumpToUserspace;
96 if (directUserTransition) {
97 userReturnTerminal = scheduler.serviceProcessStopAtUserReturn(
98 PerProcessorScheduler::ProcessStopGateMode::DirectUserTransition);
99 Thread* current = Processor::information().getCurrentThread();
100 if (current && current->getUnwindState() != Thread::Continue) {
101 userReturnTerminal = true;
102 }
103 }
104
105 switch (action.kind) {
106 case TerminateCurrentThread:
107 commitThreadExit = true;
108 break;
109 case ExitCurrentProcess:
110 exitCurrentProcess = true;
111 processExitCode = static_cast<int>(action.value);
112 break;
113 case ReturnFromEvent:
114 if (userReturnTerminal) {
115 break;
116 }
117 tracker.finishInKernel();
118 scheduler.eventHandlerReturned();
119 break;
120 case PopEventState:
121 if (!userReturnTerminal) {
122 Processor::information().getCurrentThread()->abandonCurrentState(false);
123 }
124 break;
125 case RestoreProcessorState:
126 if (!userReturnTerminal) {
127 FATAL("Processor-state restoration requested on hosted.");
128 }
129 break;
130 case JumpToUserspace:
131 if (userReturnTerminal) {
132 break;
133 }
134 tracker.finish();
136 Processor::information().getCurrentThread()->abandonAllStates();
137 Processor::jumpUser(nullptr, action.state.getInstructionPointer(),
138 action.state.getStackPointer());
139 case RebootSystem:
140 rebootSystem = true;
141 shutdownType = static_cast<Machine::ShutdownType>(action.value);
142 break;
143 case NoPostSyscallAction:
144 if (fromUserspace) {
145 Thread* current = Processor::information().getCurrentThread();
146 if (current && current->canSkipUserReturnWork()) {
147 break;
148 }
149 }
150 if (fromUserspace) {
151 userReturnTerminal = scheduler.serviceUserReturnWork(syscallState);
152 }
153 break;
154 }
155 }
156
157 if (!exitCurrentProcess && !rebootSystem) {
158 Thread* pThread = Processor::information().getCurrentThread();
159 const Thread::UnwindType unwindState = pThread->getUnwindState();
160 if (userReturnTerminal || unwindState != Thread::Continue) {
161 if (unwindState == Thread::TerminateThread) {
162 commitThreadExit = true;
163 }
164 if (unwindState == Thread::Exit) {
165 NOTICE("Unwind state exit at syscall return");
166 exitCurrentProcess = true;
167 const Thread::DeferredProcessExit request = pThread->takeDeferredProcessExit();
168 processExitCode = request.code;
169 processExitCause = request.cause;
170 }
171 }
172 }
173 }
174
175 if (rebootSystem) {
177 Processor::information().getCurrentThread()->abandonAllStates();
179 system_reboot(shutdownType);
180 return;
181 }
182 if (exitCurrentProcess) {
183 Processor::information().getCurrentThread()->getParent()->getSubsystem()->exit(
184 processExitCode, processExitCause);
185 }
186 if (commitThreadExit) {
187 Processor::information().getScheduler().commitCurrentThreadExit();
188 }
189}
190
191uintptr_t HostedSyscallManager::syscall(Service_t service, uintptr_t function, uintptr_t p1,
192 uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5) {
193 HostedSyscallState state = {};
194 state.service = service;
195 state.number = function;
196 state.p1 = p1;
197 state.p2 = p2;
198 state.p3 = p3;
199 state.p4 = p4;
200 state.p5 = p5;
201 syscall(state);
202 return state.result;
203}
204
205//
206// Functions only usable in the kernel initialisation phase
207//
208
210
212
static void initialiseProcessor() INITIALISATION_ONLY
uintptr_t syscall(Service_t service, uintptr_t function, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5)
virtual bool registerSyscallHandler(Service_t Service, SyscallHandler *pHandler, Registration &registration, FastEntry entry=nullptr)
HostedSyscallManager() INITIALISATION_ONLY
MUST_USE_RESULT bool serviceProcessStopAtUserReturn(ProcessStopGateMode mode=ProcessStopGateMode::StopOnly)
MUST_USE_RESULT bool serviceUserReturnWork(InterruptState &state, UserReturnFrame::Origin origin=UserReturnFrame::Origin::Interrupt, bool diagnosticSample=false)
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
static ProcessorInformation & information()
static void setInterrupts(bool bEnable)
static EXPORTED_PUBLIC SyscallManager & instance()
void setErrno(size_t err)
Definition Thread.h:482
CpuTimeMode currentTimeAccountingMode() const
Definition Thread.cc:471
UnwindType
Definition Thread.h:516
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:517
@ TerminateThread
Exit only this thread during Process exit.
Definition Thread.h:519
@ Exit
Exit the owning process at the next safe boundary.
Definition Thread.h:518
size_t getErrno()
Definition Thread.h:477
UnwindType getUnwindState()
Definition Thread.h:535
DeferredProcessExit takeDeferredProcessExit()
Definition Thread.cc:3618
void attributeSyscall(size_t rawNumber)
void finishInKernel()
void finish()