Module Name:    src
Committed By:   rmind
Date:           Sat Mar 28 22:56:20 UTC 2009

Modified Files:
        src/sys/arch/amd64/amd64: copy.S trap.c

Log Message:
Change amd64 fault handler to check instruction pointer for copyin/out et al
functions, like in i386.  Avoids setting pcb_onfault, saves few instructions.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/amd64/amd64/copy.S
cvs rdiff -u -r1.54 -r1.55 src/sys/arch/amd64/amd64/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/amd64/amd64/copy.S
diff -u src/sys/arch/amd64/amd64/copy.S:1.13 src/sys/arch/amd64/amd64/copy.S:1.14
--- src/sys/arch/amd64/amd64/copy.S:1.13	Mon Feb 23 20:27:59 2009
+++ src/sys/arch/amd64/amd64/copy.S	Sat Mar 28 22:56:19 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: copy.S,v 1.13 2009/02/23 20:27:59 rmind Exp $	*/
+/*	$NetBSD: copy.S,v 1.14 2009/03/28 22:56:19 rmind Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -62,6 +62,10 @@
 	call	_C_LABEL(do_pmap_load)		; \
 	jmp	98b
 
+/*
+ * The following primitives are to copy regions of memory.
+ * Label must be before all copy functions.
+ */
 	.text
 
 x86_copyfunc_start:	.globl	x86_copyfunc_start
@@ -103,6 +107,9 @@
 	ret
 
 /*
+ * int kcopy(const void *from, void *to, size_t len);
+ * Copy len bytes, abort on fault.
+ *
  * Copy routines from and to userland, plus a few more. See the
  * section 9 manpages for info. Some cases can be optimized more.
  *
@@ -119,14 +126,9 @@
  */
 
 ENTRY(kcopy)
-	GET_CURPCB(%rax)
-	pushq	PCB_ONFAULT(%rax)
-	leaq	_C_LABEL(kcopy_fault)(%rip),%r11
-	movq	%r11, PCB_ONFAULT(%rax)
-
 	xchgq	%rdi,%rsi
 	movq	%rdx,%rcx
-
+.Lkcopy_start:
 	movq	%rdi,%rax
 	subq	%rsi,%rax
 	cmpq	%rcx,%rax		# overlapping?
@@ -141,8 +143,6 @@
 	rep
 	movsb
 
-	GET_CURPCB(%rdx)
-	popq	PCB_ONFAULT(%rdx)
 	xorq	%rax,%rax
 	ret
 
@@ -166,29 +166,23 @@
 	rep
 	movsq
 	cld
-
-	GET_CURPCB(%rdx)
-	popq	PCB_ONFAULT(%rdx)
+.Lkcopy_end:
 	xorq	%rax,%rax
 	ret
 
 ENTRY(copyout)
 	DEFERRED_SWITCH_CHECK
-	pushq	$0			# Restored to PCB_ONFAULT(%rdx)
 
 	xchgq	%rdi,%rsi		# kernel address to %rsi, user to %rdi
 	movq	%rdx,%rax		# save transfer length (bytes)
-	
+
 	addq	%rdi,%rdx		# end address to %rdx
 	jc	_C_LABEL(copy_efault)	# jump if wraps
 	movq	$VM_MAXUSER_ADDRESS,%r8
 	cmpq	%r8,%rdx
 	ja	_C_LABEL(copy_efault)	# jump if end in kernel space
 
-	GET_CURPCB(%rdx)
-	leaq	_C_LABEL(copy_fault)(%rip),%r11
-	movq	%r11,PCB_ONFAULT(%rdx)	# prime fault handler
-
+.Lcopyout_start:
 	movq	%rax,%rcx		# length
 	shrq	$3,%rcx			# count of 8-byte words
 	rep
@@ -197,18 +191,13 @@
 	andb	$7,%cl			# remaining number of bytes
 	rep
 	movsb				# copy remaining bytes
-
-	popq	PCB_ONFAULT(%rdx)
+.Lcopyout_end:
 	xorl	%eax,%eax
 	ret
 	DEFERRED_SWITCH_CALL
 
 ENTRY(copyin)
 	DEFERRED_SWITCH_CHECK
-	GET_CURPCB(%rax)
-	pushq	$0
-	leaq	_C_LABEL(copy_fault)(%rip),%r11
-	movq	%r11,PCB_ONFAULT(%rax)
 
 	xchgq	%rdi,%rsi
 	movq	%rdx,%rax
@@ -219,6 +208,7 @@
 	cmpq	%r8,%rdx
 	ja	_C_LABEL(copy_efault)	# j if end in kernel space
 
