BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 381dc7b37e5dfe249412ce3559e8b0dcd56f6267

// Related

Nucleus

Barry Virtual Memory Regions and namespace 381dc7b (3 years, 2 months ago)
diff --git a/include/nucleus/memory.h b/include/nucleus/memory.h
index 542bc77..5395278 100644
--- a/include/nucleus/memory.h
+++ b/include/nucleus/memory.h
@@ -15,6 +15,8 @@ typedef uint32_t page_t;
 typedef uint32_t page_table_t;
 typedef uint32_t page_dir_t;
 typedef struct Page Page;
+typedef struct VirtualMemory VirtualMemory;
+typedef struct VMRegion VMRegion;
 
 /* Page Table Entry flags */
 enum PTEFlag {
@@ -39,6 +41,8 @@ enum PDEFlag {
 };
 
 extern ObjectType pageType;
+extern ObjectType virtualMemoryType;
+extern ObjectType vmRegionType;
 
 /* Flush Translation Lookaside Buffer */
 static inline void
@@ -51,6 +55,7 @@ uintptr_t alloc_frame(void);
 void free_frame(uintptr_t frame);
 void init_frames(size_t memMapSize, void *memMap);
 
+page_t get_page(uintptr_t vaddr);
 void set_page(uintptr_t vaddr, page_t page);
 page_dir_t clone_dir(void);
 void init_paging(void);
@@ -61,6 +66,7 @@ void kfree(void *addr);
 
 Page *create_page(ObjectList *cache, page_t frame, off_t offset);
 Page *find_page(ObjectList *cache, off_t offset);
+void install_page(uintptr_t addr, Page *page, int prot);
 void *map_page(Page *page);
 
 int verify_access(const void *addr, size_t len, int prot);
diff --git a/include/nucleus/task.h b/include/nucleus/task.h
index 11ad4ae..460f32f 100644
--- a/include/nucleus/task.h
+++ b/include/nucleus/task.h
@@ -44,6 +44,7 @@ struct Task {
 	/* Namespaces */
 	FileSystem *fs;
 	Files *files;
+	VirtualMemory *vm;
 };
 
 extern ObjectType taskType;
diff --git a/memory/namespace.h b/memory/namespace.h
new file mode 100644
index 0000000..20a8e20
--- /dev/null
+++ b/memory/namespace.h
@@ -0,0 +1,30 @@
+#ifndef MEMORY_NAMESPACE_H
+#define MEMORY_NAMESPACE_H
+
+#include <nucleus/object.h>
+#include <nucleus/vfs.h>
+
+/* Structure for a Page in a Cache */
+struct Page {
+	Object obj;
+	off_t offset;
+	page_t frame;
+};
+
+/* Virtual Memory namespace */
+struct VirtualMemory {
+	Object obj;
+	ObjectList *regions;
+};
+
+/* Structure for a Virtual Memory Region object */
+struct VMRegion {
+	Object obj;
+	uintptr_t start, end;
+	int prot;
+	int flags;
+	off_t offset;
+	File *front, *back;
+};
+
+#endif
diff --git a/memory/page.c b/memory/page.c
index 6e1e67a..3aa4923 100644
--- a/memory/page.c
+++ b/memory/page.c
@@ -6,19 +6,7 @@
 
 #include <nucleus/object.h>
 #include <nucleus/memory.h>
-
-/* Structure for a Page in a Cache */
-struct Page {
-	Object obj;
-	off_t offset;
-	page_t frame;
-};
-
-/* Information for find callback */
-struct FindData {
-	off_t offset;
-	Page *result;
-};
+#include "namespace.h"
 
 static void page_delete(Object *);
 
@@ -37,19 +25,6 @@ page_delete(Object *obj)
 	free_frame(PAGE_ADDR(page->frame));
 }
 
-/* Callback for finding a Page by offset */
-static int
-compare_page_offset(void *object, void *data)
-{
-	Page *page = object;
-	struct FindData *find = data;
-	if (page->offset == find->offset) {
-		find->result = get(page);
-		return 1;
-	}
-	return 0;
-}
-
 /* Create a new Page entry */
 Page *
 create_page(ObjectList *cache, page_t frame, off_t offset)
@@ -58,6 +33,7 @@ create_page(ObjectList *cache, page_t frame, off_t offset)
 	page->frame = frame;
 	page->offset = offset;
 	add(cache, page);
+	put(page);
 	return page;
 }
 
