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--;

Reply via email to