From 7f997f6611090e349aa0c1306ddacb8139126072 Mon Sep 17 00:00:00 2001 From: xamidev Date: Thu, 5 Feb 2026 21:18:21 +0100 Subject: [PATCH] alloc_stack ok (HHDM mapped from mmap) --- Makefile | 4 ++- README.md | 20 ++++++++++---- src/idt/idt.c | 2 ++ src/kmain.c | 7 +---- src/mem/heap/kheap.c | 61 +++++++++++++++++++++++++++++------------ src/mem/heap/kheap.h | 1 + src/mem/paging/paging.c | 47 ++++++++++++++++++++++++------- src/mem/paging/paging.h | 9 ++++-- src/sched/process.h | 2 +- 9 files changed, 110 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index dbaa534..c4394ba 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ SOURCES = 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 + build: rm -f *.o - x86_64-elf-gcc -g -c -Isrc $(SOURCES) -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel + 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 objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o nasm -f elf64 src/idt/idt.S -o idt_stub.o x86_64-elf-ld -o pepperk -T linker.ld *.o diff --git a/README.md b/README.md index 6fc722f..e6cc45a 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,28 @@ To run it with QEMU, `make run` 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 paging / see what Limine does at boot with memory management - Implement tasks, and task switching - Load an executable -- Scheduler (round-robin using the PIT timer interrupt) -- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32 +- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32 or easier fs) w/ VFS layer - Getting to userspace (syscalls) - Porting musl libc or equivalent -In the future, maybe? +### Scalability/maintenance/expansion features -- SMP support +- Global config header file +- Documentation +- 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 + +In the future, maybe? +- SMP support (Limine provides functionality to make this easier) - Parsing the ACPI tables and using them for something - Replacing the PIT timer with APIC diff --git a/src/idt/idt.c b/src/idt/idt.c index f6665bf..8ac633f 100644 --- a/src/idt/idt.c +++ b/src/idt/idt.c @@ -188,12 +188,14 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context) case 32: //DEBUG("Timer Interrupt"); ticks++; + if (ticks % SCHEDULER_QUANTUM == 0) { CLEAR_INTERRUPTS; scheduler_schedule(); SET_INTERRUPTS; } + // Send an EOI so that we can continue having interrupts outb(0x20, 0x20); break; diff --git a/src/kmain.c b/src/kmain.c index aeb02fd..68cd159 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -67,7 +67,7 @@ void hcf() void panic(struct cpu_status_t* ctx) { - DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m at rip=%p\nSomething went horribly wrong! vect=0x%.2x errcode=0x%x\nrax=%p rbx=%p rcx=%p rdx=%p\nrsi=%p rdi=%p r8=%p r9=%p\nr10=%p r11=%p r12=%p r13=%p\nr14=%p r15=%p\n\nflags=%p\nstack at rbp=%p\nHalting...", + DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m at rip=%p\nSomething went horribly wrong! 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\rstack at rbp=%p\n\rHalting...", ctx->iret_rip, 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, @@ -126,11 +126,6 @@ void kmain() kheap_init(); - void* ptr = kmalloc(10); DEBUG("(KMALLOC TEST) Allocated 10 bytes at 0x%p", ptr); - void* ptr2 = kmalloc(200); DEBUG("(KMALLOC TEST) Allocated 200 bytes at 0x%p", ptr2); - kfree(ptr); - void* ptr3 = kmalloc(5); DEBUG("(KMALLOC TEST) Allocated 5 bytes at 0x%p", ptr3); - vmm_init(); struct process_t* pedicel = process_create("pedicel", (void*)pedicel_main, 0); diff --git a/src/mem/heap/kheap.c b/src/mem/heap/kheap.c index 493f4e6..ee1ee34 100644 --- a/src/mem/heap/kheap.c +++ b/src/mem/heap/kheap.c @@ -16,12 +16,24 @@ static uintptr_t end; // Kernel root table (level 4) extern uint64_t *kernel_pml4; -static void kheap_map_page() +static void kheap_grow(size_t size) +{ + size_t pages = ALIGN_UP(size + sizeof(struct heap_block_t), PAGE_SIZE) / PAGE_SIZE; + + if (pages == 0) pages = 1; + + for (size_t i = 0; i < pages; i++) + { + kheap_map_page(); + } +} + +void kheap_map_page() { uintptr_t phys = pmm_alloc(); paging_map_page(kernel_pml4, end, phys, PTE_PRESENT | PTE_WRITABLE | PTE_NOEXEC); end += PAGE_SIZE; - DEBUG("Mapped first kheap page"); + //DEBUG("Mapped first kheap page"); } void kheap_init() @@ -44,6 +56,7 @@ void* kmalloc(size_t size) { // No size, no memory allocated! if (!size) return NULL; + size = ALIGN(size); struct heap_block_t* curr = head; @@ -53,17 +66,16 @@ void* kmalloc(size_t 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)) + if (curr->size >= size + BLOCK_MIN_SIZE) { - struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size); - // We have to subtract the size of our block struct - new_block->size = curr->size - size - sizeof(struct heap_block_t); - new_block->free = true; - - // Then we chain up the block in the list - new_block->next = curr->next; - curr->next = new_block; + //struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size); + struct heap_block_t* split = (struct heap_block_t*)((uintptr_t)curr + sizeof(*curr) + size); + + split->size = curr->size - size - sizeof(*curr); + split->free = true; + split->next = curr->next; + curr->next = split; curr->size = size; } @@ -75,14 +87,14 @@ void* kmalloc(size_t size) curr = curr->next; } - // If we're hear it means we didn't have enough memory + // If we're here it means we didn't have enough memory // for the block allocation. So we will allocate more.. uintptr_t old_end = end; - kheap_map_page(); + kheap_grow(size + sizeof(struct heap_block_t)); struct heap_block_t* block = (struct heap_block_t*)old_end; - block->size = PAGE_SIZE - sizeof(struct heap_block_t); - block->free = false; + block->size = ALIGN_UP(end - old_end - sizeof(struct heap_block_t), 16); + block->free = true; block->next = NULL; // Put the block at the end of the list @@ -93,7 +105,7 @@ void* kmalloc(size_t size) } curr->next = block; - return (void*)((uintptr_t)block + sizeof(struct heap_block_t)); + return kmalloc(size); } void kfree(void* ptr) @@ -104,12 +116,25 @@ void kfree(void* ptr) // Set it free! struct heap_block_t* block = (struct heap_block_t*)((uintptr_t)ptr - sizeof(struct heap_block_t)); block->free = true; + + // merge adjacent free blocks (coalescing) + struct heap_block_t* curr = head; + while (curr && curr->next) + { + if (curr->free && curr->next->free) + { + curr->size += sizeof(*curr) + curr->next->size; + curr->next = curr->next->next; + continue; + } + curr = curr->next; + } } // 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) void* kalloc_stack() { - void* ptr = kmalloc(PROCESS_STACK_SIZE); - return ptr+PROCESS_STACK_SIZE; + uint8_t* ptr = kmalloc(PROCESS_STACK_SIZE); + return ptr ? ptr+PROCESS_STACK_SIZE : NULL; } \ No newline at end of file diff --git a/src/mem/heap/kheap.h b/src/mem/heap/kheap.h index 2576c59..61b097e 100644 --- a/src/mem/heap/kheap.h +++ b/src/mem/heap/kheap.h @@ -23,5 +23,6 @@ void kheap_init(); void* kmalloc(size_t size); void kfree(void* ptr); void* kalloc_stack(); +void kheap_map_page(); #endif \ No newline at end of file diff --git a/src/mem/paging/paging.c b/src/mem/paging/paging.c index ce07aa1..c2a1a28 100644 --- a/src/mem/paging/paging.c +++ b/src/mem/paging/paging.c @@ -69,7 +69,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_ root_table[pml4_i] = VIRT_TO_PHYS(pdpt) | PTE_PRESENT | PTE_WRITABLE; } else { - pdpt = (uint64_t *)PHYS_TO_VIRT(root_table[pml4_i] & ~0xFFFULL); + pdpt = (uint64_t *)PHYS_TO_VIRT(root_table[pml4_i] & PTE_ADDR_MASK); } // PDPT: same here @@ -79,7 +79,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_ pdpt[pdpt_i] = VIRT_TO_PHYS(pd) | PTE_PRESENT | PTE_WRITABLE; } else { - pd = (uint64_t *)PHYS_TO_VIRT(pdpt[pdpt_i] & ~0xFFFULL); + pd = (uint64_t *)PHYS_TO_VIRT(pdpt[pdpt_i] & PTE_ADDR_MASK); } // PD: and here @@ -89,7 +89,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_ pd[pd_i] = VIRT_TO_PHYS(pt) | PTE_PRESENT | PTE_WRITABLE; } else { - pt = (uint64_t *)PHYS_TO_VIRT(pd[pd_i] & ~0xFFFULL); + pt = (uint64_t *)PHYS_TO_VIRT(pd[pd_i] & PTE_ADDR_MASK); } // PT: finally, populate the page table entry @@ -102,13 +102,16 @@ 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; -void paging_init(struct limine_kernel_address_response* kaddr, struct limine_framebuffer* fb) +extern struct boot_context boot_ctx; + +void paging_init() { // We should map the kernel, GDT, IDT, stack, framebuffer. // Optionally we could map ACPI tables (we can find them in the Limine memmap) - kernel_phys_base = kaddr->physical_base; - kernel_virt_base = kaddr->virtual_base; + kernel_phys_base = boot_ctx.kaddr->physical_base; + kernel_virt_base = boot_ctx.kaddr->virtual_base; + struct limine_framebuffer* fb = boot_ctx.fb; DEBUG("Kernel lives at virt=0x%p phys=0x%p", kernel_virt_base, kernel_phys_base); @@ -117,14 +120,38 @@ void paging_init(struct limine_kernel_address_response* kaddr, struct limine_fra // for debug uint64_t page_count = 0; - // HHDM map first 1 GB using given offset - for (uint64_t i=0; i<0x40000000; i += PAGE_SIZE) + // Find max physical address from limine memmap + uint64_t max_phys = 0; + for (uint64_t i=0; ientry_count; i++) + { + struct limine_memmap_entry* entry = boot_ctx.mmap->entries[i]; + if (entry->length == 0) + { + continue; + } + uint64_t top = entry->base + entry->length; + if (top > max_phys) + { + max_phys = top; + } + //DEBUG("max_phys=0x%p", max_phys); + } + + // 4GB + if (max_phys > 0x100000000) + { + DEBUG("WARNING: max_phys capped to 4GB (0x100000000) (from max_phys=%p)", max_phys); + max_phys = 0x100000000; + } + + // 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" -void paging_init(struct limine_kernel_address_response* kaddr, struct limine_framebuffer* fb); +void paging_init(); void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags); extern uint64_t hhdm_off; @@ -15,10 +16,14 @@ extern uint64_t hhdm_off; #define PHYS_TO_VIRT(x) ((void*)((uintptr_t)(x) + hhdm_off)) #define VIRT_TO_PHYS(x) ((uintptr_t)(x) - hhdm_off) +#define PTE_ADDR_MASK 0x000FFFFFFFFFF000 // Stole it #define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) #define ALIGN_DOWN(x, align) ((x) & ~((align) - 1)) -#define PAGE_ALIGN_DOWN(x) ((x) & ~0xFFFULL) +#define PAGE_ALIGN_DOWN(x) ((x) & PTE_ADDR_MASK) + +#define ALIGN(size) ALIGN_UP(size, 16) +#define BLOCK_MIN_SIZE (sizeof(struct heap_block_t) + 16) #define PML4_INDEX(x) (((x) >> 39) & 0x1FF) #define PDPT_INDEX(x) (((x) >> 30) & 0x1FF) diff --git a/src/sched/process.h b/src/sched/process.h index c60f838..9ec19bd 100644 --- a/src/sched/process.h +++ b/src/sched/process.h @@ -11,7 +11,7 @@ typedef enum } status_t; #define PROCESS_NAME_MAX 64 -#define PROCESS_STACK_SIZE 0x100 // 64kb +#define PROCESS_STACK_SIZE 0x10000 // 64kb struct process_t {