Module Name:    src
Committed By:   kamil
Date:           Wed Jan 18 05:12:00 UTC 2017

Modified Files:
        src/sys/arch/amd64/amd64: trap.c
        src/sys/arch/i386/i386: trap.c
        src/sys/arch/x86/include: dbregs.h
        src/sys/arch/x86/x86: dbregs.c

Log Message:
Embed hardware trap and its type that fired (x86), information for tracers

Now x86 throws SIGTRAP on hardware exception with:
 - si_code TRAP_HWWPT - dedicated for hw assisted watchpoint interface
 - si_trap - unchanged (T_TRCTRAP)
 - si_trap2 - watchpoint number that fired
 - si_trap3 - watchpoint specific event description

x86 returns in si_trap3 one of the field from <x86/dbregs.h>
 - X86_HW_WATCHPOINT_EVENT_FIRED - watchpoint fired
 - X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP - watchpoint fired under PT_STEP

Othe changes:
 - restrict more code from <x86/dbregs.h> to _KERNEL

Sponsored bt <The NetBSD Foundation>


To generate a diff of this commit:
cvs rdiff -u -r1.88 -r1.89 src/sys/arch/amd64/amd64/trap.c
cvs rdiff -u -r1.281 -r1.282 src/sys/arch/i386/i386/trap.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/x86/include/dbregs.h
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/x86/dbregs.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/trap.c
diff -u src/sys/arch/amd64/amd64/trap.c:1.88 src/sys/arch/amd64/amd64/trap.c:1.89
--- src/sys/arch/amd64/amd64/trap.c:1.88	Thu Dec 15 12:04:17 2016
+++ src/sys/arch/amd64/amd64/trap.c	Wed Jan 18 05:11:59 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.88 2016/12/15 12:04:17 kamil Exp $	*/
+/*	$NetBSD: trap.c,v 1.89 2017/01/18 05:11:59 kamil 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.88 2016/12/15 12:04:17 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.89 2017/01/18 05:11:59 kamil Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -230,7 +230,7 @@ trap(struct trapframe *frame)
 #endif
 	ksiginfo_t ksi;
 	void *onfault;
-	int type, error;
+	int type, error, wptnfo;
 	uint64_t cr2;
 	bool pfail;
 
@@ -706,7 +706,11 @@ faultcommon:
 			KSI_INIT_TRAP(&ksi);
 			ksi.ksi_signo = SIGTRAP;
 			ksi.ksi_trap = type & ~T_USER;
-			if (type == (T_BPTFLT|T_USER))
+			if ((wptnfo = user_trap_x86_hw_watchpoint())) {
+				ksi.ksi_code = TRAP_HWWPT;
+				ksi.ksi_trap2 = x86_hw_watchpoint_reg(wptnfo);
+				ksi.ksi_trap3 = x86_hw_watchpoint_type(wptnfo);
+			} else if (type == (T_BPTFLT|T_USER))
 				ksi.ksi_code = TRAP_BRKPT;
 			else
 				ksi.ksi_code = TRAP_TRACE;

Index: src/sys/arch/i386/i386/trap.c
diff -u src/sys/arch/i386/i386/trap.c:1.281 src/sys/arch/i386/i386/trap.c:1.282
--- src/sys/arch/i386/i386/trap.c:1.281	Tue Dec 13 10:54:27 2016
+++ src/sys/arch/i386/i386/trap.c	Wed Jan 18 05:11:59 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.281 2016/12/13 10:54:27 kamil Exp $	*/
+/*	$NetBSD: trap.c,v 1.282 2017/01/18 05:11:59 kamil Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.281 2016/12/13 10:54:27 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.282 2017/01/18 05:11:59 kamil Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -251,7 +251,7 @@ trap(struct trapframe *frame)
 	struct trapframe *vframe;
 	ksiginfo_t ksi;
 	void *onfault;
-	int type, error;
+	int type, error, wptnfo;
 	uint32_t cr2;
 	bool pfail;
 
@@ -700,7 +700,11 @@ faultcommon:
 			KSI_INIT_TRAP(&ksi);
 			ksi.ksi_signo = SIGTRAP;
 			ksi.ksi_trap = type & ~T_USER;
-			if (type == (T_BPTFLT|T_USER))
+			if ((wptnfo = user_trap_x86_hw_watchpoint())) {
+				ksi.ksi_code = TRAP_HWWPT;
+				ksi.ksi_trap2 = x86_hw_watchpoint_reg(wptnfo);
+				ksi.ksi_trap3 = x86_hw_watchpoint_type(wptnfo);
+			} else if (type == (T_BPTFLT|T_USER))
 				ksi.ksi_code = TRAP_BRKPT;
 			else
 				ksi.ksi_code = TRAP_TRACE;

Index: src/sys/arch/x86/include/dbregs.h
diff -u src/sys/arch/x86/include/dbregs.h:1.2 src/sys/arch/x86/include/dbregs.h:1.3
--- src/sys/arch/x86/include/dbregs.h:1.2	Thu Dec 15 12:04:18 2016
+++ src/sys/arch/x86/include/dbregs.h	Wed Jan 18 05:12:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: dbregs.h,v 1.2 2016/12/15 12:04:18 kamil Exp $	*/
+/*	$NetBSD: dbregs.h,v 1.3 2017/01/18 05:12:00 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
 #ifndef	_X86_DBREGS_H_
 #define	_X86_DBREGS_H_
 
-#if defined(_KMEMUSER) || defined(_KERNEL)
+#if defined(_KERNEL)
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -79,10 +79,10 @@
 #define X86_HW_WATCHPOINT_DR7_DR3_CONDITION_MASK		__BITS(28, 29)
 #define X86_HW_WATCHPOINT_DR7_DR3_LENGTH_MASK			__BITS(30, 31)
 
-#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+#endif /* !defined(_KERNEL) */
 
 /*
- * X86_HW_WATCHPOINT_DR7_CONDITION_IO_READWRITE is unused
+ * X86_HW_WATCHPOINT_DR7_CONDITION_IO_READWRITE is currently unused
  * it requires DE (debug extension) flag in control register CR4 set
  * not all CPUs support it
  */
