svn commit: r354285 - in head/sys/arm64: arm64 include
Andrew Turner
andrew at FreeBSD.org
Sun Nov 3 15:42:10 UTC 2019
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 {
More information about the svn-src-head
mailing list