The Pedigree Project 0.1
Processor.h
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#ifndef KERNEL_PROCESSOR_PROCESSOR_H
21#define KERNEL_PROCESSOR_PROCESSOR_H
22#include "pedigree/kernel/LatencyAccounting.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/process/ExecutionContext.h"
25#include "pedigree/kernel/processor/ProcessorInformation.h" // exported
26#include "pedigree/kernel/processor/state_forward.h"
27#include "pedigree/kernel/processor/types.h"
28#include "pedigree/kernel/utilities/StaticString.h"
29
30#include <config.h>
31
32template <class T>
33class Vector;
34
37
41namespace DebugFlags {
42enum FaultType { InstructionFetch = 0, DataWrite = 1, IOReadWrite = 2, DataReadWrite = 3 };
43}
44
47 Schedule,
48 SemaphoreAcquire,
49 SemaphoreRelease,
50 WaitQueueAccess,
51 HeapAllocate,
52 HeapFree,
53};
54
57 Success,
58 InvalidContext,
59 UnsupportedTopology,
60 SerialisationTimedOut,
61 SubmissionFailed,
62 AcknowledgementTimedOut,
63 DrainTimedOut,
64};
65
66class ProcessorBase;
67
76 friend class ProcessorBase;
77
78 public:
79 TlbInvalidationGuard() : m_Active(false), m_Global(false) {}
81
87
89 void retire();
90
92 TlbInvalidationGuard& operator=(const TlbInvalidationGuard&) = delete;
93
94 private:
95 bool m_Active;
96 bool m_Global;
97};
98
100#define DEBUG_BREAKPOINT_0 0x01
101#define DEBUG_BREAKPOINT_1 0x02
102#define DEBUG_BREAKPOINT_2 0x04
103#define DEBUG_BREAKPOINT_3 0x08
104#define DEBUG_REG_ACCESS \
105 0x2000
107#define DEBUG_SINGLE_STEP \
108 0x4000
110#define DEBUG_TASK_SWITCH 0x8000
111
117extern void apMain() NORETURN;
118
129class EXPORTED_PUBLIC ProcessorBase {
130 friend class Multiprocessor;
131 friend class TlbInvalidationGuard;
132 friend class X86GdtManager;
133 friend class X64GdtManager;
134 friend class Scheduler;
135
136 public:
144 static void initialise1(const BootstrapStruct_t& Info) INITIALISATION_ONLY;
151 static void initialise2(const BootstrapStruct_t& Info) INITIALISATION_ONLY;
154 static void initialisationDone();
157 static void deinitialise();
162 static size_t isInitialised();
163
166 static uintptr_t getBasePointer();
169 static uintptr_t getStackPointer();
172 static uintptr_t getInstructionPointer();
173
176 static void switchAddressSpace(VirtualAddressSpace& AddressSpace);
177
182 static bool saveState(SchedulerState& state);
186 static void restoreState(SchedulerState& state, volatile uintptr_t* pLock = 0) NORETURN;
190 static void restoreState(SyscallState& state, volatile uintptr_t* pLock = 0) NORETURN;
191#if X64
198 static void contextSwitch(InterruptState* state) NORETURN;
199#endif
201 static void switchState(bool bInterrupts, SchedulerState& a, SchedulerState& b,
202 volatile uintptr_t* pLock = 0);
204 static void switchState(bool bInterrupts, SchedulerState& a, SyscallState& b,
205 volatile uintptr_t* pLock = 0);
216 static void saveAndJumpKernel(bool bInterrupts, SchedulerState& s, volatile uintptr_t* pLock,
217 uintptr_t address, uintptr_t stack, uintptr_t p1 = 0,
218 uintptr_t p2 = 0, uintptr_t p3 = 0, uintptr_t p4 = 0);
229 static void saveAndJumpUser(bool bInterrupts, SchedulerState& s, volatile uintptr_t* pLock,
230 uintptr_t address, uintptr_t stack, uintptr_t p1 = 0,
231 uintptr_t p2 = 0, uintptr_t p3 = 0, uintptr_t p4 = 0);
241 static void jumpKernel(volatile uintptr_t* pLock, uintptr_t address, uintptr_t stack,
242 uintptr_t p1 = 0, uintptr_t p2 = 0, uintptr_t p3 = 0,
243 uintptr_t p4 = 0) NORETURN;
253 static void jumpUser(volatile uintptr_t* pLock, uintptr_t address, uintptr_t stack,
254 uintptr_t p1 = 0, uintptr_t p2 = 0, uintptr_t p3 = 0,
255 uintptr_t p4 = 0) NORETURN;
256
258 static void breakpoint();
260 static void halt();
262 static void reset();
263
266 static size_t getDebugBreakpointCount();
272 static uintptr_t getDebugBreakpoint(size_t nBpNumber, DebugFlags::FaultType& nFaultType,
273 size_t& nLength, bool& bEnabled);
280 static void enableDebugBreakpoint(size_t nBpNumber, uintptr_t nLinearAddress,
281 DebugFlags::FaultType nFaultType, size_t nLength);
285 static void disableDebugBreakpoint(size_t nBpNumber);
289 static uintptr_t getDebugStatus();
290
292 static void haltUntilInterrupt();
294 static void pause();
295
298 static void setInterrupts(bool bEnable);
301 static bool getInterrupts();
302
303#if HOSTED
308 static void maskInterruptsForSignalReturn();
310 static uintptr_t hostedExecutionThreadId();
312 static bool onHostedExecutionThread();
314 static void enterHostedSignalFrame();
316 static void leaveHostedSignalFrame();
318 static bool inHostedSignalFrame();
319#if PEDIGREE_HOSTED_SMOKE_TESTS
321 static size_t hostedSignalFrameDepthForTest();
322#endif
323#endif
324
326 static bool inDeviceHardIrq();
327
332 static ExecutionContext executionContext();
333
341 static bool guardDeviceHardIrqOperation(DeviceHardIrqOperation operation);
342#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
344 static size_t deviceHardIrqDepthForTest();
345
346 using DeviceHardIrqOperationHook = bool (*)(DeviceHardIrqOperation operation);
347
352 static void setDeviceHardIrqOperationHookForTest(DeviceHardIrqOperationHook hook);
353
355 static size_t deviceHardIrqOperationDenialsForTest();
356
357 enum class HostedContextSwitchStage {
358 SwitchStateReturnedMasked,
359 SchedulerBookkeepingComplete,
360 SchedulerRestoringInterrupts,
361 };
362
363 using HostedContextSwitchHook = void (*)(HostedContextSwitchStage stage);
364
366 static void setHostedContextSwitchHook(HostedContextSwitchHook hook);
367
369 static void notifyHostedContextSwitchStage(HostedContextSwitchStage stage);
370
371#endif
375 static void setSingleStep(bool bEnable, InterruptState& state);
376
380 static void invalidate(void* pAddress);
381
391 MUST_USE_RESULT static TlbInvalidationResult beginTlbInvalidation(TlbInvalidationGuard& guard);
392
410 MUST_USE_RESULT static TlbInvalidationResult invalidateAll(void* pAddress);
411
413 MUST_USE_RESULT static TlbInvalidationResult invalidateAll(void* pAddress,
414 TlbInvalidationGuard& guard);
415
416#if X86_COMMON && !HOSTED
418 MUST_USE_RESULT static TlbInvalidationResult invalidateProcessors(void* pAddress,
420 uint64_t processors);
421#endif
422
424 static bool tlbInvalidationFailureActive();
425
427 static bool tlbInvalidationTerminal();
428
432 static void invalidateICache(uintptr_t nAddr);
436 static void invalidateDCache(uintptr_t nAddr);
440 static void flushDCache(uintptr_t nAddr);
446 static void flushDCacheAndInvalidateICache(uintptr_t startAddr, uintptr_t endAddr);
447
450 static void identify(HugeStaticString& str);
451
455 static ProcessorId id();
456
462 static size_t index();
463
466 static ProcessorInformation& information();
467
469 static ProcessorInformation* informationAt(size_t cpu);
470
472 static size_t getCount();
473
475 static void setTlsBase(uintptr_t newBase);
476
477#if X64 && !HOSTED
478 static uintptr_t getUserGsBase();
479 static void setUserGsBase(uintptr_t newBase);
480#endif
481
483 static size_t m_Initialised;
484
485 private:
486 static NEVER_INLINE __attribute__((cold)) bool rejectDeviceHardIrqOperation(
487 DeviceHardIrqOperation operation);
488
489#if X64
490 // Constant-initialized independently of the BSP information constructor.
491 static ProcessorInformation::KernelGsAnchor m_BootstrapKernelGsAnchor;
492#endif
493
495 MUST_USE_RESULT static bool closeTlbInvalidationAdmissionForTerminalFailure(
497
499 static void endTlbInvalidation(TlbInvalidationGuard& guard);
500
501#if HOSTED
503 static void _breakpoint();
504 static void _reset() NORETURN;
505 static void _haltUntilInterrupt();
506
507 static bool m_bInterrupts;
508#endif
509
513
516 static ProcessorInformation m_SafeBspProcessorInformation;
517
518 static size_t m_nProcessors;
519};
520
521#if X86_COMMON && !HOSTED && !PEDIGREE_BUILDUTILS && defined(IN_PEDIGREE_KERNEL) && \
522 !STANDALONE_MUTEXES
523ALWAYS_INLINE inline void ProcessorBase::setInterrupts(bool bEnable) {
524 if (bEnable) {
525#if PEDIGREE_LATENCY_ACCOUNTING
526 if (!getInterrupts()) {
527 pedigree_irq_time_state(true);
528 }
529#endif
530 // Consume the STI shadow before the caller's next instruction.
531 asm volatile("sti\n\tnop" : : : "memory", "cc");
532 } else {
533 asm volatile("cli" : : : "memory", "cc");
534#if PEDIGREE_LATENCY_ACCOUNTING
535 pedigree_irq_time_state(false);
536#endif
537 }
538}
539
541 size_t flags;
542 asm volatile("pushf\n\tpop %0" : "=r"(flags) : : "memory", "cc");
543 return (flags & 0x200) != 0;
544}
545#endif
546
547inline TlbInvalidationGuard::~TlbInvalidationGuard() {
548 retire();
549}
550
554
556 if (m_Active) {
558 }
559}
560
563#include "pedigree/kernel/processor/arm64/Processor.h" // IWYU pragma: export
564#include "pedigree/kernel/processor/armv7/Processor.h" // IWYU pragma: export
565#include "pedigree/kernel/processor/hosted/Processor.h" // IWYU pragma: export
566#include "pedigree/kernel/processor/x64/Processor.h" // IWYU pragma: export
567#include "pedigree/kernel/processor/x86_common/Processor.h" // IWYU pragma: export
568
569#if X64
570typedef X64Processor Processor;
571#elif ARM64
573#elif ARMV7
575#elif HOSTED
577#else
578#error No Processor type could be defined.
579#endif
580
582 return information().m_DeviceHardIrqDepth != 0;
583}
584
586 DeviceHardIrqOperation operation) {
587 if (LIKELY(!inDeviceHardIrq())) {
588 return true;
589 }
590 return rejectDeviceHardIrqOperation(operation);
591}
592
598 public:
599 EnsureInterrupts(bool desired);
600 virtual ~EnsureInterrupts();
601
602 private:
603 bool m_bPrevious;
604};
605
606#endif
static bool getInterrupts()
static ProcessorInformation & information()
static void contextSwitch(InterruptState *state) NORETURN
static size_t m_Initialised
Definition Processor.h:483
static bool inDeviceHardIrq()
Definition Processor.h:581
static Vector< ProcessorInformation * > m_ProcessorInformation
Definition Processor.h:512
static bool guardDeviceHardIrqOperation(DeviceHardIrqOperation operation)
Definition Processor.h:585
static void endTlbInvalidation(TlbInvalidationGuard &guard)
static ProcessorInformation m_SafeBspProcessorInformation
Definition Processor.h:516
static void setInterrupts(bool bEnable)
static MUST_USE_RESULT bool closeTlbInvalidationAdmissionForTerminalFailure(TlbInvalidationGuard &guard, TlbInvalidationResult result)
This class manages how processes and threads are scheduled across processors.
Definition Scheduler.h:50
A vector / dynamic array.
Definition Vector.h:33
size_t ProcessorId
void apMain() NORETURN
MUST_USE_RESULT bool closeAdmissionForTerminalFailure(TlbInvalidationResult result)
Definition Processor.h:551
DeviceHardIrqOperation
Definition Processor.h:46
TlbInvalidationResult
Definition Processor.h:56