Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 3 Nov 2019 15:42:08 +0000 (UTC)
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r354285 - in head/sys/arm64: arm64 include
Message-ID:  <201911031542.xA3Fg8pq061983@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911031542.xA3Fg8pq061983>