x86 page faults know about the reason for the PF
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 17 Aug 2010 02:16:23 +0000 (19:16 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:51 +0000 (17:35 -0700)
I love how when I track down a weird bug, I find a TODO at the end.

kern/arch/i686/trap.c
kern/arch/i686/trap.h
kern/src/mm.c

index f1604a4..b044469 100644 (file)
@@ -301,58 +301,20 @@ register_interrupt_handler(handler_t TP(TV(t)) table[],
        table[int_num].data = data;
 }
 
-void
-page_fault_handler(trapframe_t *tf)
+void page_fault_handler(struct trapframe *tf)
 {
-       uint32_t fault_va;
-
-       // Read processor's CR2 register to find the faulting address
-       fault_va = rcr2();
+       uint32_t fault_va = rcr2();
+       int prot = tf->tf_err & PF_ERROR_WRITE ? PROT_WRITE : PROT_READ;
 
-       // Handle kernel-mode page faults.
-
-       // TODO - one day, we'll want to handle this.
+       /* TODO - handle kernel page faults */
        if ((tf->tf_cs & 3) == 0) {
                print_trapframe(tf);
                panic("Page Fault in the Kernel at 0x%08x!", fault_va);
        }
-
-       // We've already handled kernel-mode exceptions, so if we get here,
-       // the page fault happened in user mode.
-
-       // Call the environment's page fault upcall, if one exists.  Set up a
-       // page fault stack frame on the user exception stack (below
-       // UXSTACKTOP), then branch to current->env_pgfault_upcall.
-       //
-       // The page fault upcall might cause another page fault, in which case
-       // we branch to the page fault upcall recursively, pushing another
-       // page fault stack frame on top of the user exception stack.
-       //
-       // The trap handler needs one word of scratch space at the top of the
-       // trap-time stack in order to return.  In the non-recursive case, we
-       // don't have to worry about this because the top of the regular user
-       // stack is free.  In the recursive case, this means we have to leave
-       // an extra word between the current top of the exception stack and
-       // the new stack frame because the exception stack _is_ the trap-time
-       // stack.
-       //
-       // If there's no page fault upcall, the environment didn't allocate a
-       // page for its exception stack, or the exception stack overflows,
-       // then destroy the environment that caused the fault.
-       //
-       // Hints:
-       //   user_mem_assert() and env_run() are useful here.
-       //   To change what the user environment runs, modify 'current->env_tf'
-       //   (the 'tf' variable points at 'current->env_tf').
-
-       // LAB 4: Your code here.
-
-       // TODO: compute correct access type
-       if(handle_page_fault(current,fault_va,PROT_READ))
-       {
-               // Destroy the environment that caused the fault.
-               cprintf("[%08x] user fault va %08x ip %08x from core %d\n",
-                       current->pid, fault_va, tf->tf_eip, core_id());
+       if (handle_page_fault(current, fault_va, prot)) {
+               /* Destroy the faulting process */
+               printk("[%08x] user fault va %08x ip %08x from core %d\n",
+                      current->pid, fault_va, tf->tf_eip, core_id());
                print_trapframe(tf);
                kref_get(&current->kref, 1);
                proc_destroy(current);
index 6af0cac..1baf057 100644 (file)
 
 #define T_DEFAULT   0xdeadbeef         // catchall
 
+/* Page faults return the nature of the fault in the bits of the error code: */
+#define PF_ERROR_PRESENT               0x01
+#define PF_ERROR_WRITE                         0x02
+#define PF_ERROR_USER                  0x04
+
 /* IPIs */
 /* Testing IPI (used in testing.c) */
 #define I_TESTING              230
index 312d9f2..9198918 100644 (file)
@@ -530,7 +530,6 @@ int handle_page_fault(struct proc* p, uintptr_t va, int prot)
 
        if (prot != PROT_READ && prot != PROT_WRITE && prot != PROT_EXEC)
                panic("bad prot!");
-
        spin_lock(&p->proc_lock);
        int ret = __handle_page_fault(p, va, prot);
        spin_unlock(&p->proc_lock);
@@ -546,12 +545,13 @@ int handle_page_fault(struct proc* p, uintptr_t va, int prot)
  * shootdown is on its way.  Userspace should have waited for the mprotect to
  * return before trying to write (or whatever), so we don't care and will fault
  * them. */
-int __handle_page_fault(struct procp, uintptr_t va, int prot)
+int __handle_page_fault(struct proc *p, uintptr_t va, int prot)
 {
        struct vm_region *vmr;
        struct page *a_page;
        unsigned int f_idx;     /* index of the missing page in the file */
-       int retval = 0;
+       int retval;
+
        /* Check the vmr's protection */
        vmr = find_vmr(p, va);
        if (!vmr)                                                       /* not mapped at all */
@@ -571,7 +571,7 @@ int __handle_page_fault(struct proc* p, uintptr_t va, int prot)
        } else if (PAGE_PAGED_OUT(*pte)) {
                /* TODO: (SWAP) bring in the paged out frame. (BLK) */
                panic("Swapping not supported!");
-               return 0;
+               return -1;
        }
        if (!vmr->vm_file) {
                /* No file - just want anonymous memory */