kernel: various changes.

+ kernel: replace sk-hello test executable with a test initramfs
+ panic: start implementing a proper kernel panic screen
+ lib: added a new string.h library for string manipulation.
+ kernel: replace all the strlen implementations with the strlen() function
This commit is contained in:
RaphProductions 2025-05-11 23:54:14 +02:00
parent 7fb04f134b
commit a838d99a5a
19 changed files with 173 additions and 149 deletions

View file

@ -3,3 +3,7 @@ Do you want to improve Soaplin? You can by contributing to the project!
## Contributing guidelines
* Before making a commit, please run `make format`. This will run clang-format over all the C source files in kernel/src.
* Large language model-generated code is **allowed**, with the condition that you do extensive testing over that code.
You must also know how to make the LLM-generated code by yourself.
Note: Even if LLM-generated code is allowed, please try to not use it.

View file

@ -83,7 +83,6 @@ run-aarch64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).iso
.PHONY: run-hdd-aarch64
run-hdd-aarch64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).hdd
@echo " Starting QEMU with $(IMAGE_NAME).hdd"
@qemu-system-$(ARCH) \
-M virt \
-cpu cortex-a72 \
@ -204,8 +203,8 @@ $(IMAGE_NAME).iso: limine/limine kernel
@mkdir -p iso_root/boot/limine
@cp -v limine.conf iso_root/boot/limine/
@mkdir -p iso_root/EFI/BOOT
@cp -v initramfs.tar iso_root/
ifeq ($(ARCH),x86_64)
@cp -v testing/sk-hello.elf iso_root/
@cp -v limine/limine-bios.sys limine/limine-bios-cd.bin limine/limine-uefi-cd.bin iso_root/boot/limine/
@cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT/
@cp -v limine/BOOTIA32.EFI iso_root/EFI/BOOT/

BIN
initramfs.tar Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
Hello World from a subdirectory!

1
initramfs/test.txt Normal file
View file

@ -0,0 +1 @@
Hello World!

View file

View file

@ -1,28 +0,0 @@
#pragma once
// btw fuck sun
#include <stdint.h>
#define VNODE_TYPE_FILE 0
#define VNODE_TYPE_DIR 1
#define VNODE_TYPE_DEV 2
typedef struct __vnode {
char name[128];
int type;
struct __vnode *children;
struct __vnode *next;
struct __vnode *parent;
void (*write)(void *buffer, uint64_t off, uint64_t size);
void (*read)(void *buffer, uint64_t off, uint64_t size);
} vnode;
typedef struct __vfs_mount {
struct vfs_node
*mount_point; // The directory in the main VFS where this is mounted
struct vfs_node *mounted_root; // The root node of the mounted filesystem
struct vfs_mount *next; // Pointer to next mount point
} vfs_mount;

57
kernel/src/lib/string.c Normal file
View file

@ -0,0 +1,57 @@
#include <lib/string.h>
#include <stddef.h>
int strlen(const char *str) {
int len = 0;
while (str[len])
len++;
return len;
}
int strcmp(const char *s1, const char *s2) {
while (*s1 && *s1 == *s2) {
s1++;
s2++;
}
return *s1 - *s2;
}
char *strcpy(char *dest, const char *src)
{
if (dest == NULL || src == NULL)
return NULL;
char *temp = dest;
while((*dest++ = *src++) != '\0');
return temp;
}
char *strchr(const char *s, int c) {
while (*s++) {
if (*s == c)
return (char *)s;
}
return NULL;
}
char *strrchr(const char *s, int c) {
const char *p = NULL;
for (;;) {
if (*s == (char)c)
p = s;
if (*s++ == '\0')
return (char *)p;
}
}
int oct2bin(unsigned char *str, int size) {
int n = 0;
unsigned char *c = str;
while (size-- > 0) {
n *= 8;
n += *c - '0';
c++;
}
return n;
}

