1
0
Fork 0

feat/kernel: Did some lapic stuff

This commit is contained in:
Kevin Alavik 2025-05-31 18:19:56 +02:00
parent d5371bcbb2
commit 01e2f6a3d8
Signed by: cmpsb
GPG key ID: 10D1CC0526FDC6D7
7 changed files with 193 additions and 91 deletions

View file

@ -36,7 +36,7 @@ ifeq ($(BUILD_MODE),release)
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \ -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
-mcmodel=kernel -fno-unwind-tables -fno-asynchronous-unwind-tables \ -mcmodel=kernel -fno-unwind-tables -fno-asynchronous-unwind-tables \
-s -Wno-unused-variable -DBUILD_MODE=\"release\" -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 \ LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
-T linker.ld -Wl,-m,elf_x86_64 -Wl,--strip-all -T linker.ld -Wl,-m,elf_x86_64 -Wl,--strip-all
else else
@ -45,7 +45,7 @@ else
-ffunction-sections -fdata-sections -m64 -march=x86-64 \ -ffunction-sections -fdata-sections -m64 -march=x86-64 \
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \ -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
-mcmodel=kernel -Wno-unused-variable -DBUILD_MODE=\"dev\" -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 \ LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
-T linker.ld -Wl,-m,elf_x86_64 -T linker.ld -Wl,-m,elf_x86_64
endif endif

View file

@ -10,20 +10,22 @@
#include <mm/heap.h> #include <mm/heap.h>
#include <arch/io.h> #include <arch/io.h>
#include <sys/apic/lapic.h> #include <sys/apic/lapic.h>
#include <sys/acpi/madt.h>
#include <arch/paging.h>
#include <util/align.h>
#include <mm/pmm.h>
#define MAX_CPUS 256 #define MAX_CPUS 256
#define MSR_GS_BASE 0xC0000101 #define MSR_GS_BASE 0xC0000101
uint32_t cpu_count = 0; uint32_t cpu_count = 0;
uint32_t bootstrap_lapic_id = 0; uint32_t bootstrap_lapic_id = 0;
atomic_uint started_cpus = 0; atomic_uint started_cpus = 0;
static cpu_local_t cpu_locals[MAX_CPUS]; static cpu_local_t cpu_locals[MAX_CPUS];
cpu_local_t *get_cpu_local(void) cpu_local_t *get_cpu_local(void)
{ {
cpu_local_t *cpu = (cpu_local_t *)rdmsr(MSR_GS_BASE); return (cpu_local_t *)rdmsr(MSR_GS_BASE);
return cpu;
} }
static inline void set_cpu_local(cpu_local_t *cpu) 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) 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); 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; cpu->ready = true;
while (1) hlt();
__asm__ volatile("hlt");
} }
void smp_init(void) void smp_init(void)
{ {
bootstrap_lapic_id = mp_response->bsp_lapic_id; bootstrap_lapic_id = mp_response->bsp_lapic_id;
cpu_count = mp_response->cpu_count; cpu_count = mp_response->cpu_count;
log_early("%u CPUs detected", cpu_count); log_early("%u CPUs detected", cpu_count);
lapic_enable();
for (uint32_t i = 0; i < cpu_count; i++) for (uint32_t i = 0; i < cpu_count; i++)
{ {
struct limine_mp_info *info = mp_response->cpus[i]; struct limine_mp_info *info = mp_response->cpus[i];
memset(&cpu_locals[i], 0, sizeof(cpu_local_t)); memset(&cpu_locals[i], 0, sizeof(cpu_local_t));
cpu_locals[i].lapic_id = info->lapic_id; cpu_locals[i].lapic_id = info->lapic_id;
cpu_locals[i].cpu_index = i; cpu_locals[i].cpu_index = i;
@ -77,30 +82,28 @@ void smp_init(void)
if (info->lapic_id == bootstrap_lapic_id) if (info->lapic_id == bootstrap_lapic_id)
{ {
set_cpu_local(&cpu_locals[i]); 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; 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 else
{ {
__atomic_store_n(&info->goto_address, smp_entry, __ATOMIC_SEQ_CST); __atomic_store_n(&info->goto_address, smp_entry, __ATOMIC_SEQ_CST);
while (atomic_load(&started_cpus) < (i + 1))
volatile uint64_t timeout = 0;
while (!cpu_locals[i].ready)
{
__asm__ volatile("pause"); __asm__ volatile("pause");
} timeout++;
} }
/* 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++)
{
if (!cpu_locals[i].ready) if (!cpu_locals[i].ready)
{ {
all_ready = false; log_early("warning: CPU %u (LAPIC ID %u) failed to start", i, info->lapic_id);
__asm__ volatile("pause"); }
break; else
{
log_early("CPU %u (LAPIC ID %u) started successfully", i, info->lapic_id);
} }
} }
} }

View file

@ -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 = { __attribute__((used, section(".limine_requests"))) static volatile struct limine_mp_request mp_request = {
.revision = 0, .revision = 0,
.id = LIMINE_MP_REQUEST}; .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_start"))) static volatile LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER; __attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER;
@ -87,8 +93,18 @@ void emk_entry(void)
/* Just do nothing */ /* 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("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); log_early("%s", LOG_SEPARATOR);
if (!LIMINE_BASE_REVISION_SUPPORTED) if (!LIMINE_BASE_REVISION_SUPPORTED)
@ -160,15 +176,6 @@ void emk_entry(void)
*c = 32; *c = 32;
kfree(c); kfree(c);
/* Setup SMP */
if (!mp_request.response)
{
kpanic(NULL, "Failed to get MP request");
}
mp_response = mp_request.response;
smp_init();
/* Setup ACPI */ /* Setup ACPI */
rsdp_response = rsdp_request.response; rsdp_response = rsdp_request.response;
if (!rsdp_response) if (!rsdp_response)
@ -182,9 +189,18 @@ void emk_entry(void)
outb(0x21, 0xff); outb(0x21, 0xff);
outb(0xA1, 0xff); outb(0xA1, 0xff);
/* Setup APIC */ /* Init APIC (LAPIC for now) */
lapic_init(); lapic_init();
/* Setup SMP */
if (!mp_request.response)
{
kpanic(NULL, "Failed to get MP request");
}
mp_response = mp_request.response;
smp_init();
/* Finished */ /* Finished */
log_early("%s", LOG_SEPARATOR); log_early("%s", LOG_SEPARATOR);
log_early("Finished initializing EMK v1.0, took ? seconds"); /* Still not usermode, so keep using log_early */ log_early("Finished initializing EMK v1.0, took ? seconds"); /* Still not usermode, so keep using log_early */

View file

@ -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); vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags);
} }
memset((void *)new->start, PAGE_SIZE * pages, 0);
return (void *)new->start; return (void *)new->start;
} }
region = region->next; 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); vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags);
} }
memset((void *)new->start, PAGE_SIZE * pages, 0);
return (void *)new->start; return (void *)new->start;
} }

