Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch Embed hardware trap and its type that fired (x86), ...
details: https://anonhg.NetBSD.org/src/rev/5453da3f1614
branches: trunk
changeset: 350730:5453da3f1614
user: kamil <kamil%NetBSD.org@localhost>
date: Wed Jan 18 05:11:59 2017 +0000
description:
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>
diffstat:
sys/arch/amd64/amd64/trap.c | 12 ++-
sys/arch/i386/i386/trap.c | 12 ++-
sys/arch/x86/include/dbregs.h | 34 +++++++++--
sys/arch/x86/x86/dbregs.c | 117 +++++++++++++++++++++++++++++------------
4 files changed, 126 insertions(+), 49 deletions(-)
diffs (truncated from 316 to 300 lines):
diff -r fb45d4e3bbcb -r 5453da3f1614 sys/arch/amd64/amd64/trap.c
--- a/sys/arch/amd64/amd64/trap.c Wed Jan 18 02:33:25 2017 +0000
+++ b/sys/arch/amd64/amd64/trap.c Wed Jan 18 05:11:59 2017 +0000
@@ -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 @@
#endif
ksiginfo_t ksi;
void *onfault;
- int type, error;
+ int type, error, wptnfo;
uint64_t cr2;
bool pfail;
@@ -706,7 +706,11 @@
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;
diff -r fb45d4e3bbcb -r 5453da3f1614 sys/arch/i386/i386/trap.c
--- a/sys/arch/i386/i386/trap.c Wed Jan 18 02:33:25 2017 +0000
+++ b/sys/arch/i386/i386/trap.c Wed Jan 18 05:11:59 2017 +0000
@@ -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 @@
struct trapframe *vframe;
ksiginfo_t ksi;
void *onfault;
- int type, error;
+ int type, error, wptnfo;
uint32_t cr2;
bool pfail;
@@ -700,7 +700,11 @@
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;
diff -r fb45d4e3bbcb -r 5453da3f1614 sys/arch/x86/include/dbregs.h
--- a/sys/arch/x86/include/dbregs.h Wed Jan 18 02:33:25 2017 +0000
+++ b/sys/arch/x86/include/dbregs.h Wed Jan 18 05:11:59 2017 +0000
@@ -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 @@
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 @@
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 @@
/*
* 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_ */
diff -r fb45d4e3bbcb -r 5453da3f1614 sys/arch/x86/x86/dbregs.c
--- a/sys/arch/x86/x86/dbregs.c Wed Jan 18 02:33:25 2017 +0000
+++ b/sys/arch/x86/x86/dbregs.c Wed Jan 18 05:11:59 2017 +0000
@@ -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 @@
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 @@
return 0;
}
- nbp = 0;
dr6 = rdr6();
bp = dr6 & \
(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
@@ -190,41 +192,88 @@
}
/*
+ * 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));
-
- return nbp;
+ 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;
+ }
+
}
- /*
- * None of the breakpoints are in user space.
- */
+ 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;
+ }
+
+ }
+
Home |
Main Index |
Thread Index |
Old Index