diff --git a/meta/targets/kernel-riscv32.ld b/meta/targets/kernel-riscv32.ld
index 1f806b8..060af29 100644
--- a/meta/targets/kernel-riscv32.ld
+++ b/meta/targets/kernel-riscv32.ld
@@ -34,9 +34,7 @@ SECTIONS {
 
     . += CONSTANT(MAXPAGESIZE);
 
-    stack_start_addr = .;
     . = ALIGN(4);
     . += 128 * 1024; /* 128KB */
     __stack_top = .;
-    stack_end_addr = .;
 }
diff --git a/src/kernel/core/mod.c b/src/kernel/core/mod.c
index 1aac74e..fcfcef6 100644
--- a/src/kernel/core/mod.c
+++ b/src/kernel/core/mod.c
@@ -1,9 +1,20 @@
+#include <allocators/slab.h>
 #include <fmt>
 #include <hal>
+#include <kmalloc>
 #include <logger>
+#include <string.h>
 
 void kmain(void) {
-    info$("Hello, World!");
+    kmalloc_init();
+
+    Allocator kmalloc = kmalloc_allocator();
+    char* hello       = (char*)kmalloc.alloc(&kmalloc, 14);
+    memset(hello, 0, 14);
+    strncpy(hello, "Hello, World!", 13);
+    info$("%s", hello);
+    kmalloc.free(&kmalloc, hello, 14);
+
     for (;;)
         ;
 }
diff --git a/src/kernel/hal/manifest.json b/src/kernel/hal/manifest.json
index 8fcd516..95166fe 100644
--- a/src/kernel/hal/manifest.json
+++ b/src/kernel/hal/manifest.json
@@ -4,6 +4,6 @@
     "id": "hal",
     "requires": [
         "hal-impl",
-        "heap"
+        "allocators"
     ]
 }
diff --git a/src/kernel/hal/mod.h b/src/kernel/hal/mod.h
index 5c7d773..5b96c74 100644
--- a/src/kernel/hal/mod.h
+++ b/src/kernel/hal/mod.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <dtb>
+#include <helpers/errors.h>
 #include <io>
 
 void hal_setup(void);
@@ -16,15 +17,17 @@ typedef enum {
     HAL_MAP_HUGE  = 1 << 4,
 } HalMapFlags;
 
-typedef enum {
-    HAL_MAP_OK,
-    HAL_MAP_PHYS_UNALIGNED,
-    HAL_MAP_VIRT_UNALIGNED,
-    HAL_MAP_COULDNT_ALLOCATE,
-    HAL_MAP_ALREADY_MAPPED,
-} HalMappingError;
+#define MAPPING_ERRORS(ERR)                                      \
+    ERR(HAL_MAP_OK, "Operation completed successfully")          \
+    ERR(HAL_MAP_PHYS_UNALIGNED, "Physical address is unaligned") \
+    ERR(HAL_MAP_VIRT_UNALIGNED, "Virtual address is unaligned")  \
+    ERR(HAL_MAP_COULDNT_ALLOCATE, "Couldn't allocate memory")    \
+    ERR(HAL_MAP_ALREADY_MAPPED, "Page is already mapped")
 
-typedef struct _page HalPage;
+DECLARE_ERROR_ENUM(HalMapping, MAPPING_ERRORS)
+DECLARE_ERROR_STRING(HalMapping, MAPPING_ERRORS)
+
+typedef struct _hal_page HalPage;
 
 HalMappingError hal_map_page(HalPage page, uintptr_t virt, uintptr_t phys, size_t length, uint8_t flags);
 
@@ -32,6 +35,16 @@ void hal_switch_space(HalPage space);
 
 size_t page_size(void);
 
+void* hal_mmap_l2h(uintptr_t addr);
+
+void* hal_mmap_h2l(uintptr_t addr);
+
+/* === TASKS & SCHEDULING === */
+
+typedef struct _hal_context HalContext;
+
+HalContext* hal_create_context(void);
+
 /* === I/O === */
 
 void hal_putc(int ch);
