summaryrefslogtreecommitdiff
path: root/kernel/kalloc.c
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-06-02 00:26:57 +0200
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-06-02 00:26:57 +0200
commit45f420a338ea02225bb8a98c9aca5eed8d6a23ae (patch)
tree97fdb1c8e81ba79b101b928158e5e37fa938c8f3 /kernel/kalloc.c
Initial commit
Diffstat (limited to 'kernel/kalloc.c')
-rw-r--r--kernel/kalloc.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/kernel/kalloc.c b/kernel/kalloc.c
new file mode 100644
index 0000000..e197c0c
--- /dev/null
+++ b/kernel/kalloc.c
@@ -0,0 +1,87 @@
+#include "kernel/lib.h"
+#include "kernel/kalloc.h"
+#include "kernel/spinlock.h"
+
+extern uint32_t _heap_start;
+extern uint32_t _heap_end;
+
+union Page
+{
+ union Page* next;
+ char dummy[PAGE_SIZE];
+};
+typedef union Page Page;
+static_assert(sizeof(Page) == PAGE_SIZE);
+
+static inline void* align_page_down(void* p)
+{
+ return (void*)((uint32_t)p & ~(PAGE_SIZE - 1));
+}
+
+static inline void* align_page_up(void* p)
+{
+ return align_page_down((char*)p + PAGE_SIZE - 1);
+}
+
+static inline bool is_page_aligned(void* p)
+{
+ return ((uint32_t)p & (PAGE_SIZE - 1)) == 0;
+}
+
+static Page* g_page_start;
+static Page* g_page_end;
+static Page* g_free_list;
+static Spinlock g_lock;
+
+void kalloc_init()
+{
+ spinlock_init(&g_lock);
+
+ g_free_list = NULL;
+ g_page_start = (Page*)align_page_up(&_heap_start);
+ g_page_end = (Page*)align_page_down(&_heap_end);
+
+ for (Page* p = g_page_end - 1; p >= g_page_start; --p)
+ {
+ p->next = g_free_list;
+ g_free_list = p;
+ }
+}
+
+void* kalloc()
+{
+ spinlock_acquire(&g_lock);
+ Page* page = g_free_list;
+ if (!page)
+ {
+ panic("kalloc: Out of memory");
+ }
+ g_free_list = page->next;
+ spinlock_release(&g_lock);
+ return page;
+}
+
+void* kzalloc()
+{
+ void* page = kalloc();
+ uint32_t* p = (uint32_t*)page;
+ for (uint32_t i = 0; i < PAGE_SIZE / 4; ++i)
+ {
+ *p++ = 0U;
+ }
+ return page;
+}
+
+void kfree(void* ptr)
+{
+ if (ptr < (void*)g_page_start || ptr >= (void*)g_page_end || !is_page_aligned(ptr))
+ {
+ panic("kfree: Invalid page");
+ }
+
+ spinlock_acquire(&g_lock);
+ Page* page = (Page*)ptr;
+ page->next = g_free_list;
+ g_free_list = page;
+ spinlock_release(&g_lock);
+}