The Pedigree Project 0.1
arm64/SyscallManager.cc
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"
12
13Arm64SyscallManager Arm64SyscallManager::m_Instance;
14
15extern void system_reboot(Machine::ShutdownType type);
16
17namespace {
18class SyscallReturnScope {
19 public:
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);
26 }
27
28 ~SyscallReturnScope() {
29 restore(this);
30 }
31
32 private:
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;
39 }
40 }
41
42 Thread* m_Thread;
43 size_t m_StateLevel;
44 const SyscallState* m_Previous;
46};
47} // namespace
48
50 return Arm64SyscallManager::instance();
51}
52
54 Registration& registration, FastEntry entry) {
55 return registerHandler(service, handler, registration, entry);
56}
57
58void Arm64SyscallManager::handle(SyscallState& state) {
59 Arm64SyscallManager& manager = m_Instance;
60 Thread* syscallThread = Processor::information().getCurrentThread();
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;
68 Subsystem::ExitCause processExitCause = Subsystem::ExitCause::Normal;
69 Machine::ShutdownType shutdownType = Machine::ShutdownType::Halt;
70
71 {
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());
78 }
79#endif
80 bool handled = false;
81 PostSyscallAction action;
82 if (service < serviceEnd) {
83 HandlerLease handler;
84 if (manager.acquireHandler(static_cast<Service_t>(service), handler, action)) {
85 handled = true;
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);
92 } else {
93 state.setSyscallReturnValue(result);
94 state.setSyscallErrno(error);
95 }
96 syscallThread->setErrno(0);
97 }
98 }
99
100 PerProcessorScheduler& scheduler = Processor::information().getScheduler();
101 if (!handled) {
102 state.setSyscallReturnValue(-static_cast<uintptr_t>(Error::Unimplemented));
103 userReturnTerminal = scheduler.serviceUserReturnWork(state);
104 } else {
105 const bool directTransition =
106 action.kind == ReturnFromEvent || action.kind == PopEventState ||
107 action.kind == RestoreProcessorState || action.kind == JumpToUserspace;
108 if (directTransition) {
109 userReturnTerminal = scheduler.serviceProcessStopAtUserReturn(
110 PerProcessorScheduler::ProcessStopGateMode::DirectUserTransition);
111 if (syscallThread->getUnwindState() != Thread::Continue) {
112 userReturnTerminal = true;
113 }
114 }
115
116 switch (action.kind) {
117 case TerminateCurrentThread:
118 commitThreadExit = true;
119 break;
120 case ExitCurrentProcess:
121 exitCurrentProcess = true;
122 processExitCode = static_cast<int>(action.value);
123 break;
124 case ReturnFromEvent:
125 if (!userReturnTerminal) {
126 tracker.finishInKernel();
127 scheduler.eventHandlerReturned();
128 }
129 break;
130 case PopEventState:
131 if (!userReturnTerminal) {
132 syscallThread->abandonCurrentState(false);
133 }
134 break;
135 case RestoreProcessorState:
136 if (!userReturnTerminal) {
137 for (size_t i = 0; i < 31; ++i) {
138 state.x[i] = action.state.x[i];
139 }
140 state.sp = action.state.sp;
141 state.pc = action.state.pc;
142 state.pstate = action.state.pstate;
143 userReturnTerminal =
144 scheduler.serviceUserReturnWork(state, UserReturnFrame::Origin::SignalRestore);
145 }
146 break;
147 case JumpToUserspace:
148 if (!userReturnTerminal) {
149 tracker.finishInKernel();
150 syscallThread->abandonAllStates();
151 for (size_t i = 0; i < 31; ++i) {
152 state.x[i] = 0;
153 }
154 state.pc = action.state.getInstructionPointer();
155 state.sp = action.state.getStackPointer();
156 state.pstate = 0;
157 state.esr = 0;
158 userReturnTerminal =
159 scheduler.serviceUserReturnWork(state, UserReturnFrame::Origin::NewImage);
160 }
161 break;
162 case RebootSystem:
163 rebootSystem = true;
164 shutdownType = static_cast<Machine::ShutdownType>(action.value);
165 break;
166 case NoPostSyscallAction:
167 if (!syscallThread->canSkipUserReturnWork() || interruptedWithoutProgress) {
168 SyscallReturnScope returnScope(interruptedWithoutProgress ? &original : nullptr);
169 userReturnTerminal = scheduler.serviceUserReturnWork(state);
170 }
171 break;
172 }
173 }
174
175 if (!exitCurrentProcess && !rebootSystem) {
176 const Thread::UnwindType unwind = syscallThread->getUnwindState();
177 if (userReturnTerminal || unwind != Thread::Continue) {
178 if (unwind == Thread::TerminateThread) {
179 commitThreadExit = true;
180 } else if (unwind == Thread::Exit) {
181 exitCurrentProcess = true;
182 const Thread::DeferredProcessExit request = syscallThread->takeDeferredProcessExit();
183 processExitCode = request.code;
184 processExitCause = request.cause;
185 }
186 }
187 }
188 tracker.finishInKernel();
189 }
190
191 if (rebootSystem) {
193 syscallThread->abandonAllStates();
195 system_reboot(shutdownType);
196 }
197 if (exitCurrentProcess) {
198 syscallThread->getParent()->getSubsystem()->exit(processExitCode, processExitCause);
199 }
200 if (commitThreadExit) {
201 Processor::information().getScheduler().commitCurrentThreadExit();
202 }
203
204 while (true) {
205 bool waited = false;
206 if (syscallThread->completeAffinityAtSafePoint(&waited) == AffinityResult::Terminal) {
207 Processor::information().getScheduler().commitUserReturnTerminalState();
208 FATAL_NOLOCK("Terminal affinity return unexpectedly returned");
209 }
210 if (!waited) {
211 break;
212 }
214 if (Processor::information().getScheduler().serviceUserReturnWork(state)) {
215 Processor::information().getScheduler().commitUserReturnTerminalState();
216 FATAL_NOLOCK("Terminal user return unexpectedly returned");
217 }
218 }
219 syscallThread->transitionTimeAtInterruptReturn(CpuTimeMode::Kernel, CpuTimeMode::User);
221}
222
223uintptr_t Arm64SyscallManager::syscall(Service_t service, uintptr_t function, uintptr_t p1,
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");
232 return x0;
233}
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 &registration, FastEntry entry=nullptr) override
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)
Definition Thread.h:465
UnwindType
Definition Thread.h:499
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:500
@ TerminateThread
Exit only this thread during Process exit.
Definition Thread.h:502
@ Exit
Exit the owning process at the next safe boundary.
Definition Thread.h:501
size_t getErrno()
Definition Thread.h:460
UnwindType getUnwindState()
Definition Thread.h:518
ALWAYS_INLINE void transitionTimeAtInterruptReturn(CpuTimeMode from, CpuTimeMode to)
Definition Thread.h:358
Process * getParent() const
Definition Thread.h:325
DeferredProcessExit takeDeferredProcessExit()
Definition Thread.cc:3588
AffinityResult completeAffinityAtSafePoint(bool *waited=nullptr)
void abandonAllStates()
Definition Thread.cc:939
void abandonCurrentState(bool clean=false)
Definition Thread.cc:930