Files
SystemPaw3/paw/stos/arch/amd64/cpu/lapic.c
T
2026-06-26 20:46:27 +00:00

106 lines
2.3 KiB
C

/*
* Copyright (c) 2026, Chloe M.
* Provided under the BSD-3 clause.
*
* Description: Local APIC driver
* Author: Chloe M.
*/
#include <machine/lapic.h>
#include <machine/lapicreg.h>
#include <machine/msr.h>
#include <machine/cpuid.h>
#include <drivers/acpi/tables.h>
#include <drivers/acpi/acpi.h>
#include <mm/vmm.h>
#include <ex/trace.h>
#include <ke/knot.h>
#include <stdef.h>
/*
* Trace only on the bootstrap processor but not on any others
* to avoid log spam...
*/
#define DTRACE_BSP(Fmt, ...) do { \
ULONG ApicBase; \
\
ApicBase = MdRdmsr(IA32_APIC_BASE_MSR); \
if (ISSET(ApicBase, BIT(8))) { \
TRACE("[ LAPIC ]: " Fmt, ##__VA_ARGS__); \
} \
} while (0);
/*
* Returns true if the Local APIC unit is supported on the
* current processor.
*/
static BOOLEAN
LapicIsSupported(VOID)
{
ULONG Edx, Unused;
CPUID(1, Unused, Unused, Unused, Edx);
return ISSET(Edx, BIT(9)) != 0;
}
/*
* Returns true if the CPU can operate its Local APIC unit
* in the newer x2APIC mode.
*/
static BOOLEAN
LapicHasX2Apic(VOID)
{
ULONG Ecx, Unused;
CPUID(1, Unused, Unused, Ecx, Unused);
return ISSET(Ecx, BIT(21)) != 0;
}
/*
* Enable the Local APIC unit
*/
static VOID
LapicEnable(VOID)
{
UQUAD ApicBase;
/* Hardware enable the Local APIC unit */
ApicBase = MdRdmsr(IA32_APIC_BASE_MSR);
ApicBase |= LAPIC_HW_ENABLE;
MdWrmsr(IA32_APIC_BASE_MSR, ApicBase);
}
VOID
MdLapicInit(KPCR *Kpcr)
{
ACPI_MADT *Madt;
MCB *Mcb;
if (Kpcr == NULL) {
KeKnot(
KNOT_MISC,
"lapic: failed to initialize lapic driver\n"
);
}
if (!LapicIsSupported()) {
KeKnot(
KNOT_MISSING_HARDWARE,
"lapic: local apic not supported\n"
);
}
/* Obtain the ACPI MADT table */
Madt = AcpiQuery("APIC");
if (Madt == NULL) {
KeKnot(KNOT_MISC, "lapic: could not obtain MADT\n");
}
Mcb = &Kpcr->Mcb;
Mcb->LapicBase = PMA_TO_VMA((UPTR)Madt->LapicAddr);
Mcb->HasX2Apic = LapicHasX2Apic();
/* Enable the Local APIC */
LapicEnable();
}