aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/memory
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/memory')
-rw-r--r--src/kernel/memory/kheap.c311
-rw-r--r--src/kernel/memory/kheap.h52
-rw-r--r--src/kernel/memory/ordered_array.c68
-rw-r--r--src/kernel/memory/ordered_array.h31
-rw-r--r--src/kernel/memory/paging.c203
-rw-r--r--src/kernel/memory/paging.h47
6 files changed, 712 insertions, 0 deletions
diff --git a/src/kernel/memory/kheap.c b/src/kernel/memory/kheap.c
new file mode 100644
index 0000000..def9ca2
--- /dev/null
+++ b/src/kernel/memory/kheap.c
@@ -0,0 +1,311 @@
+#include <stdint.h>
+#include <kernel/memory/kheap.h>
+#include <kernel/memory/paging.h>
+#include <kernel/system.h>
+
+uint32_t placement_address = (uint32_t) &ASM_KERNEL_END;
+extern page_directory_t *kernel_directory;
+heap_t *kheap = 0;
+
+uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys)
+{
+ if (kheap != 0) {
+ void *addr = alloc(sz, (uint8_t) align, kheap);
+ if (phys != 0) {
+ page_t *page = get_page((uint32_t) addr, 0, kernel_directory);
+ *phys = page->frame * 0x1000 + ((uint32_t) addr & 0xFFF);
+ }
+ return (uint32_t) addr;
+ } else {
+ if (align == 1 && (placement_address & 0xFFFFF000)) {
+ placement_address &= 0xFFFFF000;
+ placement_address += 0x1000;
+ }
+ if (phys) {
+ *phys = placement_address;
+ }
+ uint32_t tmp = placement_address;
+ placement_address += sz;
+ return tmp;
+ }
+}
+
+void kfree(void *p)
+{
+ free(p, kheap);
+}
+
+uint32_t kmalloc_a(uint32_t sz)
+{
+ return kmalloc_int(sz, 1, 0);
+}
+
+uint32_t kmalloc_p(uint32_t sz, uint32_t *phys)
+{
+ return kmalloc_int(sz, 0, phys);
+}
+
+uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys)
+{
+ return kmalloc_int(sz, 1, phys);
+}
+
+uint32_t kmalloc(uint32_t sz)
+{
+ return kmalloc_int(sz, 0, 0);
+}
+
+static void expand(uint32_t new_size, heap_t *heap)
+{
+ assert(new_size > heap->end_address - heap->start_address);
+
+ if ((new_size & 0xFFFFF000) != 0) {
+ new_size &= 0xFFFFF000;
+ new_size += 0x1000;
+ }
+
+ assert(heap->start_address + new_size <= heap->max_address);
+
+ uint32_t old_size = heap->end_address - heap->start_address;
+
+ uint32_t i = old_size;
+ while (i < new_size) {
+ alloc_frame(get_page(heap->start_address + i, 1, kernel_directory),
+ (heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1);
+ i += 0x1000;
+ }
+ heap->end_address = heap->start_address + new_size;
+}
+
+static uint32_t contract(uint32_t new_size, heap_t *heap)
+{
+ assert(new_size < heap->end_address - heap->start_address);
+
+ if (new_size & 0x1000) {
+ new_size &= 0x1000;
+ new_size += 0x1000;
+ }
+
+ if (new_size < HEAP_MIN_SIZE)
+ new_size = HEAP_MIN_SIZE;
+
+ uint32_t old_size = heap->end_address - heap->start_address;
+ uint32_t i = old_size - 0x1000;
+ while (new_size < i) {
+ free_frame(get_page(heap->start_address + i, 0, kernel_directory));
+ i -= 0x1000;
+ }
+
+ heap->end_address = heap->start_address + new_size;
+ return new_size;
+}
+
+static int32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap)
+{
+ uint32_t iterator = 0;
+ while (iterator < heap->index.size) {
+ header_t *header = (header_t *) lookup_ordered_array(iterator, &heap->index);
+ if (page_align > 0) {
+ uint32_t location = (uint32_t) header;
+ int32_t offset = 0;
+ if (((location + sizeof(header_t)) & 0xFFFFF000) != 0)
+ offset = 0x1000 - (location + sizeof(header_t)) % 0x1000;
+ int32_t hole_size = (int32_t) header->size - offset;
+ if (hole_size >= (int32_t) size)
+ break;
+ } else if (header->size >= size)
+ break;
+ iterator++;
+ }
+ if (iterator == heap->index.size)
+ return -1;
+ else
+ return iterator;
+}
+
+static int8_t header_t_less_than(void *a, void *b)
+{
+ return (int8_t) ((((header_t *) a)->size < ((header_t *) b)->size) ? 1 : 0);
+}
+
+heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly)
+{
+ heap_t *heap = (heap_t *) kmalloc(sizeof(heap_t));
+
+ assert(start % 0x1000 == 0);
+ assert(end_addr % 0x1000 == 0);
+
+ heap->index = place_ordered_array((void *) start, HEAP_INDEX_SIZE, &header_t_less_than);
+
+ start += sizeof(type_t) * HEAP_INDEX_SIZE;
+
+ if ((start & 0xFFFFF000) != 0) {
+ start &= 0xFFFFF000;
+ start += 0x1000;
+ }
+
+ heap->start_address = start;
+ heap->end_address = end_addr;
+ heap->max_address = max;
+ heap->supervisor = supervisor;
+ heap->readonly = readonly;
+
+ header_t *hole = (header_t *) start;
+ hole->size = end_addr - start;
+ hole->magic = HEAP_MAGIC;
+ hole->is_hole = 1;
+ insert_ordered_array((void *) hole, &heap->index);
+
+ return heap;
+}
+
+void *alloc(uint32_t size, uint8_t page_align, heap_t *heap)
+{
+ uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t);
+ int32_t iterator = find_smallest_hole(new_size, page_align, heap);
+
+ if (iterator == -1) {
+ uint32_t old_length = heap->end_address - heap->start_address;
+ uint32_t old_end_address = heap->end_address;
+
+ expand(old_length + new_size, heap);
+ uint32_t new_length = heap->end_address - heap->start_address;
+
+ iterator = 0;
+ uint32_t idx = (uint32_t) -1;
+ uint32_t value = 0x0;
+ while ((uint32_t) iterator < heap->index.size) {
+ uint32_t tmp = (uint32_t) lookup_ordered_array((uint32_t) iterator, &heap->index);
+ if (tmp > value) {
+ value = tmp;
+ idx = (uint32_t) iterator;
+ }
+ iterator++;
+ }
+
+ if ((int) idx == -1) {
+ header_t *header = (header_t *) old_end_address;
+ header->magic = HEAP_MAGIC;
+ header->size = new_length - old_length;
+ header->is_hole = 1;
+ footer_t *footer = (footer_t *) (old_end_address + header->size - sizeof(footer_t));
+ footer->magic = HEAP_MAGIC;
+ footer->header = header;
+ insert_ordered_array((void *) header, &heap->index);
+ } else {
+ header_t *header = lookup_ordered_array(idx, &heap->index);
+ header->size += new_length - old_length;
+ footer_t *footer = (footer_t *) ((uint32_t) header + header->size - sizeof(footer_t));
+ footer->header = header;
+ footer->magic = HEAP_MAGIC;
+ }
+ return alloc(size, page_align, heap);
+ }
+
+ header_t *orig_hole_header = (header_t *) lookup_ordered_array((uint32_t) iterator, &heap->index);
+ uint32_t orig_hole_pos = (uint32_t) orig_hole_header;
+ uint32_t orig_hole_size = orig_hole_header->size;
+ if (orig_hole_size - new_size < sizeof(header_t) + sizeof(footer_t)) {
+ size += orig_hole_size - new_size;
+ new_size = orig_hole_size;
+ }
+
+ if (page_align && orig_hole_pos & 0xFFFFF000) {
+ uint32_t new_location = orig_hole_pos + 0x1000 - (orig_hole_pos & 0xFFF) - sizeof(header_t);
+ header_t *hole_header = (header_t *) orig_hole_pos;
+ hole_header->size = 0x1000 - (orig_hole_pos & 0xFFF) - sizeof(header_t);
+ hole_header->magic = HEAP_MAGIC;
+ hole_header->is_hole = 1;
+ footer_t *hole_footer = (footer_t *) ((uint32_t) new_location - sizeof(footer_t));
+ hole_footer->magic = HEAP_MAGIC;
+ hole_footer->header = hole_header;
+ orig_hole_pos = new_location;
+ orig_hole_size = orig_hole_size - hole_header->size;
+ } else {
+ remove_ordered_array((uint32_t) iterator, &heap->index);
+ }
+
+ header_t *block_header = (header_t *) orig_hole_pos;
+ block_header->magic = HEAP_MAGIC;
+ block_header->is_hole = 0;
+ block_header->size = new_size;
+ footer_t *block_footer = (footer_t *) (orig_hole_pos + sizeof(header_t) + size);
+ block_footer->magic = HEAP_MAGIC;
+ block_footer->header = block_header;
+
+ if (orig_hole_size - new_size > 0) {
+ header_t *hole_header = (header_t *) (orig_hole_pos + sizeof(header_t) + size + sizeof(footer_t));
+ hole_header->magic = HEAP_MAGIC;
+ hole_header->is_hole = 1;
+ hole_header->size = orig_hole_size - new_size;
+ footer_t *hole_footer = (footer_t *) ((uint32_t) hole_header + orig_hole_size - new_size - sizeof(footer_t));
+ if ((uint32_t) hole_footer < heap->end_address) {
+ hole_footer->magic = HEAP_MAGIC;
+ hole_footer->header = hole_header;
+ }
+ insert_ordered_array((void *) hole_header, &heap->index);
+ }
+
+ return (void *) ((uint32_t) block_header + sizeof(header_t));
+}
+
+void free(void *p, heap_t *heap)
+{
+ if (p == 0)
+ return;
+
+ header_t *header = (header_t *) ((uint32_t) p - sizeof(header_t));
+ footer_t *footer = (footer_t *) ((uint32_t) header + header->size - sizeof(footer_t));
+
+ assert(header->magic == HEAP_MAGIC);
+ assert(footer->magic == HEAP_MAGIC);
+
+ header->is_hole = 1;
+
+ char do_add = 1;
+
+ footer_t *test_footer = (footer_t *) ((uint32_t) header - sizeof(footer_t));
+ if (test_footer->magic == HEAP_MAGIC &&
+ test_footer->header->is_hole == 1) {
+ uint32_t cache_size = header->size;
+ header = test_footer->header;
+ footer->header = header;
+ header->size += cache_size;
+ do_add = 0;
+ }
+
+ header_t *test_header = (header_t *) ((uint32_t) footer + sizeof(footer_t));
+ if (test_header->magic == HEAP_MAGIC &&
+ test_header->is_hole) {
+ header->size += test_header->size;
+ test_footer = (footer_t *) ((uint32_t) test_header + test_header->size - sizeof(footer_t));
+ footer = test_footer;
+ uint32_t iterator = 0;
+ while ((iterator < heap->index.size) && (lookup_ordered_array(iterator, &heap->index) != (void *) test_header))
+ iterator++;
+
+ assert(iterator < heap->index.size);
+ remove_ordered_array(iterator, &heap->index);
+ }
+
+ if ((uint32_t) footer + sizeof(footer_t) == heap->end_address) {
+ uint32_t old_length = heap->end_address - heap->start_address;
+ uint32_t new_length = contract((uint32_t) header - heap->start_address, heap);
+ if (header->size - (old_length - new_length) > 0) {
+ header->size -= old_length - new_length;
+ footer = (footer_t *) ((uint32_t) header + header->size - sizeof(footer_t));
+ footer->magic = HEAP_MAGIC;
+ footer->header = header;
+ } else {
+ uint32_t iterator = 0;
+ while ((iterator < heap->index.size) &&
+ (lookup_ordered_array(iterator, &heap->index) != (void *) test_header))
+ iterator++;
+ if (iterator < heap->index.size)
+ remove_ordered_array(iterator, &heap->index);
+ }
+ }
+
+ if (do_add == 1)
+ insert_ordered_array((void *) header, &heap->index);
+} \ No newline at end of file
diff --git a/src/kernel/memory/kheap.h b/src/kernel/memory/kheap.h
new file mode 100644
index 0000000..f31a2d3
--- /dev/null
+++ b/src/kernel/memory/kheap.h
@@ -0,0 +1,52 @@
+#ifndef MELVIX_KHEAP_H
+#define MELVIX_KHEAP_H
+
+#include <stdint.h>
+#include <kernel/memory/ordered_array.h>
+
+#define KHEAP_START 0xC0000000
+#define KHEAP_INITIAL_SIZE 0x100000
+
+#define HEAP_INDEX_SIZE 0x20000
+#define HEAP_MAGIC 0xabcdef42
+#define HEAP_MIN_SIZE 0x70000
+
+typedef struct {
+ uint32_t magic;
+ uint8_t is_hole;
+ uint32_t size;
+} header_t;
+
+typedef struct {
+ uint32_t magic;
+ header_t *header;
+} footer_t;
+
+typedef struct {
+ ordered_array_t index;
+ uint32_t start_address;
+ uint32_t end_address;
+ uint32_t max_address;
+ uint8_t supervisor;
+ uint8_t readonly;
+} heap_t;
+
+heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly);
+
+void *alloc(uint32_t size, uint8_t page_align, heap_t *heap);
+
+void free(void *p, heap_t *heap);
+
+uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys);
+
+uint32_t kmalloc_a(uint32_t sz);
+
+uint32_t kmalloc_p(uint32_t sz, uint32_t *phys);
+
+uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys);
+
+uint32_t kmalloc(uint32_t sz);
+
+void kfree(void *p);
+
+#endif \ No newline at end of file
diff --git a/src/kernel/memory/ordered_array.c b/src/kernel/memory/ordered_array.c
new file mode 100644
index 0000000..5d94491
--- /dev/null
+++ b/src/kernel/memory/ordered_array.c
@@ -0,0 +1,68 @@
+#include <kernel/memory/ordered_array.h>
+#include <stdint.h>
+#include <kernel/lib/lib.h>
+#include <kernel/system.h>
+#include "kheap.h"
+
+int8_t standard_lessthan_predicate(type_t a, type_t b)
+{
+ return (int8_t) ((a < b) ? 1 : 0);
+}
+
+ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than)
+{
+ ordered_array_t to_ret;
+ to_ret.array = (void *) kmalloc(max_size * sizeof(type_t));
+ memset(to_ret.array, 0, max_size * sizeof(type_t));
+ to_ret.size = 0;
+ to_ret.max_size = max_size;
+ to_ret.less_than = less_than;
+ return to_ret;
+}
+
+ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than)
+{
+ ordered_array_t to_ret;
+ to_ret.array = (type_t *) addr;
+ memset(to_ret.array, 0, max_size * sizeof(type_t));
+ to_ret.size = 0;
+ to_ret.max_size = max_size;
+ to_ret.less_than = less_than;
+ return to_ret;
+}
+
+void insert_ordered_array(type_t item, ordered_array_t *array)
+{
+ assert((int) array->less_than);
+ uint32_t iterator = 0;
+ while (iterator < array->size && array->less_than(array->array[iterator], item))
+ iterator++;
+ if (iterator == array->size)
+ array->array[array->size++] = item;
+ else {
+ type_t tmp = array->array[iterator];
+ array->array[iterator] = item;
+ while (iterator < array->size) {
+ iterator++;
+ type_t tmp2 = array->array[iterator];
+ array->array[iterator] = tmp;
+ tmp = tmp2;
+ }
+ array->size++;
+ }
+}
+
+type_t lookup_ordered_array(uint32_t i, ordered_array_t *array)
+{
+ assert(i < array->size);
+ return array->array[i];
+}
+
+void remove_ordered_array(uint32_t i, ordered_array_t *array)
+{
+ while (i < array->size) {
+ array->array[i] = array->array[i + 1];
+ i++;
+ }
+ array->size--;
+} \ No newline at end of file
diff --git a/src/kernel/memory/ordered_array.h b/src/kernel/memory/ordered_array.h
new file mode 100644
index 0000000..cf753e3
--- /dev/null
+++ b/src/kernel/memory/ordered_array.h
@@ -0,0 +1,31 @@
+#ifndef MELVIX_ORDERED_ARRAY_H
+#define MELVIX_ORDERED_ARRAY_H
+
+#include <stdint.h>
+
+typedef void *type_t;
+
+typedef int8_t (*lessthan_predicate_t)(type_t, type_t);
+
+typedef struct {
+ type_t *array;
+ uint32_t size;
+ uint32_t max_size;
+ lessthan_predicate_t less_than;
+} ordered_array_t;
+
+int8_t standard_lessthan_predicate(type_t a, type_t b);
+
+ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than);
+
+ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than);
+
+void destroy_ordered_array(ordered_array_t *array);
+
+void insert_ordered_array(type_t item, ordered_array_t *array);
+
+type_t lookup_ordered_array(uint32_t i, ordered_array_t *array);
+
+void remove_ordered_array(uint32_t i, ordered_array_t *array);
+
+#endif
diff --git a/src/kernel/memory/paging.c b/src/kernel/memory/paging.c
new file mode 100644
index 0000000..e050861
--- /dev/null
+++ b/src/kernel/memory/paging.c
@@ -0,0 +1,203 @@
+#include <kernel/memory/paging.h>
+#include <kernel/memory/kheap.h>
+#include <kernel/lib/lib.h>
+#include <kernel/system.h>
+
+int paging_enabled = 0;
+
+page_directory_t *kernel_directory = 0;
+page_directory_t *current_directory = 0;
+
+uint32_t *frames;
+uint32_t nframes;
+
+extern uint32_t placement_address;
+extern heap_t *kheap;
+
+extern void copy_page_physical();
+
+#define INDEX_FROM_BIT(a) (a/(8*4))
+#define OFFSET_FROM_BIT(a) (a%(8*4))
+
+static void set_frame(uint32_t frame_addr)
+{
+ uint32_t frame = frame_addr / 0x1000;
+ uint32_t idx = INDEX_FROM_BIT(frame);
+ uint32_t off = OFFSET_FROM_BIT(frame);
+ frames[idx] |= (0x1 << off);
+}
+
+static void clear_frame(uint32_t frame_addr)
+{
+ uint32_t frame = frame_addr / 0x1000;
+ uint32_t idx = INDEX_FROM_BIT(frame);
+ uint32_t off = OFFSET_FROM_BIT(frame);
+ frames[idx] &= ~(0x1 << off);
+}
+
+static uint32_t first_frame()
+{
+ uint32_t i, j;
+ for (i = 0; i < INDEX_FROM_BIT(nframes); i++) {
+ if (frames[i] != 0xFFFFFFFF) {
+ for (j = 0; j < 32; j++) {
+ uint32_t toTest = (0x1 << j);
+ if (!(frames[i] & toTest)) {
+ return i * 4 * 8 + j;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void alloc_frame(page_t *page, int is_kernel, int is_writeable)
+{
+ if (page->frame != 0) {
+ return;
+ } else {
+ uint32_t idx = first_frame();
+ if (idx == (uint32_t) -1)
+ panic("No free frames!");
+ set_frame(idx * 0x1000);
+ page->present = 1;
+ page->rw = (is_writeable == 1) ? 1 : 0;
+ page->user = (is_kernel == 1) ? 0 : 1;
+ page->frame = idx;
+ }
+}
+
+void free_frame(page_t *page)
+{
+ uint32_t frame;
+ if (!(frame = page->frame)) {
+ return;
+ } else {
+ clear_frame(frame);
+ page->frame = 0x0;
+ }
+}
+
+void paging_install()
+{
+ uint32_t mem_end_page = memory_get_all() << 10;
+
+ nframes = mem_end_page / 0x1000;
+ frames = (uint32_t *) kmalloc(INDEX_FROM_BIT(nframes));
+ memset(frames, 0, INDEX_FROM_BIT(nframes));
+
+ kernel_directory = (page_directory_t *) kmalloc_a(sizeof(page_directory_t));
+ memset(kernel_directory, 0, sizeof(page_directory_t));
+ kernel_directory->physicalAddr = (uint32_t) kernel_directory->tablesPhysical;
+
+ for (uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += 0x1000)
+ get_page((uint32_t) i, 1, kernel_directory);
+
+ int i = 0;
+ while (i < 0x400000) {
+ alloc_frame(get_page((uint32_t) i, 1, kernel_directory), 0, 0);
+ i += 0x1000;
+ }
+
+ for (i = KHEAP_START; i < (int) (KHEAP_START + KHEAP_INITIAL_SIZE); i += 0x1000)
+ alloc_frame(get_page((uint32_t) i, 1, kernel_directory), 0, 0);
+
+ switch_page_directory(kernel_directory);
+
+ kheap = create_heap(KHEAP_START, KHEAP_START + KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
+
+ current_directory = clone_directory(kernel_directory);
+ switch_page_directory(current_directory);
+ vga_log("Installed Paging");
+}
+
+void switch_page_directory(page_directory_t *dir)
+{
+ current_directory = dir;
+ asm volatile("mov %0, %%cr3"::"r"(dir->physicalAddr));
+ uint32_t cr0;
+ asm volatile("mov %%cr0, %0": "=r"(cr0));
+ cr0 |= 0x80000000; // Enable paging!
+ asm volatile("mov %0, %%cr0"::"r"(cr0));
+}
+
+void paging_enable()
+{
+ switch_page_directory(kernel_directory);
+ paging_enabled = 1;
+}
+
+void paging_disable()
+{
+ uint32_t cr0;
+ asm ("mov %%cr0, %0": "=r"(cr0));
+ cr0 &= 0x7fffffff;
+ asm ("mov %0, %%cr0"::"r"(cr0));
+ paging_enabled = 0;
+}
+
+page_t *get_page(uint32_t address, int make, page_directory_t *dir)
+{
+ address /= 0x1000;
+ uint32_t table_idx = address / 1024;
+
+ if (dir->tables[table_idx]) {
+ return &dir->tables[table_idx]->pages[address % 1024];
+ } else if (make) {
+ uint32_t tmp;
+ dir->tables[table_idx] = (page_table_t *) kmalloc_ap(sizeof(page_table_t), &tmp);
+ memset(dir->tables[table_idx], 0, 0x1000);
+ dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US
+ return &dir->tables[table_idx]->pages[address % 1024];
+ } else {
+ return 0;
+ }
+}
+
+static page_table_t *clone_table(page_table_t *src, uint32_t *physAddr)
+{
+ page_table_t *table = (page_table_t *) kmalloc_ap(sizeof(page_table_t), physAddr);
+ memset(table, 0, sizeof(page_directory_t));
+
+ for (int i = 0; i < 1024; i++) {
+ if (!src->pages[i].frame)
+ continue;
+
+ alloc_frame(&table->pages[i], 0, 0);
+
+ if (src->pages[i].present) table->pages[i].present = 1;
+ if (src->pages[i].rw) table->pages[i].rw = 1;
+ if (src->pages[i].user) table->pages[i].user = 1;
+ if (src->pages[i].accessed)table->pages[i].accessed = 1;
+ if (src->pages[i].dirty) table->pages[i].dirty = 1;
+
+ copy_page_physical(src->pages[i].frame * 0x1000, table->pages[i].frame * 0x1000);
+ }
+ return table;
+}
+
+page_directory_t *clone_directory(page_directory_t *src)
+{
+ uint32_t phys;
+ page_directory_t *dir = (page_directory_t *) kmalloc_ap(sizeof(page_directory_t), &phys);
+ memset(dir, 0, sizeof(page_directory_t));
+
+ uint32_t offset = (uint32_t) dir->tablesPhysical - (uint32_t) dir;
+
+ dir->physicalAddr = phys + offset;
+
+ for (int i = 0; i < 1024; i++) {
+ if (!src->tables[i])
+ continue;
+
+ if (kernel_directory->tables[i] == src->tables[i]) {
+ dir->tables[i] = src->tables[i];
+ dir->tablesPhysical[i] = src->tablesPhysical[i];
+ } else {
+ uint32_t phys;
+ dir->tables[i] = clone_table(src->tables[i], &phys);
+ dir->tablesPhysical[i] = phys | 0x07;
+ }
+ }
+ return dir;
+} \ No newline at end of file
diff --git a/src/kernel/memory/paging.h b/src/kernel/memory/paging.h
new file mode 100644
index 0000000..285cb6f
--- /dev/null
+++ b/src/kernel/memory/paging.h
@@ -0,0 +1,47 @@
+#ifndef MELVIX_PAGING_H
+#define MELVIX_PAGING_H
+
+#include <stdint.h>
+#include <kernel/interrupts/interrupts.h>
+
+typedef struct page {
+ uint32_t present: 1;
+ uint32_t rw: 1;
+ uint32_t user: 1;
+ uint32_t accessed: 1;
+ uint32_t dirty: 1;
+ uint32_t unused: 7;
+ uint32_t frame: 20;
+} page_t;
+
+typedef struct page_table {
+ page_t pages[1024];
+} page_table_t;
+
+typedef struct page_directory {
+ page_table_t *tables[1024];
+ uint32_t tablesPhysical[1024];
+ uint32_t physicalAddr;
+} page_directory_t;
+
+int paging_enabled;
+
+void alloc_frame(page_t *page, int is_kernel, int is_writeable);
+
+void free_frame(page_t *page);
+
+void paging_install();
+
+void switch_page_directory(page_directory_t *new);
+
+void paging_enable();
+
+void paging_disable();
+
+page_t *get_page(uint32_t address, int make, page_directory_t *dir);
+
+void page_fault(struct regs *regs);
+
+page_directory_t *clone_directory(page_directory_t *src);
+
+#endif