Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/aarch64 Add support hardware breakpoint and watchpo...



details:   https://anonhg.NetBSD.org/src/rev/bc32000ff500
branches:  trunk
changeset: 953456:bc32000ff500
user:      ryo <ryo%NetBSD.org@localhost>
date:      Tue Mar 09 16:44:27 2021 +0000

description:
Add support hardware breakpoint and watchpoint again.

Limited support for hardware watchpoint has been available for some time, but it
has not been working properly. In addition, it stopped working at the time of
the PTRACE support commit on 2018-12-13. This has been fixed to work correctly,
and also fixed to be practical by sharing hardware watchpoints and breakpoints
between CPUs on MULTIPROCESSOR.

Also fixed a bug that causes a malfunction when switching CPUs with
"machine cpu N" when entering ddb mode from other than cpu_Debugger().

I have confirmed that the CPU can be switched by "machine cpu N" and return from
ddb properly in each case where ddb is called triggered by ddb break/watchpoint,
hardware break/watchpoint, and cpu_Debugger().

diffstat:

 sys/arch/aarch64/aarch64/cpu.c        |   12 +-
 sys/arch/aarch64/aarch64/cpuswitch.S  |    6 +-
 sys/arch/aarch64/aarch64/db_machdep.c |  455 +++++++++++++++++++++++----------
 sys/arch/aarch64/aarch64/trap.c       |   23 +-
 sys/arch/aarch64/aarch64/vectors.S    |    7 +-
 sys/arch/aarch64/include/db_machdep.h |    8 +-
 6 files changed, 353 insertions(+), 158 deletions(-)

diffs (truncated from 844 to 300 lines):

diff -r 9e5da8bbf8ef -r bc32000ff500 sys/arch/aarch64/aarch64/cpu.c
--- a/sys/arch/aarch64/aarch64/cpu.c    Tue Mar 09 16:43:13 2021 +0000
+++ b/sys/arch/aarch64/aarch64/cpu.c    Tue Mar 09 16:44:27 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.c,v 1.58 2021/01/11 21:58:31 skrll Exp $ */
+/* $NetBSD: cpu.c,v 1.59 2021/03/09 16:44:27 ryo Exp $ */
 
 /*
  * Copyright (c) 2017 Ryo Shimizu <ryo%nerv.org@localhost>
@@ -27,10 +27,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.58 2021/01/11 21:58:31 skrll Exp $");
+__KERNEL_RCSID(1, "$NetBSD: cpu.c,v 1.59 2021/03/09 16:44:27 ryo Exp $");
 
 #include "locators.h"
 #include "opt_arm_debug.h"
+#include "opt_ddb.h"
 #include "opt_fdt.h"
 #include "opt_multiprocessor.h"
 
@@ -53,6 +54,9 @@
 #include <aarch64/armreg.h>
 #include <aarch64/cpu.h>
 #include <aarch64/cpu_counter.h>
+#ifdef DDB
+#include <aarch64/db_machdep.h>
+#endif
 #include <aarch64/machdep.h>
 
 #include <arm/cpufunc.h>
@@ -681,7 +685,9 @@
        aarch64_getcacheinfo(device_unit(ci->ci_dev));
        aarch64_printcacheinfo(ci->ci_dev);
        cpu_identify2(ci->ci_dev, ci);
-
+#ifdef DDB
+       db_machdep_init();
+#endif
        mutex_exit(&cpu_hatch_lock);
 
        cpu_init_counter(ci);
diff -r 9e5da8bbf8ef -r bc32000ff500 sys/arch/aarch64/aarch64/cpuswitch.S
--- a/sys/arch/aarch64/aarch64/cpuswitch.S      Tue Mar 09 16:43:13 2021 +0000
+++ b/sys/arch/aarch64/aarch64/cpuswitch.S      Tue Mar 09 16:44:27 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: cpuswitch.S,v 1.32 2020/12/26 00:55:26 jmcneill Exp $ */
+/* $NetBSD: cpuswitch.S,v 1.33 2021/03/09 16:44:27 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014, 2020 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
 #include "opt_ddb.h"
 #include "opt_kasan.h"
 
-RCSID("$NetBSD: cpuswitch.S,v 1.32 2020/12/26 00:55:26 jmcneill Exp $")
+RCSID("$NetBSD: cpuswitch.S,v 1.33 2021/03/09 16:44:27 ryo Exp $")
 
        ARMV8_DEFINE_OPTIONS
 
@@ -310,7 +310,7 @@
 
 #ifdef DDB
 ENTRY_NP(cpu_Debugger)
-       brk     #0
+       brk     #0xffff
        ret
 END(cpu_Debugger)
 #endif /* DDB */
