27#include "pedigree/kernel/Log.h"
28#include "pedigree/kernel/machine/Bus.h"
29#include "pedigree/kernel/machine/Controller.h"
30#include "pedigree/kernel/machine/Device.h"
31#include "pedigree/kernel/machine/Pci.h"
32#include "pedigree/kernel/panic.h"
33#include "pedigree/kernel/processor/Processor.h"
34#include "pedigree/kernel/utilities/String.h"
35#include "pedigree/kernel/utilities/Vector.h"
36#include "pedigree/kernel/utilities/new"
53constexpr uint32_t Ia32TscAux = 0xC0000103;
54constexpr uint32_t RdtscpFeature = 1u << 27;
56bool supportsRdtscp() {
57 uint32_t maxLeaf, unusedEax, unusedEbx, unusedEcx, unusedEdx;
59 if (maxLeaf < 0x80000001) {
64 return (unusedEdx & RdtscpFeature) != 0;
67void initialiseVdsoCpuId() {
68 if (!supportsRdtscp()) {
83bool reportProcessorControlResult(LocalApic::ProcessorControlResult result,
const char* operation) {
84 if (result != LocalApic::ProcessorControlResult::Success &&
92 case LocalApic::ProcessorControlResult::Success:
94 case LocalApic::ProcessorControlResult::InvalidState:
95 ERROR_NOLOCK(
"Pc: " << operation <<
" failed: invalid processor state");
97 case LocalApic::ProcessorControlResult::SubmissionFailed:
98 ERROR_NOLOCK(
"Pc: " << operation <<
" IPI transaction failed");
100 case LocalApic::ProcessorControlResult::AcknowledgementTimedOut:
101 ERROR_NOLOCK(
"Pc: " << operation <<
" acknowledgement timed out");
103 case LocalApic::ProcessorControlResult::DrainTimedOut:
104 ERROR_NOLOCK(
"Pc: " << operation <<
" processor-control drain timed out");
112bool Pc::supportsPowerOff()
const {
114 return Acpi::instance().supportsPowerOff();
122 return Acpi::instance().prepareShutdown(type == ShutdownType::PowerOff);
129 if (type == ShutdownType::PowerOff) {
130 NOTICE_NOLOCK(
"Powering off...");
132 return Acpi::instance().powerOff();
134 return "ACPI power-off support is disabled.";
136 }
else if (type == ShutdownType::Restart) {
137 NOTICE_NOLOCK(
"Rebooting...");
139 Acpi::instance().reset();
143 for (
size_t i = 0; i < 100000; ++i) {
145 asm volatile(
"inb %1, %0" :
"=a"(status) :
"Nd"(uint16_t(0x64)));
147 asm volatile(
"outb %0, %1" : :
"a"(uint8_t(0xfe)),
"Nd"(uint16_t(0x64)));
151 for (
size_t i = 0; i < 100000; ++i)
152 asm volatile(
"pause");
154 return "The firmware reset request returned without restarting the computer.";
156 NOTICE_NOLOCK(
"System halted");
164 if (m_Vga->initialise() ==
false)
165 panic(
"Pc: Vga initialisation failed");
167 uint8_t rtcCenturyIndex = 0;
169 Acpi& acpi = Acpi::instance();
171 rtcCenturyIndex = acpi.getRtcCenturyIndex();
174 Rtc& rtc = Rtc::instance();
176 panic(
"Pc: Rtc initialisation phase 1 failed");
178 panic(
"Pc: Rtc initialisation phase 2 failed");
180 bool localApicInitialised =
false;
181#if MULTIPROCESSOR && ACPI
182 const uint64_t localApicAddress = acpi.getLocalApicAddress();
183 if (acpi.validApicInfo() && localApicAddress && m_LocalApic->initialise(localApicAddress)) {
184 localApicInitialised =
true;
185 NOTICE(
"Local APIC initialised");
189 m_SchedulerTimerSelection.recordLocalApicInitialisation(localApicInitialised);
191 NOTICE(
"Falling back to dual 8259 PIC Mode");
194 panic(
"Pc: Pic initialisation failed");
203 if (m_SchedulerTimerSelection.usesPit()) {
204 NOTICE(
"Using PIT scheduler timer fallback");
207 panic(
"Pc: Pit initialisation failed");
211 m_Ps2Controller->initialise();
215 initialiseVdsoCpuId();
217 m_bInitialised =
true;
221 if (!m_bInitialised) {
230 m_Keyboard->stopReaderThread();
231 if (m_SchedulerTimerSelection.usesPit()) {
237 panic(
"Shutdown aborted: threaded IRQ workers did not stop");
239 m_bInitialised =
false;
243void Pc::initialiseProcessor() {
247 if (m_LocalApic->initialiseProcessor() ==
false)
248 panic(
"Pc::initialiseProcessor(): Failed to initialise the local APIC");
253 initialiseVdsoCpuId();
259 panic(
"Pc: threaded IRQ worker initialisation failed");
262 panic(
"Pc: RTC bottom-half initialisation failed");
265 panic(
"Pc: PS/2 bottom-half initialisation failed");
267 m_Keyboard->startReaderThread();
271 for (
size_t i = 0; i < 4; ++i) {
277 m_IsaBus =
new Bus(
"ISA");
280 m_Watchdog =
new Device();
283 m_pKeyboard = m_Keyboard =
new X86Keyboard(m_Ps2Controller);
286 m_LocalApic =
new LocalApic();
311 m_IsaBus->
addChild(m_Ps2Controller);
347 if (m_SchedulerTimerSelection.usesLocalApic()) {
355 return &Rtc::instance();
373 return reportProcessorControlResult(
374 m_LocalApic->quiesceAllOtherProcessors(processorCount > 1 ? processorCount - 1 : 0),
375 "processor quiesce");
381 return reportProcessorControlResult(m_LocalApic->resumeAllOtherProcessors(),
"processor resume");
386 return reportProcessorControlResult(
387 m_LocalApic->haltAllOtherProcessors(processorCount > 1 ? processorCount - 1 : 0),
395 m_pKeyboard(nullptr),
397 m_LocalApic(nullptr),
399 m_SchedulerTimerSelection(),
402 m_AtaMaster(nullptr),
404 m_Ps2Controller(nullptr),
405 m_Watchdog(nullptr) {
406 for (
size_t i = 0; i < 4; ++i) {
407 m_pSerial[i] =
nullptr;
static void addToRoot(Device *device)
virtual Vector< Address * > & addresses()
virtual void setInterruptNumber(uintptr_t n)
void addChild(Device *pDevice)
virtual void setSpecificType(String str)
void setParent(Device *p)
virtual MUST_USE_RESULT bool quiesceAllOtherProcessors()
static void setShutdownPhase(ShutdownPhase phase, const char *detail=nullptr)
virtual MUST_USE_RESULT bool resumeAllOtherProcessors()
virtual MUST_USE_RESULT bool stopAllOtherProcessors()
virtual void initialise3()
Called after processor startup - for thread creation etc.
virtual void initialise() INITIALISATION_ONLY
virtual Serial * getSerial(size_t n)
virtual Timer * getTimer()
virtual Vga * getVga(size_t n)
virtual SchedulerTimer * getSchedulerTimer()
virtual void initialiseDeviceTree()
bool prepareShutdown(ShutdownType type) override
virtual void deinitialise()
virtual size_t getNumSerial()
virtual void setKeyboard(Keyboard *kb)
virtual Keyboard * getKeyboard()
const char * finalShutdown(ShutdownType type) override
virtual size_t getNumVga()
bool initialise() INITIALISATION_ONLY
bool initialise() INITIALISATION_ONLY
static bool tlbInvalidationTerminal()
bool initialise1(uint8_t centuryIndex) INITIALISATION_ONLY
bool initialise2() INITIALISATION_ONLY
void initialiseProcessorClock() INITIALISATION_ONLY
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)
virtual void initialise()
Initialises the device.
virtual void setBase(uintptr_t nBaseAddr)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN