Clean up IOAPIC and LAPIC implementations
All checks were successful
Build documentation / build-and-deploy (push) Successful in 33s

This commit is contained in:
2026-01-08 22:05:11 +01:00
parent ebb026b807
commit 0555ddd041
6 changed files with 68 additions and 88 deletions

View File

@@ -4,6 +4,7 @@
#include <amd64/msr.h>
#include <libk/std.h>
#include <limine/requests.h>
#include <sync/spin_lock.h>
#include <sys/debug.h>
#include <sys/mm.h>
#include <sys/spin.h>
@@ -33,8 +34,14 @@
/* Divide config register */
#define LAPIC_DCR 0x3E0
struct ioapic {
struct acpi_madt_ioapic table_data;
spin_lock_t lock;
uintptr_t mmio_base;
};
/* Table of IOAPICS */
static struct acpi_madt_ioapic apics[IOAPICS_MAX];
static struct ioapic ioapics[IOAPICS_MAX];
/* Table of interrupt source overrides */
/* clang-format off */
static struct acpi_madt_interrupt_source_override intr_src_overrides[INTERRUPT_SRC_OVERRIDES_MAX];
@@ -43,33 +50,39 @@ static struct acpi_madt_interrupt_source_override intr_src_overrides[INTERRUPT_S
static size_t ioapic_entries = 0;
/* Count of actual interrupt source overrides */
static size_t intr_src_override_entries = 0;
/* Local APIC MMIO base address. It comes from MSR_APIC_BASE */
static uintptr_t lapic_mmio_base = 0;
static uint64_t lapic_ticks;
/* Read IOAPIC */
static uint32_t amd64_ioapic_read (uintptr_t vaddr, uint32_t reg) {
*(volatile uint32_t*)vaddr = reg;
return *(volatile uint32_t*)(vaddr + 0x10);
static uint32_t amd64_ioapic_read (struct ioapic* ioapic, uint32_t reg) {
spin_lock (&ioapic->lock);
*(volatile uint32_t*)ioapic->mmio_base = reg;
uint32_t ret = *(volatile uint32_t*)(ioapic->mmio_base + 0x10);
spin_unlock (&ioapic->lock);
return ret;
}
/* Write IOAPIC */
static void amd64_ioapic_write (uintptr_t vaddr, uint32_t reg, uint32_t value) {
*(volatile uint32_t*)vaddr = reg;
*(volatile uint32_t*)(vaddr + 0x10) = value;
static void amd64_ioapic_write (struct ioapic* ioapic, uint32_t reg, uint32_t value) {
spin_lock (&ioapic->lock);
*(volatile uint32_t*)ioapic->mmio_base = reg;
*(volatile uint32_t*)(ioapic->mmio_base + 0x10) = value;
spin_unlock (&ioapic->lock);
}
/* Find an IOAPIC corresposting to provided IRQ */
static struct acpi_madt_ioapic* amd64_ioapic_find (uint8_t irq) {
struct acpi_madt_ioapic* apic = NULL;
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
static struct ioapic* amd64_ioapic_find (uint8_t irq) {
struct ioapic* ioapic = NULL;
for (size_t i = 0; i < ioapic_entries; i++) {
apic = &apics[i];
uint32_t version = amd64_ioapic_read ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, 1);
ioapic = &ioapics[i];
/* uint32_t version = amd64_ioapic_read ((uintptr_t)hhdm->offset +
* (uintptr_t)ioapic->table_data.address, 1); */
uint32_t version = amd64_ioapic_read (ioapic, 1);
uint32_t max = ((version >> 16) & 0xFF);
if ((irq >= apic->gsi_base) && (irq <= (apic->gsi_base + max)))
return apic;
if ((irq >= ioapic->table_data.gsi_base) && (irq <= (ioapic->table_data.gsi_base + max)))
return ioapic;
}
return NULL;
@@ -85,10 +98,9 @@ static struct acpi_madt_ioapic* amd64_ioapic_find (uint8_t irq) {
* lapic_id - Local APIC that will receive the interrupt.
*/
void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags, uint64_t lapic_id) {
struct acpi_madt_ioapic* apic = NULL;
struct ioapic* ioapic = NULL;
struct acpi_madt_interrupt_source_override* override;
bool found_override = false;
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
for (size_t i = 0; i < intr_src_override_entries; i++) {
override = &intr_src_overrides[i];
@@ -111,52 +123,15 @@ void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags, uint64_t
calc_flags |= flags;
}
apic = amd64_ioapic_find (irq);
ioapic = amd64_ioapic_find (irq);
if (apic == NULL)
if (ioapic == NULL)
return;
uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10;
uint32_t irq_reg = ((irq - ioapic->table_data.gsi_base) * 2) + 0x10;
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg,
(uint32_t)calc_flags);
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg + 1,
(uint32_t)(calc_flags >> 32));
}
/* Mask a given IRQ */
void amd64_ioapic_mask (uint8_t irq) {
struct acpi_madt_ioapic* apic;
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
apic = amd64_ioapic_find (irq);
if (apic == NULL)
return;
uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10;
uint32_t value = amd64_ioapic_read ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg);
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg,
value | (1 << 16));
}
/* Unmask a given IRQ */
void amd64_ioapic_unmask (uint8_t irq) {
struct acpi_madt_ioapic* apic;
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
apic = amd64_ioapic_find (irq);
if (apic == NULL)
return;
uint32_t irq_reg = ((irq - apic->gsi_base) * 2) + 0x10;
uint32_t value = amd64_ioapic_read ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg);
amd64_ioapic_write ((uintptr_t)hhdm->offset + (uintptr_t)apic->address, irq_reg,
value & ~(1 << 16));
amd64_ioapic_write (ioapic, irq_reg + 1, (uint32_t)(calc_flags >> 32));
amd64_ioapic_write (ioapic, irq_reg, (uint32_t)calc_flags);
}
/* Find and initialize the IOAPIC */
@@ -180,11 +155,15 @@ void amd64_ioapic_init (void) {
switch (current->type) {
case ACPI_MADT_ENTRY_TYPE_IOAPIC: {
struct acpi_madt_ioapic* ioapic = (struct acpi_madt_ioapic*)current;
mm_map_kernel_page ((uintptr_t)ioapic->address,
(uintptr_t)hhdm->offset + (uintptr_t)ioapic->address,
struct acpi_madt_ioapic* ioapic_table_data = (struct acpi_madt_ioapic*)current;
mm_map_kernel_page ((uintptr_t)ioapic_table_data->address,
(uintptr_t)hhdm->offset + (uintptr_t)ioapic_table_data->address,
MM_PG_PRESENT | MM_PG_RW | MM_PD_RELOAD);
apics[ioapic_entries++] = *ioapic;
ioapics[ioapic_entries++] = (struct ioapic){
.lock = SPIN_LOCK_INIT,
.table_data = *ioapic_table_data,
.mmio_base = ((uintptr_t)hhdm->offset + (uintptr_t)ioapic_table_data->address),
};
} break;
case ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE: {
struct acpi_madt_interrupt_source_override* override =
@@ -198,7 +177,7 @@ void amd64_ioapic_init (void) {
}
/* Get MMIO base of Local APIC */
static uintptr_t amd64_lapic_base (void) { return lapic_mmio_base; }
static uintptr_t amd64_lapic_base (void) { return thiscpu->lapic_mmio_base; }
/* Write Local APIC */
static void amd64_lapic_write (uint32_t reg, uint32_t value) {
@@ -216,9 +195,6 @@ uint32_t amd64_lapic_id (void) { return amd64_lapic_read (LAPIC_ID) >> 24; }
/* Send End of interrupt command to Local APIC */
void amd64_lapic_eoi (void) { amd64_lapic_write (LAPIC_EOI, 0); }
/* Set initial counter value in Local APIC timer */
void amd64_lapic_tick (uint32_t tick) { amd64_lapic_write (LAPIC_TIMICT, tick); }
/*
* Calibrate Local APIC to send interrupts in a set interval.
*
@@ -255,24 +231,24 @@ static void amd64_lapic_start (uint32_t ticks) {
* Initialize Local APIC, configure to send timer interrupts at a given period. See
* amd64_lapic_calibrate and amd64_lapic_start.
*/
uint64_t amd64_lapic_init (uint32_t us) {
void amd64_lapic_init (uint32_t us) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
amd64_wrmsr (MSR_APIC_BASE, amd64_rdmsr (MSR_APIC_BASE) | (1 << 11));
uintptr_t lapic_paddr = amd64_rdmsr (MSR_APIC_BASE) & 0xFFFFF000;
lapic_mmio_base = lapic_paddr + (uintptr_t)hhdm->offset;
thiscpu->lapic_mmio_base = lapic_paddr + (uintptr_t)hhdm->offset;
mm_map_kernel_page (lapic_paddr, lapic_mmio_base,
mm_map_kernel_page (lapic_paddr, thiscpu->lapic_mmio_base,
MM_PG_PRESENT | MM_PG_RW | MM_PD_LOCK | MM_PD_RELOAD);
amd64_lapic_write (LAPIC_SIVR, 0xFF | (1 << 8));
uint32_t ticks = amd64_lapic_calibrate (us);
if (thiscpu->id == 0) {
lapic_ticks = amd64_lapic_calibrate (us);
}
amd64_lapic_start (ticks);
return ticks;
amd64_lapic_start (lapic_ticks);
}
/*
@@ -282,6 +258,11 @@ uint64_t amd64_lapic_init (uint32_t us) {
* vec - Interrupt vector/IDT stub, which will be invoked by the IPI.
*/
void amd64_lapic_ipi (uint8_t lapic_id, uint8_t vec) {
/* wait for previous IPI to finish */
while (amd64_lapic_read (LAPIC_ICR) & (1 << 12)) {
__asm__ volatile ("pause");
}
amd64_lapic_write (LAPIC_ICR + 0x10, (lapic_id << 24));
amd64_lapic_write (LAPIC_ICR, vec);
}

View File

@@ -4,14 +4,11 @@
#include <libk/std.h>
void amd64_ioapic_route_irq (uint8_t vec, uint8_t irq, uint64_t flags, uint64_t lapic_id);
void amd64_ioapic_mask (uint8_t irq);
void amd64_ioapic_unmask (uint8_t irq);
void amd64_ioapic_init (void);
uint32_t amd64_lapic_id (void);
void amd64_lapic_tick (uint32_t tick);
void amd64_lapic_eoi (void);
void amd64_lapic_ipi (uint8_t lapic_id, uint8_t vec);
uint64_t amd64_lapic_init (uint32_t us);
void amd64_lapic_init (uint32_t us);
#endif // _KERNEL_AMD64_APIC_H

View File

@@ -61,8 +61,7 @@ static void amd64_smp_bootstrap (struct limine_mp_info* mp_info) {
amd64_init (cpu, true); /* gdt + idt */
syscall_init ();
thiscpu->lapic_ticks = amd64_lapic_init (10000);
amd64_lapic_tick (thiscpu->lapic_ticks);
amd64_lapic_init (0);
DEBUG ("CPU %u is online!\n", thiscpu->id);
@@ -76,7 +75,7 @@ static void amd64_smp_bootstrap (struct limine_mp_info* mp_info) {
/// Initialize SMP subsystem for AMD64. Start AP CPUs
void smp_init (void) {
thiscpu->lapic_ticks = amd64_lapic_init (10000);
amd64_lapic_init (10000);
struct limine_mp_response* mp = limine_mp_request.response;

View File

@@ -21,7 +21,7 @@ struct cpu {
volatile struct gdt_extended gdt ALIGNED (16);
volatile struct tss tss;
uint64_t lapic_ticks;
uintptr_t lapic_mmio_base;
uint32_t id;
struct {