mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-25 22:14:37 +00:00
Rework for APIC & added support for x2APIC
This commit is contained in:
parent
612e8cc726
commit
6d95cd5261
@ -52,22 +52,16 @@ namespace APIC
|
||||
if (Register != APIC_ICRLO &&
|
||||
Register != APIC_ICRHI &&
|
||||
Register != APIC_ID)
|
||||
debug("APIC::Read(%#lx) [x2=%d]", Register, x2APICSupported ? 1 : 0);
|
||||
debug("APIC::Read(%#lx) [x2=%d]",
|
||||
Register, x2APICSupported ? 1 : 0);
|
||||
#endif
|
||||
if (x2APICSupported)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
return s_cst(uint32_t, rdmsr((Register >> 4) + 0x800));
|
||||
else
|
||||
return s_cst(uint32_t, rdmsr(0x30 + 0x800));
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU::MemBar::Barrier();
|
||||
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
|
||||
CPU::MemBar::Barrier();
|
||||
return ret;
|
||||
}
|
||||
assert(false);
|
||||
|
||||
CPU::MemBar::Barrier();
|
||||
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
|
||||
CPU::MemBar::Barrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void APIC::Write(uint32_t Register, uint32_t Value)
|
||||
@ -79,21 +73,15 @@ namespace APIC
|
||||
Register != APIC_TICR &&
|
||||
Register != APIC_ICRLO &&
|
||||
Register != APIC_ICRHI)
|
||||
debug("APIC::Write(%#lx, %#lx) [x2=%d]", Register, Value, x2APICSupported ? 1 : 0);
|
||||
debug("APIC::Write(%#lx, %#lx) [x2=%d]",
|
||||
Register, Value, x2APICSupported ? 1 : 0);
|
||||
#endif
|
||||
if (x2APICSupported)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
wrmsr((Register >> 4) + 0x800, Value);
|
||||
else
|
||||
wrmsr(MSR_X2APIC_ICR, Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
|
||||
CPU::MemBar::Barrier();
|
||||
}
|
||||
assert(false);
|
||||
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
|
||||
CPU::MemBar::Barrier();
|
||||
}
|
||||
|
||||
void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value)
|
||||
@ -117,30 +105,50 @@ namespace APIC
|
||||
return ret;
|
||||
}
|
||||
|
||||
void APIC::EOI() { this->Write(APIC_EOI, 0); }
|
||||
void APIC::EOI()
|
||||
{
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_EOI, 0);
|
||||
else
|
||||
this->Write(APIC_EOI, 0);
|
||||
}
|
||||
|
||||
void APIC::WaitForIPI()
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
do
|
||||
if (this->x2APICSupported)
|
||||
{
|
||||
icr.raw = this->Read(APIC_ICRLO);
|
||||
CPU::Pause();
|
||||
} while (icr.DeliveryStatus != Idle);
|
||||
ErrorStatusRegister esr{};
|
||||
esr.raw = uint32_t(rdmsr(MSR_X2APIC_ESR));
|
||||
UNUSED(esr);
|
||||
/* FIXME: Not sure if this is required or
|
||||
how to implement it. */
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegister icr{};
|
||||
do
|
||||
{
|
||||
icr.split.Low = this->Read(APIC_ICRLO);
|
||||
CPU::Pause();
|
||||
} while (icr.DS != Idle);
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::IPI(int CPU, InterruptCommandRegisterLow icr)
|
||||
void APIC::ICR(InterruptCommandRegister icr)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
assert(icr.MT != LowestPriority);
|
||||
assert(icr.MT != DeliveryMode);
|
||||
assert(icr.MT != ExtINT);
|
||||
wrmsr(MSR_X2APIC_ICR, icr.raw);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
this->Write(APIC_ICRHI, icr.split.High);
|
||||
this->Write(APIC_ICRLO, icr.split.Low);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
@ -148,21 +156,25 @@ namespace APIC
|
||||
void APIC::SendInitIPI(int CPU)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
InterruptCommandRegister icr{};
|
||||
|
||||
if (x2APICSupported)
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.DeliveryMode = INIT;
|
||||
icr.Level = Assert;
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
icr.x2.MT = INIT;
|
||||
icr.x2.L = Assert;
|
||||
icr.x2.DES = uint8_t(CPU);
|
||||
|
||||
wrmsr(MSR_X2APIC_ICR, icr.raw);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.DeliveryMode = INIT;
|
||||
icr.Level = Assert;
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
icr.MT = INIT;
|
||||
icr.L = Assert;
|
||||
icr.DES = uint8_t(CPU);
|
||||
|
||||
this->Write(APIC_ICRHI, icr.split.High);
|
||||
this->Write(APIC_ICRLO, icr.split.Low);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
@ -170,45 +182,54 @@ namespace APIC
|
||||
void APIC::SendStartupIPI(int CPU, uint64_t StartupAddress)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
InterruptCommandRegister icr{};
|
||||
|
||||
if (x2APICSupported)
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.DeliveryMode = Startup;
|
||||
icr.Level = Assert;
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
icr.x2.VEC = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.x2.MT = Startup;
|
||||
icr.x2.L = Assert;
|
||||
icr.x2.DES = uint8_t(CPU);
|
||||
|
||||
wrmsr(MSR_X2APIC_ICR, icr.raw);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.DeliveryMode = Startup;
|
||||
icr.Level = Assert;
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
icr.VEC = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.MT = Startup;
|
||||
icr.L = Assert;
|
||||
icr.DES = uint8_t(CPU);
|
||||
|
||||
this->Write(APIC_ICRHI, icr.split.High);
|
||||
this->Write(APIC_ICRLO, icr.split.Low);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
|
||||
{
|
||||
uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion));
|
||||
return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry;
|
||||
ACPI::MADT::MADTIOApic *ioapic = ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID];
|
||||
uint32_t TableAddress = (this->IORead(ioapic->Address, GetIOAPICVersion));
|
||||
IOAPICVersion ver = {.raw = TableAddress};
|
||||
return ver.MLE + 1;
|
||||
}
|
||||
|
||||
void APIC::RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status)
|
||||
void APIC::RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, uint8_t CPU, int Status)
|
||||
{
|
||||
uint64_t Value = Vector;
|
||||
|
||||
int64_t IOAPICTarget = -1;
|
||||
for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i] != 0; i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase <= GSI)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase + IOGetMaxRedirect(s_cst(uint32_t, i)) > GSI)
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
for (size_t i = 0; i < madt->ioapic.size(); i++)
|
||||
{
|
||||
if (madt->ioapic[i]->GSIBase <= GSI)
|
||||
{
|
||||
if (madt->ioapic[i]->GSIBase + IOGetMaxRedirect(uint32_t(i)) > GSI)
|
||||
{
|
||||
IOAPICTarget = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IOAPICTarget == -1)
|
||||
{
|
||||
@ -216,40 +237,46 @@ namespace APIC
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: IOAPICRedirectEntry Entry = {.raw = 0};
|
||||
IOAPICRedirectEntry Entry{};
|
||||
Entry.VEC = Vector;
|
||||
Entry.DES = CPU;
|
||||
|
||||
if (Flags & ActiveHighLow)
|
||||
Value |= (1 << 13);
|
||||
Entry.IPP = 1;
|
||||
|
||||
if (Flags & EdgeLevel)
|
||||
Value |= (1 << 15);
|
||||
Entry.TGM = 1;
|
||||
|
||||
if (!Status)
|
||||
Value |= (1 << 16);
|
||||
Entry.M = 1;
|
||||
|
||||
Value |= (((uintptr_t)CPU) << 56);
|
||||
uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->GSIBase) * 2 + 16;
|
||||
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister, (uint32_t)Value);
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister + 1, (uint32_t)(Value >> 32));
|
||||
uint32_t IORegister = (GSI - madt->ioapic[IOAPICTarget]->GSIBase) * 2 + 16;
|
||||
this->IOWrite(madt->ioapic[IOAPICTarget]->Address,
|
||||
IORegister, Entry.split.Low);
|
||||
this->IOWrite(madt->ioapic[IOAPICTarget]->Address,
|
||||
IORegister + 1, Entry.split.High);
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQ(int CPU, uint16_t IRQ, int Status)
|
||||
void APIC::RedirectIRQ(uint8_t CPU, uint8_t IRQ, int Status)
|
||||
{
|
||||
for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource == IRQ)
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
for (uint64_t i = 0; i < madt->iso.size(); i++)
|
||||
if (madt->iso[i]->IRQSource == IRQ)
|
||||
{
|
||||
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
|
||||
i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, CPU);
|
||||
i, madt->iso[i]->IRQSource, madt->iso[i]->GSI, CPU);
|
||||
|
||||
this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource + 0x20, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->Flags, CPU, Status);
|
||||
this->RawRedirectIRQ(madt->iso[i]->IRQSource + 0x20,
|
||||
madt->iso[i]->GSI,
|
||||
madt->iso[i]->Flags,
|
||||
CPU, Status);
|
||||
return;
|
||||
}
|
||||
debug("Mapping IRQ%d on CPU %d", IRQ, CPU);
|
||||
this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status);
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQs(int CPU)
|
||||
void APIC::RedirectIRQs(uint8_t CPU)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
debug("Redirecting IRQs...");
|
||||
@ -262,21 +289,22 @@ namespace APIC
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)};
|
||||
uint64_t BaseLow = BaseStruct.ApicBaseLo;
|
||||
uint64_t BaseHigh = BaseStruct.ApicBaseHi;
|
||||
uint64_t BaseLow = BaseStruct.ABALow;
|
||||
uint64_t BaseHigh = BaseStruct.ABAHigh;
|
||||
this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u;
|
||||
trace("APIC Address: %#lx", this->APICBaseAddress);
|
||||
Memory::Virtual().Map((void *)this->APICBaseAddress, (void *)this->APICBaseAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD);
|
||||
Memory::Virtual().Map((void *)this->APICBaseAddress,
|
||||
(void *)this->APICBaseAddress,
|
||||
Memory::RW | Memory::PCD);
|
||||
|
||||
bool x2APICSupported = false;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
CPU::x86::AMD::CPUID0x00000001 cpuid;
|
||||
cpuid.Get();
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||
fixme("x2APIC is supported");
|
||||
this->x2APICSupported = cpuid.ECX.x2APIC;
|
||||
debug("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
@ -285,39 +313,38 @@ namespace APIC
|
||||
cpuid.Get();
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||
fixme("x2APIC is supported");
|
||||
this->x2APICSupported = cpuid.ECX.x2APIC;
|
||||
debug("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
|
||||
if (x2APICSupported)
|
||||
{
|
||||
this->x2APICSupported = true;
|
||||
wrmsr(MSR_APIC_BASE, (rdmsr(MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10));
|
||||
BaseStruct.EN = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseStruct.EN = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
BaseStruct.AE = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
|
||||
this->Write(APIC_TPR, 0x0);
|
||||
// this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100
|
||||
if (this->x2APICSupported)
|
||||
{
|
||||
BaseStruct.EXTD = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
|
||||
if (!this->x2APICSupported)
|
||||
{
|
||||
this->Write(APIC_TPR, 0x0);
|
||||
this->Write(APIC_DFR, 0xF0000000);
|
||||
this->Write(APIC_LDR, this->Read(APIC_ID));
|
||||
}
|
||||
else
|
||||
{
|
||||
wrmsr(MSR_X2APIC_TPR, 0x0);
|
||||
}
|
||||
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
|
||||
for (size_t i = 0; i < madt->nmi.size(); i++)
|
||||
{
|
||||
if (madt->nmi[i]->processor != 0xFF && Core != madt->nmi[i]->processor)
|
||||
return;
|
||||
if (madt->nmi[i]->processor != 0xFF &&
|
||||
Core != madt->nmi[i]->processor)
|
||||
break;
|
||||
|
||||
uint32_t nmi = 0x402;
|
||||
if (madt->nmi[i]->flags & 2)
|
||||
@ -325,16 +352,34 @@ namespace APIC
|
||||
if (madt->nmi[i]->flags & 8)
|
||||
nmi |= 1 << 15;
|
||||
if (madt->nmi[i]->lint == 0)
|
||||
this->Write(APIC_LINT0, nmi);
|
||||
{
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_LVT_LINT0, nmi);
|
||||
else
|
||||
this->Write(APIC_LINT0, nmi);
|
||||
}
|
||||
else if (madt->nmi[i]->lint == 1)
|
||||
this->Write(APIC_LINT1, nmi);
|
||||
{
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_LVT_LINT1, nmi);
|
||||
else
|
||||
this->Write(APIC_LINT1, nmi);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the spurrious interrupt vector
|
||||
Spurious Spurious = {.raw = this->Read(APIC_SVR)};
|
||||
Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something?
|
||||
Spurious.Software = 1;
|
||||
this->Write(APIC_SVR, s_cst(uint32_t, Spurious.raw));
|
||||
/* Setup the spurious interrupt vector */
|
||||
Spurious svr{};
|
||||
if (this->x2APICSupported)
|
||||
svr.raw = uint32_t(rdmsr(MSR_X2APIC_SIVR));
|
||||
else
|
||||
svr.raw = this->Read(APIC_SVR);
|
||||
|
||||
svr.VEC = IRQ223;
|
||||
svr.ASE = 1;
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_SIVR, svr.raw);
|
||||
else
|
||||
this->Write(APIC_SVR, svr.raw);
|
||||
|
||||
static int once = 0;
|
||||
if (!once++)
|
||||
@ -356,45 +401,85 @@ namespace APIC
|
||||
void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
LVTTimer timer = {.raw = 0};
|
||||
timer.Vector = s_cst(uint8_t, Vector);
|
||||
timer.TimerMode = 0;
|
||||
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)
|
||||
this->lapic->Write(APIC_TDCR, DivideBy128);
|
||||
LVTTimer timer{};
|
||||
timer.VEC = uint8_t(Vector);
|
||||
timer.TMM = LVTTimerMode::OneShot;
|
||||
|
||||
LVTTimerDivide Divider = DivideBy8;
|
||||
|
||||
if (unlikely(strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0))
|
||||
Divider = DivideBy128;
|
||||
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_DIV_CONF, Divider);
|
||||
wrmsr(MSR_X2APIC_INIT_COUNT, uint32_t(Ticks * Miliseconds));
|
||||
wrmsr(MSR_X2APIC_LVT_TIMER, uint32_t(timer.raw));
|
||||
}
|
||||
else
|
||||
this->lapic->Write(APIC_TDCR, DivideBy16);
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds));
|
||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||
{
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, uint32_t(Ticks * Miliseconds));
|
||||
this->lapic->Write(APIC_TIMER, uint32_t(timer.raw));
|
||||
}
|
||||
}
|
||||
|
||||
Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
this->lapic = apic;
|
||||
LVTTimerDivide Divider = DivideBy16;
|
||||
LVTTimerDivide Divider = DivideBy8;
|
||||
|
||||
trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID);
|
||||
trace("Initializing APIC timer on CPU %d",
|
||||
GetCurrentCPU()->ID);
|
||||
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_DIV_CONF, Divider);
|
||||
wrmsr(MSR_X2APIC_INIT_COUNT, 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
||||
|
||||
// Mask the timer
|
||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_LVT_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
Ticks = 0xFFFFFFFF - rdmsr(MSR_X2APIC_CUR_COUNT);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
|
||||
}
|
||||
|
||||
// Config for IRQ0 timer
|
||||
LVTTimer timer = {.raw = 0};
|
||||
timer.Vector = IRQ0;
|
||||
timer.Mask = Unmasked;
|
||||
timer.TimerMode = LVTTimerMode::OneShot;
|
||||
LVTTimer timer{};
|
||||
timer.VEC = IRQ0;
|
||||
timer.M = Unmasked;
|
||||
timer.TMM = LVTTimerMode::OneShot;
|
||||
|
||||
// Initialize APIC timer
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks));
|
||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||
trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks);
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_DIV_CONF, Divider);
|
||||
wrmsr(MSR_X2APIC_INIT_COUNT, Ticks);
|
||||
wrmsr(MSR_X2APIC_LVT_TIMER, timer.raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, uint32_t(Ticks));
|
||||
this->lapic->Write(APIC_TIMER, uint32_t(timer.raw));
|
||||
}
|
||||
|
||||
trace("%d APIC Timer %d ticks in.",
|
||||
GetCurrentCPU()->ID, Ticks);
|
||||
KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,15 @@ SafeFunction CPUData *GetCurrentCPU()
|
||||
if (unlikely(!Interrupts::apic[0]))
|
||||
return &CPUs[0]; /* No APIC means we are on the BSP. */
|
||||
|
||||
int CoreID = ((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24;
|
||||
APIC::APIC *apic = (APIC::APIC *)Interrupts::apic[0];
|
||||
int CoreID = 0;
|
||||
if (CPUEnabled.load(std::memory_order_acquire) == true)
|
||||
{
|
||||
if (apic->x2APIC)
|
||||
CoreID = int(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID));
|
||||
else
|
||||
CoreID = apic->Read(APIC::APIC_ID) >> 24;
|
||||
}
|
||||
|
||||
if (unlikely((&CPUs[CoreID])->IsActive != true))
|
||||
{
|
||||
@ -94,18 +102,23 @@ namespace SMP
|
||||
int Cores = madt->CPUCores + 1;
|
||||
|
||||
if (Config.Cores > madt->CPUCores + 1)
|
||||
KPrint("More cores requested than available. Using %d cores", madt->CPUCores + 1);
|
||||
KPrint("More cores requested than available. Using %d cores",
|
||||
madt->CPUCores + 1);
|
||||
else if (Config.Cores != 0)
|
||||
Cores = Config.Cores;
|
||||
|
||||
CPUCores = Cores;
|
||||
|
||||
uint64_t TrampolineLength = (uintptr_t)&_trampoline_end - (uintptr_t)&_trampoline_start;
|
||||
uint64_t TrampolineLength = (uintptr_t)&_trampoline_end -
|
||||
(uintptr_t)&_trampoline_start;
|
||||
Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW);
|
||||
/* We reserved the TRAMPOLINE_START address inside Physical class. */
|
||||
Memory::Virtual().Map((void *)TRAMPOLINE_START, (void *)TRAMPOLINE_START, TrampolineLength, Memory::PTFlag::RW);
|
||||
Memory::Virtual().Map((void *)TRAMPOLINE_START, (void *)TRAMPOLINE_START,
|
||||
TrampolineLength, Memory::PTFlag::RW);
|
||||
memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength);
|
||||
debug("Trampoline address: %#lx-%#lx", TRAMPOLINE_START, TRAMPOLINE_START + TrampolineLength);
|
||||
debug("Trampoline address: %#lx-%#lx",
|
||||
TRAMPOLINE_START,
|
||||
TRAMPOLINE_START + TrampolineLength);
|
||||
|
||||
void *CPUTmpStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
|
||||
asmv("sgdt [0x580]");
|
||||
@ -117,26 +130,39 @@ namespace SMP
|
||||
for (int i = 0; i < Cores; i++)
|
||||
{
|
||||
ACPI::MADT::LocalAPIC *lapic = madt->lapic[i];
|
||||
APIC::APIC *apic = (APIC::APIC *)Interrupts::apic[0];
|
||||
|
||||
debug("Initializing CPU %d", lapic->APICId);
|
||||
if ((((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24) != lapic->APICId)
|
||||
uint8_t APIC_ID = 0;
|
||||
if (apic->x2APIC)
|
||||
APIC_ID = uint8_t(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID));
|
||||
else
|
||||
APIC_ID = uint8_t(apic->Read(APIC::APIC_ID) >> 24);
|
||||
|
||||
if (APIC_ID != lapic->APICId)
|
||||
{
|
||||
VPOKE(int, CORE) = i;
|
||||
if (!apic->x2APIC)
|
||||
{
|
||||
APIC::InterruptCommandRegister icr{};
|
||||
icr.MT = APIC::INIT;
|
||||
icr.DES = lapic->APICId;
|
||||
apic->ICR(icr);
|
||||
}
|
||||
|
||||
((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRHI, (lapic->APICId << 24));
|
||||
((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRLO, 0x500);
|
||||
|
||||
((APIC::APIC *)Interrupts::apic[0])->SendInitIPI(lapic->APICId);
|
||||
TimeManager->Sleep(5, Time::Units::Milliseconds);
|
||||
((APIC::APIC *)Interrupts::apic[0])->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
|
||||
|
||||
apic->SendInitIPI(lapic->APICId);
|
||||
TimeManager->Sleep(20, Time::Units::Milliseconds);
|
||||
apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
|
||||
debug("Waiting for CPU %d to load...", lapic->APICId);
|
||||
|
||||
uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds);
|
||||
while (CPUEnabled.load(std::memory_order_acquire) == false)
|
||||
{
|
||||
if (TimeManager->GetCounter() > Timeout)
|
||||
{
|
||||
error("CPU %d failed to load!", lapic->APICId);
|
||||
KPrint("\eFF8C19CPU \e8888FF%d \eFF8C19failed to load!", lapic->APICId);
|
||||
KPrint("\eFF8C19CPU \e8888FF%d \eFF8C19failed to load!",
|
||||
lapic->APICId);
|
||||
break;
|
||||
}
|
||||
CPU::Pause();
|
||||
|
@ -27,32 +27,66 @@ namespace APIC
|
||||
{
|
||||
enum APICRegisters
|
||||
{
|
||||
// source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c
|
||||
APIC_ID = 0x20, // Local APIC ID
|
||||
APIC_VER = 0x30, // Local APIC Version
|
||||
APIC_TPR = 0x80, // Task Priority
|
||||
APIC_APR = 0x90, // Arbitration Priority
|
||||
APIC_PPR = 0xA0, // Processor Priority
|
||||
APIC_EOI = 0xB0, // EOI
|
||||
APIC_RRD = 0xC0, // Remote Read
|
||||
APIC_LDR = 0xD0, // Logical Destination
|
||||
APIC_DFR = 0xE0, // Destination Format
|
||||
APIC_SVR = 0xF0, // Spurious Interrupt Vector
|
||||
APIC_ISR = 0x100, // In-Service (8 registers)
|
||||
APIC_TMR = 0x180, // Trigger Mode (8 registers)
|
||||
APIC_IRR = 0x200, // Interrupt Request (8 registers)
|
||||
APIC_ESR = 0x280, // Error Status
|
||||
APIC_ICRLO = 0x300, // Interrupt Command
|
||||
APIC_ICRHI = 0x310, // Interrupt Command [63:32]
|
||||
APIC_TIMER = 0x320, // LVT Timer
|
||||
APIC_THERMAL = 0x330, // LVT Thermal Sensor
|
||||
APIC_PERF = 0x340, // LVT Performance Counter
|
||||
APIC_LINT0 = 0x350, // LVT LINT0
|
||||
APIC_LINT1 = 0x360, // LVT LINT1
|
||||
APIC_ERROR = 0x370, // LVT Error
|
||||
APIC_TICR = 0x380, // Initial Count (for Timer)
|
||||
APIC_TCCR = 0x390, // Current Count (for Timer)
|
||||
APIC_TDCR = 0x3E0, // Divide Configuration (for Timer)
|
||||
/* APIC ID Register */
|
||||
APIC_ID = 0x20,
|
||||
/* APIC Version Register */
|
||||
APIC_VER = 0x30,
|
||||
/* Task Priority Register (TPR) */
|
||||
APIC_TPR = 0x80,
|
||||
/* Arbitration Priority Register (APR) */
|
||||
APIC_APR = 0x90,
|
||||
/* Processor Priority Register (PPR) */
|
||||
APIC_PPR = 0xA0,
|
||||
/* End of Interrupt Register (EOI) */
|
||||
APIC_EOI = 0xB0,
|
||||
/* Remote Read Register */
|
||||
APIC_RRD = 0xC0,
|
||||
/* Logical Destination Register (LDR) */
|
||||
APIC_LDR = 0xD0,
|
||||
/* Destination Format Register (DFR) */
|
||||
APIC_DFR = 0xE0,
|
||||
/* Spurious Interrupt Vector Register */
|
||||
APIC_SVR = 0xF0,
|
||||
/* In-Service Register (ISR) */
|
||||
APIC_ISR = 0x100,
|
||||
/* Trigger Mode Register (TMR) */
|
||||
APIC_TMR = 0x180,
|
||||
/* Interrupt Request Register (IRR) */
|
||||
APIC_IRR = 0x200,
|
||||
/* Error Status Register (ESR) */
|
||||
APIC_ESR = 0x280,
|
||||
/* Interrupt Command Register Low (bits 31:0) */
|
||||
APIC_ICRLO = 0x300,
|
||||
/* Interrupt Command Register High (bits 63:32) */
|
||||
APIC_ICRHI = 0x310,
|
||||
/* Timer Local Vector Table Entry */
|
||||
APIC_TIMER = 0x320,
|
||||
/* Thermal Local Vector Table Entry */
|
||||
APIC_THERMAL = 0x330,
|
||||
/* Performance Counter Local Vector Table Entry */
|
||||
APIC_PERF = 0x340,
|
||||
/* Local Interrupt 0 Vector Table Entry */
|
||||
APIC_LINT0 = 0x350,
|
||||
/* Local Interrupt 1 Vector Table Entry */
|
||||
APIC_LINT1 = 0x360,
|
||||
/* Error Vector Table Entry */
|
||||
APIC_ERROR = 0x370,
|
||||
/* Timer Initial Count Register */
|
||||
APIC_TICR = 0x380,
|
||||
/* Timer Current Count Register */
|
||||
APIC_TCCR = 0x390,
|
||||
/* Timer Divide Configuration Register */
|
||||
APIC_TDCR = 0x3E0,
|
||||
/* Extended APIC Feature Register */
|
||||
APIC_EFR = 0x400,
|
||||
/* Extended APIC Control Register */
|
||||
APIC_ECR = 0x410,
|
||||
/* Specific End of Interrupt Register (SEOI) */
|
||||
APIC_SEOI = 0x420,
|
||||
/* Interrupt Enable Registers (IER) */
|
||||
APIC_IER0 = 0x480,
|
||||
/* Extended Interrupt [3:0] Local Vector Table Registers */
|
||||
APIC_EILVT0 = 0x500,
|
||||
};
|
||||
|
||||
enum IOAPICRegisters
|
||||
@ -66,12 +100,12 @@ namespace APIC
|
||||
EdgeLevel = 8
|
||||
};
|
||||
|
||||
enum APICDeliveryMode
|
||||
enum APICMessageType
|
||||
{
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001, /* Reserved */
|
||||
SMI = 0b010,
|
||||
APIC_DELIVERY_MODE_RESERVED0 = 0b011, /* Reserved */
|
||||
DeliveryMode = 0b011, /* Reserved */
|
||||
NMI = 0b100,
|
||||
INIT = 0b101,
|
||||
Startup = 0b110,
|
||||
@ -139,163 +173,153 @@ namespace APIC
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Reserved */
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 4;
|
||||
/**
|
||||
* @brief Delivery Status
|
||||
*
|
||||
* 0: Idle
|
||||
* 1: Send Pending
|
||||
*/
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Reserved */
|
||||
/** Delivery Status */
|
||||
uint64_t DS : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 3;
|
||||
/**
|
||||
* @brief Mask
|
||||
*
|
||||
* 0: Not masked
|
||||
* 1: Masked
|
||||
*/
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Timer Mode
|
||||
*
|
||||
* 0: One-shot
|
||||
* 1: Periodic
|
||||
* 2: TSC-Deadline
|
||||
*/
|
||||
uint64_t TimerMode : 1;
|
||||
/** @brief Reserved */
|
||||
/** Mask */
|
||||
uint64_t M : 1;
|
||||
/** Timer Mode */
|
||||
uint64_t TMM : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 14;
|
||||
};
|
||||
uint64_t raw;
|
||||
uint32_t raw;
|
||||
} __packed LVTTimer;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Spurious Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Enable or disable APIC software */
|
||||
uint64_t Software : 1;
|
||||
/** @brief Focus Processor Checking */
|
||||
uint64_t FocusProcessorChecking : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved : 2;
|
||||
/** @brief Disable EOI Broadcast */
|
||||
uint64_t DisableEOIBroadcast : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 19;
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** APIC Software Enable */
|
||||
uint64_t ASE : 1;
|
||||
/** Focus CPU Core Checking */
|
||||
uint64_t FCC : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 22;
|
||||
};
|
||||
uint64_t raw;
|
||||
uint32_t raw;
|
||||
} __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 */
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Message Type */
|
||||
uint64_t MT : 3;
|
||||
/** Destination Mode */
|
||||
uint64_t DM : 1;
|
||||
/** Delivery Status */
|
||||
uint64_t DS : 1;
|
||||
/** 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 */
|
||||
/** Level */
|
||||
uint64_t L : 1;
|
||||
/** Trigger Mode */
|
||||
uint64_t TGM : 1;
|
||||
/** Remote Read Status */
|
||||
uint64_t RSS : 2;
|
||||
/** Destination Shorthand */
|
||||
uint64_t DSH : 2;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 36;
|
||||
/** Destination */
|
||||
uint64_t DES : 8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Message Type */
|
||||
uint64_t MT : 3;
|
||||
/** Destination Mode */
|
||||
uint64_t DM : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 2;
|
||||
/** Level */
|
||||
uint64_t L : 1;
|
||||
/** Trigger Mode */
|
||||
uint64_t TGM : 1;
|
||||
/** 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 */
|
||||
/** Destination Shorthand */
|
||||
uint64_t DSH : 2;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 12;
|
||||
};
|
||||
/** Destination */
|
||||
uint64_t DES : 32;
|
||||
} x2;
|
||||
struct
|
||||
{
|
||||
uint32_t Low;
|
||||
uint32_t High;
|
||||
} split;
|
||||
uint64_t raw;
|
||||
} __packed InterruptCommandRegisterLow;
|
||||
} __packed InterruptCommandRegister;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t Destination : 8;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 2;
|
||||
/** Sent Accept Error */
|
||||
uint64_t SAE : 1;
|
||||
/** Receive Accept Error */
|
||||
uint64_t RAE : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 1;
|
||||
/** Sent Illegal Vector */
|
||||
uint64_t SIV : 1;
|
||||
/** Received Illegal Vector */
|
||||
uint64_t RIV : 1;
|
||||
/** Illegal Register Address */
|
||||
uint64_t IRA : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 24;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed InterruptCommandRegisterHigh;
|
||||
uint32_t raw;
|
||||
} ErrorStatusRegister;
|
||||
|
||||
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 */
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Interrupt Input Pin Polarity
|
||||
*
|
||||
* 0: Active High
|
||||
* 1: Active Low
|
||||
*/
|
||||
uint64_t Polarity : 1;
|
||||
/** @brief Remote IRR */
|
||||
uint64_t RemoteIRR : 1;
|
||||
/** @brief Trigger Mode
|
||||
*
|
||||
* 0: Edge
|
||||
* 1: Level
|
||||
*/
|
||||
uint64_t TriggerMode : 1;
|
||||
/** @brief Mask */
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Reserved */
|
||||
/** Interrupt Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Delivery Mode */
|
||||
uint64_t MT : 3;
|
||||
/** Destination Mode */
|
||||
uint64_t DM : 1;
|
||||
/** Delivery Status */
|
||||
uint64_t DS : 1;
|
||||
/** Interrupt Input Pin Polarity */
|
||||
uint64_t IPP : 1;
|
||||
/** Remote IRR */
|
||||
uint64_t RIR : 1;
|
||||
/** Trigger Mode */
|
||||
uint64_t TGM : 1;
|
||||
/** Mask */
|
||||
uint64_t M : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 15;
|
||||
/** @brief Reserved */
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t DestinationID : 8;
|
||||
/** Destination */
|
||||
uint64_t DES : 8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint64_t Low;
|
||||
uint64_t High;
|
||||
uint32_t Low;
|
||||
uint32_t High;
|
||||
} split;
|
||||
uint64_t raw;
|
||||
} __packed IOAPICRedirectEntry;
|
||||
@ -304,12 +328,18 @@ namespace APIC
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64_t Version : 8;
|
||||
uint64_t Reserved : 8;
|
||||
uint64_t MaximumRedirectionEntry : 8;
|
||||
uint64_t Reserved2 : 8;
|
||||
/** Version */
|
||||
uint64_t VER : 8;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 8;
|
||||
/** Max LVT Entries */
|
||||
uint64_t MLE : 8;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 7;
|
||||
/** Extended APIC Register Space Present */
|
||||
uint64_t EAS : 1;
|
||||
};
|
||||
uint64_t raw;
|
||||
uint32_t raw;
|
||||
} __packed IOAPICVersion;
|
||||
|
||||
class APIC
|
||||
@ -319,19 +349,21 @@ namespace APIC
|
||||
uint64_t APICBaseAddress = 0;
|
||||
|
||||
public:
|
||||
decltype(x2APICSupported) &x2APIC = x2APICSupported;
|
||||
|
||||
uint32_t Read(uint32_t Register);
|
||||
void Write(uint32_t Register, uint32_t Value);
|
||||
void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
|
||||
uint32_t IORead(uint64_t Base, uint32_t Register);
|
||||
void EOI();
|
||||
void RedirectIRQs(int CPU = 0);
|
||||
void RedirectIRQs(uint8_t CPU = 0);
|
||||
void WaitForIPI();
|
||||
void IPI(int CPU, InterruptCommandRegisterLow icr);
|
||||
void ICR(InterruptCommandRegister icr);
|
||||
void SendInitIPI(int CPU);
|
||||
void SendStartupIPI(int CPU, uint64_t StartupAddress);
|
||||
uint32_t IOGetMaxRedirect(uint32_t APICID);
|
||||
void RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status);
|
||||
void RedirectIRQ(int CPU, uint16_t IRQ, int Status);
|
||||
void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, uint8_t CPU, int Status);
|
||||
void RedirectIRQ(uint8_t CPU, uint8_t IRQ, int Status);
|
||||
APIC(int Core);
|
||||
~APIC();
|
||||
};
|
||||
|
10
Core/CPU.cpp
10
Core/CPU.cpp
@ -267,12 +267,10 @@ namespace CPU
|
||||
cr4.OSXMMEXCPT = 1;
|
||||
|
||||
CPUData *CoreData = GetCPU(Core);
|
||||
CoreData->Data.FPU = (CPU::x64::FXState *)KernelAllocator.RequestPages(TO_PAGES(sizeof(CPU::x64::FXState) + 1));
|
||||
memset(CoreData->Data.FPU, 0, FROM_PAGES(TO_PAGES(sizeof(CPU::x64::FXState))));
|
||||
CoreData->Data.FPU->mxcsr = 0b0001111110000000;
|
||||
CoreData->Data.FPU->mxcsrmask = 0b1111111110111111;
|
||||
CoreData->Data.FPU->fcw = 0b0000001100111111;
|
||||
CPU::x64::fxrstor(CoreData->Data.FPU);
|
||||
CoreData->Data.FPU.mxcsr = 0b0001111110000000;
|
||||
CoreData->Data.FPU.mxcsrmask = 0b1111111110111111;
|
||||
CoreData->Data.FPU.fcw = 0b0000001100111111;
|
||||
CPU::x64::fxrstor(&CoreData->Data.FPU);
|
||||
|
||||
SSEEnableAfter = true;
|
||||
}
|
||||
|
@ -263,7 +263,7 @@ namespace ACPI
|
||||
}
|
||||
}
|
||||
|
||||
((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, acpi->FADT->SCI_Interrupt, 1);
|
||||
((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, uint8_t(acpi->FADT->SCI_Interrupt), 1);
|
||||
return;
|
||||
}
|
||||
warn("Failed to parse _S5 in ACPI");
|
||||
|
@ -110,7 +110,7 @@ namespace Interrupts
|
||||
// TODO: This function is called by SMP too. Do not initialize timers that doesn't support multiple cores.
|
||||
apic[Core] = new APIC::APIC(Core);
|
||||
if (Core == Config.IOAPICInterruptCore) // Redirect IRQs to the specified core.
|
||||
((APIC::APIC *)apic[Core])->RedirectIRQs(Core);
|
||||
((APIC::APIC *)apic[Core])->RedirectIRQs(uint8_t(Core));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -168,7 +168,8 @@ namespace Interrupts
|
||||
Core = CoreData->ID;
|
||||
|
||||
/* If this is false, we have a big problem. */
|
||||
if (likely(Frame->InterruptNumber < CPU::x86::IRQ223 && Frame->InterruptNumber > CPU::x86::ISR0))
|
||||
if (likely(Frame->InterruptNumber < CPU::x86::IRQ223 &&
|
||||
Frame->InterruptNumber > CPU::x86::ISR0))
|
||||
{
|
||||
/* Halt core interrupt */
|
||||
if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ29))
|
||||
@ -201,7 +202,8 @@ namespace Interrupts
|
||||
|
||||
if (likely(apic[Core]))
|
||||
{
|
||||
((APIC::APIC *)Interrupts::apic[Core])->EOI();
|
||||
APIC::APIC *this_apic = (APIC::APIC *)apic[Core];
|
||||
this_apic->EOI();
|
||||
// TODO: Handle PIC too
|
||||
return;
|
||||
}
|
||||
|
@ -349,7 +349,7 @@ static int sys_fork(SysFrm *Frame)
|
||||
ReturnAddress = Frame->ReturnAddress;
|
||||
ChildStackPointer = Frame->StackPointer;
|
||||
|
||||
memcpy(NewThread->FPU, Thread->FPU, sizeof(CPU::x64::FXState));
|
||||
memcpy(&NewThread->FPU, &Thread->FPU, sizeof(CPU::x64::FXState));
|
||||
NewThread->Stack->Fork(Thread->Stack);
|
||||
NewThread->Info = Thread->Info;
|
||||
NewThread->Registers = Thread->Registers;
|
||||
|
@ -525,7 +525,7 @@ namespace Tasking
|
||||
else
|
||||
{
|
||||
CurrentCPU->CurrentThread->Registers = *Frame;
|
||||
CPU::x64::fxsave(CurrentCPU->CurrentThread->FPU);
|
||||
CPU::x64::fxsave(&CurrentCPU->CurrentThread->FPU);
|
||||
CurrentCPU->CurrentThread->ShadowGSBase = CPU::x64::rdmsr(CPU::x64::MSR_SHADOW_GS_BASE);
|
||||
CurrentCPU->CurrentThread->GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
|
||||
CurrentCPU->CurrentThread->FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
|
||||
@ -616,7 +616,7 @@ namespace Tasking
|
||||
/* Not sure if this is needed, but it's better to be safe than sorry. */
|
||||
asmv("movq %cr3, %rax");
|
||||
asmv("movq %rax, %cr3");
|
||||
CPU::x64::fxrstor(CurrentCPU->CurrentThread->FPU);
|
||||
CPU::x64::fxrstor(&CurrentCPU->CurrentThread->FPU);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->ShadowGSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase);
|
||||
CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
|
||||
|
@ -458,27 +458,10 @@ namespace Tasking
|
||||
this->Security.ExecutionMode =
|
||||
this->Parent->Security.ExecutionMode;
|
||||
|
||||
std::size_t FXPgs = TO_PAGES(sizeof(CPU::x64::FXState) + 1);
|
||||
this->FPU = (CPU::x64::FXState *)this->Memory->RequestPages(FXPgs);
|
||||
memset(this->FPU, 0, sizeof(CPU::x64::FXState));
|
||||
|
||||
// TODO: Is really a good idea to use the FPU in kernel mode?
|
||||
this->FPU->mxcsr = 0b0001111110000000;
|
||||
this->FPU->mxcsrmask = 0b1111111110111111;
|
||||
this->FPU->fcw = 0b0000001100111111;
|
||||
|
||||
// CPU::x64::fxrstor(this->FPU);
|
||||
// uint16_t FCW = 0b1100111111;
|
||||
// asmv("fldcw %0"
|
||||
// :
|
||||
// : "m"(FCW)
|
||||
// : "memory");
|
||||
// uint32_t MXCSR = 0b1111110000000;
|
||||
// asmv("ldmxcsr %0"
|
||||
// :
|
||||
// : "m"(MXCSR)
|
||||
// : "memory");
|
||||
// CPU::x64::fxsave(this->FPU);
|
||||
this->FPU.mxcsr = 0b0001111110000000;
|
||||
this->FPU.mxcsrmask = 0b1111111110111111;
|
||||
this->FPU.fcw = 0b0000001100111111;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef a64
|
||||
|
@ -534,27 +534,36 @@ namespace CPU
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Reserved */
|
||||
uint32_t Reserved0 : 8;
|
||||
/**
|
||||
* @brief BSP Flag
|
||||
* @details If the BSP flag is set to 1, the processor is the bootstrap processor.
|
||||
*/
|
||||
uint32_t BSP : 1;
|
||||
/** @brief Reserved */
|
||||
uint32_t Reserved1 : 1;
|
||||
/** @brief Enable x2APIC mode */
|
||||
uint32_t EXTD : 1;
|
||||
/** @brief APIC Global Enable */
|
||||
uint32_t EN : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 8;
|
||||
/** Boot Strap CPU Core */
|
||||
uint64_t BSC : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 1;
|
||||
/** x2APIC Mode Enable */
|
||||
uint64_t EXTD : 1;
|
||||
/** APIC Enable */
|
||||
uint64_t AE : 1;
|
||||
/** @brief APIC Base Low Address */
|
||||
uint32_t ApicBaseLo : 20;
|
||||
uint64_t ABALow : 20;
|
||||
/** @brief APIC Base High Address */
|
||||
uint32_t ApicBaseHi : 32;
|
||||
uint64_t ABAHigh : 32;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 12;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed APIC_BASE;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64_t Reserved : 24;
|
||||
uint64_t AID : 8;
|
||||
};
|
||||
uint32_t raw;
|
||||
} __packed APIC_ID;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
|
@ -30,43 +30,41 @@
|
||||
struct CPUArchData
|
||||
{
|
||||
#if defined(a64)
|
||||
CPU::x64::FXState *FPU;
|
||||
/* TODO */
|
||||
__aligned(16) CPU::x64::FXState FPU{};
|
||||
#elif defined(a32)
|
||||
CPU::x32::FXState *FPU;
|
||||
/* TODO */
|
||||
__aligned(16) CPU::x32::FXState FPU{};
|
||||
#elif defined(aa64)
|
||||
#endif
|
||||
};
|
||||
|
||||
struct CPUData
|
||||
{
|
||||
/** @brief Used by CPU */
|
||||
uintptr_t Stack;
|
||||
/** @brief Used by CPU */
|
||||
uintptr_t Stack;
|
||||
|
||||
/** @brief CPU ID. */
|
||||
int ID;
|
||||
/** @brief CPU ID. */
|
||||
int ID;
|
||||
|
||||
/** @brief Local CPU error code. */
|
||||
long ErrorCode;
|
||||
/** @brief Local CPU error code. */
|
||||
long ErrorCode;
|
||||
|
||||
/** @brief Current running process */
|
||||
std::atomic<Tasking::PCB *> CurrentProcess;
|
||||
/** @brief Current running process */
|
||||
std::atomic<Tasking::PCB *> CurrentProcess;
|
||||
|
||||
/** @brief Current running thread */
|
||||
std::atomic<Tasking::TCB *> CurrentThread;
|
||||
/** @brief Current running thread */
|
||||
std::atomic<Tasking::TCB *> CurrentThread;
|
||||
|
||||
/** @brief Unwind data */
|
||||
__cxa_eh_globals EHGlobals;
|
||||
/** @brief Unwind data */
|
||||
__cxa_eh_globals EHGlobals;
|
||||
|
||||
/** @brief Architecture-specific data. */
|
||||
CPUArchData Data;
|
||||
/** @brief Architecture-specific data. */
|
||||
CPUArchData Data;
|
||||
|
||||
/** @brief Checksum. Used to verify the integrity of the data. Must be equal to CPU_DATA_CHECKSUM (0xC0FFEE). */
|
||||
int Checksum;
|
||||
/** @brief Checksum. Used to verify the integrity of the data. Must be equal to CPU_DATA_CHECKSUM (0xC0FFEE). */
|
||||
int Checksum;
|
||||
|
||||
/** @brief Is CPU online? */
|
||||
bool IsActive;
|
||||
/** @brief Is CPU online? */
|
||||
bool IsActive;
|
||||
} __aligned(16);
|
||||
|
||||
CPUData *GetCurrentCPU();
|
||||
@ -74,8 +72,8 @@ CPUData *GetCPU(long ID);
|
||||
|
||||
namespace SMP
|
||||
{
|
||||
extern int CPUCores;
|
||||
void Initialize(void *madt);
|
||||
extern int CPUCores;
|
||||
void Initialize(void *madt);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_SMP_H__
|
||||
|
@ -198,7 +198,7 @@ namespace Tasking
|
||||
uintptr_t Registers; // TODO
|
||||
#endif
|
||||
uintptr_t IPHistory[128];
|
||||
CPU::x64::FXState *FPU;
|
||||
__aligned(16) CPU::x64::FXState FPU;
|
||||
|
||||
/* Info & Security info */
|
||||
struct
|
||||
|
Loading…
x
Reference in New Issue
Block a user