The branch stable/13 has been updated by mhorne:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4786c8582c569a7245dadbdbb4638d1667c10d62

commit 4786c8582c569a7245dadbdbb4638d1667c10d62
Author:     Mitchell Horne <mho...@freebsd.org>
AuthorDate: 2021-01-28 17:49:47 +0000
Commit:     Mitchell Horne <mho...@freebsd.org>
CommitDate: 2021-02-24 14:58:43 +0000

    arm64: extend struct db_reg to include watchpoint registers
    
    The motivation is to provide access to these registers from userspace
    via ptrace(2) requests PT_GETDBREGS and PT_SETDBREGS.
    
    This change breaks the ABI of these particular requests, but is
    justified by the fact that the intended consumers (debuggers) have not
    been taught to use them yet. Making this change now enables active
    upstream work on lldb to begin using this interface, and take advantage
    of the hardware debugging registers available on the platform.
    
    PR:             252860
    Reported by:    Michał Górny (mgo...@gentoo.org)
    Reviewed by:    andrew, markj (earlier version)
    Tested by:      Michał Górny (mgo...@gentoo.org)
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit f2583be110ca3a5b32f0993f1464a5c69151c62f)
---
 sys/arm64/arm64/identcpu.c |  2 +-
 sys/arm64/arm64/machdep.c  | 71 ++++++++++++++++++++++++++++++++++++++--------
 sys/arm64/include/armreg.h | 22 ++++++++++++++
 sys/arm64/include/reg.h    | 13 +++++++--
 4 files changed, 92 insertions(+), 16 deletions(-)

diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
index bfbaad7a6483..c3544e9de9aa 100644
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -350,7 +350,7 @@ static struct mrs_field id_aa64dfr0_fields[] = {
        MRS_FIELD(ID_AA64DFR0, PMSVer, false, MRS_EXACT, id_aa64dfr0_pmsver),
        MRS_FIELD(ID_AA64DFR0, CTX_CMPs, false, MRS_EXACT,
            id_aa64dfr0_ctx_cmps),
-       MRS_FIELD(ID_AA64DFR0, WRPs, false, MRS_EXACT, id_aa64dfr0_wrps),
+       MRS_FIELD(ID_AA64DFR0, WRPs, false, MRS_LOWER, id_aa64dfr0_wrps),
        MRS_FIELD(ID_AA64DFR0, BRPs, false, MRS_LOWER, id_aa64dfr0_brps),
        MRS_FIELD(ID_AA64DFR0, PMUVer, false, MRS_EXACT, id_aa64dfr0_pmuver),
        MRS_FIELD(ID_AA64DFR0, TraceVer, false, MRS_EXACT,
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index bf44dba19482..73b06beeba7e 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -321,8 +321,8 @@ int
 fill_dbregs(struct thread *td, struct dbreg *regs)
 {
        struct debug_monitor_state *monitor;
-       int count, i;
-       uint8_t debug_ver, nbkpts;
+       int i;
+       uint8_t debug_ver, nbkpts, nwtpts;
 
        memset(regs, 0, sizeof(*regs));
 
@@ -330,23 +330,30 @@ fill_dbregs(struct thread *td, struct dbreg *regs)
            &debug_ver);
        extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_BRPs_SHIFT,
            &nbkpts);
+       extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_WRPs_SHIFT,
+           &nwtpts);
 
        /*
         * The BRPs field contains the number of breakpoints - 1. Armv8-A
         * allows the hardware to provide 2-16 breakpoints so this won't
-        * overflow an 8 bit value.
+        * overflow an 8 bit value. The same applies to the WRPs field.
         */
-       count = nbkpts + 1;
+       nbkpts++;
+       nwtpts++;
 
