X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fcortex_m3.c;h=0aa7ac13850dbab6531282b04ded737fd523fe52;hp=86469c4efa203cda857252bdb7f652c5bba7d81c;hb=550abe7396f60274ffd0c5f373eda046af9d9a85;hpb=a585bdf7269ce5c861c83ee3294ba1f074e9c877 diff --git a/src/target/cortex_m3.c b/src/target/cortex_m3.c index 86469c4efa..0aa7ac1385 100644 --- a/src/target/cortex_m3.c +++ b/src/target/cortex_m3.c @@ -31,32 +31,35 @@ #include "config.h" #endif +#include "breakpoints.h" #include "cortex_m3.h" #include "target_request.h" #include "target_type.h" #include "arm_disassembler.h" +#include "register.h" +#include "arm_opcodes.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. */ -#define ARRAY_SIZE(x) ((int)(sizeof(x)/sizeof((x)[0]))) - /* forward declarations */ -static int cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -static int cortex_m3_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint); -static void cortex_m3_enable_watchpoints(struct target_s *target); -static int cortex_m3_store_core_reg_u32(target_t *target, +static int cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint); +static int cortex_m3_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); +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 reg_t armv7m_gdb_dummy_cpsr_reg; -#endif - -static int cortexm3_dap_read_coreregister_u32(swjdp_common_t *swjdp, +static int cortexm3_dap_read_coreregister_u32(struct swjdp_common *swjdp, uint32_t *value, int regnum) { int retval; @@ -67,8 +70,6 @@ static int cortexm3_dap_read_coreregister_u32(swjdp_common_t *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); @@ -77,7 +78,7 @@ static int cortexm3_dap_read_coreregister_u32(swjdp_common_t *swjdp, 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 = swjdp_transaction_endcheck(swjdp); + retval = jtagdp_transaction_endcheck(swjdp); /* restore DCB_DCRDR - this needs to be in a seperate * transaction otherwise the emulated DCC channel breaks */ @@ -87,7 +88,7 @@ static int cortexm3_dap_read_coreregister_u32(swjdp_common_t *swjdp, return retval; } -static int cortexm3_dap_write_coreregister_u32(swjdp_common_t *swjdp, +static int cortexm3_dap_write_coreregister_u32(struct swjdp_common *swjdp, uint32_t value, int regnum) { int retval; @@ -98,8 +99,6 @@ static int cortexm3_dap_write_coreregister_u32(swjdp_common_t *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); @@ -108,7 +107,7 @@ static int cortexm3_dap_write_coreregister_u32(swjdp_common_t *swjdp, 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 = swjdp_transaction_endcheck(swjdp); + retval = jtagdp_transaction_endcheck(swjdp); /* restore DCB_DCRDR - this needs to be in a seperate * transaction otherwise the emulated DCC channel breaks */ @@ -118,11 +117,11 @@ static int cortexm3_dap_write_coreregister_u32(swjdp_common_t *swjdp, return retval; } -static int cortex_m3_write_debug_halt_mask(target_t *target, +static int cortex_m3_write_debug_halt_mask(struct target *target, uint32_t mask_on, uint32_t mask_off) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; /* mask off status bits */ cortex_m3->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off); @@ -132,16 +131,17 @@ static int cortex_m3_write_debug_halt_mask(target_t *target, return mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, cortex_m3->dcb_dhcsr); } -static int cortex_m3_clear_halt(target_t *target) +static int cortex_m3_clear_halt(struct target *target) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; /* 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); @@ -149,19 +149,24 @@ static int cortex_m3_clear_halt(target_t *target) return ERROR_OK; } -static int cortex_m3_single_step_core(target_t *target) +static int cortex_m3_single_step_core(struct target *target) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; 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 */ @@ -171,19 +176,21 @@ static int cortex_m3_single_step_core(target_t *target) return ERROR_OK; } -static int cortex_m3_endreset_event(target_t *target) +static int cortex_m3_endreset_event(struct target *target) { int i; uint32_t dcb_demcr; - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; - cortex_m3_fp_comparator_t *fp_list = cortex_m3->fp_comparator_list; - cortex_m3_dwt_comparator_t *dwt_list = cortex_m3->dwt_comparator_list; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct armv7m_common *armv7m = &cortex_m3->armv7m; + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; + 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 */ @@ -194,10 +201,18 @@ static int cortex_m3_endreset_event(target_t *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); @@ -219,9 +234,9 @@ static int cortex_m3_endreset_event(target_t *target) target_write_u32(target, dwt_list[i].dwt_comparator_address + 8, dwt_list[i].function); } - swjdp_transaction_endcheck(swjdp); + jtagdp_transaction_endcheck(swjdp); - armv7m_invalidate_core_regs(target); + 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); @@ -229,9 +244,9 @@ static int cortex_m3_endreset_event(target_t *target) return ERROR_OK; } -static int cortex_m3_examine_debug_reason(target_t *target) +static int cortex_m3_examine_debug_reason(struct target *target) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* THIS IS NOT GOOD, TODO - better logic for detection of debug state reason */ /* only check the debug reason if we don't know it already */ @@ -256,11 +271,11 @@ static int cortex_m3_examine_debug_reason(target_t *target) return ERROR_OK; } -static int cortex_m3_examine_exception_reason(target_t *target) +static int cortex_m3_examine_exception_reason(struct target *target) { uint32_t shcsr, except_sr, cfsr = -1, except_ar = -1; - struct armv7m_common_s *armv7m = target_to_armv7m(target); - swjdp_common_t *swjdp = &armv7m->swjdp_info; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct swjdp_common *swjdp = &armv7m->swjdp_info; mem_ap_read_u32(swjdp, NVIC_SHCSR, &shcsr); switch (armv7m->exception_number) @@ -298,20 +313,40 @@ static int cortex_m3_examine_exception_reason(target_t *target) except_sr = 0; break; } - swjdp_transaction_endcheck(swjdp); + jtagdp_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; } -static int cortex_m3_debug_entry(target_t *target) +/* 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; uint32_t xPSR; int retval; - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct armv7m_common_s *armv7m = &cortex_m3->armv7m; - swjdp_common_t *swjdp = &armv7m->swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct armv7m_common *armv7m = &cortex_m3->armv7m; + struct arm *arm = &armv7m->arm; + struct swjdp_common *swjdp = &armv7m->swjdp_info; + struct reg *r; LOG_DEBUG(" "); @@ -331,20 +366,24 @@ static int cortex_m3_debug_entry(target_t *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. + * Instead, each CM3 should have its own dummy value... + */ /* 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); } @@ -353,10 +392,27 @@ static int cortex_m3_debug_entry(target_t *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; } @@ -367,7 +423,7 @@ static int cortex_m3_debug_entry(target_t *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) @@ -376,12 +432,12 @@ static int cortex_m3_debug_entry(target_t *target) return ERROR_OK; } -static int cortex_m3_poll(target_t *target) +static int cortex_m3_poll(struct target *target) { int retval; enum target_state prev_target_state = target->state; - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; /* Read from Debug Halting Control and Status Register */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); @@ -391,6 +447,21 @@ static int cortex_m3_poll(target_t *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 */ @@ -405,8 +476,11 @@ static int cortex_m3_poll(target_t *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; @@ -450,7 +524,7 @@ static int cortex_m3_poll(target_t *target) return ERROR_OK; } -static int cortex_m3_halt(target_t *target) +static int cortex_m3_halt(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); @@ -492,37 +566,47 @@ static int cortex_m3_halt(target_t *target) return ERROR_OK; } -static int cortex_m3_soft_reset_halt(struct target_s *target) +static int cortex_m3_soft_reset_halt(struct target *target) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; 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 */ - armv7m_invalidate_core_regs(target); + register_cache_invalidate(cortex_m3->armv7m.core_cache); while (timeout < 100) { 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); @@ -531,25 +615,26 @@ static int cortex_m3_soft_reset_halt(struct target_s *target) return ERROR_OK; } -static void cortex_m3_enable_breakpoints(struct target_s *target) +static void cortex_m3_enable_breakpoints(struct target *target) { - breakpoint_t *breakpoint = target->breakpoints; + struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->set) cortex_m3_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } -static int cortex_m3_resume(struct target_s *target, int current, +static int cortex_m3_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { - struct armv7m_common_s *armv7m = target_to_armv7m(target); - breakpoint_t *breakpoint = NULL; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct breakpoint *breakpoint = NULL; uint32_t resume_pc; + struct reg *r; if (target->state != TARGET_HALTED) { @@ -566,30 +651,50 @@ static int cortex_m3_resume(struct target_s *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; } - resume_pc = buf_get_u32(armv7m->core_cache->reg_list[15].value, 0, 32); + /* 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(r->value, 0, 32); armv7m_restore_context(target); @@ -614,7 +719,8 @@ static int cortex_m3_resume(struct target_s *target, int current, target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ - armv7m_invalidate_core_regs(target); + register_cache_invalidate(armv7m->core_cache); + if (!debug_execution) { target->state = TARGET_RUNNING; @@ -632,13 +738,15 @@ static int cortex_m3_resume(struct target_s *target, int current, } /* int irqstepcount = 0; */ -static int cortex_m3_step(struct target_s *target, int current, +static int cortex_m3_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct armv7m_common_s *armv7m = &cortex_m3->armv7m; - swjdp_common_t *swjdp = &armv7m->swjdp_info; - breakpoint_t *breakpoint = NULL; + 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 breakpoint *breakpoint = NULL; + struct reg *pc = armv7m->arm.pc; + bool bkpt_inst_found = false; if (target->state != TARGET_HALTED) { @@ -648,46 +756,59 @@ static int cortex_m3_step(struct target_s *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 */ - armv7m_invalidate_core_regs(target); + register_cache_invalidate(cortex_m3->armv7m.core_cache); 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(target_t *target) +static int cortex_m3_assert_reset(struct target *target) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; int assert_srst = 1; LOG_DEBUG("target->state: %s", @@ -714,21 +835,25 @@ static int cortex_m3_assert_reset(target_t *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); } /* @@ -809,7 +934,7 @@ static int cortex_m3_assert_reset(target_t *target) target->state = TARGET_RESET; jtag_add_sleep(50000); - armv7m_invalidate_core_regs(target); + register_cache_invalidate(cortex_m3->armv7m.core_cache); if (target->reset_halt) { @@ -821,7 +946,7 @@ static int cortex_m3_assert_reset(target_t *target) return ERROR_OK; } -static int cortex_m3_deassert_reset(target_t *target) +static int cortex_m3_deassert_reset(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); @@ -833,13 +958,13 @@ static int cortex_m3_deassert_reset(target_t *target) } static int -cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; int fp_num = 0; uint32_t hilo; - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - cortex_m3_fp_comparator_t *comparator_list = cortex_m3->fp_comparator_list; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct cortex_m3_fp_comparator *comparator_list = cortex_m3->fp_comparator_list; if (breakpoint->set) { @@ -858,9 +983,8 @@ cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) fp_num++; if (fp_num >= cortex_m3->fp_num_code) { - LOG_DEBUG("ERROR Can not find free FP Comparator"); - LOG_WARNING("ERROR Can not find free FP Comparator"); - exit(-1); + LOG_ERROR("Can not find free FPB Comparator!"); + return ERROR_FAIL; } breakpoint->set = fp_num + 1; hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW; @@ -877,16 +1001,25 @@ cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; - buf_set_u32(code, 0, 32, ARMV7M_T_BKPT(0x11)); - if ((retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr)) != ERROR_OK) - { + + /* 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)); + 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)", @@ -900,11 +1033,11 @@ cortex_m3_set_breakpoint(struct target_s *target, breakpoint_t *breakpoint) } static int -cortex_m3_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +cortex_m3_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - cortex_m3_fp_comparator_t * comparator_list = cortex_m3->fp_comparator_list; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct cortex_m3_fp_comparator * comparator_list = cortex_m3->fp_comparator_list; if (!breakpoint->set) { @@ -949,15 +1082,15 @@ cortex_m3_unset_breakpoint(struct target_s *target, breakpoint_t *breakpoint) } } } - breakpoint->set = 0; + breakpoint->set = false; return ERROR_OK; } static int -cortex_m3_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +cortex_m3_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); if (cortex_m3->auto_bp_type) { @@ -1004,9 +1137,9 @@ cortex_m3_add_breakpoint(struct target_s *target, breakpoint_t *breakpoint) } static int -cortex_m3_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) +cortex_m3_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* REVISIT why check? FBP can be updated with core running ... */ if (target->state != TARGET_HALTED) @@ -1032,11 +1165,11 @@ cortex_m3_remove_breakpoint(struct target_s *target, breakpoint_t *breakpoint) } static int -cortex_m3_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +cortex_m3_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int dwt_num = 0; uint32_t mask, temp; - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* watchpoint params were validated earlier */ mask = 0; @@ -1052,7 +1185,7 @@ cortex_m3_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) * watchpoint using comparator #1; comparator #0 matching cycle * count; send data trace info through ITM and TPIU; etc */ - cortex_m3_dwt_comparator_t *comparator; + struct cortex_m3_dwt_comparator *comparator; for (comparator = cortex_m3->dwt_comparator_list; comparator->used && dwt_num < cortex_m3->dwt_num_comp; @@ -1097,10 +1230,10 @@ cortex_m3_set_watchpoint(struct target_s *target, watchpoint_t *watchpoint) } static int -cortex_m3_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +cortex_m3_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - cortex_m3_dwt_comparator_t *comparator; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct cortex_m3_dwt_comparator *comparator; int dwt_num; if (!watchpoint->set) @@ -1128,22 +1261,15 @@ cortex_m3_unset_watchpoint(struct target_s *target, watchpoint_t *watchpoint) target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - watchpoint->set = 0; + watchpoint->set = false; return ERROR_OK; } static int -cortex_m3_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +cortex_m3_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - - /* REVISIT why check? DWT can be updated with core running ... */ - if (target->state != TARGET_HALTED) - { - LOG_WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); if (cortex_m3->dwt_comp_available < 1) { @@ -1192,9 +1318,9 @@ cortex_m3_add_watchpoint(struct target_s *target, watchpoint_t *watchpoint) } static int -cortex_m3_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) +cortex_m3_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* REVISIT why check? DWT can be updated with core running ... */ if (target->state != TARGET_HALTED) @@ -1214,25 +1340,25 @@ cortex_m3_remove_watchpoint(struct target_s *target, watchpoint_t *watchpoint) return ERROR_OK; } -static void cortex_m3_enable_watchpoints(struct target_s *target) +static void cortex_m3_enable_watchpoints(struct target *target) { - watchpoint_t *watchpoint = target->watchpoints; + struct watchpoint *watchpoint = target->watchpoints; /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->set) cortex_m3_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } -static int cortex_m3_load_core_reg_u32(struct target_s *target, +static int cortex_m3_load_core_reg_u32(struct target *target, enum armv7m_regtype type, uint32_t num, uint32_t * value) { int retval; - struct armv7m_common_s *armv7m = target_to_armv7m(target); - swjdp_common_t *swjdp = &armv7m->swjdp_info; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct swjdp_common *swjdp = &armv7m->swjdp_info; /* NOTE: we "know" here that the register identifiers used * in the v7m header match the Cortex-M3 Debug Core Register @@ -1290,13 +1416,13 @@ static int cortex_m3_load_core_reg_u32(struct target_s *target, return ERROR_OK; } -static int cortex_m3_store_core_reg_u32(struct target_s *target, +static int cortex_m3_store_core_reg_u32(struct target *target, enum armv7m_regtype type, uint32_t num, uint32_t value) { int retval; uint32_t reg; - struct armv7m_common_s *armv7m = target_to_armv7m(target); - swjdp_common_t *swjdp = &armv7m->swjdp_info; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct swjdp_common *swjdp = &armv7m->swjdp_info; #ifdef ARMV7_GDB_HACKS /* If the LR register is being modified, make sure it will put us @@ -1319,8 +1445,11 @@ static int cortex_m3_store_core_reg_u32(struct target_s *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); @@ -1367,21 +1496,16 @@ static int cortex_m3_store_core_reg_u32(struct target_s *target, return ERROR_OK; } -static int cortex_m3_read_memory(struct target_s *target, uint32_t address, +static int cortex_m3_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - struct armv7m_common_s *armv7m = target_to_armv7m(target); - swjdp_common_t *swjdp = &armv7m->swjdp_info; - int retval; - - /* sanitize arguments */ - if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) - return ERROR_INVALID_ARGUMENTS; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct swjdp_common *swjdp = &armv7m->swjdp_info; + int retval = ERROR_INVALID_ARGUMENTS; /* cortex_m3 handles unaligned memory access */ - - switch (size) - { + if (count && buffer) { + switch (size) { case 4: retval = mem_ap_read_buf_u32(swjdp, buffer, 4 * count, address); break; @@ -1391,27 +1515,21 @@ static int cortex_m3_read_memory(struct target_s *target, uint32_t address, case 1: retval = mem_ap_read_buf_u8(swjdp, buffer, count, address); break; - default: - LOG_ERROR("BUG: we shouldn't get here"); - exit(-1); + } } return retval; } -static int cortex_m3_write_memory(struct target_s *target, uint32_t address, +static int cortex_m3_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - struct armv7m_common_s *armv7m = target_to_armv7m(target); - swjdp_common_t *swjdp = &armv7m->swjdp_info; - int retval; - - /* sanitize arguments */ - if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) - return ERROR_INVALID_ARGUMENTS; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct swjdp_common *swjdp = &armv7m->swjdp_info; + int retval = ERROR_INVALID_ARGUMENTS; - switch (size) - { + if (count && buffer) { + switch (size) { case 4: retval = mem_ap_write_buf_u32(swjdp, buffer, 4 * count, address); break; @@ -1421,22 +1539,20 @@ static int cortex_m3_write_memory(struct target_s *target, uint32_t address, case 1: retval = mem_ap_write_buf_u8(swjdp, buffer, count, address); break; - default: - LOG_ERROR("BUG: we shouldn't get here"); - exit(-1); + } } return retval; } -static int cortex_m3_bulk_write_memory(target_t *target, uint32_t address, +static int cortex_m3_bulk_write_memory(struct target *target, uint32_t address, uint32_t count, uint8_t *buffer) { return cortex_m3_write_memory(target, address, 4, count, buffer); } -static int cortex_m3_init_target(struct command_context_s *cmd_ctx, - struct target_s *target) +static int cortex_m3_init_target(struct command_context *cmd_ctx, + struct target *target) { armv7m_build_reg_cache(target); return ERROR_OK; @@ -1448,19 +1564,19 @@ static int cortex_m3_init_target(struct command_context_s *cmd_ctx, */ struct dwt_reg_state { - struct target_s *target; + struct target *target; uint32_t addr; uint32_t value; /* scratch/cache */ }; -static int cortex_m3_dwt_get_reg(struct reg_s *reg) +static int cortex_m3_dwt_get_reg(struct reg *reg) { struct dwt_reg_state *state = reg->arch_info; return target_read_u32(state->target, state->addr, &state->value); } -static int cortex_m3_dwt_set_reg(struct reg_s *reg, uint8_t *buf) +static int cortex_m3_dwt_set_reg(struct reg *reg, uint8_t *buf) { struct dwt_reg_state *state = reg->arch_info; @@ -1476,6 +1592,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 */ }; @@ -1492,10 +1611,13 @@ static struct dwt_reg dwt_comp[] = { #undef DWT_COMPARATOR }; -static int dwt_reg_type = -1; +static const struct reg_arch_type dwt_reg_type = { + .get = cortex_m3_dwt_get_reg, + .set = cortex_m3_dwt_set_reg, +}; static void -cortex_m3_dwt_addreg(struct target_s *t, struct reg_s *r, struct dwt_reg *d) +cortex_m3_dwt_addreg(struct target *t, struct reg *r, struct dwt_reg *d) { struct dwt_reg_state *state; @@ -1509,15 +1631,15 @@ cortex_m3_dwt_addreg(struct target_s *t, struct reg_s *r, struct dwt_reg *d) r->size = d->size; r->value = &state->value; r->arch_info = state; - r->arch_type = dwt_reg_type; + r->type = &dwt_reg_type; } static void -cortex_m3_dwt_setup(cortex_m3_common_t *cm3, struct target_s *target) +cortex_m3_dwt_setup(struct cortex_m3_common *cm3, struct target *target) { uint32_t dwtcr; - struct reg_cache_s *cache; - cortex_m3_dwt_comparator_t *comparator; + struct reg_cache *cache; + struct cortex_m3_dwt_comparator *comparator; int reg, i; target_read_u32(target, DWT_CTRL, &dwtcr); @@ -1526,14 +1648,10 @@ cortex_m3_dwt_setup(cortex_m3_common_t *cm3, struct target_s *target) return; } - if (dwt_reg_type < 0) - dwt_reg_type = register_reg_arch_type(cortex_m3_dwt_get_reg, - cortex_m3_dwt_set_reg); - cm3->dwt_num_comp = (dwtcr >> 28) & 0xF; cm3->dwt_comp_available = cm3->dwt_num_comp; cm3->dwt_comparator_list = calloc(cm3->dwt_num_comp, - sizeof(cortex_m3_dwt_comparator_t)); + sizeof(struct cortex_m3_dwt_comparator)); if (!cm3->dwt_comparator_list) { fail0: cm3->dwt_num_comp = 0; @@ -1582,13 +1700,13 @@ fail1: */ } -static int cortex_m3_examine(struct target_s *target) +static int cortex_m3_examine(struct target *target) { int retval; uint32_t cpuid, fpcr; int i; - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct swjdp_common_s *swjdp = &cortex_m3->armv7m.swjdp_info; + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); + struct swjdp_common *swjdp = &cortex_m3->armv7m.swjdp_info; if ((retval = ahbap_debugport_init(swjdp)) != ERROR_OK) return retval; @@ -1603,7 +1721,8 @@ static int cortex_m3_examine(struct target_s *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. */ @@ -1614,7 +1733,7 @@ static int cortex_m3_examine(struct target_s *target) cortex_m3->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF); /* bits [14:12] and [7:4] */ cortex_m3->fp_num_lit = (fpcr >> 8) & 0xF; cortex_m3->fp_code_available = cortex_m3->fp_num_code; - cortex_m3->fp_comparator_list = calloc(cortex_m3->fp_num_code + cortex_m3->fp_num_lit, sizeof(cortex_m3_fp_comparator_t)); + cortex_m3->fp_comparator_list = calloc(cortex_m3->fp_num_code + cortex_m3->fp_num_lit, sizeof(struct cortex_m3_fp_comparator)); cortex_m3->fpb_enabled = fpcr & 1; for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++) { @@ -1625,12 +1744,18 @@ static int cortex_m3_examine(struct target_s *target) /* Setup DWT */ cortex_m3_dwt_setup(cortex_m3, target); + + /* These hardware breakpoints only work for code in flash! */ + LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", + target_name(target), + cortex_m3->fp_num_code, + cortex_m3->dwt_num_comp); } return ERROR_OK; } -static int cortex_m3_dcc_read(swjdp_common_t *swjdp, uint8_t *value, uint8_t *ctrl) +static int cortex_m3_dcc_read(struct swjdp_common *swjdp, uint8_t *value, uint8_t *ctrl) { uint16_t dcrdr; @@ -1651,11 +1776,11 @@ static int cortex_m3_dcc_read(swjdp_common_t *swjdp, uint8_t *value, uint8_t *ct return ERROR_OK; } -static int cortex_m3_target_request_data(target_t *target, +static int cortex_m3_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { - struct armv7m_common_s *armv7m = target_to_armv7m(target); - swjdp_common_t *swjdp = &armv7m->swjdp_info; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct swjdp_common *swjdp = &armv7m->swjdp_info; uint8_t data; uint8_t ctrl; uint32_t i; @@ -1671,11 +1796,11 @@ static int cortex_m3_target_request_data(target_t *target, static int cortex_m3_handle_target_request(void *priv) { - target_t *target = priv; + struct target *target = priv; if (!target_was_examined(target)) return ERROR_OK; - struct armv7m_common_s *armv7m = target_to_armv7m(target); - swjdp_common_t *swjdp = &armv7m->swjdp_info; + struct armv7m_common *armv7m = target_to_armv7m(target); + struct swjdp_common *swjdp = &armv7m->swjdp_info; if (!target->dbg_msg_enabled) return ERROR_OK; @@ -1707,11 +1832,11 @@ static int cortex_m3_handle_target_request(void *priv) return ERROR_OK; } -static int cortex_m3_init_arch_info(target_t *target, - cortex_m3_common_t *cortex_m3, jtag_tap_t *tap) +static int cortex_m3_init_arch_info(struct target *target, + struct cortex_m3_common *cortex_m3, struct jtag_tap *tap) { int retval; - struct armv7m_common_s *armv7m = &cortex_m3->armv7m; + struct armv7m_common *armv7m = &cortex_m3->armv7m; armv7m_init_arch_info(target, armv7m); @@ -1719,12 +1844,11 @@ static int cortex_m3_init_arch_info(target_t *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; + /* Leave (only) generic DAP stuff for debugport_init(); */ 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 */ + /* Cortex-M3 has 4096 bytes autoincrement range */ + armv7m->swjdp_info.tar_autoincr_block = (1 << 12); /* register arch-specific functions */ armv7m->examine_debug_reason = cortex_m3_examine_debug_reason; @@ -1747,9 +1871,9 @@ static int cortex_m3_init_arch_info(target_t *target, return ERROR_OK; } -static int cortex_m3_target_create(struct target_s *target, Jim_Interp *interp) +static int cortex_m3_target_create(struct target *target, Jim_Interp *interp) { - cortex_m3_common_t *cortex_m3 = calloc(1,sizeof(cortex_m3_common_t)); + struct cortex_m3_common *cortex_m3 = calloc(1,sizeof(struct cortex_m3_common)); cortex_m3->common_magic = CORTEX_M3_COMMON_MAGIC; cortex_m3_init_arch_info(target, cortex_m3, target->tap); @@ -1759,8 +1883,8 @@ static int cortex_m3_target_create(struct target_s *target, Jim_Interp *interp) /*--------------------------------------------------------------------------*/ -static int cortex_m3_verify_pointer(struct command_context_s *cmd_ctx, - struct cortex_m3_common_s *cm3) +static int cortex_m3_verify_pointer(struct command_context *cmd_ctx, + struct cortex_m3_common *cm3) { if (cm3->common_magic != CORTEX_M3_COMMON_MAGIC) { command_print(cmd_ctx, "target is not a Cortex-M3"); @@ -1775,50 +1899,6 @@ static int cortex_m3_verify_pointer(struct command_context_s *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; - target_t *target = get_current_target(cmd_ctx); - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - uint32_t address; - unsigned long count = 1; - arm_instruction_t cur_instruction; - - retval = cortex_m3_verify_pointer(cmd_ctx, cortex_m3); - if (retval != ERROR_OK) - return retval; - - errno = 0; - switch (argc) { - case 2: - COMMAND_PARSE_NUMBER(ulong, args[1], count); - /* FALL THROUGH */ - case 1: - COMMAND_PARSE_NUMBER(u32, args[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; @@ -1835,123 +1915,133 @@ static const struct { COMMAND_HANDLER(handle_cortex_m3_vector_catch_command) { - target_t *target = get_current_target(cmd_ctx); - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); - struct armv7m_common_s *armv7m = &cortex_m3->armv7m; - swjdp_common_t *swjdp = &armv7m->swjdp_info; + 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; uint32_t demcr = 0; int retval; - int i; - retval = cortex_m3_verify_pointer(cmd_ctx, cortex_m3); + retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3); if (retval != ERROR_OK) return retval; mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr); - if (argc > 0) { + if (CMD_ARGC > 0) { unsigned catch = 0; - if (argc == 1) { - if (strcmp(args[0], "all") == 0) { + if (CMD_ARGC == 1) { + if (strcmp(CMD_ARGV[0], "all") == 0) { catch = VC_HARDERR | VC_INTERR | VC_BUSERR | VC_STATERR | VC_CHKERR | VC_NOCPERR | VC_MMERR | VC_CORERESET; goto write; - } else if (strcmp(args[0], "none") == 0) { + } else if (strcmp(CMD_ARGV[0], "none") == 0) { goto write; } } - while (argc-- > 0) { + while (CMD_ARGC-- > 0) { + unsigned i; for (i = 0; i < ARRAY_SIZE(vec_ids); i++) { - if (strcmp(args[argc], vec_ids[i].name) != 0) + if (strcmp(CMD_ARGV[CMD_ARGC], vec_ids[i].name) != 0) continue; catch |= vec_ids[i].mask; break; } if (i == ARRAY_SIZE(vec_ids)) { - LOG_ERROR("No CM3 vector '%s'", args[argc]); + LOG_ERROR("No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); return ERROR_INVALID_ARGUMENTS; } } 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 (i = 0; i < ARRAY_SIZE(vec_ids); i++) - command_print(cmd_ctx, "%9s: %s", vec_ids[i].name, + for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) + { + command_print(CMD_CTX, "%9s: %s", vec_ids[i].name, (demcr & vec_ids[i].mask) ? "catch" : "ignore"); + } return ERROR_OK; } COMMAND_HANDLER(handle_cortex_m3_mask_interrupts_command) { - target_t *target = get_current_target(cmd_ctx); - struct cortex_m3_common_s *cortex_m3 = target_to_cm3(target); + struct target *target = get_current_target(CMD_CTX); + struct cortex_m3_common *cortex_m3 = target_to_cm3(target); int retval; - retval = cortex_m3_verify_pointer(cmd_ctx, cortex_m3); + retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { - command_print(cmd_ctx, "target must be stopped for \"%s\" command", CMD_NAME); + command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } - if (argc > 0) + if (CMD_ARGC > 0) { - if (!strcmp(args[0], "on")) - { - cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); - } - else if (!strcmp(args[0], "off")) - { - cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS); - } - else - { - command_print(cmd_ctx, "usage: cortex_m3 maskisr ['on'|'off']"); - } + bool enable; + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); + uint32_t mask_on = C_HALT | (enable ? C_MASKINTS : 0); + uint32_t mask_off = enable ? 0 : C_MASKINTS; + cortex_m3_write_debug_halt_mask(target, mask_on, mask_off); } - command_print(cmd_ctx, "cortex_m3 interrupt mask %s", + command_print(CMD_CTX, "cortex_m3 interrupt mask %s", (cortex_m3->dcb_dhcsr & C_MASKINTS) ? "on" : "off"); return ERROR_OK; } -static int cortex_m3_register_commands(struct command_context_s *cmd_ctx) -{ - int retval; - command_t *cortex_m3_cmd; - - retval = armv7m_register_commands(cmd_ctx); - - cortex_m3_cmd = register_command(cmd_ctx, NULL, "cortex_m3", - NULL, COMMAND_ANY, "cortex_m3 specific commands"); - - register_command(cmd_ctx, cortex_m3_cmd, "disassemble", - handle_cortex_m3_disassemble_command, COMMAND_EXEC, - "disassemble Thumb2 instructions
[]"); - register_command(cmd_ctx, cortex_m3_cmd, "maskisr", - handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC, - "mask cortex_m3 interrupts ['on'|'off']"); - register_command(cmd_ctx, cortex_m3_cmd, "vector_catch", - handle_cortex_m3_vector_catch_command, COMMAND_EXEC, - "catch hardware vectors ['all'|'none'|]"); - - return retval; -} +static const struct command_registration cortex_m3_exec_command_handlers[] = { + { + .name = "maskisr", + .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, + .mode = COMMAND_EXEC, + .help = "configure hardware vectors to trigger debug entry", + .usage = "['all'|'none'|('bus_err'|'chk_err'|...)*]", + }, + COMMAND_REGISTRATION_DONE +}; +static const struct command_registration cortex_m3_command_handlers[] = { + { + .chain = armv7m_command_handlers, + }, + { + .name = "cortex_m3", + .mode = COMMAND_EXEC, + .help = "Cortex-M3 command group", + .chain = cortex_m3_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; -target_type_t cortexm3_target = +struct target_type cortexm3_target = { .name = "cortex_m3", @@ -1983,7 +2073,7 @@ target_type_t cortexm3_target = .add_watchpoint = cortex_m3_add_watchpoint, .remove_watchpoint = cortex_m3_remove_watchpoint, - .register_commands = cortex_m3_register_commands, + .commands = cortex_m3_command_handlers, .target_create = cortex_m3_target_create, .init_target = cortex_m3_init_target, .examine = cortex_m3_examine,