feat/kernel: Added I/O APIC support
This commit is contained in:
parent
03cc8ff8de
commit
f81181ea9c
9 changed files with 141 additions and 43 deletions
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
64
kernel/src/sys/apic/ioapic.c
Normal file
64
kernel/src/sys/apic/ioapic.c
Normal 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);
|
||||
}
|
15
kernel/src/sys/apic/ioapic.h
Normal file
15
kernel/src/sys/apic/ioapic.h
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue