BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 6217f0db2c8f2513994f4cc773aaa4171a049963 / memory

// Related

Nucleus

Barry Kernel threads + threads share address space 6217f0d (3 years, 1 month ago)
diff --git a/memory/fault.c b/memory/fault.c
index 7dfae10..cbff7b2 100644
--- a/memory/fault.c
+++ b/memory/fault.c
@@ -142,14 +142,10 @@ not_present_write(VMRegion *region, uintptr_t addr)
 	ASSERT(front);
 	inode = front->inode;
 	page = find_page(inode->pages, offset);
+	if (page)
+		return install_page(addr, page, region->prot);
 	newPage = create_page(inode->pages, alloc_frame(), offset);
 	install_page(addr, newPage, region->prot);
-	if (page) {
-		copy_page_frame(PAGE_ADDR(page->frame),
-		                PAGE_ADDR(newPage->frame));
-		remove(inode->pages, page);
-		return;
-	}
 
 	/* Anonymous region, zero-fill */
 	if (region->flags & MAP_ANONYMOUS) {
@@ -179,14 +175,20 @@ page_fault_handler(struct InterruptFrame *frame)
 	uint8_t present = frame->err & (1 << 0);
 	uint8_t write   = frame->err & (1 << 1);
 	uint8_t user    = frame->err & (1 << 2);
+	page_t pg = get_page(addr);
 
 	ASSERT(current && current->vm);
 
+	/* Handle lazy invalidation */
+	if (!present && (pg & PTE_PRESENT))
+		return flush_tlb(addr);
+	if (write && (pg & PTE_WRITE))
+		return flush_tlb(addr);
+
 	/* Iterate VM Regions */
 	VMRegion *region = find_region(addr);
 	if (__builtin_expect(!region, 0)) {
 		/* Not in a region */
-		page_t pg = get_page(addr);
 		panic("Page Fault [%d:%d] (%#.8x -> %#.8x [tbl:%d, pg:%d][%#.8x], %s, %s, %s)",
 		      current->tgid, current->tid, frame->eip,
 		      addr, (addr >> 12) / 1024, (addr >> 12) % 1024, pg,
@@ -195,9 +197,12 @@ page_fault_handler(struct InterruptFrame *frame)
 		      user ? "user" : "kernel");
 	}
 
+	/* Protection violation, kill process */
 	if (user && write && !(region->prot & PROT_WRITE))
-		panic("Segmentation violation");
+		panic("Segmentation violation : %#.8x[%#.8x] (%#.8x -> %#.8x)",
+		      region, region->prot, frame->eip, addr);
 
+	/* Update paging structures correctly */
 	if (present && write)
 		return copy_on_write(region, addr);
 	if (!present && write)
diff --git a/memory/frame.c b/memory/frame.c
index 428aae9..0e0f8fd 100644
--- a/memory/frame.c
+++ b/memory/frame.c
@@ -174,6 +174,7 @@ init_frames(uint32_t size, void *addr)
 	struct {uint32_t start, end;} remaps[] = {
 		{.start = 0x0000,   .end = bumpAlloc}, /* PMM bitmaps */
 		{.start = 0x100000, .end = 0x180000 }, /* Kernel */
+		{.start = 0x200000, .end = 0x800000 }, /* Kernel heap */
 	};
 
 	/* Check bitmaps */
@@ -183,10 +184,11 @@ init_frames(uint32_t size, void *addr)
 		numFrames += region->numFrames;
 		uintptr_t end = region->base + (region->numFrames * PAGE_SIZE);
 		/* Iterate the remaps[] to find overlapping regions */
-		for (i = 0; i < sizeof(remaps)/sizeof(remaps[0]); i++)
+		for (i = 0; i < sizeof(remaps)/sizeof(remaps[0]); i++) {
 			for (j = remaps[i].start;
 			     j < remaps[i].end && j >= region->base && j < end;
 			     j += PAGE_SIZE)
 				set_frame(region, (j - region->base) >> 12);
+		}
 	}
 }
