20#include "pedigree/kernel/ActivityDiagnostics.h"
21#include "pedigree/kernel/BootstrapInfo.h"
22#include "pedigree/kernel/panic.h"
23#include "pedigree/kernel/processor/Processor.h"
24#include "pedigree/kernel/processor/ProcessorInformation.h"
25#include "pedigree/kernel/processor/VirtualAddressSpace.h"
26#include "pedigree/kernel/processor/state.h"
27#include "pedigree/kernel/processor/x86_common/ProcessorInformation.h"
28#include "pedigree/kernel/utilities/Vector.h"
30#include "../x64/VirtualAddressSpace.h"
31#include "PhysicalMemoryManager.h"
32#include <machine/mach_pc/LocalApic.h>
33#include <machine/mach_pc/Pc.h>
37 g_pBootstrapInfo =
nullptr;
42 *
reinterpret_cast<uint64_t*
>(KernelAddressSpace.
m_PhysicalPML4) = 0;
53 size_t& nLength,
bool& bEnabled) {
54 uintptr_t nLinearAddress = 0;
57 asm volatile(
"mov %%db0, %0" :
"=r"(nLinearAddress));
60 asm volatile(
"mov %%db1, %0" :
"=r"(nLinearAddress));
63 asm volatile(
"mov %%db2, %0" :
"=r"(nLinearAddress));
66 asm volatile(
"mov %%db3, %0" :
"=r"(nLinearAddress));
71 asm volatile(
"mov %%db7, %0" :
"=r"(nStatus));
73 bEnabled =
static_cast<bool>(nStatus & (1 << (nBpNumber * 2 + 1)));
74 nFaultType =
static_cast<DebugFlags::FaultType
>((nStatus >> (nBpNumber * 4 + 16)) & 0x3);
75 switch ((nStatus >> (nBpNumber * 4 + 18)) & 0x3) {
90 return nLinearAddress;
94 DebugFlags::FaultType nFaultType,
size_t nLength) {
97 asm volatile(
"mov %0, %%db0" ::
"r"(nLinearAddress));
100 asm volatile(
"mov %0, %%db1" ::
"r"(nLinearAddress));
103 asm volatile(
"mov %0, %%db2" ::
"r"(nLinearAddress));
106 asm volatile(
"mov %0, %%db3" ::
"r"(nLinearAddress));
111 asm volatile(
"mov %%db7, %0" :
"=r"(nStatus));
113 size_t lengthField = 0;
129 nStatus |= 1 << (nBpNumber * 2 + 1);
130 nStatus |= (nFaultType & 0x3) << (nBpNumber * 4 + 16);
131 nStatus |= (lengthField & 0x3) << (nBpNumber * 4 + 18);
132 asm volatile(
"mov %0, %%db7" ::
"r"(nStatus));
137 asm volatile(
"mov %%db7, %0" :
"=r"(nStatus));
139 nStatus &= ~(1 << (nBpNumber * 2 + 1));
140 asm volatile(
"mov %0, %%db7" ::
"r"(nStatus));
150 uintptr_t eflags = state.getFlags();
155 state.setFlags(eflags);
160 asm volatile(
"rdmsr" :
"=a"(eax),
"=d"(edx) :
"c"(
index));
161 return static_cast<uint64_t
>(eax) | (
static_cast<uint64_t
>(edx) << 32);
165 uint32_t eax = value, edx = value >> 32;
166 asm volatile(
"wrmsr" ::
"a"(eax),
"d"(edx),
"c"(
index));
170 asm volatile(
"invlpg (%0)" ::
"a"(pAddress));
175 if (guard.m_Active ||
176 (context != ExecutionContext::WaitableThread && context != ExecutionContext::AtomicThread)) {
177 return TlbInvalidationResult::InvalidContext;
182 Pc& pc = Pc::instance();
184 return TlbInvalidationResult::UnsupportedTopology;
189 if (result != TlbInvalidationResult::Success) {
192 guard.m_Global = global;
196 guard.m_Active =
true;
197 return TlbInvalidationResult::Success;
202 if (guard.m_Global) {
203 Pc::instance().getLocalApic().endTlbInvalidation();
206 guard.m_Global =
false;
207 guard.m_Active =
false;
212 if (!guard.m_Active) {
217 if (guard.m_Global) {
218 return Pc::instance().getLocalApic().closeTlbInvalidationAdmissionForTerminalFailure(result);
228 Pc& pc = Pc::instance();
238 Pc& pc = Pc::instance();
248 if (result != TlbInvalidationResult::Success) {
258 if (invalidation == TlbInvalidationResult::Success) {
274 switch (invalidation) {
275 case TlbInvalidationResult::InvalidContext:
276 panic(
"TLB invalidation failed from an invalid context");
277 case TlbInvalidationResult::UnsupportedTopology:
278 panic(
"TLB invalidation has no safe all-processor route");
279 case TlbInvalidationResult::SerialisationTimedOut:
280 panic(
"TLB invalidation serialisation timed out");
281 case TlbInvalidationResult::SubmissionFailed:
282 panic(
"TLB invalidation IPI submission failed");
283 case TlbInvalidationResult::AcknowledgementTimedOut:
284 panic(
"TLB invalidation acknowledgement timed out");
285 case TlbInvalidationResult::DrainTimedOut:
286 panic(
"TLB invalidation service drain timed out");
287 case TlbInvalidationResult::Success:
290 panic(
"TLB invalidation returned an unknown result");
299 uint64_t processors) {
300 if (!guard.m_Active) {
301 return TlbInvalidationResult::InvalidContext;
305 if (guard.m_Global) {
306 return Pc::instance().getLocalApic().invalidateAllProcessors(pAddress, processors);
311 return TlbInvalidationResult::Success;
315 uint32_t& ecx, uint32_t& edx) {
316 asm volatile(
"cpuid" :
"=a"(eax),
"=b"(ebx),
"=c"(ecx),
"=d"(edx) :
"a"(inEax),
"c"(inEcx));
319#if MULTIPROCESSOR && !X64
322 Pc& pc = Pc::instance();
329 const uint8_t apicId = pc.getLocalApic().getId();
330 for (
size_t i = 0; i < processors.
count(); ++i) {
331 ProcessorInformation* information = processors.
begin()[i];
332 if (information->localApicId() == apicId) {
341 *processorIndex = processors.
count();
386 return count ? count : 1;
393 asm volatile(
"int $3");
406 Pc& pc = Pc::instance();
408 pc.getLocalApic().servicePendingTlbShootdown();
409 pc.getLocalApic().servicePendingTerminalProcessorControl();
413 asm volatile(
"pause");
421 }
PACKED emptyIdt = {0, 0};
422 asm volatile(
"cli; lidt %0; int $3" : :
"m"(emptyIdt) :
"memory");
426#if PEDIGREE_ACTIVITY_DIAGNOSTICS
427 ActivityDiagnostics::recordIdleHalt();
430#if PEDIGREE_LATENCY_ACCOUNTING
431 asm volatile(
"cli" : : :
"memory",
"cc");
432 pedigree_irq_time_state(
true);
434 __asm__ __volatile__(
"sti; hlt");
440 __asm__ __volatile__(
"clflush (%0)" ::
"a"(nAddr));
444 __asm__ __volatile__(
"clflush (%0)" ::
"a"(nAddr));
448 __asm__ __volatile__(
"clflush (%0)" ::
"a"(nAddr));
452 const size_t length = endAddr > startAddr ? endAddr - startAddr : 0;
453 for (
size_t i = 0; i < length; ++i) {
454 __asm__ __volatile__(
"clflush (%0)" ::
"a"(startAddr + i));
bool localApicAvailable() const
static MUST_USE_RESULT TlbInvalidationResult invalidateProcessors(void *pAddress, TlbInvalidationGuard &guard, uint64_t processors)
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 initialisationDone()
static ProcessorInformation & information()
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 void disableDebugBreakpoint(size_t nBpNumber)
static Vector< ProcessorInformation * > m_ProcessorInformation
static ExecutionContext executionContext()
static void flushDCacheAndInvalidateICache(uintptr_t startAddr, uintptr_t endAddr)
static void setSingleStep(bool bEnable, InterruptState &state)
static void endTlbInvalidation(TlbInvalidationGuard &guard)
static void invalidate(void *pAddress)
static void invalidateDCache(uintptr_t nAddr)
static void enableDebugBreakpoint(size_t nBpNumber, uintptr_t nLinearAddress, DebugFlags::FaultType nFaultType, size_t nLength)
static void setInterrupts(bool bEnable)
static MUST_USE_RESULT TlbInvalidationResult beginTlbInvalidation(TlbInvalidationGuard &guard)
static size_t getDebugBreakpointCount()
static MUST_USE_RESULT bool closeTlbInvalidationAdmissionForTerminalFailure(TlbInvalidationGuard &guard, TlbInvalidationResult result)
static void haltUntilInterrupt()
A vector / dynamic array.
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
physical_uintptr_t m_PhysicalPML4
static X86CommonPhysicalMemoryManager & instance()
void initialisationDone()
static void cpuid(uint32_t inEax, uint32_t inEcx, uint32_t &eax, uint32_t &ebx, uint32_t &ecx, uint32_t &edx)
static void writeMachineSpecificRegister(uint32_t index, uint64_t value)
static uint64_t readMachineSpecificRegister(uint32_t index)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
MUST_USE_RESULT bool closeAdmissionForTerminalFailure(TlbInvalidationResult result)