process #9

Merged
xamidev merged 7 commits from process into main 2026-02-06 21:46:08 +01:00
9 changed files with 110 additions and 43 deletions
Showing only changes of commit 7f997f6611 - Show all commits

View File

@@ -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 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: build:
rm -f *.o 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 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 nasm -f elf64 src/idt/idt.S -o idt_stub.o
x86_64-elf-ld -o pepperk -T linker.ld *.o x86_64-elf-ld -o pepperk -T linker.ld *.o

View File

@@ -11,18 +11,28 @@ To run it with QEMU, `make run`
The basics that I'm targeting are: 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 - 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 - Implement tasks, and task switching
- Load an executable - 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 or easier fs) w/ VFS layer
- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32
- Getting to userspace (syscalls) - Getting to userspace (syscalls)
- Porting musl libc or equivalent - 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 - Parsing the ACPI tables and using them for something
- Replacing the PIT timer with APIC - Replacing the PIT timer with APIC

View File

@@ -188,12 +188,14 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
case 32: case 32:
//DEBUG("Timer Interrupt"); //DEBUG("Timer Interrupt");
ticks++; ticks++;
if (ticks % SCHEDULER_QUANTUM == 0) if (ticks % SCHEDULER_QUANTUM == 0)
{ {
CLEAR_INTERRUPTS; CLEAR_INTERRUPTS;
scheduler_schedule(); scheduler_schedule();
SET_INTERRUPTS; SET_INTERRUPTS;
} }
// Send an EOI so that we can continue having interrupts // Send an EOI so that we can continue having interrupts
outb(0x20, 0x20); outb(0x20, 0x20);
break; break;

View File

@@ -67,7 +67,7 @@ void hcf()
void panic(struct cpu_status_t* ctx) 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->iret_rip,
ctx->vector_number, ctx->error_code, ctx->rax, ctx->rbx, ctx->rcx, ctx->rdx, ctx->rsi, ctx->rdi, 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, 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(); 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(); vmm_init();
struct process_t* pedicel = process_create("pedicel", (void*)pedicel_main, 0); struct process_t* pedicel = process_create("pedicel", (void*)pedicel_main, 0);

View File

@@ -16,12 +16,24 @@ static uintptr_t end;
// Kernel root table (level 4) // Kernel root table (level 4)
extern uint64_t *kernel_pml4; 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(); uintptr_t phys = pmm_alloc();
paging_map_page(kernel_pml4, end, phys, PTE_PRESENT | PTE_WRITABLE | PTE_NOEXEC); paging_map_page(kernel_pml4, end, phys, PTE_PRESENT | PTE_WRITABLE | PTE_NOEXEC);
end += PAGE_SIZE; end += PAGE_SIZE;
DEBUG("Mapped first kheap page"); //DEBUG("Mapped first kheap page");
} }
void kheap_init() void kheap_init()
@@ -44,6 +56,7 @@ void* kmalloc(size_t size)
{ {
// No size, no memory allocated! // No size, no memory allocated!
if (!size) return NULL; if (!size) return NULL;
size = ALIGN(size);
struct heap_block_t* curr = head; struct heap_block_t* curr = head;
@@ -53,17 +66,16 @@ void* kmalloc(size_t size)
if (curr->free && curr->size >= size) if (curr->free && curr->size >= size)
{ {
// We split the block if it is big enough // 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); //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 struct heap_block_t* split = (struct heap_block_t*)((uintptr_t)curr + sizeof(*curr) + size);
new_block->size = curr->size - size - sizeof(struct heap_block_t);
new_block->free = true; split->size = curr->size - size - sizeof(*curr);
split->free = true;
// Then we chain up the block in the list split->next = curr->next;
new_block->next = curr->next;
curr->next = new_block;
curr->next = split;
curr->size = size; curr->size = size;
} }
@@ -75,14 +87,14 @@ void* kmalloc(size_t size)
curr = curr->next; 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.. // for the block allocation. So we will allocate more..
uintptr_t old_end = end; 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; struct heap_block_t* block = (struct heap_block_t*)old_end;
block->size = PAGE_SIZE - sizeof(struct heap_block_t); block->size = ALIGN_UP(end - old_end - sizeof(struct heap_block_t), 16);
block->free = false; block->free = true;
block->next = NULL; block->next = NULL;
// Put the block at the end of the list // Put the block at the end of the list
@@ -93,7 +105,7 @@ void* kmalloc(size_t size)
} }
curr->next = block; curr->next = block;
return (void*)((uintptr_t)block + sizeof(struct heap_block_t)); return kmalloc(size);
} }
void kfree(void* ptr) void kfree(void* ptr)
@@ -104,12 +116,25 @@ void kfree(void* ptr)
// Set it free! // Set it free!
struct heap_block_t* block = (struct heap_block_t*)((uintptr_t)ptr - sizeof(struct heap_block_t)); struct heap_block_t* block = (struct heap_block_t*)((uintptr_t)ptr - sizeof(struct heap_block_t));
block->free = true; 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 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) // Should return a pointer to top of the stack (as stack grows DOWNWARDS)
void* kalloc_stack() void* kalloc_stack()
{ {
void* ptr = kmalloc(PROCESS_STACK_SIZE); uint8_t* ptr = kmalloc(PROCESS_STACK_SIZE);
return ptr+PROCESS_STACK_SIZE; return ptr ? ptr+PROCESS_STACK_SIZE : NULL;
} }

