From 7ad2167e9d1949537a5fd7115c34bf2b71c03c14 Mon Sep 17 00:00:00 2001 From: Kevin Alavik Date: Mon, 26 May 2025 19:37:22 +0200 Subject: [PATCH] feat: Improved SMP and added CPU-local contexts --- .vscode/settings.json | 3 +- GNUmakefile | 2 +- kernel/src/arch/smp.c | 77 ++++++++++++++++++++++++++++++--------- kernel/src/arch/smp.h | 8 ++++ kernel/src/emk.c | 2 + kernel/src/sys/kpanic.c | 7 +++- kernel/src/util/kprintf.c | 7 ++++ 7 files changed, 86 insertions(+), 20 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 78a7aff..7d4a96c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,7 +21,8 @@ "kpanic.h": "c", "smp.h": "c", "string_view": "c", - "lapic.h": "c" + "lapic.h": "c", + "spinlock.h": "c" }, "editor.formatOnPaste": true, "editor.formatOnSave": true, diff --git a/GNUmakefile b/GNUmakefile index fbf16f2..6dd2ae8 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -2,7 +2,7 @@ MAKEFLAGS += -rR .SUFFIXES: -QEMUFLAGS := -m 2G -serial stdio -smp 4 +QEMUFLAGS := -serial stdio -smp 4 USER_QEMUFLAGS ?= IMAGE_NAME := release/emk diff --git a/kernel/src/arch/smp.c b/kernel/src/arch/smp.c index 338c07e..ac6af23 100644 --- a/kernel/src/arch/smp.c +++ b/kernel/src/arch/smp.c @@ -1,44 +1,87 @@ /* EMK 1.0 Copyright (c) 2025 Piraterna */ #include +#include #include #include #include +#include +#include +#include +#include + +#define MAX_CPUS 256 +#define MSR_GS_BASE 0xC0000101 -uint32_t bootstrap_lapic_id = 0; uint32_t cpu_count = 0; +uint32_t bootstrap_lapic_id = 0; -uint32_t ctr = 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; +} + +static inline void set_cpu_local(cpu_local_t *cpu) +{ + wrmsr(MSR_GS_BASE, (uint64_t)cpu); +} void smp_entry(struct limine_mp_info *smp_info) { + uint32_t lapic_id = smp_info->lapic_id; + cpu_local_t *cpu = NULL; - log_early("CPU %d started", smp_info->processor_id); - __atomic_fetch_add(&ctr, 1, __ATOMIC_SEQ_CST); + for (uint32_t i = 0; i < cpu_count; i++) + { + if (cpu_locals[i].lapic_id == lapic_id) + { + cpu = &cpu_locals[i]; + break; + } + } + + if (!cpu) + kpanic(NULL, "CPU with LAPIC ID %u not found in cpu_locals!", lapic_id); + + set_cpu_local(cpu); + atomic_fetch_add(&started_cpus, 1); while (1) - ; + __asm__ volatile("hlt"); } -void smp_init() +void smp_init(void) { bootstrap_lapic_id = mp_response->bsp_lapic_id; cpu_count = mp_response->cpu_count; - for (uint64_t i = 0; i < cpu_count; i++) + log_early("%u CPUs detected", cpu_count); + + for (uint32_t i = 0; i < cpu_count; i++) { - if (mp_response->cpus[i]->lapic_id != bootstrap_lapic_id) + 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; + + if (info->lapic_id == bootstrap_lapic_id) { - uint32_t old_ctr = __atomic_load_n(&ctr, __ATOMIC_SEQ_CST); - - __atomic_store_n(&mp_response->cpus[i]->goto_address, smp_entry, - __ATOMIC_SEQ_CST); - - while (__atomic_load_n(&ctr, __ATOMIC_SEQ_CST) == old_ctr) - ; + set_cpu_local(&cpu_locals[i]); + log_early("CPU %u (LAPIC %u) is the bootstrap processor", i, info->lapic_id); + atomic_fetch_add(&started_cpus, 1); } else { - log_early("CPU %d is the bootstrap processor", i); + atomic_store((_Atomic(void **))&info->goto_address, smp_entry); + while (atomic_load(&started_cpus) < (i + 1)) + __asm__ volatile("pause"); } } -} \ No newline at end of file + + while (atomic_load(&started_cpus) < cpu_count) + __asm__ volatile("pause"); +} diff --git a/kernel/src/arch/smp.h b/kernel/src/arch/smp.h index 59f7f71..7148c2c 100644 --- a/kernel/src/arch/smp.h +++ b/kernel/src/arch/smp.h @@ -5,6 +5,14 @@ #include extern uint32_t bootstrap_lapic_id; + +typedef struct +{ + uint32_t lapic_id; + uint32_t cpu_index; +} cpu_local_t; + void smp_init(); +cpu_local_t *get_cpu_local(void); #endif // SMP_H \ No newline at end of file diff --git a/kernel/src/emk.c b/kernel/src/emk.c index 14b47c5..d05b26c 100644 --- a/kernel/src/emk.c +++ b/kernel/src/emk.c @@ -176,5 +176,7 @@ void emk_entry(void) smp_init(); log_early("Initialized SMP"); + __asm__ volatile("int $0x01"); + hlt(); } \ No newline at end of file diff --git a/kernel/src/sys/kpanic.c b/kernel/src/sys/kpanic.c index 01e3288..0b57c34 100644 --- a/kernel/src/sys/kpanic.c +++ b/kernel/src/sys/kpanic.c @@ -5,6 +5,7 @@ #include #include #include +#include static const char *strings[32] = { "Division by Zero", @@ -126,7 +127,11 @@ void kpanic(struct register_ctx *ctx, const char *fmt, ...) } } - log_panic("=== Kernel panic: '%s' @ 0x%.16llx ===", buf, regs.rip); + cpu_local_t *cpu = get_cpu_local(); + if (cpu) + log_panic("=== Kernel panic: '%s' on CPU %d @ 0x%.16llx ===", buf, cpu->cpu_index, regs.rip); + else + log_panic("=== Kernel panic: '%s' on CPU ??? @ 0x%.16llx ===", buf, regs.rip); log_panic("Registers:"); log_panic(" rax: 0x%.16llx rbx: 0x%.16llx rcx: 0x%.16llx rdx: 0x%.16llx", regs.rax, regs.rbx, regs.rcx, regs.rdx); log_panic(" rsi: 0x%.16llx rdi: 0x%.16llx rbp: 0x%.16llx rsp: 0x%.16llx", regs.rsi, regs.rdi, regs.rbp, regs.rsp); diff --git a/kernel/src/util/kprintf.c b/kernel/src/util/kprintf.c index be9a8b3..72a8da7 100644 --- a/kernel/src/util/kprintf.c +++ b/kernel/src/util/kprintf.c @@ -5,6 +5,7 @@ #if FLANTERM_SUPPORT #include #endif // FLANTERM_SUPPORT +#include #define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1 #define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1 @@ -16,8 +17,12 @@ #define NANOPRINTF_IMPLEMENTATION #include +static spinlock_t kprintf_lock = {0}; + int kprintf(const char *fmt, ...) { + spinlock_acquire(&kprintf_lock); + va_list args; va_start(args, fmt); char buffer[1024]; @@ -33,6 +38,8 @@ int kprintf(const char *fmt, ...) } va_end(args); + + spinlock_release(&kprintf_lock); return length; }