The Pedigree Project 0.1
LocalApic.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 <config.h>
21
22#if MULTIPROCESSOR
23
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"
32
33#include "LocalApic.h"
34#include "LocalApicIcrTransaction.h"
35#include "LocalApicLint0Policy.h"
36#include "LocalApicMode.h"
37
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
46// NOTE ISR
47// NOTE TMR
48// NOTE IRR
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
61
62#define LAPIC_TIMER_PERIODIC 0x00020000
63#define LAPIC_MASKED 0x00010000
64
67#define INITIAL_COUNT_VALUE (78125 * 40)
68
70#define INITIAL_HZ 100
71
72uint64_t LocalApic::nominalQuantumNs() const {
73 return uint64_t(1000000000) / INITIAL_HZ;
74}
75
76static constexpr size_t IcrDeliveryPollLimit = 100000;
77static constexpr size_t ProcessorControlPollLimit = 10000000;
78static constexpr size_t TlbShootdownPollLimit = 10000000;
79
80[[noreturn]] static void haltInvalidApicMode(const char* reason) {
81 __asm__ volatile("cli" ::: "memory");
82 ERROR_NOLOCK("Local APIC: " << reason);
83 for (;;) {
84 __asm__ volatile("hlt");
85 }
86}
87
88bool LocalApic::initialise(uint64_t physicalAddress) {
89 // Detect local APIC presence
90 uint32_t eax, ebx, ecx, edx;
91 Processor::cpuid(1, 0, eax, ebx, ecx, edx);
92 if (((edx >> 9) & 0x01) != 0x01) {
93 ERROR("Local APIC: No local APIC present");
94 return false;
95 }
96
97 const uint64_t apicBase = Processor::readMachineSpecificRegister(LocalApicMode::BaseMsr);
98 m_X2Apic = LocalApicMode::decode(apicBase) == LocalApicMode::Mode::X2Apic;
99 m_PhysicalAddress = physicalAddress;
100
101 // Some checks
102 if (check(physicalAddress) == false)
103 return false;
104
105 if (m_X2Apic && (ecx & (1U << 21)) == 0) {
106 haltInvalidApicMode("x2APIC mode inherited without CPU support");
107 }
108 if (m_X2Apic && readRegister(LAPIC_REG_ID) > 0xFF) {
109 haltInvalidApicMode("x2APIC ID exceeds the current 8-bit processor topology");
110 }
111 NOTICE("Local APIC: " << (m_X2Apic ? "x2APIC" : "xAPIC") << " mode");
112
113 // Allocate the local APIC memory-mapped I/O space
114 if (!m_X2Apic) {
116 if (physicalMemoryManager.allocateRegion(
117 m_IoSpace, 1,
122 physicalAddress) == false) {
123 ERROR("Local APIC: Could not allocate the memory region");
124 return false;
125 }
126 }
127
128 // Register the timer vector.
129 if (!InterruptManager::instance().registerInterruptHandler(TIMER_VECTOR, this))
130 return false;
131
132 // Register the reversible/terminal processor-control IPI vector.
133 if (!InterruptManager::instance().registerInterruptHandler(IPI_PROCESSOR_CONTROL_VECTOR, this))
134 return false;
135
136 // Register the synchronous shared-mapping TLB shootdown vector.
137 if (!InterruptManager::instance().registerInterruptHandler(IPI_TLB_SHOOTDOWN_VECTOR, this))
138 return false;
139
140 // This vector is a directed scheduler prompt for work published by a
141 // remote hard producer. It shares the timer's owner-qualified scheduler
142 // callback but is never routed through the legacy PIC path.
143 if (!InterruptManager::instance().registerInterruptHandler(IPI_RESCHEDULE_VECTOR, this))
144 return false;
145
146 return initialiseProcessor();
147}
148
149void LocalApic::prepareApplicationProcessor() {
150 const uint64_t apicBase = Processor::readMachineSpecificRegister(LocalApicMode::BaseMsr);
151 if (m_X2Apic) {
152 uint32_t eax, ebx, ecx, edx;
153 Processor::cpuid(1, 0, eax, ebx, ecx, edx);
154 if ((ecx & (1U << 21)) == 0) {
155 haltInvalidApicMode("application processor does not support x2APIC");
156 }
157 if (LocalApicMode::decode(apicBase) == LocalApicMode::Mode::XApic) {
158 if ((apicBase & 0xFFFFFFFFFFFFF000ULL) != m_PhysicalAddress) {
159 haltInvalidApicMode("application processor has a different APIC base");
160 }
161 Processor::writeMachineSpecificRegister(LocalApicMode::BaseMsr,
162 apicBase | LocalApicMode::Extended);
163 }
164 }
165
166 if (!check(m_PhysicalAddress)) {
167 haltInvalidApicMode("application processor's local APIC is unavailable");
168 }
169 if (m_X2Apic && readRegister(LAPIC_REG_ID) > 0xFF) {
170 haltInvalidApicMode("x2APIC ID exceeds the current 8-bit processor topology");
171 }
172 NOTICE("Local APIC: processor #" << Dec << static_cast<size_t>(getId())
173 << (m_X2Apic ? " x2APIC" : " xAPIC") << " mode" << Hex);
174}
175
176bool LocalApic::initialiseProcessor() {
177 // Some checks
178 if (check(m_PhysicalAddress) == false)
179 return false;
180 if (m_X2Apic && readRegister(LAPIC_REG_ID) > 0xFF) {
181 haltInvalidApicMode("x2APIC ID exceeds the current 8-bit processor topology");
182 }
183
184 // Enable the Local APIC and set the spurious interrupt vector
185 uint32_t tmp = readRegister(LAPIC_REG_SPURIOUS_INT);
186 writeRegister((tmp & 0xFFFFFE00) | 0x100 | SPURIOUS_VECTOR, LAPIC_REG_SPURIOUS_INT);
187
188 const uint64_t apicBase =
189 Processor::readMachineSpecificRegister(LocalApicLint0Policy::ApicBaseMsr);
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");
199 }
200 FATAL("Local APIC: LINT0 virtual-wire routing did not latch");
201 }
202
203 // Set the task priority to 0
204 tmp = readRegister(LAPIC_REG_TASK_PRIORITY);
205 writeRegister(tmp & 0xFFFFFF00, LAPIC_REG_TASK_PRIORITY);
206
207 // No error-vector handler exists yet, so keep this source masked rather
208 // than routing an interrupt that cannot be acknowledged safely.
209 tmp = readRegister(LAPIC_REG_LVT_ERROR);
210 writeRegister((tmp & 0xFFFEEF00) | LAPIC_MASKED | ERROR_VECTOR, LAPIC_REG_LVT_ERROR);
211
212 if (!m_BusFrequency) {
213 // Divide by 16
214 writeRegister(0x3, LAPIC_REG_DIVIDE_CONFIG);
215
216 // Set the maximum count so we can calculate the frequency without this
217 // rolling over.
218 writeRegister(0xFFFFFFFF, LAPIC_REG_INITIAL_COUNT);
219
220 // Measure the delay with the RTC-calibrated monotonic clock instead of
221 // assuming a platform-specific port-0x80 delay.
222 const Time::Timestamp calibrationStart = Time::getTicks();
223 for (size_t i = 0; i < 10000; ++i) {
224 uint8_t a = 0;
225 __asm__ __volatile__("outb %0, %1" ::"a"(a), "Nd"(0x80));
226 }
227 uint32_t out = readRegister(LAPIC_REG_CURRENT_COUNT);
228
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");
233 return false;
234 }
235
236 // The counter is already divided by 16 above, and m_BusFrequency is the
237 // rate consumed by the initial-count register.
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");
242 return false;
243 }
244 }
245
246 m_TimerState[getId()] = {0, false, 0};
247
248 // Set the LVT timer register.
249 writeRegister(LAPIC_TIMER_PERIODIC | TIMER_VECTOR, LAPIC_REG_LVT_TIMER);
250
251 // Initialise the intial-count register
252 writeRegister(m_BusFrequency / INITIAL_HZ, LAPIC_REG_INITIAL_COUNT);
253
254 // Initialise the divisor register. (Divide by 16)
255 writeRegister(0x3, LAPIC_REG_DIVIDE_CONFIG);
256
257 return true;
258}
259
260bool LocalApic::armDeadline(uint64_t absoluteMonotonicNs) {
261 if (!m_BusFrequency) {
262 return false;
263 }
264
265 const bool restoreInterrupts = Processor::getInterrupts();
267
268 TimerState& timer = m_TimerState[getId()];
269 if (timer.oneShot && timer.armedDeadlineNs == absoluteMonotonicNs) {
270 Processor::setInterrupts(restoreInterrupts);
271 return true;
272 }
273 const uint64_t now = Time::getTicksFast();
274 if (!timer.lastInterruptNs) {
275 timer.lastInterruptNs = now;
276 }
277
278 // An immediate count can expire during the register writes under TCG, and
279 // repeated scheduling boundaries must not restart the same near deadline.
280 constexpr uint64_t MinimumDelayNs = 100000;
281 const uint64_t remaining = absoluteMonotonicNs > now && absoluteMonotonicNs - now > MinimumDelayNs
282 ? absoluteMonotonicNs - now
283 : MinimumDelayNs;
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;
290 } else if (count) {
291 initialCount = static_cast<uint32_t>(count);
292 }
293
294 // A saturated count expires before a distant deadline. The scheduler
295 // reevaluates its absolute deadline at that interrupt and arms another
296 // chunk as needed.
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;
301 }
302 writeRegister(TIMER_VECTOR, LAPIC_REG_LVT_TIMER);
303 // Start the countdown only after the vector is unmasked. A short count can
304 // otherwise expire while the LVT is still masked under TCG.
305 writeRegister(initialCount, LAPIC_REG_INITIAL_COUNT);
306 timer.armedDeadlineNs = absoluteMonotonicNs;
307
308 Processor::setInterrupts(restoreInterrupts);
309 return true;
310}
311
312void LocalApic::disarm() {
313 const bool restoreInterrupts = Processor::getInterrupts();
315
316 TimerState& timer = m_TimerState[getId()];
317 if (!timer.lastInterruptNs) {
318 timer.lastInterruptNs = Time::getTicksFast();
319 }
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);
324
325 Processor::setInterrupts(restoreInterrupts);
326}
327
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));
333}
334
335bool LocalApic::interProcessorInterruptAllExcludingThis(uint8_t vector, size_t deliveryMode) {
336 return submitIcr(0, vector | (deliveryMode << 8) | (1 << 14) | (0x3 << 18));
337}
338
339TlbInvalidationResult LocalApic::invalidateAllProcessors(void* address, uint64_t processors) {
340 const ExecutionContext context = Processor::executionContext();
341 if (!LocalApicTlbShootdown::supportsContext(context)) {
342 return TlbInvalidationResult::InvalidContext;
343 }
344
345 const size_t processorCount = Processor::getCount();
346 const size_t processor = Processor::index();
347 if (!processorCount || processorCount > LocalApicTlbShootdown::MaxProcessors ||
348 processor >= processorCount) {
349 return TlbInvalidationResult::UnsupportedTopology;
350 }
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;
355 }
356 if (processors & ~available) {
357 return TlbInvalidationResult::UnsupportedTopology;
358 }
359 const uint64_t self = uint64_t(1) << processor;
360 processors |= self;
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) {
366 // Terminal processors have acknowledged their permanent CLI+HLT loop and
367 // can never execute with a stale translation again. Processor::getCount()
368 // intentionally remains the immutable discovered topology at shutdown.
369 Processor::invalidate(address);
370 return TlbInvalidationResult::Success;
371 }
372
373 if (!acquireTlbShootdownBarrier()) {
374 return TlbInvalidationResult::SerialisationTimedOut;
375 }
376
377 // A terminal transition holds the owner until every peer has committed to
378 // its permanent CLI+HLT loop. A caller which lost that race must recheck
379 // after acquiring rather than publishing a request to processors which can
380 // no longer acknowledge it.
381 if (processorControlState() == ProcessorControlState::Terminal &&
382 LocalApicTlbShootdown::onlyCurrentProcessorServiceable(processorCount,
383 m_TerminalProcessorCount.value())) {
384 Processor::invalidate(address);
385 return releaseTlbShootdownBarrier() ? TlbInvalidationResult::Success
386 : TlbInvalidationResult::DrainTimedOut;
387 }
388
389 // A reader can have speculated on the prior generation before this owner
390 // acquired. Publishing a new generation is safe while that reader retires:
391 // it copied the prior address and its generation tag cannot acknowledge the
392 // request published last below.
393 Processor::invalidate(address);
394 if (!m_TlbShootdown.publish(reinterpret_cast<uintptr_t>(address), processor, processorCount,
395 processors)) {
396 return TlbInvalidationResult::UnsupportedTopology;
397 }
398
399 bool submitted = true;
400 if (processors == available) {
401 submitted =
402 interProcessorInterruptAllExcludingThis(IPI_TLB_SHOOTDOWN_VECTOR, deliveryModeFixed);
403 } else {
404 for (size_t target = 0; target < processorCount; ++target) {
405 if (!(remote & (uint64_t(1) << target))) {
406 continue;
407 }
408 ProcessorInformation* information = Processor::informationAt(target);
409 if (!information ||
410 !interProcessorInterrupt(information->localApicId(), IPI_TLB_SHOOTDOWN_VECTOR,
411 deliveryModeFixed, true, false)) {
412 submitted = false;
413 break;
414 }
415 }
416 }
417 if (!submitted) {
418 m_TlbShootdown.close();
419 for (size_t poll = 0; !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit; ++poll) {
421 }
422 if (!m_TlbShootdown.drained()) {
423 return TlbInvalidationResult::DrainTimedOut;
424 }
425 return TlbInvalidationResult::SubmissionFailed;
426 }
427
428 bool complete = false;
429 for (size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
430 if (m_TlbShootdown.complete()) {
431 complete = true;
432 break;
433 }
435 }
436
437 m_TlbShootdown.close();
438 for (size_t poll = 0; !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit; ++poll) {
440 }
441 if (!m_TlbShootdown.drained()) {
442 return TlbInvalidationResult::DrainTimedOut;
443 }
444 if (!complete) {
445 return TlbInvalidationResult::AcknowledgementTimedOut;
446 }
447 return releaseTlbShootdownBarrier() ? TlbInvalidationResult::Success
448 : TlbInvalidationResult::DrainTimedOut;
449}
450
451TlbInvalidationResult LocalApic::beginTlbInvalidation(bool& global) {
452 global = false;
453 const ExecutionContext context = Processor::executionContext();
454 if (!LocalApicTlbShootdown::supportsContext(context)) {
455 return TlbInvalidationResult::InvalidContext;
456 }
457
458 const size_t processorCount = Processor::getCount();
459 const size_t processor = Processor::index();
460 if (!processorCount || processorCount > LocalApicTlbShootdown::MaxProcessors ||
461 processor >= processorCount) {
462 return TlbInvalidationResult::UnsupportedTopology;
463 }
464
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;
470 }
471 if (m_TlbMutations.terminalClosed()) {
472 return TlbInvalidationResult::SerialisationTimedOut;
473 }
474 if (m_TlbMutations.tryEnter()) {
475 global = true;
476 return TlbInvalidationResult::Success;
477 }
479 }
480 return TlbInvalidationResult::SerialisationTimedOut;
481}
482
483void LocalApic::endTlbInvalidation() {
484 if (!m_TlbMutations.leave()) {
485 FATAL("Local APIC TLB mutation admission underflow");
486 }
487}
488
489bool LocalApic::closeTlbInvalidationAdmissionForTerminalFailure(TlbInvalidationResult result) {
490 const size_t processor = Processor::index();
491 const bool coordinator = m_TlbTerminalFailure.elect(processor, static_cast<size_t>(result));
492 if (!m_TlbMutations.closeTerminal()) {
493 return false;
494 }
495 return coordinator;
496}
497
498bool LocalApic::tlbInvalidationFailureActive() const {
499 return m_TlbTerminalFailure.active();
500}
501
502bool LocalApic::tlbInvalidationTerminal() const {
503 return m_TlbMutations.terminalClosed();
504}
505
506void LocalApic::servicePendingTlbShootdown() {
507 // This is only a fast-path hint; beginService publishes and revalidates its
508 // reader lease before using any generation data.
509 if (!m_TlbShootdown.generation()) {
510 return;
511 }
512
513 const bool restoreInterrupts = Processor::getInterrupts();
515
516 const size_t processor = Processor::index();
518 if (!m_TlbShootdown.beginService(processor, service)) {
519 Processor::setInterrupts(restoreInterrupts);
520 return;
521 }
522
523 Processor::invalidate(reinterpret_cast<void*>(service.address));
524 m_TlbShootdown.finishService(service);
525 Processor::setInterrupts(restoreInterrupts);
526}
527
528void LocalApic::servicePendingTerminalProcessorControl() {
529 if (!m_TlbMutations.terminalClosed()) {
530 return;
531 }
532
533 const ProcessorControlState state = processorControlState();
534 const size_t processor = Processor::index();
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) {
540 return;
541 }
542
543 enterTerminalProcessorControl();
544}
545
546bool LocalApic::acquireTlbShootdownBarrier() {
547 for (size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
548 if (m_TlbShootdown.tryAcquire()) {
549 return true;
550 }
551
552 // The current processor can be part of the transaction which owns the
553 // barrier, including while it holds an IRQ-disabling lock.
554 servicePendingTlbShootdown();
556 }
557 return false;
558}
559
560bool LocalApic::releaseTlbShootdownBarrier() {
561 for (size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
562 if (!m_TlbShootdown.generation() && m_TlbShootdown.drained() && m_TlbShootdown.release()) {
563 return true;
564 }
566 }
567 return !m_TlbShootdown.generation() && m_TlbShootdown.drained() && m_TlbShootdown.release();
568}
569
570bool LocalApic::waitForTlbMutationDrain() {
571 for (size_t poll = 0; poll < TlbShootdownPollLimit; ++poll) {
572 if (m_TlbMutations.drained()) {
573 return true;
574 }
575 servicePendingTlbShootdown();
577 }
578 return m_TlbMutations.drained();
579}
580
581LocalApic::ProcessorControlState LocalApic::processorControlState() const {
582 return static_cast<ProcessorControlState>(m_ProcessorControlState.value());
583}
584
585bool LocalApic::acquireProcessorControlOwner(bool acceptRetained,
586 ProcessorControlOwnership& ownership) {
587 ownership = ProcessorControlOwnership::Fresh;
588 const size_t processor = Processor::index();
589 if (processor >= LocalApicProcessorControlOwner::MaxProcessors) {
590 return false;
591 }
592
593 if (acceptRetained && m_ProcessorControlOwner.claimAnyQuiesced(processor)) {
594 ownership = ProcessorControlOwnership::Quiesced;
595 return true;
596 }
597 if (acceptRetained && m_ProcessorControlOwner.claimAnyFailed(processor)) {
598 ownership = ProcessorControlOwnership::Failed;
599 return true;
600 }
601 if (acceptRetained && m_ProcessorControlOwner.claimTerminal(processor)) {
602 ownership = ProcessorControlOwnership::Terminal;
603 return true;
604 }
605 if (acceptRetained && m_ProcessorControlOwner.activeBy(processor)) {
606 return true;
607 }
608
609 for (size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
610 if (m_ProcessorControlOwner.tryAcquire(processor)) {
611 return true;
612 }
613 if (acceptRetained && m_ProcessorControlOwner.claimAnyQuiesced(processor)) {
614 ownership = ProcessorControlOwnership::Quiesced;
615 return true;
616 }
617 if (acceptRetained && m_ProcessorControlOwner.claimAnyFailed(processor)) {
618 ownership = ProcessorControlOwnership::Failed;
619 return true;
620 }
621 if (acceptRetained && m_ProcessorControlOwner.claimTerminal(processor)) {
622 ownership = ProcessorControlOwnership::Terminal;
623 return true;
624 }
625 if (acceptRetained && m_ProcessorControlOwner.activeBy(processor)) {
626 return true;
627 }
629 }
630 return false;
631}
632
633bool LocalApic::releaseProcessorControlOwner() {
634 return m_ProcessorControlOwner.release(Processor::index());
635}
636
637LocalApic::ProcessorControlResult LocalApic::completeTerminalControl(size_t expectedProcessors) {
638 if (!waitForTerminalProcessorCount(expectedProcessors)) {
639 return retainTerminalControl(ProcessorControlResult::AcknowledgementTimedOut);
640 }
641
642 const size_t processor = Processor::index();
643 if (!m_ProcessorControlOwner.activeBy(processor)) {
644 return ProcessorControlResult::InvalidState;
645 }
646
647 for (size_t poll = 0;
648 m_TlbShootdown.owned() && !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit;
649 ++poll) {
651 }
652 ProcessorControlResult result = ProcessorControlResult::Success;
653 if (m_TlbShootdown.owned() && !releaseTlbShootdownBarrier()) {
654 result = ProcessorControlResult::DrainTimedOut;
655 }
656 return retainTerminalControl(result);
657}
658
659LocalApic::ProcessorControlResult LocalApic::retainTerminalControl(ProcessorControlResult result) {
660 return m_ProcessorControlOwner.markTerminal(Processor::index())
661 ? result
662 : ProcessorControlResult::DrainTimedOut;
663}
664
665bool LocalApic::adoptTerminalTlbShootdownBarrier() {
666 if (!m_TlbMutations.terminalClosed() || !m_TlbMutations.drained()) {
667 return false;
668 }
669
670 if (!m_TlbShootdown.owned() && !m_TlbShootdown.tryAcquire()) {
671 return false;
672 }
673 if (m_TlbShootdown.generation()) {
674 return false;
675 }
676
677 // A service path may have read the old generation immediately before its
678 // owner closed it. Keep the retained barrier and wait for that observer to
679 // reject the stale generation before adopting the orphaned owner.
680 for (size_t poll = 0; !m_TlbShootdown.drained() && poll < TlbShootdownPollLimit; ++poll) {
682 }
683 return !m_TlbShootdown.generation() && m_TlbShootdown.drained();
684}
685
686bool LocalApic::waitForProcessorCount(size_t expectedProcessors) {
687 for (size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
688 if (m_ControlledProcessorCount >= expectedProcessors)
689 return true;
691 }
692 return m_ControlledProcessorCount >= expectedProcessors;
693}
694
695bool LocalApic::waitForTerminalProcessorCount(size_t expectedProcessors) {
696 for (size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
697 if (m_TerminalProcessorCount >= expectedProcessors)
698 return true;
700 }
701 return m_TerminalProcessorCount >= expectedProcessors;
702}
703
704bool LocalApic::waitForProcessorDrain() {
705 for (size_t poll = 0; poll < ProcessorControlPollLimit; ++poll) {
706 if (!m_ControlledProcessorCount)
707 return true;
709 }
710 return !m_ControlledProcessorCount;
711}
712
713bool LocalApic::markTerminalProcessor(size_t processor) {
714 if (processor >= LocalApicTlbShootdown::MaxProcessors) {
715 return false;
716 }
717
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;
723 return true;
724 }
725 mask = m_TerminalProcessorMask.value();
726 }
727 return false;
728}
729
730void LocalApic::enterTerminalProcessorControl() {
732 while (processorControlState() != ProcessorControlState::Terminal) {
733 // Processor::pause() would recurse into this cooperative service path.
734 asm volatile("pause");
735 }
736
737 markTerminalProcessor(Processor::index());
738 while (true) {
740 }
741}
742
743LocalApic::ProcessorControlResult LocalApic::retainQuiescedControl(ProcessorControlResult result) {
744 if (!releaseTlbShootdownBarrier()) {
745 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
746 }
747 if (m_ProcessorControlOwner.markQuiesced(Processor::index())) {
748 return result;
749 }
750 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
751}
752
753LocalApic::ProcessorControlResult LocalApic::retainFailedControl(ProcessorControlResult result) {
754 return m_ProcessorControlOwner.markFailed(Processor::index())
755 ? result
756 : ProcessorControlResult::DrainTimedOut;
757}
758
759LocalApic::ProcessorControlResult LocalApic::releaseProcessorControlOrRetainFailure(
760 ProcessorControlResult released, ProcessorControlResult retained) {
761 if (releaseProcessorControlOwner()) {
762 return released;
763 }
764 return retainFailedControl(retained);
765}
766
767LocalApic::ProcessorControlResult LocalApic::finishFailedQuiesce(ProcessorControlResult result) {
768 if (!releaseTlbShootdownBarrier()) {
769 result = ProcessorControlResult::DrainTimedOut;
770 }
771 return retainFailedControl(result);
772}
773
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;
779 }
780
781 // The IPI transaction may have timed out after submission. Keep this
782 // generation unavailable so a late interrupt cannot acknowledge a future
783 // quiesce attempt.
784 return waitForProcessorDrain() ? failure : ProcessorControlResult::DrainTimedOut;
785}
786
787LocalApic::ProcessorControlResult LocalApic::quiesceAllOtherProcessors(size_t expectedProcessors) {
788 if (!expectedProcessors)
789 return ProcessorControlResult::Success;
790
791 ProcessorControlOwnership ownership = ProcessorControlOwnership::Fresh;
792 if (!acquireProcessorControlOwner(false, ownership)) {
793 return ProcessorControlResult::InvalidState;
794 }
795 if (processorControlState() != ProcessorControlState::Idle) {
796 if (m_TlbMutations.terminalClosed()) {
797 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
798 ProcessorControlResult::InvalidState);
799 }
800 // Terminal is already safe and needs no retained owner. Any other state
801 // is inconsistent without an existing owner, so fail closed and publish
802 // the abandoned operation as transferable only after this last access.
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);
810 }
811 }
812 return retainFailedControl(ProcessorControlResult::InvalidState);
813 }
814 if (!waitForProcessorDrain()) {
815 if (m_TlbMutations.terminalClosed()) {
816 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
817 ProcessorControlResult::InvalidState);
818 }
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);
825 }
826 if (!m_TlbMutations.closed()) {
827 if (!m_TlbMutations.closeReversible() && m_TlbMutations.terminalClosed()) {
828 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
829 ProcessorControlResult::InvalidState);
830 }
831 }
832 return retainFailedControl(ProcessorControlResult::InvalidState);
833 }
834 // A stale control generation did not drain. Retain ownership and close
835 // mapping admission so neither a new quiesce nor halt can reuse it.
836 if (m_TlbMutations.terminalClosed()) {
837 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
838 ProcessorControlResult::InvalidState);
839 }
840 if (!m_TlbMutations.closeReversible()) {
841 if (m_TlbMutations.terminalClosed()) {
842 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
843 ProcessorControlResult::InvalidState);
844 }
845 return retainFailedControl(ProcessorControlResult::InvalidState);
846 }
847 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
848 }
849
850 // Admission begins before the VAS lock and first PTE write. Closing it here
851 // therefore drains both published shootdowns and the mutation-before-
852 // publication window before any processor can be paused.
853 if (!m_TlbMutations.closeReversible()) {
854 if (m_TlbMutations.terminalClosed()) {
855 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
856 ProcessorControlResult::InvalidState);
857 }
858 return retainFailedControl(ProcessorControlResult::InvalidState);
859 }
860 if (!waitForTlbMutationDrain()) {
861 if (m_TlbMutations.terminalClosed()) {
862 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
863 ProcessorControlResult::InvalidState);
864 }
865 // No processor-control state has changed, so a debugger which interrupted
866 // an admitted mapper can safely cancel this close and resume that mapper.
867 if (!m_TlbMutations.cancelClose()) {
868 if (m_TlbMutations.terminalClosed()) {
869 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
870 ProcessorControlResult::InvalidState);
871 }
872 return retainFailedControl(ProcessorControlResult::InvalidState);
873 }
874 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
875 ProcessorControlResult::InvalidState);
876 }
877 if (m_TlbMutations.terminalClosed()) {
878 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
879 ProcessorControlResult::InvalidState);
880 }
881
882 // Do not interrupt a remote shootdown owner inside its synchronous wait.
883 // Once this barrier is held, changing Idle to Paused closes the interval in
884 // which a published generation can be stranded by the control IPI.
885 if (!acquireTlbShootdownBarrier()) {
886 if (m_TlbMutations.terminalClosed()) {
887 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
888 ProcessorControlResult::InvalidState);
889 }
890 if (!m_TlbMutations.reopen()) {
891 if (m_TlbMutations.terminalClosed()) {
892 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
893 ProcessorControlResult::InvalidState);
894 }
895 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
896 }
897 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::DrainTimedOut,
898 ProcessorControlResult::InvalidState);
899 }
900 if (processorControlState() != ProcessorControlState::Idle) {
901 // The control owner excludes legitimate state changes here. Keep the
902 // mutation gate closed and ownership retained on any invariant failure.
903 return finishFailedQuiesce(ProcessorControlResult::InvalidState);
904 }
905 if (!m_ProcessorControlState.compareAndSwap(static_cast<size_t>(ProcessorControlState::Idle),
906 static_cast<size_t>(ProcessorControlState::Paused))) {
907 return finishFailedQuiesce(ProcessorControlResult::InvalidState);
908 }
909
910 // Once Paused is visible, terminal observers may already be waiting for the
911 // irreversible state. Retain this completed pause for the elected terminal
912 // coordinator instead of publishing Unavailable underneath them.
913 if (m_TlbMutations.terminalClosed()) {
914 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
915 }
916
917 const bool submitted =
918 interProcessorInterruptAllExcludingThis(IPI_PROCESSOR_CONTROL_VECTOR, deliveryModeFixed);
919 if (m_TlbMutations.terminalClosed()) {
920 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
921 }
922 if (!submitted) {
923 const ProcessorControlResult result = unwindQuiesce(ProcessorControlResult::SubmissionFailed);
924 return finishFailedQuiesce(result);
925 }
926 if (!waitForProcessorCount(expectedProcessors)) {
927 if (m_TlbMutations.terminalClosed()) {
928 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
929 }
930 const ProcessorControlResult result =
931 unwindQuiesce(ProcessorControlResult::AcknowledgementTimedOut);
932 return finishFailedQuiesce(result);
933 }
934 if (m_TlbMutations.terminalClosed()) {
935 return retainQuiescedControl(ProcessorControlResult::DrainTimedOut);
936 }
937 if (processorControlState() != ProcessorControlState::Paused) {
938 return finishFailedQuiesce(ProcessorControlResult::InvalidState);
939 }
940 return retainQuiescedControl(ProcessorControlResult::Success);
941}
942
943LocalApic::ProcessorControlResult LocalApic::resumeAllOtherProcessors() {
944 const size_t processor = Processor::index();
945 if (!m_ProcessorControlOwner.claimQuiesced(processor)) {
946 return ProcessorControlResult::InvalidState;
947 }
948 if (m_TlbMutations.terminalClosed()) {
949 if (m_ProcessorControlOwner.markQuiesced(processor)) {
950 return ProcessorControlResult::InvalidState;
951 }
952 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
953 }
954 if (!m_ProcessorControlState.compareAndSwap(
955 static_cast<size_t>(ProcessorControlState::Paused),
956 static_cast<size_t>(ProcessorControlState::Unavailable))) {
957 return retainFailedControl(ProcessorControlResult::InvalidState);
958 }
959 if (!waitForProcessorDrain()) {
960 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
961 }
962 if (!m_ProcessorControlState.compareAndSwap(
963 static_cast<size_t>(ProcessorControlState::Unavailable),
964 static_cast<size_t>(ProcessorControlState::Idle))) {
965 return retainFailedControl(ProcessorControlResult::InvalidState);
966 }
967 if (!m_TlbMutations.reopen()) {
968 if (!m_TlbMutations.closed()) {
969 return releaseProcessorControlOrRetainFailure(ProcessorControlResult::InvalidState,
970 ProcessorControlResult::DrainTimedOut);
971 }
972 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
973 }
974 if (releaseProcessorControlOwner()) {
975 return ProcessorControlResult::Success;
976 }
977 return retainFailedControl(ProcessorControlResult::DrainTimedOut);
978}
979
980LocalApic::ProcessorControlResult LocalApic::haltAllOtherProcessors(size_t expectedProcessors) {
981 if (!expectedProcessors)
982 return ProcessorControlResult::Success;
983
984 ProcessorControlOwnership ownership = ProcessorControlOwnership::Fresh;
985 if (!acquireProcessorControlOwner(true, ownership)) {
986 return ProcessorControlResult::InvalidState;
987 }
988 if (!m_TlbMutations.closeTerminal() || !waitForTlbMutationDrain()) {
989 return retainTerminalControl(ProcessorControlResult::DrainTimedOut);
990 }
991 if (!adoptTerminalTlbShootdownBarrier()) {
992 return retainTerminalControl(ProcessorControlResult::DrainTimedOut);
993 }
994
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;
1002 break;
1003 }
1005 }
1006 if (!terminalSelected) {
1007 return retainTerminalControl(ProcessorControlResult::InvalidState);
1008 }
1009
1010 // Retried terminal operations resend the IPI only to prompt peers which did
1011 // not observe the first attempt. The terminal mask makes acknowledgements
1012 // idempotent for processors which were already committed.
1013 if (!interProcessorInterruptAllExcludingThis(IPI_PROCESSOR_CONTROL_VECTOR, deliveryModeFixed)) {
1014 return retainTerminalControl(ProcessorControlResult::SubmissionFailed);
1015 }
1016 return completeTerminalControl(expectedProcessors);
1017}
1018
1019bool LocalApic::waitForIcrIdle() {
1020 if (m_X2Apic) {
1021 return true;
1022 }
1023 for (size_t poll = 0; poll < IcrDeliveryPollLimit; ++poll) {
1024 if ((readRegister(LAPIC_REG_INT_CMD_LOW) & 0x1000) == 0)
1025 return true;
1027 }
1028 return (readRegister(LAPIC_REG_INT_CMD_LOW) & 0x1000) == 0;
1029}
1030
1031bool LocalApic::submitIcr(uint32_t high, uint32_t low) {
1034
1035 bool submitted = waitForIcrIdle();
1036 if (submitted) {
1037 if (m_X2Apic) {
1038 Processor::writeMachineSpecificRegister(LocalApicMode::X2ApicIcrMsr,
1039 LocalApicMode::x2ApicIcr(high, low));
1040 } else {
1041 writeRegister(high, LAPIC_REG_INT_CMD_HIGH);
1042 writeRegister(low, LAPIC_REG_INT_CMD_LOW);
1043 submitted = waitForIcrIdle();
1044 }
1045 }
1046
1047 Processor::setInterrupts(transaction.restoreInterrupts());
1048 return submitted;
1049}
1050
1051uint8_t LocalApic::getId() {
1052 const uint32_t id = readRegister(LAPIC_REG_ID);
1053 return m_X2Apic ? id : (id >> 24) & 0xFF;
1054}
1055
1056bool LocalApic::check(uint64_t physicalAddress) {
1057 const uint64_t apicBase = Processor::readMachineSpecificRegister(LocalApicMode::BaseMsr);
1058 const LocalApicMode::Mode mode = LocalApicMode::decode(apicBase);
1059 // An invalid or changed inherited mode cannot use either register backend.
1060 if (mode == LocalApicMode::Mode::Invalid || (mode == LocalApicMode::Mode::X2Apic) != m_X2Apic) {
1061 // panic() sends stop IPIs, which could use the wrong register backend.
1062 haltInvalidApicMode("inherited APIC mode changed or is invalid");
1063 }
1064 if (mode == LocalApicMode::Mode::Disabled) {
1065 ERROR("Local APIC: Disabled");
1066 return false;
1067 }
1068
1069 // Check Local APIC base address
1070 if ((apicBase & 0xFFFFFFFFFFFFF000ULL) != physicalAddress) {
1071 ERROR("Local APIC: Wrong physical address");
1072 return false;
1073 }
1074
1075 return true;
1076}
1077
1078uint32_t LocalApic::readRegister(uint32_t offset) {
1079 if (m_X2Apic) {
1080 return Processor::readMachineSpecificRegister(LocalApicMode::x2ApicMsr(offset));
1081 }
1082 return m_IoSpace.read32(offset);
1083}
1084
1085void LocalApic::writeRegister(uint32_t value, uint32_t offset) {
1086 if (m_X2Apic) {
1087 Processor::writeMachineSpecificRegister(LocalApicMode::x2ApicMsr(offset), value);
1088 } else {
1089 m_IoSpace.write32(value, offset);
1090 }
1091}
1092
1093void LocalApic::interrupt(size_t nInterruptNumber, InterruptState& state) {
1094 if (nInterruptNumber == IPI_TLB_SHOOTDOWN_VECTOR) {
1095 ack();
1096 servicePendingTlbShootdown();
1097 return;
1098 }
1099
1100 if (nInterruptNumber == TIMER_VECTOR || nInterruptNumber == IPI_RESCHEDULE_VECTOR) {
1101 // Ack early. timer() may schedule away and an IPI must never retain
1102 // its hard frame while the remote producer waits for progress.
1103 ack();
1104
1105 uint64_t delta = 0;
1106 if (nInterruptNumber == TIMER_VECTOR) {
1107 TimerState& timer = m_TimerState[getId()];
1108 timer.armedDeadlineNs = 0;
1109 const uint64_t now = Time::getTicksFast();
1110 // Zero identifies a reschedule IPI to the scheduler.
1111 delta = timer.oneShot ? (now > timer.lastInterruptNs ? now - timer.lastInterruptNs : 1)
1112 : nominalQuantumNs();
1113 timer.lastInterruptNs = now;
1114 }
1115
1116 // Load only after acknowledging the delivered vector. The slot is
1117 // qualified by the receiving physical processor's scheduler owner,
1118 // so an IPI can neither borrow another CPU's timer callback nor carry
1119 // an interrupted register frame into a bottom-half callback.
1121 if (LIKELY(m_Handlers.beginDispatch(getId(), dispatch))) {
1122 SchedulerTimerDispatchCleanup dispatchCleanup(dispatch);
1123 ExecutionContextGuard schedulerContext(ExecutionContext::SchedulerIrq);
1124 dispatch.handler()->timer(delta, state);
1125 }
1126 return;
1127 }
1128
1129 // This IPI temporarily pauses processors for the debugger or permanently
1130 // halts them for panic and shutdown paths.
1131 if (nInterruptNumber == IPI_PROCESSOR_CONTROL_VECTOR) {
1132 ack();
1134 const ProcessorControlState initialState = processorControlState();
1135 if (m_TlbMutations.terminalClosed() && (initialState == ProcessorControlState::Paused ||
1136 initialState == ProcessorControlState::Terminal)) {
1137 enterTerminalProcessorControl();
1138 }
1139
1140 m_ControlledProcessorCount += 1;
1141 while (true) {
1142 const ProcessorControlState controlState = processorControlState();
1143 if (controlState == ProcessorControlState::Idle ||
1144 controlState == ProcessorControlState::Unavailable) {
1145 m_ControlledProcessorCount -= 1;
1146 return;
1147 }
1148 if (controlState == ProcessorControlState::Terminal) {
1149 m_ControlledProcessorCount -= 1;
1150 markTerminalProcessor(Processor::index());
1151 while (true) {
1153 }
1154 }
1155 asm volatile("pause");
1156 }
1157 }
1158}
1159
1160void LocalApic::ack() {
1161 // Send EOI.
1162 writeRegister(0, LAPIC_REG_EOI);
1163}
1164
1165#endif
static EXPORTED_PUBLIC InterruptManager & instance()
static PhysicalMemoryManager & instance()
virtual bool allocateRegion(MemoryRegion &Region, size_t cPages, size_t pageConstraints, size_t Flags, physical_uintptr_t start=-1)=0
static void halt()
static bool getInterrupts()
static size_t getCount()
static void pause()
static ExecutionContext executionContext()
Definition Processor.cc:109
static void invalidate(void *pAddress)
static ProcessorInformation * informationAt(size_t cpu)
Definition Processor.cc:39
static void setInterrupts(bool bEnable)
static size_t index()
virtual void timer(uint64_t delta, InterruptState &state)=0
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)
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
TlbInvalidationResult
Definition Processor.h:56
uintptr_t physicalAddress(physical_uintptr_t address) PURE
Definition utils.h:39