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);
}