@@ -103,6 +103,15 @@ enum x86_hw_watchpoint_length {
 	X86_HW_WATCHPOINT_DR7_LENGTH_FOURBYTES	= 0x3
 };
 
+/*
+ * 0x2 is currently unimplemented - it reflects 8 bytes on modern CPUs
+ */
+enum x86_hw_watchpoint_event {
+	X86_HW_WATCHPOINT_EVENT_NONE		= 0x0,
+	X86_HW_WATCHPOINT_EVENT_FIRED		= 0x1,
+	X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP	= 0x2,
+};
+
 #if defined(_KMEMUSER) || defined(_KERNEL)
 
 /*
@@ -122,6 +131,9 @@ struct x86_hw_watchpoint {
 	enum x86_hw_watchpoint_length length;
 };
 
+#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+
+#if defined(_KERNEL)
 /*
  * Set CPU Debug Registers - to be used before entering user-land context
  */
@@ -134,11 +146,19 @@ void clear_x86_hw_watchpoints(void);
 
 /*
  * Check if trap is triggered from user-land if so return nonzero value
- *
- * This resets Debug Status Register (DR6) break point detection
  */
 int user_trap_x86_hw_watchpoint(void);
 
-#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+/*
+ * Check if trap is triggered from user-land if so return nonzero value
+ */
+int x86_hw_watchpoint_type(int);
+
+/*
+ * Return register that fired
+ */
+int x86_hw_watchpoint_reg(int);
+
+#endif /* !defined(_KERNEL) */
 
 #endif /* !_X86_DBREGS_H_ */