View File

@@ -23,5 +23,6 @@ void kheap_init();
void* kmalloc(size_t size); void* kmalloc(size_t size);
void kfree(void* ptr); void kfree(void* ptr);
void* kalloc_stack(); void* kalloc_stack();
void kheap_map_page();
#endif #endif

View File

@@ -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; root_table[pml4_i] = VIRT_TO_PHYS(pdpt) | PTE_PRESENT | PTE_WRITABLE;
} }
else { 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 // 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; pdpt[pdpt_i] = VIRT_TO_PHYS(pd) | PTE_PRESENT | PTE_WRITABLE;
} }
else { 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 // 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; pd[pd_i] = VIRT_TO_PHYS(pt) | PTE_PRESENT | PTE_WRITABLE;
} }
else { 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 // 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_phys_base;
uint64_t kernel_virt_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. // We should map the kernel, GDT, IDT, stack, framebuffer.
// Optionally we could map ACPI tables (we can find them in the Limine memmap) // Optionally we could map ACPI tables (we can find them in the Limine memmap)
kernel_phys_base = kaddr->physical_base; kernel_phys_base = boot_ctx.kaddr->physical_base;
kernel_virt_base = kaddr->virtual_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); 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 // for debug
uint64_t page_count = 0; uint64_t page_count = 0;
// HHDM map first 1 GB using given offset // Find max physical address from limine memmap
for (uint64_t i=0; i<0x40000000; i += PAGE_SIZE) uint64_t max_phys = 0;
for (uint64_t i=0; i<boot_ctx.mmap->entry_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<max_phys; i += PAGE_SIZE)
{ {
//paging_kmap_page(i+hhdm_off, i, PTE_WRITABLE); //paging_kmap_page(i+hhdm_off, i, PTE_WRITABLE);
paging_map_page(kernel_pml4, i+hhdm_off, i, PTE_WRITABLE); paging_map_page(kernel_pml4, i+hhdm_off, i, PTE_WRITABLE | PTE_PRESENT);
page_count++; page_count++;
} }
DEBUG("Mapped %u pages for first 1GB (HHDM)", page_count); page_count = 0; DEBUG("Mapped %u pages up to 0x%p (HHDM)", page_count, max_phys); page_count = 0;
// Map the kernel (according to virt/phys_base given by Limine) // Map the kernel (according to virt/phys_base given by Limine)
// SOME DAY when we want a safer kernel we should map .text as Read/Exec // SOME DAY when we want a safer kernel we should map .text as Read/Exec

View File

@@ -6,8 +6,9 @@
#include <stdint.h> #include <stdint.h>
#include <limine.h> #include <limine.h>
#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); void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags);
extern uint64_t hhdm_off; 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 PHYS_TO_VIRT(x) ((void*)((uintptr_t)(x) + hhdm_off))
#define VIRT_TO_PHYS(x) ((uintptr_t)(x) - hhdm_off) #define VIRT_TO_PHYS(x) ((uintptr_t)(x) - hhdm_off)
#define PTE_ADDR_MASK 0x000FFFFFFFFFF000
// Stole it // Stole it
#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) #define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
#define ALIGN_DOWN(x, align) ((x) & ~((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 PML4_INDEX(x) (((x) >> 39) & 0x1FF)
#define PDPT_INDEX(x) (((x) >> 30) & 0x1FF) #define PDPT_INDEX(x) (((x) >> 30) & 0x1FF)

View File

@@ -11,7 +11,7 @@ typedef enum
} status_t; } status_t;
#define PROCESS_NAME_MAX 64 #define PROCESS_NAME_MAX 64
#define PROCESS_STACK_SIZE 0x100 // 64kb #define PROCESS_STACK_SIZE 0x10000 // 64kb
struct process_t struct process_t
{ {