From 1dd4e728d41265ac3cfe819eb87b9a2917e92c54 Mon Sep 17 00:00:00 2001 From: xamidev Date: Wed, 11 Mar 2026 14:59:20 +0100 Subject: [PATCH 1/6] Build folder + coding style guidelines --- .gitignore | 3 +- DOOM.txt | 24 --------------- Makefile | 21 ++++++++----- docs/STYLE.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ test.bin | 1 - 5 files changed, 98 insertions(+), 34 deletions(-) delete mode 100644 DOOM.txt create mode 100644 docs/STYLE.md delete mode 100644 test.bin diff --git a/.gitignore b/.gitignore index 8120a94..8de7009 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ iso_root .gdb_history symbols.map symbols.S -*.log \ No newline at end of file +*.log +build/ \ No newline at end of file diff --git a/DOOM.txt b/DOOM.txt deleted file mode 100644 index 4f1aa83..0000000 --- a/DOOM.txt +++ /dev/null @@ -1,24 +0,0 @@ -up to doom: - -- Return from pedicel_main() normally (to idle) - -** Checkpoint: ring0 process working - -- VFS layer (open/read/write/...) with USTar filesystem (for initrd) - -** Checkpoint: files not linked to but accessible by the kernel - -- Ring3 memory mappings -- Ring3 privilege switch - -** Checkpoint: welcome to userland - -- Syscall interface -- Implement syscalls needed for doom - -** Checkpoint: can run simple programs, ring 3, loaded from filesystem - -- Properly handle the keyboard interrupt (keyboard buffer) -- Port DOOMgeneric (few functions with Framebuffer/ticks/etc.) - -** Achievement: It runs doom! diff --git a/Makefile b/Makefile index e0bc1e9..4a0a45c 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,21 @@ SOURCES = src/debug/misc.c src/io/term/flanterm_backends/fb.c src/io/term/flanterm.c src/debug/panic.c src/debug/stacktrace.c src/boot/boot.c src/sched/scheduler.c src/sched/process.c src/mem/heap/kheap.c src/mem/paging/vmm.c src/mem/paging/paging.c src/mem/paging/pmm.c src/string/string.c src/io/kbd/ps2.c src/io/serial/serial.c src/io/term/printf.c src/io/term/term.c src/idt/idt.c src/mem/gdt/gdt.c src/mem/misc/utils.c src/time/timer.c src/kmain.c -PROBLEMATIC_FLAGS=-Wno-unused-parameter -Wno-unused-variable +CC_FLAGS=-Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel +CC_PROBLEMATIC_FLAGS=-Wno-unused-parameter -Wno-unused-variable + +.PHONY: build build-iso debug debug2 run clean build: - rm -f *.o - x86_64-elf-gcc -g -c -Isrc $(SOURCES) $(PROBLEMATIC_FLAGS) -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel - nasm -f elf64 src/idt/idt.S -o idt_stub.o - x86_64-elf-ld -o pepperk -T linker.ld *.o + mkdir -p build + rm -f *.o build/*.o + x86_64-elf-gcc -g -c -Isrc $(SOURCES) $(CC_PROBLEMATIC_FLAGS) $(CC_FLAGS) + mv *.o build/ + nasm -f elf64 src/idt/idt.S -o build/idt_stub.o + x86_64-elf-ld -o pepperk -T linker.ld build/*.o nm -n pepperk | awk '$$2 ~ /[TtDdBbRr]/ {print $$1, $$3}' > symbols.map python3 symbols.py - nasm -f elf64 symbols.S -o symbols.o - x86_64-elf-ld -o pepperk -T linker.ld *.o + nasm -f elf64 symbols.S -o build/symbols.o + x86_64-elf-ld -o pepperk -T linker.ld build/*.o limine/limine: rm -rf limine @@ -46,4 +51,4 @@ run: build-iso /usr/bin/qemu-system-x86_64 -cdrom pepper.iso -serial stdio clean: - rm -rf *.o symbols.map symbols.S pepperk iso_root pepper.iso limine + rm -rf *.o symbols.map symbols.S pepperk iso_root pepper.iso limine build/*.o diff --git a/docs/STYLE.md b/docs/STYLE.md new file mode 100644 index 0000000..c7db749 --- /dev/null +++ b/docs/STYLE.md @@ -0,0 +1,83 @@ +# Pepper kernel coding style + +This document describes the coding style for the Pepper kernel. It is used as a guideline across all source files. + +## Indentation + +Indentations should be 4 characters long. + +## Line length + +Lines should not be more than 100 characters long. + +## Variables + +Variables should be declared at most once per line. + +## Braces + +Non-function statement blocks should have an opening brace last on the line, and a closing brace first. Exception is made for `else`, `else if` statements and the like: + +```c +if (something) { + do_something(); +} else if (something_else) { + do_something_else(); +} +``` + +Functions should have their opening brace on a separate line, and the same goes for the closing brace: + +```c +void function() +{ + do_something(); +} +``` + +## Spaces + +Use a space after `if, switch, case, for, do, while` keywords, but not for `sizeof, typeof, alignof, __attribute__` and the like. + +For pointers, the asterisk should always be placed adjacent to the type name, like `char* str;`. + +## Naming + +Functions should be named with whole words, beginning with the corresponding name of the module in the kernel (the parent folder). Words should be spaced with underscores, like so: + +```c +serial_init(void* ptr, char* str, int foo); +``` + +Constants should be named in all caps, separated by underscores: + +```c +#define MAX_HEAP_SIZE 0x1000 +``` + +Global variables need to have descriptive names. Local variables can be kept short (especially for loop counters). + +## Typedefs + +Structures should not be `typedef`'d. + +## Functions + +Functions should be short, simple, and only do one thing. + +Function prototypes should include parameter names and their data types. + +## Commenting + +Comments should describe what a function does and why, not how it does it. + +```c +/* + * This is the preferred style for multi-line + * comments in the Pepper kernel + */ +``` + +### Resources + +Some of the elements here are inspired by the [Linux kernel coding style](https://www.kernel.org/doc/html/v4.10/process/coding-style.html). \ No newline at end of file diff --git a/test.bin b/test.bin deleted file mode 100644 index 60f94fd..0000000 --- a/test.bin +++ /dev/null @@ -1 +0,0 @@ -ΈοΎ­ήλώ \ No newline at end of file From 9d409317e224a2a537524462b9267a456393dc10 Mon Sep 17 00:00:00 2001 From: xamidev Date: Wed, 11 Mar 2026 15:24:45 +0100 Subject: [PATCH 2/6] DEBUG with Capital Letters --- docs/STYLE.md | 4 ++++ src/debug/misc.c | 4 ++-- src/debug/panic.c | 8 ++++---- src/idt/idt.c | 44 ++++++++++++++++++++--------------------- src/mem/paging/paging.c | 11 +---------- src/mem/paging/pmm.c | 3 +-- src/sched/scheduler.c | 2 +- 7 files changed, 34 insertions(+), 42 deletions(-) diff --git a/docs/STYLE.md b/docs/STYLE.md index c7db749..7055ccc 100644 --- a/docs/STYLE.md +++ b/docs/STYLE.md @@ -78,6 +78,10 @@ Comments should describe what a function does and why, not how it does it. */ ``` +## Kernel messages + +When printing kernel messages with the `DEBUG` macro, they should start with a capital letter. + ### Resources Some of the elements here are inspired by the [Linux kernel coding style](https://www.kernel.org/doc/html/v4.10/process/coding-style.html). \ No newline at end of file diff --git a/src/debug/misc.c b/src/debug/misc.c index 5cba142..eb7392e 100644 --- a/src/debug/misc.c +++ b/src/debug/misc.c @@ -43,7 +43,7 @@ void memmap_display(struct limine_memmap_response* response) strcpy(type, "UNKNOWN"); break; } - DEBUG("entry %02u: [0x%016x | %016u bytes] - %s", i, entry->base, entry->length, type); + DEBUG("Entry %02u: [0x%016x | %016u bytes] - %s", i, entry->base, entry->length, type); } } @@ -57,5 +57,5 @@ void boot_mem_display() { memmap_display(boot_ctx.mmap); hhdm_display(boot_ctx.hhdm); - DEBUG("kernel: phys_base=0x%p virt_base=0x%p", boot_ctx.kaddr->physical_base, boot_ctx.kaddr->virtual_base); + DEBUG("Kernel is at phys_base=0x%p virt_base=0x%p", boot_ctx.kaddr->physical_base, boot_ctx.kaddr->virtual_base); } \ No newline at end of file diff --git a/src/debug/panic.c b/src/debug/panic.c index fce9bbe..f770ac7 100644 --- a/src/debug/panic.c +++ b/src/debug/panic.c @@ -20,13 +20,13 @@ void panic(struct cpu_status_t* ctx, const char* str) if (init.terminal) { - printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m Something went horribly wrong! (no cpu ctx)"); - printf("\r\n%s\r\n\x1b[38;5;231m\x1b[48;5;196mend Kernel panic - halting...\x1b[0m", str); + printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[48;5;232m Something went horribly wrong! (no cpu ctx)"); + printf("\r\n%s\r\n\x1b[38;5;231mend Kernel panic - halting...\x1b[0m", str); } hcf(); } - DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m at rip=%p\r\nSomething went horribly wrong! (%s) vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p r8=%p r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p\n\rHalting...", + DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m at rip=%p\r\nSomething went horribly wrong! (%s) vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p r8=%p r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p\n\rHalting...\x1b[0m", ctx->iret_rip, str, ctx->vector_number, ctx->error_code, ctx->rax, ctx->rbx, ctx->rcx, ctx->rdx, ctx->rsi, ctx->rdi, @@ -34,7 +34,7 @@ void panic(struct cpu_status_t* ctx, const char* str) if (init.terminal) { - printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m at rip=%p\r\nSomething went horribly wrong! (%s) vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p r8=%p r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p\n\rHalting...", + printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[48;5;232mat rip=%p\r\nSomething went horribly wrong! (%s) vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p r8=%p r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p\n\rHalting...\x1b[0m", ctx->iret_rip, str, ctx->vector_number, ctx->error_code, ctx->rax, ctx->rbx, ctx->rcx, ctx->rdx, ctx->rsi, ctx->rdi, diff --git a/src/idt/idt.c b/src/idt/idt.c index 5b9504b..9203c54 100644 --- a/src/idt/idt.c +++ b/src/idt/idt.c @@ -126,72 +126,70 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) switch(context->vector_number) { case 0: - DEBUG("Divide Error!"); + panic(context, "Divide Error"); break; case 1: - DEBUG("Debug Exception!"); + panic(context, "Debug Exception"); break; case 2: - DEBUG("NMI Interrupt!"); + panic(context, "NMI Interrupt"); break; case 3: - DEBUG("Breakpoint Interrupt!"); + panic(context, "Breakpoint Interrupt"); break; case 4: - DEBUG("Overflow Trap!"); + panic(context, "Overflow Trap"); break; case 5: - DEBUG("BOUND Range Exceeded!"); + panic(context, "BOUND Range Exceeded"); break; case 6: - DEBUG("Invalid Opcode!"); - panic(context, "Invalid Opcode!"); + panic(context, "Invalid Opcode"); break; case 7: - DEBUG("Device Not Available!"); + panic(context, "Device Not Available"); break; case 8: - DEBUG("Double Fault!"); + panic(context, "Double Fault"); break; case 9: - DEBUG("Coprocessor Segment Overrun!"); + panic(context, "Coprocessor Segment Overrun"); break; case 10: - DEBUG("Invalid TSS!"); + panic(context, "Invalid TSS"); break; case 11: - DEBUG("Segment Not Present!"); + panic(context, "Segment Not Present"); break; case 12: - DEBUG("Stack-Segment Fault!"); + panic(context, "Stack-Segment Fault"); break; case 13: gp_fault_handler(context); break; case 14: - // Better debugging for page faults... page_fault_handler(context); break; case 15: - DEBUG("Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)"); + panic(context, "Intel Reserved Interrupt (Achievement unlocked: How Did We Get Here?)"); break; case 16: - DEBUG("x87 Floating-Point Error!"); + panic(context, "x87 Floating-Point Error"); break; case 17: - DEBUG("Alignment Check Fault!"); + panic(context, "Alignment Check Fault"); break; case 18: - DEBUG("Machine Check!"); + panic(context, "Machine Check"); break; case 19: - DEBUG("SIMD Floating-Point Exception!"); + panic(context, "SIMD Floating-Point Exception"); break; case 20: - DEBUG("Virtualization Exception!"); + panic(context, "Virtualization Exception"); break; case 21: - DEBUG("Control Protection Exception!"); + panic(context, "Control Protection Exception"); break; case 32: // Timer Interrupt @@ -213,7 +211,7 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) break; default: - DEBUG("Unexpected interrupt"); + DEBUG("Unexpected Interrupt"); break; } diff --git a/src/mem/paging/paging.c b/src/mem/paging/paging.c index 4128b14..ba61b55 100644 --- a/src/mem/paging/paging.c +++ b/src/mem/paging/paging.c @@ -141,7 +141,6 @@ void paging_init() { max_phys = top; } - //DEBUG("max_phys=0x%p", max_phys); } // 4GB @@ -187,15 +186,7 @@ void paging_init() } DEBUG("Mapped %u pages for framebuffer", page_count); - // test for flanterm - // When 10 pages are mapped, SOMETIMES (1 out of 50 times) it prints everything without problem! - // Other times it prints garbage (almost full cursors) and/or panics. -/* for (uint64_t i=0; i<10; i++) - { - paging_map_page(kernel_pml4, 0, kernel_phys_base+KERNEL_SIZE+i*PAGE_SIZE, PTE_WRITABLE); - } */ - // Finally, we load the physical address of our PML4 (root table) into cr3 load_cr3(VIRT_TO_PHYS(kernel_pml4)); - DEBUG("cr3 loaded, we're still alive"); + DEBUG("Loaded kernel PML4 into CR3"); } \ No newline at end of file diff --git a/src/mem/paging/pmm.c b/src/mem/paging/pmm.c index 2b45699..472ccfa 100644 --- a/src/mem/paging/pmm.c +++ b/src/mem/paging/pmm.c @@ -102,8 +102,7 @@ void pmm_init(struct limine_memmap_response* memmap, struct limine_hhdm_response { hhdm_off = hhdm->offset; pmm_find_biggest_usable_region(memmap, hhdm); - //pmm_allocate_bitmap(hhdm); too complicated for my small brain - + // Now we have biggest USABLE region, // so to populate the free list we just iterate through it pmm_init_freelist(); diff --git a/src/sched/scheduler.c b/src/sched/scheduler.c index 14a3fe0..528e769 100644 --- a/src/sched/scheduler.c +++ b/src/sched/scheduler.c @@ -61,7 +61,7 @@ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context) DEBUG("current_process={pid=%u, name='%s', root_page_table[virt]=%p}", current_process->pid, current_process->name, current_process->root_page_table); load_cr3(VIRT_TO_PHYS((uint64_t)current_process->root_page_table)); - DEBUG("loaded process pml4 into cr3"); + DEBUG("Loaded process PML4 into CR3"); return current_process->context; } \ No newline at end of file From 8e2a612d88538971c8166e2b3244bc9d390b20fc Mon Sep 17 00:00:00 2001 From: xamidev Date: Wed, 11 Mar 2026 19:58:00 +0100 Subject: [PATCH 3/6] Fix braces + init_paging args --- docs/STYLE.md | 4 ++- src/boot/boot.c | 4 --- src/config.h | 4 +++ src/debug/misc.c | 12 ++++++--- src/debug/panic.c | 15 ++++++----- src/debug/stacktrace.c | 45 ++++++++++++++++----------------- src/idt/idt.c | 18 +++++--------- src/idt/idt.h | 9 +++---- src/io/kbd/ps2.c | 28 +++++++-------------- src/io/kbd/ps2.h | 9 +++---- src/io/serial/serial.c | 9 ++----- src/io/serial/serial.h | 3 +++ src/io/term/term.c | 3 +-- src/kernel.h | 9 +++---- src/kmain.c | 7 +++--- src/mem/gdt/gdt.h | 3 +-- src/mem/heap/kheap.c | 22 ++++++----------- src/mem/heap/kheap.h | 3 +-- src/mem/misc/utils.c | 24 ++++++------------ src/mem/paging/paging.c | 55 ++++++++++++++--------------------------- src/mem/paging/paging.h | 3 ++- src/mem/paging/pmm.c | 19 ++++++-------- src/mem/paging/pmm.h | 3 ++- src/mem/paging/vmm.h | 3 +-- src/sched/process.c | 27 ++++++-------------- src/sched/process.h | 6 ++--- src/sched/scheduler.c | 18 +++++--------- src/string/string.c | 8 +++--- src/time/timer.c | 3 +-- 29 files changed, 147 insertions(+), 229 deletions(-) diff --git a/docs/STYLE.md b/docs/STYLE.md index 7055ccc..c463c98 100644 --- a/docs/STYLE.md +++ b/docs/STYLE.md @@ -26,6 +26,8 @@ if (something) { } ``` +Having no braces for a single statement structure is fine. + Functions should have their opening brace on a separate line, and the same goes for the closing brace: ```c @@ -59,7 +61,7 @@ Global variables need to have descriptive names. Local variables can be kept sho ## Typedefs -Structures should not be `typedef`'d. +Structures should not be `typedef`'d. However using `typedef` for an enumeration is fine. ## Functions diff --git a/src/boot/boot.c b/src/boot/boot.c index f10c4e1..20abcd1 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -6,28 +6,24 @@ #include -// Framebuffer request __attribute__((used, section(".limine_requests"))) volatile struct limine_framebuffer_request framebuffer_request = { .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0 }; -// Memory map request __attribute__((used, section(".limine_requests"))) volatile struct limine_memmap_request memmap_request = { .id = LIMINE_MEMMAP_REQUEST, .revision = 0 }; -// Higher Half Direct Map __attribute__((used, section(".limine_requests"))) volatile struct limine_hhdm_request hhdm_request = { .id = LIMINE_HHDM_REQUEST, .revision = 0 }; -// Executable Address/Kernel Address (find base phys/virt address of kernel) __attribute__((used, section(".limine_requests"))) volatile struct limine_kernel_address_request kerneladdr_request = { .id = LIMINE_KERNEL_ADDRESS_REQUEST, diff --git a/src/config.h b/src/config.h index d243f93..61cd7a7 100644 --- a/src/config.h +++ b/src/config.h @@ -28,6 +28,10 @@ // 2 MB should be enough (as of now, the whole kernel ELF is around 75kb) #define KERNEL_SIZE 0x200000 #define KERNEL_STACK_SIZE 65536 +#define KERNEL_IDT_ENTRIES 33 + +/* paging */ +#define PAGING_MAX_PHYS 0x100000000 /* heap */ #define KHEAP_SIZE (32*1024*1024) diff --git a/src/debug/misc.c b/src/debug/misc.c index eb7392e..19c076f 100644 --- a/src/debug/misc.c +++ b/src/debug/misc.c @@ -1,3 +1,9 @@ +/* + * @author xamidev + * @brief Miscellaneous debug features + * @license GPL-3.0-only + */ + #include #include "limine.h" #include "string/string.h" @@ -9,12 +15,10 @@ void memmap_display(struct limine_memmap_response* response) { DEBUG("Got memory map from Limine: revision %u, %u entries", response->revision, response->entry_count); - for (size_t i=0; ientry_count; i++) - { + for (size_t i=0; ientry_count; i++) { struct limine_memmap_entry* entry = response->entries[i]; char type[32] = {0}; - switch(entry->type) - { + switch(entry->type) { case LIMINE_MEMMAP_USABLE: strcpy(type, "USABLE"); break; diff --git a/src/debug/panic.c b/src/debug/panic.c index f770ac7..e1cf694 100644 --- a/src/debug/panic.c +++ b/src/debug/panic.c @@ -1,3 +1,9 @@ +/* + * @author xamidev + * @brief Kernel panic + * @license GPL-3.0-only + */ + #include #include "idt/idt.h" #include "io/serial/serial.h" @@ -8,8 +14,7 @@ extern struct init_status init; void panic(struct cpu_status_t* ctx, const char* str) { CLEAR_INTERRUPTS; - if (ctx == NULL) - { + if (ctx == NULL) { DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m Something went horribly wrong! (no cpu ctx)"); fctprintf((void*)&skputc, 0, "\x1b[38;5;231m\x1b[48;5;27m"); DIE_DEBUG(str); @@ -18,8 +23,7 @@ void panic(struct cpu_status_t* ctx, const char* str) skputc('\n'); DEBUG("\x1b[38;5;231m\x1b[48;5;196mend Kernel panic - halting...\x1b[0m"); - if (init.terminal) - { + if (init.terminal) { printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[48;5;232m Something went horribly wrong! (no cpu ctx)"); printf("\r\n%s\r\n\x1b[38;5;231mend Kernel panic - halting...\x1b[0m", str); } @@ -32,8 +36,7 @@ void panic(struct cpu_status_t* ctx, const char* str) ctx->vector_number, ctx->error_code, ctx->rax, ctx->rbx, ctx->rcx, ctx->rdx, ctx->rsi, ctx->rdi, ctx->r8, ctx->r9, ctx->r10, ctx->r11, ctx->r12, ctx->r13, ctx->r14, ctx->r15, ctx->iret_flags); - if (init.terminal) - { + if (init.terminal) { printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[48;5;232mat rip=%p\r\nSomething went horribly wrong! (%s) vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p r8=%p r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p\n\rHalting...\x1b[0m", ctx->iret_rip, str, diff --git a/src/debug/stacktrace.c b/src/debug/stacktrace.c index d71ca3e..f1bca8e 100644 --- a/src/debug/stacktrace.c +++ b/src/debug/stacktrace.c @@ -1,3 +1,9 @@ +/* + * @author xamidev + * @brief Stack trace tools + * @license GPL-3.0-only + */ + #include #include "kernel.h" @@ -6,45 +12,39 @@ extern struct init_status init; void debug_stack_trace(unsigned int max_frames) { DEBUG("*** begin stack trace ***"); - if (init.terminal) - { + if (init.terminal) { printf("\r\n*** begin stack trace ***\r\n"); } // Thanks GCC :) uintptr_t* rbp = (uintptr_t*)__builtin_frame_address(0); - for (unsigned int frame=0; frame (%s+0x%x)", frame, (void*)rip, name, offset); - if (init.terminal) - { + if (init.terminal) { printf("[%u] <0x%p> (%s+0x%x)\r\n", frame, (void*)rip, name, offset); } uintptr_t* next_rbp = (uintptr_t*)rbp[0]; - // invalid rbp or we're at the end - if (next_rbp <= rbp || next_rbp == NULL) - { + // Invalid rbp or we're at the end + if (next_rbp <= rbp || next_rbp == NULL) { break; } rbp = next_rbp; } - if (init.terminal) - { + if (init.terminal) { printf("*** end stack trace ***"); } DEBUG("*** end stack trace ***"); } -typedef struct -{ +typedef struct { uint64_t addr; const char *name; } __attribute__((packed)) kernel_symbol_t; @@ -55,8 +55,7 @@ __attribute__((weak)) extern uint64_t symbol_count; // binary search const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset) { - if (!symbol_table || symbol_count == 0) - { + if (!symbol_table || symbol_count == 0) { if (offset) *offset = 0; return "???"; } @@ -64,11 +63,9 @@ const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset) int low = 0, high = (int)symbol_count - 1; int best = -1; - while (low <= high) - { + while (low <= high) { int mid = (low + high) / 2; - if (symbol_table[mid].addr <= rip) - { + if (symbol_table[mid].addr <= rip) { best = mid; low = mid + 1; } else { @@ -76,15 +73,15 @@ const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset) } } - if (best != -1) - { - if (offset) - { + if (best != -1) { + if (offset) { *offset = rip - symbol_table[best].addr; } return symbol_table[best].name; } - if (offset) *offset = 0; + if (offset) { + *offset = 0; + } return "unknown"; } \ No newline at end of file diff --git a/src/idt/idt.c b/src/idt/idt.c index 9203c54..ee1fa5c 100644 --- a/src/idt/idt.c +++ b/src/idt/idt.c @@ -53,8 +53,7 @@ void idt_load(void* idt_addr) void idt_init() { // Hardcoded... - for (size_t i=0; i<=33; i++) - { + for (size_t i=0; i<=KERNEL_IDT_ENTRIES; i++) { // Each vector handler is 16-byte aligned, so *16 = address of that handler idt_set_entry(i, vector_0_handler + (i*16), 0); } @@ -98,8 +97,7 @@ static void gp_fault_handler(struct cpu_status_t* ctx) (ctx->error_code == 0) ? "NOT_SEGMENT_RELATED" : "SEGMENT_RELATED"); // Segment-related - if (ctx->error_code != 0) - { + if (ctx->error_code != 0) { bool is_external = CHECK_BIT(ctx->error_code, 0); // is it IDT, GDT, LDT? uint8_t table = ctx->error_code & 0x6; // 0b110 (isolate table) @@ -118,13 +116,11 @@ static void gp_fault_handler(struct cpu_status_t* ctx) struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) { - if (context == NULL) - { + if (context == NULL) { panic(NULL, "Interrupt dispatch recieved NULL context!"); } - switch(context->vector_number) - { + switch(context->vector_number) { case 0: panic(context, "Divide Error"); break; @@ -197,15 +193,13 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) // Send an EOI so that we can continue having interrupts outb(0x20, 0x20); - if (ticks % SCHEDULER_QUANTUM == 0) - { + if (ticks % SCHEDULER_QUANTUM == 0) { return scheduler_schedule(context); } break; - case 33: - DEBUG("Keyboard Interrupt"); + case 33: // Keyboard Interrupt keyboard_handler(); outb(0x20, 0x20); break; diff --git a/src/idt/idt.h b/src/idt/idt.h index 898e49c..fab7853 100644 --- a/src/idt/idt.h +++ b/src/idt/idt.h @@ -11,8 +11,7 @@ void idt_init(); -struct interrupt_descriptor -{ +struct interrupt_descriptor { uint16_t address_low; uint16_t selector; uint8_t ist; @@ -22,8 +21,7 @@ struct interrupt_descriptor uint32_t reserved; } __attribute__((packed)); -struct idtr -{ +struct idtr { uint16_t limit; uint64_t base; } __attribute__((packed)); @@ -31,8 +29,7 @@ struct idtr // All general-purpose registers (except rsp) as stored on the stack, // plus the values we pushed (vector number, error code) and the iret frame // In reverse order because the stack grows downwards. -struct cpu_status_t -{ +struct cpu_status_t { uint64_t r15; uint64_t r14; uint64_t r13; diff --git a/src/io/kbd/ps2.c b/src/io/kbd/ps2.c index fdd1946..b28b31b 100644 --- a/src/io/kbd/ps2.c +++ b/src/io/kbd/ps2.c @@ -161,11 +161,9 @@ void keyboard_handler() unsigned char scancode = inb(0x60); // Key release (bit 7 set) - if (scancode & 0x80) - { + if (scancode & 0x80) { unsigned char code = scancode & 0x7F; - switch (code) - { + switch (code) { // Clear the corresponding bit if corresponding key is released case LEFT_SHIFT_PRESSED: case RIGHT_SHIFT_PRESSED: @@ -179,12 +177,9 @@ void keyboard_handler() break; } return; - } - else - { + } else { // Key press - switch (scancode) - { + switch (scancode) { // Set bits for corresponding special key press case LEFT_SHIFT_PRESSED: case RIGHT_SHIFT_PRESSED: @@ -200,15 +195,12 @@ void keyboard_handler() default: { // Avoiding buffer overflow from extended keys lol - if (scancode < 128) - { + if (scancode < 128) { // Should we get a SHIFTED char or a regular one? unsigned char c = (key_status & SHIFT_PRESSED_BIT) ? keymap_shifted[scancode] : keymap[scancode]; - if (c) - { - if (c == '\n') - { + if (c) { + if (c == '\n') { _putchar('\r'); } // Should probably have a keyboard buffer here... instead of this @@ -225,8 +217,7 @@ void keyboard_init(unsigned char layout) // Here we might go and select PS/2, USB, or other... (once we implement multiple keyboard protocols) // Keyboard layout selection - switch (layout) - { + switch (layout) { case US: keymap = kbdus; keymap_shifted = kbdus_shifted; @@ -242,8 +233,7 @@ void keyboard_init(unsigned char layout) } // Flush keyboard buffer - while (inb(0x64) & 1) - { + while (inb(0x64) & 1) { inb(0x60); } diff --git a/src/io/kbd/ps2.h b/src/io/kbd/ps2.h index 031fd91..a1d4860 100644 --- a/src/io/kbd/ps2.h +++ b/src/io/kbd/ps2.h @@ -13,15 +13,13 @@ void keyboard_handler(); #define ALT_PRESSED_BIT 0b00000010 #define CTRL_PRESSED_BIT 0b00000100 -enum SpecialKeys -{ +enum SpecialKeys { SHIFT = 255, ALT = 254, CTRL = 253 }; -enum SpecialScancodes -{ +enum SpecialScancodes { LEFT_SHIFT_PRESSED = 0x2A, LEFT_SHIFT_RELEASED = 0xAA, RIGHT_SHIFT_PRESSED = 0x36, @@ -32,8 +30,7 @@ enum SpecialScancodes ALT_RELEASED = 0xB8 }; -enum KeyboardLayout -{ +enum KeyboardLayout { US, FR }; diff --git a/src/io/serial/serial.c b/src/io/serial/serial.c index 8c8c9ac..fbf06c8 100644 --- a/src/io/serial/serial.c +++ b/src/io/serial/serial.c @@ -21,9 +21,6 @@ unsigned char inb(int port) return data; } -// COM1 -#define PORT 0x3F8 - int serial_init() { outb(PORT + 1, 0x00); // Disable all interrupts @@ -36,8 +33,7 @@ int serial_init() outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) - if (inb(PORT) != 0xAE) - { + if (inb(PORT) != 0xAE) { return -EIO; } @@ -66,8 +62,7 @@ void skputc(char c) void skputs(const char* str) { unsigned int i=0; - while (str[i]) - { + while (str[i]) { skputc(str[i]); i++; } diff --git a/src/io/serial/serial.h b/src/io/serial/serial.h index dc29d14..b60c488 100644 --- a/src/io/serial/serial.h +++ b/src/io/serial/serial.h @@ -7,6 +7,9 @@ #ifndef SERIAL_H #define SERIAL_H +// COM1 +#define PORT 0x3F8 + void outb(int port, unsigned char data); unsigned char inb(int port); diff --git a/src/io/term/term.c b/src/io/term/term.c index 89e5df9..cf90125 100644 --- a/src/io/term/term.c +++ b/src/io/term/term.c @@ -34,8 +34,7 @@ void _putchar(char character) void kputs(const char* str) { size_t i=0; - while (str[i] != 0) - { + while (str[i] != 0) { _putchar(str[i]); i++; } diff --git a/src/kernel.h b/src/kernel.h index f7dd570..0b276cc 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -7,8 +7,7 @@ #ifndef KERNEL_H #define KERNEL_H -enum ErrorCodes -{ +enum ErrorCodes { ENOMEM, EIO }; @@ -47,8 +46,7 @@ void boot_mem_display(); #define assert(check) do { if(!(check)) hcf(); } while(0) -struct boot_context -{ +struct boot_context { struct limine_framebuffer* fb; struct limine_memmap_response* mmap; struct limine_hhdm_response* hhdm; @@ -56,8 +54,7 @@ struct boot_context }; // Are these modules initialized yet? -struct init_status -{ +struct init_status { bool terminal; bool serial; bool keyboard; diff --git a/src/kmain.c b/src/kmain.c index 920639d..4ccd31b 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -65,8 +65,7 @@ void pedicel_main(void* arg) void idle_main(void* arg) { - for (;;) - { + for (;;) { asm("hlt"); } } @@ -89,10 +88,10 @@ void kmain() boot_ctx.kaddr = kerneladdr_request.response ? kerneladdr_request.response : NULL; boot_mem_display(); - pmm_init(boot_ctx.mmap, boot_ctx.hhdm); + pmm_init(boot_ctx); // Remap kernel , HHDM and framebuffer - paging_init(boot_ctx.kaddr, boot_ctx.fb); + paging_init(boot_ctx); kheap_init(); keyboard_init(FR); diff --git a/src/mem/gdt/gdt.h b/src/mem/gdt/gdt.h index a122387..33f744e 100644 --- a/src/mem/gdt/gdt.h +++ b/src/mem/gdt/gdt.h @@ -21,8 +21,7 @@ #define USER_CODE_SEGMENT 0x18 #define USER_DATA_SEGMENT 0x20 -struct GDTR -{ +struct GDTR { uint16_t limit; uint64_t address; } __attribute__((packed)); diff --git a/src/mem/heap/kheap.c b/src/mem/heap/kheap.c index b97f344..5393614 100644 --- a/src/mem/heap/kheap.c +++ b/src/mem/heap/kheap.c @@ -33,11 +33,9 @@ void kheap_init() uintptr_t current_addr = kheap_start; // Map/alloc enough pages for heap (KHEAP_SIZE) - for (size_t i=0; ifree && curr->size >= size) - { + if (curr->free && curr->size >= size) { // We split the block if it is big enough - if (curr->size >= size + sizeof(struct heap_block_t) + 16) - { - //struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size); + if (curr->size >= size + sizeof(struct heap_block_t) + 16) { struct heap_block_t* split = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size); split->size = curr->size - size - sizeof(struct heap_block_t); @@ -109,10 +103,8 @@ void kfree(void* ptr) // merge adjacent free blocks (coalescing) struct heap_block_t* curr = head; - while (curr && curr->next) - { - if (curr->free && curr->next->free) - { + while (curr && curr->next) { + if (curr->free && curr->next->free) { curr->size += sizeof(*curr) + curr->next->size; curr->next = curr->next->next; continue; diff --git a/src/mem/heap/kheap.h b/src/mem/heap/kheap.h index e59b204..52b9315 100644 --- a/src/mem/heap/kheap.h +++ b/src/mem/heap/kheap.h @@ -16,8 +16,7 @@ #include #include -struct heap_block_t -{ +struct heap_block_t { size_t size; bool free; // 1byte uint8_t reserved[7]; // (7+1 = 8 bytes) diff --git a/src/mem/misc/utils.c b/src/mem/misc/utils.c index bdd5f07..d43ec16 100644 --- a/src/mem/misc/utils.c +++ b/src/mem/misc/utils.c @@ -21,8 +21,7 @@ void* memcpy(void* restrict dest, const void* restrict src, size_t n) uint8_t* restrict pdest = (uint8_t* restrict)dest; const uint8_t* restrict psrc = (const uint8_t* restrict)src; - for (size_t i=0; i dest) - { - for (size_t i=0; i dest) { + for (size_t i=0; i0; i--) - { + } else if (src < dest) { + for (size_t i=n; i>0; i--) { pdest[i-1] = psrc[i-1]; } } @@ -67,10 +61,8 @@ int memcmp(const void* s1, const void* s2, size_t n) const uint8_t* p1 = (const uint8_t*)s1; const uint8_t* p2 = (const uint8_t*)s2; - for (size_t i=0; ientry_count; i++) - { + for (uint64_t i=0; ientry_count; i++) { struct limine_memmap_entry* entry = boot_ctx.mmap->entries[i]; - if (entry->length == 0) - { + if (entry->length == 0) { continue; } uint64_t top = entry->base + entry->length; - if (top > max_phys) - { + if (top > max_phys) { max_phys = top; } } // 4GB - if (max_phys > 0x100000000) - { - DEBUG("WARNING: max_phys capped to 4GB (0x100000000) (from max_phys=%p)", max_phys); - max_phys = 0x100000000; + if (max_phys > PAGING_MAX_PHYS) { + DEBUG("WARNING: max_phys capped to 4GB (%x) (from max_phys=%p)", PAGING_MAX_PHYS, max_phys); + max_phys = PAGING_MAX_PHYS; } - // HHDM map up to max_phys or 4GB, whichever is smaller, using given offset - for (uint64_t i=0; i #include #include "mem/heap/kheap.h" +#include -void paging_init(); +void paging_init(struct boot_context boot_ctx); void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags); // To swap root page tables diff --git a/src/mem/paging/pmm.c b/src/mem/paging/pmm.c index 472ccfa..db3a5e9 100644 --- a/src/mem/paging/pmm.c +++ b/src/mem/paging/pmm.c @@ -38,12 +38,10 @@ static void pmm_find_biggest_usable_region(struct limine_memmap_response* memmap uint64_t offset = hhdm->offset; DEBUG("Usable Memory:"); - for (size_t i=0; ientry_count; i++) - { + for (size_t i=0; ientry_count; i++) { struct limine_memmap_entry* entry = memmap->entries[i]; - if (entry->type == LIMINE_MEMMAP_USABLE) - { + if (entry->type == LIMINE_MEMMAP_USABLE) { DEBUG("0x%p-0x%p mapped at 0x%p-0x%p", entry->base, entry->base+entry->length, entry->base+offset, entry->base+entry->length+offset); if (entry->length > length_max) @@ -66,8 +64,7 @@ static uintptr_t g_freelist = 0; uintptr_t pmm_alloc() { - if (!g_freelist) - { + if (!g_freelist) { panic(NULL, "PMM is out of memory!"); } uintptr_t addr = g_freelist; @@ -89,19 +86,17 @@ static void pmm_init_freelist() uint64_t end = ALIGN_DOWN(biggest_entry->base + biggest_entry->length, PAGE_SIZE); uint64_t page_count=0; - for (uint64_t addr = base; addr < end; addr += PAGE_SIZE) - { + for (uint64_t addr = base; addr < end; addr += PAGE_SIZE) { pmm_free(addr); - //DEBUG("page %u lives at phys 0x%p (virt 0x%p)", page_count, addr, PHYS_TO_VIRT(addr)); page_count++; } DEBUG("%u frames in freelist, available for use (%u bytes)", page_count, page_count*PAGE_SIZE); } -void pmm_init(struct limine_memmap_response* memmap, struct limine_hhdm_response* hhdm) +void pmm_init(struct boot_context boot_ctx) { - hhdm_off = hhdm->offset; - pmm_find_biggest_usable_region(memmap, hhdm); + hhdm_off = boot_ctx.hhdm->offset; + pmm_find_biggest_usable_region(boot_ctx.mmap, boot_ctx.hhdm); // Now we have biggest USABLE region, // so to populate the free list we just iterate through it diff --git a/src/mem/paging/pmm.h b/src/mem/paging/pmm.h index a166727..90e2f54 100644 --- a/src/mem/paging/pmm.h +++ b/src/mem/paging/pmm.h @@ -8,8 +8,9 @@ #define PAGING_PMM_H #include +#include -void pmm_init(struct limine_memmap_response* memmap, struct limine_hhdm_response* hhdm); +void pmm_init(struct boot_context boot_ctx); void pmm_free(uintptr_t addr); uintptr_t pmm_alloc(); diff --git a/src/mem/paging/vmm.h b/src/mem/paging/vmm.h index b70e1a8..368a1f9 100644 --- a/src/mem/paging/vmm.h +++ b/src/mem/paging/vmm.h @@ -16,8 +16,7 @@ Flags here aren't x86 flags, they are platform-agnostic kernel-defined flags. */ -struct vm_object -{ +struct vm_object { uintptr_t base; size_t length; size_t flags; diff --git a/src/sched/process.c b/src/sched/process.c index 484f7dc..c4e879d 100644 --- a/src/sched/process.c +++ b/src/sched/process.c @@ -34,8 +34,7 @@ void process_display_list(struct process_t* processes_list) { int process_view_id = 0; struct process_t* tmp = processes_list; - while (tmp != NULL) - { + while (tmp != NULL) { DEBUG("{%d: %p} -> ", process_view_id, tmp); tmp = tmp->next; process_view_id++; @@ -47,7 +46,6 @@ struct process_t* process_create(char* name, void(*function)(void*), void* arg) { CLEAR_INTERRUPTS; struct process_t* proc = (struct process_t*)kmalloc(sizeof(struct process_t)); - struct cpu_status_t* ctx = (struct cpu_status_t*)kmalloc(sizeof(struct cpu_status_t)); // No more memory? @@ -88,29 +86,25 @@ void process_add(struct process_t** processes_list, struct process_t* process) if (!process) return; process->next = NULL; - if (*processes_list == NULL) - { + if (*processes_list == NULL) { // List is empty *processes_list = process; return; } struct process_t* tmp = *processes_list; - while (tmp->next != NULL) - { + while (tmp->next != NULL) { tmp = tmp->next; } // We're at last process before NULL tmp->next = process; - // process->next = NULL; } void process_delete(struct process_t** processes_list, struct process_t* process) { if (!processes_list || !*processes_list || !process) return; - if (*processes_list == process) - { + if (*processes_list == process) { // process to delete is at head *processes_list = process->next; process->next = NULL; @@ -119,13 +113,11 @@ void process_delete(struct process_t** processes_list, struct process_t* process } struct process_t* tmp = *processes_list; - while (tmp->next && tmp->next != process) - { + while (tmp->next && tmp->next != process) { tmp = tmp->next; } - if (tmp->next == NULL) - { + if (tmp->next == NULL) { // Didn't find the process return; } @@ -148,15 +140,12 @@ void process_exit() { DEBUG("Exiting from process '%s'", current_process->name); CLEAR_INTERRUPTS; - if (current_process) - { + if (current_process) { current_process->status = DEAD; } SET_INTERRUPTS; - //outb(0x20, 0x20); - for (;;) - { + for (;;) { asm("hlt"); } } \ No newline at end of file diff --git a/src/sched/process.h b/src/sched/process.h index 5209e65..cb080b3 100644 --- a/src/sched/process.h +++ b/src/sched/process.h @@ -11,15 +11,13 @@ #include "config.h" #include -typedef enum -{ +typedef enum { READY, RUNNING, DEAD } status_t; -struct process_t -{ +struct process_t { size_t pid; char name[PROCESS_NAME_MAX]; diff --git a/src/sched/scheduler.c b/src/sched/scheduler.c index 528e769..1c9dce0 100644 --- a/src/sched/scheduler.c +++ b/src/sched/scheduler.c @@ -22,13 +22,11 @@ void scheduler_init() struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context) { - if (context == NULL) - { + if (context == NULL) { panic(NULL, "Scheduler called with NULL context"); } - if (current_process == NULL) - { + if (current_process == NULL) { // If no more processes, then set IDLE as the current process, that's it. current_process = idle_proc; } @@ -38,21 +36,17 @@ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context) for (;;) { struct process_t* prev_process = current_process; - if (current_process->next != NULL) - { + if (current_process->next != NULL) { current_process = current_process->next; - } else - { + } else { current_process = processes_list; } - if (current_process != NULL && current_process->status == DEAD) - { + if (current_process != NULL && current_process->status == DEAD) { process_delete(&prev_process, current_process); current_process = NULL; return idle_proc->context; - } else - { + } else { current_process->status = RUNNING; break; } diff --git a/src/string/string.c b/src/string/string.c index f95f000..b21a650 100644 --- a/src/string/string.c +++ b/src/string/string.c @@ -14,12 +14,14 @@ char* strcpy(char *dest, const char *src) } // https://stackoverflow.com/questions/2488563/strcat-implementation -char *strcat(char *dest, const char *src){ +char *strcat(char *dest, const char *src) +{ size_t i,j; - for (i = 0; dest[i] != '\0'; i++) - ; + for (i = 0; dest[i] != '\0'; i++); + for (j = 0; src[j] != '\0'; j++) dest[i+j] = src[j]; + dest[i+j] = '\0'; return dest; } diff --git a/src/time/timer.c b/src/time/timer.c index ab1cc24..5c591ef 100644 --- a/src/time/timer.c +++ b/src/time/timer.c @@ -78,8 +78,7 @@ void pit_init() void timer_wait(uint64_t wait_ticks) { uint64_t then = ticks + wait_ticks; - while (ticks < then) - { + while (ticks < then) { asm("hlt"); }; } From 8026c3363965bca93e6e5d577ff1856288d2f8ee Mon Sep 17 00:00:00 2001 From: xamidev Date: Fri, 13 Mar 2026 12:51:29 +0100 Subject: [PATCH 4/6] Function comments (v1) --- .gitignore | 4 ++- README.md | 6 +++++ docs/STYLE.md | 10 +++++--- src/boot/boot.c | 5 ++++ src/config.h | 3 +++ src/debug/misc.c | 17 +++++++++++-- src/debug/panic.c | 9 +++++++ src/debug/stacktrace.c | 18 +++++++++++++- src/idt/idt.c | 53 +++++++++++++++++++++++++++++++++++++++- src/idt/idt.h | 1 - src/io/kbd/ps2.c | 14 +++++++++++ src/io/serial/serial.c | 41 +++++++++++++++++++++++++++++-- src/io/term/term.c | 26 ++++++++++++++++++-- src/kmain.c | 25 ++++++++++++++++--- src/mem/gdt/gdt.c | 18 ++++++++++++++ src/mem/heap/kheap.c | 42 ++++++++++++++++++++++++++++++-- src/mem/misc/utils.c | 51 ++++++++++++++++++++++++++++++++++++++ src/mem/paging/paging.c | 54 ++++++++++++++++++++++++++++++++++++----- src/mem/paging/paging.h | 17 +++++++------ src/mem/paging/pmm.c | 38 +++++++++++++++++++++++++---- src/mem/paging/vmm.c | 8 ++++++ src/sched/process.c | 54 ++++++++++++++++++++++++++++++++++++++--- src/sched/scheduler.c | 14 ++++++++++- src/string/string.c | 42 ++++++++++++++++++++++++++++++-- src/time/timer.c | 38 ++++++++++++++++++++++++----- 25 files changed, 560 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 8de7009..3db12c3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ iso_root symbols.map symbols.S *.log -build/ \ No newline at end of file +build/ +compile_commands.json +.cache/ \ No newline at end of file diff --git a/README.md b/README.md index 70a26f1..d97dd0c 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ First install the dependencies: `sudo apt install python3 xorriso make qemu-system` +Also, you have to get an x86_64 toolchain for compilation. The easiest way to do that on most systems is to install it from Homebrew: + +``` +brew install x86_64-elf-gcc +``` + Then, to compile the kernel and make an ISO image file: `make build-iso` To run it with QEMU, `make run` diff --git a/docs/STYLE.md b/docs/STYLE.md index c463c98..aa5e220 100644 --- a/docs/STYLE.md +++ b/docs/STYLE.md @@ -71,12 +71,16 @@ Function prototypes should include parameter names and their data types. ## Commenting -Comments should describe what a function does and why, not how it does it. +Comments should describe what a function does and why, not how it does it. The preferred way of commenting functions is the following: ```c /* - * This is the preferred style for multi-line - * comments in the Pepper kernel + * function_name - Function brief description + * @arg1: Argument 1 description + * @arg2: Argument 2 description + * + * A longer description can be featured here, explaining more + * in detail what the function does and why it does it. */ ``` diff --git a/src/boot/boot.c b/src/boot/boot.c index 20abcd1..966f202 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -1,6 +1,11 @@ /* * @author xamidev * @brief Limine requests for boot + * @description + * The kernel makes a few requests to the Limine bootloader + * in order to get precious information about the system. + * We get a framebuffer, a memory map, the address of the + * kernel in memory, and the Higher Half Direct Map offset. * @license GPL-3.0-only */ diff --git a/src/config.h b/src/config.h index 61cd7a7..1c0bf25 100644 --- a/src/config.h +++ b/src/config.h @@ -39,4 +39,7 @@ /* term */ #define TERM_HISTORY_MAX_LINES 256 +/* time */ +#define TIMER_FREQUENCY 1000 + #endif diff --git a/src/debug/misc.c b/src/debug/misc.c index 19c076f..874c328 100644 --- a/src/debug/misc.c +++ b/src/debug/misc.c @@ -10,7 +10,14 @@ extern struct boot_context boot_ctx; -// Display the memmap so we see how the memory is laid out at handoff +/* + * memmap_display - displays a memory map + * @response: Limine memory map response + * + * Displays the memory map we get from Limine + * to see different regions, their sizes, and + * how the memory is laid out at handoff. + */ void memmap_display(struct limine_memmap_response* response) { DEBUG("Got memory map from Limine: revision %u, %u entries", response->revision, response->entry_count); @@ -51,12 +58,18 @@ void memmap_display(struct limine_memmap_response* response) } } -// Display the HHDM +/* + * hhdm_display - displays the HHDM offset + * @hhdm: Limine HHDM offset response + */ void hhdm_display(struct limine_hhdm_response* hhdm) { DEBUG("Got HHDM revision=%u offset=0x%p", hhdm->revision, hhdm->offset); } +/* + * boot_mem_display - displays all memory info + */ void boot_mem_display() { memmap_display(boot_ctx.mmap); diff --git a/src/debug/panic.c b/src/debug/panic.c index e1cf694..d15a27d 100644 --- a/src/debug/panic.c +++ b/src/debug/panic.c @@ -11,6 +11,15 @@ extern struct init_status init; +/* + * panic - Kernel panic + * @ctx: CPU context (optional) + * @str: Error message + * + * Ends execution of the kernel in case of an unrecoverable error. + * Will display to terminal if it is initialized, otherwise serial only. + * Can be called with or without a CPU context. + */ void panic(struct cpu_status_t* ctx, const char* str) { CLEAR_INTERRUPTS; diff --git a/src/debug/stacktrace.c b/src/debug/stacktrace.c index f1bca8e..1717663 100644 --- a/src/debug/stacktrace.c +++ b/src/debug/stacktrace.c @@ -9,6 +9,13 @@ extern struct init_status init; +/* + * debug_stack_trace - Prints the stack trace + * @max_frames: Maximum amount of stack frames to walk + * + * Walks back the stack and gets all return values (RIP) + * and prints them to the DEBUG interface. + */ void debug_stack_trace(unsigned int max_frames) { DEBUG("*** begin stack trace ***"); @@ -52,7 +59,16 @@ typedef struct { __attribute__((weak)) extern kernel_symbol_t symbol_table[]; __attribute__((weak)) extern uint64_t symbol_count; -// binary search +/* + * debug_find_symbol - Finds the symbol name associated to an address + * @rip: Pointer to executable code + * @offset: Out pointer to reference the offset in the found function, if any + * + * Return: + * - symbol name + * "???" - no symbol table found + * "unknown" - symbol table found, but address isn't in the table + */ const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset) { if (!symbol_table || symbol_count == 0) { diff --git a/src/idt/idt.c b/src/idt/idt.c index ee1fa5c..dd465e9 100644 --- a/src/idt/idt.c +++ b/src/idt/idt.c @@ -24,6 +24,12 @@ extern char vector_0_handler[]; // Timer ticks extern volatile uint64_t ticks; +/* + * idt_set_entry - Sets an Interrupt Descriptor Table entry + * @vector: Vector number in the IDT + * @handler: Pointer to the executable Interrupt Service Routine + * @dpl: Desired privilege level + */ void idt_set_entry(uint8_t vector, void* handler, uint8_t dpl) { uint64_t handler_addr = (uint64_t)handler; @@ -42,6 +48,10 @@ void idt_set_entry(uint8_t vector, void* handler, uint8_t dpl) entry->ist = 0; } +/* + * idt_load - Loads the Interrupt Descriptor Table + * @idt_addr: Address to the IDT + */ void idt_load(void* idt_addr) { // "limit" = "size" = Size of the IDT - 1 byte = (16*256)-1 = 0xFFF @@ -50,9 +60,14 @@ void idt_load(void* idt_addr) asm volatile("lidt %0" :: "m"(idt_reg)); } +/* + * idt_init - Initializes the Interrupt Descriptor Table + * + * Sets all IDT entries and their corresponding service routines, + * then loads it. + */ void idt_init() { - // Hardcoded... for (size_t i=0; i<=KERNEL_IDT_ENTRIES; i++) { // Each vector handler is 16-byte aligned, so *16 = address of that handler idt_set_entry(i, vector_0_handler + (i*16), 0); @@ -61,6 +76,15 @@ void idt_init() DEBUG("IDT initialized"); } +/* + * read_cr2 - Reads the CR2 register + * + * This function is useful because it gets the address + * that the CPU tried to access in the case of a #PF. + * + * Return: + * %val - CR2 register value + */ static inline uint64_t read_cr2(void) { uint64_t val; @@ -68,6 +92,15 @@ static inline uint64_t read_cr2(void) return val; } +/* + * page_fault_handler - Handler for #PF + * @ctx: CPU context + * + * Shows detail about a #PF, especially what instruction (RIP) + * caused it, and what address access (CR2) caused it. + * Also displays an interpretation of the thrown error code. + * Then halts the system. We could implement demand paging later. + */ static void page_fault_handler(struct cpu_status_t* ctx) { // It could be used to remap pages etc. to fix the fault, but right now what I'm more @@ -89,6 +122,13 @@ static void page_fault_handler(struct cpu_status_t* ctx) panic(ctx, "page fault"); } +/* + * gp_fault_handler - Handler for #GP + * @ctx: CPU context + * + * Shows detail about a General Protection Fault, + * and what may have caused it. Halts the system. + */ static void gp_fault_handler(struct cpu_status_t* ctx) { DEBUG("\x1b[38;5;231mGeneral Protection Fault at rip=0x%p, err=%u (%s)\x1b[0m", @@ -114,6 +154,17 @@ static void gp_fault_handler(struct cpu_status_t* ctx) panic(ctx, "gp fault"); } +/* + * interrupt_dispatch - Interrupt dispatcher + * @context: CPU context + * + * This function is where all interrupt routines go, after they passed + * through their corresponding vector handler in the IDT assembly stub. + * It catches all exceptions. + * + * Return: + * - CPU context after interrupt + */ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) { if (context == NULL) { diff --git a/src/idt/idt.h b/src/idt/idt.h index fab7853..de2c166 100644 --- a/src/idt/idt.h +++ b/src/idt/idt.h @@ -39,7 +39,6 @@ struct cpu_status_t { uint64_t r9; uint64_t r8; uint64_t rbp; - //uint64_t rsp; uint64_t rdi; uint64_t rsi; uint64_t rdx; diff --git a/src/io/kbd/ps2.c b/src/io/kbd/ps2.c index b28b31b..32c0d3c 100644 --- a/src/io/kbd/ps2.c +++ b/src/io/kbd/ps2.c @@ -156,6 +156,14 @@ unsigned char kbdfr_shifted[128] = 0 }; +/* + * keyboard_handler - Keyboard event handler + * + * Is called from the interrupt dispatcher. + * When a key is pressed or released, we get a scancode, and + * it is then translated to an ASCII character. + * Left Shift, Ctrl, and Alt keys are also taken into consideration. + */ void keyboard_handler() { unsigned char scancode = inb(0x60); @@ -212,6 +220,12 @@ void keyboard_handler() } } +/* + * keyboard_init - Keyboard initialization + * @layout: Desired layout + * + * Prepares the PS/2 keyboard to recieve input. + */ void keyboard_init(unsigned char layout) { // Here we might go and select PS/2, USB, or other... (once we implement multiple keyboard protocols) diff --git a/src/io/serial/serial.c b/src/io/serial/serial.c index fbf06c8..5b8e931 100644 --- a/src/io/serial/serial.c +++ b/src/io/serial/serial.c @@ -9,11 +9,25 @@ extern struct init_status init; +/* + * outb - Writes a byte to a CPU port + * @port: CPU port to write to + * @data: Byte to write + * + * Writes a single byte to the serial interface. + */ void outb(int port, unsigned char data) { __asm__ __volatile__("outb %%al, %%dx" :: "a" (data),"d" (port)); } +/* + * inb - Gets a byte in through a CPU port + * @port: The CPU port to get a byte from + * + * Return: + * - byte got from port + */ unsigned char inb(int port) { unsigned char data = 0; @@ -21,6 +35,13 @@ unsigned char inb(int port) return data; } +/* + * serial_init - Initializes serial interface + * + * Return: + * %-EIO - Input/output error + * %0 - Success + */ int serial_init() { outb(PORT + 1, 0x00); // Disable all interrupts @@ -45,12 +66,23 @@ int serial_init() return 0; } +/* + * is_transmit_empty - Check if the serial transmit register is empty + * + * Return: Non-zero if the transmit register is empty and a new + * byte can be written to the serial port, 0 otherwise. + */ static int is_transmit_empty() { return inb(PORT + 5) & 0x20; } -// Serial kernel putchar +/* + * skputc - Serial kernel putchar + * @c: character to write + * + * Writes a single character to the serial interface. + */ void skputc(char c) { // TODO: Spinlock here (serial access) @@ -58,7 +90,12 @@ void skputc(char c) outb(PORT, c); } -// Serial kernel putstring +/* + * skputs - Serial kernel puts + * @str: Message to write + * + * Writes a non-formatted string to serial output. + */ void skputs(const char* str) { unsigned int i=0; diff --git a/src/io/term/term.c b/src/io/term/term.c index cf90125..ebd979e 100644 --- a/src/io/term/term.c +++ b/src/io/term/term.c @@ -23,14 +23,22 @@ because this shitty implementation will be replaced one day by Flanterm extern struct flanterm_context* ft_ctx; extern struct init_status init; -// Overhead that could be avoided, right? (for printf) +/* + * _putchar - Writes a character to terminal + * @character: character to write + */ void _putchar(char character) { // TODO: Spinlock here (terminal access) flanterm_write(ft_ctx, &character, 1); } -// Debug-printing +/* + * kputs - Kernel puts + * @str: String to write + * + * Writes a non-formatted string to terminal + */ void kputs(const char* str) { size_t i=0; @@ -44,12 +52,26 @@ void kputs(const char* str) extern struct flanterm_context* ft_ctx; extern struct boot_context boot_ctx; +/* + * flanterm_free_wrapper - free() wrapper for Flanterm + * @ptr: pointer to free + * @size: amount of bytes to free + * + * This function exists solely because the Flanterm initialization + * function only accepts a free() function with a size parameter, + * and the default one doesn't have it. + */ void flanterm_free_wrapper(void* ptr, size_t size) { (void)size; kfree(ptr); } +/* + * term_init - Video output/terminal initialization + * + * Uses Flanterm and the framebuffer given by Limine. + */ void term_init() { uint32_t bgColor = 0x252525; diff --git a/src/kmain.c b/src/kmain.c index 4ccd31b..5a9b7bc 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -30,13 +30,25 @@ __attribute__((used, section(".limine_requests"))) volatile LIMINE_BASE_REVISION(3); -// Halt and catch fire (makes machine stall) +/* + * hcf - Halt and catch fire + * + * This function is called only in the case of an unrecoverable + * error. It halts interrupts, and stops execution. The machine + * will stay in an infinite loop state. + */ void hcf() { CLEAR_INTERRUPTS; for (;;)asm("hlt"); } -// Doing nothing (can be interrupted) +/* + * idle - Make the machine idle + * + * When there is nothing else to do, this function + * gets called. It can be interrupted, so it allows + * the scheduler, timer, and keyboard to work. + */ void idle() {SET_INTERRUPTS; for(;;)asm("hlt");} struct flanterm_context *ft_ctx; @@ -72,7 +84,14 @@ void idle_main(void* arg) extern uintptr_t kheap_start; -// This is our entry point +/* + * kmain - Kernel entry point + * + * This is where execution begins at handoff from Limine. + * The function fetches all needed information from the + * bootloader, initializes all kernel modules and structures, + * and then goes in an idle state. + */ void kmain() { CLEAR_INTERRUPTS; diff --git a/src/mem/gdt/gdt.c b/src/mem/gdt/gdt.c index fd5a318..175cab1 100644 --- a/src/mem/gdt/gdt.c +++ b/src/mem/gdt/gdt.c @@ -14,11 +14,20 @@ uint64_t gdt_entries[NUM_GDT_ENTRIES]; struct GDTR gdtr; +/* + * gdt_load - Loads Global Descriptor Table + */ static void gdt_load() { asm("lgdt %0" : : "m"(gdtr)); } +/* + * gdt_flush - Flushes the Global Descriptor Table + * + * This function loads new Segment Selectors to make + * the GDT changes take effect + */ static void gdt_flush() { // Here, 0x8 is the kernel code selector @@ -42,6 +51,15 @@ static void gdt_flush() ); } +/* + * gdt_init - Global Descriptor Table initialization + * + * This function loads a new GDT in the CPU. + * It contains a null descriptor, kernel code and data + * segments, and user code and data segments. + * However, we do not use segmentation to manage memory on + * 64-bit x86, as it's deprecated. Instead, we use paging. + */ void gdt_init() { // Null descriptor (required) diff --git a/src/mem/heap/kheap.c b/src/mem/heap/kheap.c index 5393614..9adb0d2 100644 --- a/src/mem/heap/kheap.c +++ b/src/mem/heap/kheap.c @@ -23,6 +23,15 @@ static uintptr_t end; // Kernel root table (level 4) extern uint64_t *kernel_pml4; +/* + * kheap_init - Kernel heap initialization + * + * This function physically allocates and maps enough pages + * of memory for KHEAP_SIZE, which is defined in config.h. + * + * It then creates one big heap block, which will be the + * base for a linked list. + */ void kheap_init() { kheap_start = ALIGN_UP(kernel_virt_base + KERNEL_SIZE, PAGE_SIZE); @@ -53,6 +62,18 @@ void kheap_init() DEBUG("Kernel heap initialized, head=0x%p, size=%u bytes", head, head->size); } +/* + * kmalloc - Kernel memory allocation + * @size: number of bytes to allocate + * + * Looks for a big enough free block and marks it + * as taken. Each block of memory is preceded by + * the linked list header. + * + * Return: + * - Pointer to at least bytes of usable memory + * NULL - No more memory, or no valid size given + */ void* kmalloc(size_t size) { // No size, no memory allocated! @@ -92,6 +113,14 @@ void* kmalloc(size_t size) return NULL; } +/* + * kfree - Kernel memory freeing + * @ptr: pointer to memory region to free + * + * Marks the memory block beginning at + * as free. Also merges adjacent free blocks + * to lessen fragmentation. + */ void kfree(void* ptr) { // Nothing to free @@ -113,8 +142,17 @@ void kfree(void* ptr) } } -// Should alloc enough for a stack (at least 64kb) to be used for a process. -// Should return a pointer to top of the stack (as stack grows DOWNWARDS) +/* + * kalloc_stack - Stack memory allocation + * + * Allocates a memory region of at least PROCESS_STACK_SIZE, + * to be used as a stack for a process. The pointer returned + * points to the end of the region, as the stack grows downwards. + * + * Return: + * - Pointer to a region after at least PROCESS_STACK_SIZE bytes of usable memory + * NULL - No more memory + */ void* kalloc_stack() { uint8_t* ptr = kmalloc(PROCESS_STACK_SIZE); // As it's out of kmalloc, stack is already mapped into kernel space diff --git a/src/mem/misc/utils.c b/src/mem/misc/utils.c index d43ec16..81c7b29 100644 --- a/src/mem/misc/utils.c +++ b/src/mem/misc/utils.c @@ -16,6 +16,19 @@ // We use the "restrict" keyword on pointers so that the compiler knows it can // do more optimization on them (and as it's a much used function, it's good to // be able to do that) + +/* + * memcpy - Copy memory from one place to another + * @dest: pointer to the destination region + * @src: pointer to the source region + * @n: amount of bytes to copy + * + * This function copies n bytes of memory from + * src to dest. + * + * Return: + * - Pointer to destination region + */ void* memcpy(void* restrict dest, const void* restrict src, size_t n) { uint8_t* restrict pdest = (uint8_t* restrict)dest; @@ -28,6 +41,18 @@ void* memcpy(void* restrict dest, const void* restrict src, size_t n) return dest; } +/* + * memset - Sets a memory region to given byte + * @s: pointer to memory region + * @c: byte to be written + * @n: amount of bytes to write + * + * This function writes n times the byte c + * to the memory region pointed to by s. + * + * Return: + * - Pointer to memory region + */ void* memset(void* s, int c, size_t n) { uint8_t* p = (uint8_t*)s; @@ -39,6 +64,18 @@ void* memset(void* s, int c, size_t n) return s; } +/* + * memmove - Move memory from one place to another + * @dest: pointer to the destination region + * @src: pointer to the source region + * @n: amount of bytes to move + * + * This function moves n bytes of memory from + * src to dest. + * + * Return: + * - Pointer to destination region + */ void* memmove(void *dest, const void* src, size_t n) { uint8_t* pdest = (uint8_t*)dest; @@ -56,6 +93,20 @@ void* memmove(void *dest, const void* src, size_t n) return dest; } +/* + * memcmp - Compare two memory regions + * @s1: pointer to the first region + * @s2: pointer to the second region + * @n: amount of bytes to compare + * + * This function compares n bytes of memory + * bewteen regions pointed to by s1 and s2. + * + * Return: + * %0 - if s1 and s2 are equal + * %-1 - if s1 is smaller than s2 + * %1 - if s1 is greater than s2 + */ int memcmp(const void* s1, const void* s2, size_t n) { const uint8_t* p1 = (const uint8_t*)s1; diff --git a/src/mem/paging/paging.c b/src/mem/paging/paging.c index b6bd9dc..f1b6afe 100644 --- a/src/mem/paging/paging.c +++ b/src/mem/paging/paging.c @@ -24,17 +24,41 @@ If we use 1GB huge pages: PML4 -> PDPT -> 1gb pages 4KB (regular size): PML4 -> PDPT -> PD -> PT -> 4kb pages */ +/* + * load_cr3 - Load a new value into the CR3 register + * @value: the value to load + * + * This function is used to load the physical address + * of the root page table (PML4), to switch the paging + * structures the CPU sees and uses. + */ void load_cr3(uint64_t value) { asm volatile ("mov %0, %%cr3" :: "r"(value) : "memory"); } -// To flush TLB +/* + * invlpg - Invalidates a Translation Lookaside Buffer entry + * @addr: page memory address + * + * This function is used to flush at least the TLB entrie(s) + * for the page that contains the address. + */ static inline void invlpg(void *addr) { asm volatile("invlpg (%0)" :: "r"(addr) : "memory"); } -// Allocates a 512-entry 64bit page table/directory/whatever (zeroed) +/* + * alloc_page_table - Page table allocation + * + * This function allocates enough memory for a 512-entry + * 64-bit page table, for any level (PML4/3/2). + * + * Memory allocated here is zeroed. + * + * Return: + * - Pointer to allocated page table + */ static uint64_t* alloc_page_table() { uint64_t* virt = (uint64_t*)PHYS_TO_VIRT(pmm_alloc()); @@ -49,10 +73,19 @@ static uint64_t* alloc_page_table() __attribute__((aligned(4096))) uint64_t *kernel_pml4; -// Map a page, taking virt and phys address. This will go through the paging structures -// beginning at the given root table, translate the virtual address in indexes in -// page table/directories, and then mapping the correct page table entry with the -// given physical address + flags +/* + * paging_map_page - Mapping a memory page + * @root_table: Address of the PML4 + * @virt: Virtual address + * @phys: Physical address + * @flags: Flags to set on page + * + * This function maps the physical address to the virtual + * address , using the paging structures beginning at + * . can be set according to the PTE_FLAGS enum. + * + * If a page table/directory entry is not present yet, it creates it. + */ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags) { virt = PAGE_ALIGN_DOWN(virt); @@ -102,6 +135,15 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_ uint64_t kernel_phys_base; uint64_t kernel_virt_base; +/* + * paging_init - Paging initialization + * @boot_ctx: Boot context structure + * + * This function initializes new paging structures, to replace + * the ones given by the bootloader. + * + * It maps the kernel, the HHDM space, and the framebuffer. + */ void paging_init(struct boot_context boot_ctx) { // We should map the kernel, GDT, IDT, stack, framebuffer. diff --git a/src/mem/paging/paging.h b/src/mem/paging/paging.h index 30cfbb5..dd55c99 100644 --- a/src/mem/paging/paging.h +++ b/src/mem/paging/paging.h @@ -41,12 +41,15 @@ extern uint64_t hhdm_off; // Page entry special bits // Bits set on a parent (directory, table) fall back to their children -#define PTE_PRESENT (1ULL << 0) -#define PTE_WRITABLE (1ULL << 1) -#define PTE_USER (1ULL << 2) -#define PTE_PWT (1ULL << 3) -#define PTE_PCD (1ULL << 4) -#define PTE_HUGE (1ULL << 7) -#define PTE_NOEXEC (1ULL << 63) +enum PTE_FLAGS +{ + PTE_PRESENT = (1ULL << 0), + PTE_WRITABLE = (1ULL << 1), + PTE_USER = (1ULL << 2), + PTE_PWT = (1ULL << 3), + PTE_PCD = (1ULL << 4), + PTE_HUGE = (1ULL << 7), + PTE_NOEXEC = (1ULL << 63) +}; #endif \ No newline at end of file diff --git a/src/mem/paging/pmm.c b/src/mem/paging/pmm.c index db3a5e9..2d8dc2c 100644 --- a/src/mem/paging/pmm.c +++ b/src/mem/paging/pmm.c @@ -24,13 +24,16 @@ First we'll have to discover the physical memory layout, and for that we can use a Limine request. */ -/* -We will look for the biggest usable physical memory region -and use this for the bitmap. The reserved memory will be ignored. -*/ - struct limine_memmap_entry* biggest_entry; +/* + * pmm_find_biggest_usable_region - Finding the biggest free memory region + * @memmap: Limine memory map + * @hhdm: Limine HHDM offset + * + * This function uses the memory map provided by the bootloader + * to find the single biggest free memory region we can use. + */ static void pmm_find_biggest_usable_region(struct limine_memmap_response* memmap, struct limine_hhdm_response* hhdm) { // Max length of a usable memory region @@ -62,6 +65,14 @@ uint64_t hhdm_off; static uintptr_t g_freelist = 0; +/* + * pmm_alloc - Allocate a physical page + * + * This function allocates a single physical page (frame) + * + * Return: + * - Address for the allocated page + */ uintptr_t pmm_alloc() { if (!g_freelist) { @@ -72,12 +83,22 @@ uintptr_t pmm_alloc() return addr; } +/* + * pmm_free - Frees a memory page + * @addr: Address to the page + */ void pmm_free(uintptr_t addr) { *(uintptr_t*) PHYS_TO_VIRT(addr) = g_freelist; g_freelist = addr; } +/* + * pmm_init_freelist - PMM freelist initialization + * + * This function marks the biggest memory region as + * free, so we can use it in pmm_alloc. + */ static void pmm_init_freelist() { // We simply call pmm_free() on each page that is marked USABLE @@ -93,6 +114,13 @@ static void pmm_init_freelist() DEBUG("%u frames in freelist, available for use (%u bytes)", page_count, page_count*PAGE_SIZE); } +/* + * pmm_init - Physical memory manager initialization + * @boot_ctx: Boot context structure + * + * This function prepares the PMM for use. + * The PMM works with a freelist. + */ void pmm_init(struct boot_context boot_ctx) { hhdm_off = boot_ctx.hhdm->offset; diff --git a/src/mem/paging/vmm.c b/src/mem/paging/vmm.c index 3e989f9..8a52b4a 100644 --- a/src/mem/paging/vmm.c +++ b/src/mem/paging/vmm.c @@ -24,6 +24,14 @@ void* vmm_pt_root = 0; // Linked list head for virtual memory objects struct vm_object* vm_objs = NULL; +/* + * Will have to be rewritten and expanded, + * to prepare for userspace. + * The platform-agnostic flags will be removed + * because as long as the kernel is x86 only, + * we don't need over complication. + * Plus I don't plan to port to other architectures +*/ uint64_t convert_x86_vm_flags(size_t flags) { diff --git a/src/sched/process.c b/src/sched/process.c index c4e879d..dc1d2df 100644 --- a/src/sched/process.c +++ b/src/sched/process.c @@ -23,13 +23,22 @@ extern uint64_t *kernel_pml4; size_t next_free_pid = 0; +/* + * process_init - Initializes process list + */ void process_init() { processes_list = NULL; current_process = NULL; } -// Only for debug +/* + * process_display_list - Debug function to display processes + * @processes_list: head of the process linked list + * + * This function prints the linked list of processes + * to the DEBUG output. + */ void process_display_list(struct process_t* processes_list) { int process_view_id = 0; @@ -42,6 +51,19 @@ void process_display_list(struct process_t* processes_list) DEBUG("NULL"); } +/* + * process_create - Create a process + * @name: name of the process + * @function: beginning of process executable code + * @arg: (optional) argument provided to process + * + * This function creates a process, gives it all + * necessary context and a stack, and adds the + * process to the linked list. + * + * Return: + * - pointer to created process + */ struct process_t* process_create(char* name, void(*function)(void*), void* arg) { CLEAR_INTERRUPTS; @@ -81,6 +103,11 @@ struct process_t* process_create(char* name, void(*function)(void*), void* arg) return proc; } +/* + * process_add - Add a process to the end of the linked list + * @processes_list: pointer to the head of the linked list + * @process: process to add at the end of the linked list + */ void process_add(struct process_t** processes_list, struct process_t* process) { if (!process) return; @@ -100,6 +127,11 @@ void process_add(struct process_t** processes_list, struct process_t* process) tmp->next = process; } +/* + * process_delete - Delete a process from the linked list + * @processes_list: pointer to head of linked list + * @process: the process to delete from the list + */ void process_delete(struct process_t** processes_list, struct process_t* process) { if (!processes_list || !*processes_list || !process) return; @@ -128,14 +160,30 @@ void process_delete(struct process_t** processes_list, struct process_t* process kfree(process); } +/* + * process_get_next - Get the next process (unused) + * @process: pointer to process + * + * Return: + * next> - process right after the one specified + */ struct process_t* process_get_next(struct process_t* process) { if (!process) return NULL; return process->next; } -// Will be used to clean up resources (if any, when we implement it) -// Just mark as DEAD then idle. Scheduler will delete process at next timer interrupt % quantum. +/* + * process_exit - Exit from a process + * + * This function is pushed to all process stacks, as a last + * return address. Once the process is done executing, it + * ends up here. + * + * Process is marked as DEAD, and then execution loops. + * Next time the scheduler sees the process, it will + * automatically delete it from the linked list. + */ void process_exit() { DEBUG("Exiting from process '%s'", current_process->name); diff --git a/src/sched/scheduler.c b/src/sched/scheduler.c index 1c9dce0..eedd3bc 100644 --- a/src/sched/scheduler.c +++ b/src/sched/scheduler.c @@ -14,12 +14,24 @@ extern struct process_t* processes_list; extern struct process_t* current_process; extern struct process_t* idle_proc; +/* + * scheduler_init - Choose the first process + */ void scheduler_init() { - // Choose first process? current_process = processes_list; } +/* + * scheduler_schedule - Main scheduling routine + * @context: CPU context of previous process + * + * Chooses the next process that we should run. + * The routine is executed every SCHEDULER_QUANTUM ticks. + * + * Return: + * - CPU context for next process + */ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context) { if (context == NULL) { diff --git a/src/string/string.c b/src/string/string.c index b21a650..3c7c7af 100644 --- a/src/string/string.c +++ b/src/string/string.c @@ -6,6 +6,16 @@ #include +/* + * strcpy - copy a NULL-terminated string + * @dest: destination buffer where the string is copied + * @src: source string to copy from + * + * Copies the string pointed to by @src (including the terminating + * NULL byte) into the buffer pointed to by @dest. + * + * Return: pointer to the destination string (@dest) + */ char* strcpy(char *dest, const char *src) { char *temp = dest; @@ -13,7 +23,21 @@ char* strcpy(char *dest, const char *src) return temp; } -// https://stackoverflow.com/questions/2488563/strcat-implementation +/* + * strcat - append a NUL-terminated string + * @dest: destination buffer containing the initial string + * @src: source string to append + * + * Appends the string pointed to by @src to the end of the string + * pointed to by @dest. The terminating NUL byte in @dest is + * overwritten and a new terminating NUL byte is added. + * + * The destination buffer must be large enough to hold the result. + * + * Taken from: https://stackoverflow.com/questions/2488563/strcat-implementation + * + * Return: pointer to the destination string (@dest) + */ char *strcat(char *dest, const char *src) { size_t i,j; @@ -26,7 +50,21 @@ char *strcat(char *dest, const char *src) return dest; } -// https://stackoverflow.com/questions/14159625/implementation-of-strncpy +/* + * strncpy - copy a string with length limit + * @dst: destination buffer + * @src: source string + * @n: maximum number of bytes to copy + * + * Copies up to @n bytes from @src to @dst. Copying stops early if a + * NULL byte is encountered in @src. If @src is shorter than @n, the + * remaining bytes in @dst are left unchanged in this implementation. + * + * Note: This differs slightly from the standard strncpy behavior, + * which pads the remaining bytes with NULL. + * + * Taken from: https://stackoverflow.com/questions/14159625/implementation-of-strncpy + */ void strncpy(char* dst, const char* src, size_t n) { size_t i = 0; diff --git a/src/time/timer.c b/src/time/timer.c index 5c591ef..bea150b 100644 --- a/src/time/timer.c +++ b/src/time/timer.c @@ -7,6 +7,7 @@ #include #include "io/serial/serial.h" #include +#include "config.h" /* For now, the timer module will be using the PIC. @@ -20,6 +21,13 @@ volatile uint64_t ticks = 0; extern struct init_status init; +/* + * pic_remap - Remap the Programmable Interrupt Controller + * + * By default, interrupts are mapped at the wrong place. + * This function remaps interrupt numbers so interrupts + * don't conflict with each other. + */ void pic_remap() { uint8_t master_mask = inb(0x21); @@ -47,6 +55,12 @@ void pic_remap() outb(0xA1, slave_mask); } +/* + * pic_enable - Enable the Programmable Interrupt Controller + * + * This function enables IRQ0 and IRQ1, which correspond to + * the timer and keyboard interrupts, respectively. + */ void pic_enable() { // Enabling IRQ0 (unmasking it) but not the others @@ -57,12 +71,15 @@ void pic_enable() } /* -Base frequency = 1.193182 MHz -1 tick per ms (divide by 1000) = roughly 1193 Hz -*/ + * pit_init - Initialization of the Programmable Interval Timer + * + * The PIT is the simplest timer we can get working on x86. + * It has a base frequency of 1.193182 MHz. + * A custom frequency can be set using TIMER_FREQUENCY macro. + */ void pit_init() { - uint32_t frequency = 1000; // 1 kHz + uint32_t frequency = TIMER_FREQUENCY; uint32_t divisor = 1193182 / frequency; // Set PIT to mode 3, channel 0 @@ -73,8 +90,12 @@ void pit_init() outb(0x40, (divisor >> 8) & 0xFF); } -// Wait n ticks -// Given that there's a tick every 1ms, wait n milliseconds +/* + * timer_wait - Wait for X ticks + * + * By default, the timer frequency is 1000Hz, meaning + * ticks are equal to milliseconds. + */ void timer_wait(uint64_t wait_ticks) { uint64_t then = ticks + wait_ticks; @@ -83,6 +104,11 @@ void timer_wait(uint64_t wait_ticks) }; } +/* + * timer_init - Initialization of the timer + * + * This function wakes the PIT. + */ void timer_init() { // Remapping the PIC, because at startup it conflicts with From 5c0d02579b03a129961fea52ba7e6004c67458af Mon Sep 17 00:00:00 2001 From: xamidev Date: Fri, 13 Mar 2026 17:21:52 +0100 Subject: [PATCH 5/6] void parameter on functions of arity 0 --- src/debug/stacktrace.c | 4 ++-- src/idt/idt.h | 2 +- src/io/kbd/ps2.h | 2 +- src/io/serial/serial.h | 2 +- src/io/term/term.h | 2 +- src/kmain.c | 7 +------ src/mem/gdt/gdt.h | 2 +- src/mem/heap/kheap.h | 6 +++--- src/mem/paging/pmm.h | 2 +- src/mem/paging/vmm.h | 2 +- src/sched/process.h | 4 ++-- src/sched/scheduler.h | 2 +- src/time/timer.h | 2 +- 13 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/debug/stacktrace.c b/src/debug/stacktrace.c index 1717663..1f9c27c 100644 --- a/src/debug/stacktrace.c +++ b/src/debug/stacktrace.c @@ -20,7 +20,7 @@ void debug_stack_trace(unsigned int max_frames) { DEBUG("*** begin stack trace ***"); if (init.terminal) { - printf("\r\n*** begin stack trace ***\r\n"); + printf("\r\n\x1b[48;5;232m\x1b[38;5;231m*** begin stack trace ***\r\n"); } // Thanks GCC :) uintptr_t* rbp = (uintptr_t*)__builtin_frame_address(0); @@ -46,7 +46,7 @@ void debug_stack_trace(unsigned int max_frames) rbp = next_rbp; } if (init.terminal) { - printf("*** end stack trace ***"); + printf("*** end stack trace ***[0m"); } DEBUG("*** end stack trace ***"); } diff --git a/src/idt/idt.h b/src/idt/idt.h index de2c166..b74fb56 100644 --- a/src/idt/idt.h +++ b/src/idt/idt.h @@ -9,7 +9,7 @@ #include -void idt_init(); +void idt_init(void); struct interrupt_descriptor { uint16_t address_low; diff --git a/src/io/kbd/ps2.h b/src/io/kbd/ps2.h index a1d4860..c9aed30 100644 --- a/src/io/kbd/ps2.h +++ b/src/io/kbd/ps2.h @@ -7,7 +7,7 @@ #ifndef PS2_H #define PS2_H -void keyboard_handler(); +void keyboard_handler(void); #define SHIFT_PRESSED_BIT 0b00000001 #define ALT_PRESSED_BIT 0b00000010 diff --git a/src/io/serial/serial.h b/src/io/serial/serial.h index b60c488..1106460 100644 --- a/src/io/serial/serial.h +++ b/src/io/serial/serial.h @@ -13,7 +13,7 @@ void outb(int port, unsigned char data); unsigned char inb(int port); -int serial_init(); +int serial_init(void); void skputs(const char* str); void skputc(char c); diff --git a/src/io/term/term.h b/src/io/term/term.h index b470c1b..ee15ea6 100644 --- a/src/io/term/term.h +++ b/src/io/term/term.h @@ -9,6 +9,6 @@ void kputs(const char* str); void _putchar(char character); -void term_init(); +void term_init(void); #endif diff --git a/src/kmain.c b/src/kmain.c index 5a9b7bc..d75831b 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -64,15 +64,10 @@ extern struct process_t* processes_list; extern struct process_t* current_process; struct process_t* idle_proc; -bool iran = false; - // Never gets executed although pedicel is scheduled? void pedicel_main(void* arg) { - //panic(NULL, "test"); - bool iran = true; - // FROM THE NEXT LINE ONWARDS, CANNOT WRITE TO FRAMEBUFFER WITHOUT PAGE FAULT! - //printf("\n\nWelcome to PepperOS! Pedicel speaking.\nNothing left to do, halting the system!"); + printf("\n\nWelcome to PepperOS! Pedicel speaking.\r\nNothing left to do, let's go idle!"); } void idle_main(void* arg) diff --git a/src/mem/gdt/gdt.h b/src/mem/gdt/gdt.h index 33f744e..abe3eba 100644 --- a/src/mem/gdt/gdt.h +++ b/src/mem/gdt/gdt.h @@ -26,6 +26,6 @@ struct GDTR { uint64_t address; } __attribute__((packed)); -void gdt_init(); +void gdt_init(void); #endif \ No newline at end of file diff --git a/src/mem/heap/kheap.h b/src/mem/heap/kheap.h index 52b9315..ee4672d 100644 --- a/src/mem/heap/kheap.h +++ b/src/mem/heap/kheap.h @@ -23,10 +23,10 @@ struct heap_block_t { struct heap_block_t* next; } __attribute__((aligned(16))); -void kheap_init(); +void kheap_init(void); void* kmalloc(size_t size); void kfree(void* ptr); -void* kalloc_stack(); -void kheap_map_page(); +void* kalloc_stack(void); +void kheap_map_page(void); #endif \ No newline at end of file diff --git a/src/mem/paging/pmm.h b/src/mem/paging/pmm.h index 90e2f54..7634af1 100644 --- a/src/mem/paging/pmm.h +++ b/src/mem/paging/pmm.h @@ -12,6 +12,6 @@ void pmm_init(struct boot_context boot_ctx); void pmm_free(uintptr_t addr); -uintptr_t pmm_alloc(); +uintptr_t pmm_alloc(void); #endif \ No newline at end of file diff --git a/src/mem/paging/vmm.h b/src/mem/paging/vmm.h index 368a1f9..3b60a84 100644 --- a/src/mem/paging/vmm.h +++ b/src/mem/paging/vmm.h @@ -29,6 +29,6 @@ struct vm_object { #define VM_FLAG_EXEC (1 << 1) #define VM_FLAG_USER (1 << 2) -void vmm_init(); +void vmm_init(void); #endif \ No newline at end of file diff --git a/src/sched/process.h b/src/sched/process.h index cb080b3..c6b6ecf 100644 --- a/src/sched/process.h +++ b/src/sched/process.h @@ -27,12 +27,12 @@ struct process_t { struct process_t* next; }; -void process_init(); +void process_init(void); struct process_t* process_create(char* name, void(*function)(void*), void* arg); void process_add(struct process_t** processes_list, struct process_t* process); void process_delete(struct process_t** processes_list, struct process_t* process); struct process_t* process_get_next(struct process_t* process); -void process_exit(); +void process_exit(void); void process_display_list(struct process_t* processes_list); diff --git a/src/sched/scheduler.h b/src/sched/scheduler.h index 9ec712e..071321e 100644 --- a/src/sched/scheduler.h +++ b/src/sched/scheduler.h @@ -8,6 +8,6 @@ #define SCHEDULER_H struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context); -void scheduler_init(); +void scheduler_init(void); #endif \ No newline at end of file diff --git a/src/time/timer.h b/src/time/timer.h index 8b398fd..bd13056 100644 --- a/src/time/timer.h +++ b/src/time/timer.h @@ -7,7 +7,7 @@ #ifndef TIMER_H #define TIMER_H -void timer_init(); +void timer_init(void); void timer_wait(unsigned int wait_ticks); #endif \ No newline at end of file From e5c296238cd6331250263bfdc073976ec5ef4279 Mon Sep 17 00:00:00 2001 From: xamidev Date: Sat, 14 Mar 2026 09:31:57 +0100 Subject: [PATCH 6/6] Stack trace all black & void arg fix --- README.md | 4 +--- docs/STYLE.md | 2 +- src/debug/stacktrace.c | 2 +- src/kernel.h | 6 +++--- src/kmain.c | 1 + src/sched/scheduler.c | 5 +++++ 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d97dd0c..fa971a0 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,10 @@ The basics that I'm targeting are: ### Basic utility of what we call a "kernel" -- Fix terminal driver (backspace issues, scrolling) OR add Flanterm or equivalent - Implement tasks, and task switching + context switching and spinlock acquire/release - Load an executable - Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32 or easier fs) w/ VFS layer -- Getting to userspace (syscalls) +- Getting to userspace (ring 3 switching, syscall interface) - Porting musl libc or equivalent ### Scalability/maintenance/expansion features @@ -32,7 +31,6 @@ The basics that I'm targeting are: - SOME error handling in functions - Unit tests - Good error codes (like Linux kernel: ENOMEM, ENOENT, ...) -- Make the panic function work within itself without dependencies + error message (and still get cpu context?) ### Optional features diff --git a/docs/STYLE.md b/docs/STYLE.md index aa5e220..6321955 100644 --- a/docs/STYLE.md +++ b/docs/STYLE.md @@ -8,7 +8,7 @@ Indentations should be 4 characters long. ## Line length -Lines should not be more than 100 characters long. +Lines should not be more than 100 characters long. Exceptions is made for printing strings. ## Variables diff --git a/src/debug/stacktrace.c b/src/debug/stacktrace.c index 1f9c27c..430bf94 100644 --- a/src/debug/stacktrace.c +++ b/src/debug/stacktrace.c @@ -46,7 +46,7 @@ void debug_stack_trace(unsigned int max_frames) rbp = next_rbp; } if (init.terminal) { - printf("*** end stack trace ***[0m"); + printf("*** end stack trace ***\x1b[0m"); } DEBUG("*** end stack trace ***"); } diff --git a/src/kernel.h b/src/kernel.h index 0b276cc..f15e53e 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -36,13 +36,13 @@ extern volatile uint64_t ticks; // printf("debug: [%s]: " log "\n", __FILE__, ##__VA_ARGS__); void panic(struct cpu_status_t* ctx, const char* str); -void hcf(); -void idle(); +void hcf(void); +void idle(void); /* debug */ void debug_stack_trace(unsigned int max_frames); const char* debug_find_symbol(uintptr_t rip, uintptr_t* offset); -void boot_mem_display(); +void boot_mem_display(void); #define assert(check) do { if(!(check)) hcf(); } while(0) diff --git a/src/kmain.c b/src/kmain.c index d75831b..0f527e4 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -124,5 +124,6 @@ void kmain() scheduler_init(); kputs(PEPPEROS_SPLASH); + idle(); } diff --git a/src/sched/scheduler.c b/src/sched/scheduler.c index eedd3bc..381b601 100644 --- a/src/sched/scheduler.c +++ b/src/sched/scheduler.c @@ -43,6 +43,11 @@ struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context) current_process = idle_proc; } + if (current_process == idle_proc && current_process->next == NULL) + { + return idle_proc->context; + } + current_process->context = context; //current_process->status = READY;