From 89bb8c8a4b7efdd600239b4806d4181302a68fc8 Mon Sep 17 00:00:00 2001 From: RaphProductions <81994075+RaphProductions@users.noreply.github.com> Date: Sun, 18 May 2025 15:54:12 +0200 Subject: [PATCH] kernel: add some basic features + feat list: + * gdt/idt + * brokie pmm --- kernel/GNUmakefile | 13 ++-- kernel/src/arch/aarch64/cpu.c | 10 +++ kernel/src/arch/cpu.h | 10 +++ kernel/src/arch/la64/cpu.c | 10 +++ kernel/src/arch/riscv/cpu.c | 10 +++ kernel/src/arch/x86_64/cpu.c | 14 +++++ kernel/src/arch/x86_64/gdt.asm | 20 ++++++ kernel/src/arch/x86_64/gdt.c | 60 ++++++++++++++++++ kernel/src/arch/x86_64/gdt.h | 43 +++++++++++++ kernel/src/arch/x86_64/idt.asm | 111 +++++++++++++++++++++++++++++++++ kernel/src/arch/x86_64/idt.c | 60 ++++++++++++++++++ kernel/src/arch/x86_64/idt.h | 51 +++++++++++++++ kernel/src/boot/limine.c | 52 +++++++++++++++ kernel/src/boot/limine.h | 22 ++++++- kernel/src/config.h | 11 ++++ kernel/src/dev/tty.c | 26 +++++++- kernel/src/dev/tty.h | 11 +++- kernel/src/lib/ansi.c | 29 +++++++++ kernel/src/lib/ansi.h | 15 +++++ kernel/src/lib/log.c | 53 ++++++++++++++++ kernel/src/lib/log.h | 35 +++++++++++ kernel/src/lib/logoutputs_sk.c | 26 ++++++++ kernel/src/lib/logoutputs_sk.h | 16 +++++ kernel/src/lib/npf.c | 18 ++++++ kernel/src/lib/string.c | 7 +++ kernel/src/lib/string.h | 7 +++ kernel/src/main.c | 23 ++++++- kernel/src/mm/memop.c | 19 +++--- kernel/src/mm/memop.h | 7 +++ kernel/src/mm/pmm.c | 65 +++++++++++++++++++ kernel/src/mm/pmm.h | 23 +++++++ 31 files changed, 854 insertions(+), 23 deletions(-) create mode 100644 kernel/src/arch/x86_64/gdt.asm create mode 100644 kernel/src/arch/x86_64/gdt.c create mode 100644 kernel/src/arch/x86_64/gdt.h create mode 100644 kernel/src/arch/x86_64/idt.asm create mode 100644 kernel/src/arch/x86_64/idt.c create mode 100644 kernel/src/arch/x86_64/idt.h create mode 100644 kernel/src/config.h create mode 100644 kernel/src/lib/ansi.c create mode 100644 kernel/src/lib/ansi.h create mode 100644 kernel/src/lib/log.c create mode 100644 kernel/src/lib/log.h create mode 100644 kernel/src/lib/logoutputs_sk.c create mode 100644 kernel/src/lib/logoutputs_sk.h create mode 100644 kernel/src/lib/npf.c create mode 100644 kernel/src/mm/pmm.c create mode 100644 kernel/src/mm/pmm.h diff --git a/kernel/GNUmakefile b/kernel/GNUmakefile index 0d7f9ff..a859d42 100644 --- a/kernel/GNUmakefile +++ b/kernel/GNUmakefile @@ -57,6 +57,13 @@ override CFLAGS += \ -ffunction-sections \ -fdata-sections +ifeq ($(CC_IS_CLANG), 1) + # Force Clang to use it's own linker instead of the host's one, since it + # might be used for cross-compilation. + override LDFLAGS += \ + -fuse-ld=lld +endif + # Internal C preprocessor flags that should not be changed by the user. override CPPFLAGS := \ -I src \ @@ -66,12 +73,6 @@ override CPPFLAGS := \ -MMD \ -MP -ifeq ($(ARCH),x86_64) - # Internal nasm flags that should not be changed by the user. - override NASMFLAGS += \ - -Wall -endif - # Architecture specific internal flags. ifeq ($(ARCH),x86_64) ifeq ($(CC_IS_CLANG),1) diff --git a/kernel/src/arch/aarch64/cpu.c b/kernel/src/arch/aarch64/cpu.c index d7f43b1..48fee8b 100644 --- a/kernel/src/arch/aarch64/cpu.c +++ b/kernel/src/arch/aarch64/cpu.c @@ -1,7 +1,17 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * cpu.c - AArch64 CPU control implementation. + */ + #if defined (__aarch64__) #include +void arch_init_stage1() { +} + void hcf() { for (;;) { asm ("wfi"); diff --git a/kernel/src/arch/cpu.h b/kernel/src/arch/cpu.h index 5d30628..11a28af 100644 --- a/kernel/src/arch/cpu.h +++ b/kernel/src/arch/cpu.h @@ -1,4 +1,14 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * cpu.h - CPU control and management functions. + */ + #pragma once +// Stage 1 initialization: Core components (such as the GDT & IDT on x86_64...) +void arch_init_stage1(); + // Disable interrupts and halt the system. void hcf(); \ No newline at end of file diff --git a/kernel/src/arch/la64/cpu.c b/kernel/src/arch/la64/cpu.c index cf58c4d..6abe756 100644 --- a/kernel/src/arch/la64/cpu.c +++ b/kernel/src/arch/la64/cpu.c @@ -1,7 +1,17 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * cpu.c - LoongArch64 CPU control implementation. + */ + #if defined (__loongarch64) #include +void arch_init_stage1() { +} + void hcf() { for (;;) { asm ("idle 0"); diff --git a/kernel/src/arch/riscv/cpu.c b/kernel/src/arch/riscv/cpu.c index 4717e48..658b2a4 100644 --- a/kernel/src/arch/riscv/cpu.c +++ b/kernel/src/arch/riscv/cpu.c @@ -1,7 +1,17 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * cpu.c - RISC-V CPU control implementation. + */ + #if defined (__riscv) #include +void arch_init_stage1() { +} + void hcf() { for (;;) { asm ("wfi"); diff --git a/kernel/src/arch/x86_64/cpu.c b/kernel/src/arch/x86_64/cpu.c index 688812b..99c591a 100644 --- a/kernel/src/arch/x86_64/cpu.c +++ b/kernel/src/arch/x86_64/cpu.c @@ -1,7 +1,21 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * cpu.c - x86_64 CPU control implementation. + */ + #if defined (__x86_64__) +#include +#include #include +void arch_init_stage1() { + gdt_init(); + idt_init(); +} + void hcf() { asm ("cli"); for (;;) { diff --git a/kernel/src/arch/x86_64/gdt.asm b/kernel/src/arch/x86_64/gdt.asm new file mode 100644 index 0000000..224581b --- /dev/null +++ b/kernel/src/arch/x86_64/gdt.asm @@ -0,0 +1,20 @@ +bits 64 + +section .text + global gdt_reload_segments + +gdt_reload_segments: + ; Reload CS register: + PUSH 0x08 ; Push code segment to stack, 0x08 is a stand-in for your code segment + LEA RAX, [rel .reload_CS] ; Load address of .reload_CS into RAX + PUSH RAX ; Push this value to the stack + RETFQ ; Perform a far return, RETFQ or LRETQ depending on syntax +.reload_CS: + ; Reload data segment registers + MOV AX, 0x10 ; 0x10 is a stand-in for your data segment + MOV DS, AX + MOV ES, AX + MOV FS, AX + MOV GS, AX + MOV SS, AX + RET \ No newline at end of file diff --git a/kernel/src/arch/x86_64/gdt.c b/kernel/src/arch/x86_64/gdt.c new file mode 100644 index 0000000..f916dfe --- /dev/null +++ b/kernel/src/arch/x86_64/gdt.c @@ -0,0 +1,60 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * gdt.c - x86_64 Global Descriptor Table implementation. + */ + +#include "lib/log.h" +#if defined(__x86_64__) + +#include +#include +#include + +gdt_table gdt = {{ + 0x0000000000000000, // 0x0, null + + 0x00af9b000000ffff, // 0x8, 64-bit code + 0x00af93000000ffff, // 0x10, 64-bit data + + 0x00affb000000ffff, // 0x18, usermode 64-bit code + 0x00aff3000000ffff // 0x20, usermode 64-bit data +}, {}}; + +tssr tss_list[255]; +static uint64_t __gdt_kstack[4096]; + +extern void gdt_reload_segments(); + +void gdt_init() { + memset(&tss_list[0], 0, sizeof(tssr)); + tss_list[0].rsp[0] = (uint64_t)__gdt_kstack; + tss_list[0].iopb = sizeof(tssr); + uintptr_t tss = (uintptr_t)&tss_list[0]; + + gdt.tss_entry = (tss_entry){ + .length = sizeof(tss_entry), + .base = (uint16_t)(tss & 0xFFFF), + .base1 = (uint8_t)((tss >> 16) & 0xFF), + .flags = 0x89, + .flags1 = 0, + .base2 = (uint8_t)((tss >> 24) & 0xFF), + .base3 = (uint32_t)(tss >> 32), + .resv = 0, + }; + + gdtr gdtr = { + .size = (sizeof(gdt_table)) - 1, + .address = (uint64_t)&gdt + }; + + __asm__ volatile("lgdt %0\n\t" : : "m"(gdtr) : "memory"); + __asm__ volatile("ltr %0\n\t" : : "r"((uint16_t)0x28)); // 0x20 (last GDT entry) + 0x8 (size of a GDT entry) + + gdt_reload_segments(); + + debug("arch: GDT & TSS initialized.\n"); +} + +#endif \ No newline at end of file diff --git a/kernel/src/arch/x86_64/gdt.h b/kernel/src/arch/x86_64/gdt.h new file mode 100644 index 0000000..d7a3e61 --- /dev/null +++ b/kernel/src/arch/x86_64/gdt.h @@ -0,0 +1,43 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * gdt.h - x86_64 Global Descriptor Table definitions. + */ + +#pragma once + +#include + +typedef struct tss_entry { + uint16_t length; + uint16_t base; + uint8_t base1; + uint8_t flags; + uint8_t flags1; + uint8_t base2; + uint32_t base3; + uint32_t resv; +} __attribute__((packed)) tss_entry; + +typedef struct { + uint64_t entries[5]; + struct tss_entry tss_entry; +} __attribute__((packed)) gdt_table; + +typedef struct { + uint16_t size; + uint64_t address; +} __attribute__((packed)) gdtr; + +typedef struct { + uint32_t resv; + uint64_t rsp[4]; + uint64_t resv1; + uint64_t ist[7]; + uint64_t resv2; + uint16_t resv3; + uint16_t iopb; +} __attribute__((packed)) tssr; // 1 TSSR per CPU. + +void gdt_init(); \ No newline at end of file diff --git a/kernel/src/arch/x86_64/idt.asm b/kernel/src/arch/x86_64/idt.asm new file mode 100644 index 0000000..fec724d --- /dev/null +++ b/kernel/src/arch/x86_64/idt.asm @@ -0,0 +1,111 @@ + +%macro pushall 0 + push rax + push rcx + push rdx + push rbx + push rbp + push rsi + push rdi + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 +%endmacro + +%macro popall 0 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rdi + pop rsi + pop rbp + pop rbx + pop rdx + pop rcx + pop rax +%endmacro + +%macro isr_err_stub 1 +isr_stub_%+%1: + push %1 ; push intno into the stack + + pushall + + mov rdi, rsp ; put the stack as the first arg. + + call idt_interrupt_handler + + popall + + add rsp, 16 + iretq +%endmacro + +%macro isr_no_err_stub 1 +isr_stub_%+%1: + push 0 ; push the error code (0) into the stack + push %1 ; push intno into the stack + + pushall + + mov rdi, rsp ; put the stack as the first arg. + + call idt_interrupt_handler + + popall + + add rsp, 16 + iretq +%endmacro + +extern idt_interrupt_handler +isr_no_err_stub 0 +isr_no_err_stub 1 +isr_no_err_stub 2 +isr_no_err_stub 3 +isr_no_err_stub 4 +isr_no_err_stub 5 +isr_no_err_stub 6 +isr_no_err_stub 7 +isr_err_stub 8 +isr_no_err_stub 9 +isr_err_stub 10 +isr_err_stub 11 +isr_err_stub 12 +isr_err_stub 13 +isr_err_stub 14 +isr_no_err_stub 15 +isr_no_err_stub 16 +isr_err_stub 17 +isr_no_err_stub 18 +isr_no_err_stub 19 +isr_no_err_stub 20 +isr_no_err_stub 21 +isr_no_err_stub 22 +isr_no_err_stub 23 +isr_no_err_stub 24 +isr_no_err_stub 25 +isr_no_err_stub 26 +isr_no_err_stub 27 +isr_no_err_stub 28 +isr_no_err_stub 29 +isr_err_stub 30 +isr_no_err_stub 31 + +global isr_stub_table +isr_stub_table: +%assign i 0 +%rep 32 + 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 new file mode 100644 index 0000000..34e8589 --- /dev/null +++ b/kernel/src/arch/x86_64/idt.c @@ -0,0 +1,60 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * idt.c - x86_64 Interrupt Descriptor Table implementation. + */ +#if defined(__x86_64__) + +#include "arch/cpu.h" +#include "lib/log.h" +#include + +__attribute__((aligned(0x10))) +static idt_entry_t idt[256]; +static idtr_t idtr; + +void idt_interrupt_handler(registers_t *regs) { + 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); + fatal("r8: %p, r9: %p, r10: %p\n", regs->r8, regs->r8, regs->r10); + fatal("r11: %p, r12: %p, r13: %p\n", regs->r11, regs->r12, regs->r13); + 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: %p, rsp: %p\n", regs->rflags, regs->err_code, regs->rsp); + hcf(); +} + +void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) { + 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; +} + +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; + + for (uint8_t vector = 0; vector < 32; vector++) { + idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); + vectors[vector] = true; + } + + __asm__ volatile ("lidt %0" : : "m"(idtr)); + __asm__ volatile ("sti"); + + debug("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 new file mode 100644 index 0000000..e66648e --- /dev/null +++ b/kernel/src/arch/x86_64/idt.h @@ -0,0 +1,51 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * idt.h - x86_64 Interrupt Descriptor Table declarations. + */ +#pragma once + +#include + +typedef struct { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rbx; + uint64_t rdx; + uint64_t rcx; + uint64_t rax; + uint64_t int_no; + uint64_t err_code; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +} __attribute__((packed)) registers_t; + +typedef struct { + uint16_t isr_low; + uint16_t kernel_cs; + uint8_t ist; + uint8_t attributes; + uint16_t isr_mid; + uint32_t isr_high; + uint32_t reserved; +} __attribute__((packed)) idt_entry_t; + +typedef struct { + uint16_t limit; + uint64_t base; +} __attribute__((packed)) idtr_t; + +void idt_init(void); \ No newline at end of file diff --git a/kernel/src/boot/limine.c b/kernel/src/boot/limine.c index 67178c1..f913498 100644 --- a/kernel/src/boot/limine.c +++ b/kernel/src/boot/limine.c @@ -1,4 +1,12 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * limine.c - Limine bootloader interface implementation. + */ + #include "deps/limine.h" +#include "limine.h" #include #include #include @@ -12,12 +20,34 @@ static volatile struct limine_framebuffer_request framebuffer_request = { .revision = 0 }; +__attribute__((used, section(".limine_requests"))) +static volatile struct limine_bootloader_info_request bl_info_request = { + .id = LIMINE_BOOTLOADER_INFO_REQUEST, + .revision = 0 +}; + +__attribute__((used, section(".limine_requests"))) +static volatile struct limine_firmware_type_request firmware_type_req = { + .id = LIMINE_FIRMWARE_TYPE_REQUEST, + .revision = 0 +}; + +__attribute__((used, section(".limine_requests"))) +static volatile struct limine_memmap_request memmap_req = { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0 +}; + __attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER; __attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER; + +static limine_bootinfo_t __limine_bootinfo; + + bool limine_ensure_baserev() { return LIMINE_BASE_REVISION_SUPPORTED; } limine_fb_t *limine_get_fb(int id) { @@ -27,4 +57,26 @@ limine_fb_t *limine_get_fb(int id) { if (id >= (int32_t)framebuffer_request.response->framebuffer_count) // Limine, WHY putting the FB count as a 64-bit integer??? I never seen someone with 0xFFFFFFFFFFFFFFFF screens return NULL; return framebuffer_request.response->framebuffers[id]; +} + +struct limine_memmap_response *limine_get_memmap() { + return memmap_req.response; +} + +limine_bootinfo_t *limine_get_bootinfo() { + __limine_bootinfo.bl_name = bl_info_request.response->name; + __limine_bootinfo.bl_ver = bl_info_request.response->version; + __limine_bootinfo.fw_type = firmware_type_req.response->firmware_type; + +#if defined(__x86_64__) + __limine_bootinfo.arch = "x86_64"; +#elif defined(__aarch64__) + __limine_bootinfo.arch = "aarch64"; +#elif defined(__riscv) + __limine_bootinfo.arch = "riscv"; +#elif defined(__loongarch64) + __limine_bootinfo.arch = "loongarch64"; +#endif + + return &__limine_bootinfo; } \ No newline at end of file diff --git a/kernel/src/boot/limine.h b/kernel/src/boot/limine.h index 9173039..443cd44 100644 --- a/kernel/src/boot/limine.h +++ b/kernel/src/boot/limine.h @@ -1,3 +1,10 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * limine.h - Limine bootloader interface declarations. + */ + #pragma once #include @@ -5,8 +12,21 @@ typedef struct limine_framebuffer limine_fb_t; +typedef struct { + char *bl_name; + char *bl_ver; + char *arch; + int fw_type; +} limine_bootinfo_t; + // Ensure that the used boot loader supports the kernel's LBP revision bool limine_ensure_baserev(); // Get a framebuffer -limine_fb_t *limine_get_fb(int id); \ No newline at end of file +limine_fb_t *limine_get_fb(int id); + +// Get some informations about how the kernel was booted +limine_bootinfo_t *limine_get_bootinfo(); + +// Get the memory map. +struct limine_memmap_response *limine_get_memmap(); \ No newline at end of file diff --git a/kernel/src/config.h b/kernel/src/config.h new file mode 100644 index 0000000..38af8b2 --- /dev/null +++ b/kernel/src/config.h @@ -0,0 +1,11 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * config.h - Kernel configuration definitions. + */ + +#pragma once + +#define KERNEL_NAME "Soaplin" +#define KERNEL_VER "0.0.1" \ No newline at end of file diff --git a/kernel/src/dev/tty.c b/kernel/src/dev/tty.c index 3ddccfb..9d64dd3 100644 --- a/kernel/src/dev/tty.c +++ b/kernel/src/dev/tty.c @@ -1,7 +1,15 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * tty.c - Terminal interface implementation. + */ -#include +#include #include #include +#include +#include #include struct flanterm_context *tty0_ctx; @@ -26,6 +34,20 @@ void tty_init() { ); } -void tty_write_raw(char *str) { +void tty_putc(char c) { + flanterm_write(tty0_ctx, &c, 1); +} + +void tty_puts(char *str) { flanterm_write(tty0_ctx, str, strlen(str)); +} + +void tty_printf(char *fmt, ...) { + char buf[2048]; + va_list l; + va_start(l, fmt); + npf_vsnprintf(buf, 2048, fmt, l); + va_end(l); + + tty_puts(buf); } \ No newline at end of file diff --git a/kernel/src/dev/tty.h b/kernel/src/dev/tty.h index 14fc734..03b838c 100644 --- a/kernel/src/dev/tty.h +++ b/kernel/src/dev/tty.h @@ -1,4 +1,13 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * tty.h - Terminal interface declarations. + */ + #pragma once void tty_init(); -void tty_write_raw(char *str); \ No newline at end of file +void tty_putc(char c); +void tty_puts(char *str); +void tty_printf(char *fmt, ...); \ No newline at end of file diff --git a/kernel/src/lib/ansi.c b/kernel/src/lib/ansi.c new file mode 100644 index 0000000..0eb8c87 --- /dev/null +++ b/kernel/src/lib/ansi.c @@ -0,0 +1,29 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * ansi.c - ANSI escape sequence generation functions implementation. + */ + +#include +#include +#include + +static char __ansi_bg_buf[32]; +static char __ansi_fg_buf[32]; + +char *ansi_gen_bg(uint8_t r, uint8_t g, uint8_t b) { + int len = npf_snprintf(__ansi_bg_buf, sizeof(__ansi_bg_buf), "\033[48;2;%d;%d;%d;m", r, g, b); + if (len < 0 || len >= (int)sizeof(__ansi_bg_buf)) { + return "\033[0m"; + } + return __ansi_bg_buf; +} + +char *ansi_gen_fg(uint8_t r, uint8_t g, uint8_t b) { + int len = npf_snprintf(__ansi_fg_buf, sizeof(__ansi_fg_buf), "\033[38;2;%d;%d;%d;m", r, g, b); + if (len < 0 || len >= (int)sizeof(__ansi_fg_buf)) { + return "\033[0m"; + } + return __ansi_fg_buf; +} \ No newline at end of file diff --git a/kernel/src/lib/ansi.h b/kernel/src/lib/ansi.h new file mode 100644 index 0000000..2036e2e --- /dev/null +++ b/kernel/src/lib/ansi.h @@ -0,0 +1,15 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * ansi.h - ANSI escape sequence generation functions. + */ + +#pragma once +#include + +#define ANSI_CLEAR_SCREEN "\033[H\033[2J" +#define ANSI_RESET_COLOR "\033[39m\\033[49m" + +char *ansi_gen_bg(uint8_t r, uint8_t g, uint8_t b); +char *ansi_gen_fg(uint8_t r, uint8_t g, uint8_t b); \ No newline at end of file diff --git a/kernel/src/lib/log.c b/kernel/src/lib/log.c new file mode 100644 index 0000000..e21cf80 --- /dev/null +++ b/kernel/src/lib/log.c @@ -0,0 +1,53 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * log.c - Kernel logging interface. + */ +#include +#include + +static int __logger_max_loglevel = 0; +static log_output_func __logger_outputs[16]; +static int __logger_output_count = 0; + +static char* prelog[7] = { + "\033[38;2;169;68;66;mFAULT | \033[39m", + "\033[38;2;217;83;79;mERROR | \033[39m", + "\033[38;2;240;173;78;mWARN | \033[39m", + "\033[38;2;240;240;240;mNOTICE | \033[39m", + "\033[38;2;92;184;92;mINFO | \033[39m", + "\033[38;2;87;201;193;mDEBUG | \033[39m", + "\033[38;2;150;150;150;mTRACE | \033[39m", +}; + +void log_init(int max_loglevel) { + __logger_max_loglevel = max_loglevel; +} + +bool log_register_output(log_output_func fn) { + if (fn && __logger_output_count <= 16) { + __logger_output_count ++; + __logger_outputs[__logger_output_count - 1] = fn; + return true; + } + return false; +} + +void log(int loglevel, char *str, ...) { + if (__logger_max_loglevel == 0 || __logger_output_count == 0) + return; // The user forgot to initialize the logger. + + if (loglevel > __logger_max_loglevel) + return; // The user does not want this type of log to show up. + + va_list vl; + va_start(vl, str); + + for (int i = 0; i < __logger_output_count; i++) { + __logger_outputs[i](prelog[loglevel - 1], (void*)0); + __logger_outputs[i](str, &vl); + } + + va_end(vl); +} \ No newline at end of file diff --git a/kernel/src/lib/log.h b/kernel/src/lib/log.h new file mode 100644 index 0000000..6c47f8e --- /dev/null +++ b/kernel/src/lib/log.h @@ -0,0 +1,35 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * log.h - Kernel logging interface. + */ + +#pragma once + +// Log levels in order of increasing severity +#include +#include + +#define LOGLEVEL_TRACE 7 +#define LOGLEVEL_DEBUG 6 +#define LOGLEVEL_INFO 5 +#define LOGLEVEL_NOTICE 4 +#define LOGLEVEL_WARNING 3 +#define LOGLEVEL_ERROR 2 +#define LOGLEVEL_FATAL 1 + +typedef void(*log_output_func)(char *str, va_list *vl); + +void log_init(int max_loglevel); +bool log_register_output(log_output_func fn); +void log(int loglevel, char *str, ...); + +// Shortcuts to log +#define trace(str, ...) log(LOGLEVEL_TRACE, str, ##__VA_ARGS__) +#define debug(str, ...) log(LOGLEVEL_DEBUG, str, ##__VA_ARGS__) +#define info(str, ...) log(LOGLEVEL_INFO, str, ##__VA_ARGS__) +#define notice(str, ...) log(LOGLEVEL_NOTICE, str, ##__VA_ARGS__) +#define warn(str, ...) log(LOGLEVEL_WARNING, str, ##__VA_ARGS__) +#define error(str, ...) log(LOGLEVEL_ERROR, str, ##__VA_ARGS__) +#define fatal(str, ...) log(LOGLEVEL_FATAL, str, ##__VA_ARGS__) \ No newline at end of file diff --git a/kernel/src/lib/logoutputs_sk.c b/kernel/src/lib/logoutputs_sk.c new file mode 100644 index 0000000..4276d48 --- /dev/null +++ b/kernel/src/lib/logoutputs_sk.c @@ -0,0 +1,26 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * logoutputs_sk.c - Output functions for the logger + */ +#include "deps/npf.h" +#include +#include + +void sklogoutput_tty(char *str, va_list *vl) { + if (!vl) { + tty_puts(str); + return; + } + + char buf[2048]; + npf_vsnprintf(buf, 2048, str, *vl); + tty_puts(buf); +} + +void sklogoutput_e9(char *str, va_list *vl) { + // TODO: implement this + (void)str; + (void)vl; +} \ No newline at end of file diff --git a/kernel/src/lib/logoutputs_sk.h b/kernel/src/lib/logoutputs_sk.h new file mode 100644 index 0000000..bb51ff0 --- /dev/null +++ b/kernel/src/lib/logoutputs_sk.h @@ -0,0 +1,16 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * logoutputs_sk.h - Output functions for the logger + */ + +#pragma once + +// Output to the terminal. +#include + +void sklogoutput_tty(char *str, va_list *vl); + +// Output to QEMU & Bochs's E9 port. +void sklogoutput_e9(char *str, va_list *vl); \ No newline at end of file diff --git a/kernel/src/lib/npf.c b/kernel/src/lib/npf.c new file mode 100644 index 0000000..59df675 --- /dev/null +++ b/kernel/src/lib/npf.c @@ -0,0 +1,18 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * npf.c - nanoprintf configuration and implementation. + */ + +#define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1 +#define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 0 +#define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 1 +#define NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS 1 +#define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 0 +#define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS 1 +#define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 1 + +// Compile nanoprintf in this translation unit. +#define NANOPRINTF_IMPLEMENTATION +#include \ No newline at end of file diff --git a/kernel/src/lib/string.c b/kernel/src/lib/string.c index a345e2d..98652b5 100644 --- a/kernel/src/lib/string.c +++ b/kernel/src/lib/string.c @@ -1,3 +1,10 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * string.c - String manipulation functions implementation. + */ + #include size_t strlen(char *str) { diff --git a/kernel/src/lib/string.h b/kernel/src/lib/string.h index 4e6e619..b0d1424 100644 --- a/kernel/src/lib/string.h +++ b/kernel/src/lib/string.h @@ -1,3 +1,10 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * string.h - String manipulation functions. + */ + #pragma once #include diff --git a/kernel/src/main.c b/kernel/src/main.c index b4c2057..14c33ba 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -1,15 +1,36 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * main.c - Kernel entry point and initialization. + */ + #include #include #include + #include #include +#include #include +#include +#include +#include +#include void kmain(void) { tty_init(); + log_init(LOGLEVEL_TRACE); + log_register_output(sklogoutput_tty); - tty_write_raw("Hello, World!\n"); + limine_bootinfo_t *bi = limine_get_bootinfo(); + trace("%s %s-%s (booted using %s %s, with firmware type %d)\n", KERNEL_NAME, KERNEL_VER, + bi->arch, bi->bl_name, bi->bl_ver, bi->fw_type); + arch_init_stage1(); + + pmm_init(); + // We're done, just hang... hcf(); } diff --git a/kernel/src/mm/memop.c b/kernel/src/mm/memop.c index 8910891..1bd42be 100644 --- a/kernel/src/mm/memop.c +++ b/kernel/src/mm/memop.c @@ -1,18 +1,14 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * memop.c - Memory operations implementation. + */ + #include #include void *memcpy(void *restrict dest, const void *restrict src, size_t n) { -#if defined(__x86_64__) - long d0, d1, d2; - asm volatile( - "rep ; movsq\n\t movq %4,%%rcx\n\t""rep ; movsb\n\t": "=&c" (d0), - "=&D" (d1), - "=&S" (d2): "0" (n >> 3), - "g" (n & 7), - "1" (dest), - "2" (src): "memory" - ); -#else uint8_t *restrict pdest = (uint8_t *restrict)dest; const uint8_t *restrict psrc = (const uint8_t *restrict)src; @@ -21,7 +17,6 @@ void *memcpy(void *restrict dest, const void *restrict src, size_t n) { } return dest; -#endif } void *memset(void *s, int c, size_t n) { diff --git a/kernel/src/mm/memop.h b/kernel/src/mm/memop.h index 1d75ae1..d556d74 100644 --- a/kernel/src/mm/memop.h +++ b/kernel/src/mm/memop.h @@ -1,3 +1,10 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * memop.h - Memory operations declarations. + */ + #pragma once #include diff --git a/kernel/src/mm/pmm.c b/kernel/src/mm/pmm.c new file mode 100644 index 0000000..da05a58 --- /dev/null +++ b/kernel/src/mm/pmm.c @@ -0,0 +1,65 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * pmm.c - Physical memory allocator + */ + +#include "arch/cpu.h" +#include +#include + +#include +#include +#include +#include + +uint64_t pmm_available_pages = 0; +uint64_t pmm_total_pages = 0; + +static pmm_page_t* pmm_free_list_head = NULL; + +void pmm_free_page(void *mem) { + pmm_page_t *page = (pmm_page_t*)mem; + page->next = pmm_free_list_head; + pmm_free_list_head = page; + + pmm_available_pages++; +} + +void *pmm_alloc_page() { + if (!pmm_free_list_head) + { + fatal("pmm: out of memory!\n"); + hcf(); + } + + pmm_available_pages--; + + pmm_page_t *page = pmm_free_list_head; + pmm_free_list_head = page->next; + + memset(page, 0, PMM_PAGE_SIZE); + return page; +} + +void pmm_init() { + struct limine_memmap_response *mmap = limine_get_memmap(); + + for (uint64_t i = 0; i < mmap->entry_count; i++) { + struct limine_memmap_entry *entry = mmap->entries[i]; + + if (entry->type == LIMINE_MEMMAP_USABLE) + { + trace("pmm: found a usable memory block: %p-%p\n", entry->base, entry->base + entry->length); + + uint64_t newlen = ALIGN_UP(entry->length, PMM_PAGE_SIZE); + for (uint64_t j = 0; j < newlen; j += PMM_PAGE_SIZE) { + pmm_free_page((void*)(entry->base + j)); + pmm_total_pages++; + } + } + } + + trace("pmm: %d pages available\n", pmm_available_pages); +} \ No newline at end of file diff --git a/kernel/src/mm/pmm.h b/kernel/src/mm/pmm.h new file mode 100644 index 0000000..db52cc5 --- /dev/null +++ b/kernel/src/mm/pmm.h @@ -0,0 +1,23 @@ +/* + * The Soaplin Kernel + * Copyright (C) 2025 The SILD Project + * + * pmm.c - Physical memory allocator + */ + +#pragma once + +#include + +#define DIV_ROUND_UP(x, y) \ + (((uint64_t)(x) + ((uint64_t)(y) - 1)) / (uint64_t)(y)) +#define ALIGN_UP(x, y) (DIV_ROUND_UP(x, y) * (uint64_t)(y)) +#define ALIGN_DOWN(x, y) (((uint64_t)(x) / (uint64_t)(y)) * (uint64_t)(y)) + +#define PMM_PAGE_SIZE 0x1000 // We are using 4kb pages. + +typedef struct __pmm_page { + struct __pmm_page *next; +} pmm_page_t; + +void pmm_init(); \ No newline at end of file