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 <[email protected]>
@@ -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 <[email protected]>
@@ -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--;