Module Name: src Committed By: reinoud Date: Wed Aug 31 12:42:41 UTC 2011
Modified Files: src/sys/arch/usermode/conf: GENERIC src/sys/arch/usermode/usermode: pmap.c trap.c Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.14 -r1.15 src/sys/arch/usermode/conf/GENERIC cvs rdiff -u -r1.48 -r1.49 src/sys/arch/usermode/usermode/pmap.c cvs rdiff -u -r1.13 -r1.14 src/sys/arch/usermode/usermode/trap.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/usermode/conf/GENERIC diff -u src/sys/arch/usermode/conf/GENERIC:1.14 src/sys/arch/usermode/conf/GENERIC:1.15 --- src/sys/arch/usermode/conf/GENERIC:1.14 Sat Aug 27 18:13:09 2011 +++ src/sys/arch/usermode/conf/GENERIC Wed Aug 31 12:42:41 2011 @@ -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 DEBUG_EXEC options DIAGNOSTIC -options LOCKDEBUG +options LOCKDEBUG +options DEBUG_EXEC +#options CPU_DEBUG +#options UVMHIST +#options UVMHIST_PRINT options COMPAT_BSDPTY options COMPAT_50 Index: src/sys/arch/usermode/usermode/pmap.c diff -u src/sys/arch/usermode/usermode/pmap.c:1.48 src/sys/arch/usermode/usermode/pmap.c:1.49 --- src/sys/arch/usermode/usermode/pmap.c:1.48 Tue Aug 30 12:02:38 2011 +++ src/sys/arch/usermode/usermode/pmap.c Wed Aug 31 12:42:41 2011 @@ -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 <rein...@netbsd.org> @@ -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; - uintptr_t lpn; + /* get current protection settings */ - 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"); -#endif + 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]; - /* raise interupt level */ - pv = pmap->pm_entries[lpn]; + /* not known! then it must be UVM's work */ if (pv == NULL) { - *cur_prot = *prot = VM_PROT_NONE; - return; +aprint_debug("no mapping yet\n"); + *atype = VM_PROT_READ; /* assume it was a read */ + return false; } - *prot = pv->pv_prot; - *cur_prot = VM_PROT_NONE; + /* determine physical address and lookup 'root' pv_entry */ + ppn = pv->pv_ppn; + ppv = &pv_table[ppn]; + + /* 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; + cur_prot |= VM_PROT_READ; if (pv->pv_mmap_ppl & PROT_WRITE) - *cur_prot |= VM_PROT_WRITE; + cur_prot |= VM_PROT_WRITE; if (pv->pv_mmap_ppl & PROT_EXEC) - *cur_prot |= VM_PROT_EXECUTE; + cur_prot |= VM_PROT_EXECUTE; + + diff = prot & (prot ^ cur_prot); + +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 + + *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; + } + + /* 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)) Index: src/sys/arch/usermode/usermode/trap.c diff -u src/sys/arch/usermode/usermode/trap.c:1.13 src/sys/arch/usermode/usermode/trap.c:1.14 --- src/sys/arch/usermode/usermode/trap.c:1.13 Mon Aug 29 14:59:09 2011 +++ src/sys/arch/usermode/usermode/trap.c Wed Aug 31 12:42:41 2011 @@ -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 <rein...@netbsd.org> @@ -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,11 +52,12 @@ /* forwards and externals */ void setup_signal_handlers(void); static void mem_access_handler(int sig, siginfo_t *info, void *ctx); - -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; } - if ((va < VM_MIN_ADDRESS) || (va > VM_MAX_ADDRESS)) { - panic("peeing outside the box!"); - } - /* determine accesstype */ - pmap_get_current_protection(vm_map->pmap, va, &cur_prot, &prot); + /* can pmap handle it? on its own? (r/m) */ rv = 0; - if ((prot == VM_PROT_NONE) && (cur_prot == VM_PROT_NONE)) { - /* not mapped in yet */ -printf("was not mapped in yet --> faulting read first\n"); + if (!pmap_fault(vm_map->pmap, va, &atype)) { + aprint_debug("pmap fault couldn't handle it! : " + "derived atype %d\n", atype); pcb->pcb_onfault = NULL; - rv = uvm_fault(vm_map, (vaddr_t) va, VM_PROT_READ); - pcb->pcb_onfault = (void *) onfault; - - /* update accesstypes */ - pmap_get_current_protection(vm_map->pmap, va, &cur_prot, &prot); + rv = uvm_fault(vm_map, va, atype); + pcb->pcb_onfault = onfault; } - /* if no error, its map-able */ - if (rv == 0) { - atype = VM_PROT_NONE; /* assume read */ - if (prot & PROT_EXEC) - atype |= VM_PROT_EXECUTE; /* could well be execute */ - if ((prot & PROT_WRITE) && (cur_prot & VM_PROT_READ)) - atype = VM_PROT_WRITE; /* if it had write access */ - -printf("%sva %p, prot = %d, cur_prot = %d ==> atype = %d\n", kmem?"kmem, ":"", (void *) va, prot, cur_prot, atype); - if (atype != VM_PROT_NONE) { - pcb->pcb_onfault = NULL; - rv = uvm_fault(vm_map, (vaddr_t) va, atype); - pcb->pcb_onfault = (void *) onfault; - } - } +#if 0 +//if (!rv) { +// static int off = 0; + printf("*va = %d\n", *((uint32_t *) va)); + thunk_pwrite(debug_fh, (void *) va, PAGE_SIZE, va); +// off += PAGE_SIZE; +//} +#endif - if (rv) + if (rv) { aprint_debug("uvm_fault returned error %d\n", rv); - if (rv) { /* something got wrong */ if (kmem) { /* copyin / copyout */ @@ -194,6 +190,7 @@ } panic("should deliver a trap to the process"); } + if (recurse > 1) printf("leaving trap recursion level %d\n", recurse); recurse--;