Implemented a simple kernel heap

This commit is contained in:
2025-04-29 20:10:59 +02:00
parent 9181f3afd3
commit 5522218767
5 changed files with 190 additions and 89 deletions
+25
View File
@@ -0,0 +1,25 @@
#ifndef _KALLOC_H
#define _KALLOC_H
#include <kernel.h>
// TODO: Set a better minimum that just a random number
#define KMALLOC_MIN_PAGES 4
// kmalloc() singly-linked list node
struct kmalloc_node {
size_t size;
int free;
struct kmalloc_node* next;
};
extern struct kmalloc_node* kmalloc_head;
int kmalloc_init(void);
void* kmalloc(size_t size);
void* kzalloc(size_t size);
void* kcalloc(size_t size, size_t count);
void* krealloc(size_t size, void* ptr);
void kfree(void* ptr);
#endif
-13
View File
@@ -1,13 +0,0 @@
#ifndef _VMM_H
#define _VMM_H
#include <kernel.h>
#include <bitmap.h>
extern bitmap_t vmm_bitmap;
int vmm_init(void);
void* vmm_alloc(size_t pages);
void vmm_free(void* ptr, size_t pages);
#endif
+3 -4
View File
@@ -1,4 +1,5 @@
#include <bootloader.h>
#include <kmalloc.h>
#include <kernel.h>
#include <paging.h>
#include <serial.h>
@@ -7,7 +8,6 @@
#include <isr.h>
#include <pmm.h>
#include <tty.h>
#include <vmm.h>
__noreturn
void kmain(void* ptr, uint32_t magic) {
@@ -24,17 +24,16 @@ void kmain(void* ptr, uint32_t magic) {
// Memory manager init
if (pmm_init() != 0) panic("Failed to initalize Physical Memory Manager.");
if (vmm_init() != 0) panic("Failed to initalize Virtual Memory Manager.");
if (kmalloc_init() != 0) panic("Failed to initialize kernel heap.");
// VGA TTY
if (tty_init() != 0) panic("Failed to initalize TTY driver.");
tty_puts("kern.\n\n");
// Timer
if (timer_init() != 0) panic("Failed to initialize timer.");
// TODO: Syscalls
// TODO: Scheduler
// TODO: Syscalls
// TODO: Interprocess communication
// TODO: Tasking
// TODO: Load & run /sbin/init
+162
View File
@@ -0,0 +1,162 @@
#include <kernel.h>
#include <paging.h>
#include <serial.h>
#include <string.h>
#include <pmm.h>
#include <kmalloc.h>
struct kmalloc_node* kmalloc_head = NULL;
size_t kmalloc_pages;
size_t kmalloc_base;
int kmalloc_init(void) {
kmalloc_base = KERNEL_HEAP_BASE;
kmalloc_pages = KMALLOC_MIN_PAGES;
for (size_t i = 0; i < kmalloc_pages; i++) {
uint32_t paddr = (uint32_t)pmm_alloc();
if (paddr == 0) {
kmalloc_pages = i;
break;
}
pag_map(kmalloc_base + i * PAGE_SIZE, paddr, 0);
}
kmalloc_head = (struct kmalloc_node*)kmalloc_base;
if (kmalloc_pages < KMALLOC_MIN_PAGES) return 1;
kmalloc_head->size = (kmalloc_pages * PAGE_SIZE) - sizeof(*kmalloc_head);
kmalloc_head->free = 1;
kmalloc_head->next = NULL;
debugf("[kmalloc] kmalloc() initialized.\n");
return 0;
}
void kmalloc_split(struct kmalloc_node* node, size_t size) {
if (node->size < size + sizeof(struct kmalloc_node)) return;
struct kmalloc_node* remainder =
(struct kmalloc_node*)((uint32_t)node + size + sizeof(struct kmalloc_node));
remainder->size = node->size - size - sizeof(struct kmalloc_node);
remainder->free = 1;
remainder->next = node->next;
node->size = size;
node->free = 0;
node->next = remainder;
}
void kmalloc_merge() {
struct kmalloc_node* current = kmalloc_head;
while (current != NULL && current->next != NULL) {
if (current->free && current->next->free) {
current->size += current->next->size + sizeof(struct kmalloc_node);
current->next = current->next->next;
break;
}
current = current->next;
}
}
void* kmalloc(size_t size) {
if (size == 0) return NULL; // Why would you...
struct kmalloc_node* current = kmalloc_head;
while ((current->size <= size || !current->free) && current->next != NULL) {
current = current->next;
}
if (current->size == size) current->free = 0;
else if (current->size > size) kmalloc_split(current, size);
else { // Allocate more pages
size_t found_size = current->free ? current->size : 0;
size_t page_count = 1;
found_size += PAGE_SIZE;
while (found_size < size + sizeof(struct kmalloc_node)) {
page_count++;
found_size += PAGE_SIZE;
}
uint32_t vaddr = kmalloc_base + kmalloc_pages * PAGE_SIZE;
for (size_t i = 0; i < page_count; i++) {
// WARN: This could be a memory leak! It doesn't free after allocating :/
uint32_t paddr = (uint32_t)pmm_alloc();
if (paddr == 0) return NULL;
pag_map(vaddr + i * PAGE_SIZE, paddr, 0);
kmalloc_pages++;
}
if (current->free) {
current->size += PAGE_SIZE * page_count;
} else {
current->next = (struct kmalloc_node*)vaddr;
current = current->next;
current->size = PAGE_SIZE * page_count;
current->free = 1;
current->next = NULL;
}
return kmalloc(size);
}
return (void*)current + sizeof(struct kmalloc_node);
}
void* kzalloc(size_t size) {
void* ptr = kmalloc(size);
if (ptr == NULL) return NULL;
memset(ptr, 0, size);
return ptr;
}
void* kcalloc(size_t size, size_t count) {
size_t siz = size * count;
void* ptr = kmalloc(siz);
if (ptr == NULL) return NULL;
memset(ptr, 0, siz);
return ptr;
}
void* krealloc(size_t size, void* ptr) {
void* new = kmalloc(size);
struct kmalloc_node* current = kmalloc_head;
while (current != NULL) {
if ((void*)current + sizeof(struct kmalloc_node) == ptr) break;
current = current->next;
}
// Tried to realloc non-existent buffer
if (current == NULL) return NULL;
if (size > current->size) size = current->size;
memcpy(ptr, new, size);
kfree(ptr);
return new;
}
void kfree(void* ptr) {
struct kmalloc_node* current = kmalloc_head;
while (current != NULL) {
if ((void*)current + sizeof(struct kmalloc_node) == ptr) {
current->free = 1;
kmalloc_merge();
break;
}
current = current->next;
}
}
-72
View File
@@ -1,72 +0,0 @@
#include <bitmap.h>
#include <kernel.h>
#include <paging.h>
#include <pmm.h>
#include <vmm.h>
bitmap_t vmm_bitmap;
int vmm_init(void) {
vmm_bitmap.ready = 0;
vmm_bitmap.membase = KERNEL_HEAP_BASE;
vmm_bitmap.blocks = dceil(KERNEL_HEAP_SIZE, BLOCK_SIZE);
vmm_bitmap.bytes = dceil(vmm_bitmap.blocks, 8);
uint32_t bitmap_loc = 0xC6000000;
size_t page_count = dceil(vmm_bitmap.bytes, PAGE_SIZE);
for (size_t i = 0; i < page_count; i++) {
void* fr = pmm_alloc();
if (fr == NULL) return 1;
pag_map(bitmap_loc + i * PAGE_SIZE, (uint32_t)fr, 0);
}
// Set all pages as
vmm_bitmap.map = (void*)bitmap_loc;
bmap_set_all(&vmm_bitmap, 0);
bmap_set(&vmm_bitmap, 0, 1);
bmap_set(&vmm_bitmap, 8, 1);
debugf(
"[vmm] Virtual memory manager initialized.\n"
"\tBitmap manages %d blocks\n"
"\tBitmap is at 0x%08x in virtual memory\n"
"\tBitmap is %d bytes over %d pages\n",
vmm_bitmap.blocks, vmm_bitmap.map,
vmm_bitmap.bytes, page_count
);
vmm_bitmap.ready = 1;
return 0;
}
void* vmm_alloc(size_t pages) {
size_t idx = bmap_get_area(&vmm_bitmap, pages, 0);
if (idx == BMAP_NOT_FOUND) return NULL;
void* ptr = bmap_ptr(&vmm_bitmap, idx);
bmap_set_area(&vmm_bitmap, idx * BLOCK_SIZE, pages * PAGE_SIZE, 1);
for (size_t i = 0; i < pages; i++) {
void* fr = pmm_alloc();
if (fr == NULL) return NULL;
pag_map((uint32_t)ptr + i * PAGE_SIZE, (uint32_t)fr, 0);
}
return ptr;
}
void vmm_free(void* ptr, size_t pages) {
for (size_t i = 0; i < pages; i++) {
uint32_t vaddr = (uint32_t)ptr + i * PAGE_SIZE;
uint32_t paddr = (uint32_t)pag_virt_to_phys((uint32_t)ptr);
pmm_free((void*)paddr);
pag_umap(vaddr);
}
size_t base = ((size_t)ptr - KERNEL_BASE) / BLOCK_SIZE;
bmap_set_area(&vmm_bitmap, base, pages, 0);
}