+.Lcopyin_start:
 3:	/* bcopy(%rsi, %rdi, %rax); */
 	movq	%rax,%rcx
 	shrq	$3,%rcx
@@ -228,9 +218,7 @@
 	andb	$7,%cl
 	rep
 	movsb
-
-	GET_CURPCB(%rdx)
-	popq	PCB_ONFAULT(%rdx)
+.Lcopyin_end:
 	xorl	%eax,%eax
 	ret
 	DEFERRED_SWITCH_CALL
@@ -245,13 +233,9 @@
  */
 
 NENTRY(kcopy_fault)
-	GET_CURPCB(%rdx)
-	popq	PCB_ONFAULT(%rdx)
 	ret
 
 NENTRY(copy_fault)
-	GET_CURPCB(%rdx)
-	popq	PCB_ONFAULT(%rdx)
 	ret
 
 ENTRY(copyoutstr)
@@ -260,9 +244,6 @@
 	movq	%rdx,%r8
 	movq	%rcx,%r9
 
-5:	GET_CURPCB(%rax)
-	leaq	_C_LABEL(copystr_fault)(%rip),%r11
-	movq	%r11,PCB_ONFAULT(%rax)
 	/*
 	 * Get min(%rdx, VM_MAXUSER_ADDRESS-%rdi).
 	 */
@@ -273,7 +254,7 @@
 	jae	1f
 	movq	%rax,%rdx
 	movq	%rax,%r8
-
+.Lcopyoutstr_start:
 1:	incq	%rdx
 
 1:	decq	%rdx
@@ -282,7 +263,7 @@
 	stosb
 	testb	%al,%al
 	jnz	1b
-
+.Lcopyoutstr_end:
 	/* Success -- 0 byte reached. */
 	decq	%rdx
 	xorq	%rax,%rax
@@ -302,10 +283,6 @@
 	movq	%rdx,%r8
 	movq	%rcx,%r9
 
-	GET_CURPCB(%rcx)
-	leaq	_C_LABEL(copystr_fault)(%rip),%r11
-	movq	%r11,PCB_ONFAULT(%rcx)
-
 	/*
 	 * Get min(%rdx, VM_MAXUSER_ADDRESS-%rsi).
 	 */
@@ -316,7 +293,7 @@
 	jae	1f
 	movq	%rax,%rdx
 	movq	%rax,%r8
-
+.Lcopyinstr_start:
 1:	incq	%rdx
 
 1:	decq	%rdx
@@ -325,6 +302,7 @@
 	stosb
 	testb	%al,%al
 	jnz	1b
+.Lcopyinstr_end:
 
 	/* Success -- 0 byte reached. */
 	decq	%rdx
@@ -345,8 +323,6 @@
 ENTRY(copystr_fault)
 copystr_return:
 	/* Set *lencopied and return %eax. */
-	GET_CURPCB(%rcx)
-	movq	$0,PCB_ONFAULT(%rcx)
 	testq	%r9,%r9
 	jz	8f
 	subq	%rdx,%r8
@@ -526,15 +502,14 @@
 	movq	$VM_MAXUSER_ADDRESS-8, %r8
 	cmpq	%r8, %rdi
 	ja	1f
-	/* Set the fault handler */
-	GET_CURPCB(%r8)
-	leaq	_C_LABEL(ucas_fault)(%rip), %r9
-	movq	%r9, PCB_ONFAULT(%r8)
+	/* Label for fault handler */
+.Lucas64_start:
 	/* Perform the CAS */
 	lock
 	cmpxchgq %rdx, (%rdi)
 	/* Clear the fault handler */
 	movq	%rax, PCB_ONFAULT(%r8)
+.Lucas64_end:
 	/*
 	 * Note: %rax is "old" value.
 	 * Set the return values.
@@ -558,13 +533,12 @@
 	movq	$VM_MAXUSER_ADDRESS-4, %r8
 	cmpq	%r8, %rdi
 	ja	1f
-	/* Set the fault handler */
-	GET_CURPCB(%r8)
-	leaq	_C_LABEL(ucas_fault)(%rip), %r9
-	movq	%r9, PCB_ONFAULT(%r8)
+	/* Label for fault handler */
+.Lucas32_start:
 	/* Perform the CAS */
 	lock
 	cmpxchgl %edx, (%rdi)
+.Lucas32_end:
 	/*
 	 * Note: %eax is "old" value.
 	 * Set the return values.
@@ -582,7 +556,6 @@
  * Unset the handler and return the failure.
  */
 NENTRY(ucas_fault)
-	movq	$0, PCB_ONFAULT(%r8)
 	movq	$EFAULT, %rax
 	ret
 
