X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Fcortex_m3.c;h=7f6cbafa522b3f2ccd062a933bfe9211e2932c50;hb=e7e9bfde47768b22be8b15c30c027dc8fb67c778;hp=bdd323349fbc99cf91b41e2df05c87b2530bb55b;hpb=81aec6be045792f3ed6a2d8fdbf1f534993b5c14;p=openocd.git diff --git a/src/target/cortex_m3.c b/src/target/cortex_m3.c index bdd323349f..7f6cbafa52 100644 --- a/src/target/cortex_m3.c +++ b/src/target/cortex_m3.c @@ -38,10 +38,17 @@ #include "arm_disassembler.h" #include "register.h" #include "arm_opcodes.h" - +#include "arm_semihosting.h" /* NOTE: most of this should work fine for the Cortex-M1 and * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M. + * Some differences: M0/M1 doesn't have FBP remapping or the + * DWT tracing/profiling support. (So the cycle counter will + * not be usable; the other stuff isn't currently used here.) + * + * Although there are some workarounds for errata seen only in r0p0 + * silicon, such old parts are hard to find and thus not much tested + * any longer. */ @@ -52,12 +59,7 @@ static void cortex_m3_enable_watchpoints(struct target *target); static int cortex_m3_store_core_reg_u32(struct target *target, enum armv7m_regtype type, uint32_t num, uint32_t value); -#ifdef ARMV7_GDB_HACKS -extern uint8_t armv7m_gdb_dummy_cpsr_value[]; -extern struct reg armv7m_gdb_dummy_cpsr_reg; -#endif - -static int cortexm3_dap_read_coreregister_u32(struct swjdp_common *swjdp, +static int cortexm3_dap_read_coreregister_u32(struct adiv5_dap *swjdp, uint32_t *value, int regnum) { int retval; @@ -68,17 +70,21 @@ static int cortexm3_dap_read_coreregister_u32(struct swjdp_common *swjdp, mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr); - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - /* mem_ap_write_u32(swjdp, DCB_DCRSR, regnum); */ dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); - dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum); + retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum); + if (retval != ERROR_OK) + return retval; /* mem_ap_read_u32(swjdp, DCB_DCRDR, value); */ dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); - dap_ap_read_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value); + retval = dap_queue_ap_read(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value); + if (retval != ERROR_OK) + return retval; - retval = swjdp_transaction_endcheck(swjdp); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + return retval; /* restore DCB_DCRDR - this needs to be in a seperate * transaction otherwise the emulated DCC channel breaks */ @@ -88,7 +94,7 @@ static int cortexm3_dap_read_coreregister_u32(struct swjdp_common *swjdp, return retval; } -static int cortexm3_dap_write_coreregister_u32(struct swjdp_common *swjdp, +static int cortexm3_dap_write_coreregister_u32(struct adiv5_dap *swjdp, uint32_t value, int regnum) { int retval; @@ -99,17 +105,17 @@ static int cortexm3_dap_write_coreregister_u32(struct swjdp_common *swjdp, mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr); - swjdp->trans_mode = TRANS_MODE_COMPOSITE; - /* mem_ap_write_u32(swjdp, DCB_DCRDR, core_regs[i]); */ dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); - dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value); + retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value); + // XXX check retval /* mem_ap_write_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR); */ dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); - dap_ap_write_reg_u32(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR); + retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR); + // XXX check retval - retval = swjdp_transaction_endcheck(swjdp); + retval = dap_run(swjdp); /* restore DCB_DCRDR - this needs to be in a seperate * transaction otherwise the emulated DCC channel breaks */ @@ -123,7 +129,7 @@ static int cortex_m3_write_debug_halt_mask(struct target *target, uint32_t mask_on, uint32_t mask_off) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; /* mask off status bits */ cortex_m3->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off); @@ -136,13 +142,14 @@ static int cortex_m3_write_debug_halt_mask(struct target *target, static int cortex_m3_clear_halt(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; /* clear step if any */ cortex_m3_write_debug_halt_mask(target, C_HALT, C_STEP); /* Read Debug Fault Status Register */ mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr); + /* Clear Debug Fault Status */ mem_ap_write_atomic_u32(swjdp, NVIC_DFSR, cortex_m3->nvic_dfsr); LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m3->nvic_dfsr); @@ -153,16 +160,21 @@ static int cortex_m3_clear_halt(struct target *target) static int cortex_m3_single_step_core(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; uint32_t dhcsr_save; /* backup dhcsr reg */ dhcsr_save = cortex_m3->dcb_dhcsr; - /* mask interrupts if not done already */ + /* Mask interrupts before clearing halt, if done already. This avoids + * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing + * HALT can put the core into an unknown state. + */ if (!(cortex_m3->dcb_dhcsr & C_MASKINTS)) - mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN); - mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN); + mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, + DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN); + mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, + DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN); LOG_DEBUG(" "); /* restore dhcsr reg */ @@ -175,16 +187,19 @@ static int cortex_m3_single_step_core(struct target *target) static int cortex_m3_endreset_event(struct target *target) { int i; + int retval; uint32_t dcb_demcr; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct armv7m_common *armv7m = &cortex_m3->armv7m; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; struct cortex_m3_fp_comparator *fp_list = cortex_m3->fp_comparator_list; struct cortex_m3_dwt_comparator *dwt_list = cortex_m3->dwt_comparator_list; + /* REVISIT The four debug monitor bits are currently ignored... */ mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &dcb_demcr); LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "",dcb_demcr); - /* this regsiter is used for emulated dcc channel */ + /* this register is used for emulated dcc channel */ mem_ap_write_u32(swjdp, DCB_DCRDR, 0); /* Enable debug requests */ @@ -195,10 +210,18 @@ static int cortex_m3_endreset_event(struct target *target) /* clear any interrupt masking */ cortex_m3_write_debug_halt_mask(target, 0, C_MASKINTS); - /* Enable trace and dwt */ - mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR); - /* Monitor bus faults */ - mem_ap_write_u32(swjdp, NVIC_SHCSR, SHCSR_BUSFAULTENA); + /* Enable features controlled by ITM and DWT blocks, and catch only + * the vectors we were told to pay attention to. + * + * Target firmware is responsible for all fault handling policy + * choices *EXCEPT* explicitly scripted overrides like "vector_catch" + * or manual updates to the NVIC SHCSR and CCR registers. + */ + mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | armv7m->demcr); + + /* Paranoia: evidently some (early?) chips don't preserve all the + * debug state (including FBP, DWT, etc) across reset... + */ /* Enable FPB */ target_write_u32(target, FP_CTRL, 3); @@ -220,14 +243,16 @@ static int cortex_m3_endreset_event(struct target *target) target_write_u32(target, dwt_list[i].dwt_comparator_address + 8, dwt_list[i].function); } - swjdp_transaction_endcheck(swjdp); + retval = dap_run(swjdp); + if (retval != ERROR_OK) + return retval; register_cache_invalidate(cortex_m3->armv7m.core_cache); /* make sure we have latest dhcsr flags */ mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); - return ERROR_OK; + return retval; } static int cortex_m3_examine_debug_reason(struct target *target) @@ -261,7 +286,8 @@ static int cortex_m3_examine_exception_reason(struct target *target) { uint32_t shcsr, except_sr, cfsr = -1, except_ar = -1; struct armv7m_common *armv7m = target_to_armv7m(target); - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; + int retval; mem_ap_read_u32(swjdp, NVIC_SHCSR, &shcsr); switch (armv7m->exception_number) @@ -299,12 +325,33 @@ static int cortex_m3_examine_exception_reason(struct target *target) except_sr = 0; break; } - swjdp_transaction_endcheck(swjdp); - LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32 "", armv7m_exception_string(armv7m->exception_number), \ - shcsr, except_sr, cfsr, except_ar); - return ERROR_OK; + retval = dap_run(swjdp); + if (retval == ERROR_OK) + LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 + ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32, + armv7m_exception_string(armv7m->exception_number), + shcsr, except_sr, cfsr, except_ar); + return retval; } +/* PSP is used in some thread modes */ +static const int armv7m_psp_reg_map[17] = { + ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, + ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, + ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, + ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC, + ARMV7M_xPSR, +}; + +/* MSP is used in handler and some thread modes */ +static const int armv7m_msp_reg_map[17] = { + ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, + ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, + ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, + ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC, + ARMV7M_xPSR, +}; + static int cortex_m3_debug_entry(struct target *target) { int i; @@ -312,7 +359,9 @@ static int cortex_m3_debug_entry(struct target *target) int retval; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct arm *arm = &armv7m->arm; + struct adiv5_dap *swjdp = &armv7m->dap; + struct reg *r; LOG_DEBUG(" "); @@ -332,7 +381,8 @@ static int cortex_m3_debug_entry(struct target *target) armv7m->read_core_reg(target, i); } - xPSR = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32); + r = armv7m->core_cache->reg_list + ARMV7M_xPSR; + xPSR = buf_get_u32(r->value, 0, 32); #ifdef ARMV7_GDB_HACKS /* FIXME this breaks on scan chains with more than one Cortex-M3. @@ -341,14 +391,14 @@ static int cortex_m3_debug_entry(struct target *target) /* copy real xpsr reg for gdb, setting thumb bit */ buf_set_u32(armv7m_gdb_dummy_cpsr_value, 0, 32, xPSR); buf_set_u32(armv7m_gdb_dummy_cpsr_value, 5, 1, 1); - armv7m_gdb_dummy_cpsr_reg.valid = armv7m->core_cache->reg_list[ARMV7M_xPSR].valid; - armv7m_gdb_dummy_cpsr_reg.dirty = armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty; + armv7m_gdb_dummy_cpsr_reg.valid = r->valid; + armv7m_gdb_dummy_cpsr_reg.dirty = r->dirty; #endif /* For IT instructions xPSR must be reloaded on resume and clear on debug exec */ if (xPSR & 0xf00) { - armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = armv7m->core_cache->reg_list[ARMV7M_xPSR].valid; + r->dirty = r->valid; cortex_m3_store_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 16, xPSR &~ 0xff); } @@ -357,10 +407,27 @@ static int cortex_m3_debug_entry(struct target *target) { armv7m->core_mode = ARMV7M_MODE_HANDLER; armv7m->exception_number = (xPSR & 0x1FF); + + arm->core_mode = ARM_MODE_HANDLER; + arm->map = armv7m_msp_reg_map; } else { - armv7m->core_mode = buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1); + unsigned control = buf_get_u32(armv7m->core_cache + ->reg_list[ARMV7M_CONTROL].value, 0, 2); + + /* is this thread privileged? */ + armv7m->core_mode = control & 1; + arm->core_mode = armv7m->core_mode + ? ARM_MODE_USER_THREAD + : ARM_MODE_THREAD; + + /* which stack is it using? */ + if (control & 2) + arm->map = armv7m_psp_reg_map; + else + arm->map = armv7m_msp_reg_map; + armv7m->exception_number = 0; } @@ -371,7 +438,7 @@ static int cortex_m3_debug_entry(struct target *target) LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", target->state: %s", armv7m_mode_strings[armv7m->core_mode], - *(uint32_t*)(armv7m->core_cache->reg_list[15].value), + *(uint32_t*)(arm->pc->value), target_state_name(target)); if (armv7m->post_debug_entry) @@ -385,7 +452,7 @@ static int cortex_m3_poll(struct target *target) int retval; enum target_state prev_target_state = target->state; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; /* Read from Debug Halting Control and Status Register */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); @@ -395,6 +462,21 @@ static int cortex_m3_poll(struct target *target) return retval; } + /* Recover from lockup. See ARMv7-M architecture spec, + * section B1.5.15 "Unrecoverable exception cases". + * + * REVISIT Is there a better way to report and handle this? + */ + if (cortex_m3->dcb_dhcsr & S_LOCKUP) { + LOG_WARNING("%s -- clearing lockup after double fault", + target_name(target)); + cortex_m3_write_debug_halt_mask(target, C_HALT, 0); + target->debug_reason = DBG_REASON_DBGRQ; + + /* refresh status bits */ + mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); + } + if (cortex_m3->dcb_dhcsr & S_RESET_ST) { /* check if still in reset */ @@ -409,8 +491,11 @@ static int cortex_m3_poll(struct target *target) if (target->state == TARGET_RESET) { - /* Cannot switch context while running so endreset is called with target->state == TARGET_RESET */ - LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32 "", cortex_m3->dcb_dhcsr); + /* Cannot switch context while running so endreset is + * called with target->state == TARGET_RESET + */ + LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32, + cortex_m3->dcb_dhcsr); cortex_m3_endreset_event(target); target->state = TARGET_RUNNING; prev_target_state = TARGET_RUNNING; @@ -425,6 +510,9 @@ static int cortex_m3_poll(struct target *target) if ((retval = cortex_m3_debug_entry(target)) != ERROR_OK) return retval; + if (arm_semihosting(target, &retval) != 0) + return retval; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); } if (prev_target_state == TARGET_DEBUG_RUNNING) @@ -499,15 +587,17 @@ static int cortex_m3_halt(struct target *target) static int cortex_m3_soft_reset_halt(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; uint32_t dcb_dhcsr = 0; int retval, timeout = 0; - /* Enter debug state on reset, cf. end_reset_event() */ - mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); + /* Enter debug state on reset; restore DEMCR in endreset_event() */ + mem_ap_write_u32(swjdp, DCB_DEMCR, + TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); - /* Request a reset */ - mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_VECTRESET); + /* Request a core-only reset */ + mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR, + AIRCR_VECTKEY | AIRCR_VECTRESET); target->state = TARGET_RESET; /* registers are now invalid */ @@ -518,15 +608,23 @@ static int cortex_m3_soft_reset_halt(struct target *target) retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr); if (retval == ERROR_OK) { - mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr); - if ((dcb_dhcsr & S_HALT) && (cortex_m3->nvic_dfsr & DFSR_VCATCH)) + mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, + &cortex_m3->nvic_dfsr); + if ((dcb_dhcsr & S_HALT) + && (cortex_m3->nvic_dfsr & DFSR_VCATCH)) { - LOG_DEBUG("system reset-halted, dcb_dhcsr 0x%" PRIx32 ", nvic_dfsr 0x%" PRIx32 "", dcb_dhcsr, cortex_m3->nvic_dfsr); + LOG_DEBUG("system reset-halted, DHCSR 0x%08x, " + "DFSR 0x%08x", + (unsigned) dcb_dhcsr, + (unsigned) cortex_m3->nvic_dfsr); cortex_m3_poll(target); + /* FIXME restore user's vector catch config */ return ERROR_OK; } else - LOG_DEBUG("waiting for system reset-halt, dcb_dhcsr 0x%" PRIx32 ", %i ms", dcb_dhcsr, timeout); + LOG_DEBUG("waiting for system reset-halt, " + "DHCSR 0x%08x, %d ms", + (unsigned) dcb_dhcsr, timeout); } timeout++; alive_sleep(1); @@ -542,7 +640,7 @@ static void cortex_m3_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->set) cortex_m3_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -554,6 +652,7 @@ static int cortex_m3_resume(struct target *target, int current, struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; + struct reg *r; if (target->state != TARGET_HALTED) { @@ -570,30 +669,50 @@ static int cortex_m3_resume(struct target *target, int current, if (debug_execution) { + r = armv7m->core_cache->reg_list + ARMV7M_PRIMASK; + /* Disable interrupts */ - /* We disable interrupts in the PRIMASK register instead of masking with C_MASKINTS, - * This is probably the same issue as Cortex-M3 Errata 377493: - * C_MASKINTS in parallel with disabled interrupts can cause local faults to not be taken. */ - buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_PRIMASK].value, 0, 32, 1); - armv7m->core_cache->reg_list[ARMV7M_PRIMASK].dirty = 1; - armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = 1; + /* We disable interrupts in the PRIMASK register instead of + * masking with C_MASKINTS. This is probably the same issue + * as Cortex-M3 Erratum 377493 (fixed in r1p0): C_MASKINTS + * in parallel with disabled interrupts can cause local faults + * to not be taken. + * + * REVISIT this clearly breaks non-debug execution, since the + * PRIMASK register state isn't saved/restored... workaround + * by never resuming app code after debug execution. + */ + buf_set_u32(r->value, 0, 1, 1); + r->dirty = true; + r->valid = true; /* Make sure we are in Thumb mode */ - buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32, - buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32) | (1 << 24)); - armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = 1; - armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = 1; + r = armv7m->core_cache->reg_list + ARMV7M_xPSR; + buf_set_u32(r->value, 24, 1, 1); + r->dirty = true; + r->valid = true; } /* current = 1: continue on current pc, otherwise continue at
*/ + r = armv7m->arm.pc; if (!current) { - buf_set_u32(armv7m->core_cache->reg_list[15].value, 0, 32, address); - armv7m->core_cache->reg_list[15].dirty = 1; - armv7m->core_cache->reg_list[15].valid = 1; + buf_set_u32(r->value, 0, 32, address); + r->dirty = true; + r->valid = true; + } + + /* if we halted last time due to a bkpt instruction + * then we have to manually step over it, otherwise + * the core will break again */ + + if (!breakpoint_find(target, buf_get_u32(r->value, 0, 32)) + && !debug_execution) + { + armv7m_maybe_skip_bkpt_inst(target, NULL); } - resume_pc = buf_get_u32(armv7m->core_cache->reg_list[15].value, 0, 32); + resume_pc = buf_get_u32(r->value, 0, 32); armv7m_restore_context(target); @@ -642,8 +761,10 @@ static int cortex_m3_step(struct target *target, int current, { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; struct breakpoint *breakpoint = NULL; + struct reg *pc = armv7m->arm.pc; + bool bkpt_inst_found = false; if (target->state != TARGET_HALTED) { @@ -653,25 +774,33 @@ static int cortex_m3_step(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) - buf_set_u32(cortex_m3->armv7m.core_cache->reg_list[15].value, - 0, 32, address); + buf_set_u32(pc->value, 0, 32, address); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { - breakpoint = breakpoint_find(target, buf_get_u32(armv7m - ->core_cache->reg_list[15].value, 0, 32)); + breakpoint = breakpoint_find(target, + buf_get_u32(pc->value, 0, 32)); if (breakpoint) cortex_m3_unset_breakpoint(target, breakpoint); } + armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found); + target->debug_reason = DBG_REASON_SINGLESTEP; armv7m_restore_context(target); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - /* set step and clear halt */ - cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT); + /* if no bkpt instruction is found at pc then we can perform + * a normal step, otherwise we have to manually step over the bkpt + * instruction - as such simulate a step */ + if (bkpt_inst_found == false) + { + /* set step and clear halt */ + cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT); + } + mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); /* registers are now invalid */ @@ -680,19 +809,24 @@ static int cortex_m3_step(struct target *target, int current, if (breakpoint) cortex_m3_set_breakpoint(target, breakpoint); - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32 "", cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr); + LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + " nvic_icsr = 0x%" PRIx32, + cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr); cortex_m3_debug_entry(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32 "", cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr); + LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + " nvic_icsr = 0x%" PRIx32, + cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr); + return ERROR_OK; } static int cortex_m3_assert_reset(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; int assert_srst = 1; LOG_DEBUG("target->state: %s", @@ -719,21 +853,25 @@ static int cortex_m3_assert_reset(struct target *target) { /* Set/Clear C_MASKINTS in a separate operation */ if (cortex_m3->dcb_dhcsr & C_MASKINTS) - mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN | C_HALT); + mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, + DBGKEY | C_DEBUGEN | C_HALT); /* clear any debug flags before resuming */ cortex_m3_clear_halt(target); /* clear C_HALT in dhcsr reg */ cortex_m3_write_debug_halt_mask(target, 0, C_HALT); - - /* Enter debug state on reset, cf. end_reset_event() */ - mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR); } else { - /* Enter debug state on reset, cf. end_reset_event() */ - mem_ap_write_atomic_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); + /* Halt in debug on reset; endreset_event() restores DEMCR. + * + * REVISIT catching BUSERR presumably helps to defend against + * bad vector table entries. Should this include MMERR or + * other flags too? + */ + mem_ap_write_atomic_u32(swjdp, DCB_DEMCR, + TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); } /* @@ -881,16 +1019,25 @@ cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint) else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; + + /* NOTE: on ARMv6-M and ARMv7-M, BKPT(0xab) is used for + * semihosting; don't use that. Otherwise the BKPT + * parameter is arbitrary. + */ buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); - if ((retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr)) != ERROR_OK) - { + retval = target_read_memory(target, + breakpoint->address & 0xFFFFFFFE, + breakpoint->length, 1, + breakpoint->orig_instr); + if (retval != ERROR_OK) return retval; - } - if ((retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code)) != ERROR_OK) - { + retval = target_write_memory(target, + breakpoint->address & 0xFFFFFFFE, + breakpoint->length, 1, + code); + if (retval != ERROR_OK) return retval; - } - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->set = true; } LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)", @@ -953,7 +1100,7 @@ cortex_m3_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) } } } - breakpoint->set = 0; + breakpoint->set = false; return ERROR_OK; } @@ -1132,7 +1279,7 @@ cortex_m3_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - watchpoint->set = 0; + watchpoint->set = false; return ERROR_OK; } @@ -1218,7 +1365,7 @@ static void cortex_m3_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->set) cortex_m3_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1229,7 +1376,7 @@ static int cortex_m3_load_core_reg_u32(struct target *target, { int retval; struct armv7m_common *armv7m = target_to_armv7m(target); - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; /* NOTE: we "know" here that the register identifiers used * in the v7m header match the Cortex-M3 Debug Core Register @@ -1293,7 +1440,7 @@ static int cortex_m3_store_core_reg_u32(struct target *target, int retval; uint32_t reg; struct armv7m_common *armv7m = target_to_armv7m(target); - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; #ifdef ARMV7_GDB_HACKS /* If the LR register is being modified, make sure it will put us @@ -1316,8 +1463,11 @@ static int cortex_m3_store_core_reg_u32(struct target *target, retval = cortexm3_dap_write_coreregister_u32(swjdp, value, num); if (retval != ERROR_OK) { + struct reg *r; + LOG_ERROR("JTAG failure %i", retval); - armv7m->core_cache->reg_list[num].dirty = armv7m->core_cache->reg_list[num].valid; + r = armv7m->core_cache->reg_list + num; + r->dirty = r->valid; return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); @@ -1368,7 +1518,7 @@ static int cortex_m3_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; int retval = ERROR_INVALID_ARGUMENTS; /* cortex_m3 handles unaligned memory access */ @@ -1393,7 +1543,7 @@ static int cortex_m3_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; int retval = ERROR_INVALID_ARGUMENTS; if (count && buffer) { @@ -1460,6 +1610,9 @@ struct dwt_reg { static struct dwt_reg dwt_base_regs[] = { { DWT_CTRL, "dwt_ctrl", 32, }, + /* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly + * increments while the core is asleep. + */ { DWT_CYCCNT, "dwt_cyccnt", 32, }, /* plus some 8 bit counters, useful for profiling with TPIU */ }; @@ -1571,7 +1724,7 @@ static int cortex_m3_examine(struct target *target) uint32_t cpuid, fpcr; int i; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + struct adiv5_dap *swjdp = &cortex_m3->armv7m.dap; if ((retval = ahbap_debugport_init(swjdp)) != ERROR_OK) return retval; @@ -1586,7 +1739,8 @@ static int cortex_m3_examine(struct target *target) return retval; if (((cpuid >> 4) & 0xc3f) == 0xc23) - LOG_DEBUG("CORTEX-M3 processor detected"); + LOG_DEBUG("Cortex-M3 r%" PRId8 "p%" PRId8 " processor detected", + (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid); /* NOTE: FPB and DWT are both optional. */ @@ -1619,7 +1773,7 @@ static int cortex_m3_examine(struct target *target) return ERROR_OK; } -static int cortex_m3_dcc_read(struct swjdp_common *swjdp, uint8_t *value, uint8_t *ctrl) +static int cortex_m3_dcc_read(struct adiv5_dap *swjdp, uint8_t *value, uint8_t *ctrl) { uint16_t dcrdr; @@ -1644,7 +1798,7 @@ static int cortex_m3_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; uint8_t data; uint8_t ctrl; uint32_t i; @@ -1664,7 +1818,7 @@ static int cortex_m3_handle_target_request(void *priv) if (!target_was_examined(target)) return ERROR_OK; struct armv7m_common *armv7m = target_to_armv7m(target); - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; if (!target->dbg_msg_enabled) return ERROR_OK; @@ -1708,12 +1862,13 @@ static int cortex_m3_init_arch_info(struct target *target, cortex_m3->jtag_info.tap = tap; cortex_m3->jtag_info.scann_size = 4; - armv7m->swjdp_info.dp_select_value = -1; - armv7m->swjdp_info.ap_csw_value = -1; - armv7m->swjdp_info.ap_tar_value = -1; - armv7m->swjdp_info.jtag_info = &cortex_m3->jtag_info; - armv7m->swjdp_info.memaccess_tck = 8; - armv7m->swjdp_info.tar_autoincr_block = (1 << 12); /* Cortex-M3 has 4096 bytes autoincrement range */ + armv7m->arm.dap = &armv7m->dap; + + /* Leave (only) generic DAP stuff for debugport_init(); */ + armv7m->dap.jtag_info = &cortex_m3->jtag_info; + armv7m->dap.memaccess_tck = 8; + /* Cortex-M3 has 4096 bytes autoincrement range */ + armv7m->dap.tar_autoincr_block = (1 << 12); /* register arch-specific functions */ armv7m->examine_debug_reason = cortex_m3_examine_debug_reason; @@ -1721,7 +1876,6 @@ static int cortex_m3_init_arch_info(struct target *target, armv7m->post_debug_entry = NULL; armv7m->pre_restore_context = NULL; - armv7m->post_restore_context = NULL; armv7m->load_core_reg_u32 = cortex_m3_load_core_reg_u32; armv7m->store_core_reg_u32 = cortex_m3_store_core_reg_u32; @@ -1764,50 +1918,6 @@ static int cortex_m3_verify_pointer(struct command_context *cmd_ctx, * cortexm3_target structure, which is only used with CM3 targets. */ -/* - * REVISIT Thumb2 disassembly should work for all ARMv7 cores, as well - * as at least ARM-1156T2. The interesting thing about Cortex-M is - * that *only* Thumb2 disassembly matters. There are also some small - * additions to Thumb2 that are specific to ARMv7-M. - */ -COMMAND_HANDLER(handle_cortex_m3_disassemble_command) -{ - int retval; - struct target *target = get_current_target(CMD_CTX); - struct cortex_m3_common *cortex_m3 = target_to_cm3(target); - uint32_t address; - unsigned long count = 1; - struct arm_instruction cur_instruction; - - retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3); - if (retval != ERROR_OK) - return retval; - - errno = 0; - switch (CMD_ARGC) { - case 2: - COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], count); - /* FALL THROUGH */ - case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); - break; - default: - command_print(CMD_CTX, - "usage: cortex_m3 disassemble
[]"); - return ERROR_OK; - } - - while (count--) { - retval = thumb2_opcode(target, address, &cur_instruction); - if (retval != ERROR_OK) - return retval; - command_print(CMD_CTX, "%s", cur_instruction.text); - address += cur_instruction.instruction_size; - } - - return ERROR_OK; -} - static const struct { char name[10]; unsigned mask; @@ -1827,7 +1937,7 @@ COMMAND_HANDLER(handle_cortex_m3_vector_catch_command) struct target *target = get_current_target(CMD_CTX); struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; - struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct adiv5_dap *swjdp = &armv7m->dap; uint32_t demcr = 0; int retval; @@ -1864,12 +1974,20 @@ COMMAND_HANDLER(handle_cortex_m3_vector_catch_command) } } write: + /* For now, armv7m->demcr only stores vector catch flags. */ + armv7m->demcr = catch; + demcr &= ~0xffff; demcr |= catch; - /* write, but don't assume it stuck */ + /* write, but don't assume it stuck (why not??) */ mem_ap_write_u32(swjdp, DCB_DEMCR, demcr); mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr); + + /* FIXME be sure to clear DEMCR on clean server shutdown. + * Otherwise the vector catch hardware could fire when there's + * no debugger hooked up, causing much confusion... + */ } for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) @@ -1913,26 +2031,19 @@ COMMAND_HANDLER(handle_cortex_m3_mask_interrupts_command) } static const struct command_registration cortex_m3_exec_command_handlers[] = { - { - .name = "disassemble", - .handler = &handle_cortex_m3_disassemble_command, - .mode = COMMAND_EXEC, - .help = "disassemble Thumb2 instructions", - .usage = "
[]", - }, { .name = "maskisr", - .handler = &handle_cortex_m3_mask_interrupts_command, + .handler = handle_cortex_m3_mask_interrupts_command, .mode = COMMAND_EXEC, .help = "mask cortex_m3 interrupts", .usage = "['on'|'off']", }, { .name = "vector_catch", - .handler = &handle_cortex_m3_vector_catch_command, + .handler = handle_cortex_m3_vector_catch_command, .mode = COMMAND_EXEC, - .help = "catch hardware vectors", - .usage = "['all'|'none'|]", + .help = "configure hardware vectors to trigger debug entry", + .usage = "['all'|'none'|('bus_err'|'chk_err'|...)*]", }, COMMAND_REGISTRATION_DONE }; @@ -1942,7 +2053,7 @@ static const struct command_registration cortex_m3_command_handlers[] = { }, { .name = "cortex_m3", - .mode = COMMAND_ANY, + .mode = COMMAND_EXEC, .help = "Cortex-M3 command group", .chain = cortex_m3_exec_command_handlers, },