20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/TargetInfo.h"
22#include "pedigree/kernel/compiler.h"
23#include "pedigree/kernel/panic.h"
24#include "pedigree/kernel/process/Scheduler.h"
25#include "pedigree/kernel/process/Thread.h"
26#include "pedigree/kernel/process/initialiseMultitasking.h"
27#include "pedigree/kernel/processor/PageFaultHandler.h"
28#include "pedigree/kernel/processor/Processor.h"
29#include "pedigree/kernel/processor/state.h"
30#if PEDIGREE_HOSTED_FUNCTION_PROFILE
31#include "pedigree/kernel/processor/hosted/FunctionProfile.h"
34#include "HostedPlatform.h"
35#include "InterruptManager.h"
36#include "PhysicalMemoryManager.h"
37#include "SyscallManager.h"
38#include "VirtualAddressSpace.h"
40namespace __pedigree_hosted {};
41using namespace __pedigree_hosted;
43#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
45ProcessorBase::HostedContextSwitchHook g_HostedContextSwitchHook =
nullptr;
54#if defined(__APPLE__) && defined(__aarch64__)
55#include <libkern/OSCacheControl.h>
59void addHostedIrqSignals(sigset_t& set) {
60 sigaddset(&set, SIGUSR1);
61 sigaddset(&set, SIGUSR2);
62#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
63 sigaddset(&set, SIGURG);
68bool ProcessorBase::m_bInterrupts;
76void __sanitizer_start_switch_fiber(
void** fake_stack_save,
const void* bottom,
size_t size);
78void __sanitizer_finish_switch_fiber(
void* fake_stack_save,
const void** bottom_old,
83typedef void (*jump_func_t)(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
87uintptr_t hosted_kernel_fs_base = 0;
88uintptr_t hosted_user_fs_base = 0;
90long hostedCaptureKernelFs() {
94extern uintptr_t hosted_kernel_fs_base;
95extern uintptr_t hosted_user_fs_base;
96long hostedCaptureKernelFs();
101uintptr_t currentHostedExecutionThread() {
102 static_assert(
sizeof(pthread_t) <=
sizeof(uintptr_t),
103 "pthread_t does not fit in the hosted execution-thread identity");
104 const pthread_t thread = pthread_self();
106 __builtin_memcpy(&
identity, &thread,
sizeof(thread));
110pthread_t hostedExecutionThread(uintptr_t
identity) {
111 pthread_t thread = {};
112 __builtin_memcpy(&thread, &
identity,
sizeof(thread));
122 const size_t hostPageSize = HostedPlatform::pageSize();
125 panic(
"Hosted: incompatible target and host page sizes");
128 <<
" host=" << hostPageSize <<
Hex);
130 const uintptr_t executionThreadId = currentHostedExecutionThread();
131 if (!executionThreadId) {
132 panic(
"Hosted: failed to capture the processor execution thread");
134 __atomic_store_n(&
information().m_HostedExecutionThreadId, executionThreadId, __ATOMIC_RELEASE);
136 if (hostedCaptureKernelFs() != 0) {
137 panic(
"Hosted: failed to capture the host FS base");
139 hosted_user_fs_base = hosted_kernel_fs_base;
150 initialiseMultitasking();
158 str.append(
"Hosted Processor");
162 return reinterpret_cast<uintptr_t
>(__builtin_return_address(0));
170 return reinterpret_cast<uintptr_t
>(__builtin_frame_address(0));
174 FATAL(
"ProcessorBase::saveState is NOT safe on HOSTED builds.");
179#if PEDIGREE_HOSTED_FUNCTION_PROFILE
180 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
186 __sanitizer_start_switch_fiber(
nullptr,
reinterpret_cast<void*
>(state.stackBase),
190 setcontext(
reinterpret_cast<ucontext_t*
>(state.state));
191 FATAL(
"Hosted: setcontext failed in Processor::restoreState");
195#if defined(__APPLE__)
199 FATAL(
"Hosted Darwin does not emulate userspace syscall return");
200 __builtin_unreachable();
204 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
212 FATAL(
"Hosted Darwin does not emulate userspace entry");
213 __builtin_unreachable();
217#if SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH
219 volatile uintptr_t* pLock) {
220#if PEDIGREE_HOSTED_FUNCTION_PROFILE
221 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
223 void* fake_stack_save =
nullptr;
225 ucontext_t* a_ctx =
reinterpret_cast<ucontext_t*
>(a.state);
226 ucontext_t* b_ctx =
reinterpret_cast<ucontext_t*
>(b.state);
231 __sanitizer_start_switch_fiber(&fake_stack_save,
reinterpret_cast<void*
>(b.stackBase),
234 swapcontext(a_ctx, b_ctx);
236 __sanitizer_finish_switch_fiber(fake_stack_save,
nullptr,
nullptr);
238#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
239 notifyHostedContextSwitchStage(HostedContextSwitchStage::SwitchStateReturnedMasked);
243static void syscallStateWrapper(uintptr_t state, uintptr_t lock, uintptr_t sourceState);
246 volatile uintptr_t* pLock) {
247#if PEDIGREE_HOSTED_FUNCTION_PROFILE
248 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
251 size_t stackSize = 0;
253 const uintptr_t stackBegin =
reinterpret_cast<uintptr_t
>(stackBase);
254 const uintptr_t stateAddress =
reinterpret_cast<uintptr_t
>(&b);
255 if (!stackBegin || stackSize <
sizeof(SyscallState) || stateAddress < stackBegin ||
256 stateAddress - stackBegin != stackSize -
sizeof(SyscallState)) {
257 FATAL(
"Hosted syscall state is not on the target kernel stack");
260 ucontext_t newContext;
261 getcontext(&newContext);
262 newContext.uc_stack.ss_sp = stackBase;
265 newContext.uc_stack.ss_size = stateAddress - stackBegin;
266 newContext.uc_link =
nullptr;
267 makecontext(&newContext,
reinterpret_cast<void (*)()
>(syscallStateWrapper), 3, stateAddress,
268 reinterpret_cast<uintptr_t
>(pLock),
reinterpret_cast<uintptr_t
>(&a));
271 void* fakeStackSave =
nullptr;
272 __sanitizer_start_switch_fiber(&fakeStackSave, newContext.uc_stack.ss_sp,
273 newContext.uc_stack.ss_size);
275 swapcontext(
reinterpret_cast<ucontext_t*
>(a.state), &newContext);
277 __sanitizer_finish_switch_fiber(fakeStackSave,
nullptr,
nullptr);
279#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
280 notifyHostedContextSwitchStage(HostedContextSwitchStage::SwitchStateReturnedMasked);
286static void finishInitialFiberSwitch(uintptr_t sourceState) {
287 const void* sourceStack =
nullptr;
288 size_t sourceStackSize = 0;
289 __sanitizer_finish_switch_fiber(
nullptr, &sourceStack, &sourceStackSize);
291 SchedulerState* source =
reinterpret_cast<SchedulerState*
>(sourceState);
293 source->stackBase =
reinterpret_cast<uintptr_t
>(sourceStack);
294 source->stackSize = sourceStackSize;
299static void syscallStateWrapper(uintptr_t state, uintptr_t lock, uintptr_t sourceState) {
301 finishInitialFiberSwitch(sourceState);
306 volatile uintptr_t* sourceLock =
reinterpret_cast<volatile uintptr_t*
>(lock);
316static void threadWrapper(uintptr_t func,
volatile uintptr_t* pLock, uintptr_t bInterrupts,
317 uintptr_t sourceState, uintptr_t p1, uintptr_t p2, uintptr_t p3,
320 finishInitialFiberSwitch(sourceState);
333 auto entry =
reinterpret_cast<void (*)(uintptr_t, uintptr_t, uintptr_t, uintptr_t)
>(func);
334 entry(p1, p2, p3, p4);
338static void userThreadWrapper(uintptr_t func,
volatile uintptr_t* pLock, uintptr_t bInterrupts,
339 uintptr_t sourceState, uintptr_t stack, uintptr_t p1, uintptr_t p2,
340 uintptr_t p3, uintptr_t p4) {
342 finishInitialFiberSwitch(sourceState);
359 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
360 FATAL(
"Hosted: jumpKernel() is not supported - an atomic context switch is needed");
364 volatile uintptr_t* pLock, uintptr_t address, uintptr_t stack,
365 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
366#if PEDIGREE_HOSTED_FUNCTION_PROFILE
367 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
371 uintptr_t stackBottom = stack - KERNEL_STACK_SIZE;
373 ucontext_t new_context;
374 getcontext(&new_context);
375 new_context.uc_stack.ss_sp = adjust_pointer(
reinterpret_cast<void*
>(stack), -KERNEL_STACK_SIZE);
376 new_context.uc_stack.ss_size = KERNEL_STACK_SIZE;
377 new_context.uc_link = NULL;
378 makecontext(&new_context,
reinterpret_cast<void (*)()
>(threadWrapper), 8, address,
379 reinterpret_cast<uintptr_t
>(pLock),
static_cast<uintptr_t
>(bInterrupts),
380 reinterpret_cast<uintptr_t
>(&s), p1, p2, p3, p4);
383 void* fake_stack_save =
nullptr;
387 __sanitizer_start_switch_fiber(&fake_stack_save, new_context.uc_stack.ss_sp,
388 new_context.uc_stack.ss_size);
390 swapcontext(
reinterpret_cast<ucontext_t*
>(s.state), &new_context);
392 __sanitizer_finish_switch_fiber(fake_stack_save,
nullptr,
nullptr);
397 uintptr_t address, uintptr_t stack, uintptr_t p1, uintptr_t p2,
398 uintptr_t p3, uintptr_t p4) {
399#if PEDIGREE_HOSTED_FUNCTION_PROFILE
400 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
404 ucontext_t new_context;
405 getcontext(&new_context);
406 new_context.uc_stack.ss_sp = adjust_pointer(
reinterpret_cast<void*
>(stack), -KERNEL_STACK_SIZE);
407 new_context.uc_stack.ss_size = KERNEL_STACK_SIZE;
408 new_context.uc_link = NULL;
409 makecontext(&new_context,
reinterpret_cast<void (*)()
>(userThreadWrapper), 9, address,
410 reinterpret_cast<uintptr_t
>(pLock),
static_cast<uintptr_t
>(bInterrupts),
411 reinterpret_cast<uintptr_t
>(&s), stack, p1, p2, p3, p4);
414 void* fake_stack_save =
nullptr;
415 __sanitizer_start_switch_fiber(&fake_stack_save, new_context.uc_stack.ss_sp,
416 new_context.uc_stack.ss_size);
418 swapcontext(
reinterpret_cast<ucontext_t*
>(s.state), &new_context);
420 __sanitizer_finish_switch_fiber(fake_stack_save,
nullptr,
nullptr);
427 if (&info.getVirtualAddressSpace() != &AddressSpace) {
429 info.setVirtualAddressSpace(AddressSpace);
436 hosted_user_fs_base = newBase;
444 size_t& nLength,
bool& bEnabled) {
450 DebugFlags::FaultType nFaultType,
size_t nLength) {
459#if PEDIGREE_HOSTED_FUNCTION_PROFILE
461 hostedFunctionProfileInvalidate(HostedProfileInvalidation::InterruptEnable);
470 const bool signalFrameOnCurrentStack =
471 current ? current->getHostedSignalDepth() : inHostedSignalFrame();
472 if (signalFrameOnCurrentStack) {
475 addHostedIrqSignals(set);
483 addHostedIrqSignals(set);
490 m_bInterrupts =
true;
493 int r = pthread_sigmask(SIG_SETMASK, &set, 0);
495 ERROR(
"ProcessorBase::setInterrupts failed to set new mask");
502 m_bInterrupts =
false;
507 return m_bInterrupts;
510void ProcessorBase::maskInterruptsForSignalReturn() {
513 addHostedIrqSignals(set);
514 if (pthread_sigmask(SIG_BLOCK, &set,
nullptr) != 0) {
515 FATAL_NOLOCK(
"Hosted signal return failed to mask IRQ signals");
519uintptr_t ProcessorBase::hostedExecutionThreadId() {
520 return __atomic_load_n(&
information().m_HostedExecutionThreadId, __ATOMIC_ACQUIRE);
523bool ProcessorBase::onHostedExecutionThread() {
524 const uintptr_t executionThreadId = hostedExecutionThreadId();
525 return executionThreadId && currentHostedExecutionThread() == executionThreadId;
528void ProcessorBase::enterHostedSignalFrame() {
529 __atomic_add_fetch(&
information().m_HostedSignalFrameDepth, 1, __ATOMIC_ACQ_REL);
532void ProcessorBase::leaveHostedSignalFrame() {
533 const size_t previous =
534 __atomic_fetch_sub(&
information().m_HostedSignalFrameDepth, 1, __ATOMIC_ACQ_REL);
536 __atomic_store_n(&
information().m_HostedSignalFrameDepth, 0, __ATOMIC_RELEASE);
537 FATAL_NOLOCK(
"Hosted signal-frame depth underflowed");
541bool ProcessorBase::inHostedSignalFrame() {
542 return __atomic_load_n(&
information().m_HostedSignalFrameDepth, __ATOMIC_ACQUIRE) != 0;
545#if PEDIGREE_HOSTED_SMOKE_TESTS
546size_t ProcessorBase::hostedSignalFrameDepthForTest() {
547 return __atomic_load_n(&
information().m_HostedSignalFrameDepth, __ATOMIC_ACQUIRE);
551#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
552void ProcessorBase::setHostedContextSwitchHook(HostedContextSwitchHook hook) {
553 __atomic_store_n(&g_HostedContextSwitchHook, hook, __ATOMIC_RELEASE);
556void ProcessorBase::notifyHostedContextSwitchStage(HostedContextSwitchStage stage) {
557 HostedContextSwitchHook hook = __atomic_load_n(&g_HostedContextSwitchHook, __ATOMIC_ACQUIRE);
575 if (guard.m_Active ||
576 (context != ExecutionContext::WaitableThread && context != ExecutionContext::AtomicThread)) {
577 return TlbInvalidationResult::InvalidContext;
580 guard.m_Active =
true;
581 guard.m_Global =
false;
582 return TlbInvalidationResult::Success;
586 guard.m_Global =
false;
587 guard.m_Active =
false;
593 return guard.m_Active;
607 if (result != TlbInvalidationResult::Success) {
614 if (!guard.m_Active) {
615 return TlbInvalidationResult::InvalidContext;
618 return TlbInvalidationResult::Success;
641void ProcessorBase::_breakpoint() {
646 sigaddset(&set, SIGTRAP);
647 pthread_sigmask(SIG_UNBLOCK, &set, &oset);
649 pthread_sigmask(SIG_SETMASK, &oset, 0);
652void ProcessorBase::_reset() {
657void ProcessorBase::_haltUntilInterrupt() {
664 Processor::_breakpoint();
673#if defined(__APPLE__) && defined(__aarch64__)
674 asm volatile(
"yield");
676 asm volatile(
"pause");
685 Processor::_haltUntilInterrupt();
689#if defined(__APPLE__) && defined(__aarch64__)
690 sys_icache_invalidate(
reinterpret_cast<void*
>(nAddr), 1);
692 __asm__ __volatile__(
"clflush (%0)" ::
"a"(nAddr));
697#if defined(__APPLE__) && defined(__aarch64__)
698 sys_dcache_flush(
reinterpret_cast<void*
>(nAddr), 1);
700 __asm__ __volatile__(
"clflush (%0)" ::
"a"(nAddr));
705#if defined(__APPLE__) && defined(__aarch64__)
706 sys_dcache_flush(
reinterpret_cast<void*
>(nAddr), 1);
708 __asm__ __volatile__(
"clflush (%0)" ::
"a"(nAddr));
713#if defined(__APPLE__) && defined(__aarch64__)
714 if (endAddr > startAddr) {
715 void* start =
reinterpret_cast<void*
>(startAddr);
716 const size_t size = endAddr - startAddr;
717 sys_dcache_flush(start, size);
718 sys_icache_invalidate(start, size);
721 const size_t length = endAddr > startAddr ? endAddr - startAddr : 0;
722 for (
size_t i = 0; i < length; ++i) {
723 __asm__ __volatile__(
"clflush (%0)" ::
"a"(startAddr + i));
static void initialiseProcessor() INITIALISATION_ONLY
void initialisationDone()
static HostedPhysicalMemoryManager & instance()
void initialise(const BootstrapStruct_t &Info) INITIALISATION_ONLY
static void initialiseProcessor() INITIALISATION_ONLY
static void switchAddressSpace(VirtualAddressSpace &oldSpace, VirtualAddressSpace &newSpace)
static PageFaultHandler & instance()
static void restoreState(SchedulerState &state, volatile uintptr_t *pLock=0) NORETURN
static void jumpUser(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
static uintptr_t getInstructionPointer()
static void flushDCache(uintptr_t nAddr)
static void invalidateICache(uintptr_t nAddr)
static bool getInterrupts()
static MUST_USE_RESULT TlbInvalidationResult invalidateAll(void *pAddress)
static void initialise2(const BootstrapStruct_t &Info) INITIALISATION_ONLY
second/last stage in the initialisation of the processor-specific interface
static void setTlsBase(uintptr_t newBase)
static void initialise1(const BootstrapStruct_t &Info) INITIALISATION_ONLY
first stage in the initialisation of the processor-specific interface
static void initialisationDone()
static ProcessorInformation & information()
static void identify(HugeStaticString &str)
static bool saveState(SchedulerState &state)
static bool tlbInvalidationTerminal()
static uintptr_t getDebugBreakpoint(size_t nBpNumber, DebugFlags::FaultType &nFaultType, size_t &nLength, bool &bEnabled)
static bool tlbInvalidationFailureActive()
static size_t m_Initialised
static uintptr_t getStackPointer()
static void disableDebugBreakpoint(size_t nBpNumber)
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static ExecutionContext executionContext()
static void flushDCacheAndInvalidateICache(uintptr_t startAddr, uintptr_t endAddr)
static void setSingleStep(bool bEnable, InterruptState &state)
static void switchState(bool bInterrupts, SchedulerState &a, SchedulerState &b, volatile uintptr_t *pLock=0)
static void endTlbInvalidation(TlbInvalidationGuard &guard)
static void invalidate(void *pAddress)
static uintptr_t getBasePointer()
static void jumpKernel(volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0) NORETURN
static ProcessorInformation m_SafeBspProcessorInformation
static void invalidateDCache(uintptr_t nAddr)
static void enableDebugBreakpoint(size_t nBpNumber, uintptr_t nLinearAddress, DebugFlags::FaultType nFaultType, size_t nLength)
static void saveAndJumpKernel(bool bInterrupts, SchedulerState &s, volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0)
static void setInterrupts(bool bEnable)
static void deinitialise()
static MUST_USE_RESULT TlbInvalidationResult beginTlbInvalidation(TlbInvalidationGuard &guard)
static size_t getDebugBreakpointCount()
static void saveAndJumpUser(bool bInterrupts, SchedulerState &s, volatile uintptr_t *pLock, uintptr_t address, uintptr_t stack, uintptr_t p1=0, uintptr_t p2=0, uintptr_t p3=0, uintptr_t p4=0)
static MUST_USE_RESULT bool closeTlbInvalidationAdmissionForTerminalFailure(TlbInvalidationGuard &guard, TlbInvalidationResult result)
static void haltUntilInterrupt()
static constexpr size_t getPageSize() noexcept
void * getKernelStackBase(size_t *size) const
static void threadExited() NORETURN
void EXPORTED_PUBLIC panic(const char *msg) NORETURN