diff --git a/src/kernel/hal/rv32/boot.c b/src/kernel/hal/rv32/boot.c
index f4d9e00..a58e651 100644
--- a/src/kernel/hal/rv32/boot.c
+++ b/src/kernel/hal/rv32/boot.c
@@ -1,7 +1,8 @@
+#include <allocators/bump.h>
+#include <allocators/slab.h>
 #include <dtb>
 #include <hal>
 #include <handover-dtb>
-#include <heap/bump.h>
 #include <helpers/mem.h>
 #include <logger>
 #include <pmm>
diff --git a/src/kernel/hal/rv32/boot.s b/src/kernel/hal/rv32/boot.s
index 8cbb97b..ca7f99b 100644
--- a/src/kernel/hal/rv32/boot.s
+++ b/src/kernel/hal/rv32/boot.s
@@ -1,7 +1,9 @@
 .section .text.boot
+
 .global rv32_start 
 .type rv32_start, @function
 
+
 .global _start
 _start:
     mv ra, zero
diff --git a/src/kernel/hal/rv32/context.c b/src/kernel/hal/rv32/context.c
new file mode 100644
index 0000000..7d5c996
--- /dev/null
+++ b/src/kernel/hal/rv32/context.c
@@ -0,0 +1,8 @@
+#include <hal>
+#include <string.h>
+
+#include "context.h"
+
+HalContext* hal_context_create(void) {
+    return NULL;
+}
diff --git a/src/kernel/hal/rv32/context.h b/src/kernel/hal/rv32/context.h
new file mode 100644
index 0000000..2978066
--- /dev/null
+++ b/src/kernel/hal/rv32/context.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <hal>
+
+#include "regs.h"
+
+struct _hal_context {
+    Stackframe frame;
+};
diff --git a/src/kernel/hal/rv32/exception.c b/src/kernel/hal/rv32/exception.c
index 8b111bd..438b3b3 100644
--- a/src/kernel/hal/rv32/exception.c
+++ b/src/kernel/hal/rv32/exception.c
@@ -42,7 +42,7 @@ static void panic_handler(Stackframe* frame, uint32_t scause, uint32_t stval, ui
     }
 }
 
-void exception_handler(Stackframe* frame) {
+Stackframe* exception_handler(Stackframe* frame) {
     uint32_t scause  = read_csr$(scause);
     uint32_t stval   = read_csr$(stval);
     uint32_t user_pc = read_csr$(sepc);
@@ -52,4 +52,6 @@ void exception_handler(Stackframe* frame) {
     } else {
         panic_handler(frame, scause, stval, user_pc);
     }
+
+    return frame;
 }
diff --git a/src/kernel/hal/rv32/exception.h b/src/kernel/hal/rv32/exception.h
index 5ac5518..70fa1e0 100644
--- a/src/kernel/hal/rv32/exception.h
+++ b/src/kernel/hal/rv32/exception.h
@@ -4,4 +4,4 @@
 
 extern void interrupt_kernel(void);
 
-void exception_handler(Stackframe* frame);
+Stackframe* exception_handler(Stackframe* frame);
diff --git a/src/kernel/hal/rv32/exception.s b/src/kernel/hal/rv32/exception.s
index de5b2cb..3320fa2 100644
--- a/src/kernel/hal/rv32/exception.s
+++ b/src/kernel/hal/rv32/exception.s
@@ -40,6 +40,7 @@ interrupt_kernel:
 
     mv a0, sp
     call exception_handler
+    mv sp, a0
     
     lw ra,  4 * 0(sp)
     lw gp,  4 * 1(sp)
diff --git a/src/kernel/hal/rv32/hal.c b/src/kernel/hal/rv32/hal.c
index 4ae210c..b8accb4 100644
--- a/src/kernel/hal/rv32/hal.c
+++ b/src/kernel/hal/rv32/hal.c
@@ -13,3 +13,11 @@ void hal_brkpoint(void) {
 size_t page_size(void) {
     return 4096;
 }
+
+void* hal_mmap_l2h(uintptr_t addr) {
+    return (void*)addr;
+}
+
+void* hal_mmap_h2l(uintptr_t addr) {
+    return (void*)addr;
+}
diff --git a/src/kernel/hal/rv32/manifest.json b/src/kernel/hal/rv32/manifest.json
index 348c2ad..2bab839 100644
--- a/src/kernel/hal/rv32/manifest.json
+++ b/src/kernel/hal/rv32/manifest.json
@@ -7,5 +7,5 @@
         "sys": ["kernel"]
     },
     "provides": ["hal-impl"],
-    "requires": ["dtb", "pmm", "handover-dtb"]
+    "requires": ["dtb", "pmm", "handover-dtb", "kmalloc"]
 }