Index: src/sys/arch/x86/x86/dbregs.c
diff -u src/sys/arch/x86/x86/dbregs.c:1.1 src/sys/arch/x86/x86/dbregs.c:1.2
--- src/sys/arch/x86/x86/dbregs.c:1.1	Thu Dec 15 12:04:18 2016
+++ src/sys/arch/x86/x86/dbregs.c	Wed Jan 18 05:12:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: dbregs.c,v 1.1 2016/12/15 12:04:18 kamil Exp $	*/
+/*	$NetBSD: dbregs.c,v 1.2 2017/01/18 05:12:00 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -150,14 +150,17 @@ clear_x86_hw_watchpoints(void)
 	      X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED));
 }
 
+/* Local temporary bitfield concept to compose event and register that fired */
+#define DR_EVENT_MASK		__BITS(15,8)
+#define DR_REGISTER_MASK	__BITS(7,0)
+
 int
 user_trap_x86_hw_watchpoint(void)
 {
 	register_t dr7, dr6;	/* debug registers dr6 and dr7 */
 	register_t bp;		/* breakpoint bits extracted from dr6 */
-	int nbp;		/* number of breakpoints that triggered */
-	vaddr_t addr[X86_HW_WATCHPOINTS];	/* breakpoint addresses */
-	int i;
+	register_t dr;		/* temporary value of dr0-dr3 */
+	int rv;			/* register and event that fired (if any) */
 
 	dr7 = rdr7();
 	if ((dr7 &
@@ -173,7 +176,6 @@ user_trap_x86_hw_watchpoint(void)
 		return 0;
 	}
 
-	nbp = 0;
 	dr6 = rdr6();
 	bp = dr6 & \
 	    (X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
@@ -190,41 +192,88 @@ user_trap_x86_hw_watchpoint(void)
 	}
 
 	/*
+	 * Clear Status Register (DR6) now as it's not done by CPU.
+	 *
+ 	 * Clear BREAKPOINT_CONDITION_DETECTED and SINGLE_STEP bits and ignore
+	 * the rest.
+	 */
+	ldr6(dr6 &
+	   ~(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
+	     X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
+	     X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
+	     X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED |
+	     X86_HW_WATCHPOINT_DR6_SINGLE_STEP));
+
+	/*
 	 * at least one of the breakpoints were hit, check to see
 	 * which ones and if any of them are user space addresses
 	 */
 
-	if (bp & X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED)
-		addr[nbp++] = (vaddr_t)rdr0();
-	if (bp & X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED)
-		addr[nbp++] = (vaddr_t)rdr1();
-	if (bp & X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED)
-		addr[nbp++] = (vaddr_t)rdr2();
-	if (bp & X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED)
-		addr[nbp++] = (vaddr_t)rdr3();
-
-	for (i = 0; i < nbp; i++) {
-		/* Check if addr[i] is in user space */
-		if (addr[i] >= (vaddr_t)VM_MAXUSER_ADDRESS)
-			continue;
+	if (bp & X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED) {
+		dr = rdr0();	
+		if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+			rv = 0;
+			if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+			else
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+			return rv;
+		}
+		
+	}
 
-		/*
-		 * Clear Status Register (DR6) now as it's not done by CPU.
-		 *
-	 	 * Clear BREAKPOINT_CONDITION_DETECTED bits and ignore
-		 * the rest.
-		 */
-		ldr6(dr6 &
-		   ~(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
-		     X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
-		     X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
-		     X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED));
+	if (bp & X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED) {
+		dr = rdr1();
+		if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+			rv = __SHIFTIN(1, DR_REGISTER_MASK);
+			if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+			else
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+			return rv;
+		}
+		
+	}
 
-		return nbp;
+	if (bp & X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED) {
+		dr = rdr2();
+		if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+			rv = __SHIFTIN(2, DR_REGISTER_MASK);
+			if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+			else
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+			return rv;
+		}
+		
+	}
+
+	if (bp & X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED) {
+		dr = rdr3();
+		if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
+			rv = __SHIFTIN(3, DR_REGISTER_MASK);
+			if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
+			else
+				rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
+			return rv;
+		}
+		
 	}
 
-	/*
-	 * None of the breakpoints are in user space.
-	 */
 	return 0;
 }
+
+int
+x86_hw_watchpoint_type(int wptnfo)
+{
+
+	return __SHIFTOUT(wptnfo, DR_EVENT_MASK);
+}
+
+int
+x86_hw_watchpoint_reg(int wptnfo)
+{
+
+	return __SHIFTOUT(wptnfo, DR_REGISTER_MASK);
+}

Reply via email to