Files
MetalOS/kernel/src/apic.cpp
2025-12-28 21:43:30 +00:00

101 lines
2.2 KiB
C++

/*
* MetalOS Kernel - APIC (Advanced Programmable Interrupt Controller)
*
* Local APIC support for multicore systems
* Replaces legacy PIC for per-CPU interrupt handling
*/
#include "kernel/apic.h"
// APIC base address (default, can be read from MSR)
#define APIC_BASE_MSR 0x1B
// Read CPUID to check for APIC
static bool cpuidHasAPIC(void) {
uint32_t eax, ebx, ecx, edx;
// CPUID function 1
__asm__ volatile(
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(1)
);
// APIC is bit 9 of EDX
return (edx & (1 << 9)) != 0;
}
// APIC class implementation
APIC::APIC() : apicBase((volatile uint32_t*)0xFEE00000) {}
uint32_t APIC::read(uint32_t offset) const {
return apicBase[offset / 4];
}
void APIC::write(uint32_t offset, uint32_t value) {
apicBase[offset / 4] = value;
}
bool APIC::isAvailable() const {
return cpuidHasAPIC();
}
void APIC::init() {
// Enable APIC via spurious interrupt vector register
// Set spurious vector to 0xFF and enable APIC (bit 8)
write(APIC_REG_SPURIOUS, 0x1FF);
// Set Task Priority Register to 0 (accept all interrupts)
write(APIC_REG_TPR, 0);
}
uint8_t APIC::getId() const {
uint32_t idReg = read(APIC_REG_ID);
return (idReg >> 24) & 0xFF;
}
void APIC::sendEOI() {
write(APIC_REG_EOI, 0);
}
void APIC::sendIPI(uint8_t destApicId, uint8_t vector, uint32_t deliveryMode) {
// Wait for previous IPI to complete
while (read(APIC_REG_ICR_LOW) & (1 << 12)) {
__asm__ volatile("pause");
}
// Set destination in high register
write(APIC_REG_ICR_HIGH, ((uint32_t)destApicId) << 24);
// Send IPI with delivery mode and vector in low register
write(APIC_REG_ICR_LOW, deliveryMode | vector);
}
// Global APIC instance
static APIC globalAPIC;
// C-compatible wrapper functions
extern "C" {
bool apic_is_available(void) {
return globalAPIC.isAvailable();
}
void apic_init(void) {
globalAPIC.init();
}
uint8_t apic_get_id(void) {
return globalAPIC.getId();
}
void apic_send_eoi(void) {
globalAPIC.sendEOI();
}
void apic_send_ipi(uint8_t dest_apic_id, uint8_t vector, uint32_t delivery_mode) {
globalAPIC.sendIPI(dest_apic_id, vector, delivery_mode);
}
} // extern "C"