diff --git a/memory/mmap.c b/memory/mmap.c
index 2093bf3..f6e94c7 100644
--- a/memory/mmap.c
+++ b/memory/mmap.c
@@ -26,7 +26,7 @@ mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
 				break;
 			region = head;
 		}
-		if (!head && region->end + len >= 0xDFC00000)
+		if (region && region->end + len >= 0xDFC00000)
 			return (void *) -ENOMEM;
 		addr = (void *) region->end;
 	}
diff --git a/memory/namespace.h b/memory/namespace.h
index bd5b0a1..b0f3528 100644
--- a/memory/namespace.h
+++ b/memory/namespace.h
@@ -1,7 +1,9 @@
 #ifndef MEMORY_NAMESPACE_H
 #define MEMORY_NAMESPACE_H
 
+#include <nucleus/memory.h>
 #include <nucleus/object.h>
+#include <nucleus/types.h>
 #include <nucleus/vfs.h>
 
 /* Structure for a Page in a Cache */
@@ -15,6 +17,8 @@ struct Page {
 struct VirtualMemory {
 	Object obj;
 	ObjectList *regions;
+	VMRegion *stack;
+	page_dir_t pageDir;
 };
 
 /* Structure for a Virtual Memory Region object */
@@ -27,6 +31,7 @@ struct VMRegion {
 	File *front, *back;
 };
 
+void switch_dir(page_dir_t dir);
 VMRegion *vm_create_region(void *addr, size_t len, int prot, int flags,
                            off_t offset, File *back);
 
diff --git a/memory/paging.c b/memory/paging.c
index e9a8a83..aa5fa17 100644
--- a/memory/paging.c
+++ b/memory/paging.c
@@ -16,7 +16,7 @@ page_t zeroFrame;
 static page_dir_t kernelDir;
 
 /* Switch page directory */
-static void
+void
 switch_dir(page_dir_t dir)
 {
 	asm volatile("mov %0, %%cr3" :: "r" (dir));
@@ -43,6 +43,8 @@ set_page(uintptr_t vaddr, page_t page)
 	page_table_t *tables = (void *) 0xFFFFF000;
 	uintptr_t address = vaddr >> 12;
 	uint32_t tbl = address / 1024;
+	if (!(tables[tbl] & PDE_PRESENT) && !page)
+		return;
 	/* Create table if not present */
 	if (!(tables[tbl] & PDE_PRESENT)) {
 		tables[tbl] = alloc_frame() | PDE_PRESENT | PDE_WRITE;
@@ -91,18 +93,9 @@ clone_dir(void)
 			}
 
 			/* Link the pages for Copy-On-Write */
-			if (tbl < 960) { /* 0xF0000000 */
-				oldTable[pg] &= ~PTE_WRITE;
-				flush_tlb(((tbl * 1024) + pg) << 12);
-				newTable[pg] = oldTable[pg];
-			} else {
-				/* Copy the kernel stack area immediately */
-				newTable[pg] = alloc_frame()
-				             | PAGE_ATTR(oldTable[pg]);
-				flush_tlb(((tbl * 1024) + pg) << 12);
-				copy_page_frame(PAGE_ADDR(oldTable[pg]),
-				                PAGE_ADDR(newTable[pg]));
-			}
+			oldTable[pg] &= ~PTE_WRITE;
+			flush_tlb(((tbl * 1024) + pg) << 12);
+			newTable[pg] = oldTable[pg];
 		}
 	}
 	newTables[1023] = oldTables[1022];
@@ -142,23 +135,17 @@ init_paging(void)
 	/*
 	 * 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.
+	 * tables 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 */
 	register_exception(14, page_fault_handler);
 	cpu_load_paging();
