The Pedigree Project 0.1
armv7/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
13Armv7SyscallManager Armv7SyscallManager::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 Armv7SyscallManager::instance();
51}
52
54 Registration& registration, FastEntry entry) {
55 return registerHandler(service, handler, registration, entry);
56}
57
58void Armv7SyscallManager::handle(SyscallState& state) {
59 Armv7SyscallManager& 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 < 13; ++i) {
138 state.r[i] = action.state.r[i];
139 }
140 state.sp = action.state.sp;
141 state.pc = action.state.pc;
142 state.cpsr = action.state.cpsr;
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 < 13; ++i) {
152 state.r[i] = 0;
153 }
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;
159 state.svcNumber = 0;
160 userReturnTerminal =
161 scheduler.serviceUserReturnWork(state, UserReturnFrame::Origin::NewImage);
162 }
163 break;
164 case RebootSystem:
165 rebootSystem = true;
166 shutdownType = static_cast<Machine::ShutdownType>(action.value);
167 break;
168 case NoPostSyscallAction:
169 if (!syscallThread->canSkipUserReturnWork() || interruptedWithoutProgress) {
170 SyscallReturnScope returnScope(interruptedWithoutProgress ? &original : nullptr);
171 userReturnTerminal = scheduler.serviceUserReturnWork(state);
172 }
173 break;
174 }
175 }
176
177 if (!exitCurrentProcess && !rebootSystem) {
178 const Thread::UnwindType unwind = syscallThread->getUnwindState();
179 if (userReturnTerminal || unwind != Thread::Continue) {
180 if (unwind == Thread::TerminateThread) {
181 commitThreadExit = true;
182 } else if (unwind == Thread::Exit) {
183 exitCurrentProcess = true;
184 const Thread::DeferredProcessExit request = syscallThread->takeDeferredProcessExit();
185 processExitCode = request.code;
186 processExitCause = request.cause;
187 }
188 }
189 }
190 tracker.finishInKernel();
191 }
192
193 if (rebootSystem) {
195 syscallThread->abandonAllStates();
197 system_reboot(shutdownType);
198 }
199 if (exitCurrentProcess) {
200 syscallThread->getParent()->getSubsystem()->exit(processExitCode, processExitCause);
201 }
202 if (commitThreadExit) {
203 Processor::information().getScheduler().commitCurrentThreadExit();
204 }
205
206 while (true) {
207 bool waited = false;
208 if (syscallThread->completeAffinityAtSafePoint(&waited) == AffinityResult::Terminal) {
209 Processor::information().getScheduler().commitUserReturnTerminalState();
210 FATAL_NOLOCK("Terminal affinity return unexpectedly returned");
211 }
212 if (!waited) {
213 break;
214 }
216 if (Processor::information().getScheduler().serviceUserReturnWork(state)) {
217 Processor::information().getScheduler().commitUserReturnTerminalState();
218 FATAL_NOLOCK("Terminal user return unexpectedly returned");
219 }
220 }
221 syscallThread->transitionTimeAtInterruptReturn(CpuTimeMode::Kernel, CpuTimeMode::User);
223}
224
225uintptr_t Armv7SyscallManager::syscall(Service_t service, uintptr_t function, uintptr_t p1,
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}"
234 : "+r"(r0)
235 : "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7)
236 : "memory");
237 return r0;
238}
bool registerSyscallHandler(Service_t service, SyscallHandler *handler, Registration &registration, 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
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:3623
AffinityResult completeAffinityAtSafePoint(bool *waited=nullptr)
void abandonAllStates()
Definition Thread.cc:950
void abandonCurrentState(bool clean=false)
Definition Thread.cc:941