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 Armv7SyscallManager::instance();
55 return registerHandler(service, handler, registration, entry);
58void Armv7SyscallManager::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 < 13; ++i) {
138 state.r[i] = action.state.r[i];
140 state.sp = action.state.sp;
141 state.pc = action.state.pc;
142 state.cpsr = action.state.cpsr;
147 case JumpToUserspace:
148 if (!userReturnTerminal) {
149 tracker.finishInKernel();
151 for (
size_t i = 0; i < 13; ++i) {
154 const uintptr_t entry = action.state.getInstructionPointer();
155 state.pc = entry & ~uintptr_t(1);
156 state.sp = action.state.getStackPointer();
157 state.cpsr = 0x10 | ((entry & 1) ? 0x20 : 0);
158 state.faultStatus = 0;
166 shutdownType =
static_cast<Machine::ShutdownType
>(action.value);
168 case NoPostSyscallAction:
169 if (!syscallThread->canSkipUserReturnWork() || interruptedWithoutProgress) {
170 SyscallReturnScope returnScope(interruptedWithoutProgress ? &original : nullptr);
177 if (!exitCurrentProcess && !rebootSystem) {
181 commitThreadExit =
true;
183 exitCurrentProcess =
true;
185 processExitCode = request.code;
186 processExitCause = request.cause;
190 tracker.finishInKernel();
197 system_reboot(shutdownType);
199 if (exitCurrentProcess) {
200 syscallThread->
getParent()->getSubsystem()->
exit(processExitCode, processExitCause);
202 if (commitThreadExit) {
210 FATAL_NOLOCK(
"Terminal affinity return unexpectedly returned");
218 FATAL_NOLOCK(
"Terminal user return unexpectedly returned");
226 uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5) {
227 register uintptr_t r0
asm(
"r0") = p1;
228 register uintptr_t r1
asm(
"r1") = p2;
229 register uintptr_t r2
asm(
"r2") = p3;
230 register uintptr_t r3
asm(
"r3") = p4;
231 register uintptr_t r4
asm(
"r4") = p5;
232 register uintptr_t r7
asm(
"r7") = (
static_cast<uintptr_t
>(service) << 16) | function;
233 asm volatile(
"push {lr}\n\tsvc #1\n\tpop {lr}"
235 :
"r"(r1),
"r"(r2),
"r"(r3),
"r"(r4),
"r"(r7)
bool registerSyscallHandler(Service_t service, SyscallHandler *handler, Registration ®istration, FastEntry entry=nullptr) override
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
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)