24#include "pedigree/kernel/Log.h"
25#include "pedigree/kernel/Spinlock.h"
26#include "pedigree/kernel/panic.h"
27#include "pedigree/kernel/processor/Processor.h"
28#include "pedigree/kernel/processor/ProcessorInformation.h"
29#include "pedigree/kernel/processor/VirtualAddressSpace.h"
30#include "pedigree/kernel/processor/types.h"
31#include "pedigree/kernel/utilities/Vector.h"
32#include "pedigree/kernel/utilities/utility.h"
34#include "../x64/VirtualAddressSpace.h"
35#include "Multiprocessor.h"
36#include <machine/mach_pc/Acpi.h>
37#include <machine/mach_pc/LocalApic.h>
38#include <machine/mach_pc/Pc.h>
39#include <machine/mach_pc/Rtc.h>
44Spinlock Multiprocessor::m_ProcessorLock2(
true,
true);
47constexpr uint64_t InitToStartupDelayMicroseconds = 10000;
48constexpr uint64_t StartupIpiDelayMicroseconds = 200;
49constexpr uint64_t NanosecondsPerMicrosecond = 1000;
50constexpr uint64_t ApplicationProcessorTimeoutNanoseconds = 1000000000;
51constexpr size_t EarlyBootPollLimit = 10000000;
52constexpr size_t ApplicationProcessorPollLimit = 100000000;
54bool earlyBootDelay(uint64_t microseconds) {
57 if (microseconds > (~
static_cast<uint64_t
>(0) / NanosecondsPerMicrosecond)) {
60 const uint64_t duration = microseconds * NanosecondsPerMicrosecond;
62 for (
size_t poll = 0; poll < EarlyBootPollLimit; ++poll) {
63 if ((Rtc::instance().getTickCountNano() - start) >= duration)
67 return (Rtc::instance().getTickCountNano() - start) >= duration;
72extern "C" void mp_trampoline16(
void);
73extern "C" void mp_trampoline32(
void);
74extern "C" void* trampolinegdt;
75extern "C" void* trampolinegdtr;
76extern "C" void* trampolinegdt64;
77extern "C" void* trampolinegdtr64;
83 if (!Pc::instance().localApicAvailable()) {
85 "Multiprocessor: local APIC unavailable; keeping the bootstrap "
92 Acpi& acpi = Acpi::instance();
93 if (acpi.validProcessorInfo()) {
94 Processors = &acpi.getProcessorList();
100 "Multiprocessor: couldn't find any information about multiple "
105 NOTICE(
"Multiprocessor: Found " <<
Dec << Processors->
count() <<
Hex <<
" processors");
112 MemoryCopy(
reinterpret_cast<void*
>(0x7000),
reinterpret_cast<void*
>(&mp_trampoline16), 0x100);
113 MemoryCopy(
reinterpret_cast<void*
>(0x7100),
reinterpret_cast<void*
>(&mp_trampoline32), 0x100);
116 MemoryCopy(
reinterpret_cast<void*
>(0x7200), &trampolinegdtr, 0x10);
117 MemoryCopy(
reinterpret_cast<void*
>(0x7210), &trampolinegdt, 0xF0);
119 volatile uintptr_t* trampolineStack;
120 volatile uintptr_t* trampolineKernelEntry;
121 volatile uintptr_t* trampolineKernelGsAnchor =
reinterpret_cast<volatile uintptr_t*
>(0x7FE0);
127 trampolineStack =
reinterpret_cast<volatile uintptr_t*
>(0x7FF0);
128 trampolineKernelEntry =
reinterpret_cast<volatile uintptr_t*
>(0x7FE8);
132 *
reinterpret_cast<volatile uintptr_t*
>(0x7FF8) =
137 *trampolineKernelEntry =
reinterpret_cast<uintptr_t
>(&applicationProcessorStartup);
139 LocalApic& localApic = Pc::instance().getLocalApic();
142 for (
size_t i = 0; i < Processors->
count(); ++i) {
143 if ((*Processors)[i]->apicId == localApic.getId()) {
145 (*Processors)[i]->apicId);
152 for (
size_t i = 0; i < Processors->
count(); i++) {
154 ::ProcessorInformation* pProcessorInfo = 0;
157 if (localApic.getId() != (*Processors)[i]->apicId) {
160 new ::ProcessorInformation((*Processors)[i]->processorId, (*Processors)[i]->apicId);
168 *trampolineStack =
reinterpret_cast<uintptr_t
>(pStack->getTop());
169 *trampolineKernelGsAnchor =
reinterpret_cast<uintptr_t
>(pProcessorInfo->kernelGsAnchor());
171 NOTICE(
" Booting processor #" <<
Dec << (*Processors)[i]->processorId <<
", stack at 0x"
172 <<
Hex <<
reinterpret_cast<uintptr_t
>(pStack->getTop()));
174 m_ProcessorStarted =
false;
179 if (!localApic.interProcessorInterrupt((*Processors)[i]->apicId, 0,
180 LocalApic::deliveryModeInit,
true,
true)) {
181 ERROR(
"Multiprocessor: INIT assert failed for processor #"
182 <<
Dec << (*Processors)[i]->processorId <<
" (APIC " << (*Processors)[i]->apicId
184 panic(
"Multiprocessor: INIT assert did not complete");
186 if (!localApic.interProcessorInterrupt((*Processors)[i]->apicId, 0,
187 LocalApic::deliveryModeInit,
false,
true)) {
188 ERROR(
"Multiprocessor: INIT deassert failed for processor #"
189 <<
Dec << (*Processors)[i]->processorId <<
" (APIC " << (*Processors)[i]->apicId
191 panic(
"Multiprocessor: INIT deassert did not complete");
193 if (!earlyBootDelay(InitToStartupDelayMicroseconds))
194 panic(
"Multiprocessor: early-boot INIT delay timed out");
196 if (!localApic.interProcessorInterrupt((*Processors)[i]->apicId, 0x07,
197 LocalApic::deliveryModeStartup,
true,
false)) {
199 "Multiprocessor: first STARTUP IPI failed for "
201 <<
Dec << (*Processors)[i]->processorId <<
" (APIC " << (*Processors)[i]->apicId
203 panic(
"Multiprocessor: first STARTUP IPI did not complete");
205 if (!earlyBootDelay(StartupIpiDelayMicroseconds))
206 panic(
"Multiprocessor: early-boot STARTUP delay timed out");
208 if (!m_ProcessorStarted) {
209 if (!localApic.interProcessorInterrupt((*Processors)[i]->apicId, 0x07,
210 LocalApic::deliveryModeStartup,
true,
false)) {
212 "Multiprocessor: second STARTUP IPI failed for "
214 <<
Dec << (*Processors)[i]->processorId <<
" (APIC " << (*Processors)[i]->apicId
216 panic(
"Multiprocessor: second STARTUP IPI did not complete");
218 if (!earlyBootDelay(StartupIpiDelayMicroseconds))
219 panic(
"Multiprocessor: second STARTUP delay timed out");
223 bool processorStarted =
false;
224 for (
size_t poll = 0; poll < ApplicationProcessorPollLimit; ++poll) {
225 if (m_ProcessorStarted) {
226 processorStarted =
true;
229 if ((Rtc::instance().getTickCountNano() - startupWaitStart) >=
230 ApplicationProcessorTimeoutNanoseconds)
234 if (!processorStarted && !m_ProcessorStarted) {
235 ERROR(
"Multiprocessor: processor #" <<
Dec << (*Processors)[i]->processorId <<
" (APIC "
236 << (*Processors)[i]->apicId
237 <<
") did not acknowledge startup");
238 panic(
"Multiprocessor: application processor startup timed out");
241 NOTICE(
"Currently running on CPU #" <<
Dec << localApic.getId() <<
Hex
242 <<
", skipping boot (not necessary)");
250 m_ProcessorLock2.release();
static size_t initialise1() INITIALISATION_ONLY
static void initialise2() INITIALISATION_ONLY
static Vector< ProcessorInformation * > m_ProcessorInformation
static ProcessorInformation m_SafeBspProcessorInformation
virtual uint64_t getTickCountNano()
A vector / dynamic array.
virtual Stack * allocateStack()=0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static uint64_t readMachineSpecificRegister(uint32_t index)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
void pushBack(const T &value)