BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / mem / paging.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/mem/paging.c b/mem/paging.c
new file mode 100644
index 0000000..b44e843
--- /dev/null
+++ b/mem/paging.c
@@ -0,0 +1,228 @@
+/*
+ * This file contains all functions used to manipulate the virtual address
+ * spaces.  It has a static Kernel page directory and table, which it uses to
+ * initialsed an identity-paged environment for the Kernel to work in.  This is
+ * enough for the heap to function in.  The file also exposes several functions
+ * that allow a page directory to be manipulated and have pages added and moved.
+ * These functions are used by other components of the Kernel - mostly the heap
+ * and IPC.  There are also functions to create new and destroy existing page
+ * directories.  The paging system also implements features like copy-on-write.
+ */
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include "frame.h"
+#include "heap.h"
+#include "mem.h"
+#include "paging.h"
+#include "../vfs/vfs.h"
+#include "../proc/proc.h"
+#include "../io.h"
+#include "../screen.h"
+
+Spinlock quickPageLock;
+
+page_table_t kernelDir;
+page_t zeroFrame;
+
+void enable_paging(void);
+void disable_paging(void);
+void copy_page_frame(void *src, void *dest);
+
+/* Switch page directory */
+static void
+switch_dir(page_dir_t dir)
+{
+	asm volatile("mov %0, %%cr3" :: "r" (dir));
+}
+
+/* Allocate a page a frame */
+void
+alloc_page(page_t *page, uint16_t flags, page_t frame)
+{
+	page_t *mappings = (void *) 0xFFC00000;
+	page_table_t *tables = (void *) 0xFFFFF000;
+	if ((tables[(page - mappings) / 1024] & PDE_PRESENT) == 0)
+		return;
+	if (*page & 0xFFFFF000)
+		return;
+
+	if (frame == (page_t) -1)
+		frame = alloc_frames(1);
+	if (frame == (page_t) -1)
+		return;
+
+	*page = frame | flags;
+	flush_tlb((page - mappings) << 12);
+}
+
+/* Release a page's frame */
+void
+free_page(page_t *page)
+{
+	page_t *mappings = (void *) 0xFFC00000;
+	page_table_t *tables = (void *) 0xFFFFF000;
+	if ((tables[(page - mappings) / 1024] & PDE_PRESENT) == 0)
+		return;
+	if ((*page & 0xFFFFF000) == 0)
+		return;
+
+	free_frame(*page & 0xFFFFF000);
+	*page = 0x00000000;
+	flush_tlb((page - mappings) << 12);
+}
+
+/* Get Page Table Entry from virtual address */
+page_t *
+get_page(void *addr)
+{
+	page_t *mappings = (void *) 0xFFC00000;
+	page_table_t *tables = (void *) 0xFFFFF000;
+	uint32_t address = (uint32_t) addr >> 12;
+	uint32_t tbl = address / 1024;
+	/* Create table not present */
+	if ((tables[tbl] & PDE_PRESENT) == 0) {
+		tables[tbl] = alloc_frames(1)
+		            | PDE_PRESENT | PDE_WRITE | PDE_USER;
+		memset((void *) mappings + (tbl * 0x1000), 0, 0x1000);
+	}
+	return &mappings[address];
+}
+
+/* Clone a page directory */
+page_dir_t
+clone_dir(void)
+{
+	page_table_t *oldTables = (void *) 0xFFFFF000;
+	page_table_t *newTables = (void *) 0xFFFFE000;
+	page_t *oldTable, *newTable;
+	page_dir_t dir = alloc_frames(1);
+	uint16_t i, tbl, pg;
+
+	/* Temporarily link new paging structures into current directory */
+	page_table_t restore = oldTables[1022];
+	oldTables[1022] = dir | PDE_PRESENT | PDE_WRITE;
+	for (i = 0; i < 1024; i++)
+		flush_tlb((uintptr_t) newTables + (0x1000 * i));
+
+	/* Iterate tables */
+	for (tbl = 0; tbl < 1022; tbl++) {
+		if ((oldTables[tbl] & PDE_PRESENT) == 0)
+			continue;
+
+		/* Link Kernel tables */
+		if (tbl < 2 || tbl >= 1008) { /* TODO: define kernel mem */
+			newTables[tbl] = oldTables[tbl];
+			continue;
+		}
+
+		/* Copy everything else */
+		newTables[tbl] = alloc_frames(1) | PG_ATTR(oldTables[tbl]);
+		oldTable = (page_t *) 0xFFC00000 + (tbl * 1024);
+		newTable = (page_t *) 0xFF800000 + (tbl * 1024);
+		for (pg = 0; pg < 1024; pg++) {
+			if ((oldTable[pg] & PTE_PRESENT) == 0) {
+				newTable[pg] = 0;
+				continue;
+			}
+
+			/* Copy-On-Write behaviour */
+			if (tbl < 960) {
+				oldTable[pg] &= ~PTE_WRITE;
+				flush_tlb((uintptr_t) (((tbl * 1024) + pg) << 12));
+				newTable[pg] = oldTable[pg];
+			} else {
+				newTable[pg] = alloc_frames(1) | PG_ATTR(oldTable[pg]);
+				copy_page_frame((void *) PG_ADDR(oldTable[pg]),
+				                (void *) PG_ADDR(newTable[pg]));
+			}
+			/* FIXME */
+		}
+	}
+	newTables[1023] = oldTables[1022];
+
+	/* Unlink paging structures */
+	oldTables[1022] = restore;
+	for (i = 0; i < 1024; i++)
+		flush_tlb((uintptr_t) newTables + (0x1000 * i));
+
+	return dir;
+}
+
+/* Free all (copied) pages in the current directory */
+void
+clean_dir(void)
+{
+	page_t *mappings = (void *) 0xFFC00000;
+	page_table_t *tables = (void *) 0xFFFFF000;
+	page_t *pages;
+	uint16_t tbl, pg;
+	for (tbl = 2; tbl < 1008; tbl++) {
+		if ((tables[tbl] & PDE_PRESENT) == 0)
+			continue;
+		pages = mappings + (tbl * 1024);
+		for (pg = 0; pg < 1024; pg++) {
+			if ((pages[pg] & PDE_PRESENT) == 0)
+				continue;
+			free_page(pages + pg);
+		}
+	}
+}
+
+/* Quickly map a page frame into view for temporary use */
+page_t
+quick_page(uintptr_t frame)
+{
+	page_t *mappings = (void *) 0xFFC00000;
+	page_t old;
+	old = mappings[2047];
+	mappings[2047] = PG_ADDR(frame) | PG_ATTR(old);
+	flush_tlb(0x7FF000);
+	return PG_ADDR(old);
+}
+
+/* Initialise paging */
+void
+init_paging(void)
+{
+	zeroFrame = alloc_frames(1);
+	memset((void *) zeroFrame, 0, 0x1000);
+
+	uint16_t tbl, pg;
+	page_t *table;
+	page_table_t *kernelTables;
+	kernelDir = alloc_frames(1);
+	kernelTables = (page_table_t *) kernelDir;
+	for (tbl = 0; tbl < 1024; tbl++)
+		kernelTables[tbl] = 0x00000000 | PDE_WRITE;
+	for (tbl = 0; tbl < 2; tbl++) {
+		table = (void *) alloc_frames(1);
+		kernelTables[tbl] = ((page_table_t) table)
+		                  | PDE_WRITE | PDE_PRESENT;
+		for (pg = 0; pg < 1024; pg++) {
+			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;
+
+	/* Use Kernel directory */
+	switch_dir(kernelDir);
+	register_exception(14, early_page_fault_handler);
+	enable_paging();
+
+	/* Identity page the APIC registers */
+	*get_page((void *)  lapicPtr) =  lapicPtr
+	                              | PTE_PRESENT | PTE_WRITE | PTE_GLOBAL;
+	*get_page((void *) ioapicPtr) = ioapicPtr
+	                              | PTE_PRESENT | PTE_WRITE | PTE_GLOBAL;
+
+	/* Allocate Kernel stack */
+	uintptr_t stk;
+	for (stk = 0xF0400000; stk < 0xF0800000; stk += 0x1000)
+		alloc_page(get_page((void *) stk),
+		           PTE_PRESENT | PTE_WRITE | PTE_USER, -1);
+}