diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | src/target/arm11.c | 3 | ||||
-rw-r--r-- | src/target/arm11.h | 3 | ||||
-rw-r--r-- | src/target/arm11_dbgtap.c | 102 | ||||
-rw-r--r-- | src/target/arm11_dbgtap.h | 1 |
5 files changed, 102 insertions, 9 deletions
@@ -24,10 +24,12 @@ Target Layer: - accelerated GDB memory checksum - support "arm regs" command - can access all core modes and registers + - watchpoint support Cortex-A8 - support "arm regs" command - can access all core modes and registers - supports "reset-assert" event (used on OMAP3530) + - watchpoint support Cortex-M3 - Exposed DWT registers like cycle counter diff --git a/src/target/arm11.c b/src/target/arm11.c index b05ef302..943ab8ae 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -286,6 +286,8 @@ static int arm11_leave_debug_state(struct arm11_common *arm11, bool bpwp) */ retval = arm_dpm_write_dirty_registers(&arm11->dpm, bpwp); + retval = arm11_bpwp_flush(arm11); + register_cache_invalidate(arm11->arm.core_cache); /* restore DSCR */ @@ -1212,7 +1214,6 @@ static int arm11_examine(struct target *target) } arm11->brp = ((didr >> 24) & 0x0F) + 1; - arm11->wrp = ((didr >> 28) & 0x0F) + 1; /** \todo TODO: reserve one brp slot if we allow breakpoints during step */ arm11->free_brps = arm11->brp; diff --git a/src/target/arm11.h b/src/target/arm11.h index f3f0644b..421f8d18 100644 --- a/src/target/arm11.h +++ b/src/target/arm11.h @@ -53,9 +53,10 @@ struct arm11_common /** Debug module state. */ struct arm_dpm dpm; + struct arm11_sc7_action *bpwp_actions; + unsigned bpwp_n; size_t brp; /**< Number of Breakpoint Register Pairs from DIDR */ - size_t wrp; /**< Number of Watchpoint Register Pairs from DIDR */ size_t free_brps; /**< Number of breakpoints allocated */ uint32_t dscr; /**< Last retrieved DSCR value. */ diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index e37ad56c..9ad56622 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -892,7 +892,7 @@ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions */ void arm11_sc7_clear_vbw(struct arm11_common * arm11) { - size_t clear_bw_size = arm11->brp + arm11->wrp + 1; + size_t clear_bw_size = arm11->brp + 1; struct arm11_sc7_action *clear_bw = malloc(sizeof(struct arm11_sc7_action) * clear_bw_size); struct arm11_sc7_action * pos = clear_bw; @@ -905,11 +905,6 @@ void arm11_sc7_clear_vbw(struct arm11_common * arm11) for (size_t i = 0; i < arm11->brp; i++) (pos++)->address = ARM11_SC7_BCR0 + i; - - for (size_t i = 0; i < arm11->wrp; i++) - (pos++)->address = ARM11_SC7_WCR0 + i; - - (pos++)->address = ARM11_SC7_VCR; arm11_sc7_run(arm11, clear_bw, clear_bw_size); @@ -1013,6 +1008,88 @@ static int arm11_dpm_instr_read_data_r0(struct arm_dpm *dpm, opcode, data); } +/* Because arm11_sc7_run() takes a vector of actions, we batch breakpoint + * and watchpoint operations instead of running them right away. Since we + * pre-allocated our vector, we don't need to worry about space. + */ +static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned index, + uint32_t addr, uint32_t control) +{ + struct arm11_common *arm11 = dpm_to_arm11(dpm); + struct arm11_sc7_action *action; + + action = arm11->bpwp_actions + arm11->bpwp_n; + + /* Invariant: this bp/wp is disabled. + * It also happens that the core is halted here, but for + * DPM-based cores we don't actually care about that. + */ + + action[0].write = action[1].write = true; + + action[0].value = addr; + action[1].value = control; + + switch (index) { + case 0 ... 15: + action[0].address = ARM11_SC7_BVR0 + index; + action[1].address = ARM11_SC7_BCR0 + index; + break; + case 16 ... 32: + index -= 16; + action[0].address = ARM11_SC7_WVR0 + index; + action[1].address = ARM11_SC7_WCR0 + index; + break; + default: + return ERROR_FAIL; + } + + arm11->bpwp_n += 2; + + return ERROR_OK; +} + +static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned index) +{ + struct arm11_common *arm11 = dpm_to_arm11(dpm); + struct arm11_sc7_action *action; + + action = arm11->bpwp_actions + arm11->bpwp_n; + + action[0].write = true; + action[0].value = 0; + + switch (index) { + case 0 ... 15: + action[0].address = ARM11_SC7_BCR0 + index; + break; + case 16 ... 32: + index -= 16; + action[0].address = ARM11_SC7_WCR0 + index; + break; + default: + return ERROR_FAIL; + } + + arm11->bpwp_n += 1; + + return ERROR_OK; +} + +/** Flush any pending breakpoint and watchpoint updates. */ +int arm11_bpwp_flush(struct arm11_common *arm11) +{ + int retval; + + if (!arm11->bpwp_n) + return ERROR_OK; + + retval = arm11_sc7_run(arm11, arm11->bpwp_actions, arm11->bpwp_n); + arm11->bpwp_n = 0; + + return retval; +} + /** Set up high-level debug module utilities */ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) { @@ -1032,11 +1109,22 @@ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) dpm->instr_read_data_dcc = arm11_dpm_instr_read_data_dcc; dpm->instr_read_data_r0 = arm11_dpm_instr_read_data_r0; + dpm->bpwp_enable = arm11_bpwp_enable; + dpm->bpwp_disable = arm11_bpwp_disable; + retval = arm_dpm_setup(dpm); if (retval != ERROR_OK) return retval; + /* alloc enough to enable all breakpoints and watchpoints at once */ + arm11->bpwp_actions = calloc(2 * (dpm->nbp + dpm->nwp), + sizeof *arm11->bpwp_actions); + if (!arm11->bpwp_actions) + return ERROR_FAIL; + retval = arm_dpm_initialize(dpm); + if (retval != ERROR_OK) + return retval; - return retval; + return arm11_bpwp_flush(arm11); } diff --git a/src/target/arm11_dbgtap.h b/src/target/arm11_dbgtap.h index 2c586cc9..3139a09a 100644 --- a/src/target/arm11_dbgtap.h +++ b/src/target/arm11_dbgtap.h @@ -59,5 +59,6 @@ int arm11_read_memory_word(struct arm11_common *arm11, uint32_t address, uint32_t *result); int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr); +int arm11_bpwp_flush(struct arm11_common *arm11); #endif // ARM11_DBGTAP_H |