Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/machdep.c
Show First 20 Lines • Show All 315 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
fill_dbregs(struct thread *td, struct dbreg *regs) | fill_dbregs(struct thread *td, struct dbreg *regs) | ||||
{ | { | ||||
struct debug_monitor_state *monitor; | struct debug_monitor_state *monitor; | ||||
int count, i; | int i; | ||||
uint8_t debug_ver, nbkpts; | uint8_t debug_ver, nbkpts, nwtpts; | ||||
memset(regs, 0, sizeof(*regs)); | memset(regs, 0, sizeof(*regs)); | ||||
extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_DebugVer_SHIFT, | extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_DebugVer_SHIFT, | ||||
&debug_ver); | &debug_ver); | ||||
extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_BRPs_SHIFT, | extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_BRPs_SHIFT, | ||||
&nbkpts); | &nbkpts); | ||||
extract_user_id_field(ID_AA64DFR0_EL1, ID_AA64DFR0_WRPs_SHIFT, | |||||
&nwtpts); | |||||
/* | /* | ||||
* The BRPs field contains the number of breakpoints - 1. Armv8-A | * The BRPs field contains the number of breakpoints - 1. Armv8-A | ||||
* allows the hardware to provide 2-16 breakpoints so this won't | * allows the hardware to provide 2-16 breakpoints so this won't | ||||
* overflow an 8 bit value. | * overflow an 8 bit value. The same applies to the WRPs field. | ||||
*/ | */ | ||||
count = nbkpts + 1; | nbkpts++; | ||||
nwtpts++; | |||||
regs->db_info = debug_ver; | regs->db_debug_ver = debug_ver; | ||||
regs->db_info <<= 8; | regs->db_nbkpts = nbkpts; | ||||
regs->db_info |= count; | regs->db_nwtpts = nwtpts; | ||||
monitor = &td->td_pcb->pcb_dbg_regs; | monitor = &td->td_pcb->pcb_dbg_regs; | ||||
if ((monitor->dbg_flags & DBGMON_ENABLED) != 0) { | if ((monitor->dbg_flags & DBGMON_ENABLED) != 0) { | ||||
for (i = 0; i < count; i++) { | for (i = 0; i < nbkpts; i++) { | ||||
regs->db_regs[i].dbr_addr = monitor->dbg_bvr[i]; | regs->db_breakregs[i].dbr_addr = monitor->dbg_bvr[i]; | ||||
regs->db_regs[i].dbr_ctrl = monitor->dbg_bcr[i]; | regs->db_breakregs[i].dbr_ctrl = monitor->dbg_bcr[i]; | ||||
} | } | ||||
for (i = 0; i < nwtpts; i++) { | |||||
regs->db_watchregs[i].dbw_addr = monitor->dbg_wvr[i]; | |||||
regs->db_watchregs[i].dbw_ctrl = monitor->dbg_wcr[i]; | |||||
} | } | ||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
set_dbregs(struct thread *td, struct dbreg *regs) | set_dbregs(struct thread *td, struct dbreg *regs) | ||||
{ | { | ||||
struct debug_monitor_state *monitor; | struct debug_monitor_state *monitor; | ||||
uint64_t addr; | uint64_t addr; | ||||
uint32_t ctrl; | uint32_t ctrl; | ||||
int count; | int count; | ||||
int i; | int i; | ||||
monitor = &td->td_pcb->pcb_dbg_regs; | monitor = &td->td_pcb->pcb_dbg_regs; | ||||
count = 0; | count = 0; | ||||
monitor->dbg_enable_count = 0; | monitor->dbg_enable_count = 0; | ||||
for (i = 0; i < DBG_BRP_MAX; i++) { | for (i = 0; i < DBG_BRP_MAX; i++) { | ||||
addr = regs->db_regs[i].dbr_addr; | addr = regs->db_breakregs[i].dbr_addr; | ||||
ctrl = regs->db_regs[i].dbr_ctrl; | ctrl = regs->db_breakregs[i].dbr_ctrl; | ||||
/* Don't let the user set a breakpoint on a kernel address. */ | /* Don't let the user set a breakpoint on a kernel address. */ | ||||
if (addr >= VM_MAXUSER_ADDRESS) | if (addr >= VM_MAXUSER_ADDRESS) | ||||
return (EINVAL); | return (EINVAL); | ||||
/* | /* | ||||
* The lowest 2 bits are ignored, so record the effective | * The lowest 2 bits are ignored, so record the effective | ||||
* address. | * address. | ||||
Show All 15 Lines | if ((ctrl & DBG_BCR_EN) != 0) { | ||||
return (EINVAL); | return (EINVAL); | ||||
monitor->dbg_enable_count++; | monitor->dbg_enable_count++; | ||||
} | } | ||||
monitor->dbg_bvr[i] = addr; | monitor->dbg_bvr[i] = addr; | ||||
monitor->dbg_bcr[i] = ctrl; | monitor->dbg_bcr[i] = ctrl; | ||||
} | } | ||||
for (i = 0; i < DBG_WRP_MAX; i++) { | |||||
addr = regs->db_watchregs[i].dbw_addr; | |||||
ctrl = regs->db_watchregs[i].dbw_ctrl; | |||||
/* Don't let the user set a watchpoint on a kernel address. */ | |||||
if (addr >= VM_MAXUSER_ADDRESS) | |||||
return (EINVAL); | |||||
/* | |||||
* Some control fields are ignored, and other bits reserved. | |||||
* Only unlinked watchpoints are supported. | |||||
*/ | |||||
ctrl &= DBG_WCR_EN | DBG_WCR_PAC | DBG_WCR_LSC | DBG_WCR_BAS | | |||||
DBG_WCR_MASK; | |||||
if ((ctrl & DBG_WCR_EN) != 0) { | |||||
/* Only target EL0. */ | |||||
if ((ctrl & DBG_WCR_PAC) != DBG_WCR_PAC_EL0) | |||||
return (EINVAL); | |||||
/* Must set at least one of the load/store bits. */ | |||||
if ((ctrl & DBG_WCR_LSC) == 0) | |||||
return (EINVAL); | |||||
/* | |||||
* When specifying the address range with BAS, the MASK | |||||
* field must be zero. | |||||
*/ | |||||
if ((ctrl & DBG_WCR_BAS) != DBG_WCR_BAS_MASK && | |||||
(ctrl & DBG_WCR_MASK) != 0) | |||||
return (EINVAL); | |||||
monitor->dbg_enable_count++; | |||||
} | |||||
monitor->dbg_wvr[i] = addr; | |||||
monitor->dbg_wcr[i] = ctrl; | |||||
} | |||||
if (monitor->dbg_enable_count > 0) | if (monitor->dbg_enable_count > 0) | ||||
monitor->dbg_flags |= DBGMON_ENABLED; | monitor->dbg_flags |= DBGMON_ENABLED; | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
int | int | ||||
▲ Show 20 Lines • Show All 1,005 Lines • Show Last 20 Lines |