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>