Author: andrew
Date: Sun Nov  3 15:42:08 2019
New Revision: 354285
URL: https://svnweb.freebsd.org/changeset/base/354285

Log:
  Add support for setting hardware breakpoints from ptrace on arm64.
  
  Implement get/fill_dbregs on arm64. This is used by ptrace with the
  PT_GETDBREGS and PT_SETDBREGS requests. It allows userspace to set hardware
  breakpoints.
  
  The struct dbreg is based on Linux to ease adding hardware breakpoint
  support to debuggers.
  
  Reviewed by:  jhb
  Sponsored by: DARPA, AFRL
  Differential Revision:        https://reviews.freebsd.org/D22195

Modified:
  head/sys/arm64/arm64/debug_monitor.c
  head/sys/arm64/arm64/exception.S
  head/sys/arm64/arm64/identcpu.c
  head/sys/arm64/arm64/machdep.c
  head/sys/arm64/arm64/trap.c
  head/sys/arm64/include/armreg.h
  head/sys/arm64/include/pcb.h
  head/sys/arm64/include/reg.h

Modified: head/sys/arm64/arm64/debug_monitor.c
==============================================================================
--- head/sys/arm64/arm64/debug_monitor.c        Sun Nov  3 14:36:16 2019        
(r354284)
+++ head/sys/arm64/arm64/debug_monitor.c        Sun Nov  3 15:42:08 2019        
(r354285)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/types.h>
 #include <sys/kdb.h>
 #include <sys/pcpu.h>
+#include <sys/proc.h>
 #include <sys/systm.h>
 
 #include <machine/armreg.h>
@@ -59,6 +60,10 @@ static struct debug_monitor_state kernel_monitor = {
        .dbg_flags = DBGMON_KERNEL
 };
 
+/* Called from the exception handlers */
+void dbg_monitor_enter(struct thread *);
+void dbg_monitor_exit(struct thread *, struct trapframe *);
+
 /* Watchpoints/breakpoints control register bitfields */
 #define DBG_WATCH_CTRL_LEN_1           (0x1 << 5)
 #define DBG_WATCH_CTRL_LEN_2           (0x3 << 5)
@@ -496,4 +501,58 @@ dbg_monitor_init(void)
        }
 
        dbg_enable();
+}
+
+void
+dbg_monitor_enter(struct thread *thread)
+{
+       int i;
+
+       if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
+               /* Install the kernel version of the registers */
+               dbg_register_sync(&kernel_monitor);
+       } else if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 
0) {
+               /* Disable the user breakpoints until we return to userspace */
+               for (i = 0; i < dbg_watchpoint_num; i++) {
+                       dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
+                       dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
+               }
+
+               for (i = 0; i < dbg_breakpoint_num; ++i) {
+                       dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
+                       dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
+               }
+               WRITE_SPECIALREG(mdscr_el1,
+                   READ_SPECIALREG(mdscr_el1) &
+                   ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));
+               isb();
+       }
+}
+
+void
+dbg_monitor_exit(struct thread *thread, struct trapframe *frame)
+{
+       int i;
+
+       frame->tf_spsr |= PSR_D;
+       if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
+               /* Install the kernel version of the registers */
+               dbg_register_sync(&thread->td_pcb->pcb_dbg_regs);
+               frame->tf_spsr &= ~PSR_D;
+       } else if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
+               /* Disable the user breakpoints until we return to userspace */
+               for (i = 0; i < dbg_watchpoint_num; i++) {
+                       dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
+                       dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
+               }
+
+               for (i = 0; i < dbg_breakpoint_num; ++i) {
+                       dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
+                       dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
+               }
+               WRITE_SPECIALREG(mdscr_el1,
+                   READ_SPECIALREG(mdscr_el1) &
+                   ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));
+               isb();
+       }
 }

Modified: head/sys/arm64/arm64/exception.S
==============================================================================
--- head/sys/arm64/arm64/exception.S    Sun Nov  3 14:36:16 2019        
(r354284)
+++ head/sys/arm64/arm64/exception.S    Sun Nov  3 15:42:08 2019        
(r354285)
@@ -73,6 +73,9 @@ __FBSDID("$FreeBSD$");
        mov     w0, #1
        blr     x1
 1:
