From 01e2f6a3d857d2a8a6b6e6e4bc455116646f4856 Mon Sep 17 00:00:00 2001 From: Kevin Alavik Date: Sat, 31 May 2025 18:19:56 +0200 Subject: [PATCH] feat/kernel: Did some lapic stuff --- kernel/GNUmakefile | 4 +- kernel/src/arch/smp.c | 57 +++++++++++++++-------------- kernel/src/emk.c | 38 +++++++++++++------ kernel/src/mm/vmm.c | 2 + kernel/src/sys/acpi.c | 73 ++++++++++++++++++++++++------------- kernel/src/sys/apic/lapic.c | 72 ++++++++++++++++++++++++++---------- kernel/src/sys/apic/lapic.h | 38 ++++++++++++++++--- 7 files changed, 193 insertions(+), 91 deletions(-) diff --git a/kernel/GNUmakefile b/kernel/GNUmakefile index de5ae61..7c7ae95 100644 --- a/kernel/GNUmakefile +++ b/kernel/GNUmakefile @@ -36,7 +36,7 @@ ifeq ($(BUILD_MODE),release) -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \ -mcmodel=kernel -fno-unwind-tables -fno-asynchronous-unwind-tables \ -s -Wno-unused-variable -DBUILD_MODE=\"release\" - NASMFLAGS := + NASMFLAGS := -f elf64 -F dwarf -g LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \ -T linker.ld -Wl,-m,elf_x86_64 -Wl,--strip-all else @@ -45,7 +45,7 @@ else -ffunction-sections -fdata-sections -m64 -march=x86-64 \ -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \ -mcmodel=kernel -Wno-unused-variable -DBUILD_MODE=\"dev\" - NASMFLAGS := -F dwarf -g + NASMFLAGS := -f elf64 -F dwarf -g LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \ -T linker.ld -Wl,-m,elf_x86_64 endif diff --git a/kernel/src/arch/smp.c b/kernel/src/arch/smp.c index a89ed0d..f121d07 100644 --- a/kernel/src/arch/smp.c +++ b/kernel/src/arch/smp.c @@ -10,20 +10,22 @@ #include #include #include +#include +#include +#include +#include #define MAX_CPUS 256 #define MSR_GS_BASE 0xC0000101 uint32_t cpu_count = 0; uint32_t bootstrap_lapic_id = 0; - atomic_uint started_cpus = 0; static cpu_local_t cpu_locals[MAX_CPUS]; cpu_local_t *get_cpu_local(void) { - cpu_local_t *cpu = (cpu_local_t *)rdmsr(MSR_GS_BASE); - return cpu; + return (cpu_local_t *)rdmsr(MSR_GS_BASE); } static inline void set_cpu_local(cpu_local_t *cpu) @@ -46,29 +48,32 @@ void smp_entry(struct limine_mp_info *smp_info) } if (!cpu) - kpanic(NULL, "CPU with LAPIC ID %u not found in cpu_locals!", lapic_id); + kpanic(NULL, "CPU with LAPIC ID %u not found!", lapic_id); set_cpu_local(cpu); - atomic_fetch_add(&started_cpus, 1); - log_early("CPU %d is up", cpu->cpu_index); + /* Setup core */ + pmset(kernel_pagemap); + lapic_enable(); + + atomic_fetch_add(&started_cpus, 1); + log_early("CPU %d (LAPIC ID %u) is up", cpu->cpu_index, lapic_id); cpu->ready = true; - while (1) - __asm__ volatile("hlt"); + hlt(); } void smp_init(void) { bootstrap_lapic_id = mp_response->bsp_lapic_id; cpu_count = mp_response->cpu_count; - log_early("%u CPUs detected", cpu_count); + lapic_enable(); + for (uint32_t i = 0; i < cpu_count; i++) { struct limine_mp_info *info = mp_response->cpus[i]; - memset(&cpu_locals[i], 0, sizeof(cpu_local_t)); cpu_locals[i].lapic_id = info->lapic_id; cpu_locals[i].cpu_index = i; @@ -77,33 +82,31 @@ void smp_init(void) if (info->lapic_id == bootstrap_lapic_id) { set_cpu_local(&cpu_locals[i]); - log_early("CPU %u is the bootstrap processor", i); - atomic_fetch_add(&started_cpus, 1); cpu_locals[i].ready = true; + atomic_fetch_add(&started_cpus, 1); + log_early("CPU %u (LAPIC ID %u) is the bootstrap processor", i, info->lapic_id); } else { __atomic_store_n(&info->goto_address, smp_entry, __ATOMIC_SEQ_CST); - while (atomic_load(&started_cpus) < (i + 1)) - __asm__ volatile("pause"); - } - } - /* trick to wait for all procs to be ready */ - bool all_ready = false; - while (!all_ready) - { - all_ready = true; - for (uint32_t i = 0; i < cpu_count; i++) - { + volatile uint64_t timeout = 0; + while (!cpu_locals[i].ready) + { + __asm__ volatile("pause"); + timeout++; + } + if (!cpu_locals[i].ready) { - all_ready = false; - __asm__ volatile("pause"); - break; + log_early("warning: CPU %u (LAPIC ID %u) failed to start", i, info->lapic_id); + } + else + { + log_early("CPU %u (LAPIC ID %u) started successfully", i, info->lapic_id); } } } log_early("All CPUs are ready"); -} +} \ No newline at end of file diff --git a/kernel/src/emk.c b/kernel/src/emk.c index 3eabc8e..c5a8ea6 100644 --- a/kernel/src/emk.c +++ b/kernel/src/emk.c @@ -43,6 +43,12 @@ __attribute__((used, section(".limine_requests"))) static volatile struct limine __attribute__((used, section(".limine_requests"))) static volatile struct limine_mp_request mp_request = { .revision = 0, .id = LIMINE_MP_REQUEST}; +__attribute__((used, section(".limine_requests"))) static volatile struct limine_bootloader_info_request binfo_request = { + .revision = 0, + .id = LIMINE_BOOTLOADER_INFO_REQUEST}; +__attribute__((used, section(".limine_requests"))) static volatile struct limine_firmware_type_request firmware_request = { + .revision = 0, + .id = LIMINE_FIRMWARE_TYPE_REQUEST}; __attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER; __attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER; @@ -87,8 +93,18 @@ void emk_entry(void) /* Just do nothing */ } + if (!binfo_request.response) + { + kpanic(NULL, "Failed to get bootloader info"); + } + + if (!firmware_request.response) + { + kpanic(NULL, "Failed to get firmware type"); + } + log_early("Experimental Micro Kernel (EMK) 1.0 Copyright (c) 2025 Piraterna"); - log_early("Compiled at %s %s, emk1.0-%s, flanterm support: %s", __TIME__, __DATE__, BUILD_MODE, FLANTERM_SUPPORT ? "yes" : "no"); + log_early("Compiled at %s %s, emk1.0-%s, flanterm support: %s, bootloader: %s v%s, firmware: %s", __TIME__, __DATE__, BUILD_MODE, FLANTERM_SUPPORT ? "yes" : "no", binfo_request.response->name, binfo_request.response->version, (firmware_request.response->firmware_type == LIMINE_FIRMWARE_TYPE_UEFI64 || firmware_request.response->firmware_type == LIMINE_FIRMWARE_TYPE_UEFI32) ? "UEFI" : "BIOS"); log_early("%s", LOG_SEPARATOR); if (!LIMINE_BASE_REVISION_SUPPORTED) @@ -160,15 +176,6 @@ void emk_entry(void) *c = 32; kfree(c); - /* Setup SMP */ - if (!mp_request.response) - { - kpanic(NULL, "Failed to get MP request"); - } - - mp_response = mp_request.response; - smp_init(); - /* Setup ACPI */ rsdp_response = rsdp_request.response; if (!rsdp_response) @@ -182,9 +189,18 @@ void emk_entry(void) outb(0x21, 0xff); outb(0xA1, 0xff); - /* Setup APIC */ + /* Init APIC (LAPIC for now) */ lapic_init(); + /* Setup SMP */ + if (!mp_request.response) + { + kpanic(NULL, "Failed to get MP request"); + } + + mp_response = mp_request.response; + smp_init(); + /* Finished */ log_early("%s", LOG_SEPARATOR); log_early("Finished initializing EMK v1.0, took ? seconds"); /* Still not usermode, so keep using log_early */ diff --git a/kernel/src/mm/vmm.c b/kernel/src/mm/vmm.c index afb0f2c..cf26189 100644 --- a/kernel/src/mm/vmm.c +++ b/kernel/src/mm/vmm.c @@ -135,6 +135,7 @@ void *vallocat(vctx_t *ctx, size_t pages, uint64_t flags, uint64_t phys) vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags); } + memset((void *)new->start, PAGE_SIZE * pages, 0); return (void *)new->start; } region = region->next; @@ -160,6 +161,7 @@ void *vallocat(vctx_t *ctx, size_t pages, uint64_t flags, uint64_t phys) vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags); } + memset((void *)new->start, PAGE_SIZE * pages, 0); return (void *)new->start; } diff --git a/kernel/src/sys/acpi.c b/kernel/src/sys/acpi.c index 8e38375..425a70d 100644 --- a/kernel/src/sys/acpi.c +++ b/kernel/src/sys/acpi.c @@ -1,14 +1,28 @@ -/* EMK 1.0 Copyright (c) 2025 Piraterna */ #include #include #include #include #include #include +#include static int acpi_uses_xsdt = 0; static void *acpi_rsdt_ptr = NULL; +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"); + return NULL; + } + + uint32_t full_size = tmp->length; + uint32_t page_count = (full_size + 0xFFF) / 0x1000; + return vallocat(kvm_ctx, page_count, VALLOC_RW, phys); +} + void acpi_init(void) { if (!rsdp_response || !rsdp_response->address) @@ -18,47 +32,54 @@ void acpi_init(void) acpi_rsdp_t *rsdp = (acpi_rsdp_t *)vallocat(kvm_ctx, 1, VALLOC_RW, rsdp_response->address); if (memcmp(rsdp->signature, "RSD PTR", 7) != 0) - kpanic(NULL, "Invalid RSDP signature!"); + kpanic(NULL, "Invalid RSDP signature! EMK depends on APIC 1.0 or higher"); - if (rsdp->revision != 0) + if (rsdp->revision >= 2) { acpi_uses_xsdt = 1; acpi_xsdp_t *xsdp = (acpi_xsdp_t *)rsdp; - acpi_rsdt_ptr = (acpi_xsdt_t *)HIGHER_HALF(xsdp->xsdt_address); - log_early("XSDT found at %p", acpi_rsdt_ptr); - return; + acpi_rsdt_ptr = acpi_vtable(xsdp->xsdt_address); + log_early("Using XSDT"); + } + else + { + acpi_uses_xsdt = 0; + acpi_rsdt_ptr = acpi_vtable(rsdp->rsdt_address); + log_early("Using RSDT"); } - - acpi_rsdt_ptr = (acpi_rsdt_t *)HIGHER_HALF(rsdp->rsdt_address); - log_early("RSDT found at %p", acpi_rsdt_ptr); } void *acpi_find_table(const char *name) { - if (!acpi_uses_xsdt) + if (!acpi_rsdt_ptr || !name) + return NULL; + + if (acpi_uses_xsdt) + { + acpi_xsdt_t *xsdt = (acpi_xsdt_t *)acpi_rsdt_ptr; + uint32_t entries = (xsdt->sdt.length - sizeof(xsdt->sdt)) / 8; + + for (uint32_t i = 0; i < entries; i++) + { + uint64_t phys_addr = ((uint64_t *)xsdt->table)[i]; + acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)acpi_vtable(phys_addr); + if (!memcmp(sdt->signature, name, 4)) + return sdt; + } + } + else { acpi_rsdt_t *rsdt = (acpi_rsdt_t *)acpi_rsdt_ptr; uint32_t entries = (rsdt->sdt.length - sizeof(rsdt->sdt)) / 4; + for (uint32_t i = 0; i < entries; i++) { - acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)HIGHER_HALF(*((uint32_t *)rsdt->table + i)); + uint32_t phys_addr = ((uint32_t *)rsdt->table)[i]; + acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)acpi_vtable(phys_addr); if (!memcmp(sdt->signature, name, 4)) - return (void *)sdt; - } - return NULL; - } - acpi_xsdt_t *xsdt = (acpi_xsdt_t *)acpi_rsdt_ptr; - log_early("XSDT address: %p", xsdt); - uint32_t entries = (xsdt->sdt.length - sizeof(xsdt->sdt)) / 8; - - for (uint32_t i = 0; i < entries; i++) - { - acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)HIGHER_HALF(*((uint64_t *)xsdt->table + i)); - if (!memcmp(sdt->signature, name, 4)) - { - return (void *)sdt; + return sdt; } } return NULL; -} \ No newline at end of file +} diff --git a/kernel/src/sys/apic/lapic.c b/kernel/src/sys/apic/lapic.c index f0c58bd..a71ccca 100644 --- a/kernel/src/sys/apic/lapic.c +++ b/kernel/src/sys/apic/lapic.c @@ -1,43 +1,75 @@ /* EMK 1.0 Copyright (c) 2025 Piraterna */ #include #include -#include +#include #include -#include #include +#include atomic_uintptr_t lapic_msr = 0; -volatile uint64_t *lapic_base = 0; +atomic_uintptr_t lapic_base_atomic = 0; + +#define LAPIC_BASE ((volatile uint32_t *)atomic_load(&lapic_base_atomic)) void lapic_write(uint32_t offset, uint32_t value) { - if (!lapic_base) + volatile uint32_t *base = LAPIC_BASE; + if (!base) { - log_early("warning: LAPIC not initialized!"); - return; + log_early("error: LAPIC not initialized!"); + kpanic(NULL, "LAPIC write attempted before initialization"); } - - volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset); - atomic_store((_Atomic uint32_t *)reg, value); + base[offset / 4] = value; } uint32_t lapic_read(uint32_t offset) { - if (!lapic_base) + volatile uint32_t *base = LAPIC_BASE; + if (!base) { - log_early("warning: LAPIC not initialized!"); + log_early("error: LAPIC not initialized!"); return 0; } - - volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset); - return atomic_load((_Atomic uint32_t *)reg); + return base[offset / 4]; } -void lapic_init() +void lapic_init(void) { - uint64_t msr = rdmsr(LAPIC_BASE); + uint64_t msr = rdmsr(LAPIC_BASE_MSR); + msr |= (1 << 11); // Set global LAPIC enable bit + wrmsr(LAPIC_BASE_MSR, msr); atomic_store(&lapic_msr, msr); - lapic_base = (volatile uint64_t *)(msr & ~(0xffff)); - atomic_store(&lapic_addr, (uint64_t)lapic_base); - log_early("New LAPIC base: 0x%lx", lapic_base); -} \ No newline at end of file + + uint64_t phys_addr = msr & ~0xFFFULL; + uint64_t virt_addr = (uint64_t)HIGHER_HALF(phys_addr); + + int ret = vmap(pmget(), virt_addr, phys_addr, VMM_PRESENT | VMM_WRITE | VMM_NX); + if (ret != 0) + { + log_early("error: Failed to map LAPIC base 0x%lx to 0x%lx", phys_addr, virt_addr); + kpanic(NULL, "LAPIC mapping failed"); + } + + atomic_store(&lapic_base_atomic, virt_addr); + atomic_store(&lapic_addr, virt_addr); +} + +void lapic_enable(void) +{ + volatile uint32_t *base = LAPIC_BASE; + if (!base) + { + log_early("warning: lapic_enable called before lapic_init"); + return; + } + + uint32_t svr = lapic_read(LAPIC_SVR); + svr |= (1 << 8); // Enable APIC + svr &= ~(1 << 9); // Disable focus processor checking + svr = (svr & ~0xFF) | 0xFF; // Set spurious interrupt vector to 0xFF + + lapic_write(LAPIC_SVR, svr); + lapic_write(LAPIC_TPR, 0); + uint32_t id = lapic_read(LAPIC_ID) >> 24; + log_early("LAPIC enabled and initialized for CPU %u", id); +} diff --git a/kernel/src/sys/apic/lapic.h b/kernel/src/sys/apic/lapic.h index 2852b8f..d0d9a77 100644 --- a/kernel/src/sys/apic/lapic.h +++ b/kernel/src/sys/apic/lapic.h @@ -4,13 +4,41 @@ #include -#define LAPIC_BASE 0x1b -#define LAPIC_REGOFF_LAPICID 0x20 -#define LAPIC_REGOFF_EOI 0xB0 -#define LAPIC_REGOFF_SPIV 0xF0 +#define LAPIC_BASE_MSR 0x1B + +// Local APIC Registers +#define LAPIC_ID 0x0020 // Local APIC ID +#define LAPIC_VER 0x0030 // Local APIC Version +#define LAPIC_TPR 0x0080 // Task Priority +#define LAPIC_EOI 0x00B0 // End of Interrupt +#define LAPIC_SVR 0x00F0 // Spurious Interrupt Vector +#define LAPIC_ESR 0x0280 // Error Status +#define LAPIC_ICRLO 0x0300 // Interrupt Command (Low) +#define LAPIC_ICRHI 0x0310 // Interrupt Command (High) +#define LAPIC_TIMER 0x0320 // LVT Timer +#define LAPIC_TICR 0x0380 // Timer Initial Count +#define LAPIC_TDCR 0x03E0 // Timer Divide Configuration + +// ICR Fields +#define ICR_FIXED 0x00000000 +#define ICR_INIT 0x00000500 +#define ICR_STARTUP 0x00000600 +#define ICR_PHYSICAL 0x00000000 +#define ICR_ASSERT 0x00004000 +#define ICR_EDGE 0x00000000 +#define ICR_NO_SHORTHAND 0x00000000 +#define ICR_SEND_PENDING 0x00001000 +#define ICR_DESTINATION_SHIFT 24 + +// 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 lapic_init(void); +void lapic_enable(void); #endif // LAPIC_H \ No newline at end of file