From b2cf9b471067ad2d6e93b47c50634851a5e718b8 Mon Sep 17 00:00:00 2001 From: RaphProductions <81994075+RaphProductions@users.noreply.github.com> Date: Tue, 20 May 2025 08:29:23 +0200 Subject: [PATCH] kernel: Implemented various features + lapic: Start implementation + ioapic: Start implementation + apic: Now properly working + madt: Start implementation + pit: Start implementation + smp: Start implementation (only grabs the bootstrap processor's LAPIC ID) --- kernel/src/acpi/acpi.c | 35 ++++++++- kernel/src/acpi/acpi.h | 30 +++++++- kernel/src/acpi/madt.c | 42 +++++++++++ kernel/src/acpi/madt.h | 61 ++++++++++++++++ kernel/src/arch/cpu.h | 7 ++ kernel/src/arch/x86_64/cpu.h | 0 kernel/src/arch/x86_64/idt.asm | 15 ++-- kernel/src/arch/x86_64/idt.c | 129 ++++++++++++++++----------------- kernel/src/arch/x86_64/idt.h | 11 +++ kernel/src/arch/x86_64/io.h | 23 ++++++ kernel/src/arch/x86_64/pit.c | 30 ++++++++ kernel/src/arch/x86_64/smp.c | 17 +++++ kernel/src/arch/x86_64/smp.h | 12 +++ kernel/src/boot/limine.c | 9 ++- kernel/src/boot/limine.h | 3 +- kernel/src/dev/ioapic.c | 87 ++++++++++++++++++++++ kernel/src/dev/ioapic.h | 17 +++++ kernel/src/dev/lapic.c | 33 +++++++++ kernel/src/dev/lapic.h | 26 +++++++ kernel/src/main.c | 12 ++- kernel/src/mm/pmm.md | 0 kernel/src/mm/vmm.c | 0 22 files changed, 520 insertions(+), 79 deletions(-) create mode 100644 kernel/src/acpi/madt.c create mode 100644 kernel/src/acpi/madt.h create mode 100644 kernel/src/arch/x86_64/cpu.h create mode 100644 kernel/src/arch/x86_64/io.h create mode 100644 kernel/src/arch/x86_64/pit.c create mode 100644 kernel/src/arch/x86_64/smp.c create mode 100644 kernel/src/arch/x86_64/smp.h create mode 100644 kernel/src/dev/ioapic.c create mode 100644 kernel/src/dev/ioapic.h create mode 100644 kernel/src/dev/lapic.c create mode 100644 kernel/src/dev/lapic.h create mode 100644 kernel/src/mm/pmm.md create mode 100644 kernel/src/mm/vmm.c diff --git a/kernel/src/acpi/acpi.c b/kernel/src/acpi/acpi.c index 81e1efb..e063caa 100644 --- a/kernel/src/acpi/acpi.c +++ b/kernel/src/acpi/acpi.c @@ -12,10 +12,41 @@ #include #include #include +#include +#include static bool __acpi_use_xsdt; static uint64_t __acpi_rsdt_addr; +void *acpi_find_table(char *sign) { + if (__acpi_use_xsdt) { + acpi_xsdt_t *xsdt = (acpi_xsdt_t*)__acpi_rsdt_addr; + uint32_t entries = (xsdt->hdr.len - sizeof(xsdt->hdr)) / 8; + + for (uint32_t i = 0; i < entries; i++) + { + acpi_sdt_hdr_t *h = (acpi_sdt_hdr_t *)higher_half(*((uint64_t*)xsdt->entries + i)); + if (!memcmp(h->sign, sign, 4)) + return (void *) h; + } + + return NULL; + } + + acpi_rsdt_t *rsdt = (acpi_rsdt_t*)__acpi_rsdt_addr; + int entries = (rsdt->hdr.len - sizeof(rsdt->hdr)) / 4; + uint32_t *entries_hhalf = (uint32_t *)higher_half((uint64_t)rsdt->entries); + + for (int i = 0; i < entries; i++) + { + acpi_sdt_hdr_t *h = (acpi_sdt_hdr_t *)(entries_hhalf[i] + (i * sizeof(uint32_t))); + if (!memcmp(h->sign, sign, 4)) + return (void *) h; + } + + return NULL; +} + void acpi_init() { acpi_rsdp_t *rsdp = (acpi_rsdp_t*)limine_get_rsdp(); if (memcmp(rsdp->sign, "RSD PTR ", 8)) @@ -30,13 +61,13 @@ void acpi_init() { acpi_xsdp_t *xsdp = (acpi_xsdp_t *)rsdp; __acpi_use_xsdt = 1; - __acpi_rsdt_addr = xsdp->xsdt_addr; + __acpi_rsdt_addr = higher_half(xsdp->xsdt_addr); goto initialized; } __acpi_use_xsdt = 0; - __acpi_rsdt_addr = rsdp->rsdt_addr; // Do not use a pointer, to shut up the compiler. + __acpi_rsdt_addr = higher_half(rsdp->rsdt_addr); // Do not use a pointer, to shut up the compiler. initialized: trace("acpi: Initialized!\n"); diff --git a/kernel/src/acpi/acpi.h b/kernel/src/acpi/acpi.h index 5a929da..75ee2c2 100644 --- a/kernel/src/acpi/acpi.h +++ b/kernel/src/acpi/acpi.h @@ -15,14 +15,36 @@ typedef struct { char oemid[6]; char rev; uint32_t rsdt_addr; -} acpi_rsdp_t; +} __attribute__((packed)) acpi_rsdp_t; typedef struct { acpi_rsdp_t base; uint32_t len; uint64_t xsdt_addr; char chksumex; -} acpi_xsdp_t; +} __attribute__((packed)) acpi_xsdp_t; -void acpi_init(); -void acpi_init(); \ No newline at end of file +typedef struct { + char sign[4]; + uint32_t len; + uint8_t rev; + uint8_t chksum; + char oemid[6]; + char oemtabid[8]; + uint32_t oemrev; + uint32_t creaid; + uint32_t crearev; +} __attribute__((packed)) acpi_sdt_hdr_t; + +typedef struct { + acpi_sdt_hdr_t hdr; + char entries[]; +} acpi_rsdt_t; + +typedef struct { + acpi_sdt_hdr_t hdr; + char entries[]; +} acpi_xsdt_t; + +void *acpi_find_table(char *sign); +void acpi_init(); \ No newline at end of file diff --git a/kernel/src/acpi/madt.c b/kernel/src/acpi/madt.c new file mode 100644 index 0000000..eb03144 --- /dev/null +++ b/kernel/src/acpi/madt.c @@ -0,0 +1,42 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * madt.c - MADT lookup + */ + +#include "acpi/acpi.h" +#include "lib/log.h" +#include + +acpi_madt_ioapic_t* madt_ioapic_list[128]; +acpi_madt_iso_t* madt_iso_list[128]; + +uint32_t madt_ioapic_len = 0; +uint32_t madt_iso_len = 0; + +uint64_t *madt_lapic_addr = (uint64_t *)0; + +void madt_init() { + void *addr = acpi_find_table("APIC"); + acpi_madt_t *madt = (acpi_madt_t *)addr; + uint64_t offset = 0; + + while (1) { + if (offset > madt->hdr.len - sizeof(acpi_madt_t)) + break; + + madt_entry *entry = (madt_entry *)(madt->table + offset); + + if (entry->type == 1) + madt_ioapic_list[madt_ioapic_len++] = (acpi_madt_ioapic_t *)entry; + else if (entry->type == 2) + madt_iso_list[madt_iso_len++] = (acpi_madt_iso_t *)entry; + else if (entry->type == 5) + madt_lapic_addr = (uint64_t *)((acpi_madt_lapic_addr_override_t *)entry)->plapic; + + offset += entry->len; + } + + trace("madt: Initialized\n"); +} diff --git a/kernel/src/acpi/madt.h b/kernel/src/acpi/madt.h new file mode 100644 index 0000000..78bf28b --- /dev/null +++ b/kernel/src/acpi/madt.h @@ -0,0 +1,61 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * madt.h - MADT lookup + */ +#pragma once + +#include +#include + +typedef struct { + acpi_sdt_hdr_t hdr; + uint32_t lapic_addr; + uint32_t flags; + char table[]; +} acpi_madt_t; + +typedef struct { + uint8_t type; + uint8_t len; +} madt_entry; + +typedef struct { + madt_entry entry; + uint8_t cpu_id; + uint8_t lapic_id; + uint32_t flags; +} acpi_madt_lapic_t; + +typedef struct { + madt_entry entry; + uint8_t ioapic_id; + uint8_t reserved; + uint32_t ioapic_addr; + uint32_t gsi_base; +} acpi_madt_ioapic_t; + +typedef struct { + madt_entry entry; + uint8_t bus; + uint8_t source; + uint32_t gsi; + uint16_t flags; +} acpi_madt_iso_t; // iso = interrupt source override + +typedef struct { + madt_entry entry; + uint16_t reserved; + uint64_t plapic; +} acpi_madt_lapic_addr_override_t; + +extern acpi_madt_ioapic_t* madt_ioapic_list[128]; +extern acpi_madt_iso_t* madt_iso_list[128]; + +extern uint32_t madt_ioapic_len; +extern uint32_t madt_iso_len; + +extern uint64_t *lapic_addr; + +void madt_init(); \ No newline at end of file diff --git a/kernel/src/arch/cpu.h b/kernel/src/arch/cpu.h index 97b5307..76861ff 100644 --- a/kernel/src/arch/cpu.h +++ b/kernel/src/arch/cpu.h @@ -18,5 +18,12 @@ void cpu_load_pm(pagemap_t pm); // Invalidate a page table entry void cpu_invalidate_page(uint64_t vaddr); +// Initialize SMP. The implementations are in arch since the Limine +// structure changes depending on the architecture. +void cpu_init_smp(); + +// Initialize the CPU's timer +void cpu_init_timer(); + // Disable interrupts and halt the system. void hcf(); \ No newline at end of file diff --git a/kernel/src/arch/x86_64/cpu.h b/kernel/src/arch/x86_64/cpu.h new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/arch/x86_64/idt.asm b/kernel/src/arch/x86_64/idt.asm index fec724d..48b69b9 100644 --- a/kernel/src/arch/x86_64/idt.asm +++ b/kernel/src/arch/x86_64/idt.asm @@ -37,11 +37,9 @@ %macro isr_err_stub 1 isr_stub_%+%1: - push %1 ; push intno into the stack - + push %1 pushall - - mov rdi, rsp ; put the stack as the first arg. + mov rdi, rsp call idt_interrupt_handler @@ -102,10 +100,17 @@ isr_no_err_stub 29 isr_err_stub 30 isr_no_err_stub 31 +%assign i 32 +%rep 224 + isr_no_err_stub i +%assign i i+1 +%endrep + + global isr_stub_table isr_stub_table: %assign i 0 -%rep 32 +%rep 256 dq isr_stub_%+i %assign i i+1 %endrep \ No newline at end of file diff --git a/kernel/src/arch/x86_64/idt.c b/kernel/src/arch/x86_64/idt.c index 520c0b3..33985c6 100644 --- a/kernel/src/arch/x86_64/idt.c +++ b/kernel/src/arch/x86_64/idt.c @@ -4,65 +4,38 @@ * * idt.c - x86_64 Interrupt Descriptor Table implementation. */ + +#include "dev/lapic.h" #if defined(__x86_64__) -#include "arch/cpu.h" -#include "lib/log.h" +#include + +#include #include +#include +#include +#include __attribute__((aligned(0x10))) static idt_entry_t idt[256]; static idtr_t idtr; -static void __panic_display_bt(registers_t *regs) { - if (regs->cs == 0x43 || regs->cs == 0x3B) { - fatal("The backtrace can't be dumped from a userspace process.\n"); - return; // Don't try to backtrace userspace - } +static uint8_t __idt_vectors[256]; +static interrupt_handler __idt_external_handlers[256]; - fatal("-- BACKTRACE --\n"); +void idt_register_handler(uint8_t vector, void *isr) { + if (vector <= 16) + ioapic_redir_irq(bootstrap_lapic_id, vector + 32, vector, false); - // First print the current instruction pointer from the interrupt frame - if (regs->rip) { - fatal("* %p (current)\n", regs->rip); - } - - uint64_t *frame = (uint64_t*)regs->rbp; - if (!frame || (uint64_t)frame < 0xffffffff80000000) { - fatal("No further stack frames available\n"); - return; - } - - // Frame format in x86_64: - // [rbp] -> previous rbp - // [rbp+8] -> return address - int depth = 0; - while (frame && depth < 16) { // Limit depth to avoid infinite loops - // Validate both frame and return address pointers - uint64_t *ret_addr_ptr = frame + 1; - if ((uint64_t)ret_addr_ptr < 0xffffffff80000000) { - break; - } - - uint64_t ret_addr = *ret_addr_ptr; - if (ret_addr < 0xffffffff80000000 || ret_addr > 0xfffffffffffff000) { - break; - } - - fatal("* %p\n", ret_addr); - - uint64_t next_rbp = *frame; - if (next_rbp < 0xffffffff80000000 || next_rbp > 0xfffffffffffff000) { - break; - } - - frame = (uint64_t*)next_rbp; - depth++; - } - fatal("\n"); + __idt_external_handlers[vector] = isr; + __idt_vectors[vector <= 16 ? vector + 32 : vector] = vector <= 16 ? VT_HWI : VT_SWI; } void idt_interrupt_handler(registers_t *regs) { + if (__idt_vectors[regs->int_no] == VT_SPURIOUS || __idt_vectors[regs->int_no] == VT_NONE) + return; + + if (regs->int_no < 32) { fatal("Kernel panic: CPU exception %d\n", regs->int_no); fatal("rax: %p, rbx: %p, rbp: %p, rdx\n", regs->rax, regs->rbx, regs->rbp, regs->rdx); fatal("rdi: %p, rsi: %p, rcx: %p\n", regs->rdi, regs->rsi, regs->rcx); @@ -71,39 +44,65 @@ void idt_interrupt_handler(registers_t *regs) { fatal("r14: %p, r15: %p\n", regs->r14, regs->r15); fatal("rip: %p, cs: %p, ss: %p\n", regs->rip, regs->cs, regs->ss); fatal("rflags: %p, err: %d, rsp: %p\n", regs->rflags, regs->err_code, regs->rsp); - __panic_display_bt(regs); hcf(); + } + + int vec = regs->int_no; + if (vec >= 32 && vec < 48) + vec -= 32; + + if (__idt_vectors[regs->int_no] == VT_HWI) { + interrupt_handler i = __idt_external_handlers[vec]; + i(regs); + } else if (__idt_vectors[regs->int_no] == VT_SWI) { + interrupt_handler i = __idt_external_handlers[regs->int_no]; + i(regs); + } + + lapic_eoi(); } void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) { - idt_entry_t* descriptor = &idt[vector]; + idt_entry_t* descriptor = &idt[vector]; - descriptor->isr_low = (uint64_t)isr & 0xFFFF; - descriptor->kernel_cs = 0x08; - descriptor->ist = 0; - descriptor->attributes = flags; - descriptor->isr_mid = ((uint64_t)isr >> 16) & 0xFFFF; - descriptor->isr_high = ((uint64_t)isr >> 32) & 0xFFFFFFFF; - descriptor->reserved = 0; + descriptor->isr_low = (uint64_t)isr & 0xFFFF; + descriptor->kernel_cs = 0x08; + descriptor->ist = 0; + descriptor->attributes = flags; + descriptor->isr_mid = ((uint64_t)isr >> 16) & 0xFFFF; + descriptor->isr_high = ((uint64_t)isr >> 32) & 0xFFFFFFFF; + descriptor->reserved = 0; } -static bool vectors[32]; extern void* isr_stub_table[]; void idt_init() { - idtr.base = (uintptr_t)&idt[0]; - idtr.limit = (uint16_t)sizeof(idt_entry_t) * 32 - 1; + idtr.base = (uintptr_t)&idt[0]; + idtr.limit = (uint16_t)sizeof(idt_entry_t) * 256 - 1; - for (uint8_t vector = 0; vector < 32; vector++) { - idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); - vectors[vector] = true; - } + for (uint8_t vector = 0; vector < 32; vector++) { + idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); + __idt_vectors[vector] = VT_EXCEPTION; + } + trace("idt: Exception vectors has been set!\n"); - __asm__ volatile ("lidt %0" : : "m"(idtr)); - __asm__ volatile ("sti"); + for (uint8_t vector = 32; vector < 48; vector++) { + idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); + __idt_vectors[vector] = VT_HWI; + } + trace("idt: Hardware interrupt vectors has been set!\n"); + for (uint16_t vector = 48; vector < 256; vector++) { + idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); + __idt_vectors[vector] = VT_NONE; + } + __idt_vectors[IDT_SPURIOUS_INT] = VT_SPURIOUS; + trace("idt: Spurious interrupt vector has been set!\n"); - trace("arch: IDT loaded successfully\n"); + __asm__ volatile ("lidt %0" : : "m"(idtr)); + __asm__ volatile ("sti"); + + trace("arch: IDT loaded successfully\n"); } #endif \ No newline at end of file diff --git a/kernel/src/arch/x86_64/idt.h b/kernel/src/arch/x86_64/idt.h index e66648e..7c8707c 100644 --- a/kernel/src/arch/x86_64/idt.h +++ b/kernel/src/arch/x86_64/idt.h @@ -8,6 +8,14 @@ #include +#define VT_NONE 0 +#define VT_EXCEPTION 1 +#define VT_HWI 2 +#define VT_SWI 3 +#define VT_SPURIOUS 4 + +#define IDT_SPURIOUS_INT 0xFF + typedef struct { uint64_t r15; uint64_t r14; @@ -33,6 +41,8 @@ typedef struct { uint64_t ss; } __attribute__((packed)) registers_t; +typedef void(*interrupt_handler)(registers_t*); + typedef struct { uint16_t isr_low; uint16_t kernel_cs; @@ -48,4 +58,5 @@ typedef struct { uint64_t base; } __attribute__((packed)) idtr_t; +void idt_register_handler(uint8_t vector, void *isr); void idt_init(void); \ No newline at end of file diff --git a/kernel/src/arch/x86_64/io.h b/kernel/src/arch/x86_64/io.h new file mode 100644 index 0000000..4892c8e --- /dev/null +++ b/kernel/src/arch/x86_64/io.h @@ -0,0 +1,23 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * io.h - x86_64 I/O functions + */ + +#pragma once + +#include + +inline void outb(uint16_t port, uint8_t val) { + __asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); +} + +inline uint8_t inb(uint16_t port) { + uint8_t ret; + __asm__ volatile ( "inb %w1, %b0" + : "=a"(ret) + : "Nd"(port) + : "memory"); + return ret; +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/pit.c b/kernel/src/arch/x86_64/pit.c new file mode 100644 index 0000000..d61cd7b --- /dev/null +++ b/kernel/src/arch/x86_64/pit.c @@ -0,0 +1,30 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * pit.c - x86_64 Programmable Interval Timer implementation. + */ +#if defined(__x86_64__) + +#include +#include +#include + +void pit_handler(registers_t *reg) { + trace("pit: Interrupt!\n"); +} + +void cpu_init_timer() { + outb(0x43, 0x36); + + uint16_t div = (uint16_t)(1193180 / 1000); + + // Since the PIT uses 8-bit IO operations, + // we need to split div in 2. + outb(0x40, (uint8_t)div); + outb(0x40, (uint8_t)(div >> 8)); + + idt_register_handler(0, pit_handler); +} + +#endif \ No newline at end of file diff --git a/kernel/src/arch/x86_64/smp.c b/kernel/src/arch/x86_64/smp.c new file mode 100644 index 0000000..3253f7f --- /dev/null +++ b/kernel/src/arch/x86_64/smp.c @@ -0,0 +1,17 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * smp.c - x86_64 Symetric Multiprocessing implementation + */ + +#include +#include +#include + +uint32_t bootstrap_lapic_id; + +void cpu_init_smp() { + struct limine_mp_response *smp = limine_get_smp(); + bootstrap_lapic_id = smp->bsp_lapic_id; +} diff --git a/kernel/src/arch/x86_64/smp.h b/kernel/src/arch/x86_64/smp.h new file mode 100644 index 0000000..06c3422 --- /dev/null +++ b/kernel/src/arch/x86_64/smp.h @@ -0,0 +1,12 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * smp.c - x86_64 Symetric Multiprocessing definitions + */ + + #pragma once + +#include + +extern uint32_t bootstrap_lapic_id; \ No newline at end of file diff --git a/kernel/src/boot/limine.c b/kernel/src/boot/limine.c index d936ffd..151c9d8 100644 --- a/kernel/src/boot/limine.c +++ b/kernel/src/boot/limine.c @@ -69,6 +69,12 @@ static volatile struct limine_rsdp_request rsdp_req = { .revision = 0 }; +__attribute__((used, section(".limine_requests"))) +static volatile struct limine_mp_request smp_req = { + .id = LIMINE_MP_REQUEST, + .revision = 0 +}; + __attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER; @@ -116,4 +122,5 @@ uint64_t limine_get_hhdm_offset() { return hhdm_req.response->offset; } uint64_t limine_get_kernel_vaddr() { return kaddr_req.response->virtual_base; } uint64_t limine_get_kernel_paddr() { return kaddr_req.response->physical_base; } uint64_t limine_get_kernel_ehdr_addr() { return (uint64_t)execfile_req.response->executable_file->address; } -uint64_t limine_get_rsdp() { return rsdp_req.response->address + limine_get_hhdm_offset(); } \ No newline at end of file +uint64_t limine_get_rsdp() { return rsdp_req.response->address + limine_get_hhdm_offset(); } +struct limine_mp_response *limine_get_smp() { return smp_req.response; } \ No newline at end of file diff --git a/kernel/src/boot/limine.h b/kernel/src/boot/limine.h index f264a30..4c5522d 100644 --- a/kernel/src/boot/limine.h +++ b/kernel/src/boot/limine.h @@ -35,4 +35,5 @@ uint64_t limine_get_hhdm_offset(); uint64_t limine_get_kernel_vaddr(); uint64_t limine_get_kernel_paddr(); uint64_t limine_get_kernel_ehdr_addr(); -uint64_t limine_get_rsdp(); \ No newline at end of file +uint64_t limine_get_rsdp(); +struct limine_mp_response *limine_get_smp(); \ No newline at end of file diff --git a/kernel/src/dev/ioapic.c b/kernel/src/dev/ioapic.c new file mode 100644 index 0000000..831c455 --- /dev/null +++ b/kernel/src/dev/ioapic.c @@ -0,0 +1,87 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * ioapic.c - I/O APIC implementation. + */ + +#include +#include + +#include +#include +#include +#include + +static void __ioapic_write(acpi_madt_ioapic_t *ioapic, uint32_t reg, uint32_t val) { + *(volatile uint32_t *)(higher_half(ioapic->ioapic_addr)) = reg; + *(volatile uint32_t *)(higher_half(ioapic->ioapic_addr+0x10)) = val; +} +static uint32_t __ioapic_read(acpi_madt_ioapic_t *ioapic, uint32_t reg) { + *(volatile uint32_t *)(higher_half(ioapic->ioapic_addr)) = reg; + return *(volatile uint32_t *)(higher_half(ioapic->ioapic_addr+0x10)); +} + +void ioapic_init() { + acpi_madt_ioapic_t *ioapic = madt_ioapic_list[0]; + + uint32_t value = __ioapic_read(ioapic, IOAPIC_VERSION); + uint32_t count = (value >> 16) & 0xFF; + + for (uint8_t i = 0; i <= count; ++i) { + __ioapic_write(ioapic, + IOAPIC_REDTBL+2 * i, + 0x00010000 | (32 + i)); + __ioapic_write(ioapic, + IOAPIC_REDTBL + 2 * i + 1, 0); + } + + trace("ioapic: Initialized\n"); +} + +uint32_t ioapic_gsi_count(acpi_madt_ioapic_t* ioapic) { + return (__ioapic_read(ioapic, 1) & 0xff0000) >> 16; +} + +acpi_madt_ioapic_t *ioapic_get_gsi(uint32_t gsi) { + for (uint32_t i = 0; i < madt_ioapic_len; i++) { + acpi_madt_ioapic_t* ioapic = madt_ioapic_list[i]; + if (ioapic->gsi_base <= gsi && ioapic->gsi_base + ioapic_gsi_count(ioapic) > gsi) + return ioapic; + } + return NULL; +} + +void ioapic_redirect_gsi(uint32_t lapic_id, uint8_t vec, uint32_t gsi, uint16_t flags, bool mask) { + acpi_madt_ioapic_t* ioapic = ioapic_get_gsi(gsi); + + uint64_t redirect = vec; + + if ((flags & (1 << 1)) != 0) { + redirect |= (1 << 13); + } + + if ((flags & (1 << 3)) != 0) { + redirect |= (1 << 15); + } + + if (mask) redirect |= (1 << 16); + else redirect &= ~(1 << 16); + + redirect |= (uint64_t)lapic_id << 56; + + uint32_t redtbl = (gsi - ioapic->gsi_base) * 2 + 16; + __ioapic_write(ioapic, redtbl, (uint32_t)redirect); + __ioapic_write(ioapic, redtbl + 1, (uint32_t)(redirect >> 32)); +} + +void ioapic_redir_irq(uint32_t lapic_id, uint8_t vec, uint8_t irq, bool mask) { + uint8_t idx = 0; + acpi_madt_iso_t* iso = NULL; + + for (idx = 0; idx < madt_iso_len; ++idx) { + iso = madt_iso_list[idx]; + if (iso->source == irq) { ioapic_redirect_gsi(lapic_id, vec, iso->gsi, iso->flags, mask); return; } + } + ioapic_redirect_gsi(lapic_id, vec, irq, 0, mask); +} \ No newline at end of file diff --git a/kernel/src/dev/ioapic.h b/kernel/src/dev/ioapic.h new file mode 100644 index 0000000..df39a1f --- /dev/null +++ b/kernel/src/dev/ioapic.h @@ -0,0 +1,17 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * ioapic.c - I/O APIC definitions. + */ + +#pragma once + +#include +#include + +#define IOAPIC_VERSION 0x1 +#define IOAPIC_REDTBL 0x10 + +void ioapic_init(); +void ioapic_redir_irq(uint32_t lapic_id, uint8_t vec, uint8_t irq, bool mask); \ No newline at end of file diff --git a/kernel/src/dev/lapic.c b/kernel/src/dev/lapic.c new file mode 100644 index 0000000..50bf04e --- /dev/null +++ b/kernel/src/dev/lapic.c @@ -0,0 +1,33 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * lapic.c - Local APIC implementation. + */ + +#include "dev/lapic.h" +#include "arch/x86_64/idt.h" +#include "lib/log.h" +#include "mm/pmm.h" +#include + +static uint64_t __lapic_pbase = 0xfee00000; +static uint64_t __lapic_vbase; + +static void __lapic_write(uint32_t reg, uint32_t val) { *(volatile uint32_t *)(__lapic_vbase + reg) = val; } +static uint32_t __lapic_read(uint32_t reg) { return *(volatile uint32_t *)(__lapic_vbase + reg); } +static void __lapic_write_svr(uint32_t reg, lapic_svr_entry e) { *(volatile uint32_t *)(__lapic_vbase + reg) = *(uint32_t*)&e; } + +void lapic_init() { + __lapic_vbase = higher_half(__lapic_pbase); + __lapic_write_svr(LAPIC_SVR, (lapic_svr_entry){ .swenabled = true, .vec = IDT_SPURIOUS_INT }); + trace("lapic: Initialized\n"); +} + +void lapic_eoi() { + __lapic_write(LAPIC_EOI, 0x0); +} + +uint32_t lapic_get_id() { + return __lapic_read(LAPIC_ID) >> LAPIC_ICDESTSHIFT; +} \ No newline at end of file diff --git a/kernel/src/dev/lapic.h b/kernel/src/dev/lapic.h new file mode 100644 index 0000000..5697054 --- /dev/null +++ b/kernel/src/dev/lapic.h @@ -0,0 +1,26 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * lapic.h - Local APIC definitions. + */ + +#pragma once + +#include +#include + +#define LAPIC_ID 0x20 +#define LAPIC_SVR 0xF0 +#define LAPIC_EOI 0xB0 + +#define LAPIC_ICDESTSHIFT 24 + +typedef struct { + uint8_t vec; + bool swenabled; +} lapic_svr_entry; + +void lapic_init(); +void lapic_eoi(); +uint32_t lapic_get_id(); \ No newline at end of file diff --git a/kernel/src/main.c b/kernel/src/main.c index daa02d2..d34e903 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -19,6 +20,8 @@ #include #include #include +#include "dev/ioapic.h" +#include "dev/lapic.h" #include "mm/paging.h" #include "mm/vma.h" @@ -37,7 +40,14 @@ void kmain(void) { pg_init(); acpi_init(); + madt_init(); + lapic_init(); + ioapic_init(); + cpu_init_smp(); + cpu_init_timer(); + while (1) + ;; // We're done, just hang... for now. - hcf(); + //hcf(); } diff --git a/kernel/src/mm/pmm.md b/kernel/src/mm/pmm.md new file mode 100644 index 0000000..e69de29 diff --git a/kernel/src/mm/vmm.c b/kernel/src/mm/vmm.c new file mode 100644 index 0000000..e69de29