kernel: add some basic features

+ feat list:
+ * gdt/idt
+ * brokie pmm
This commit is contained in:
RaphProductions 2025-05-18 15:54:12 +02:00
parent a1e27c2730
commit 89bb8c8a4b
31 changed files with 854 additions and 23 deletions

View file

@ -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)

View file

@ -1,7 +1,17 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* cpu.c - AArch64 CPU control implementation.
*/
#if defined (__aarch64__)
#include <arch/cpu.h>
void arch_init_stage1() {
}
void hcf() {
for (;;) {
asm ("wfi");

View file

@ -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();

View file

@ -1,7 +1,17 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* cpu.c - LoongArch64 CPU control implementation.
*/
#if defined (__loongarch64)
#include <arch/cpu.h>
void arch_init_stage1() {
}
void hcf() {
for (;;) {
asm ("idle 0");

View file

@ -1,7 +1,17 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* cpu.c - RISC-V CPU control implementation.
*/
#if defined (__riscv)
#include <arch/cpu.h>
void arch_init_stage1() {
}
void hcf() {
for (;;) {
asm ("wfi");

View file

@ -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 <arch/x86_64/gdt.h>
#include <arch/x86_64/idt.h>
#include <arch/cpu.h>
void arch_init_stage1() {
gdt_init();
idt_init();
}
void hcf() {
asm ("cli");
for (;;) {

View file

@ -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

View file

@ -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 <stdint.h>
#include <arch/x86_64/gdt.h>
#include <mm/memop.h>
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

View file

@ -0,0 +1,43 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* gdt.h - x86_64 Global Descriptor Table definitions.
*/
#pragma once
#include <stdint.h>
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();

View file

@ -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

View file

@ -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 <arch/x86_64/idt.h>
__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

View file

@ -0,0 +1,51 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* idt.h - x86_64 Interrupt Descriptor Table declarations.
*/
#pragma once
#include <stdint.h>
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);

View file

@ -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 <stdbool.h>
#include <stddef.h>
#include <boot/limine.h>
@ -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;
}

View file

@ -1,3 +1,10 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* limine.h - Limine bootloader interface declarations.
*/
#pragma once
#include <deps/limine.h>
@ -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);
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();

11
kernel/src/config.h Normal file
View file

@ -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"

View file

@ -1,7 +1,15 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* tty.c - Terminal interface implementation.
*/
#include <boot/limine.h>
#include <stdarg.h>
#include <deps/flanterm/backends/fb.h>
#include <deps/flanterm/flanterm.h>
#include <boot/limine.h>
#include <deps/npf.h>
#include <lib/string.h>
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);
}

View file

@ -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);
void tty_putc(char c);
void tty_puts(char *str);
void tty_printf(char *fmt, ...);

29
kernel/src/lib/ansi.c Normal file
View file

@ -0,0 +1,29 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* ansi.c - ANSI escape sequence generation functions implementation.
*/
#include <deps/npf.h>
#include <lib/ansi.h>
#include <stdint.h>
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;
}

15
kernel/src/lib/ansi.h Normal file
View file

@ -0,0 +1,15 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* ansi.h - ANSI escape sequence generation functions.
*/
#pragma once
#include <stdint.h>
#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);

53
kernel/src/lib/log.c Normal file
View file

@ -0,0 +1,53 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* log.c - Kernel logging interface.
*/
#include <stdarg.h>
#include <lib/log.h>
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);
}

35
kernel/src/lib/log.h Normal file
View file

@ -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 <stdarg.h>
#include <stdbool.h>
#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__)

View file

@ -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 <dev/tty.h>
#include <lib/logoutputs_sk.h>
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;
}

View file

@ -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 <stdarg.h>
void sklogoutput_tty(char *str, va_list *vl);
// Output to QEMU & Bochs's E9 port.
void sklogoutput_e9(char *str, va_list *vl);

18
kernel/src/lib/npf.c Normal file
View file

@ -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 <deps/npf.h>

View file

@ -1,3 +1,10 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* string.c - String manipulation functions implementation.
*/
#include <lib/string.h>
size_t strlen(char *str) {

View file

@ -1,3 +1,10 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* string.h - String manipulation functions.
*/
#pragma once
#include <stddef.h>

View file

@ -1,15 +1,36 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* main.c - Kernel entry point and initialization.
*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <arch/cpu.h>
#include <boot/limine.h>
#include <config.h>
#include <dev/tty.h>
#include <lib/ansi.h>
#include <lib/log.h>
#include <lib/logoutputs_sk.h>
#include <mm/pmm.h>
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();
}

View file

@ -1,18 +1,14 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* memop.c - Memory operations implementation.
*/
#include <mm/memop.h>
#include <stdint.h>
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) {

View file

@ -1,3 +1,10 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* memop.h - Memory operations declarations.
*/
#pragma once
#include <stddef.h>

65
kernel/src/mm/pmm.c Normal file
View file

@ -0,0 +1,65 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* pmm.c - Physical memory allocator
*/
#include "arch/cpu.h"
#include <stdint.h>
#include <stddef.h>
#include <boot/limine.h>
#include <lib/log.h>
#include <mm/memop.h>
#include <mm/pmm.h>
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);
}

23
kernel/src/mm/pmm.h Normal file
View file

@ -0,0 +1,23 @@
/*
* The Soaplin Kernel
* Copyright (C) 2025 The SILD Project
*
* pmm.c - Physical memory allocator
*/
#pragma once
#include <stdint.h>
#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();