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/8a7122bc080d
branches:  trunk
changeset: 820981:8a7122bc080d
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 70c61e49becc -r 8a7122bc080d 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 70c61e49becc -r 8a7122bc080d 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 70c61e49becc -r 8a7122bc080d 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 70c61e49becc -r 8a7122bc080d 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