From abd273ce0a9ae9267f8b0a144ea9b56d8912f9b5 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 19 Jun 2012 23:31:28 +0200 Subject: add dynamic stack growing --- userprog/exception.c | 80 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 29 deletions(-) (limited to 'userprog/exception.c') diff --git a/userprog/exception.c b/userprog/exception.c index 54621fa..debe7f0 100644 --- a/userprog/exception.c +++ b/userprog/exception.c @@ -2,6 +2,8 @@ #include #include #include "userprog/gdt.h" +#include "userprog/process.h" +#include "userprog/syscall.h" #include "threads/interrupt.h" #include "threads/thread.h" #include "threads/vaddr.h" @@ -128,7 +130,8 @@ page_fault (struct intr_frame *f) bool write; /* True: access was write, false: access was read. */ bool user; /* True: access by user, false: access by kernel. */ void *fault_addr; /* Fault address. */ - struct page_table_entry *pte; + void *sp; /* Stack pointer. */ + struct page_table_entry *pte; /* Page table entry. */ /* Obtain faulting address, the virtual address that was accessed to cause the fault. It may point to code or to @@ -151,38 +154,57 @@ page_fault (struct intr_frame *f) write = (f->error_code & PF_W) != 0; user = (f->error_code & PF_U) != 0; - /* To implement virtual memory, adapt the rest of the function - body, adding code that brings in the page to - which fault_addr refers. */ - if (is_user_vaddr(fault_addr)) { - pte = page_table_fetch (&thread_current ()->page_table, pg_round_down (fault_addr)); - if (pte != NULL) - page_load (pte); - else + /* accessing r/o page is always wrong */ + if (!not_present) + thread_exit (); + + if (is_user_vaddr (fault_addr)) { - printf ("Page fault %p\n", pte); - kill (f); - } + /* if page fault occurs during syscall, use saved stack pointer */ + sp = (!user) ? syscall_sp : f->esp; + + /* try to fetch page entry */ + pte = page_table_fetch (&thread_current ()->page_table, + pg_round_down (fault_addr)); + + /* we got a page entry so try to load the page */ + if (pte != NULL) + { + if (page_load (pte)) + return; + printf ("Unable to load page at %p in %s context.\n", + fault_addr, user ? "user" : "kernel"); + } + /* there's no page in our page table but we might still have an valid + stack access and need to expand our stack. so just check for that. + the maxium offset we consider as a valid access is caused by the PUSHA + instruction. it's 32 bytes below the current stack pointer */ + else if (fault_addr >= (sp - 32) && (PHYS_BASE - fault_addr) <= STACK_SIZE) + { + if (process_grow_stack (pg_round_down (fault_addr))) + return; + printf ("Unable to grow stack %p in %s context.\n", + fault_addr, user ? "user" : "kernel"); + } - //TODO -#if 0 - if (! user) { /* syscall exception; set eax and eip */ - f->eip = (void*)f->eax; - f->eax = 0xFFFFFFFF; - return; - } else { + if (!user) + { + f->eip = (void*)f->eax; + f->eax = 0xFFFFFFFF; + return; + } + /* user process access violation */ - thread_exit(); + thread_exit (); + return; } -#endif - } else { - printf ("Page fault at %p: %s error %s page in %s context.\n", - fault_addr, - not_present ? "not present" : "rights violation", - write ? "writing" : "reading", - user ? "user" : "kernel"); - kill (f); - } + + printf ("Page fault at %p: %s error %s page in %s context.\n", + fault_addr, + not_present ? "not present" : "rights violation", + write ? "writing" : "reading", + user ? "user" : "kernel"); + kill (f); } -- cgit v1.2.3