BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 665af0a43af0d406733bda816ca1a7b2f9184319 / memory / fault.c

// Related

Nucleus

Barry Improved page fault handling and mmap system call 665af0a (3 years, 2 months ago)
diff --git a/memory/fault.c b/memory/fault.c
index 3c5ecfe..02c95ca 100644
--- a/memory/fault.c
+++ b/memory/fault.c
@@ -44,25 +44,26 @@ copy_on_write(VMRegion *region, uintptr_t addr)
 		inode = back->inode;
 		page = find_page(inode->pages, offset);
 	}
+	if (!page) {
+		panic("no page! %#.8x = %#.8x", addr, get_page(addr));
+	}
 	ASSERT(page);
 
-	/* Copy already happened, or region is shared file */
-	if (usage(page) == 1 && page->frame != zeroFrame
-	 && ((front && inode == front->inode) || !private))
-		return install_page(addr, page, PROT_WRITE);
-
-	/* Page is still in use, or in wrong inode for writing */
-	if (usage(inode) == 1) {
-		add(front->inode->pages, page);
-		install_page(addr, page, PROT_WRITE);
-		remove(inode->pages, page);
-	} else {
+	/* Determine what to do */
+	if (usage(page) > 1 || page->frame == zeroFrame) {
+		/* Copy page */
 		newPage = create_page(front->inode->pages,
 		                      alloc_frame(), offset);
-		install_page(addr, newPage, PROT_WRITE);
 		copy_page_frame(PAGE_ADDR(page->frame),
 		                PAGE_ADDR(newPage->frame));
+		remove(inode->pages, page);
+		page = newPage;
+	} else if (back && inode == back->inode && private) {
+		/* Page in wrong inode for write */
+		add(front->inode->pages, page);
+		remove(inode->pages, page);
 	}
+	return install_page(addr, page, region->prot);
 }
 
 /* Handle a non-present read page fault */
@@ -84,7 +85,7 @@ not_present_read(VMRegion *region, uintptr_t addr)
 		inode = front->inode;
 		page = find_page(inode->pages, offset);
 		if (page)
-			return install_page(addr, page, PROT_READ);
+			return install_page(addr, page, region->prot);
 		/* Zero-fill if anonymous */
 		if (region->flags & MAP_ANONYMOUS) {
 			page = create_page(inode->pages, zeroFrame, offset);
@@ -127,10 +128,15 @@ not_present_write(VMRegion *region, uintptr_t addr)
 		inode = back->inode;
 		page = find_page(inode->pages, offset);
 		if (page)
-			return install_page(addr, page, PROT_WRITE);
+			return install_page(addr, page, region->prot);
 		page = create_page(inode->pages, alloc_frame(), offset);
-		install_page(addr, page, PROT_WRITE);
-		memset((void *) PAGE_ADDR(addr), 0, PAGE_SIZE);
+		install_page(addr, page, region->prot);
+		/* Zero-fill if anonymous, otherwise read */
+		if (region->flags & MAP_ANONYMOUS)
+			memset((void *) PAGE_ADDR(addr), 0, PAGE_SIZE);
+		else
+			file_mmap(back, (void *) PAGE_ADDR(addr),
+		                  PAGE_SIZE, offset);
 		return;
 	}
 
@@ -139,7 +145,7 @@ not_present_write(VMRegion *region, uintptr_t addr)
 	inode = front->inode;
 	page = find_page(inode->pages, offset);
 	newPage = create_page(inode->pages, alloc_frame(), offset);
-	install_page(addr, newPage, PROT_WRITE);
+	install_page(addr, newPage, region->prot);
 	if (page) {
 		copy_page_frame(PAGE_ADDR(page->frame),
 		                PAGE_ADDR(newPage->frame));
@@ -194,9 +200,9 @@ page_fault_handler(struct InterruptFrame *frame, uint32_t err)
 
 	if (present && write)
 		return copy_on_write(region, addr);
-	if (write)
+	if (!present && write)
 		return not_present_write(region, addr);
-	else
+	if (!present && !write)
 		return not_present_read(region, addr);
 }