kernel: add some basic features
+ feat list: + * gdt/idt + * brokie pmm
This commit is contained in:
parent
a1e27c2730
commit
89bb8c8a4b
31 changed files with 854 additions and 23 deletions
|
@ -57,6 +57,13 @@ override CFLAGS += \
|
||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
-fdata-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.
|
# Internal C preprocessor flags that should not be changed by the user.
|
||||||
override CPPFLAGS := \
|
override CPPFLAGS := \
|
||||||
-I src \
|
-I src \
|
||||||
|
@ -66,12 +73,6 @@ override CPPFLAGS := \
|
||||||
-MMD \
|
-MMD \
|
||||||
-MP
|
-MP
|
||||||
|
|
||||||
ifeq ($(ARCH),x86_64)
|
|
||||||
# Internal nasm flags that should not be changed by the user.
|
|
||||||
override NASMFLAGS += \
|
|
||||||
-Wall
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Architecture specific internal flags.
|
# Architecture specific internal flags.
|
||||||
ifeq ($(ARCH),x86_64)
|
ifeq ($(ARCH),x86_64)
|
||||||
ifeq ($(CC_IS_CLANG),1)
|
ifeq ($(CC_IS_CLANG),1)
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* cpu.c - AArch64 CPU control implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined (__aarch64__)
|
#if defined (__aarch64__)
|
||||||
|
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
|
void arch_init_stage1() {
|
||||||
|
}
|
||||||
|
|
||||||
void hcf() {
|
void hcf() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
asm ("wfi");
|
asm ("wfi");
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* cpu.h - CPU control and management functions.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#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.
|
// Disable interrupts and halt the system.
|
||||||
void hcf();
|
void hcf();
|
|
@ -1,7 +1,17 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* cpu.c - LoongArch64 CPU control implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined (__loongarch64)
|
#if defined (__loongarch64)
|
||||||
|
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
|
void arch_init_stage1() {
|
||||||
|
}
|
||||||
|
|
||||||
void hcf() {
|
void hcf() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
asm ("idle 0");
|
asm ("idle 0");
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* cpu.c - RISC-V CPU control implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined (__riscv)
|
#if defined (__riscv)
|
||||||
|
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
|
void arch_init_stage1() {
|
||||||
|
}
|
||||||
|
|
||||||
void hcf() {
|
void hcf() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
asm ("wfi");
|
asm ("wfi");
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* cpu.c - x86_64 CPU control implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined (__x86_64__)
|
#if defined (__x86_64__)
|
||||||
|
|
||||||
|
#include <arch/x86_64/gdt.h>
|
||||||
|
#include <arch/x86_64/idt.h>
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
|
void arch_init_stage1() {
|
||||||
|
gdt_init();
|
||||||
|
idt_init();
|
||||||
|
}
|
||||||
|
|
||||||
void hcf() {
|
void hcf() {
|
||||||
asm ("cli");
|
asm ("cli");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
20
kernel/src/arch/x86_64/gdt.asm
Normal file
20
kernel/src/arch/x86_64/gdt.asm
Normal 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
|
60
kernel/src/arch/x86_64/gdt.c
Normal file
60
kernel/src/arch/x86_64/gdt.c
Normal 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
|
43
kernel/src/arch/x86_64/gdt.h
Normal file
43
kernel/src/arch/x86_64/gdt.h
Normal 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();
|
111
kernel/src/arch/x86_64/idt.asm
Normal file
111
kernel/src/arch/x86_64/idt.asm
Normal 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
|
60
kernel/src/arch/x86_64/idt.c
Normal file
60
kernel/src/arch/x86_64/idt.c
Normal 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
|
51
kernel/src/arch/x86_64/idt.h
Normal file
51
kernel/src/arch/x86_64/idt.h
Normal 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);
|
|
@ -1,4 +1,12 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* limine.c - Limine bootloader interface implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "deps/limine.h"
|
#include "deps/limine.h"
|
||||||
|
#include "limine.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <boot/limine.h>
|
#include <boot/limine.h>
|
||||||
|
@ -12,12 +20,34 @@ static volatile struct limine_framebuffer_request framebuffer_request = {
|
||||||
.revision = 0
|
.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")))
|
__attribute__((used, section(".limine_requests_start")))
|
||||||
static volatile LIMINE_REQUESTS_START_MARKER;
|
static volatile LIMINE_REQUESTS_START_MARKER;
|
||||||
|
|
||||||
__attribute__((used, section(".limine_requests_end")))
|
__attribute__((used, section(".limine_requests_end")))
|
||||||
static volatile LIMINE_REQUESTS_END_MARKER;
|
static volatile LIMINE_REQUESTS_END_MARKER;
|
||||||
|
|
||||||
|
|
||||||
|
static limine_bootinfo_t __limine_bootinfo;
|
||||||
|
|
||||||
|
|
||||||
bool limine_ensure_baserev() { return LIMINE_BASE_REVISION_SUPPORTED; }
|
bool limine_ensure_baserev() { return LIMINE_BASE_REVISION_SUPPORTED; }
|
||||||
|
|
||||||
limine_fb_t *limine_get_fb(int id) {
|
limine_fb_t *limine_get_fb(int id) {
|
||||||
|
@ -28,3 +58,25 @@ limine_fb_t *limine_get_fb(int id) {
|
||||||
return NULL;
|
return NULL;
|
||||||
return framebuffer_request.response->framebuffers[id];
|
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;
|
||||||
|
}
|
|
@ -1,3 +1,10 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* limine.h - Limine bootloader interface declarations.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <deps/limine.h>
|
#include <deps/limine.h>
|
||||||
|
@ -5,8 +12,21 @@
|
||||||
|
|
||||||
typedef struct limine_framebuffer limine_fb_t;
|
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
|
// Ensure that the used boot loader supports the kernel's LBP revision
|
||||||
bool limine_ensure_baserev();
|
bool limine_ensure_baserev();
|
||||||
|
|
||||||
// Get a framebuffer
|
// 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
11
kernel/src/config.h
Normal 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"
|
|
@ -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/backends/fb.h>
|
||||||
#include <deps/flanterm/flanterm.h>
|
#include <deps/flanterm/flanterm.h>
|
||||||
|
#include <boot/limine.h>
|
||||||
|
#include <deps/npf.h>
|
||||||
#include <lib/string.h>
|
#include <lib/string.h>
|
||||||
|
|
||||||
struct flanterm_context *tty0_ctx;
|
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));
|
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);
|
||||||
|
}
|
|
@ -1,4 +1,13 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* tty.h - Terminal interface declarations.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void tty_init();
|
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
29
kernel/src/lib/ansi.c
Normal 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
15
kernel/src/lib/ansi.h
Normal 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
53
kernel/src/lib/log.c
Normal 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
35
kernel/src/lib/log.h
Normal 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__)
|
26
kernel/src/lib/logoutputs_sk.c
Normal file
26
kernel/src/lib/logoutputs_sk.c
Normal 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;
|
||||||
|
}
|
16
kernel/src/lib/logoutputs_sk.h
Normal file
16
kernel/src/lib/logoutputs_sk.h
Normal 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
18
kernel/src/lib/npf.c
Normal 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>
|
|
@ -1,3 +1,10 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* string.c - String manipulation functions implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <lib/string.h>
|
#include <lib/string.h>
|
||||||
|
|
||||||
size_t strlen(char *str) {
|
size_t strlen(char *str) {
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* string.h - String manipulation functions.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
|
@ -1,14 +1,35 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* main.c - Kernel entry point and initialization.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <boot/limine.h>
|
#include <boot/limine.h>
|
||||||
|
#include <config.h>
|
||||||
#include <dev/tty.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) {
|
void kmain(void) {
|
||||||
tty_init();
|
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...
|
// We're done, just hang...
|
||||||
hcf();
|
hcf();
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* memop.c - Memory operations implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <mm/memop.h>
|
#include <mm/memop.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void *memcpy(void *restrict dest, const void *restrict src, size_t n) {
|
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;
|
uint8_t *restrict pdest = (uint8_t *restrict)dest;
|
||||||
const uint8_t *restrict psrc = (const uint8_t *restrict)src;
|
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;
|
return dest;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *memset(void *s, int c, size_t n) {
|
void *memset(void *s, int c, size_t n) {
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
/*
|
||||||
|
* The Soaplin Kernel
|
||||||
|
* Copyright (C) 2025 The SILD Project
|
||||||
|
*
|
||||||
|
* memop.h - Memory operations declarations.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
65
kernel/src/mm/pmm.c
Normal file
65
kernel/src/mm/pmm.c
Normal 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
23
kernel/src/mm/pmm.h
Normal 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();
|
Loading…
Add table
Add a link
Reference in a new issue