BarryServer : Git

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

// Related

Nucleus

Barry Virtual Memory Regions and namespace 381dc7b (3 years, 3 months ago)
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;
+}