Improved APIC (more human readable)

This commit is contained in:
Alex 2022-10-25 02:24:37 +03:00
parent 7918999799
commit 6af8c9c4ee
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
3 changed files with 136 additions and 17 deletions

View File

@ -2,6 +2,7 @@
#include <memory.hpp>
#include <uart.hpp>
#include <lock.hpp>
#include <cpu.hpp>
#include <smp.hpp>
#include <io.h>
@ -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);

View File

@ -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();

View File

@ -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);