aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/memory/paging.c
diff options
context:
space:
mode:
authorMarvin Borner2020-01-20 23:12:54 +0100
committerMarvin Borner2020-01-20 23:12:54 +0100
commit391ed256d21a6ae2e2456d1809f357e6e96e15d1 (patch)
tree0fe9ffb3c59bbfeb3d8a04ab7fc6efba60d81e79 /src/kernel/memory/paging.c
parentd5d1749257ff8b9aa6b5ace4b4720b484a2860f3 (diff)
Added pure awesomeness
Actually quite some days of work but ok
Diffstat (limited to 'src/kernel/memory/paging.c')
-rw-r--r--src/kernel/memory/paging.c203
1 files changed, 203 insertions, 0 deletions
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