Index: head/sys/arm64/arm64/debug_monitor.c =================================================================== --- head/sys/arm64/arm64/debug_monitor.c +++ head/sys/arm64/arm64/debug_monitor.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,10 @@ .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_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(); + } } Index: head/sys/arm64/arm64/exception.S =================================================================== --- head/sys/arm64/arm64/exception.S +++ head/sys/arm64/arm64/exception.S @@ -73,6 +73,9 @@ 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 @@ 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 Index: head/sys/arm64/arm64/identcpu.c =================================================================== --- head/sys/arm64/arm64/identcpu.c +++ head/sys/arm64/arm64/identcpu.c @@ -320,7 +320,7 @@ 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), Index: head/sys/arm64/arm64/machdep.c =================================================================== --- head/sys/arm64/arm64/machdep.c +++ head/sys/arm64/arm64/machdep.c @@ -281,17 +281,60 @@ 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 Index: head/sys/arm64/arm64/trap.c =================================================================== --- head/sys/arm64/arm64/trap.c +++ head/sys/arm64/arm64/trap.c @@ -482,6 +482,7 @@ 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); Index: head/sys/arm64/include/armreg.h =================================================================== --- head/sys/arm64/include/armreg.h +++ head/sys/arm64/include/armreg.h @@ -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 */ Index: head/sys/arm64/include/pcb.h =================================================================== --- head/sys/arm64/include/pcb.h +++ head/sys/arm64/include/pcb.h @@ -31,6 +31,7 @@ #ifndef LOCORE +#include #include struct trapframe; @@ -66,6 +67,8 @@ * 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 Index: head/sys/arm64/include/reg.h =================================================================== --- head/sys/arm64/include/reg.h +++ head/sys/arm64/include/reg.h @@ -60,7 +60,14 @@ }; 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 {