/** Clear VCR and all breakpoints and watchpoints via scan chain 7 * * \param arm11 Target state variable. * */ void arm11_sc7_clear_vbw(arm11_common_t * arm11) { arm11_sc7_action_t clear_bw[arm11->brp + arm11->wrp + 1]; arm11_sc7_action_t * pos = clear_bw; {size_t i; for (i = 0; i < asizeof(clear_bw); i++) { clear_bw[i].write = true; clear_bw[i].value = 0; }} {size_t i; for (i = 0; i < arm11->brp; i++) (pos++)->address = ARM11_SC7_BCR0 + i; } {size_t i; for (i = 0; i < arm11->wrp; i++) (pos++)->address = ARM11_SC7_WCR0 + i; } (pos++)->address = ARM11_SC7_VCR; arm11_sc7_run(arm11, clear_bw, asizeof(clear_bw)); }
/** Write VCR register * * \param arm11 Target state variable. * \param value Value to be written */ void arm11_sc7_set_vcr(struct arm11_common * arm11, uint32_t value) { struct arm11_sc7_action set_vcr; set_vcr.write = true; set_vcr.address = ARM11_SC7_VCR; set_vcr.value = value; arm11_sc7_run(arm11, &set_vcr, 1); }
/** Write VCR register * * \param arm11 Target state variable. * \param value Value to be written */ void arm11_sc7_set_vcr(arm11_common_t * arm11, u32 value) { arm11_sc7_action_t set_vcr; set_vcr.write = true; set_vcr.address = ARM11_SC7_VCR; set_vcr.value = value; arm11_sc7_run(arm11, &set_vcr, 1); }
/** 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; }
/** Clear VCR and all breakpoints and watchpoints via scan chain 7 * * \param arm11 Target state variable. * */ void arm11_sc7_clear_vbw(struct arm11_common * arm11) { 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; for (size_t i = 0; i < clear_bw_size; i++) { clear_bw[i].write = true; clear_bw[i].value = 0; } for (size_t i = 0; i < arm11->brp; i++) (pos++)->address = ARM11_SC7_BCR0 + i; (pos++)->address = ARM11_SC7_VCR; arm11_sc7_run(arm11, clear_bw, clear_bw_size); free (clear_bw); }
static int arm11_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } struct arm11_common *arm11 = target_to_arm11(target); address = arm11_nextpc(arm11, current, address); LOG_DEBUG("STEP PC %08" PRIx32 "%s", address, !current ? "!" : ""); /** \todo TODO: Thumb not supported here */ uint32_t next_instruction; CHECK_RETVAL(arm11_read_memory_word(arm11, address, &next_instruction)); /* skip over BKPT */ if ((next_instruction & 0xFFF00070) == 0xe1200070) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping BKPT"); } /* skip over Wait for interrupt / Standby */ /* mcr 15, 0, r?, cr7, cr0, {4} */ else if ((next_instruction & 0xFFFF0FFF) == 0xee070f90) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping WFI"); } /* ignore B to self */ else if ((next_instruction & 0xFEFFFFFF) == 0xeafffffe) { LOG_DEBUG("Not stepping jump to self"); } else { /** \todo TODO: check if break-/watchpoints make any sense at all in combination * with this. */ /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively * the VCR might be something worth looking into. */ /* Set up breakpoint for stepping */ struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0; if (arm11->hardware_step) { /* Hardware single stepping ("instruction address * mismatch") is used if enabled. It's not quite * exactly "run one instruction"; "branch to here" * loops won't break, neither will some other cases, * but it's probably the best default. * * Hardware single stepping isn't supported on v6 * debug modules. ARM1176 and v7 can support it... * * FIXME Thumb stepping likely needs to use 0x03 * or 0xc0 byte masks, not 0x0f. */ brp[0].value = address; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); } else { /* Sets a breakpoint on the next PC, as calculated * by instruction set simulation. * * REVISIT stepping Thumb on ARM1156 requires Thumb2 * support from the simulator. */ uint32_t next_pc; int retval; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) return retval; brp[0].value = next_pc; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); } CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); /* resume */ if (arm11->step_irq_enable) /* this disable should be redundant ... */ arm11->dscr &= ~DSCR_INT_DIS; else arm11->dscr |= DSCR_INT_DIS; CHECK_RETVAL(arm11_leave_debug_state(arm11, handle_breakpoints)); arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); /* wait for halt */ int i = 0; while (1) { const uint32_t mask = DSCR_CORE_RESTARTED | DSCR_CORE_HALTED; CHECK_RETVAL(arm11_read_DSCR(arm11)); LOG_DEBUG("DSCR %08x e", (unsigned) arm11->dscr); if ((arm11->dscr & mask) == mask) break; long long then = 0; if (i == 1000) { then = timeval_ms(); } if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } /* clear breakpoint */ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); /* save state */ CHECK_RETVAL(arm11_debug_entry(arm11)); /* restore default state */ arm11->dscr &= ~DSCR_INT_DIS; } target->debug_reason = DBG_REASON_SINGLESTEP; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); return ERROR_OK; }
static int arm11_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { // LOG_DEBUG("current %d address %08x handle_breakpoints %d debug_execution %d", // current, address, handle_breakpoints, debug_execution); struct arm11_common *arm11 = target_to_arm11(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } address = arm11_nextpc(arm11, current, address); LOG_DEBUG("RESUME PC %08" PRIx32 "%s", address, !current ? "!" : ""); /* clear breakpoints/watchpoints and VCR*/ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); if (!debug_execution) target_free_all_working_areas(target); /* Should we skip over breakpoints matching the PC? */ if (handle_breakpoints) { struct breakpoint *bp; for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { LOG_DEBUG("must step over %08" PRIx32 "", bp->address); arm11_step(target, 1, 0, 0); break; } } } /* activate all breakpoints */ if (true) { struct breakpoint *bp; unsigned brp_num = 0; for (bp = target->breakpoints; bp; bp = bp->next) { struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0 + brp_num; brp[0].value = bp->address; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0 + brp_num; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); LOG_DEBUG("Add BP %d at %08" PRIx32, brp_num, bp->address); brp_num++; } if (arm11->vcr) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr)); } /* activate all watchpoints and breakpoints */ CHECK_RETVAL(arm11_leave_debug_state(arm11, true)); arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { CHECK_RETVAL(arm11_read_DSCR(arm11)); LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); if (arm11->dscr & DSCR_CORE_RESTARTED) break; long long then = 0; if (i == 1000) { then = timeval_ms(); } if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) target->state = TARGET_RUNNING; else target->state = TARGET_DEBUG_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); return ERROR_OK; }