Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148925497
D4338.id10647.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D4338.id10647.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 22, 1:50 AM (15 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30083440
Default Alt Text
D4338.id10647.diff (8 KB)
Attached To
Mode
D4338: SMP support for ARMv6/v7 HW watchpoints
Attached
Detach File
Event Timeline
Log In to Comment