The Pedigree Project 0.1
UserReturnFrame.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "pedigree/kernel/processor/UserReturnFrame.h"
3
4#include <config.h>
5
6#if X64 && !HOSTED && THREADS
7#include "pedigree/kernel/process/Thread.h"
8#include "pedigree/kernel/processor/Processor.h"
9#include "pedigree/kernel/processor/ProcessorInformation.h"
10#include "pedigree/kernel/processor/state.h"
11
12static_assert(sizeof(X64UserEntryMetadata) == 32, "entry metadata prefix size");
13static_assert(__builtin_offsetof(X64UserEntryMetadata, ds) == 0, "entry DS offset");
14static_assert(__builtin_offsetof(X64UserEntryMetadata, es) == 2, "entry ES offset");
15static_assert(__builtin_offsetof(X64UserEntryMetadata, fs) == 4, "entry FS offset");
16static_assert(__builtin_offsetof(X64UserEntryMetadata, gs) == 6, "entry GS offset");
17static_assert(__builtin_offsetof(X64UserEntryMetadata, fsBase) == 8, "entry FS base offset");
18static_assert(__builtin_offsetof(X64UserEntryMetadata, gsBase) == 16, "entry GS base offset");
19static_assert(__builtin_offsetof(X64UserEntryMetadata, origRax) == 24, "entry original RAX offset");
20static_assert(sizeof(X64SyscallState) == 160, "syscall frame includes entry metadata");
21static_assert(sizeof(X64InterruptState) == 208, "interrupt frame includes entry metadata");
22
23namespace {
24void copyMetadata(Amd64UserRegisters& output, const X64UserEntryMetadata& entry) {
25 output.orig_rax = entry.origRax;
26 output.fs_base = entry.fsBase;
27 output.gs_base = entry.gsBase;
28 output.ds = entry.ds;
29 output.es = entry.es;
30 output.fs = entry.fs;
31 output.gs = entry.gs;
32}
33
34void capture(Amd64UserRegisters& output, const X64SyscallState& state) {
35 output.r15 = state.getRegister(12);
36 output.r14 = state.getRegister(11);
37 output.r13 = state.getRegister(10);
38 output.r12 = state.getRegister(9);
39 output.rbp = state.getRegister(5);
40 output.rbx = state.getRegister(1);
41 output.r11 = state.getFlags();
42 output.r10 = state.getRegister(8);
43 output.r9 = state.getRegister(7);
44 output.r8 = state.getRegister(6);
45 output.rax = state.getRegister(0);
46 output.rcx = state.getInstructionPointer();
47 output.rdx = state.getRegister(2);
48 output.rsi = state.getRegister(4);
49 output.rdi = state.getRegister(3);
50 output.rip = state.getInstructionPointer();
51 // X64SyscallManager's STAR value selects these actual SYSRET selectors.
52 output.cs = 0x2b;
53 output.eflags = state.getFlags();
54 output.rsp = state.getStackPointer();
55 output.ss = 0x23;
56 copyMetadata(output, state.getUserEntryMetadata());
57}
58
59void capture(Amd64UserRegisters& output, const X64InterruptState& state) {
60 output.r15 = state.getRegister(14);
61 output.r14 = state.getRegister(13);
62 output.r13 = state.getRegister(12);
63 output.r12 = state.getRegister(11);
64 output.rbp = state.getRegister(6);
65 output.rbx = state.getRegister(1);
66 output.r11 = state.getRegister(10);
67 output.r10 = state.getRegister(9);
68 output.r9 = state.getRegister(8);
69 output.r8 = state.getRegister(7);
70 output.rax = state.getRegister(0);
71 output.rcx = state.getRegister(2);
72 output.rdx = state.getRegister(3);
73 output.rsi = state.getRegister(5);
74 output.rdi = state.getRegister(4);
75 output.rip = state.getInstructionPointer();
76 output.cs = state.getCodeSegment();
77 output.eflags = state.getFlags();
78 output.rsp = state.getStackPointer();
79 output.ss = state.getStackSegment();
80 copyMetadata(output, state.getUserEntryMetadata());
81}
82} // namespace
83#endif
84
85bool UserReturnFrame::snapshot(UserRegisterSnapshot& output) const {
86#if X64 && !HOSTED && THREADS
87 // Selection, scope validation and the bounded copy observe one current task.
88 // A deferred syscall entry may need its live TLS bases captured here.
89 EnsureInterrupts interrupts(false);
90 if (Processor::information().getCurrentThread() != m_Owner ||
91 m_Owner->currentUserReturnFrame() != this)
92 return false;
93
95 if (m_Syscall) {
96 if (m_Origin != Origin::Syscall && m_Origin != Origin::NewImage)
97 return false;
98 capture(next.amd64, *m_Syscall);
99 } else if (m_Interrupt) {
100 if ((m_Origin != Origin::Interrupt && m_Origin != Origin::SignalRestore) ||
101 m_Interrupt->kernelMode())
102 return false;
103 capture(next.amd64, *m_Interrupt);
104 } else {
105 return false;
106 }
107 next.architecture = UserRegisterSnapshot::Architecture::Amd64;
108 output = next;
109 return true;
110#else
111 (void)output;
112 return false;
113#endif
114}
static ProcessorInformation & information()
uintptr_t getStackPointer() const
Definition x64/state.h:430
uintptr_t getInstructionPointer() const
Definition x64/state.h:436
uint64_t getFlags() const
Definition x64/state.h:468
uint16_t getCodeSegment() const
Definition x64/state.h:461
uint16_t getStackSegment() const
Definition x64/state.h:464
processor_register_t getRegister(size_t index) const
Definition x64/state.cc:35
EXPORTED_PUBLIC processor_register_t getRegister(size_t index) const
Definition x64/state.cc:119
uintptr_t getInstructionPointer() const
Definition x64/state.h:481
uintptr_t getStackPointer() const
Definition x64/state.h:475