@@ -65,12 +41,23 @@ create_page(ObjectList *cache, page_t frame, off_t offset)
 Page *
 find_page(ObjectList *cache, off_t offset)
 {
-	struct FindData data = {
-		.offset = offset,
-		.result = NULL,
-	};
-	iterate(cache, compare_page_offset, &data);
-	return data.result;
+	Page *page;
+	foreach (cache, page) {
+		if (page->offset == offset)
+			break;
+	}
+	return page;
+}
+
+/* Install a page into a virtual address space */
+void
+install_page(uintptr_t addr, Page *page, int prot)
+{
+	int access = PTE_PRESENT | PTE_USER;
+	if (prot & PROT_WRITE)
+		access |= PTE_WRITE;
+	set_page(PAGE_ADDR(addr), page->frame | access);
+	flush_tlb(PAGE_ADDR(addr));
 }
 
 /* Get the virtual address for the mapping of a page */
diff --git a/memory/region.c b/memory/region.c
new file mode 100644
index 0000000..3cf9fa4
--- /dev/null
+++ b/memory/region.c
@@ -0,0 +1,198 @@
+/*
+ * This file implements the Virtual Memory namespace, the VMRegion object and
+ * the associated function.  A Virtual Memory namespace stores all of the
+ * VMRegions for a task.  A VMRegion represents a region of virtual memory that
+ * is mapped in the task's virtual address space.
+ */
+
+#include <nucleus/object.h>
+#include <nucleus/memory.h>
+#include <nucleus/task.h>
+#include <nucleus/vfs.h>
+#include "namespace.h"
+
+static void vm_new(Object *);
+static void vm_delete(Object *);
+static void region_new(Object *);
+static void region_delete(Object *);
+static void region_copy(Object *a, Object *b);
+
+/* Virtual Memory Namespace object type */
+ObjectType virtualMemoryType = {
+	.name = "VIRTUAL MEMORY",
+	.size = sizeof(VirtualMemory),
+	.new = vm_new,
+	.delete = vm_delete,
+};
+
+/* VMRegion object type */
+ObjectType vmRegionType = {
+	.name = "VIRTUAL MEMORY REGION",
+	.size = sizeof(VMRegion),
+	.delete = region_delete,
+	.copy = region_copy,
+};
+
+/* Create a new Virtual Memory object */
+static void
+vm_new(Object *obj)
+{
+	VirtualMemory *vm = (void *) obj;
+	vm->regions = create_list(&vmRegionType);
+}
+
+/* Destroy a Virtual Memory object */
+static void
+vm_delete(Object *obj)
+{
+	VirtualMemory *vm = (void *) obj;
+	destroy_list(vm->regions);
+}
+
+/* Copy a Virtual Memory object */
+static void
+vm_copy(Object *a, Object *b)
+{
+	VirtualMemory *parent = (void *) a, *child = (void *) b;
+	VMRegion *region, *insert;
+	foreach (parent->regions, region) {
+		insert = copy(region);
+		add(child->regions, insert);
+		put(insert);
+	}
+}
+
+/* Delete a Virtual Memory Region */
+static void
+region_delete(Object *obj)
+{
+	VMRegion *region = (void *) obj;
+
+	/* Unlink files */
+	if (region->front)
+		put(region->front);
+	if (region->back)
+		put(region->back);
+
+	/* Clean page directory */
+	uintptr_t addr;
+	for (addr = PAGE_ADDR(region->start); addr < region->end;
+	     addr += PAGE_SIZE) {
+		set_page(addr, 0x00000000);
+		flush_tlb(addr);
+	}
+}
+
+/* Copy a Virtual Memory Region */
+static void
+region_copy(Object *a, Object *b)
+{
+	VMRegion *parent = (void *) a, *child = (void *) b;
+	child->start = parent->start;
+	child->end = parent->end;
+	child->prot = parent->prot;
+	child->flags = parent->flags;
+	child->offset = parent->offset;
+	/* Front (anonymous regions) */
+	if (parent->front && (parent->flags & MAP_PRIVATE))
+		child->front = copy(parent->front);
+	else if (parent->front)
+		child->front = get(parent->front);
+	/* Back (always a disk file) */
+	if (parent->back)
+		child->back = get(parent->back);
+}
+
+/* Remove a range of pages from a region's page cache */
+static void
+remove_cache_range(VMRegion *region, uintptr_t start, uintptr_t end)
+{
+	Page *page;
+	Inode *inode;
+	uintptr_t p;
+	for (p = 0; p < end - start; p += PAGE_SIZE) {
+		page = NULL;
+		if (!page && region->front) {
+			inode = region->front->inode;
+			page = find_page(inode->pages, region->offset + p);
+		}
+		if (!page && region->back) {
+			inode = region->back->inode;
+			page = find_page(inode->pages, region->offset + p);
+		}
+		if (page) {
+			set_page(PAGE_ADDR(start) + p, 0x00000000);
+			flush_tlb(PAGE_ADDR(start) + p);
+			remove(inode->pages, page);
+		}
+	}
+}
+
+/* Find a Virtual Memory Region by address */
+VMRegion *
+find_region(uintptr_t addr)
+{
+	VMRegion *region;
+	foreach (current->vm->regions, region) {
+		if (region->start <= addr && region->end > addr)
+			break;
+	}
+	return region;
+}
+
+/* Create a new Virtual Memory Region */
+VMRegion *
+vm_create_region(void *addr, size_t len, int prot, int flags, off_t offset,
+                 File *back)
+{
+	/* Create new region */
+	VMRegion *region = new(&vmRegionType);
+	region->end = (uintptr_t) addr + len;
+	if (region-> end % PAGE_SIZE)
+		region->end += PAGE_SIZE - (region->end % PAGE_SIZE);
+	region->start = PAGE_ADDR((uintptr_t) addr);
+	region->prot = prot;
+	region->flags = flags;
+	region->offset = offset;
+	region->front = NULL;
+	region->back = NULL;
+	if (back)
+		region->back = get(back);
+
+	/* Fix overlaps */
+	VMRegion *head, *insert;
+	foreach (current->vm->regions, head) {
+		if (head->start >= region->end || head->end <= region->start)
+			continue;
+
+		/* Middle eclipsed */
+		if (head->start < region->start && head->end > region->end) {
+			/* Split into two regions */
+			insert = copy(head);
+			remove_cache_range(head, region->start, head->end);
+			head->end = region->start;
+			remove_cache_range(insert, insert->start, region->end);
+			insert->offset += (region->end - insert->start);
+			insert->start = region->end;
+			add(current->vm->regions, insert);
+			put(insert);
+		}
+		/* Start eclipsed */
+		if (head->start >= region->start && head->end > region->end) {
+			remove_cache_range(head, head->start, region->end);
+			head->offset += (region->end - head->start);
+			head->start = region->end;
+		}
+		/* End eclipsed */
+		if (head->start < region->start && head->end <= region->end) {
+			remove_cache_range(head, region->start, head->end);
+			head->end = region->start;
+		}
+		/* Total eclipse */
+		if (head->start >= region->start && head->end <= region->end)
+			remove(current->vm->regions, region);
+	}
+
+	add(current->vm->regions, region);
+	return region;
+}
diff --git a/task/clone.c b/task/clone.c
index c9a6dc0..0ec2f95 100644
--- a/task/clone.c
+++ b/task/clone.c
@@ -32,6 +32,12 @@ clone(int flags)
 	else
 		child->files = copy(parent->files);
 
+	/* Clone parent's virtual memory namespace */
+	if (flags & CLONE_VM)
+		child->vm = get(parent->fs);
+	else
+		child->fs = copy(parent->fs);
+
 	/* After this, anything on the stack is desynchronised */
 	child->pageDir = clone_dir();
 
diff --git a/task/scheduler.c b/task/scheduler.c
index 5cb1440..3a9605c 100644
--- a/task/scheduler.c
+++ b/task/scheduler.c
@@ -28,7 +28,7 @@ switch_to_task(Task *task)
 	}
 
 	/* Switch to new context */
-	current = task; /* Use the passed reference */
+	current = task; /* Given reference, so no get() */
 	asm volatile (
 		"cli;"
 		"movl %0, %%ecx;"
diff --git a/task/task.c b/task/task.c
index 0e53b77..b23c54b 100644
--- a/task/task.c
+++ b/task/task.c
@@ -81,9 +81,10 @@ init_tasking(void)
 
 	/* File System namespace */
 	current->fs = new(&fsType);
-
 	/* Files namespace */
 	current->files = new(&filesType);
+	/* Virtual Memory namespace */
+	current->vm = new(&virtualMemoryType);
 
 	init_scheduler();
 	register_interrupt(0, timer_handler);