diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index d5a3ddc..6195b25 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -19,6 +19,19 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) extern void *BootGDT; vmm_set_page(0, V2P(&BootGDT), V2P(&BootGDT), PAGE_PRESENT); + void *a = kmalloc(0x400); + void *b = kmalloc(0x200); + void *c = kmalloc(0x100); + kfree(b); + void *d = kmalloc(0x100); + + (void)a; + (void)b; + (void)c; + (void)d; + + heap_print(); + debug_info("BOOT COMPLETE\n"); for(;;)asm("hlt"); } diff --git a/kernel/include/mem.h b/kernel/include/mem.h index f383f7d..d14f567 100644 --- a/kernel/include/mem.h +++ b/kernel/include/mem.h @@ -1,6 +1,7 @@ #pragma once #define KERNEL_OFFSET 0xFFFFFF8000000000 +#define KERNEL_HEAP_S 0xFFFFFFC000000000 #ifdef __ASSEMBLER__ #define V2P(a) ((a) - KERNEL_OFFSET) @@ -37,6 +38,8 @@ #define PAGE_GLOBAL 0x100 #ifndef __ASSEMBLER__ +#include + typedef void * page_table; extern page_table BootP4; @@ -54,4 +57,10 @@ void vmm_set_P4(page_table *P4); void vmm_free_P4(page_table *P4); uintptr_t vmm_get_page(page_table *P4, uintptr_t addr); uintptr_t vmm_set_page(page_table *P4, uintptr_t addr, uintptr_t phys, uint32_t flags); + +void kfree(void *a); +void *kmalloc(size_t size); +void *kcalloc(size_t count, size_t size); +void *krealloc(void *ptr, size_t size); +void heap_print(); #endif diff --git a/kernel/mem/heap.c b/kernel/mem/heap.c new file mode 100644 index 0000000..f0c8e9c --- /dev/null +++ b/kernel/mem/heap.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include + +typedef struct chunk_st +{ + struct chunk_st *p, *n; + uint8_t flags; + size_t size; + uint8_t data[]; +} chunk_t; +#define CHUNK_FREE 0x1 + +uintptr_t heap_max = KERNEL_HEAP_S; +uintptr_t brk = KERNEL_HEAP_S; + +chunk_t *heap = 0; + +void *ksbrk(size_t size) +{ + // This can only be used to increase the size of the kernel heap + // for now... + while(brk < heap_max + size) + { + vmm_set_page(0, brk, (uintptr_t)pmm_alloc(), PAGE_PRESENT | PAGE_WRITE); + brk += PAGE_SIZE; + } + heap_max += size; + return (void *)heap_max; +} + +void merge_chunk(chunk_t *c) +{ + // Join free chunks together if they are next to each other + + if(c->n && c->n->flags & CHUNK_FREE) // Merge with next + { + // Update size + c->size += c->n->size + sizeof(chunk_t); + // Update list + c->n = c->n->n; + if(c->n) + c->n->p = c; + } + if(c->p && c->p->flags & CHUNK_FREE) // Merge with previous + { + // Update size + c->p->size += c->size + sizeof(chunk_t); + // Update list + c->p->n = c->n; + if(c->n) + c->n->p = c->p; + } +} + +void split_chunk(chunk_t *c, size_t size) +{ + // Split a chunk into one of given size and one of with the rest + + if(c->size <= size + sizeof(chunk_t)) + return; + + // Split off as much as isn't needed + chunk_t *c2 = incptr(c->data, size); + c2->size = c->size - size - sizeof(chunk_t); + c2->flags = CHUNK_FREE; + + // Insert into list + c2->n = c->n; + if(c2->n) c2->n->p = c2; + c->n = c2; + c2->p = c; + + // Change size of first chunk + c->size = size; +} + +void kfree(void *a) +{ + if((uintptr_t)a < KERNEL_HEAP_S || (uintptr_t)a > heap_max) + { + debug_error("PANIC: kfree - Tried to free %x\n", a); + for(;;); + } + + // Find chunk header and mark as free + chunk_t *c = incptr(a, -sizeof(chunk_t)); + c->flags = CHUNK_FREE; + merge_chunk(c); +} + +void *kmalloc(size_t size) +{ + chunk_t *c = heap, *p = 0; + while(c) + { + // Linear search of list for free chunk + + if((c->flags & CHUNK_FREE) && c->size >= size) + { + // A large enough free chunk has been found + // adjust and return + split_chunk(c, size); + c->flags = 0; + return (void *)c->data; + } + p = c; + c = c->n; + } + + // No free chunk of right size found + // increase heap size + if(p) + { + c = incptr(p, p->size + sizeof(chunk_t)); + } else { + c = heap = (chunk_t *)heap_max; + } + + void *end = ksbrk(size + sizeof(chunk_t)); + // Add a new chunk + c->size = (uintptr_t)end - (uintptr_t)c->data; + c->flags = CHUNK_FREE; + c->n = c->p = 0; + c->p = p; + if(p) c->n = p->n; + if(p) p->n = c; + // And try again... + return kmalloc(size); +} + +void *kcalloc(size_t count, size_t size) +{ + void *ptr = kmalloc(count*size); + memset(ptr, 0, count*size); + return ptr; +} + +void *krealloc(void *ptr, size_t size) +{ + void *new = kmalloc(size); + if(ptr) + { + memcpy(new, ptr, size); + kfree(ptr); + } + return new; +} + +void heap_print() +{ + // Print all heap chunks + + chunk_t *c = heap; + debug_info("Heap map:\n"); + while(c) + { + debug("s:%x f:%x\n", c->size, c->flags); + c = c->n; + } +}