1
0
Fork 0

feat/kernel: Added I/O APIC support

This commit is contained in:
Kevin Alavik 2025-06-01 12:52:41 +02:00
parent 03cc8ff8de
commit f81181ea9c
Signed by: cmpsb
GPG key ID: 10D1CC0526FDC6D7
9 changed files with 141 additions and 43 deletions

View file

@ -25,7 +25,9 @@
"spinlock.h": "c",
"fb.h": "c",
"acpi.h": "c",
"madt.h": "c"
"madt.h": "c",
"ioapic.h": "c",
"stdatomic.h": "c"
},
"editor.formatOnPaste": true,
"editor.formatOnSave": true,

View file

@ -112,42 +112,6 @@ uint64_t *pmget(void)
return (uint64_t *)HIGHER_HALF(cr3);
}
/* Map virtual to physical address */
int vmap(uint64_t *pagemap, uint64_t virt, uint64_t phys, uint64_t flags)
{
if (!pagemap || (virt & (PAGE_SIZE - 1)) || (phys & (PAGE_SIZE - 1)))
{
return -1;
}
uint64_t pml4_idx = page_index(virt, PML4_SHIFT);
uint64_t pml3_idx = page_index(virt, PML3_SHIFT);
uint64_t pml2_idx = page_index(virt, PML2_SHIFT);
uint64_t pml1_idx = page_index(virt, PML1_SHIFT);
uint64_t *pml3 = get_or_alloc_table(pagemap, pml4_idx, flags);
if (!pml3)
{
return -1;
}
uint64_t *pml2 = get_or_alloc_table(pml3, pml3_idx, flags);
if (!pml2)
{
return -1;
}
uint64_t *pml1 = get_or_alloc_table(pml2, pml2_idx, flags);
if (!pml1)
{
return -1;
}
pml1[pml1_idx] = phys | flags;
__asm__ volatile("invlpg (%0)" ::"r"(virt) : "memory");
return 0;
}
/* Map virtual to physical address (large), only use during paging init */
bool _supports_large_pages()
{
@ -187,6 +151,42 @@ int vmap_large(uint64_t *pagemap, uint64_t virt, uint64_t phys, uint64_t flags)
return 0;
}
/* Map virtual to physical address */
int vmap(uint64_t *pagemap, uint64_t virt, uint64_t phys, uint64_t flags)
{
if (!pagemap)
{
return -1;
}
uint64_t pml4_idx = page_index(virt, PML4_SHIFT);
uint64_t pml3_idx = page_index(virt, PML3_SHIFT);
uint64_t pml2_idx = page_index(virt, PML2_SHIFT);
uint64_t pml1_idx = page_index(virt, PML1_SHIFT);
uint64_t *pml3 = get_or_alloc_table(pagemap, pml4_idx, flags);
if (!pml3)
{
return -1;
}
uint64_t *pml2 = get_or_alloc_table(pml3, pml3_idx, flags);
if (!pml2)
{
return -1;
}
uint64_t *pml1 = get_or_alloc_table(pml2, pml2_idx, flags);
if (!pml1)
{
return -1;
}
pml1[pml1_idx] = phys | flags;
__asm__ volatile("invlpg (%0)" ::"r"(virt) : "memory");
return 0;
}
/* Unmap virtual address */
int vunmap(uint64_t *pagemap, uint64_t virt)
{

View file

@ -21,6 +21,7 @@
#include <sys/acpi.h>
#include <sys/acpi/madt.h>
#include <sys/apic/lapic.h>
#include <sys/apic/ioapic.h>
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
__attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = {
@ -189,7 +190,7 @@ void emk_entry(void)
outb(0x21, 0xff);
outb(0xA1, 0xff);
/* Init APIC (LAPIC for now) */
/* Setup LAPIC */
lapic_init();
/* Setup SMP */
@ -201,6 +202,9 @@ void emk_entry(void)
mp_response = mp_request.response;
smp_init();
/* Setup IOAPIC */
ioapic_init();
/* Finished */
log_early("%s", LOG_SEPARATOR);
log_early("Finished initializing EMK v1.0, took ? seconds"); /* Still not usermode, so keep using log_early */

View file

@ -14,7 +14,7 @@ void *acpi_vtable(uint64_t phys)
acpi_sdt_header_t *tmp = (acpi_sdt_header_t *)vallocat(kvm_ctx, 1, VALLOC_RW, phys);
if (!tmp)
{
kpanic(NULL, "Failed to map first page of ACPI table");
kpanic(NULL, "Failed to map first page of ACPI table, got virt: %p", tmp);
return NULL;
}

View file

@ -95,8 +95,16 @@ typedef struct acpi_madt_lx2apic
extern acpi_madt_ioapic_t *madt_ioapic_list[256];
extern acpi_madt_ioapic_src_ovr_t *madt_iso_list[256];
extern acpi_madt_lapic_t *madt_lapic_list[256];
extern acpi_madt_lapic_nmi_t *madt_lapic_nmi_list[256];
extern acpi_madt_ioapic_nmi_src_t *madt_ioapic_nmi_list[256];
extern acpi_madt_lx2apic_t *madt_lx2apic_list[256];
extern uint32_t madt_ioapic_len;
extern uint32_t madt_iso_len;
extern uint32_t madt_lapic_len;
extern uint32_t madt_lapic_nmi_len;
extern uint32_t madt_ioapic_nmi_len;
extern uint32_t madt_lx2apic_len;
extern uint64_t lapic_addr;
void madt_init();

View file

@ -0,0 +1,64 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#include <sys/apic/ioapic.h>
#include <sys/acpi/madt.h>
#include <sys/kpanic.h>
#include <stdatomic.h>
#include <util/log.h>
#include <arch/paging.h>
#include <boot/emk.h>
#include <arch/idt.h>
#include <arch/smp.h>
atomic_uintptr_t ioapic_base = 0;
void ioapic_write(uint8_t index, uint32_t value)
{
volatile uint32_t *ioapic = (volatile uint32_t *)atomic_load(&ioapic_base);
ioapic[IOAPIC_OFF_IOREGSEL / 4] = index; // Write register index to IOREGSEL
ioapic[IOAPIC_OFF_IOWIN / 4] = value; // Write value to IOWIN
}
uint32_t ioapic_read(uint8_t index)
{
volatile uint32_t *ioapic = (volatile uint32_t *)atomic_load(&ioapic_base);
ioapic[IOAPIC_OFF_IOREGSEL / 4] = index; // Write register index to IOREGSEL
return ioapic[IOAPIC_OFF_IOWIN / 4]; // Read value from IOWIN
}
void ioapic_map(int irq, int vec, idt_intr_handler handler)
{
uint32_t redtble_lo = (0 << 16) | /* Unmask the entry */
(0 << 11) | /* Dest mode */
(0 << 8) | /* Delivery mode */
vec; /* Interrupt vector*/
ioapic_write(2 * irq, redtble_lo);
uint32_t redtble_hi = (get_cpu_local()->lapic_id << 24);
ioapic_write(2 * irq + 1, redtble_hi);
idt_register_handler(vec, handler);
}
void ioapic_init()
{
if (madt_ioapic_len < 1)
{
kpanic(NULL, "No I/O APIC's available");
}
/* Set base of I/O APIC */
uint64_t base = madt_ioapic_list[0]->ioapic_addr;
log_early("I/O APIC phys addr: 0x%lx", base);
uint64_t virt_addr = (uint64_t)HIGHER_HALF(base);
int ret = vmap(pmget(), virt_addr, base, VMM_PRESENT | VMM_WRITE | VMM_NX);
if (ret != 0)
{
log_early("error: Failed to map I/O APIC base 0x%lx to 0x%lx", base, virt_addr);
kpanic(NULL, "I/O APIC mapping failed");
}
atomic_store(&ioapic_base, virt_addr);
// Read IOAPICVER register to get the maximum redirection entry
uint32_t ioapic_ver = ioapic_read(IOAPIC_IDX_IOAPICVER);
uint32_t max_irqs = ((ioapic_ver >> 16) & 0xFF) + 1;
log_early("I/O APIC supports %u IRQs", max_irqs);
}

View file

@ -0,0 +1,15 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#ifndef IOAPIC_H
#define IOAPIC_H
#include <arch/idt.h>
// I/O APIC Registers
#define IOAPIC_OFF_IOREGSEL 0x0
#define IOAPIC_OFF_IOWIN 0x10
#define IOAPIC_IDX_IOAPICVER 0x01
void ioapic_init();
void ioapic_map(int irq, int vec, idt_intr_handler handler);
#endif // IOAPIC_H

View file

@ -10,9 +10,9 @@
#define LAPIC_REG_SIZE 4
atomic_uintptr_t lapic_msr = 0;
atomic_uintptr_t lapic_base_atomic = 0;
atomic_uintptr_t lapic_base = 0;
#define LAPIC_BASE ((volatile uint32_t *)atomic_load(&lapic_base_atomic))
#define LAPIC_BASE ((volatile uint32_t *)atomic_load(&lapic_base))
void lapic_write(uint32_t offset, uint32_t value)
{
@ -65,10 +65,15 @@ void lapic_init(void)
kpanic(NULL, "LAPIC mapping failed");
}
atomic_store(&lapic_base_atomic, virt_addr);
atomic_store(&lapic_base, virt_addr);
atomic_store(&lapic_addr, virt_addr);
}
void lapic_eoi(void)
{
lapic_write(LAPIC_EOI, 0);
}
void lapic_enable(void)
{
volatile uint32_t *base = LAPIC_BASE;

View file

@ -33,12 +33,12 @@
// Startup vector address (must be in first 1MB, page-aligned)
#define AP_BOOT_ADDRESS 0x8000 // Example: 32KB physical address
extern volatile uint32_t *lapic_base;
extern uint64_t lapic_addr;
uint32_t lapic_read(uint32_t offset);
void lapic_write(uint32_t offset, uint32_t value);
void lapic_init(void);
void lapic_enable(void);
void lapic_eoi(void);
#endif // LAPIC_H