24#include "pedigree/kernel/Log.h"
25#include "pedigree/kernel/machine/SchedulerTimerDispatchCleanup.h"
26#include "pedigree/kernel/machine/SchedulerTimerHandler.h"
27#include "pedigree/kernel/processor/InterruptManager.h"
28#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
29#include "pedigree/kernel/processor/Processor.h"
30#include "pedigree/kernel/processor/VirtualAddressSpace.h"
31#include "pedigree/kernel/time/Time.h"
34#include "LocalApicIcrTransaction.h"
35#include "LocalApicLint0Policy.h"
36#include "LocalApicMode.h"
38#define LAPIC_REG_ID 0x0020
39#define LAPIC_REG_VERSION 0x0030
40#define LAPIC_REG_TASK_PRIORITY 0x0080
41#define LAPIC_REG_PROCESSOR_PRIORITY 0x00A0
42#define LAPIC_REG_EOI 0x00B0
43#define LAPIC_REG_LOGICAL_DESTINATION 0x00D0
44#define LAPIC_REG_DESTINATION_FORMAT 0x00E0
45#define LAPIC_REG_SPURIOUS_INT 0x00F0
49#define LAPIC_REG_ERR_STATUS 0x0280
50#define LAPIC_REG_INT_CMD_LOW 0x0300
51#define LAPIC_REG_INT_CMD_HIGH 0x0310
52#define LAPIC_REG_LVT_TIMER 0x0320
53#define LAPIC_REG_LVT_THERMAL 0x0330
54#define LAPIC_REG_LVT_PERFORMANCE 0x0340
55#define LAPIC_REG_LVT_LINT0 0x0350
56#define LAPIC_REG_LVT_LINT1 0x0360
57#define LAPIC_REG_LVT_ERROR 0x0370
58#define LAPIC_REG_INITIAL_COUNT 0x0380
59#define LAPIC_REG_CURRENT_COUNT 0x0390
60#define LAPIC_REG_DIVIDE_CONFIG 0x03E0
62#define LAPIC_TIMER_PERIODIC 0x00020000
63#define LAPIC_MASKED 0x00010000
67#define INITIAL_COUNT_VALUE (78125 * 40)
72uint64_t LocalApic::nominalQuantumNs()
const {
73 return uint64_t(1000000000) / INITIAL_HZ;
76static constexpr size_t IcrDeliveryPollLimit = 100000;
77static constexpr size_t ProcessorControlPollLimit = 10000000;
78static constexpr size_t TlbShootdownPollLimit = 10000000;
80[[noreturn]]
static void haltInvalidApicMode(
const char* reason) {
81 __asm__
volatile(
"cli" :::
"memory");
82 ERROR_NOLOCK(
"Local APIC: " << reason);
84 __asm__
volatile(
"hlt");
90 uint32_t eax, ebx, ecx, edx;
92 if (((edx >> 9) & 0x01) != 0x01) {
93 ERROR(
"Local APIC: No local APIC present");
98 m_X2Apic = LocalApicMode::decode(apicBase) == LocalApicMode::Mode::X2Apic;
105 if (m_X2Apic && (ecx & (1U << 21)) == 0) {
106 haltInvalidApicMode(
"x2APIC mode inherited without CPU support");
108 if (m_X2Apic && readRegister(LAPIC_REG_ID) > 0xFF) {
109 haltInvalidApicMode(
"x2APIC ID exceeds the current 8-bit processor topology");
111 NOTICE(
"Local APIC: " << (m_X2Apic ?
"x2APIC" :
"xAPIC") <<
" mode");
123 ERROR(
"Local APIC: Could not allocate the memory region");
146 return initialiseProcessor();
149void LocalApic::prepareApplicationProcessor() {
152 uint32_t eax, ebx, ecx, edx;
154 if ((ecx & (1U << 21)) == 0) {
155 haltInvalidApicMode(
"application processor does not support x2APIC");
157 if (LocalApicMode::decode(apicBase) == LocalApicMode::Mode::XApic) {
158 if ((apicBase & 0xFFFFFFFFFFFFF000ULL) != m_PhysicalAddress) {
159 haltInvalidApicMode(
"application processor has a different APIC base");
162 apicBase | LocalApicMode::Extended);
166 if (!check(m_PhysicalAddress)) {
167 haltInvalidApicMode(
"application processor's local APIC is unavailable");
169 if (m_X2Apic && readRegister(LAPIC_REG_ID) > 0xFF) {
170 haltInvalidApicMode(
"x2APIC ID exceeds the current 8-bit processor topology");
172 NOTICE(
"Local APIC: processor #" <<
Dec <<
static_cast<size_t>(getId())
173 << (m_X2Apic ?
" x2APIC" :
" xAPIC") <<
" mode" <<
Hex);
176bool LocalApic::initialiseProcessor() {
178 if (check(m_PhysicalAddress) ==
false)
180 if (m_X2Apic && readRegister(LAPIC_REG_ID) > 0xFF) {
181 haltInvalidApicMode(
"x2APIC ID exceeds the current 8-bit processor topology");
185 uint32_t tmp = readRegister(LAPIC_REG_SPURIOUS_INT);
186 writeRegister((tmp & 0xFFFFFE00) | 0x100 | SPURIOUS_VECTOR, LAPIC_REG_SPURIOUS_INT);
188 const uint64_t apicBase =
190 tmp = readRegister(LAPIC_REG_LVT_LINT0);
191 const uint32_t lint0 = LocalApicLint0Policy::configuredValue(tmp, apicBase);
192 writeRegister(lint0, LAPIC_REG_LVT_LINT0);
193 const uint32_t lint0Readback = readRegister(LAPIC_REG_LVT_LINT0);
194 if (!LocalApicLint0Policy::matchesRole(lint0Readback, apicBase)) {
195 writeRegister(lint0Readback | LocalApicLint0Policy::Masked, LAPIC_REG_LVT_LINT0);
196 const uint32_t maskedReadback = readRegister(LAPIC_REG_LVT_LINT0);
197 if (!(maskedReadback & LocalApicLint0Policy::Masked)) {
198 FATAL(
"Local APIC: failed to mask an invalid LINT0 route");
200 FATAL(
"Local APIC: LINT0 virtual-wire routing did not latch");
204 tmp = readRegister(LAPIC_REG_TASK_PRIORITY);
205 writeRegister(tmp & 0xFFFFFF00, LAPIC_REG_TASK_PRIORITY);
209 tmp = readRegister(LAPIC_REG_LVT_ERROR);
210 writeRegister((tmp & 0xFFFEEF00) | LAPIC_MASKED | ERROR_VECTOR, LAPIC_REG_LVT_ERROR);
212 if (!m_BusFrequency) {
214 writeRegister(0x3, LAPIC_REG_DIVIDE_CONFIG);
218 writeRegister(0xFFFFFFFF, LAPIC_REG_INITIAL_COUNT);
222 const Time::Timestamp calibrationStart = Time::getTicks();
223 for (
size_t i = 0; i < 10000; ++i) {
225 __asm__ __volatile__(
"outb %0, %1" ::
"a"(a),
"Nd"(0x80));
227 uint32_t out = readRegister(LAPIC_REG_CURRENT_COUNT);
229 uint32_t ticks = 0xFFFFFFFFU - out;
230 const Time::Timestamp calibrationElapsed = Time::getTicks() - calibrationStart;
231 if (!ticks || !calibrationElapsed) {
232 ERROR(
"Local APIC: timer calibration produced no elapsed interval");
238 m_BusFrequency =
static_cast<size_t>(
239 (
static_cast<unsigned __int128
>(ticks) * Time::Multiplier::Second) / calibrationElapsed);
240 if (!m_BusFrequency) {
241 ERROR(
"Local APIC: timer calibration produced a zero frequency");
246 m_TimerState[getId()] = {0,
false, 0};
249 writeRegister(LAPIC_TIMER_PERIODIC | TIMER_VECTOR, LAPIC_REG_LVT_TIMER);
252 writeRegister(m_BusFrequency / INITIAL_HZ, LAPIC_REG_INITIAL_COUNT);
255 writeRegister(0x3, LAPIC_REG_DIVIDE_CONFIG);
260bool LocalApic::armDeadline(uint64_t absoluteMonotonicNs) {
261 if (!m_BusFrequency) {
268 TimerState& timer = m_TimerState[getId()];
269 if (timer.oneShot && timer.armedDeadlineNs == absoluteMonotonicNs) {
273 const uint64_t now = Time::getTicksFast();
274 if (!timer.lastInterruptNs) {
275 timer.lastInterruptNs = now;
280 constexpr uint64_t MinimumDelayNs = 100000;
281 const uint64_t remaining = absoluteMonotonicNs > now && absoluteMonotonicNs - now > MinimumDelayNs
282 ? absoluteMonotonicNs - now
284 const unsigned __int128 count =
285 (
static_cast<unsigned __int128
>(remaining) * m_BusFrequency + Time::Multiplier::Second - 1) /
286 Time::Multiplier::Second;
287 uint32_t initialCount = 1;
288 if (count > 0xFFFFFFFFU) {
289 initialCount = 0xFFFFFFFFU;
291 initialCount =
static_cast<uint32_t
>(count);
297 if (!timer.oneShot) {
298 writeRegister(LAPIC_MASKED | TIMER_VECTOR, LAPIC_REG_LVT_TIMER);
299 writeRegister(0, LAPIC_REG_INITIAL_COUNT);
300 timer.oneShot =
true;
302 writeRegister(TIMER_VECTOR, LAPIC_REG_LVT_TIMER);
305 writeRegister(initialCount, LAPIC_REG_INITIAL_COUNT);
306 timer.armedDeadlineNs = absoluteMonotonicNs;
312void LocalApic::disarm() {
316 TimerState& timer = m_TimerState[getId()];
317 if (!timer.lastInterruptNs) {
318 timer.lastInterruptNs = Time::getTicksFast();
320 timer.oneShot =
true;
321 timer.armedDeadlineNs = 0;
322 writeRegister(LAPIC_MASKED | TIMER_VECTOR, LAPIC_REG_LVT_TIMER);
323 writeRegister(0, LAPIC_REG_INITIAL_COUNT);
328bool LocalApic::interProcessorInterrupt(uint8_t destinationApicId, uint8_t vector,
329 size_t deliveryMode,
bool bAssert,
bool bLevelTriggered) {
330 return submitIcr(destinationApicId << 24, vector | (deliveryMode << 8) |
331 (bAssert ? (1 << 14) : 0) |
332 (bLevelTriggered ? (1 << 15) : 0));
335bool LocalApic::interProcessorInterruptAllExcludingThis(uint8_t vector,
size_t deliveryMode) {
336 return submitIcr(0, vector | (deliveryMode << 8) | (1 << 14) | (0x3 << 18));
341 if (!LocalApicTlbShootdown::supportsContext(context)) {
342 return TlbInvalidationResult::InvalidContext;
347 if (!processorCount || processorCount > LocalApicTlbShootdown::MaxProcessors ||
348 processor >= processorCount) {
349 return TlbInvalidationResult::UnsupportedTopology;
351 const uint64_t available =
352 processorCount == 64 ? ~uint64_t(0) : (uint64_t(1) << processorCount) - 1;
353 if (processors == ~uint64_t(0)) {
354 processors = available;
356 if (processors & ~available) {
357 return TlbInvalidationResult::UnsupportedTopology;
359 const uint64_t self = uint64_t(1) << processor;
361 const uint64_t remote = processors & ~self;
362 const bool terminalSelfOnly = processorControlState() == ProcessorControlState::Terminal &&
363 LocalApicTlbShootdown::onlyCurrentProcessorServiceable(
364 processorCount, m_TerminalProcessorCount.value());
365 if (!remote || terminalSelfOnly) {
370 return TlbInvalidationResult::Success;
373 if (!acquireTlbShootdownBarrier()) {
374 return TlbInvalidationResult::SerialisationTimedOut;
381 if (processorControlState() == ProcessorControlState::Terminal &&
382 LocalApicTlbShootdown::onlyCurrentProcessorServiceable(processorCount,
383 m_TerminalProcessorCount.value())) {
385 return releaseTlbShootdownBarrier() ? TlbInvalidationResult::Success
386 : TlbInvalidationResult::DrainTimedOut;
394 if (!m_TlbShootdown.publish(
reinterpret_cast<uintptr_t
>(address), processor, processorCount,
396 return TlbInvalidationResult::UnsupportedTopology;
399 bool submitted =
true;
400 if (processors == available) {
402 interProcessorInterruptAllExcludingThis(IPI_TLB_SHOOTDOWN_VECTOR, deliveryModeFixed);
404 for (
size_t target = 0; target < processorCount; ++target) {
405 if (!(remote & (uint64_t(1) << target))) {
410 !interProcessorInterrupt(information->localApicId(), IPI_TLB_SHOOTDOWN_VECTOR,
411 deliveryModeFixed,
true,
false)) {
418 m_TlbShootdown.close();
419 for (
size_t poll = 0; !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit; ++poll) {
422 if (!m_TlbShootdown.drained()) {
423 return TlbInvalidationResult::DrainTimedOut;
425 return TlbInvalidationResult::SubmissionFailed;
428 bool complete =
false;
429 for (
size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
430 if (m_TlbShootdown.complete()) {
437 m_TlbShootdown.close();
438 for (
size_t poll = 0; !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit; ++poll) {
441 if (!m_TlbShootdown.drained()) {
442 return TlbInvalidationResult::DrainTimedOut;
445 return TlbInvalidationResult::AcknowledgementTimedOut;
447 return releaseTlbShootdownBarrier() ? TlbInvalidationResult::Success
448 : TlbInvalidationResult::DrainTimedOut;
454 if (!LocalApicTlbShootdown::supportsContext(context)) {
455 return TlbInvalidationResult::InvalidContext;
460 if (!processorCount || processorCount > LocalApicTlbShootdown::MaxProcessors ||
461 processor >= processorCount) {
462 return TlbInvalidationResult::UnsupportedTopology;
465 for (
size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
466 if (processorControlState() == ProcessorControlState::Terminal &&
467 LocalApicTlbShootdown::onlyCurrentProcessorServiceable(processorCount,
468 m_TerminalProcessorCount.value())) {
469 return TlbInvalidationResult::Success;
471 if (m_TlbMutations.terminalClosed()) {
472 return TlbInvalidationResult::SerialisationTimedOut;
474 if (m_TlbMutations.tryEnter()) {
476 return TlbInvalidationResult::Success;
480 return TlbInvalidationResult::SerialisationTimedOut;
483void LocalApic::endTlbInvalidation() {
484 if (!m_TlbMutations.leave()) {
485 FATAL(
"Local APIC TLB mutation admission underflow");
491 const bool coordinator = m_TlbTerminalFailure.elect(processor,
static_cast<size_t>(result));
492 if (!m_TlbMutations.closeTerminal()) {
498bool LocalApic::tlbInvalidationFailureActive()
const {
499 return m_TlbTerminalFailure.active();
502bool LocalApic::tlbInvalidationTerminal()
const {
503 return m_TlbMutations.terminalClosed();
506void LocalApic::servicePendingTlbShootdown() {
509 if (!m_TlbShootdown.generation()) {
518 if (!m_TlbShootdown.beginService(processor, service)) {
524 m_TlbShootdown.finishService(service);
528void LocalApic::servicePendingTerminalProcessorControl() {
529 if (!m_TlbMutations.terminalClosed()) {
533 const ProcessorControlState state = processorControlState();
535 const bool precommitFailureCoordinator =
536 state != ProcessorControlState::Terminal && m_TlbTerminalFailure.coordinator(processor);
537 if ((state != ProcessorControlState::Paused && state != ProcessorControlState::Terminal) ||
538 !m_ProcessorControlOwner.owned() || m_ProcessorControlOwner.ownedBy(processor) ||
539 precommitFailureCoordinator) {
543 enterTerminalProcessorControl();
546bool LocalApic::acquireTlbShootdownBarrier() {
547 for (
size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
548 if (m_TlbShootdown.tryAcquire()) {
554 servicePendingTlbShootdown();
560bool LocalApic::releaseTlbShootdownBarrier() {
561 for (
size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
562 if (!m_TlbShootdown.generation() && m_TlbShootdown.drained() && m_TlbShootdown.release()) {
567 return !m_TlbShootdown.generation() && m_TlbShootdown.drained() && m_TlbShootdown.release();
570bool LocalApic::waitForTlbMutationDrain() {
571 for (
size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
572 if (m_TlbMutations.drained()) {
575 servicePendingTlbShootdown();
578 return m_TlbMutations.drained();
581LocalApic::ProcessorControlState LocalApic::processorControlState()
const {
582 return static_cast<ProcessorControlState
>(m_ProcessorControlState.value());
585bool LocalApic::acquireProcessorControlOwner(
bool acceptRetained,
586 ProcessorControlOwnership& ownership) {
587 ownership = ProcessorControlOwnership::Fresh;
589 if (processor >= LocalApicProcessorControlOwner::MaxProcessors) {
593 if (acceptRetained && m_ProcessorControlOwner.claimAnyQuiesced(processor)) {
594 ownership = ProcessorControlOwnership::Quiesced;
597 if (acceptRetained && m_ProcessorControlOwner.claimAnyFailed(processor)) {
598 ownership = ProcessorControlOwnership::Failed;
601 if (acceptRetained && m_ProcessorControlOwner.claimTerminal(processor)) {
602 ownership = ProcessorControlOwnership::Terminal;
605 if (acceptRetained && m_ProcessorControlOwner.activeBy(processor)) {
609 for (
size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
610 if (m_ProcessorControlOwner.tryAcquire(processor)) {
613 if (acceptRetained && m_ProcessorControlOwner.claimAnyQuiesced(processor)) {
614 ownership = ProcessorControlOwnership::Quiesced;
617 if (acceptRetained && m_ProcessorControlOwner.claimAnyFailed(processor)) {
618 ownership = ProcessorControlOwnership::Failed;
621 if (acceptRetained && m_ProcessorControlOwner.claimTerminal(processor)) {
622 ownership = ProcessorControlOwnership::Terminal;
625 if (acceptRetained && m_ProcessorControlOwner.activeBy(processor)) {
633bool LocalApic::releaseProcessorControlOwner() {
637LocalApic::ProcessorControlResult LocalApic::completeTerminalControl(
size_t expectedProcessors) {
638 if (!waitForTerminalProcessorCount(expectedProcessors)) {
639 return retainTerminalControl(ProcessorControlResult::AcknowledgementTimedOut);
643 if (!m_ProcessorControlOwner.activeBy(processor)) {
644 return ProcessorControlResult::InvalidState;
647 for (
size_t poll = 0;
648 m_TlbShootdown.owned() && !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit;
652 ProcessorControlResult result = ProcessorControlResult::Success;
653 if (m_TlbShootdown.owned() && !releaseTlbShootdownBarrier()) {
654 result = ProcessorControlResult::DrainTimedOut;
656 return retainTerminalControl(result);
659LocalApic::ProcessorControlResult LocalApic::retainTerminalControl(ProcessorControlResult result) {
662 : ProcessorControlResult::DrainTimedOut;
665bool LocalApic::adoptTerminalTlbShootdownBarrier() {
666 if (!m_TlbMutations.terminalClosed() || !m_TlbMutations.drained()) {
670 if (!m_TlbShootdown.owned() && !m_TlbShootdown.tryAcquire()) {
673 if (m_TlbShootdown.generation()) {
680 for (
size_t poll = 0; !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit; ++poll) {
683 return !m_TlbShootdown.generation() && m_TlbShootdown.drained();
686bool LocalApic::waitForProcessorCount(
size_t expectedProcessors) {
687 for (
size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
688 if (m_ControlledProcessorCount >= expectedProcessors)
692 return m_ControlledProcessorCount >= expectedProcessors;
695bool LocalApic::waitForTerminalProcessorCount(
size_t expectedProcessors) {
696 for (
size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
697 if (m_TerminalProcessorCount >= expectedProcessors)
701 return m_TerminalProcessorCount >= expectedProcessors;
704bool LocalApic::waitForProcessorDrain() {
705 for (
size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
706 if (!m_ControlledProcessorCount)
710 return !m_ControlledProcessorCount;
713bool LocalApic::markTerminalProcessor(
size_t processor) {
714 if (processor >= LocalApicTlbShootdown::MaxProcessors) {
718 const uint64_t processorBit = uint64_t(1) << processor;
719 uint64_t mask = m_TerminalProcessorMask.value();
720 while (!(mask & processorBit)) {
721 if (m_TerminalProcessorMask.compareAndSwap(mask, mask | processorBit)) {
722 m_TerminalProcessorCount += 1;
725 mask = m_TerminalProcessorMask.value();
730void LocalApic::enterTerminalProcessorControl() {
732 while (processorControlState() != ProcessorControlState::Terminal) {
734 asm volatile(
"pause");
743LocalApic::ProcessorControlResult LocalApic::retainQuiescedControl(ProcessorControlResult result) {
744 if (!releaseTlbShootdownBarrier()) {
745 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
750 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
753LocalApic::ProcessorControlResult LocalApic::retainFailedControl(ProcessorControlResult result) {
756 : ProcessorControlResult::DrainTimedOut;
759LocalApic::ProcessorControlResult LocalApic::releaseProcessorControlOrRetainFailure(
760 ProcessorControlResult released, ProcessorControlResult retained) {
761 if (releaseProcessorControlOwner()) {
764 return retainFailedControl(retained);
767LocalApic::ProcessorControlResult LocalApic::finishFailedQuiesce(ProcessorControlResult result) {
768 if (!releaseTlbShootdownBarrier()) {
769 result = ProcessorControlResult::DrainTimedOut;
771 return retainFailedControl(result);
774LocalApic::ProcessorControlResult LocalApic::unwindQuiesce(ProcessorControlResult failure) {
775 if (!m_ProcessorControlState.compareAndSwap(
776 static_cast<size_t>(ProcessorControlState::Paused),
777 static_cast<size_t>(ProcessorControlState::Unavailable))) {
778 return ProcessorControlResult::InvalidState;
784 return waitForProcessorDrain() ? failure : ProcessorControlResult::DrainTimedOut;
787LocalApic::ProcessorControlResult LocalApic::quiesceAllOtherProcessors(
size_t expectedProcessors) {
788 if (!expectedProcessors)
789 return ProcessorControlResult::Success;
791 ProcessorControlOwnership ownership = ProcessorControlOwnership::Fresh;
792 if (!acquireProcessorControlOwner(
false, ownership)) {
793 return ProcessorControlResult::InvalidState;
795 if (processorControlState() != ProcessorControlState::Idle) {
796 if (m_TlbMutations.terminalClosed()) {
797 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
798 ProcessorControlResult::InvalidState);
803 if (processorControlState() == ProcessorControlState::Terminal) {
804 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::InvalidState,
805 ProcessorControlResult::DrainTimedOut);
806 }
else if (!m_TlbMutations.closed()) {
807 if (!m_TlbMutations.closeReversible() && m_TlbMutations.terminalClosed()) {
808 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
809 ProcessorControlResult::InvalidState);
812 return retainFailedControl(ProcessorControlResult::InvalidState);
814 if (!waitForProcessorDrain()) {
815 if (m_TlbMutations.terminalClosed()) {
816 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
817 ProcessorControlResult::InvalidState);
819 if (!m_ProcessorControlState.compareAndSwap(
820 static_cast<size_t>(ProcessorControlState::Idle),
821 static_cast<size_t>(ProcessorControlState::Unavailable))) {
822 if (m_TlbMutations.terminalClosed()) {
823 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
824 ProcessorControlResult::InvalidState);
826 if (!m_TlbMutations.closed()) {
827 if (!m_TlbMutations.closeReversible() && m_TlbMutations.terminalClosed()) {
828 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
829 ProcessorControlResult::InvalidState);
832 return retainFailedControl(ProcessorControlResult::InvalidState);
836 if (m_TlbMutations.terminalClosed()) {
837 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
838 ProcessorControlResult::InvalidState);
840 if (!m_TlbMutations.closeReversible()) {
841 if (m_TlbMutations.terminalClosed()) {
842 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
843 ProcessorControlResult::InvalidState);
845 return retainFailedControl(ProcessorControlResult::InvalidState);
847 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
853 if (!m_TlbMutations.closeReversible()) {
854 if (m_TlbMutations.terminalClosed()) {
855 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
856 ProcessorControlResult::InvalidState);
858 return retainFailedControl(ProcessorControlResult::InvalidState);
860 if (!waitForTlbMutationDrain()) {
861 if (m_TlbMutations.terminalClosed()) {
862 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
863 ProcessorControlResult::InvalidState);
867 if (!m_TlbMutations.cancelClose()) {
868 if (m_TlbMutations.terminalClosed()) {
869 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
870 ProcessorControlResult::InvalidState);
872 return retainFailedControl(ProcessorControlResult::InvalidState);
874 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
875 ProcessorControlResult::InvalidState);
877 if (m_TlbMutations.terminalClosed()) {
878 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
879 ProcessorControlResult::InvalidState);
885 if (!acquireTlbShootdownBarrier()) {
886 if (m_TlbMutations.terminalClosed()) {
887 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
888 ProcessorControlResult::InvalidState);
890 if (!m_TlbMutations.reopen()) {
891 if (m_TlbMutations.terminalClosed()) {
892 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
893 ProcessorControlResult::InvalidState);
895 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
897 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
898 ProcessorControlResult::InvalidState);
900 if (processorControlState() != ProcessorControlState::Idle) {
903 return finishFailedQuiesce(ProcessorControlResult::InvalidState);
905 if (!m_ProcessorControlState.compareAndSwap(
static_cast<size_t>(ProcessorControlState::Idle),
906 static_cast<size_t>(ProcessorControlState::Paused))) {
907 return finishFailedQuiesce(ProcessorControlResult::InvalidState);
913 if (m_TlbMutations.terminalClosed()) {
914 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
917 const bool submitted =
918 interProcessorInterruptAllExcludingThis(IPI_PROCESSOR_CONTROL_VECTOR, deliveryModeFixed);
919 if (m_TlbMutations.terminalClosed()) {
920 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
923 const ProcessorControlResult result = unwindQuiesce(ProcessorControlResult::SubmissionFailed);
924 return finishFailedQuiesce(result);
926 if (!waitForProcessorCount(expectedProcessors)) {
927 if (m_TlbMutations.terminalClosed()) {
928 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
930 const ProcessorControlResult result =
931 unwindQuiesce(ProcessorControlResult::AcknowledgementTimedOut);
932 return finishFailedQuiesce(result);
934 if (m_TlbMutations.terminalClosed()) {
935 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
937 if (processorControlState() != ProcessorControlState::Paused) {
938 return finishFailedQuiesce(ProcessorControlResult::InvalidState);
940 return retainQuiescedControl(ProcessorControlResult::Success);
943LocalApic::ProcessorControlResult LocalApic::resumeAllOtherProcessors() {
945 if (!m_ProcessorControlOwner.claimQuiesced(processor)) {
946 return ProcessorControlResult::InvalidState;
948 if (m_TlbMutations.terminalClosed()) {
949 if (m_ProcessorControlOwner.markQuiesced(processor)) {
950 return ProcessorControlResult::InvalidState;
952 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
954 if (!m_ProcessorControlState.compareAndSwap(
955 static_cast<size_t>(ProcessorControlState::Paused),
956 static_cast<size_t>(ProcessorControlState::Unavailable))) {
957 return retainFailedControl(ProcessorControlResult::InvalidState);
959 if (!waitForProcessorDrain()) {
960 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
962 if (!m_ProcessorControlState.compareAndSwap(
963 static_cast<size_t>(ProcessorControlState::Unavailable),
964 static_cast<size_t>(ProcessorControlState::Idle))) {
965 return retainFailedControl(ProcessorControlResult::InvalidState);
967 if (!m_TlbMutations.reopen()) {
968 if (!m_TlbMutations.closed()) {
969 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::InvalidState,
970 ProcessorControlResult::DrainTimedOut);
972 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
974 if (releaseProcessorControlOwner()) {
975 return ProcessorControlResult::Success;
977 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
980LocalApic::ProcessorControlResult LocalApic::haltAllOtherProcessors(
size_t expectedProcessors) {
981 if (!expectedProcessors)
982 return ProcessorControlResult::Success;
984 ProcessorControlOwnership ownership = ProcessorControlOwnership::Fresh;
985 if (!acquireProcessorControlOwner(
true, ownership)) {
986 return ProcessorControlResult::InvalidState;
988 if (!m_TlbMutations.closeTerminal() || !waitForTlbMutationDrain()) {
989 return retainTerminalControl(ProcessorControlResult::DrainTimedOut);
991 if (!adoptTerminalTlbShootdownBarrier()) {
992 return retainTerminalControl(ProcessorControlResult::DrainTimedOut);
995 bool terminalSelected =
false;
996 for (
size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
997 const ProcessorControlState state = processorControlState();
998 if (state == ProcessorControlState::Terminal ||
999 m_ProcessorControlState.compareAndSwap(
1000 static_cast<size_t>(state),
static_cast<size_t>(ProcessorControlState::Terminal))) {
1001 terminalSelected =
true;
1006 if (!terminalSelected) {
1007 return retainTerminalControl(ProcessorControlResult::InvalidState);
1013 if (!interProcessorInterruptAllExcludingThis(IPI_PROCESSOR_CONTROL_VECTOR, deliveryModeFixed)) {
1014 return retainTerminalControl(ProcessorControlResult::SubmissionFailed);
1016 return completeTerminalControl(expectedProcessors);
1019bool LocalApic::waitForIcrIdle() {
1023 for (
size_t poll = 0; poll < IcrDeliveryPollLimit; ++poll) {
1024 if ((readRegister(LAPIC_REG_INT_CMD_LOW) & 0x1000) == 0)
1028 return (readRegister(LAPIC_REG_INT_CMD_LOW) & 0x1000) == 0;
1031bool LocalApic::submitIcr(uint32_t high, uint32_t low) {
1035 bool submitted = waitForIcrIdle();
1039 LocalApicMode::x2ApicIcr(high, low));
1041 writeRegister(high, LAPIC_REG_INT_CMD_HIGH);
1042 writeRegister(low, LAPIC_REG_INT_CMD_LOW);
1043 submitted = waitForIcrIdle();
1051uint8_t LocalApic::getId() {
1052 const uint32_t
id = readRegister(LAPIC_REG_ID);
1053 return m_X2Apic ? id : (
id >> 24) & 0xFF;
1058 const LocalApicMode::Mode mode = LocalApicMode::decode(apicBase);
1060 if (mode == LocalApicMode::Mode::Invalid || (mode == LocalApicMode::Mode::X2Apic) != m_X2Apic) {
1062 haltInvalidApicMode(
"inherited APIC mode changed or is invalid");
1064 if (mode == LocalApicMode::Mode::Disabled) {
1065 ERROR(
"Local APIC: Disabled");
1071 ERROR(
"Local APIC: Wrong physical address");
1078uint32_t LocalApic::readRegister(uint32_t offset) {
1082 return m_IoSpace.read32(offset);
1085void LocalApic::writeRegister(uint32_t value, uint32_t offset) {
1089 m_IoSpace.write32(value, offset);
1093void LocalApic::interrupt(
size_t nInterruptNumber, InterruptState& state) {
1094 if (nInterruptNumber == IPI_TLB_SHOOTDOWN_VECTOR) {
1096 servicePendingTlbShootdown();
1100 if (nInterruptNumber == TIMER_VECTOR || nInterruptNumber == IPI_RESCHEDULE_VECTOR) {
1106 if (nInterruptNumber == TIMER_VECTOR) {
1107 TimerState& timer = m_TimerState[getId()];
1108 timer.armedDeadlineNs = 0;
1109 const uint64_t now = Time::getTicksFast();
1111 delta = timer.oneShot ? (now > timer.lastInterruptNs ? now - timer.lastInterruptNs : 1)
1112 : nominalQuantumNs();
1113 timer.lastInterruptNs = now;
1121 if (
LIKELY(m_Handlers.beginDispatch(getId(), dispatch))) {
1124 dispatch.handler()->
timer(delta, state);
1131 if (nInterruptNumber == IPI_PROCESSOR_CONTROL_VECTOR) {
1134 const ProcessorControlState initialState = processorControlState();
1135 if (m_TlbMutations.terminalClosed() && (initialState == ProcessorControlState::Paused ||
1136 initialState == ProcessorControlState::Terminal)) {
1137 enterTerminalProcessorControl();
1140 m_ControlledProcessorCount += 1;
1142 const ProcessorControlState controlState = processorControlState();
1143 if (controlState == ProcessorControlState::Idle ||
1144 controlState == ProcessorControlState::Unavailable) {
1145 m_ControlledProcessorCount -= 1;
1148 if (controlState == ProcessorControlState::Terminal) {
1149 m_ControlledProcessorCount -= 1;
1155 asm volatile(
"pause");
1160void LocalApic::ack() {
1162 writeRegister(0, LAPIC_REG_EOI);
static EXPORTED_PUBLIC InterruptManager & instance()
static const size_t continuous
static PhysicalMemoryManager & instance()
static const size_t force
static const size_t nonRamMemory
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
static bool getInterrupts()
static ExecutionContext executionContext()
static void invalidate(void *pAddress)
static ProcessorInformation * informationAt(size_t cpu)
static void setInterrupts(bool bEnable)
virtual void timer(uint64_t delta, InterruptState &state)=0
static const size_t CacheDisable
static const size_t KernelMode
static const size_t Write
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)
uintptr_t physicalAddress(physical_uintptr_t address) PURE