144 Metrics::increment(Metrics::Syscall);
145 captureUserEntry(syscallState);
147 const SyscallState originalState = syscallState;
148#if PEDIGREE_ACTIVITY_DIAGNOSTICS
149 const bool diagnosticSample =
152 const bool diagnosticSample =
false;
155 bool commitThreadExit =
false;
156 bool exitCurrentProcess =
false;
157 bool rebootSystem =
false;
158 Machine::ShutdownType shutdownType = Machine::ShutdownType::Halt;
159 bool userReturnTerminal =
false;
160 bool interruptedWithoutProgress =
false;
161 bool deferTimeAccountingToUserReturn =
false;
162 uint64_t returnTailStart = 0;
163 int processExitCode = 0;
175 size_t serviceNumber = syscallState.getSyscallService();
176#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
177 if (serviceNumber == linuxCompat) {
181 bool handled =
false;
183 if (
LIKELY(serviceNumber < serviceEnd)) {
187 if (
m_Instance.acquireHandler(
static_cast<Service_t
>(serviceNumber), handler, action)) {
189 uint64_t result =
m_Instance.dispatchHandler(handler, syscallState);
190 uint64_t errno = syscallThread->
getErrno();
191 interruptedWithoutProgress = result ==
static_cast<uint64_t
>(-1) &&
192 errno == Error::Interrupted && serviceNumber == linuxCompat;
195 if (serviceNumber == linuxCompat) {
197 syscallState.setSyscallReturnValue(-errno);
199 syscallState.setSyscallReturnValue(result);
202 syscallState.setSyscallReturnValue(result);
203 syscallState.setSyscallErrno(errno);
210 returnTailStart = diagnosticSample ? ActivityDiagnostics::timestamp() : 0;
215 syscallState, UserReturnFrame::Origin::Syscall, diagnosticSample);
217 const bool directUserTransition =
218 action.kind == ReturnFromEvent || action.kind == PopEventState ||
219 action.kind == RestoreProcessorState || action.kind == JumpToUserspace;
220 if (directUserTransition) {
221 const uint64_t stopStart = diagnosticSample ? ActivityDiagnostics::timestamp() : 0;
223 PerProcessorScheduler::ProcessStopGateMode::DirectUserTransition);
224 if (diagnosticSample) {
225 ActivityDiagnostics::recordUserReturnStage(
226 ActivityDiagnostics::UserReturnStage::ProcessStop,
227 ActivityDiagnostics::timestamp() - stopStart);
229 Thread* current = syscallThread;
231 userReturnTerminal =
true;
235 switch (action.kind) {
236 case TerminateCurrentThread:
237 commitThreadExit =
true;
239 case ExitCurrentProcess:
240 exitCurrentProcess =
true;
241 processExitCode =
static_cast<int>(action.value);
243 case ReturnFromEvent:
244 if (userReturnTerminal) {
251 if (!userReturnTerminal) {
255 case RestoreProcessorState: {
256 if (userReturnTerminal) {
261 const uintptr_t userStack = action.state.rsp;
262 const uint64_t userFlags = action.state.rflags;
263 alignas(16)
unsigned char interruptStack[
sizeof(InterruptState)] = {};
264 action.state.setStackPointer(
265 reinterpret_cast<uintptr_t
>(interruptStack +
sizeof(interruptStack)));
267 metadata.origRax = ~uint64_t(0);
268 InterruptState* returnState = InterruptState::construct(action.state,
true, metadata);
269 returnState->setStackPointer(userStack);
270 returnState->setFlags(userFlags);
275 *returnState, UserReturnFrame::Origin::SignalRestore, diagnosticSample);
276 if (userReturnTerminal) {
280 Thread* current = syscallThread;
281 if (finishAffinityReturn(*returnState, UserReturnFrame::Origin::SignalRestore,
283 userReturnTerminal =
true;
287 const uint64_t accountingStart = diagnosticSample ? ActivityDiagnostics::timestamp() : 0;
289 recordAccountingSample(diagnosticSample, accountingStart);
292 case JumpToUserspace: {
293 if (userReturnTerminal)
297 Thread* current = syscallThread;
299 SyscallState newImage;
300 ByteSet(&newImage, 0,
sizeof(newImage));
301 newImage.setInstructionPointer(action.state.getInstructionPointer());
302 newImage.setStackPointer(action.state.getStackPointer());
303 newImage.setFlags(0x202);
305 metadata.ds = metadata.es = 0x23;
306 metadata.origRax = 59;
307 newImage.setUserEntryMetadata(metadata);
309 newImage.refreshUserTlsBase();
312 *
reinterpret_cast<volatile uint64_t*
>(newImage.getStackPointer() - 8) = 0;
315 newImage, UserReturnFrame::Origin::NewImage, diagnosticSample);
316 if (userReturnTerminal)
319 const uint64_t affinityStart = diagnosticSample ? ActivityDiagnostics::timestamp() : 0;
322 recordAffinitySample(diagnosticSample, waited, affinityStart);
323 if (userReturnTerminal || !waited)
327 if (userReturnTerminal) {
331 const uint64_t accountingStart = diagnosticSample ? ActivityDiagnostics::timestamp() : 0;
333 recordAccountingSample(diagnosticSample, accountingStart);
340 shutdownType =
static_cast<Machine::ShutdownType
>(action.value);
342 case NoPostSyscallAction: {
343#if PEDIGREE_FAST_USER_RETURN
344 Thread* current = syscallThread;
345 if (!interruptedWithoutProgress && current && current->canSkipUserReturnWork()) {
346 deferTimeAccountingToUserReturn =
true;
350 SyscallReturnScope returnScope(interruptedWithoutProgress ? &originalState :
nullptr);
352 syscallState, UserReturnFrame::Origin::Syscall, diagnosticSample);
358 if (!exitCurrentProcess && !rebootSystem) {
359 Thread* pThread = syscallThread;
363 commitThreadExit =
true;
366 NOTICE(
"Unwind state exit at syscall return");
367 exitCurrentProcess =
true;
369 processExitCode = request.code;
370 processExitCause = request.cause;
376 if ((syscallState.m_RFlagsR11 & 0x200) != 0x200) {
377 syscallState.m_RFlagsR11 |= 0x200;
380 if (deferTimeAccountingToUserReturn)
390 system_reboot(shutdownType);
393 if (exitCurrentProcess) {
394 syscallThread->
getParent()->getSubsystem()->
exit(processExitCode, processExitCause);
396 if (commitThreadExit) {
403 Thread* current = syscallThread;
404 if (finishAffinityReturn(syscallState, interruptedWithoutProgress ? &originalState :
nullptr,
408 FATAL_NOLOCK(
"Terminal affinity return unexpectedly returned");
410 const uint64_t accountingStart = diagnosticSample ? ActivityDiagnostics::timestamp() : 0;
414 recordAccountingSample(diagnosticSample, accountingStart);
415 if (diagnosticSample) {
416 ActivityDiagnostics::recordUserReturnStage(ActivityDiagnostics::UserReturnStage::SyscallTail,
417 ActivityDiagnostics::timestamp() - returnTailStart);