8
kernel/src/lib/string.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
int strlen(const char *str);
int strcmp(const char *s1, const char *s2);
char *strchr(const char *s, int c);
char *strcpy(char *dest, const char *src);
char *strrchr(const char *s, int c);
int oct2bin(unsigned char *str, int size);

View file

@ -1,5 +1,7 @@
#include "exec/elf.h"
#include "exec/exec.h"
#include "fs/tapefs.h"
#include "fs/vfs.h"
#include "mm/liballoc/liballoc.h"
#include "mm/pmm.h"
#include "mm/vma.h"
@ -11,29 +13,22 @@
#include "sys/syscall.h"
#include <font.h>
#include <limine.h>
#include <mm/memop.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/arch/x86_64/fpu.h>
#include <sys/arch/x86_64/gdt.h>
#include <sys/arch/x86_64/idt.h>
#include <sys/error_handling/panic.h>
#include <sys/gfx/flanterm/backends/fb.h>
#include <sys/gfx/flanterm/flanterm.h>
#include <sys/log.h>
#include <sys/printf.h>
// Set the base revision to 3, this is recommended as this is the latest
// base revision described by the Limine boot protocol specification.
// See specification for further info.
__attribute__((
used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
// The Limine requests can be placed anywhere, but it is important that
// the compiler does not optimise them away, so, usually, they should
// be made volatile or equivalent, _and_ they should be accessed at least
// once or marked as used with the "used" attribute as done here.
__attribute__((
used,
section(
@ -45,14 +40,6 @@ __attribute__((
section(".limine_requests"))) static volatile struct limine_module_request
module_request = {.id = LIMINE_MODULE_REQUEST, .revision = 0};
/*__attribute__((used, section(".limine_requests")))
static volatile struct limine_entry_point_request entrypoint_request = {
.id = LIMINE_ENTRY_POINT_REQUEST,
.revision = 3
};*/
// Finally, define the start and end markers for the Limine requests.
// These can also be moved anywhere, to any .c file, as seen fit.
__attribute__((used,
section(".limine_requests_"
"start"))) static volatile LIMINE_REQUESTS_START_MARKER;
@ -62,38 +49,14 @@ __attribute__((
section(
".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER;
// Halt and catch fire function.
static void hcf(void) {
for (;;) {
#if defined(__x86_64__)
asm("hlt");
#elif defined(__aarch64__) || defined(__riscv)
asm("wfi");
#elif defined(__loongarch64)
asm("idle 0");
#endif
}
}
struct limine_framebuffer *fb;
struct flanterm_context *ft_ctx;
uint32_t fg = 0xFFFFFF;
char kstack[8192];
// The following will be our kernel's entry point.
// If renaming kmain() to something else, make sure to change the
// linker script accordingly.
void kmain(void) {
// Ensure the bootloader actually understands our base revision (see spec).
/*if (LIMINE_BASE_REVISION_SUPPORTED == false) {
hcf();
}*/
// Ensure we got a framebuffer.
if (framebuffer_request.response != NULL) {
// Fetch the first framebuffer.
struct limine_framebuffer *framebuffer =
framebuffer_request.response->framebuffers[0];
fb = framebuffer;
@ -103,12 +66,11 @@ void kmain(void) {
framebuffer->height, framebuffer->pitch, framebuffer->red_mask_size,
framebuffer->red_mask_shift, framebuffer->green_mask_size,
framebuffer->green_mask_shift, framebuffer->blue_mask_size,
framebuffer->blue_mask_shift, NULL, NULL, NULL, NULL, &fg, NULL, NULL,
framebuffer->blue_mask_shift, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
VGA8, 8, 16, 0, 0, 0, 0);
}
printf("\n Soaplin 1.0-sild is booting up your computer...\n\n");
// printf("Physical kernel EP: %p", entrypoint_request.entry);
gdt_init(&kstack[8192]);
idt_init();
@ -125,21 +87,13 @@ void kmain(void) {
asm("hlt");
}
// acpi_init();
syscall_init();
pit_init(1000);
sched_init();
// user_init();
struct limine_file *f = module_request.response->modules[0];
log("kmain - %s\n", f->path);
program_t *prog = elf_load((char *)f->address, 1);
sched_create("Init", prog->entry, prog->pm, SCHED_USER_PROCESS);
log("kernel - Soaplin initialized sucessfully.\n");
while (1)
;
; //__asm__ volatile ("hlt");
;
}

View file

@ -211,8 +211,8 @@ void vmm_map_user(pagemap_t *pm, uint64_t vaddr, uint64_t paddr,
uint64_t pml2_entry = (vaddr >> 21) & 0x1ff;
uint64_t pml1_entry = (vaddr >> 12) & 0x1ff;
uint64_t *pml3 = __vmm_get_next_lvl(pm->toplevel, pml4_entry, flags | VMM_WRITABLE,
uint64_t *pml3 =
__vmm_get_next_lvl(pm->toplevel, pml4_entry, flags | VMM_WRITABLE,
true); // PML3 / Page Directory Pointer Entry
uint64_t *pml2 = __vmm_get_next_lvl(pml3, pml3_entry, flags | VMM_WRITABLE,
true); // PML2 / Page Directory Entry

View file

@ -4,6 +4,7 @@
#include "mm/vmm.h"
#include "sys/arch/x86_64/idt.h"
#include "sys/log.h"
#include <lib/string.h>
#include <stddef.h>
sched_process *proc_list;
@ -47,16 +48,11 @@ void sched_init() {
sched_process *sched_create(char *name, uint64_t entry_point, pagemap_t *pm,
uint32_t flags) {
// TODO: implement a separate strlen function
// as there's like 4 strlen impls in the kernel.
int i = 0;
while (name[i] != 0)
i++;
sched_process *proc = pmm_request_page();
memset(proc, 0, sizeof(sched_process));
memcpy(proc->name, name, i);
memcpy(proc->name, name, strlen(name) > 128 ? 128 : strlen(name));
proc->pid = current_pid;
proc->type = SCHED_RUNNING;
proc->flags = flags;
@ -141,7 +137,6 @@ void schedule(registers_t *regs) {
prev_proc->next = curr_proc->next;
// Now, it is safe to free the process's memory.
vmm_release_pm(curr_proc->pm);
pmm_free_page(curr_proc->stack_base_physical);
@ -155,15 +150,7 @@ void schedule(registers_t *regs) {
if (curr_proc == NULL)
curr_proc = proc_list;
//log("sched - I choosed process %d\n", curr_proc->pid);
//log("sched - I choosed process %d (pm: %s, rip: %p)\n", curr_proc->pid, curr_proc->pm == vmm_kernel_pm ? "kernel" : "user", curr_proc->regs.rip);
memcpy(regs, &curr_proc->regs, sizeof(registers_t));
// Finally, load our pagemap
// if (memcmp(curr_proc->name, "Init", 4)== 0) {
vmm_load_pagemap(curr_proc->pm);
// asm("cli");
// while (1)
// asm("hlt");}
}

View file

@ -1,5 +1,3 @@
// #include "mm/pmm.h"
// #include "mm/vmm.h"
#include "mm/pmm.h"
#include "mm/vmm.h"
#include "sched/sched.h"
@ -7,39 +5,20 @@
#include "sys/arch/x86_64/rtc.h"
#include "sys/log.h"
#include "sys/syscall.h"
// #include "sys/sched.h"
#include <stdint.h>
#include <sys/arch/x86_64/idt.h>
#include <sys/arch/x86_64/io.h>
// #include <sys/errhand/panic.h>
int pit_millis = 0;
int pit_secs = 0;
extern int vmm_kernel_pm_exists;
struct Idt_StackFrame {
struct Idt_StackFrame *rbp;
uint64_t rip;
} __attribute__((packed));
void dump_backtrace(registers_t *r) {
log("ints - backtrace : \n");
struct Idt_StackFrame *frame = (struct Idt_StackFrame *)r->rbp;
while (frame) {
log("ints - %s (ip: %p)\n", frame->rip);
frame = frame->rbp;
}
log("ints - <end of backtrace>\n");
}
void pit_handler(registers_t *regs);
void exception_handler(registers_t *regs) {
vmm_load_pagemap(vmm_kernel_pm);
if (regs->int_no < 32) {
// panic(kmode_cpu_exception, regs);
log("ints - %d (RIP: %p, ERR: %d)\n", regs->int_no, regs->rip,
regs->err_code);
@ -53,7 +32,6 @@ void exception_handler(registers_t *regs) {
log("ints - PF: Faulting page map: %p\n", PHYSICAL(vmm_current_pm));
}
// dump_backtrace(regs);
asm("cli");
while (1)
asm("hlt");
@ -73,7 +51,6 @@ void exception_handler(registers_t *regs) {
} else if (regs->int_no == 0x80) {
syscall_handle(regs);
}
// logln(info, "arch/ints", "Received interrupt %d\n", regs->int_no);
//vmm_load_pagemap(curr_proc->pm);
pic_ack(regs->int_no - 32);
}

View file

@ -1 +1,75 @@
void panic_ctx() {}
#include "sys/arch/x86_64/idt.h"
#include <sys/log.h>
static registers_t __panic_regdump;
static void __panic_dump_regs() {
asm volatile(
// Save general purpose registers
"movq %%r15, %0\n\t"
"movq %%r14, %1\n\t"
"movq %%r13, %2\n\t"
"movq %%r12, %3\n\t"
"movq %%r11, %4\n\t"
"movq %%r10, %5\n\t"
"movq %%r9, %6\n\t"
"movq %%r8, %7\n\t"
"movq %%rdi, %8\n\t"
"movq %%rsi, %9\n\t"
"movq %%rbp, %10\n\t"
"movq %%rbx, %11\n\t"
"movq %%rdx, %12\n\t"
"movq %%rcx, %13\n\t"
"movq %%rax, %14\n\t"
// The rest of the registers (rip, cs, rflags, rsp, ss) would typically
// be captured in the interrupt/exception handler context and passed in
// We'll zero them out here since we don't have direct access
: "=m"(__panic_regdump.r15), "=m"(__panic_regdump.r14),
"=m"(__panic_regdump.r13), "=m"(__panic_regdump.r12),
"=m"(__panic_regdump.r11), "=m"(__panic_regdump.r10),
"=m"(__panic_regdump.r9), "=m"(__panic_regdump.r8),
"=m"(__panic_regdump.rdi), "=m"(__panic_regdump.rsi),
"=m"(__panic_regdump.rbp), "=m"(__panic_regdump.rbx),
"=m"(__panic_regdump.rdx), "=m"(__panic_regdump.rcx),
"=m"(__panic_regdump.rax)
:
: "memory");
// Zero out the registers we can't directly access in this context
__panic_regdump.int_no = 0;
__panic_regdump.err_code = 0;
__panic_regdump.rip = 0;
__panic_regdump.cs = 0;
__panic_regdump.rflags = 0;
__panic_regdump.rsp = 0;
__panic_regdump.ss = 0;
}
void panic() {
__panic_dump_regs();
log(" _ __ _ ___ _ \n");
log("| |/ /___ _ _ _ _ ___| | | _ \\__ _ _ _ (_)__ \n");
log("| ' </ -_) '_| ' \\/ -_) | | _/ _` | ' \\| / _|_ _ _ \n");
log("|_|\\_\\___|_| |_||_\\___|_| |_| \\__,_|_||_|_\\__(_|_|_)\n");
log("\n");
log("Due to an error that can't be recovered from, Soaplin was needed to "
"halt the PC.\n");
log("Please report this error to the Soaplin developers, along with the "
"information provided below:\n");
log("-- REGISTER DUMP --\n");
log("RDI: %p, RSI: %p, RDX: %p, RCX: %p, R8: %p, R9: %p\n",
__panic_regdump.rdi, __panic_regdump.rsi, __panic_regdump.rdx,
__panic_regdump.rcx, __panic_regdump.r8, __panic_regdump.r9);
log("RAX: %p, RBP: %p, RBX: %p, R10: %p, R11: %p, R12: %p\n",
__panic_regdump.rax, __panic_regdump.rbp, __panic_regdump.rbx,
__panic_regdump.r10, __panic_regdump.r11, __panic_regdump.r12);
log("R13: %p, R14: %p, R15: %p\n", __panic_regdump.r13, __panic_regdump.r14,
__panic_regdump.r15);
log("System halted.");
asm("cli");
for (;;)
asm("hlt");
}

View file

@ -0,0 +1 @@
void panic();

View file

@ -45,11 +45,11 @@ extern "C" {
struct flanterm_context *flanterm_fb_init(
/* If _malloc and _free are nulled, use the bump allocated instance (1 use
only). */
void *(*_malloc)(size_t size),
void (*_free)(void *ptr, size_t size), uint32_t *framebuffer, size_t width,
size_t height, size_t pitch, uint8_t red_mask_size, uint8_t red_mask_shift,
uint8_t green_mask_size, uint8_t green_mask_shift, uint8_t blue_mask_size,
uint8_t blue_mask_shift, uint32_t *canvas, /* If nulled, no canvas. */
void *(*_malloc)(size_t size), void (*_free)(void *ptr, size_t size),
uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
uint8_t red_mask_size, uint8_t red_mask_shift, uint8_t green_mask_size,
uint8_t green_mask_shift, uint8_t blue_mask_size, uint8_t blue_mask_shift,
uint32_t *canvas, /* If nulled, no canvas. */
uint32_t *ansi_colours,
uint32_t *ansi_bright_colours, /* If nulled, default. */
uint32_t *default_bg, uint32_t *default_fg, /* If nulled, default. */

View file

@ -1,6 +1,7 @@
#include "sys/arch/x86_64/io.h"
#include "sys/gfx/flanterm/flanterm.h"
#include <lib/spinlock.h>
#include <lib/string.h>
#include <stdarg.h>
#include <sys/printf.h>
@ -14,12 +15,8 @@ void log(char *format, ...) {
// TODO: replace this call with a call to printf() when the RTC is
// implemented.
char *date = "1970-01-01 00:00:00 | ";
int i2 = 0;
for (i2; date[i2] != 0; i2++)
;
;
if (ft_ctx)
flanterm_write(ft_ctx, date, i2);
flanterm_write(ft_ctx, date, strlen(date));
char buf[2048];
va_list l;
@ -27,14 +24,10 @@ void log(char *format, ...) {
npf_vsnprintf(buf, 2048, format, l);
va_end(l);
int i = 0;
for (i; buf[i] != 0; i++)
;
;
if (ft_ctx)
flanterm_write(ft_ctx, buf, i);
flanterm_write(ft_ctx, buf, strlen(buf));
for (int i = 0;; i++) {
/*for (int i = 0;; i++) {
if (date[i] == '\0')
break;
@ -46,7 +39,7 @@ void log(char *format, ...) {
break;
outb(0xE9, buf[i]);
}
}*/
// spinlock_release(&log_lock);
}

View file

@ -2,6 +2,7 @@
// This code is part of the Soaplin kernel and is licensed under the terms of
// the MIT License.
#include "sys/gfx/flanterm/flanterm.h"
#include <lib/string.h>
#include <stdarg.h>
#define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1
@ -25,11 +26,6 @@ void printf(char *format, ...) {
va_end(lst);
// rt_print(buf);
int i = 0;
for (i; buf[i] != 0; i++)
;
;
if (ft_ctx)
flanterm_write(ft_ctx, buf, i);
flanterm_write(ft_ctx, buf, strlen(buf));
}

View file

@ -6,4 +6,4 @@ verbose: yes
protocol: limine
path: boot():/boot/soaplin
module_path: boot():/sk-hello.elf
module_path: boot():/initramfs.tar