20#include "pedigree/kernel/LockGuard.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/process/Scheduler.h"
23#include "pedigree/kernel/process/TerminationDeferral.h"
24#include "pedigree/kernel/process/Thread.h"
25#include "pedigree/kernel/processor/Processor.h"
26#include "pedigree/kernel/processor/ProcessorInformation.h"
27#include "pedigree/kernel/processor/SyscallHandler.h"
28#include "pedigree/kernel/processor/SyscallManager.h"
29#include "pedigree/kernel/utilities/assert.h"
30#include "pedigree/kernel/utilities/new"
36 const FastEntry entry;
41SyscallManager::Registration::Registration()
42 : m_pManager(nullptr), m_Service(serviceEnd), m_pSlot(nullptr) {}
44SyscallManager::Registration::Registration(Registration&& other)
45 : m_pManager(other.m_pManager), m_Service(other.m_Service), m_pSlot(other.m_pSlot) {
46 other.m_pManager =
nullptr;
47 other.m_Service = serviceEnd;
48 other.m_pSlot =
nullptr;
51SyscallManager::Registration::~Registration() {
52 if (m_pManager && !reset()) {
53 FATAL(
"Live syscall registration could not be retired.");
59 if (m_pManager && !reset()) {
60 FATAL(
"Syscall registration move could not retire ownership.");
62 m_pManager = other.m_pManager;
63 m_Service = other.m_Service;
64 m_pSlot = other.m_pSlot;
65 other.m_pManager =
nullptr;
66 other.m_Service = serviceEnd;
67 other.m_pSlot =
nullptr;
73 return !m_pManager || m_pManager->closeHandler(*
this);
76bool SyscallManager::Registration::reset() {
80 if (!m_pManager->unregisterHandler(*
this)) {
85 m_Service = serviceEnd;
94#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
96 m_HandlerPinHook(nullptr),
97 m_PostSyscallHook(nullptr)
104uintptr_t SyscallManager::dispatchVirtual(
SyscallHandler* handler, SyscallState& state) {
105 return handler->
syscall(state);
108bool SyscallManager::inCallback() {
110 return thread && thread->getSyscallDispatchContext();
113bool SyscallManager::registerHandler(Service_t service,
SyscallHandler* handler,
114 Registration& registration, FastEntry entry) {
115 if (
UNLIKELY(service >= serviceEnd) || !handler || registration) {
119 auto* slot =
new HandlerSlot(handler, entry ? entry : dispatchVirtual);
124 if (m_HandlerSlots[service]) {
130 m_HandlerSlots[service] = slot;
131 registration.m_pManager =
this;
132 registration.m_Service = service;
133 registration.m_pSlot = slot;
134 __atomic_store_n(&m_Published[service], slot, __ATOMIC_SEQ_CST);
139bool SyscallManager::closeHandler(Registration& registration) {
140 if (registration.m_pManager !=
this ||
UNLIKELY(registration.m_Service >= serviceEnd) ||
141 !registration.m_pSlot || inCallback()) {
146 if (m_HandlerSlots[registration.m_Service] != registration.m_pSlot) {
149 __atomic_store_n(&m_Published[registration.m_Service],
nullptr, __ATOMIC_SEQ_CST);
153#if PEDIGREE_CONCURRENCY_SMOKE_TESTS
154bool SyscallManager::dispatchHandlerForTest(Service_t service, uintptr_t& result) {
155 PostSyscallAction action;
156 HandlerLease handler;
157 if (!acquireHandler(service, handler, action)) {
161 SyscallState state = {};
162 result = dispatchHandler(handler, state);
163 return action.kind == NoPostSyscallAction;
167bool SyscallManager::unregisterHandler(Registration& registration) {
168 if (registration.m_pManager !=
this ||
UNLIKELY(registration.m_Service >= serviceEnd) ||
169 !registration.m_pSlot) {
176 HandlerSlot* slot = registration.m_pSlot;
177 const Service_t service = registration.m_Service;
184 if (m_HandlerSlots[service] != slot) {
187 HandlerSlot* published =
188 __atomic_exchange_n(&m_Published[service], &m_ClosingSlot, __ATOMIC_SEQ_CST);
190 __atomic_store_n(&m_Published[service], published, __ATOMIC_SEQ_CST);
193 __atomic_store_n(&m_Published[service],
nullptr, __ATOMIC_SEQ_CST);
194 m_HandlerSlots[service] =
nullptr;
198 if (m_HandlerSlots[service] != slot) {
201 __atomic_store_n(&m_Published[service],
nullptr, __ATOMIC_SEQ_CST);
218 m_HandlerSlots[service] =
nullptr;
224bool SyscallManager::acquireHandler(Service_t service, HandlerLease& lease,
225 PostSyscallAction& action) {
227 if (
UNLIKELY(service >= serviceEnd) || lease.m_pThread || !thread) {
234 const size_t count = __atomic_load_n(&admission, __ATOMIC_RELAXED);
235 if (count == ~
size_t(0)) {
236 FATAL(
"Syscall admission nesting overflow.");
241 __atomic_store_n(&admission, count + 1, __ATOMIC_SEQ_CST);
244 slot = __atomic_load_n(&m_Published[service], __ATOMIC_SEQ_CST);
245 if (slot == &m_ClosingSlot) {
248 }
while (slot == &m_ClosingSlot);
250 __atomic_store_n(&admission, count, __ATOMIC_RELEASE);
255 lease.m_Service = service;
256 lease.m_pHandler = slot->handler;
257 lease.m_Entry = slot->entry;
258 lease.m_pThread = thread;
259 lease.m_Previous =
static_cast<HandlerLease*
>(thread->getSyscallDispatchContext());
260 lease.m_Action = &action;
261 thread->registerFreshTerminationDeferral(lease.m_Cleanup, abandonedHandlerCleanup, &lease);
262 thread->setSyscallDispatchContext(&lease);
265#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
266 HandlerPinHook hook = __atomic_load_n(&m_HandlerPinHook, __ATOMIC_ACQUIRE);
268 hook(service, lease.m_pHandler);
274void SyscallManager::releaseHandler(HandlerLease& lease,
bool normalReturn) {
277 Thread* thread = lease.m_pThread;
280 FATAL(
"Syscall lease released by a different Thread.");
282 thread->unregisterDeferredScope(lease.m_Cleanup);
284 auto* current =
static_cast<HandlerLease*
>(thread->getSyscallDispatchContext());
285 if (current == &lease) {
286 thread->setSyscallDispatchContext(lease.m_Previous);
290 while (current && current->m_Previous != &lease) {
291 current = current->m_Previous;
294 FATAL(
"Syscall lease was absent from its Thread's dispatch chain.");
296 current->m_Previous = lease.m_Previous;
299 const size_t count = __atomic_load_n(&admission, __ATOMIC_RELAXED);
301 FATAL(
"Syscall admission nesting underflow.");
303 lease.m_pThread =
nullptr;
304 __atomic_store_n(&admission, count - 1, __ATOMIC_RELEASE);
308void SyscallManager::abandonedHandlerCleanup(
void* context) {
309 HandlerLease* lease =
reinterpret_cast<HandlerLease*
>(context);
310 if (lease && lease->m_pThread) {
311 releaseHandler(*lease,
false);
315bool SyscallManager::requestPostSyscallAction(PostSyscallActionKind kind, intptr_t value,
316 const ProcessorState* state) {
318 auto* lease = thread ?
static_cast<HandlerLease*
>(thread->getSyscallDispatchContext()) : nullptr;
319 PostSyscallAction* action = lease ? lease->m_Action :
nullptr;
320 if (!action || action->kind != NoPostSyscallAction) {
323 if ((kind == ReturnFromEvent || kind == PopEventState) && !thread->
getStateLevel()) {
328 new (&action->state) ProcessorState(*state);
330 action->value = value;
336 return requestPostSyscallAction(TerminateCurrentThread, 0);
339bool SyscallManager::requestProcessExit(
int status) {
340 return requestPostSyscallAction(ExitCurrentProcess,
static_cast<intptr_t
>(status));
343bool SyscallManager::requestEventReturn() {
344 return requestPostSyscallAction(ReturnFromEvent, 0);
347bool SyscallManager::requestEventStatePop() {
348 return requestPostSyscallAction(PopEventState, 0);
351bool SyscallManager::requestStateRestore(
const ProcessorState& state) {
352 return requestPostSyscallAction(RestoreProcessorState, 0, &state);
355bool SyscallManager::requestUserJump(uintptr_t instructionPointer, uintptr_t stackPointer) {
356 ProcessorState state;
357 state.setInstructionPointer(instructionPointer);
358 state.setStackPointer(stackPointer);
359 return requestPostSyscallAction(JumpToUserspace, 0, &state);
362bool SyscallManager::requestReboot(Machine::ShutdownType type) {
363 return requestPostSyscallAction(RebootSystem,
static_cast<intptr_t
>(type));
366#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
367void SyscallManager::setHandlerPinHook(HandlerPinHook hook) {
368 __atomic_store_n(&m_HandlerPinHook, hook, __ATOMIC_RELEASE);
371void SyscallManager::setPostSyscallHook(PostSyscallHook hook) {
372 __atomic_store_n(&m_PostSyscallHook, hook, __ATOMIC_RELEASE);
375bool SyscallManager::postSyscallHookHandled(
const PostSyscallAction& action) {
376 PostSyscallHook hook = __atomic_load_n(&m_PostSyscallHook, __ATOMIC_ACQUIRE);
377 const ProcessorState* state =
378 action.kind == RestoreProcessorState || action.kind == JumpToUserspace ? &action.state
380 return hook && hook(action.kind, action.value, state);
static bool getInterrupts()
static ProcessorInformation & information()
static ExecutionContext executionContext()
static void setInterrupts(bool bEnable)
This class manages how processes and threads are scheduled across processors.
bool hasActiveSyscallLocked(Service_t service) const
static Scheduler & instance()
bool acquire(bool recurse=false, bool safe=true)
virtual uintptr_t syscall(SyscallState &State)=0
virtual ~SyscallManager()
EXPORTED_PUBLIC bool requestThreadExit()
size_t m_ActiveSyscalls[serviceEnd]
size_t getStateLevel() const