Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/usermode Completely redo R/M emulation and fault ha...



details:   https://anonhg.NetBSD.org/src/rev/b10d0dee546a
branches:  trunk
changeset: 769091:b10d0dee546a
user:      reinoud <reinoud%NetBSD.org@localhost>
date:      Wed Aug 31 12:42:41 2011 +0000

description:
Completely redo R/M emulation and fault handling taking UVM as authorative
answer and not relying on UVM's pmap directions since UVM has its own schemes
for COW etc.

diffstat:

 sys/arch/usermode/conf/GENERIC    |   11 ++-
 sys/arch/usermode/usermode/pmap.c |  122 +++++++++++++++++++++++++++++--------
 sys/arch/usermode/usermode/trap.c |   85 ++++++++++++-------------
 3 files changed, 142 insertions(+), 76 deletions(-)

diffs (truncated from 364 to 300 lines):

diff -r 878d3367e34c -r b10d0dee546a sys/arch/usermode/conf/GENERIC
--- a/sys/arch/usermode/conf/GENERIC    Wed Aug 31 12:25:05 2011 +0000
+++ b/sys/arch/usermode/conf/GENERIC    Wed Aug 31 12:42:41 2011 +0000
@@ -1,9 +1,9 @@
-# $NetBSD: GENERIC,v 1.14 2011/08/27 18:13:09 jmcneill Exp $
+# $NetBSD: GENERIC,v 1.15 2011/08/31 12:42:41 reinoud Exp $
 
 include "arch/usermode/conf/std.usermode"
 
 options        INCLUDE_CONFIG_FILE
-#ident                 "GENERIC-$Revision: 1.14 $"
+#ident                 "GENERIC-$Revision: 1.15 $"
 maxusers       32
 
 makeoptions    DEBUG="-O1 -g3"
@@ -20,9 +20,12 @@
 options        SYSVSHM
 
 options        DEBUG
+options        DIAGNOSTIC
+options                LOCKDEBUG
 options        DEBUG_EXEC
-options        DIAGNOSTIC
-options        LOCKDEBUG
+#options               CPU_DEBUG
+#options               UVMHIST
+#options               UVMHIST_PRINT
 
 options        COMPAT_BSDPTY
 options        COMPAT_50
