chore: reorganize file directories

We have reorganized all the file directories that previously looked ugly as hell (cough cough arch/x86_64 cough)

Now it looks much cleaner

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-04-26 14:44:40 -04:00
parent d22d5ab2e4
commit 336af1c2ad
67 changed files with 96 additions and 99 deletions
+359
View File
@@ -0,0 +1,359 @@
#include "ioapic.h"
#include "apic.h"
#include "mm/vmm.h"
#include "mm/memory.h"
#include "libk/stdio.h"
#include <uacpi/tables.h> /* uacpi_table_find_by_signature / uacpi_table_unref */
#include "pic.h"
/* ══════════════════════════════════════════════════════════════════════════
* ACPI MADT structures
* (Defined locally so we don't depend on uACPI's internal acpi.h layout.)
* ══════════════════════════════════════════════════════════════════════════ */
extern const PICDriver* g_Driver; // old pic driver
bool g_IOAPIC = false; // IOAPIC enabled
typedef struct {
uint8_t signature[4]; /* "APIC" */
uint32_t length;
uint8_t revision;
uint8_t checksum;
uint8_t oem_id[6];
uint8_t oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
/* --- MADT-specific -------------------------------------------------- */
uint32_t local_apic_addr; /* Default LAPIC physical address (32-bit) */
uint32_t flags; /* bit 0 = dual 8259 PICs present */
/* followed by variable-length Interrupt Controller Structure entries */
} __attribute__((packed)) madt_t;
typedef struct {
uint8_t type;
uint8_t length;
} __attribute__((packed)) madt_entry_hdr_t;
/* Type 0: Processor Local APIC */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t uid;
uint8_t apic_id;
uint32_t flags; /* bit 0 = enabled */
} __attribute__((packed)) madt_lapic_t;
/* Type 1: I/O APIC */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t id;
uint8_t reserved;
uint32_t address; /* Physical MMIO base */
uint32_t gsi_base; /* First GSI handled by this IOAPIC */
} __attribute__((packed)) madt_ioapic_t;
/* Type 2: Interrupt Source Override */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t bus; /* 0 = ISA */
uint8_t source; /* ISA IRQ number */
uint32_t gsi; /* Remapped GSI */
uint16_t flags; /* bits [1:0] = polarity, bits [3:2] = trigger mode */
} __attribute__((packed)) madt_iso_t;
/* Type 4: Local APIC NMI */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t uid; /* 0xFF = all processors */
uint16_t flags;
uint8_t lint; /* 0 or 1 */
} __attribute__((packed)) madt_nmi_t;
/* ══════════════════════════════════════════════════════════════════════════
* Internal state
* ══════════════════════════════════════════════════════════════════════════ */
typedef struct {
volatile uint32_t *base; /* Virtual address of IOAPIC MMIO */
uint32_t gsi_base;
uint32_t gsi_count; /* Number of redirection entries */
} ioapic_t;
static ioapic_t g_ioapics[IOAPIC_MAX];
static int g_ioapic_count = 0;
/* ISA interrupt source overrides (max 16 ISA IRQs) */
typedef struct {
bool present;
uint32_t gsi;
bool active_low;
bool level;
} iso_t;
static iso_t g_iso[16]; /* indexed by ISA IRQ (source) */
/* ══════════════════════════════════════════════════════════════════════════
* Low-level IOAPIC MMIO access
*
* The IOAPIC has two MMIO registers:
* base+0x00 IOREGSEL index register (write which register to access)
* base+0x10 IOWIN data window (read/write the selected register)
* ══════════════════════════════════════════════════════════════════════════ */
static uint32_t ioapic_read(const ioapic_t *io, uint8_t reg) {
*((volatile uint32_t *)(io->base + (0x00 >> 2))) = reg;
return *((volatile uint32_t *)(io->base + (0x10 >> 2)));
}
static void ioapic_write(const ioapic_t *io, uint8_t reg, uint32_t val) {
*((volatile uint32_t *)(io->base + (0x00 >> 2))) = reg;
*((volatile uint32_t *)(io->base + (0x10 >> 2))) = val;
}
/* ── Find which IOAPIC owns a given GSI ─────────────────────────────────── */
static ioapic_t *ioapic_for_gsi(uint32_t gsi) {
for (int i = 0; i < g_ioapic_count; i++) {
ioapic_t *io = &g_ioapics[i];
if (gsi >= io->gsi_base && gsi < io->gsi_base + io->gsi_count)
return io;
}
return NULL;
}
/* ══════════════════════════════════════════════════════════════════════════
* Public API
* ══════════════════════════════════════════════════════════════════════════ */
uint32_t ioapic_gsi_for_isa_irq(uint8_t isa_irq) {
if (isa_irq < 16 && g_iso[isa_irq].present)
return g_iso[isa_irq].gsi;
return isa_irq;
}
void ioapic_redirect(uint32_t gsi, uint8_t vector, uint8_t dest_lapic,
bool active_low, bool level, bool masked) {
ioapic_t *io = ioapic_for_gsi(gsi);
if (!io) {
printf("[IOAPIC] No IOAPIC for GSI %u\n", gsi);
return;
}
uint8_t idx = (uint8_t)(gsi - io->gsi_base);
uint32_t lo = (uint32_t)vector
| IOAPIC_RTE_DM_FIXED
| (active_low ? IOAPIC_RTE_ACTIVE_LOW : 0)
| (level ? IOAPIC_RTE_LEVEL : 0)
| (masked ? IOAPIC_RTE_MASKED : 0);
uint32_t hi = (uint32_t)dest_lapic << 24;
/* Write high word first, then low (avoids momentary spurious delivery) */
ioapic_write(io, IOAPIC_REDTBL_HI(idx), hi);
ioapic_write(io, IOAPIC_REDTBL_LO(idx), lo);
}
void ioapic_mask_gsi(uint32_t gsi) {
ioapic_t *io = ioapic_for_gsi(gsi);
if (!io) return;
uint8_t idx = (uint8_t)(gsi - io->gsi_base);
uint32_t lo = ioapic_read(io, IOAPIC_REDTBL_LO(idx));
ioapic_write(io, IOAPIC_REDTBL_LO(idx), lo | IOAPIC_RTE_MASKED);
}
void ioapic_unmask_gsi(uint32_t gsi) {
ioapic_t *io = ioapic_for_gsi(gsi);
if (!io) return;
uint8_t idx = (uint8_t)(gsi - io->gsi_base);
uint32_t lo = ioapic_read(io, IOAPIC_REDTBL_LO(idx));
ioapic_write(io, IOAPIC_REDTBL_LO(idx), lo & ~IOAPIC_RTE_MASKED);
}
/* ══════════════════════════════════════════════════════════════════════════
* Initialisation
* ══════════════════════════════════════════════════════════════════════════ */
void ioapic_init(void) {
/*
* ── Step 1: Find the MADT via uACPI ──────────────────────────────────
*
* The MADT signature in ACPI is "APIC" (not "MADT").
* uacpi_table_find_by_signature returns a handle whose .ptr field points
* to the raw table data in (HHDM-mapped) physical memory.
*/
struct uacpi_table madt_table;
uacpi_status st = uacpi_table_find_by_signature("APIC", &madt_table);
if (uacpi_unlikely_error(st)) {
printf("[IOAPIC] Could not find MADT: %s\n", uacpi_status_to_string(st));
return;
}
madt_t *madt = (madt_t *)madt_table.ptr;
printf("[IOAPIC] MADT @ virt 0x%lx len=%u lapic_addr=0x%08x\n",
(uint64_t)madt, madt->length, madt->local_apic_addr);
/*
* ── Step 2: Walk the MADT entry list ─────────────────────────────────
*
* Entries start immediately after the fixed 44-byte MADT header and run
* until madt->length bytes from the table base.
*/
const uint8_t *entry_ptr = (const uint8_t *)madt + sizeof(madt_t);
const uint8_t *madt_end = (const uint8_t *)madt + madt->length;
while (entry_ptr < madt_end) {
const madt_entry_hdr_t *hdr = (const madt_entry_hdr_t *)entry_ptr;
if (hdr->length < 2) {
printf("[IOAPIC] MADT entry with length < 2, stopping parse\n");
break;
}
switch (hdr->type) {
/* ── Type 0: Processor Local APIC ──────────────────────────────── */
case 0: {
const madt_lapic_t *e = (const madt_lapic_t *)entry_ptr;
printf("[IOAPIC] MADT[0] Processor UID=%u LAPIC ID=%u flags=0x%x%s\n",
e->uid, e->apic_id, e->flags,
(e->flags & 1) ? "" : " (disabled)");
break;
}
/* ── Type 1: I/O APIC ───────────────────────────────────────────── */
case 1: {
const madt_ioapic_t *e = (const madt_ioapic_t *)entry_ptr;
if (g_ioapic_count >= IOAPIC_MAX) {
printf("[IOAPIC] Too many IOAPICs, skipping ID=%u\n", e->id);
break;
}
ioapic_t *io = &g_ioapics[g_ioapic_count];
io->gsi_base = e->gsi_base;
/*
* Map the IOAPIC MMIO page. Like the LAPIC, the HHDM covers the
* IOAPIC's physical address (typically 0xFEC00000) so we just add
* MEM_PHYS_OFFSET. Two MMIO registers are accessed (offsets 0 and
* 0x10) so one 4 KiB page is sufficient.
*
* TODO: Mark the page UC (cache-disable) in the PTE when your VMM
* gains support for PAT / PCD flags.
*/
uint64_t phys = (uint64_t)e->address;
uintptr_t virt = (uintptr_t)phys + MEM_PHYS_OFFSET;
/* The HHDM loop in vmm_init already covered this range; if not,
* uncomment the explicit map call below: */
/* vmm_map_page(kernel_pagemap, virt, phys,
PAGE_READ | PAGE_WRITE | PAGE_NO_EXECUTE, Size4KiB); */
io->base = (volatile uint32_t *)virt;
/* Read version register to discover number of redirection entries */
uint32_t ver = ioapic_read(io, IOAPIC_REG_VER);
io->gsi_count = ((ver >> 16) & 0xFF) + 1; /* bits [23:16] = max entry index */
printf("[IOAPIC] MADT[1] ID=%u phys=0x%08x GSI base=%u entries=%u\n",
e->id, e->address, io->gsi_base, io->gsi_count);
/*
* ── Mask every redirection entry ─────────────────────────────
*
* We keep all entries masked at boot time. Legacy ISA IRQs are
* handled by the i8259 → LAPIC LINT0 ExtINT path, not via the
* IOAPIC. PCI devices can be connected later with ioapic_redirect().
*/
for (uint32_t n = 0; n < io->gsi_count; n++) {
ioapic_write(io, IOAPIC_REDTBL_HI(n), 0);
ioapic_write(io, IOAPIC_REDTBL_LO(n), IOAPIC_RTE_MASKED | 0xFF);
}
g_ioapic_count++;
break;
}
/* ── Type 2: Interrupt Source Override ──────────────────────────── */
case 2: {
const madt_iso_t *e = (const madt_iso_t *)entry_ptr;
/* flags bits [1:0]: 00/11 = conforms to bus (ISA = active high edge)
* 01 = active high, 11 = active low
* flags bits [3:2]: 00/11 = conforms to bus (ISA = edge)
* 01 = edge, 11 = level */
bool active_low = ((e->flags & 0x3) == 3);
bool level = ((e->flags >> 2) & 0x3) == 3;
printf("[IOAPIC] MADT[2] ISA IRQ %u -> GSI %u %s %s\n",
e->source, e->gsi,
active_low ? "active-low" : "active-high",
level ? "level" : "edge");
if (e->source < 16) {
g_iso[e->source].present = true;
g_iso[e->source].gsi = e->gsi;
g_iso[e->source].active_low = active_low;
g_iso[e->source].level = level;
}
break;
}
/* ── Type 4: Local APIC NMI ─────────────────────────────────────── */
case 4: {
const madt_nmi_t *e = (const madt_nmi_t *)entry_ptr;
printf("[IOAPIC] MADT[4] NMI UID=0x%02x LINT%u\n",
e->uid, e->lint);
break;
}
default:
printf("[IOAPIC] MADT entry type=%u length=%u (skipped)\n",
hdr->type, hdr->length);
break;
}
entry_ptr += hdr->length;
}
uacpi_table_unref(&madt_table);
printf("[IOAPIC] Init done: %d IOAPIC(s) found\n", g_ioapic_count);
}
void irq_redirect_to_apic(uint8_t isa_irq, uint8_t vector,
uint8_t dest_lapic, bool masked)
{
if (isa_irq >= 16) {
printf("[IRQ] irq_redirect_to_apic: ISA IRQ %u out of range\n", isa_irq);
return;
}
uint32_t gsi = ioapic_gsi_for_isa_irq(isa_irq);
/* Get polarity/trigger from MADT ISO or use ISA defaults */
bool active_low = false;
bool level = false;
if (isa_irq < 16 && g_iso[isa_irq].present) {
active_low = g_iso[isa_irq].active_low;
level = g_iso[isa_irq].level;
} else {
/* Standard ISA: active-high, edge-triggered (except some like IRQ0/8) */
if (isa_irq == 0 || isa_irq == 8) {
level = true; /* often level on real hardware */
}
}
/* Mask in the 8259 so it stops firing through LINT0 */
if (g_Driver) {
g_Driver->Mask(isa_irq); // from your irq.c / i8259
}
/* Programme IOAPIC redirection entry */
ioapic_redirect(gsi, vector, dest_lapic,
active_low, level, masked);
printf("[IRQ] Redirected ISA IRQ %u -> GSI %u vector 0x%02x LAPIC %u %s %s\n",
isa_irq, gsi, vector, dest_lapic,
active_low ? "active-low" : "active-high",
level ? "level" : "edge");
g_IOAPIC = true;
}