diff -r 9e5da8bbf8ef -r bc32000ff500 sys/arch/aarch64/aarch64/db_machdep.c
--- a/sys/arch/aarch64/aarch64/db_machdep.c     Tue Mar 09 16:43:13 2021 +0000
+++ b/sys/arch/aarch64/aarch64/db_machdep.c     Tue Mar 09 16:44:27 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: db_machdep.c,v 1.36 2021/03/09 16:43:13 ryo Exp $ */
+/* $NetBSD: db_machdep.c,v 1.37 2021/03/09 16:44:27 ryo Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.36 2021/03/09 16:43:13 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: db_machdep.c,v 1.37 2021/03/09 16:44:27 ryo Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd32.h"
@@ -75,6 +75,7 @@
 void db_md_tlbi_cmd(db_expr_t, bool, db_expr_t, const char *);
 void db_md_ttbr_cmd(db_expr_t, bool, db_expr_t, const char *);
 void db_md_sysreg_cmd(db_expr_t, bool, db_expr_t, const char *);
+void db_md_break_cmd(db_expr_t, bool, db_expr_t, const char *);
 void db_md_watch_cmd(db_expr_t, bool, db_expr_t, const char *);
 #if defined(_KERNEL) && defined(MULTIPROCESSOR)
 void db_md_switch_cpu_cmd(db_expr_t, bool, db_expr_t, const char *);
@@ -83,6 +84,26 @@
 static void db_md_meminfo_cmd(db_expr_t, bool, db_expr_t, const char *);
 #endif
 
+#ifdef _KERNEL
+#define MAX_BREAKPOINT 15
+#define MAX_WATCHPOINT 15
+/* The number varies depending on the CPU core (e.g. big.LITTLE) */
+static int max_breakpoint = MAX_BREAKPOINT;
+static int max_watchpoint = MAX_WATCHPOINT;
+
+struct breakpoint_info {
+       db_addr_t addr;
+};
+static struct breakpoint_info breakpoint_buf[MAX_BREAKPOINT + 1];
+
+struct watchpoint_info {
+       db_addr_t addr;
+       int size;
+       int accesstype;
+};
+static struct watchpoint_info watchpoint_buf[MAX_WATCHPOINT + 1];
+#endif
+
 const struct db_command db_machine_command_table[] = {
 #if defined(_KERNEL) && defined(MULTIPROCESSOR)
        {
@@ -95,6 +116,14 @@
 #if defined(_KERNEL)
        {
                DDB_ADD_CMD(
+                   "break", db_md_break_cmd, 0,
+                   "set or clear breakpoint",
+                   "[address|#]",
+                   "\taddress: breakpoint address to set\n"
+                   "\t#: breakpoint number to remove\n")
+       },
+       {
+               DDB_ADD_CMD(
                    "cpuinfo", db_md_cpuinfo_cmd, 0,
                    "Displays the current cpuinfo",
                    NULL, NULL)
@@ -661,70 +690,27 @@
        }
 }
 
-static uint64_t
-aarch64_get_dbgwcr(int n)
+void
+aarch64_breakpoint_set(int n, vaddr_t addr)
 {
-#define DBGWCR_READ(regno)     (reg_dbgwcr ## regno ## _el1_read())
+       uint64_t bcr, bvr;
 
-       switch (n) {
-       case 0:         return DBGWCR_READ(0);
-       case 1:         return DBGWCR_READ(1);
-       case 2:         return DBGWCR_READ(2);
-       case 3:         return DBGWCR_READ(3);
-       case 4:         return DBGWCR_READ(4);
-       case 5:         return DBGWCR_READ(5);
-       case 6:         return DBGWCR_READ(6);
-       case 7:         return DBGWCR_READ(7);
-       case 8:         return DBGWCR_READ(8);
-       case 9:         return DBGWCR_READ(9);
-       case 10:        return DBGWCR_READ(10);
-       case 11:        return DBGWCR_READ(11);
-       case 12:        return DBGWCR_READ(12);
-       case 13:        return DBGWCR_READ(13);
-       case 14:        return DBGWCR_READ(14);
-       case 15:        return DBGWCR_READ(15);
+       if (addr == 0) {
+               bvr = 0;
+               bcr = 0;
+       } else {
+               bvr = addr;
+               bcr =
+                   __SHIFTIN(0, DBGBCR_BT) |
+                   __SHIFTIN(0, DBGBCR_LBN) |
+                   __SHIFTIN(0, DBGBCR_SSC) |
+                   __SHIFTIN(0, DBGBCR_HMC) |
+                   __SHIFTIN(15, DBGBCR_BAS) |
+                   __SHIFTIN(3, DBGBCR_PMC) |
+                   __SHIFTIN(1, DBGBCR_E);
        }
 
-       return 0;
-}
-
-static uint64_t
-aarch64_get_dbgwvr(int n)
-{
-#define DBGWVR_READ(regno)     (reg_dbgwvr ## regno ## _el1_read())
-
-       switch (n) {
-       case 0:         return DBGWVR_READ(0);
-       case 1:         return DBGWVR_READ(1);
-       case 2:         return DBGWVR_READ(2);
-       case 3:         return DBGWVR_READ(3);
-       case 4:         return DBGWVR_READ(4);
-       case 5:         return DBGWVR_READ(5);
-       case 6:         return DBGWVR_READ(6);
-       case 7:         return DBGWVR_READ(7);
-       case 8:         return DBGWVR_READ(8);
-       case 9:         return DBGWVR_READ(9);
-       case 10:        return DBGWVR_READ(10);
-       case 11:        return DBGWVR_READ(11);
-       case 12:        return DBGWVR_READ(12);
-       case 13:        return DBGWVR_READ(13);
-       case 14:        return DBGWVR_READ(14);
-       case 15:        return DBGWVR_READ(15);
-       }
-
-       return 0;
-}
-
-void
-aarch64_breakpoint_clear(int n)
-{
-       aarch64_set_bcr_bvr(n, 0, 0);
-}
-
-void
-aarch64_watchpoint_clear(int n)
-{
-       aarch64_set_wcr_wvr(n, 0, 0);
+       aarch64_set_bcr_bvr(n, bcr, bvr);
 }
 
 void
@@ -750,7 +736,7 @@
                wvr = 0;
                wcr = 0;
        } else {
-               wvr = addr & DBGWVR_MASK;
+               wvr = addr;
                wcr =
                    __SHIFTIN(0, DBGWCR_MASK) |         /* MASK: no mask */
                    __SHIFTIN(0, DBGWCR_WT) |           /* WT: 0 */
@@ -766,70 +752,135 @@
        aarch64_set_wcr_wvr(n, wcr, wvr);
 }
 
-#define MAX_BREAKPOINT 15
-static int max_breakpoint = MAX_BREAKPOINT;
+static void
+db_md_breakpoint_set(int n, vaddr_t addr)
+{
+       if (n >= __arraycount(breakpoint_buf))
+               return;
+
+       breakpoint_buf[n].addr = addr;
+}
+
+static void
+db_md_watchpoint_set(int n, vaddr_t addr, int size, int accesstype)
+{
+       if (n >= __arraycount(watchpoint_buf))
+               return;
+
+       watchpoint_buf[n].addr = addr;
+       watchpoint_buf[n].size = size;
+       watchpoint_buf[n].accesstype = accesstype;
+}
 
-#define MAX_WATCHPOINT 15
-static int max_watchpoint = MAX_WATCHPOINT;
+static void
+db_md_breakwatchpoints_clear(void)
+{
+       int i;
+
+       for (i = 0; i <= max_breakpoint; i++)
+               aarch64_breakpoint_set(i, 0);
+       for (i = 0; i <= max_watchpoint; i++)
+               aarch64_watchpoint_set(i, 0, 0, 0);
+}
+
+static void
+db_md_breakwatchpoints_reload(void)
+{
+       int i;
+
+       for (i = 0; i <= max_breakpoint; i++) {
+               aarch64_breakpoint_set(i,
+                   breakpoint_buf[i].addr);
+       }
+       for (i = 0; i <= max_watchpoint; i++) {
+               aarch64_watchpoint_set(i,
+                   watchpoint_buf[i].addr,
+                   watchpoint_buf[i].size,
+                   watchpoint_buf[i].accesstype);
+       }
+}
 
 void
 db_machdep_init(void)
 {
        uint64_t dfr, mdscr;
-       int i;
+       int i, cpu_max_breakpoint, cpu_max_watchpoint;
 
        dfr = reg_id_aa64dfr0_el1_read();
-       max_breakpoint = __SHIFTOUT(dfr, ID_AA64DFR0_EL1_BRPS);



Home | Main Index | Thread Index | Old Index