The Pedigree Project 0.1
hosted/Processor.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
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"
32#endif
33
34#include "HostedPlatform.h"
35#include "InterruptManager.h"
36#include "PhysicalMemoryManager.h"
37#include "SyscallManager.h"
38#include "VirtualAddressSpace.h"
39
40namespace __pedigree_hosted {};
41using namespace __pedigree_hosted;
42
43#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
44namespace {
45ProcessorBase::HostedContextSwitchHook g_HostedContextSwitchHook = nullptr;
46}
47#endif
48
49#include <pthread.h>
50#include <setjmp.h>
51#include <signal.h>
52#include <ucontext.h>
53#include <unistd.h>
54#if defined(__APPLE__) && defined(__aarch64__)
55#include <libkern/OSCacheControl.h>
56#endif
57
58namespace {
59void addHostedIrqSignals(sigset_t& set) {
60 sigaddset(&set, SIGUSR1);
61 sigaddset(&set, SIGUSR2);
62#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
63 sigaddset(&set, SIGURG);
64#endif
65}
66} // namespace
67
68bool ProcessorBase::m_bInterrupts;
69
70#if HAS_SANITIZERS
71// We are basically using fibers as we do scheduling ourselves. So we need to
72// make sure we are annotating these correctly.
73extern "C" {
74// TODO: to use these we need to know the full stack size, but that's not
75// available to us in the switch functions. Need to change Scheduler?
76void __sanitizer_start_switch_fiber(void** fake_stack_save, const void* bottom, size_t size);
77
78void __sanitizer_finish_switch_fiber(void* fake_stack_save, const void** bottom_old,
79 size_t* size_old);
80}
81#endif
82
83typedef void (*jump_func_t)(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
84
85extern "C" {
86#if defined(__APPLE__)
87uintptr_t hosted_kernel_fs_base = 0;
88uintptr_t hosted_user_fs_base = 0;
89
90long hostedCaptureKernelFs() {
91 return 0;
92}
93#else
94extern uintptr_t hosted_kernel_fs_base;
95extern uintptr_t hosted_user_fs_base;
96long hostedCaptureKernelFs();
97#endif
98}
99
100namespace {
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();
105 uintptr_t identity = 0;
106 __builtin_memcpy(&identity, &thread, sizeof(thread));
107 return identity;
108}
109
110pthread_t hostedExecutionThread(uintptr_t identity) {
111 pthread_t thread = {};
112 __builtin_memcpy(&thread, &identity, sizeof(thread));
113 return thread;
114}
115} // namespace
116
119}
120
122 const size_t hostPageSize = HostedPlatform::pageSize();
123 if (!hostPageSize || TargetInfo::getPageSize() < hostPageSize ||
124 (TargetInfo::getPageSize() % hostPageSize) != 0) {
125 panic("Hosted: incompatible target and host page sizes");
126 }
127 NOTICE("HOSTED-PAGE-GEOMETRY: target=" << Dec << TargetInfo::getPageSize()
128 << " host=" << hostPageSize << Hex);
129
130 const uintptr_t executionThreadId = currentHostedExecutionThread();
131 if (!executionThreadId) {
132 panic("Hosted: failed to capture the processor execution thread");
133 }
134 __atomic_store_n(&information().m_HostedExecutionThreadId, executionThreadId, __ATOMIC_RELEASE);
135
136 if (hostedCaptureKernelFs() != 0) {
137 panic("Hosted: failed to capture the host FS base");
138 }
139 hosted_user_fs_base = hosted_kernel_fs_base;
140
145 setInterrupts(false);
146 m_Initialised = 1;
147}
148
150 initialiseMultitasking();
151 m_Initialised = 2;
152}
153
155
157 str.clear();
158 str.append("Hosted Processor");
159}
160
162 return reinterpret_cast<uintptr_t>(__builtin_return_address(0));
163}
164
166 return 0;
167}
168
170 return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
171}
172
173bool ProcessorBase::saveState(SchedulerState& state) {
174 FATAL("ProcessorBase::saveState is NOT safe on HOSTED builds.");
175 return false;
176}
177
178void ProcessorBase::restoreState(SchedulerState& state, volatile uintptr_t* pLock) {
179#if PEDIGREE_HOSTED_FUNCTION_PROFILE
180 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
181#endif
182 if (pLock)
183 *pLock = 1;
184
185#if HAS_SANITIZERS
186 __sanitizer_start_switch_fiber(nullptr, reinterpret_cast<void*>(state.stackBase),
187 state.stackSize);
188#endif
189
190 setcontext(reinterpret_cast<ucontext_t*>(state.state));
191 FATAL("Hosted: setcontext failed in Processor::restoreState");
192 // Does not return.
193}
194
195#if defined(__APPLE__)
196void ProcessorBase::restoreState(SyscallState& state, volatile uintptr_t* pLock) {
197 (void)state;
198 (void)pLock;
199 FATAL("Hosted Darwin does not emulate userspace syscall return");
200 __builtin_unreachable();
201}
202
203void ProcessorBase::jumpUser(volatile uintptr_t* pLock, uintptr_t address, uintptr_t stack,
204 uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) {
205 (void)pLock;
206 (void)address;
207 (void)stack;
208 (void)p1;
209 (void)p2;
210 (void)p3;
211 (void)p4;
212 FATAL("Hosted Darwin does not emulate userspace entry");
213 __builtin_unreachable();
214}
215#endif
216
217#if SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH
218void ProcessorBase::switchState(bool bInterrupts, SchedulerState& a, SchedulerState& b,
219 volatile uintptr_t* pLock) {
220#if PEDIGREE_HOSTED_FUNCTION_PROFILE
221 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
222#endif
223 void* fake_stack_save = nullptr;
224
225 ucontext_t* a_ctx = reinterpret_cast<ucontext_t*>(a.state);
226 ucontext_t* b_ctx = reinterpret_cast<ucontext_t*>(b.state);
227
228 if (pLock)
229 *pLock = 1;
230#if HAS_SANITIZERS
231 __sanitizer_start_switch_fiber(&fake_stack_save, reinterpret_cast<void*>(b.stackBase),
232 b.stackSize);
233#endif
234 swapcontext(a_ctx, b_ctx);
235#if HAS_SANITIZERS
236 __sanitizer_finish_switch_fiber(fake_stack_save, nullptr, nullptr);
237#endif
238#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
239 notifyHostedContextSwitchStage(HostedContextSwitchStage::SwitchStateReturnedMasked);
240#endif
241}
242
243static void syscallStateWrapper(uintptr_t state, uintptr_t lock, uintptr_t sourceState);
244
245void ProcessorBase::switchState(bool bInterrupts, SchedulerState& a, SyscallState& b,
246 volatile uintptr_t* pLock) {
247#if PEDIGREE_HOSTED_FUNCTION_PROFILE
248 hostedFunctionProfileInvalidate(HostedProfileInvalidation::ContextTransfer);
249#endif
250 Thread* target = Processor::information().getCurrentThread();
251 size_t stackSize = 0;
252 void* stackBase = target ? target->getKernelStackBase(&stackSize) : nullptr;
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");
258 }
259
260 ucontext_t newContext;
261 getcontext(&newContext);
262 newContext.uc_stack.ss_sp = stackBase;
263 // The copied state is consumed later by syscall_tail and must not become
264 // part of makecontext's stack frame.
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));
269
270#if HAS_SANITIZERS
271 void* fakeStackSave = nullptr;
272 __sanitizer_start_switch_fiber(&fakeStackSave, newContext.uc_stack.ss_sp,
273 newContext.uc_stack.ss_size);
274#endif
275 swapcontext(reinterpret_cast<ucontext_t*>(a.state), &newContext);
276#if HAS_SANITIZERS
277 __sanitizer_finish_switch_fiber(fakeStackSave, nullptr, nullptr);
278#endif
279#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
280 notifyHostedContextSwitchStage(HostedContextSwitchStage::SwitchStateReturnedMasked);
281#endif
282 Processor::setInterrupts(bInterrupts);
283}
284
285#if HAS_SANITIZERS
286static void finishInitialFiberSwitch(uintptr_t sourceState) {
287 const void* sourceStack = nullptr;
288 size_t sourceStackSize = 0;
289 __sanitizer_finish_switch_fiber(nullptr, &sourceStack, &sourceStackSize);
290
291 SchedulerState* source = reinterpret_cast<SchedulerState*>(sourceState);
292 if (source) {
293 source->stackBase = reinterpret_cast<uintptr_t>(sourceStack);
294 source->stackSize = sourceStackSize;
295 }
296}
297#endif
298
299static void syscallStateWrapper(uintptr_t state, uintptr_t lock, uintptr_t sourceState) {
300#if HAS_SANITIZERS
301 finishInitialFiberSwitch(sourceState);
302#else
303 (void)sourceState;
304#endif
305
306 volatile uintptr_t* sourceLock = reinterpret_cast<volatile uintptr_t*>(lock);
307 if (sourceLock) {
308 *sourceLock = 1;
309 }
310 // A syscall return enters userspace with IRQs enabled even if clone's
311 // kernel-side publication temporarily masked them.
313 Processor::restoreState(*reinterpret_cast<SyscallState*>(state), nullptr);
314}
315
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,
318 uintptr_t p4) {
319#if HAS_SANITIZERS
320 finishInitialFiberSwitch(sourceState);
321#else
322 (void)sourceState;
323#endif
324
325 if (pLock) {
326 // unlock other thread now that we are on the new stack
327 *pLock = 1;
328 }
329 // The saved interrupt state belongs to the thread which created us.
330 // Native kernel-thread entry always starts with interrupts enabled.
331 (void)bInterrupts;
333 auto entry = reinterpret_cast<void (*)(uintptr_t, uintptr_t, uintptr_t, uintptr_t)>(func);
334 entry(p1, p2, p3, p4);
336}
337
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) {
341#if HAS_SANITIZERS
342 finishInitialFiberSwitch(sourceState);
343#else
344 (void)sourceState;
345#endif
346
347 if (pLock) {
348 // The wrapper is already running on the new kernel stack.
349 *pLock = 1;
350 }
351 Processor::setInterrupts(bInterrupts != 0);
352
353 // The ELF interpreter consumes the initial process state directly from
354 // RSP, so the final transition cannot use a C call frame.
355 Processor::jumpUser(nullptr, func, stack, p1, p2, p3, p4);
356}
357
358void ProcessorBase::jumpKernel(volatile uintptr_t* pLock, uintptr_t address, uintptr_t stack,
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");
361}
362
363void ProcessorBase::saveAndJumpKernel(bool bInterrupts, SchedulerState& s,
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);
368#endif
369 assert(stack);
370
371 uintptr_t stackBottom = stack - KERNEL_STACK_SIZE;
372
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);
381
382#if HAS_SANITIZERS
383 void* fake_stack_save = nullptr;
384 // NOTICE("make sp [saveAndJumpKernel]: " << new_context.uc_stack.ss_sp);
385 // NOTICE(" old -> " << reinterpret_cast<ucontext_t *>(s.state) << " / sp=" <<
386 // reinterpret_cast<ucontext_t *>(s.state)->uc_stack.ss_sp);
387 __sanitizer_start_switch_fiber(&fake_stack_save, new_context.uc_stack.ss_sp,
388 new_context.uc_stack.ss_size);
389#endif
390 swapcontext(reinterpret_cast<ucontext_t*>(s.state), &new_context);
391#if HAS_SANITIZERS
392 __sanitizer_finish_switch_fiber(fake_stack_save, nullptr, nullptr);
393#endif
394}
395
396void ProcessorBase::saveAndJumpUser(bool bInterrupts, SchedulerState& s, volatile uintptr_t* pLock,
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);
401#endif
402 assert(stack);
403
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);
412
413#if HAS_SANITIZERS
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);
417#endif
418 swapcontext(reinterpret_cast<ucontext_t*>(s.state), &new_context);
419#if HAS_SANITIZERS
420 __sanitizer_finish_switch_fiber(fake_stack_save, nullptr, nullptr);
421#endif
422}
423#endif // SYSTEM_REQUIRES_ATOMIC_CONTEXT_SWITCH
424
426 ProcessorInformation& info = Processor::information();
427 if (&info.getVirtualAddressSpace() != &AddressSpace) {
428 HostedVirtualAddressSpace::switchAddressSpace(info.getVirtualAddressSpace(), AddressSpace);
429 info.setVirtualAddressSpace(AddressSpace);
430 }
431}
432
433void ProcessorBase::setTlsBase(uintptr_t newBase) {
434 // Kernel code retains the host runtime's FS base. The raw user transition
435 // installs this value after all C++ work is complete.
436 hosted_user_fs_base = newBase;
437}
438
440 return 0;
441}
442
443uintptr_t ProcessorBase::getDebugBreakpoint(size_t nBpNumber, DebugFlags::FaultType& nFaultType,
444 size_t& nLength, bool& bEnabled) {
445 // no-op on hosted
446 return 0;
447}
448
449void ProcessorBase::enableDebugBreakpoint(size_t nBpNumber, uintptr_t nLinearAddress,
450 DebugFlags::FaultType nFaultType, size_t nLength) {
451 // no-op on hosted
452}
453
454void ProcessorBase::disableDebugBreakpoint(size_t nBpNumber) {
455 // no-op on hosted
456}
457
458void ProcessorBase::setInterrupts(bool bEnable) {
459#if PEDIGREE_HOSTED_FUNCTION_PROFILE
460 if (bEnable) {
461 hostedFunctionProfileInvalidate(HostedProfileInvalidation::InterruptEnable);
462 }
463#endif
464 // Block signals to toggle "interrupts".
465 sigset_t set;
466 if (bEnable) {
467 sigemptyset(&set);
468#if THREADS
469 Thread* current = Processor::information().getCurrentThread();
470 const bool signalFrameOnCurrentStack =
471 current ? current->getHostedSignalDepth() : inHostedSignalFrame();
472 if (signalFrameOnCurrentStack) {
473 // SS_AUTODISARM lets another Thread or state stack take an IRQ
474 // while this physical stack retains its suspended signal frame.
475 addHostedIrqSignals(set);
476 }
477#endif
478 } else {
479 sigemptyset(&set);
480
481 // Timer signals and the smoke-only synthetic device signal are true
482 // interrupts. Exceptions remain deliverable while IRQs are disabled.
483 addHostedIrqSignals(set);
484 }
485
486 // We must mark interrupts enabled before we unmask signals, as any pending
487 // signals may trigger immediately (and will cause problems if interrupts
488 // are marked as disabled)
489 if (bEnable) {
490 m_bInterrupts = true;
491 }
492
493 int r = pthread_sigmask(SIG_SETMASK, &set, 0);
494 if (r != 0) {
495 ERROR("ProcessorBase::setInterrupts failed to set new mask");
496 }
497
498 // We can only mark interrupts disabled after masking signals as during the
499 // mask operation signals may still come in. Setting the flag here means
500 // those signals are handled correctly.
501 if (!bEnable) {
502 m_bInterrupts = false;
503 }
504}
505
507 return m_bInterrupts;
508}
509
510void ProcessorBase::maskInterruptsForSignalReturn() {
511 sigset_t set;
512 sigemptyset(&set);
513 addHostedIrqSignals(set);
514 if (pthread_sigmask(SIG_BLOCK, &set, nullptr) != 0) {
515 FATAL_NOLOCK("Hosted signal return failed to mask IRQ signals");
516 }
517}
518
519uintptr_t ProcessorBase::hostedExecutionThreadId() {
520 return __atomic_load_n(&information().m_HostedExecutionThreadId, __ATOMIC_ACQUIRE);
521}
522
523bool ProcessorBase::onHostedExecutionThread() {
524 const uintptr_t executionThreadId = hostedExecutionThreadId();
525 return executionThreadId && currentHostedExecutionThread() == executionThreadId;
526}
527
528void ProcessorBase::enterHostedSignalFrame() {
529 __atomic_add_fetch(&information().m_HostedSignalFrameDepth, 1, __ATOMIC_ACQ_REL);
530}
531
532void ProcessorBase::leaveHostedSignalFrame() {
533 const size_t previous =
534 __atomic_fetch_sub(&information().m_HostedSignalFrameDepth, 1, __ATOMIC_ACQ_REL);
535 if (UNLIKELY(!previous)) {
536 __atomic_store_n(&information().m_HostedSignalFrameDepth, 0, __ATOMIC_RELEASE);
537 FATAL_NOLOCK("Hosted signal-frame depth underflowed");
538 }
539}
540
541bool ProcessorBase::inHostedSignalFrame() {
542 return __atomic_load_n(&information().m_HostedSignalFrameDepth, __ATOMIC_ACQUIRE) != 0;
543}
544
545#if PEDIGREE_HOSTED_SMOKE_TESTS
546size_t ProcessorBase::hostedSignalFrameDepthForTest() {
547 return __atomic_load_n(&information().m_HostedSignalFrameDepth, __ATOMIC_ACQUIRE);
548}
549#endif
550
551#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
552void ProcessorBase::setHostedContextSwitchHook(HostedContextSwitchHook hook) {
553 __atomic_store_n(&g_HostedContextSwitchHook, hook, __ATOMIC_RELEASE);
554}
555
556void ProcessorBase::notifyHostedContextSwitchStage(HostedContextSwitchStage stage) {
557 HostedContextSwitchHook hook = __atomic_load_n(&g_HostedContextSwitchHook, __ATOMIC_ACQUIRE);
558 if (hook) {
559 hook(stage);
560 }
561}
562
563#endif
564
565void ProcessorBase::setSingleStep(bool bEnable, InterruptState& state) {
566 // no-op on hosted
567}
568
569void ProcessorBase::invalidate(void* pAddress) {
570 // no-op on hosted
571}
572
574 const ExecutionContext context = executionContext();
575 if (guard.m_Active ||
576 (context != ExecutionContext::WaitableThread && context != ExecutionContext::AtomicThread)) {
577 return TlbInvalidationResult::InvalidContext;
578 }
579
580 guard.m_Active = true;
581 guard.m_Global = false;
582 return TlbInvalidationResult::Success;
583}
584
586 guard.m_Global = false;
587 guard.m_Active = false;
588}
589
591 TlbInvalidationResult result) {
592 (void)result;
593 return guard.m_Active;
594}
595
597 return false;
598}
599
601 return false;
602}
603
606 const TlbInvalidationResult result = beginTlbInvalidation(guard);
607 if (result != TlbInvalidationResult::Success) {
608 return result;
609 }
610 return invalidateAll(pAddress, guard);
611}
612
614 if (!guard.m_Active) {
615 return TlbInvalidationResult::InvalidContext;
616 }
617 invalidate(pAddress);
618 return TlbInvalidationResult::Success;
619}
620
622 return 0;
623}
624
625size_t ProcessorBase::index() {
626 return 0;
627}
628
629ProcessorInformation& ProcessorBase::information() {
631}
632
634 return 1;
635}
636
637#include <sched.h>
638#include <stdlib.h>
639#include <unistd.h>
640
641void ProcessorBase::_breakpoint() {
642 sigset_t set;
643 sigset_t oset;
644 sigemptyset(&set);
645 sigemptyset(&oset);
646 sigaddset(&set, SIGTRAP);
647 pthread_sigmask(SIG_UNBLOCK, &set, &oset);
648 raise(SIGTRAP);
649 pthread_sigmask(SIG_SETMASK, &oset, 0);
650}
651
652void ProcessorBase::_reset() {
653 // Just exit.
654 exit(0);
655}
656
657void ProcessorBase::_haltUntilInterrupt() {
658 sigset_t set;
659 sigemptyset(&set);
660 sigsuspend(&set);
661}
662
664 Processor::_breakpoint();
665}
666
667void ProcessorBase::halt() {
668 // Abnormal exit.
669 __builtin_trap();
670}
671
673#if defined(__APPLE__) && defined(__aarch64__)
674 asm volatile("yield");
675#else
676 asm volatile("pause");
677#endif
678}
679
681 Processor::_reset();
682}
683
685 Processor::_haltUntilInterrupt();
686}
687
688void ProcessorBase::invalidateICache(uintptr_t nAddr) {
689#if defined(__APPLE__) && defined(__aarch64__)
690 sys_icache_invalidate(reinterpret_cast<void*>(nAddr), 1);
691#else
692 __asm__ __volatile__("clflush (%0)" ::"a"(nAddr));
693#endif
694}
695
696void ProcessorBase::invalidateDCache(uintptr_t nAddr) {
697#if defined(__APPLE__) && defined(__aarch64__)
698 sys_dcache_flush(reinterpret_cast<void*>(nAddr), 1);
699#else
700 __asm__ __volatile__("clflush (%0)" ::"a"(nAddr));
701#endif
702}
703
704void ProcessorBase::flushDCache(uintptr_t nAddr) {
705#if defined(__APPLE__) && defined(__aarch64__)
706 sys_dcache_flush(reinterpret_cast<void*>(nAddr), 1);
707#else
708 __asm__ __volatile__("clflush (%0)" ::"a"(nAddr));
709#endif
710}
711
712void ProcessorBase::flushDCacheAndInvalidateICache(uintptr_t startAddr, uintptr_t endAddr) {
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);
719 }
720#else
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));
724 }
725#endif
726}
static void initialiseProcessor() INITIALISATION_ONLY
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 halt()
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 ProcessorId id()
static void reset()
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 size_t getCount()
static void pause()
static uintptr_t getDebugBreakpoint(size_t nBpNumber, DebugFlags::FaultType &nFaultType, size_t &nLength, bool &bEnabled)
static bool tlbInvalidationFailureActive()
static void breakpoint()
static size_t m_Initialised
Definition Processor.h:475
static uintptr_t getStackPointer()
static void disableDebugBreakpoint(size_t nBpNumber)
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static ExecutionContext executionContext()
Definition Processor.cc:109
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
Definition Processor.h:508
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 size_t index()
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
Definition TargetInfo.h:40
void * getKernelStackBase(size_t *size) const
Definition Thread.cc:1054
static void threadExited() NORETURN
Definition Thread.cc:1004
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:117
#define assert(x)
Definition assert.h:39
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
size_t ProcessorId
TlbInvalidationResult
Definition Processor.h:55