-
-	/* Allocate a kernel stack */
-	uintptr_t stk;
-	for (stk = 0xF0400000; stk < 0xF0800000; stk += PAGE_SIZE)
-		set_page(stk, alloc_frame() | PTE_PRESENT | PTE_WRITE);
-
 	zeroFrame = alloc_frame();
 }
 
diff --git a/memory/region.c b/memory/region.c
index 26cbc37..469f6b4 100644
--- a/memory/region.c
+++ b/memory/region.c
@@ -17,6 +17,7 @@ static void vm_copy(Object *, Object *);
 static void region_new(Object *);
 static void region_delete(Object *);
 static void region_copy(Object *, Object *);
+static int region_compare(void *, void *);
 
 /* Virtual Memory Namespace object type */
 ObjectType virtualMemoryType = {
@@ -40,7 +41,17 @@ static void
 vm_new(Object *obj)
 {
 	VirtualMemory *vm = (void *) obj;
-	vm->regions = create_list(&vmRegionType, LIST_NORMAL);
+	vm->regions = create_list(&vmRegionType, LIST_ORDERED, region_compare);
+
+	/* Create stack region */
+	VMRegion *stack = new(&vmRegionType);
+	stack->start = 0xDFC00000;
+	stack->end = 0xE0000000;
+	stack->prot = PROT_READ | PROT_WRITE;
+	stack->flags = MAP_PRIVATE | MAP_ANONYMOUS;
+	vm->stack = stack;
+
+	asm volatile("mov %%cr3, %0" : "=r" (vm->pageDir));
 }
 
 /* Destroy a Virtual Memory object */
@@ -49,6 +60,8 @@ vm_delete(Object *obj)
 {
 	VirtualMemory *vm = (void *) obj;
 	destroy_list(vm->regions);
+	if (vm->stack)
+		put(vm->stack);
 }
 
 /* Copy a Virtual Memory object */
@@ -62,6 +75,9 @@ vm_copy(Object *a, Object *b)
 		add(child->regions, insert);
 		put(insert);
 	}
+	if (parent->stack)
+		child->stack = copy(parent->stack);
+	child->pageDir = clone_dir();
 }
 
 /* Delete a Virtual Memory Region */
@@ -105,6 +121,14 @@ region_copy(Object *a, Object *b)
 		child->back = get(parent->back);
 }
 
+/* Compare two regions of memory */
+static int
+region_compare(void *a, void *b)
+{
+	VMRegion *ra = a, *rb = b;
+	return rb->start - ra->start;
+}
+
 /* Remove a range of pages from a region's page cache */
 static void
 remove_cache_range(VMRegion *region, uintptr_t start, uintptr_t end)
@@ -130,6 +154,18 @@ remove_cache_range(VMRegion *region, uintptr_t start, uintptr_t end)
 	}
 }
 
+/* Switch to another virtual memory namespace */
+void
+switch_to_mm(VirtualMemory *vm)
+{
+	if (!current || !current->vm)
+		return;
+	if (!vm->pageDir)
+		return;
+	if (current->vm->pageDir != vm->pageDir)
+		switch_dir(vm->pageDir);
+}
+
 /* Find a Virtual Memory Region by address */
 VMRegion *
 find_region(uintptr_t addr)
@@ -140,7 +176,7 @@ find_region(uintptr_t addr)
 			return region;
 	}
 
-	region = current->stack;
+	region = current->vm->stack;
 	if (region->start <= addr && region->end > addr)
 		return region;
 
@@ -203,14 +239,3 @@ vm_create_region(void *addr, size_t len, int prot, int flags, off_t offset,
 	add(current->vm->regions, region);
 	return region;
 }
-
-/* Create a Virtual Memory Region for the stack */
-VMRegion *
-vm_create_stack(void)
-{
-	VMRegion *stack = vm_create_region((void *) 0xDFC00000, 0x400000,
-	                                   PROT_READ | PROT_WRITE,
-	                                   MAP_PRIVATE | MAP_ANONYMOUS, 0, NULL);
-	remove(current->vm->regions, stack);
-	return stack;
-}