Nucleus
Barry Basic paging bc5e11e (3 years, 3 months ago)
diff --git a/memory/paging.c b/memory/paging.c
new file mode 100644
index 0000000..b4f505e
--- /dev/null
+++ b/memory/paging.c
@@ -0,0 +1,90 @@
+/*
+ * This file contains all the functions used to manipulate the virtual address
+ * spaces. It controls all of the system's paging and virtual memory from a low
+ * level perspective. On initialisation, a page directory is allocated for the
+ * kernel that identity maps everything.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <nucleus/memory.h>
+#include "paging.h"
+
+/* Switch page directory */
+static void
+switch_dir(page_dir_t dir)
+{
+ asm volatile("mov %0, %%cr3" :: "r" (dir));
+}
+
+/* Set a page mapping */
+void
+set_page(uintptr_t vaddr, page_t page)
+{
+ page_t *mappings = (void *) 0xFFC00000;
+ page_table_t *tables = (void *) 0xFFFFF000;
+ uintptr_t address = vaddr >> 12;
+ uint32_t tbl = address / 1024;
+ /* Create table if not present */
+ if (!(tables[tbl] & PDE_PRESENT)) {
+ tables[tbl] = alloc_frame() | PDE_PRESENT | PDE_WRITE;
+ memset(mappings + (tbl * 1024), 0, PAGE_SIZE);
+ }
+ mappings[address] = page;
+}
+
+/* Initialise paging */
+void
+init_paging(void)
+{
+ uint16_t tbl, pg;
+ page_dir_t kernelDir = alloc_frame();
+ page_table_t *kernelTables = (page_table_t *) kernelDir;
+ page_t *table;
+ for (tbl = 0; tbl < 1024; tbl++)
+ kernelTables[tbl] = 0x00000000 | PDE_WRITE;
+ for (tbl = 0; tbl < 2; tbl++) {
+ table = (page_t *) alloc_frame();
+ kernelTables[tbl] = ((page_table_t) table)
+ | PDE_WRITE | PDE_PRESENT;
+ for (pg = 0; pg < 1024; pg++) {
+ /* Skip bottom page - catches NULL dereferences */
+ if (!tbl && !pg)
+ continue;
+ table[pg] = (((tbl * 1024) + pg) << 12)
+ | PTE_WRITE | PTE_PRESENT | PTE_GLOBAL;
+ }
+ }
+ /* Map the directory into itself */
+ kernelTables[1023] = kernelDir | PDE_WRITE | PDE_PRESENT;
+
+ /*
+ * By mapping the page directory as the last page table, the page
+ * directory entries are read as page table entries, and the page
+ * table entries become the pages. This means that each page contains
+ * the contents of a page table, and the region in memory represented by
+ * the last page table contains a contiguous list of all pages in
+ * memory. The very last page contains the contents of the page
+ * directory itself. This means that each virtual address space
+ * contains it's own paging structures.
+ */
+
+ /* Use kernel directory */
+ switch_dir(kernelDir);
+ register_exception(14, early_page_fault_handler);
+ asm volatile (
+ "movl %%cr0, %%eax;"
+ "orl $0x80000000, %%eax;"
+ "movl %%eax, %%cr0"
+ ::: "eax"
+ );
+
+ /* Identity page the APIC registers */
+ set_page(lapicPtr, lapicPtr | PTE_PRESENT | PTE_WRITE | PTE_GLOBAL);
+ set_page(ioapicPtr, ioapicPtr | PTE_PRESENT | PTE_WRITE | PTE_GLOBAL);
+
+ /* Allocate a kernel stack */
+ uintptr_t stk;
+ for (stk = 0xF0400000; stk < 0xF0800000; stk += PAGE_SIZE)
+ set_page(stk, alloc_frame() | PTE_PRESENT | PTE_WRITE);
+}