+
+       ldr     x0, [x18, #(PC_CURTHREAD)]
+       bl      dbg_monitor_enter
 .endif
        msr     daifclr, #8     /* Enable the debug exception */
 .endm
@@ -87,6 +90,10 @@ __FBSDID("$FreeBSD$");
        msr     daifset, #10
 .endif
 .if \el == 0
+       ldr     x0, [x18, #PC_CURTHREAD]
+       mov     x1, sp
+       bl      dbg_monitor_exit
+
        /* Remove the SSBD (CVE-2018-3639) workaround if needed */
        ldr     x1, [x18, #PC_SSBD]
        cbz     x1, 1f

Modified: head/sys/arm64/arm64/identcpu.c
==============================================================================
--- head/sys/arm64/arm64/identcpu.c     Sun Nov  3 14:36:16 2019        
(r354284)
+++ head/sys/arm64/arm64/identcpu.c     Sun Nov  3 15:42:08 2019        
(r354285)
@@ -320,7 +320,7 @@ static struct mrs_field id_aa64dfr0_fields[] = {
        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, BRPs, false, MRS_EXACT, id_aa64dfr0_brps),
+       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,
            id_aa64dfr0_tracever),

Modified: head/sys/arm64/arm64/machdep.c
==============================================================================
--- head/sys/arm64/arm64/machdep.c      Sun Nov  3 14:36:16 2019        
(r354284)
+++ head/sys/arm64/arm64/machdep.c      Sun Nov  3 15:42:08 2019        
(r354285)
@@ -281,17 +281,60 @@ set_fpregs(struct thread *td, struct fpreg *regs)
 int
 fill_dbregs(struct thread *td, struct dbreg *regs)
 {
+       struct debug_monitor_state *monitor;
+       int count, i;
+       uint8_t debug_ver, nbkpts;
 
-       printf("ARM64TODO: fill_dbregs");
-       return (EDOOFUS);
+       memset(regs, 0, sizeof(*regs));
+
+       extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_DebugVer_SHIFT,
+           &debug_ver);
+       extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_BRPs_SHIFT,
+           &nbkpts);
+
+       /*
+        * 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.
+        */
+       count = nbkpts + 1;
+
+       regs->db_info = debug_ver;
+       regs->db_info <<= 8;
+       regs->db_info |= count;
+
+       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];
+               }
+       }
+
+       return (0);
 }
 
 int
 set_dbregs(struct thread *td, struct dbreg *regs)
 {
+       struct debug_monitor_state *monitor;
+       int count;
+       int i;
 
-       printf("ARM64TODO: set_dbregs");
-       return (EDOOFUS);
+       monitor = &td->td_pcb->pcb_dbg_regs;
+       count = 0;
+       monitor->dbg_enable_count = 0;
+       for (i = 0; i < DBG_BRP_MAX; i++) {
+               /* TODO: Check these values */
+               monitor->dbg_bvr[i] = regs->db_regs[i].dbr_addr;
+               monitor->dbg_bcr[i] = regs->db_regs[i].dbr_ctrl;
+               if ((monitor->dbg_bcr[i] & 1) != 0)
+                       monitor->dbg_enable_count++;
+       }
+       if (monitor->dbg_enable_count > 0)
+               monitor->dbg_flags |= DBGMON_ENABLED;
+
+       return (0);
 }
 
 #ifdef COMPAT_FREEBSD32

Modified: head/sys/arm64/arm64/trap.c
==============================================================================
--- head/sys/arm64/arm64/trap.c Sun Nov  3 14:36:16 2019        (r354284)
+++ head/sys/arm64/arm64/trap.c Sun Nov  3 15:42:08 2019        (r354285)
@@ -482,6 +482,7 @@ do_el0_sync(struct thread *td, struct trapframe *frame
                call_trapsignal(td, SIGBUS, BUS_ADRALN, (void *)frame->tf_elr);
                userret(td, frame);
                break;
+       case EXCP_BRKPT_EL0:
        case EXCP_BRK:
                call_trapsignal(td, SIGTRAP, TRAP_BRKPT, (void *)frame->tf_elr);
                userret(td, frame);

Modified: head/sys/arm64/include/armreg.h
==============================================================================
--- head/sys/arm64/include/armreg.h     Sun Nov  3 14:36:16 2019        
(r354284)
+++ head/sys/arm64/include/armreg.h     Sun Nov  3 15:42:08 2019        
(r354285)
@@ -163,6 +163,7 @@
 #define         EXCP_SP_ALIGN          0x26    /* SP slignment fault */
 #define         EXCP_TRAP_FP           0x2c    /* Trapped FP exception */
 #define         EXCP_SERROR            0x2f    /* SError interrupt */
+#define         EXCP_BRKPT_EL0         0x30    /* Hardware breakpoint, from 
same EL */
 #define         EXCP_SOFTSTP_EL0       0x32    /* Software Step, from lower EL 
*/
 #define         EXCP_SOFTSTP_EL1       0x33    /* Software Step, from same EL 
*/
 #define         EXCP_WATCHPT_EL1       0x35    /* Watchpoint, from same EL */

Modified: head/sys/arm64/include/pcb.h
==============================================================================
--- head/sys/arm64/include/pcb.h        Sun Nov  3 14:36:16 2019        
(r354284)
+++ head/sys/arm64/include/pcb.h        Sun Nov  3 15:42:08 2019        
(r354285)
@@ -31,6 +31,7 @@
 
 #ifndef LOCORE
 
+#include <machine/debug_monitor.h>
 #include <machine/vfp.h>
 
 struct trapframe;
@@ -66,6 +67,8 @@ struct pcb {
         * Place last to simplify the asm to access the rest if the struct.
         */
        struct vfpstate pcb_fpustate;
+
+       struct debug_monitor_state pcb_dbg_regs;
 };
 
 #ifdef _KERNEL

Modified: head/sys/arm64/include/reg.h
==============================================================================
--- head/sys/arm64/include/reg.h        Sun Nov  3 14:36:16 2019        
(r354284)
+++ head/sys/arm64/include/reg.h        Sun Nov  3 15:42:08 2019        
(r354285)
@@ -60,7 +60,14 @@ struct fpreg32 {
 };
 
 struct dbreg {
-       int dummy;
+       uint32_t        db_info;
+       uint32_t        db_pad;
+
+       struct {
+               uint64_t dbr_addr;
+               uint32_t dbr_ctrl;
+               uint32_t dbr_pad;
+       } db_regs[16];
 };
 
 struct dbreg32 {
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to