diff -r 878d3367e34c -r b10d0dee546a sys/arch/usermode/usermode/pmap.c
--- a/sys/arch/usermode/usermode/pmap.c Wed Aug 31 12:25:05 2011 +0000
+++ b/sys/arch/usermode/usermode/pmap.c Wed Aug 31 12:42:41 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.48 2011/08/30 12:02:38 reinoud Exp $ */
+/* $NetBSD: pmap.c,v 1.49 2011/08/31 12:42:41 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2011 Reinoud Zandijk <reinoud%NetBSD.org@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.48 2011/08/30 12:02:38 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.49 2011/08/31 12:42:41 reinoud Exp $");
 
 #include "opt_memsize.h"
 #include "opt_kmempages.h"
@@ -89,9 +89,8 @@
 static void    pmap_page_deactivate(struct pv_entry *pv);
 static void    pv_update(struct pv_entry *pv);
 static void    pmap_update_page(uintptr_t ppn);
+bool           pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype);
 
-void pmap_get_current_protection(pmap_t pmap, vaddr_t va,
-       vm_prot_t *cur_prot, vm_prot_t *prot);
 static struct  pv_entry *pv_get(pmap_t pmap, uintptr_t ppn, uintptr_t lpn);
 static struct  pv_entry *pv_alloc(void);
 static void    pv_free(struct pv_entry *pv);
@@ -440,39 +439,102 @@
        return pv;
 }
 
-void
-pmap_get_current_protection(pmap_t pmap, vaddr_t va,
-       vm_prot_t *cur_prot, vm_prot_t *prot)
+/*
+ * Check if the given page fault was our reference / modified emulation fault;
+ * if so return true otherwise return false and let uvm handle it
+ */
+bool
+pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype)
 {
-       struct pv_entry *pv;
+       struct pv_entry *pv, *ppv;
+       uintptr_t lpn, ppn;
+       int prot, cur_prot, diff;
+
+       /* get current protection settings */
+
+       aprint_debug("pmap_fault pmap %p, va %p\n", pmap, (void *) va);
+
+       /* get logical page from vaddr */
+       lpn = atop(va - VM_MIN_ADDRESS);        /* V->L */
+       pv  = pmap->pm_entries[lpn];
+
+       /* not known! then it must be UVM's work */
+       if (pv == NULL) {
+aprint_debug("no mapping yet\n");
+               *atype = VM_PROT_READ;          /* assume it was a read */
+               return false;
+       }
+
+       /* determine physical address and lookup 'root' pv_entry */
+       ppn = pv->pv_ppn;
+       ppv = &pv_table[ppn];
 
-       uintptr_t lpn;
+       /* if unmanaged we just make sure it is there! */
+       if (ppv->pv_vflags & PV_UNMANAGED) {
+               printf("%s: oops warning unmanaged page %"PRIiPTR" faulted\n",
+                       __func__, ppn);
+               /* atype not set */
+               pmap_page_activate(pv);
+               return true;
+       }
+
+       /* determine pmap access type (mmap doesnt need to be 1:1 on VM_PROT_) */
+       prot = pv->pv_prot;
+       cur_prot = VM_PROT_NONE;
+       if (pv->pv_mmap_ppl & PROT_READ)
+               cur_prot |= VM_PROT_READ;
+       if (pv->pv_mmap_ppl & PROT_WRITE)
+               cur_prot |= VM_PROT_WRITE;
+       if (pv->pv_mmap_ppl & PROT_EXEC)
+               cur_prot |= VM_PROT_EXECUTE;
+
+       diff = prot & (prot ^ cur_prot);
 
-       aprint_debug("pmap_get_current_protection pmap %p, va %p\n", pmap, (void *) va);
-#ifdef DIAGNOSTIC
-       if ((va < VM_MIN_ADDRESS) || (va >= VM_MAX_ADDRESS))
-               panic("pmap_do_enter: invalid va isued\n");
+aprint_debug("prot = %d, cur_prot = %d, diff = %d\n", prot, cur_prot, diff);
+       *atype = VM_PROT_READ;  /* assume its a read error */
+       if (diff & VM_PROT_READ) {
+               if ((ppv->pv_pflags & PV_REFERENCED) == 0) {
+                       ppv->pv_vflags |= PV_REFERENCED;
+                       pmap_update_page(ppn);
+                       return true;
+               }
+               return false;
+       }
+
+#if 0
+       /* this might be questionable */
+       if (diff & VM_PROT_EXECUTE) {
+               *atype = VM_PROT_EXECUTE; /* assume it was executing */
+               if (prot & VM_PROT_EXECUTE) {
+                       if ((ppv->pv_pflags & PV_REFERENCED) == 0) {
+                               ppv->pv_vflags |= PV_REFERENCED;
+                               pmap_update_page(ppn);
+                               return true;
+                       }
+               }
+               return false;
+       }
 #endif
 
-       lpn = atop(va - VM_MIN_ADDRESS);        /* V->L */
-
-       /* raise interupt level */
-       pv = pmap->pm_entries[lpn];
-       if (pv == NULL) {
-               *cur_prot = *prot = VM_PROT_NONE;
-               return;
+       *atype = VM_PROT_WRITE; /* assume its a write error */
+       if (diff & VM_PROT_WRITE) {
+               if (prot & VM_PROT_WRITE) {
+aprint_debug("should be allowed to write\n");
+                       if ((ppv->pv_pflags & PV_MODIFIED) == 0) {
+aprint_debug("was marked unmodified\n");
+                               ppv->pv_vflags |= PV_MODIFIED;
+                               pmap_update_page(ppn);
+                               return true;
+                       }
+               }
+               return false;
        }
 
-       *prot = pv->pv_prot;
-       *cur_prot = VM_PROT_NONE;
-       if (pv->pv_mmap_ppl & PROT_READ)
-               *cur_prot |= VM_PROT_READ;
-       if (pv->pv_mmap_ppl & PROT_WRITE)
-               *cur_prot |= VM_PROT_WRITE;
-       if (pv->pv_mmap_ppl & PROT_EXEC)
-               *cur_prot |= VM_PROT_EXECUTE;
+       /* not due to our r/m handling, let uvm handle it ! */
+       return false;
 }
 
+
 static void
 pmap_page_activate(struct pv_entry *pv)
 {
@@ -515,6 +577,10 @@
        pflags = pv_table[pv->pv_ppn].pv_pflags;
        vflags = pv_table[pv->pv_ppn].pv_vflags;
 
+       KASSERT(PROT_READ == VM_PROT_READ);
+       KASSERT(PROT_WRITE == VM_PROT_WRITE);
+       KASSERT(PROT_EXEC == VM_PROT_EXECUTE);
+
        /* create referenced/modified emulation */
        if ((pv->pv_prot & VM_PROT_WRITE) &&
            (pflags & PV_REFERENCED) && (pflags & PV_MODIFIED))
diff -r 878d3367e34c -r b10d0dee546a sys/arch/usermode/usermode/trap.c
--- a/sys/arch/usermode/usermode/trap.c Wed Aug 31 12:25:05 2011 +0000
+++ b/sys/arch/usermode/usermode/trap.c Wed Aug 31 12:42:41 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.13 2011/08/29 14:59:09 reinoud Exp $ */
+/* $NetBSD: trap.c,v 1.14 2011/08/31 12:42:41 reinoud Exp $ */
 
 /*-
  * Copyright (c) 2011 Reinoud Zandijk <reinoud%netbsd.org@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.13 2011/08/29 14:59:09 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.14 2011/08/31 12:42:41 reinoud Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -52,10 +52,11 @@
 /* forwards and externals */
 void setup_signal_handlers(void);
 static void mem_access_handler(int sig, siginfo_t *info, void *ctx);
+extern int errno;
 
-extern void pmap_get_current_protection(pmap_t pmap, vaddr_t va,
-       vm_prot_t *cur_prot, vm_prot_t *prot);
-extern int errno;
+bool pmap_fault(pmap_t pmap, vaddr_t va, vm_prot_t *atype);
+
+static int debug_fh;
 
 void
 startlwp(void *arg)
@@ -74,6 +75,8 @@
                panic("couldn't register SIGSEGV handler : %d", errno);
        if (thunk_sigaction(SIGBUS, &sa, NULL) == -1)
                panic("couldn't register SIGBUS handler : %d", errno);
+
+       debug_fh = thunk_open("/usr/sources/debug", O_RDWR | O_TRUNC | O_CREAT, 0666);
 }
 
 static struct trapframe kernel_tf;
@@ -81,33 +84,37 @@
 static void
 mem_access_handler(int sig, siginfo_t *info, void *ctx)
 {
+       static volatile int recurse = 0;
        struct proc *p;
        struct lwp *l;
        struct pcb *pcb;
        struct vmspace *vm;
        struct vm_map *vm_map;
        struct trapframe *tf;
-       vm_prot_t cur_prot, prot, atype;
+       vm_prot_t atype;
        vaddr_t va;
-       vaddr_t onfault;
+       void *onfault;
        int kmem, rv;
-       static volatile int recurse = 0;
 
        recurse++;
-       aprint_debug("trap lwp=%p pid=%d lid=%d\n",
-           curlwp,
-           curlwp->l_proc->p_pid,
-           curlwp->l_lid);
        if (recurse > 1)
                printf("enter trap recursion level %d\n", recurse);
        if ((info->si_signo == SIGSEGV) || (info->si_signo == SIGBUS)) {
                l = curlwp;
                p = l->l_proc;
                pcb = lwp_getpcb(l);
-               onfault = (vaddr_t) pcb->pcb_onfault;
+               onfault = pcb->pcb_onfault;
                vm = p->p_vmspace;
 
-#if 1
+#if 0
+               va = (vaddr_t) info->si_addr;
+               printf("trap lwp = %p pid = %d lid = %d, va = %p\n",
+                   curlwp,
+                   curlwp->l_proc->p_pid,
+                   curlwp->l_lid,
+                   (void *) va);
+#endif
+#if 0
                printf("SIGSEGV or SIGBUS!\n");
                printf("\tsi_signo = %d\n", info->si_signo);
                printf("\tsi_errno = %d\n", info->si_errno);
@@ -134,50 +141,39 @@
                va = (vaddr_t) info->si_addr;
                va = trunc_page(va);
 
+               /* sanity */
+               if ((va < VM_MIN_ADDRESS) || (va >= VM_MAX_ADDRESS))
+                       panic("peeing outside the box!");
+
                kmem = 1;
                vm_map = kernel_map;
                if ((va >= VM_MIN_ADDRESS) && (va < VM_MAXUSER_ADDRESS)) {
                        kmem = 0;
                        vm_map = &vm->vm_map;
                }



Home | Main Index | Thread Index | Old Index