From 6af8c9c4ee2d8995cabdad5ae287d95de47770a6 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 25 Oct 2022 02:24:37 +0300 Subject: [PATCH] Improved APIC (more human readable) --- ...dvancedProgrammableInterruptController.cpp | 77 ++++++++++++++++--- .../amd64/cpu/SymmetricMultiprocessing.cpp | 9 +-- Architecture/amd64/cpu/apic.hpp | 67 +++++++++++++++- 3 files changed, 136 insertions(+), 17 deletions(-) diff --git a/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp index 2930660..4083531 100644 --- a/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp +++ b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -9,6 +10,8 @@ #include "../../../kernel.h" #include "../acpi.hpp" +NewLock(APICLock); + using namespace CPU::x64; namespace APIC @@ -81,25 +84,67 @@ namespace APIC void APIC::EOI() { this->Write(APIC_EOI, 0); } - void APIC::RedirectIRQs(int CPU) + void APIC::WaitForIPI() { - debug("Redirecting IRQs..."); - for (int i = 0; i < 16; i++) - this->RedirectIRQ(CPU, i, 1); - debug("Redirecting IRQs completed."); + InterruptCommandRegisterLow icr; + do + { + icr.raw = this->Read(APIC_ICRLO); + } while (icr.DeliveryStatus != 0); } - void APIC::IPI(uint8_t CPU, uint32_t InterruptNumber) + void APIC::IPI(uint8_t CPU, InterruptCommandRegisterLow icr) { + SmartCriticalSection(APICLock); if (x2APICSupported) { - wrmsr(MSR_X2APIC_ICR, ((uint64_t)CPU) << 32 | InterruptNumber); + fixme("Not implemented for x2APIC"); + // wrmsr(MSR_X2APIC_ICR, ((uint64_t)CPU) << 32); } else { - InterruptNumber = (1 << 14) | InterruptNumber; this->Write(APIC_ICRHI, (CPU << 24)); - this->Write(APIC_ICRLO, InterruptNumber); + this->Write(APIC_ICRLO, icr.raw); + this->WaitForIPI(); + } + } + + void APIC::SendInitIPI(uint8_t CPU) + { + SmartCriticalSection(APICLock); + if (x2APICSupported) + { + fixme("Not implemented for x2APIC"); + // wrmsr(MSR_X2APIC_ICR, ((uint64_t)CPU) << 32); + } + else + { + InterruptCommandRegisterLow icr; + icr.DeliveryMode = INIT; + icr.Level = 1; + this->Write(APIC_ICRHI, (CPU << 24)); + this->Write(APIC_ICRLO, icr.raw); + this->WaitForIPI(); + } + } + + void APIC::SendStartupIPI(uint8_t CPU, uint64_t StartupAddress) + { + SmartCriticalSection(APICLock); + if (x2APICSupported) + { + warn("Not tested for x2APIC"); + wrmsr(MSR_X2APIC_ICR, ((uint64_t)CPU) << 32 | StartupAddress); + } + else + { + InterruptCommandRegisterLow icr; + icr.Vector = StartupAddress >> 12; + icr.DeliveryMode = Startup; + icr.Level = 1; + this->Write(APIC_ICRHI, (CPU << 24)); + this->Write(APIC_ICRLO, icr.raw); + this->WaitForIPI(); } } @@ -160,8 +205,18 @@ namespace APIC this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status); } + void APIC::RedirectIRQs(int CPU) + { + SmartCriticalSection(APICLock); + debug("Redirecting IRQs..."); + for (int i = 0; i < 16; i++) + this->RedirectIRQ(CPU, i, 1); + debug("Redirecting IRQs completed."); + } + APIC::APIC(int Core) { + SmartCriticalSection(APICLock); APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)}; APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u; trace("APIC Address: %#lx", APICBaseAddress); @@ -232,6 +287,7 @@ namespace APIC void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds) { + SmartCriticalSection(APICLock); LVTTimer timer = {.raw = 0}; timer.Vector = Vector; timer.TimerMode = 0; @@ -242,11 +298,12 @@ namespace APIC Timer::Timer(APIC *apic) : Interrupts::Handler(IRQ0) { + SmartCriticalSection(APICLock); this->lapic = apic; trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID); // Setup the spurrious interrupt vector - APICSpurious Spurious = {.raw = this->lapic->Read(APIC_SVR)}; + Spurious Spurious = {.raw = this->lapic->Read(APIC_SVR)}; Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something? Spurious.Software = 1; this->lapic->Write(APIC_SVR, Spurious.raw); diff --git a/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp b/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp index 7cbcba2..478cf41 100644 --- a/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp +++ b/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp @@ -14,8 +14,6 @@ extern "C" uint64_t _trampoline_start, _trampoline_end; -#define TRAMPOLINE_START 0x2000 - enum SMPTrampolineAddress { PAGE_TABLE = 0x500, @@ -23,7 +21,8 @@ enum SMPTrampolineAddress STACK = 0x570, GDT = 0x580, IDT = 0x590, - CORE = 0x600 + CORE = 0x600, + TRAMPOLINE_START = 0x2000 }; volatile bool CPUEnabled = false; @@ -97,8 +96,8 @@ namespace SMP POKE(volatile uint64_t, START_ADDR) = (uintptr_t)&StartCPU; - ((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRHI, (((ACPI::MADT *)madt)->lapic[i]->APICId << 24)); - ((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRLO, 0x600 | ((uint32_t)TRAMPOLINE_START / PAGE_SIZE)); + ((APIC::APIC *)Interrupts::apic[0])->SendInitIPI(((ACPI::MADT *)madt)->lapic[i]->APICId); + ((APIC::APIC *)Interrupts::apic[0])->SendStartupIPI(((ACPI::MADT *)madt)->lapic[i]->APICId, TRAMPOLINE_START); while (!CPUEnabled) CPU::Pause(); diff --git a/Architecture/amd64/cpu/apic.hpp b/Architecture/amd64/cpu/apic.hpp index e3f6fd6..9e64626 100644 --- a/Architecture/amd64/cpu/apic.hpp +++ b/Architecture/amd64/cpu/apic.hpp @@ -49,6 +49,17 @@ namespace APIC EdgeLevel = 8 }; + enum APICDeliveryMode + { + Fixed = 0, + LowestPriority = 1, + SMI = 2, + NMI = 4, + INIT = 5, + Startup = 6, + ExtINT = 7 + }; + typedef union { struct @@ -104,7 +115,56 @@ namespace APIC uint64_t Reserved1 : 19; }; uint64_t raw; - } __attribute__((packed)) APICSpurious; + } __attribute__((packed)) Spurious; + + typedef union + { + struct + { + /** @brief Interrupt Vector */ + uint64_t Vector : 8; + /** @brief Delivery Mode */ + uint64_t DeliveryMode : 3; + /** @brief Destination Mode + * + * 0: Physical + * 1: Logical + */ + uint64_t DestinationMode : 1; + /** @brief Delivery Status + * + * @note Reserved when in x2APIC mode + */ + uint64_t DeliveryStatus : 1; + /** @brief Reserved */ + uint64_t Reserved0 : 1; + /** @brief Level + * + * 0: Deassert + * 1: Assert + */ + uint64_t Level : 1; + /** @brief Trigger Mode + * + * 0: Edge + * 1: Level + */ + uint64_t TriggerMode : 1; + /** @brief Reserved */ + uint64_t Reserved1 : 2; + /** @brief Destination Shorthand + * + * 0: No shorthand + * 1: Self + * 2: All including self + * 3: All excluding self + */ + uint64_t DestinationShorthand : 2; + /** @brief Reserved */ + uint64_t Reserved2 : 12; + }; + uint64_t raw; + } __attribute__((packed)) InterruptCommandRegisterLow; typedef union { @@ -131,7 +191,10 @@ namespace APIC uint32_t IORead(uint64_t Base, uint32_t Register); void EOI(); void RedirectIRQs(int CPU = 0); - void IPI(uint8_t CPU, uint32_t InterruptNumber); + void WaitForIPI(); + void IPI(uint8_t CPU, InterruptCommandRegisterLow icr); + void SendInitIPI(uint8_t CPU); + void SendStartupIPI(uint8_t CPU, uint64_t StartupAddress); uint32_t IOGetMaxRedirect(uint32_t APICID); void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status); void RedirectIRQ(int CPU, uint8_t IRQ, int Status);