1#include "SyscallManager.h"
2#include "pedigree/kernel/Log.h"
3#include "pedigree/kernel/Subsystem.h"
4#include "pedigree/kernel/process/PerProcessorScheduler.h"
5#include "pedigree/kernel/process/Process.h"
6#include "pedigree/kernel/process/Thread.h"
7#include "pedigree/kernel/process/TimeTracker.h"
8#include "pedigree/kernel/processor/Processor.h"
9#include "pedigree/kernel/processor/ProcessorInformation.h"
10#include "pedigree/kernel/processor/state.h"
11#include "pedigree/kernel/syscallError.h"
15extern void system_reboot(Machine::ShutdownType type);
18class SyscallReturnScope {
20 explicit SyscallReturnScope(
const SyscallState* original)
21 : m_Thread(
Processor::information().getCurrentThread()),
22 m_StateLevel(m_Thread->getStateLevel()),
23 m_Previous(m_Thread->getOriginalSyscallState()),
24 m_Discard(&restore, this) {
25 m_Thread->setOriginalSyscallState(original);
28 ~SyscallReturnScope() {
33 static void restore(
void* context) {
34 auto* scope =
static_cast<SyscallReturnScope*
>(context);
35 if (scope->m_Thread) {
36 scope->m_Thread->restoreDeferredSignalMask(scope->m_StateLevel);
37 scope->m_Thread->setOriginalSyscallState(scope->m_Previous);
38 scope->m_Thread =
nullptr;
44 const SyscallState* m_Previous;
50 return Arm64SyscallManager::instance();
55 return registerHandler(service, handler, registration, entry);
58void Arm64SyscallManager::handle(SyscallState& state) {
61 const SyscallState original = state;
62 bool commitThreadExit =
false;
63 bool exitCurrentProcess =
false;
64 bool rebootSystem =
false;
65 bool userReturnTerminal =
false;
66 bool interruptedWithoutProgress =
false;
67 int processExitCode = 0;
69 Machine::ShutdownType shutdownType = Machine::ShutdownType::Halt;
72 TimeTracker tracker(
nullptr,
true,
true, syscallThread);
74 const size_t service = state.getSyscallService();
75#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
76 if (service == linuxCompat) {
77 tracker.attributeSyscall(state.getSyscallNumber());
81 PostSyscallAction action;
82 if (service < serviceEnd) {
84 if (manager.acquireHandler(
static_cast<Service_t
>(service), handler, action)) {
86 uintptr_t result = manager.dispatchHandler(handler, state);
87 uintptr_t error = syscallThread->
getErrno();
88 interruptedWithoutProgress =
89 service == linuxCompat && result == uintptr_t(-1) && error == Error::Interrupted;
90 if (service == linuxCompat) {
91 state.setSyscallReturnValue(error ? -error : result);
93 state.setSyscallReturnValue(result);
94 state.setSyscallErrno(error);
102 state.setSyscallReturnValue(-
static_cast<uintptr_t
>(Error::Unimplemented));
105 const bool directTransition =
106 action.kind == ReturnFromEvent || action.kind == PopEventState ||
107 action.kind == RestoreProcessorState || action.kind == JumpToUserspace;
108 if (directTransition) {
110 PerProcessorScheduler::ProcessStopGateMode::DirectUserTransition);
112 userReturnTerminal =
true;
116 switch (action.kind) {
117 case TerminateCurrentThread:
118 commitThreadExit =
true;
120 case ExitCurrentProcess:
121 exitCurrentProcess =
true;
122 processExitCode =
static_cast<int>(action.value);
124 case ReturnFromEvent:
125 if (!userReturnTerminal) {
126 tracker.finishInKernel();
131 if (!userReturnTerminal) {
135 case RestoreProcessorState:
136 if (!userReturnTerminal) {
137 for (
size_t i = 0; i < 31; ++i) {
138 state.x[i] = action.state.x[i];
140 state.sp = action.state.sp;
141 state.pc = action.state.pc;
142 state.pstate = action.state.pstate;
147 case JumpToUserspace:
148 if (!userReturnTerminal) {
149 tracker.finishInKernel();
151 for (
size_t i = 0; i < 31; ++i) {
154 state.pc = action.state.getInstructionPointer();
155 state.sp = action.state.getStackPointer();
164 shutdownType =
static_cast<Machine::ShutdownType
>(action.value);
166 case NoPostSyscallAction:
167 if (!syscallThread->canSkipUserReturnWork() || interruptedWithoutProgress) {
168 SyscallReturnScope returnScope(interruptedWithoutProgress ? &original : nullptr);
175 if (!exitCurrentProcess && !rebootSystem) {
179 commitThreadExit =
true;
181 exitCurrentProcess =
true;
183 processExitCode = request.code;
184 processExitCause = request.cause;
188 tracker.finishInKernel();
195 system_reboot(shutdownType);
197 if (exitCurrentProcess) {
198 syscallThread->
getParent()->getSubsystem()->
exit(processExitCode, processExitCause);
200 if (commitThreadExit) {
208 FATAL_NOLOCK(
"Terminal affinity return unexpectedly returned");
216 FATAL_NOLOCK(
"Terminal user return unexpectedly returned");
224 uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5) {
225 register uintptr_t x0
asm(
"x0") = p1;
226 register uintptr_t x1
asm(
"x1") = p2;
227 register uintptr_t x2
asm(
"x2") = p3;
228 register uintptr_t x3
asm(
"x3") = p4;
229 register uintptr_t x4
asm(
"x4") = p5;
230 register uintptr_t x8
asm(
"x8") = (
static_cast<uintptr_t
>(service) << 16) | function;
231 asm volatile(
"svc #1" :
"+r"(x0) :
"r"(x1),
"r"(x2),
"r"(x3),
"r"(x4),
"r"(x8) :
"memory");
uintptr_t syscall(Service_t service, uintptr_t function, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0, uintptr_t p5=0) override
bool registerSyscallHandler(Service_t service, SyscallHandler *handler, Registration ®istration, FastEntry entry=nullptr) override
void eventHandlerReturned() NORETURN
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 ProcessorInformation & information()
static void setInterrupts(bool bEnable)
virtual void exit(int code, ExitCause cause=ExitCause::Normal)=0
static EXPORTED_PUBLIC SyscallManager & instance()
void setErrno(size_t err)
@ Continue
No unwind necessary, carry on as normal.
@ TerminateThread
Exit only this thread during Process exit.
@ Exit
Exit the owning process at the next safe boundary.
UnwindType getUnwindState()
ALWAYS_INLINE void transitionTimeAtInterruptReturn(CpuTimeMode from, CpuTimeMode to)
Process * getParent() const
DeferredProcessExit takeDeferredProcessExit()
AffinityResult completeAffinityAtSafePoint(bool *waited=nullptr)
void abandonCurrentState(bool clean=false)