-       regs->db_info = debug_ver;
-       regs->db_info <<= 8;
-       regs->db_info |= count;
+       regs->db_debug_ver = debug_ver;
+       regs->db_nbkpts = nbkpts;
+       regs->db_nwtpts = nwtpts;
 
        monitor = &td->td_pcb->pcb_dbg_regs;
        if ((monitor->dbg_flags & DBGMON_ENABLED) != 0) {
-               for (i = 0; i < count; i++) {
-                       regs->db_regs[i].dbr_addr = monitor->dbg_bvr[i];
-                       regs->db_regs[i].dbr_ctrl = monitor->dbg_bcr[i];
+               for (i = 0; i < nbkpts; i++) {
+                       regs->db_breakregs[i].dbr_addr = monitor->dbg_bvr[i];
+                       regs->db_breakregs[i].dbr_ctrl = monitor->dbg_bcr[i];
+               }
+               for (i = 0; i < nwtpts; i++) {
+                       regs->db_watchregs[i].dbw_addr = monitor->dbg_wvr[i];
+                       regs->db_watchregs[i].dbw_ctrl = monitor->dbg_wcr[i];
                }
        }
 
@@ -365,9 +372,10 @@ set_dbregs(struct thread *td, struct dbreg *regs)
        monitor = &td->td_pcb->pcb_dbg_regs;
        count = 0;
        monitor->dbg_enable_count = 0;
+
        for (i = 0; i < DBG_BRP_MAX; i++) {
-               addr = regs->db_regs[i].dbr_addr;
-               ctrl = regs->db_regs[i].dbr_ctrl;
+               addr = regs->db_breakregs[i].dbr_addr;
+               ctrl = regs->db_breakregs[i].dbr_ctrl;
 
                /* Don't let the user set a breakpoint on a kernel address. */
                if (addr >= VM_MAXUSER_ADDRESS)
@@ -399,6 +407,45 @@ set_dbregs(struct thread *td, struct dbreg *regs)
                monitor->dbg_bvr[i] = addr;
                monitor->dbg_bcr[i] = ctrl;
        }
+
+       for (i = 0; i < DBG_WRP_MAX; i++) {
+               addr = regs->db_watchregs[i].dbw_addr;
+               ctrl = regs->db_watchregs[i].dbw_ctrl;
+
+               /* Don't let the user set a watchpoint on a kernel address. */
+               if (addr >= VM_MAXUSER_ADDRESS)
+                       return (EINVAL);
+
+               /*
+                * Some control fields are ignored, and other bits reserved.
+                * Only unlinked watchpoints are supported.
+                */
+               ctrl &= DBG_WCR_EN | DBG_WCR_PAC | DBG_WCR_LSC | DBG_WCR_BAS |
+                   DBG_WCR_MASK;
+
+               if ((ctrl & DBG_WCR_EN) != 0) {
+                       /* Only target EL0. */
+                       if ((ctrl & DBG_WCR_PAC) != DBG_WCR_PAC_EL0)
+                               return (EINVAL);
+
+                       /* Must set at least one of the load/store bits. */
+                       if ((ctrl & DBG_WCR_LSC) == 0)
+                               return (EINVAL);
+
+                       /*
+                        * When specifying the address range with BAS, the MASK
+                        * field must be zero.
+                        */
+                       if ((ctrl & DBG_WCR_BAS) != DBG_WCR_BAS_MASK &&
+                           (ctrl & DBG_WCR_MASK) != 0)
+                               return (EINVAL);
+
+                       monitor->dbg_enable_count++;
+               }
+               monitor->dbg_wvr[i] = addr;
+               monitor->dbg_wcr[i] = ctrl;
+       }
+
        if (monitor->dbg_enable_count > 0)
                monitor->dbg_flags |= DBGMON_ENABLED;
 
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index 66cd8591c7ab..81cea5431017 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -961,6 +961,28 @@
 #define        DBG_BCR_BT_SHIFT        20
 #define        DBG_BCR_BT              (0xf << DBG_BCR_BT_SHIFT)
 
+/* Debug Watchpoint Control Registers */
+#define        DBG_WCR_EN              0x1
+#define        DBG_WCR_PAC_SHIFT       1
+#define        DBG_WCR_PAC             (0x3 << DBG_WCR_PAC_SHIFT)
+#define         DBG_WCR_PAC_EL1        (0x1 << DBG_WCR_PAC_SHIFT)
+#define         DBG_WCR_PAC_EL0        (0x2 << DBG_WCR_PAC_SHIFT)
+#define        DBG_WCR_LSC_SHIFT       3
+#define        DBG_WCR_LSC             (0x3 << DBG_WCR_LSC_SHIFT)
+#define        DBG_WCR_BAS_SHIFT       5
+#define        DBG_WCR_BAS             (0xff << DBG_WCR_BAS_SHIFT)
+#define         DBG_WCR_BAS_MASK       DBG_WCR_BAS
+#define        DBG_WCR_HMC_SHIFT       13
+#define        DBG_WCR_HMC             (0x1 << DBG_WCR_HMC_SHIFT)
+#define        DBG_WCR_SSC_SHIFT       14
+#define        DBG_WCR_SSC             (0x3 << DBG_WCR_SSC_SHIFT)
+#define        DBG_WCR_LBN_SHIFT       16
+#define        DBG_WCR_LBN             (0xf << DBG_WCR_LBN_SHIFT)
+#define        DBG_WCR_WT_SHIFT        20
+#define        DBG_WCR_WT              (0x1 << DBG_WCR_WT_SHIFT)
+#define        DBG_WCR_MASK_SHIFT      24
+#define        DBG_WCR_MASK            (0x1f << DBG_WCR_MASK_SHIFT)
+
 /* Perfomance Monitoring Counters */
 #define        PMCR_E          (1 << 0) /* Enable all counters */
 #define        PMCR_P          (1 << 1) /* Reset all counters */
diff --git a/sys/arm64/include/reg.h b/sys/arm64/include/reg.h
index aafe02b70925..9cfc5ea1d437 100644
--- a/sys/arm64/include/reg.h
+++ b/sys/arm64/include/reg.h
@@ -60,14 +60,21 @@ struct fpreg32 {
 };
 
 struct dbreg {
-       uint32_t        db_info;
-       uint32_t        db_pad;
+       uint8_t         db_debug_ver;
+       uint8_t         db_nbkpts;
+       uint8_t         db_nwtpts;
+       uint8_t         db_pad[5];
 
        struct {
                uint64_t dbr_addr;
                uint32_t dbr_ctrl;
                uint32_t dbr_pad;
-       } db_regs[16];
+       } db_breakregs[16];
+       struct {
+               uint64_t dbw_addr;
+               uint32_t dbw_ctrl;
+               uint32_t dbw_pad;
+       } db_watchregs[16];
 };
 
 struct dbreg32 {
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to