@@ -592,4 +565,45 @@
 STRONG_ALIAS(ucas_ptr, ucas_64)
 STRONG_ALIAS(ucas_int, ucas_32)
 
+/*
+ * Label must be after all copy functions.
+ */
 x86_copyfunc_end:	.globl	x86_copyfunc_end
+
+/*
+ * Fault table of copy functions for trap().
+ */
+	.section ".rodata"
+	.globl _C_LABEL(onfault_table)
+_C_LABEL(onfault_table):
+	.quad .Lcopyin_start
+	.quad .Lcopyin_end
+	.quad _C_LABEL(copy_fault)
+
+	.quad .Lcopyout_start
+	.quad .Lcopyout_end
+	.quad _C_LABEL(copy_fault)
+
+	.quad .Lkcopy_start
+	.quad .Lkcopy_end
+	.quad _C_LABEL(kcopy_fault)
+
+	.quad .Lcopyoutstr_start
+	.quad .Lcopyoutstr_end
+	.quad _C_LABEL(copystr_fault)
+
+	.quad .Lcopyinstr_start
+	.quad .Lcopyinstr_end
+	.quad _C_LABEL(copystr_fault)
+
+	.quad .Lucas64_start
+	.quad .Lucas64_end
+	.quad _C_LABEL(ucas_fault)
+
+	.quad .Lucas32_start
+	.quad .Lucas32_end
+	.quad _C_LABEL(ucas_fault)
+
+	.quad 0	/* terminate */
+
+	.text

Index: src/sys/arch/amd64/amd64/trap.c
diff -u src/sys/arch/amd64/amd64/trap.c:1.54 src/sys/arch/amd64/amd64/trap.c:1.55
--- src/sys/arch/amd64/amd64/trap.c:1.54	Tue Feb 24 06:03:54 2009
+++ src/sys/arch/amd64/amd64/trap.c	Sat Mar 28 22:56:19 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.54 2009/02/24 06:03:54 yamt Exp $	*/
+/*	$NetBSD: trap.c,v 1.55 2009/03/28 22:56:19 rmind Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.54 2009/02/24 06:03:54 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.55 2009/03/28 22:56:19 rmind Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -151,6 +151,31 @@
 static void frame_dump(struct trapframe *);
 #endif
 
+static void *
+onfault_handler(const struct pcb *pcb, const struct trapframe *tf)
+{
+	struct onfault_table {
+		uintptr_t start;
+		uintptr_t end;
+		void *handler;
+	};
+	extern const struct onfault_table onfault_table[];
+	const struct onfault_table *p;
+	uintptr_t pc;
+
+	if (pcb->pcb_onfault != NULL) {
+		return pcb->pcb_onfault;
+	}
+
+	pc = tf->tf_rip;
+	for (p = onfault_table; p->start; p++) {
+		if (p->start <= pc && pc < p->end) {
+			return p->handler;
+		}
+	}
+	return NULL;
+}
+
 /*
  * trap(frame):
  *	Exception, fault, and trap interface to BSD kernel. This
@@ -250,11 +275,12 @@
 		if (p == NULL)
 			goto we_re_toast;
 		/* Check for copyin/copyout fault. */
-		if (pcb->pcb_onfault != 0) {
+		onfault = onfault_handler(pcb, frame);
+		if (onfault != NULL) {
 copyefault:
 			error = EFAULT;
 copyfault:
-			frame->tf_rip = (uint64_t)pcb->pcb_onfault;
+			frame->tf_rip = (uintptr_t)onfault;
 			frame->tf_rax = error;
 			return;
 		}
@@ -412,7 +438,8 @@
 		 * fusuintrfailure is used by [fs]uswintr() to prevent
 		 * page faulting from inside the profiling interrupt.
 		 */
-		if (pcb->pcb_onfault == fusuintrfailure) {
+		onfault = pcb->pcb_onfault;
+		if (onfault == fusuintrfailure) {
 			goto copyefault;
 		}
 		if (cpu_intr_p() || (l->l_pflag & LP_INTR) != 0) {
@@ -489,6 +516,7 @@
  				 */
 				kpreempt_disable();
 				if (curcpu()->ci_want_pmapload) {
+					onfault = onfault_handler(pcb, frame);
 					if (onfault != kcopy_fault) {
 						pmap_load();
 					}
@@ -537,7 +565,8 @@
 			ksi.ksi_code = SEGV_MAPERR;
 
 		if (type == T_PAGEFLT) {
-			if (pcb->pcb_onfault != 0)
+			onfault = onfault_handler(pcb, frame);
+			if (onfault != NULL)
 				goto copyfault;
 			printf("uvm_fault(%p, 0x%lx, %d) -> %x\n",
 			    map, va, ftype, error);

Reply via email to