Page MenuHomeFreeBSD

D4338.id10647.diff
No OneTemporary

D4338.id10647.diff

Index: sys/arm/arm/debug_monitor.c
===================================================================
--- sys/arm/arm/debug_monitor.c
+++ sys/arm/arm/debug_monitor.c
@@ -35,6 +35,7 @@
#include <sys/types.h>
#include <sys/kdb.h>
#include <sys/pcpu.h>
+#include <sys/smp.h>
#include <sys/systm.h>
#include <machine/armreg.h>
@@ -43,6 +44,7 @@
#include <machine/kdb.h>
#include <machine/param.h>
#include <machine/pcb.h>
+#include <machine/reg.h>
#include <ddb/ddb.h>
#include <ddb/db_access.h>
@@ -80,7 +82,7 @@
static uint32_t dbg_watchpoint_num;
static uint32_t dbg_breakpoint_num;
-static int dbg_ref_count_mme[MAXCPU]; /* Times monitor mode was enabled */
+static int dbg_ref_count_mme; /* Times monitor mode was enabled */
/* ID_DFR0 - Debug Feature Register 0 */
#define ID_DFR0_CP_DEBUG_M_SHIFT 0
@@ -542,11 +544,9 @@
{
uint32_t dbg_dscr;
- /* Already enabled? Just increment reference counter and return */
- if (dbg_monitor_is_enabled()) {
- dbg_ref_count_mme[PCPU_GET(cpuid)]++;
+ /* Already enabled? Just return */
+ if (dbg_monitor_is_enabled())
return (0);
- }
dbg_dscr = cp14_dbgdscrint_get();
@@ -565,10 +565,8 @@
isb();
/* Verify that Monitor mode is set */
- if (dbg_monitor_is_enabled()) {
- dbg_ref_count_mme[PCPU_GET(cpuid)]++;
+ if (dbg_monitor_is_enabled())
return (0);
- }
return (ENXIO);
}
@@ -581,9 +579,6 @@
if (!dbg_monitor_is_enabled())
return (0);
- if (--dbg_ref_count_mme[PCPU_GET(cpuid)] > 0)
- return (0);
-
dbg_dscr = cp14_dbgdscrint_get();
switch (dbg_model) {
case ID_DFR0_CP_DEBUG_M_V6:
@@ -607,11 +602,13 @@
static int
dbg_setup_xpoint(struct dbg_wb_conf *conf)
{
+ struct pcpu *pcpu;
+ struct dbreg *d;
const char *typestr;
uint32_t cr_size, cr_priv, cr_access;
uint32_t reg_ctrl, reg_addr, ctrl, addr;
boolean_t is_bkpt;
- u_int cpuid;
+ u_int cpuid, cpu;
u_int i;
int err;
@@ -705,20 +702,53 @@
dbg_wb_write_reg(reg_addr, i, addr);
dbg_wb_write_reg(reg_ctrl, i, ctrl);
- return (dbg_enable_monitor());
+ err = dbg_enable_monitor();
+ if (err != 0)
+ return (err);
+
+ rmb();
+ /* Increment monitor enable counter */
+ dbg_ref_count_mme++;
+
+ /*
+ * Save watchpoint settings for all CPUs.
+ * We don't need to do the same with breakpoints since HW breakpoints
+ * are only used to perform single stepping.
+ */
+ if (!is_bkpt) {
+ CPU_FOREACH(cpu) {
+ pcpu = pcpu_find(cpu);
+ /* Fill out the settings for watchpoint */
+ d = (struct dbreg *)pcpu->pc_dbreg;
+ d->dbg_wvr[i] = addr;
+ d->dbg_wcr[i] = ctrl;
+ /* Skip update command for the current CPU */
+ if (cpu != cpuid)
+ pcpu->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
+ }
+ }
+ /* Ensure all data is written before waking other CPUs */
+ wmb();
+
+ return (0);
}
static int
dbg_remove_xpoint(struct dbg_wb_conf *conf)
{
+ struct pcpu *pcpu;
+ struct dbreg *d;
uint32_t reg_ctrl, reg_addr, addr;
- u_int cpuid;
+ boolean_t is_bkpt;
+ u_int cpuid, cpu;
u_int i;
int err;
if (!dbg_capable)
return (ENXIO);
+ is_bkpt = (conf->type == DBG_TYPE_BREAKPOINT);
+
cpuid = PCPU_GET(cpuid);
if (!dbg_ready[cpuid]) {
err = dbg_reset_state();
@@ -729,7 +759,7 @@
addr = conf->address;
- if (conf->type == DBG_TYPE_BREAKPOINT) {
+ if (is_bkpt) {
i = conf->slot;
reg_ctrl = DBG_REG_BASE_BCR;
reg_addr = DBG_REG_BASE_BVR;
@@ -746,7 +776,40 @@
dbg_wb_write_reg(reg_ctrl, i, 0);
dbg_wb_write_reg(reg_addr, i, 0);
- return (dbg_disable_monitor());
+ rmb();
+ /* Decrement monitor enable counter */
+ dbg_ref_count_mme--;
+ if (dbg_ref_count_mme < 0)
+ dbg_ref_count_mme = 0;
+ wmb();
+
+ if (dbg_ref_count_mme == 0) {
+ err = dbg_disable_monitor();
+ if (err != 0)
+ return (err);
+ }
+
+ /*
+ * Save watchpoint settings for all CPUs.
+ * We don't need to do the same with breakpoints since HW breakpoints
+ * are only used to perform single stepping.
+ */
+ if (!is_bkpt) {
+ CPU_FOREACH(cpu) {
+ pcpu = pcpu_find(cpu);
+ /* Fill out the settings for watchpoint */
+ d = (struct dbreg *)pcpu->pc_dbreg;
+ d->dbg_wvr[i] = 0;
+ d->dbg_wcr[i] = 0;
+ /* Skip update command for the current CPU */
+ if (cpu != cpuid)
+ pcpu->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
+ }
+ /* Ensure all data is written before waking other CPUs */
+ wmb();
+ }
+
+ return (0);
}
static __inline uint32_t
@@ -941,3 +1004,66 @@
db_printf("HW Breakpoints/Watchpoints not enabled on CPU%d\n",
PCPU_GET(cpuid));
}
+
+CTASSERT(sizeof(struct dbreg) == sizeof(((struct pcpu *)NULL)->pc_dbreg));
+
+void
+dbg_resume_dbreg(void)
+{
+ struct dbreg *d;
+ u_int cpuid;
+ u_int i;
+ int err;
+
+ /*
+ * This flag is set on the primary CPU
+ * and its meaning is valid for other CPUs too.
+ */
+ if (!dbg_capable)
+ return;
+
+ rmb();
+ switch (PCPU_GET(dbreg_cmd)) {
+ case PC_DBREG_CMD_LOAD:
+ d = (struct dbreg *)PCPU_PTR(dbreg);
+ cpuid = PCPU_GET(cpuid);
+
+ /* Reset Debug Architecture State if not done earlier */
+ if (!dbg_ready[cpuid]) {
+ err = dbg_reset_state();
+ if (err != 0) {
+ /*
+ * Something is very wrong.
+ * WPs/BPs will not work correctly in this CPU.
+ */
+ panic("%s: Failed to reset Debug Architecture "
+ "state on CPU%d", __func__, cpuid);
+ }
+ dbg_ready[cpuid] = TRUE;
+ }
+
+ /* Restore watchpoints */
+ for (i = 0; i < dbg_watchpoint_num; i++) {
+ dbg_wb_write_reg(DBG_REG_BASE_WVR, i, d->dbg_wvr[i]);
+ dbg_wb_write_reg(DBG_REG_BASE_WCR, i, d->dbg_wcr[i]);
+ }
+
+ if ((dbg_ref_count_mme > 0) && !dbg_monitor_is_enabled()) {
+ err = dbg_enable_monitor();
+ if (err != 0) {
+ panic("%s: Failed to enable Debug Monitor "
+ "on CPU%d", __func__, cpuid);
+ }
+ }
+ if ((dbg_ref_count_mme == 0) && dbg_monitor_is_enabled()) {
+ err = dbg_disable_monitor();
+ if (err != 0) {
+ panic("%s: Failed to disable Debug Monitor "
+ "on CPU%d", __func__, cpuid);
+ }
+ }
+
+ PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE);
+ break;
+ }
+}
Index: sys/arm/arm/mp_machdep.c
===================================================================
--- sys/arm/arm/mp_machdep.c
+++ sys/arm/arm/mp_machdep.c
@@ -25,6 +25,9 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -46,6 +49,7 @@
#include <machine/armreg.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
+#include <machine/debug_monitor.h>
#include <machine/smp.h>
#include <machine/pcb.h>
#include <machine/pmap.h>
@@ -303,6 +307,9 @@
CPU_CLR_ATOMIC(cpu, &started_cpus);
CPU_CLR_ATOMIC(cpu, &stopped_cpus);
+#ifdef DDB
+ dbg_resume_dbreg();
+#endif
CTR0(KTR_SMP, "IPI_STOP (restart)");
}
@@ -405,6 +412,9 @@
CPU_CLR_ATOMIC(cpu, &started_cpus);
CPU_CLR_ATOMIC(cpu, &stopped_cpus);
+#ifdef DDB
+ dbg_resume_dbreg();
+#endif
CTR0(KTR_SMP, "IPI_STOP (restart)");
break;
case IPI_PREEMPT:
Index: sys/arm/include/debug_monitor.h
===================================================================
--- sys/arm/include/debug_monitor.h
+++ sys/arm/include/debug_monitor.h
@@ -48,6 +48,7 @@
void dbg_show_watchpoint(void);
int dbg_setup_watchpoint(db_expr_t, db_expr_t, enum dbg_access_t);
int dbg_remove_watchpoint(db_expr_t, db_expr_t);
+void dbg_resume_dbreg(void);
#else /* __ARM_ARCH >= 6 */
static __inline void
dbg_show_watchpoint(void)
@@ -68,6 +69,11 @@
dbg_monitor_init(void)
{
}
+
+static __inline void
+dbg_resume_dbreg(void)
+{
+}
#endif /* __ARM_ARCH < 6 */
#else /* DDB */
Index: sys/arm/include/pcpu.h
===================================================================
--- sys/arm/include/pcpu.h
+++ sys/arm/include/pcpu.h
@@ -49,7 +49,9 @@
struct pmap *pc_curpmap; \
vm_offset_t pc_qmap_addr; \
void *pc_qmap_pte; \
- char __pad[133]
+ unsigned int pc_dbreg[32]; \
+ int pc_dbreg_cmd; \
+ char __pad[1]
#else
#define PCPU_MD_FIELDS \
vm_offset_t qmap_addr; \
@@ -59,6 +61,9 @@
#ifdef _KERNEL
+#define PC_DBREG_CMD_NONE 0
+#define PC_DBREG_CMD_LOAD 1
+
struct pcb;
struct pcpu;
Index: sys/arm/include/reg.h
===================================================================
--- sys/arm/include/reg.h
+++ sys/arm/include/reg.h
@@ -19,7 +19,9 @@
};
struct dbreg {
- unsigned int dr[8]; /* debug registers */
+#define ARM_WR_MAX 16 /* Maximum number of watchpoint registers */
+ unsigned int dbg_wcr[ARM_WR_MAX]; /* Watchpoint Control Registers */
+ unsigned int dbg_wvr[ARM_WR_MAX]; /* Watchpoint Value Registers */
};
#ifdef _KERNEL

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 21, 5:32 PM (4 h, 33 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30083440
Default Alt Text
D4338.id10647.diff (8 KB)

Event Timeline