diff --git a/src/kernel/hal/rv32/paging.c b/src/kernel/hal/rv32/paging.c
index f91ab66..8ced693 100644
--- a/src/kernel/hal/rv32/paging.c
+++ b/src/kernel/hal/rv32/paging.c
@@ -4,6 +4,7 @@
 #include <pmm>
 #include <string.h>
 
+#include "base/mod.h"
 #include "paging.h"
 #include "regs.h"
 
@@ -13,8 +14,7 @@ extern uint8_t rodata_start_addr[];
 extern uint8_t rodata_end_addr[];
 extern uint8_t data_start_addr[];
 extern uint8_t data_end_addr[];
-extern uint8_t stack_start_addr[];
-extern uint8_t stack_end_addr[];
+extern uint8_t __stack_top[];
 
 static uint32_t* kernel_page_table = NULL;
 
@@ -93,6 +93,7 @@ void hal_switch_space(HalPage space) {
     __asm__ volatile("sfence.vma");
 }
 
+// TODO: Use new error from <helpers/errors.h>
 void paging_init(void) {
     PhysObj page_phys = pmm_alloc(page_size());
     if (page_phys.base == 0) {
@@ -107,7 +108,7 @@ void paging_init(void) {
     size_t text_end     = align_up$((uintptr_t)text_end_addr, page_size());
     HalMappingError err = hal_map_page((HalPage){kernel_page_table}, text_start, text_start, text_end - text_start, HAL_MAP_READ | HAL_MAP_EXEC);
     if (err != HAL_MAP_OK) {
-        error$("Couldn't map kernel text, cause: %d", err);
+        error$("Couldn't map kernel text, cause: %s", HalMappingErrorString(err));
         hal_brkpoint();
     }
 
@@ -115,7 +116,7 @@ void paging_init(void) {
     size_t rodata_end   = align_up$((uintptr_t)rodata_end_addr, page_size());
     err                 = hal_map_page((HalPage){kernel_page_table}, rodata_start, rodata_start, rodata_end - rodata_start, HAL_MAP_READ);
     if (err != HAL_MAP_OK) {
-        error$("Couldn't map kernel rodata, cause: %d", err);
+        error$("Couldn't map kernel rodata, cause: %s", HalMappingErrorString(err));
         hal_brkpoint();
     }
 
@@ -123,18 +124,23 @@ void paging_init(void) {
     size_t data_end   = align_up$((uintptr_t)data_end_addr, page_size());
     err               = hal_map_page((HalPage){kernel_page_table}, data_start, data_start, data_end - data_start, HAL_MAP_READ | HAL_MAP_WRITE);
     if (err != HAL_MAP_OK) {
-        error$("Couldn't map kernel data, cause: %d", err);
+        error$("Couldn't map kernel data, cause: %s", HalMappingErrorString(err));
         hal_brkpoint();
     }
 
-    size_t stack_start = align_down$((uintptr_t)stack_start_addr, page_size());
-    size_t stack_end   = align_up$((uintptr_t)stack_end_addr, page_size());
+    size_t stack_start = align_down$((uintptr_t)__stack_top - kib$(128), page_size());
+    size_t stack_end   = align_up$((uintptr_t)__stack_top, page_size());
     err                = hal_map_page((HalPage){kernel_page_table}, stack_start, stack_start, stack_end - stack_start, HAL_MAP_READ | HAL_MAP_WRITE);
     if (err != HAL_MAP_OK) {
-        error$("Couldn't map kernel stack, cause: %d", err);
+        error$("Couldn't map kernel stack, cause: %s", HalMappingErrorString(err));
         hal_brkpoint();
     }
 
+    HandoverRecord rec;
+    handover_foreach_record(handover(), rec) {
+        hal_map_page((HalPage){kernel_page_table}, rec.start, rec.start, rec.size, HAL_MAP_READ | HAL_MAP_WRITE);
+    }
+
     debug$("Switching to page table %p", kernel_page_table);
     hal_switch_space((HalPage){kernel_page_table});
 }
diff --git a/src/kernel/hal/rv32/paging.h b/src/kernel/hal/rv32/paging.h
index 3b69ad0..38c2958 100644
--- a/src/kernel/hal/rv32/paging.h
+++ b/src/kernel/hal/rv32/paging.h
@@ -31,7 +31,7 @@ enum mapping_flags {
     MAPPING_USER    = 1 << 4,
 };
 
-struct _page {
+struct _hal_page {
     uint32_t* ptr;
 } __attribute__((packed));
 
diff --git a/src/kernel/kmalloc/manifest.json b/src/kernel/kmalloc/manifest.json
new file mode 100644
index 0000000..9960178
--- /dev/null
+++ b/src/kernel/kmalloc/manifest.json
@@ -0,0 +1,9 @@
+{
+    "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
+    "type": "lib",
+    "id": "kmalloc",
+    "requires": [
+        "allocators",
+        "traits"
+    ]
+}
diff --git a/src/kernel/kmalloc/manifest.sync-conflict-20250504-125402-L4Z4EYX.json b/src/kernel/kmalloc/manifest.sync-conflict-20250504-125402-L4Z4EYX.json
new file mode 100644
index 0000000..d303096
--- /dev/null
+++ b/src/kernel/kmalloc/manifest.sync-conflict-20250504-125402-L4Z4EYX.json
@@ -0,0 +1,9 @@
+{
+    "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
+    "id": "kmalloc",
+    "type": "lib",
+    "requires": [
+        "allocators",
+        "traits"
+    ]
+}
diff --git a/src/kernel/kmalloc/mod.c b/src/kernel/kmalloc/mod.c
new file mode 100644
index 0000000..340bb71
--- /dev/null
+++ b/src/kernel/kmalloc/mod.c
@@ -0,0 +1,70 @@
+#include <allocators/slab.h>
+#include <logger>
+#include <pmm>
+
+static SlabAllocator slabs[6] = {0};
+
+void kmalloc_init(void) {
+    Allocator pmm = pmm_allocator();
+
+    slabs[0] = slab_create(8, &pmm);
+    slabs[1] = slab_create(16, &pmm);
+    slabs[2] = slab_create(32, &pmm);
+    slabs[3] = slab_create(64, &pmm);
+    slabs[4] = slab_create(128, &pmm);
+    slabs[5] = slab_create(256, &pmm);
+}
+
+static void* _alloc(__attribute__((unused)) void* ctx, size_t len) {
+    Allocator* alloc = NULL;
+
+    if (len <= 8) {
+        alloc = &slabs[0].base;
+    } else if (len <= 16) {
+        alloc = &slabs[1].base;
+    } else if (len <= 32) {
+        alloc = &slabs[2].base;
+    } else if (len <= 64) {
+        alloc = &slabs[3].base;
+    } else if (len <= 128) {
+        alloc = &slabs[4].base;
+    } else if (len <= 256) {
+        alloc = &slabs[5].base;
+    } else {
+        Allocator pmm = pmm_allocator();
+        alloc         = &pmm;
+    }
+
+    return alloc->alloc(alloc, len);
+}
+
+static void _free(__attribute__((unused)) void* ctx, void* ptr, size_t len) {
+    Allocator* alloc = NULL;
+
+    if (len <= 8) {
+        alloc = &slabs[0].base;
+    } else if (len <= 16) {
+        alloc = &slabs[1].base;
+    } else if (len <= 32) {
+        alloc = &slabs[2].base;
+    } else if (len <= 64) {
+        alloc = &slabs[3].base;
+    } else if (len <= 128) {
+        alloc = &slabs[4].base;
+    } else if (len <= 256) {
+        alloc = &slabs[5].base;
+    } else {
+        Allocator pmm = pmm_allocator();
+        alloc         = &pmm;
+    }
+
+    alloc->free(alloc, ptr, len);
+}
+
+Allocator kmalloc_allocator(void) {
+    return (Allocator){
+        .alloc   = _alloc,
+        .free    = _free,
+        .realloc = NULL,
+    };
+}
diff --git a/src/kernel/kmalloc/mod.h b/src/kernel/kmalloc/mod.h
new file mode 100644
index 0000000..4b20725
--- /dev/null
+++ b/src/kernel/kmalloc/mod.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <traits/allocator.h>
+
+void kmalloc_init(void);
+
+Allocator kmalloc_allocator(void);
diff --git a/src/kernel/kmalloc/mod.sync-conflict-20250504-125402-L4Z4EYX.h b/src/kernel/kmalloc/mod.sync-conflict-20250504-125402-L4Z4EYX.h
new file mode 100644
index 0000000..6f70f09
--- /dev/null
+++ b/src/kernel/kmalloc/mod.sync-conflict-20250504-125402-L4Z4EYX.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/src/kernel/libs/libc/string.c b/src/kernel/libs/libc/string.c
index 8ab67df..9c9b930 100644
--- a/src/kernel/libs/libc/string.c
+++ b/src/kernel/libs/libc/string.c
@@ -48,3 +48,14 @@ void* memcpy(void* s1, void const* s2, size_t n) {
 
     return s1;
 }
+
+char* strncpy(char* s1, char const* s2, size_t n) {
+    size_t i = 0;
+
+    while (s2[i] != 0 && i < n) {
+        s1[i] = s2[i];
+        i++;
+    }
+
+    return s1;
+}
diff --git a/src/kernel/libs/libc/string.h b/src/kernel/libs/libc/string.h
index 81704f1..db1c94d 100644
--- a/src/kernel/libs/libc/string.h
+++ b/src/kernel/libs/libc/string.h
@@ -3,6 +3,11 @@
 #include <stddef.h>
 
 size_t strlen(char const* s);
+
 void* memset(void* s, int c, size_t n);
+
 int strncmp(char const* s1, char const* s2, size_t n);
+
+char* strncpy(char* s1, char const* s2, size_t n);
+
 void* memcpy(void* s1, void const* s2, size_t n);
diff --git a/src/kernel/libs/libc/unistd.c b/src/kernel/libs/libc/unistd.c
new file mode 100644
index 0000000..a69214a
--- /dev/null
+++ b/src/kernel/libs/libc/unistd.c
@@ -0,0 +1,7 @@
+#include <hal>
+
+#include "unistd.h"
+
+int getpagesize(void) {
+    return page_size();
+}
diff --git a/src/kernel/libs/libc/unistd.h b/src/kernel/libs/libc/unistd.h
new file mode 100644
index 0000000..985cce7
--- /dev/null
+++ b/src/kernel/libs/libc/unistd.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int getpagesize(void);
diff --git a/src/kernel/pmm/mod.c b/src/kernel/pmm/mod.c
index 5475871..df2b07b 100644
--- a/src/kernel/pmm/mod.c
+++ b/src/kernel/pmm/mod.c
@@ -4,6 +4,7 @@
 #include <logger>
 #include <string.h>
 
+#include "base/mod.h"
 #include "mod.h"
 
 static PmmBitmap bitmap = {0};
@@ -50,6 +51,13 @@ void pmm_init(void) {
         if (record.tag == HANDOVER_FREE && record.size >= bitmap.len) {
             debug$("Bitmap base: %p", record.start);
             bitmap.bitmap = (uint8_t*)record.start;
+
+            handover_append(handover(), (HandoverRecord){
+                                            .tag   = HANDOVER_RESERVED,
+                                            .start = record.start,
+                                            .size  = bitmap.len,
+                                        });
+
             record.start += bitmap.len;
             record.size -= bitmap.len;
             break;
@@ -109,3 +117,27 @@ PhysObj pmm_alloc(size_t len) {
 void pmm_free(PhysObj obj) {
     pmm_mark_free(obj.base, obj.len);
 }
+
+// === ALLOCATOR ===
+
+static void* _alloc(__attribute__((unused)) void* ctx, size_t len) {
+    PhysObj obj = pmm_alloc(len);
+    if (obj.len == 0) {
+        return NULL;
+    }
+
+    return hal_mmap_l2h(obj.base);
+}
+
+static void _free(__attribute__((unused)) void* ctx, void* ptr, size_t len) {
+    PhysObj obj = {.base = (uintptr_t)hal_mmap_h2l((uintptr_t)ptr), .len = len};
+    pmm_free(obj);
+}
+
+Allocator pmm_allocator(void) {
+    return (Allocator){
+        .alloc   = _alloc,
+        .free    = _free,
+        .realloc = NULL,
+    };
+}
diff --git a/src/kernel/pmm/mod.h b/src/kernel/pmm/mod.h
index e230c5d..a4db132 100644
--- a/src/kernel/pmm/mod.h
+++ b/src/kernel/pmm/mod.h
@@ -3,6 +3,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <traits/allocator.h>
 
 typedef struct
 {
@@ -25,3 +26,7 @@ struct pmm_alloc_param {
 PhysObj pmm_alloc(size_t pages);
 
 void pmm_init(void);
+
+void pmm_free(PhysObj obj);
+
+Allocator pmm_allocator(void);
diff --git a/src/kernel/sched/manifest.json b/src/kernel/sched/manifest.json
new file mode 100644
index 0000000..7d37590
--- /dev/null
+++ b/src/kernel/sched/manifest.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
+  "type": "lib",
+  "id": "sched",
+  "requires": []
+}
diff --git a/src/kernel/sched/mod.c b/src/kernel/sched/mod.c
new file mode 100644
index 0000000..dbc62b5
--- /dev/null
+++ b/src/kernel/sched/mod.c
@@ -0,0 +1,7 @@
+#include "mod.h"
+
+static size_t pid = 0;
+
+size_t sched_next_pid(void) {
+    return pid++;
+}
diff --git a/src/kernel/sched/mod.h b/src/kernel/sched/mod.h
new file mode 100644
index 0000000..42f0a93
--- /dev/null
+++ b/src/kernel/sched/mod.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <stddef.h>
+
+void sched_init(void);
+
+size_t sched_next_pid(void);
diff --git a/src/kernel/task/manifest.json b/src/kernel/task/manifest.json
new file mode 100644
index 0000000..1982f84
--- /dev/null
+++ b/src/kernel/task/manifest.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
+  "type": "lib",
+  "id": "task",
+  "requires": ["sched"]
+}
diff --git a/src/kernel/task/mod.c b/src/kernel/task/mod.c
new file mode 100644
index 0000000..f0651fb
--- /dev/null
+++ b/src/kernel/task/mod.c
@@ -0,0 +1,23 @@
+#include <helpers/math.h>
+#include <sched>
+#include <string.h>
+
+#include "mod.h"
+
+TaskError task_new(char const* name, HalPage* page_table, uintptr_t ip, Allocator* alloc) {
+    Task* task = alloc->alloc(alloc, sizeof(Task));
+
+    if (task == NULL) {
+        return TASK_COULDNT_ALLOC;
+    }
+
+    if (page_table == NULL) {
+        return TASK_PAGE_TABLE_NULL;
+    }
+
+    task->pid        = sched_next_pid();
+    task->page_table = page_table;
+    strncpy(task->name, name, min$(strlen(name), TASK_NAME_LIMIT - 1));
+
+    return TASK_OK;
+}
diff --git a/src/kernel/task/mod.h b/src/kernel/task/mod.h
new file mode 100644
index 0000000..f4ed9b8
--- /dev/null
+++ b/src/kernel/task/mod.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <hal>
+#include <helpers/errors.h>
+#include <stddef.h>
+#include <traits/allocator.h>
+
+#define TASK_NAME_LIMIT (256)
+
+typedef struct {
+    char name[TASK_NAME_LIMIT];
+    size_t pid;
+    HalPage* page_table;
+    HalContext* context;
+} Task;
+
+#define TASK_ERRORS(ERR)                                \
+    ERR(TASK_OK, "Operation completed successfully")    \
+    ERR(TASK_COULDNT_ALLOC, "Couldn't allocate memory") \
+    ERR(TASK_PAGE_TABLE_NULL, "The provided page table is NULL")
+
+DECLARE_ERROR_ENUM(Task, TASK_ERRORS)
+DECLARE_ERROR_STRING(Task, TASK_ERRORS)
+
+TaskError task_new(char const* name, HalPage* page_table, uintptr_t ip, Allocator* alloc);
diff --git a/src/libs/heap/bump.c b/src/libs/allocators/bump.c
similarity index 90%
rename from src/libs/heap/bump.c
rename to src/libs/allocators/bump.c
index 448210e..7f7682a 100644
--- a/src/libs/heap/bump.c
+++ b/src/libs/allocators/bump.c
@@ -1,7 +1,8 @@
-#include "bump.h"
 #include <helpers/mem.h>
 #include <logger>
 
+#include "bump.h"
+
 static void* alloc(void* ctx, size_t len) {
     size_t aligned_len = len & 7 ? align_up$(len, 8) : len;
 
@@ -17,7 +18,7 @@ static void* alloc(void* ctx, size_t len) {
     return (void*)ptr;
 }
 
-static void free(void* ctx, __attribute__((unused)) void* ptr) {
+static void free(void* ctx, __attribute__((unused)) void* ptr, __attribute__((unused)) size_t len) {
     BumpAllocator* self = (BumpAllocator*)ctx;
     self->allocations--;
 
diff --git a/src/libs/heap/bump.h b/src/libs/allocators/bump.h
similarity index 100%
rename from src/libs/heap/bump.h
rename to src/libs/allocators/bump.h
diff --git a/src/libs/heap/manifest.json b/src/libs/allocators/manifest.json
similarity index 82%
rename from src/libs/heap/manifest.json
rename to src/libs/allocators/manifest.json
index 2640f03..5f2334f 100644
--- a/src/libs/heap/manifest.json
+++ b/src/libs/allocators/manifest.json
@@ -1,5 +1,5 @@
 {
     "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
-    "id": "heap",
+    "id": "allocators",
     "type": "lib"
 }
diff --git a/src/libs/allocators/slab.c b/src/libs/allocators/slab.c
new file mode 100644
index 0000000..d1cc716
--- /dev/null
+++ b/src/libs/allocators/slab.c
@@ -0,0 +1,91 @@
+#include <allocators/bump.h>
+#include <helpers/mem.h>
+#include <logger>
+#include <unistd.h>
+
+#include "slab.h"
+
+static size_t page_amount(size_t size) {
+    if (size <= 64) {
+        return 64;
+    } else if (size <= 128) {
+        return 32;
+    } else if (size <= 512) {
+        return 16;
+    } else if (size <= 1024) {
+        return 8;
+    } else {
+        return 4;
+    }
+}
+
+static void* _alloc(void* ctx, __attribute__((unused)) size_t len) {
+    SlabAllocator* alloc = (SlabAllocator*)ctx;
+    if (alloc->root == NULL) {
+        return NULL;
+    }
+
+    void* ptr   = (void*)(alloc->root->ptr + sizeof(Slab));
+    alloc->root = alloc->root->next;
+    return ptr;
+}
+
+static void _free(void* ctx, void* ptr, __attribute__((unused)) size_t len) {
+    SlabAllocator* alloc = (SlabAllocator*)ctx;
+    Slab* free           = (Slab*)((uintptr_t)ptr - sizeof(Slab));
+
+    if (free->ptr + sizeof(Slab) != (uintptr_t)ptr) {
+        error$("Invalid free %p != %p", free->ptr, ptr);
+        return;
+    }
+
+    Slab* slab = alloc->root;
+
+    while (1) {
+        if (slab->next == NULL) {
+            break;
+        }
+
+        slab = slab->next;
+    }
+
+    slab->next = free;
+}
+
+SlabAllocator slab_create(uintptr_t size, Allocator* page_alloc) {
+    size_t n_page = page_amount(size + sizeof(Slab));
+    void* page    = page_alloc->alloc(page_alloc, n_page * getpagesize());
+
+    if (page == NULL) {
+        return (SlabAllocator){0};
+    }
+
+    size_t sz          = align_up$(sizeof(Slab) + size, sizeof(void*));
+    BumpAllocator bump = bump_allocator_create(page, n_page * getpagesize());
+    Slab* root         = bump.base.alloc(&bump, sz);
+    root->ptr          = (uintptr_t)root;
+
+    Slab* slab = root;
+
+    while (1) {
+        void* ptr = bump.base.alloc(&bump, sz);
+
+        if (ptr == NULL) {
+            slab->next = NULL;
+            break;
+        }
+
+        slab->next      = ptr;
+        slab->next->ptr = (uintptr_t)ptr;
+        slab            = slab->next;
+    }
+
+    return (SlabAllocator){
+        .base = {
+            .alloc   = _alloc,
+            .free    = _free,
+            .realloc = 0,
+        },
+        .root = root,
+    };
+}
diff --git a/src/libs/allocators/slab.h b/src/libs/allocators/slab.h
new file mode 100644
index 0000000..b012881
--- /dev/null
+++ b/src/libs/allocators/slab.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <stdint.h>
+#include <traits/allocator.h>
+
+#define PAGE_SIZE 4096
+
+typedef struct _slab {
+    uintptr_t ptr;
+    struct _slab* next;
+} Slab;
+
+typedef struct {
+    Allocator base;
+    Slab* root;
+} SlabAllocator;
+
+SlabAllocator slab_create(uintptr_t size, Allocator* page_alloc);
diff --git a/src/libs/handover/dtb/mod.c b/src/libs/handover/dtb/mod.c
index cc16ba3..b249db6 100644
--- a/src/libs/handover/dtb/mod.c
+++ b/src/libs/handover/dtb/mod.c
@@ -1,10 +1,7 @@
 #include <helpers/mem.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 
-#include "handover/base/mod.h"
-#include "logger/mod.h"
 #include "mod.h"
 
 static DTBNode* dtb_root        = NULL;
diff --git a/src/libs/helpers/errors.h b/src/libs/helpers/errors.h
new file mode 100644
index 0000000..9469df3
--- /dev/null
+++ b/src/libs/helpers/errors.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#define ENUM_ITEM(name, msg) name,
+#define STRINGIFY(name, msg) #msg,
+
+#define DECLARE_ERROR_ENUM(PREFIX, LIST) \
+    typedef enum {                       \
+        LIST(ENUM_ITEM)                  \
+    } PREFIX##Error;
+
+#define DECLARE_ERROR_STRING(PREFIX, LIST)                              \
+    __attribute__((used)) static const char* PREFIX##ErrorStrings[] = { \
+        LIST(STRINGIFY)                                                 \
+    };                                                                  \
+                                                                        \
+    inline static char const* PREFIX##ErrorString(PREFIX##Error err) {  \
+        return PREFIX##ErrorStrings[err];                               \
+    }
diff --git a/src/libs/helpers/math.h b/src/libs/helpers/math.h
new file mode 100644
index 0000000..671f722
--- /dev/null
+++ b/src/libs/helpers/math.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#define min$(x, y) ((x) < (y) ? (x) : (y))
+
+#define max$(x, y) ((x) > (y) ? (x) : (y))
diff --git a/src/libs/traits/allocator.h b/src/libs/traits/allocator.h
index f2095ba..9c88e14 100644
--- a/src/libs/traits/allocator.h
+++ b/src/libs/traits/allocator.h
@@ -5,5 +5,5 @@
 typedef struct {
     void* (*alloc)(void* ctx, size_t len);
     void* (*realloc)(void* ctx, void* ptr, size_t len);
-    void (*free)(void* ctx, void* ptr);
+    void (*free)(void* ctx, void* ptr, size_t len);
 } Allocator;