View file

@ -1,14 +1,28 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#include <sys/acpi.h> #include <sys/acpi.h>
#include <boot/emk.h> #include <boot/emk.h>
#include <lib/string.h> #include <lib/string.h>
#include <util/log.h> #include <util/log.h>
#include <sys/kpanic.h> #include <sys/kpanic.h>
#include <mm/vmm.h> #include <mm/vmm.h>
#include <mm/heap.h>
static int acpi_uses_xsdt = 0; static int acpi_uses_xsdt = 0;
static void *acpi_rsdt_ptr = NULL; 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) void acpi_init(void)
{ {
if (!rsdp_response || !rsdp_response->address) if (!rsdp_response || !rsdp_response->address)
@ -18,45 +32,52 @@ void acpi_init(void)
acpi_rsdp_t *rsdp = (acpi_rsdp_t *)vallocat(kvm_ctx, 1, VALLOC_RW, rsdp_response->address); acpi_rsdp_t *rsdp = (acpi_rsdp_t *)vallocat(kvm_ctx, 1, VALLOC_RW, rsdp_response->address);
if (memcmp(rsdp->signature, "RSD PTR", 7) != 0) 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_uses_xsdt = 1;
acpi_xsdp_t *xsdp = (acpi_xsdp_t *)rsdp; acpi_xsdp_t *xsdp = (acpi_xsdp_t *)rsdp;
acpi_rsdt_ptr = (acpi_xsdt_t *)HIGHER_HALF(xsdp->xsdt_address); acpi_rsdt_ptr = acpi_vtable(xsdp->xsdt_address);
log_early("XSDT found at %p", acpi_rsdt_ptr); log_early("Using XSDT");
return; }
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) void *acpi_find_table(const char *name)
{ {
if (!acpi_uses_xsdt) if (!acpi_rsdt_ptr || !name)
{
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));
if (!memcmp(sdt->signature, name, 4))
return (void *)sdt;
}
return NULL; return NULL;
}
if (acpi_uses_xsdt)
{
acpi_xsdt_t *xsdt = (acpi_xsdt_t *)acpi_rsdt_ptr; 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; uint32_t entries = (xsdt->sdt.length - sizeof(xsdt->sdt)) / 8;
for (uint32_t i = 0; i < entries; i++) for (uint32_t i = 0; i < entries; i++)
{ {
acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)HIGHER_HALF(*((uint64_t *)xsdt->table + 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)) if (!memcmp(sdt->signature, name, 4))
return sdt;
}
}
else
{ {
return (void *)sdt; 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++)
{
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 sdt;
} }
} }

View file

@ -1,43 +1,75 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */ /* EMK 1.0 Copyright (c) 2025 Piraterna */
#include <sys/apic/lapic.h> #include <sys/apic/lapic.h>
#include <arch/cpu.h> #include <arch/cpu.h>
#include <sys/acpi/madt.h> #include <arch/paging.h>
#include <util/log.h> #include <util/log.h>
#include <mm/vmm.h>
#include <stdatomic.h> #include <stdatomic.h>
#include <sys/kpanic.h>
atomic_uintptr_t lapic_msr = 0; 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) 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!"); log_early("error: LAPIC not initialized!");
return; kpanic(NULL, "LAPIC write attempted before initialization");
} }
base[offset / 4] = value;
volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset);
atomic_store((_Atomic uint32_t *)reg, value);
} }
uint32_t lapic_read(uint32_t offset) 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; return 0;
} }
return base[offset / 4];
volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset);
return atomic_load((_Atomic uint32_t *)reg);
} }
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); atomic_store(&lapic_msr, msr);
lapic_base = (volatile uint64_t *)(msr & ~(0xffff));
atomic_store(&lapic_addr, (uint64_t)lapic_base); uint64_t phys_addr = msr & ~0xFFFULL;
log_early("New LAPIC base: 0x%lx", lapic_base); 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);
} }

View file

@ -4,13 +4,41 @@
#include <stdint.h> #include <stdint.h>
#define LAPIC_BASE 0x1b #define LAPIC_BASE_MSR 0x1B
#define LAPIC_REGOFF_LAPICID 0x20
#define LAPIC_REGOFF_EOI 0xB0 // Local APIC Registers
#define LAPIC_REGOFF_SPIV 0xF0 #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); uint32_t lapic_read(uint32_t offset);
void lapic_write(uint32_t offset, uint32_t value); void lapic_write(uint32_t offset, uint32_t value);
void lapic_init(); void lapic_init(void);
void lapic_enable(void);
#endif // LAPIC_H #endif // LAPIC_H