X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Fcortex_m3.c;h=3bbe42c911c3c0baf201b44c77e15085b5e0ba0f;hb=5dcf7898f6144266c814306003c1e0a5ee067011;hp=9685821977e0e97c6b622b98a992b6b5ebf6a34f;hpb=ec88ccc51cb5d8594ae95660c826954f3a9042ec;p=openocd.git diff --git a/src/target/cortex_m3.c b/src/target/cortex_m3.c index 9685821977..3bbe42c911 100644 --- a/src/target/cortex_m3.c +++ b/src/target/cortex_m3.c @@ -185,11 +185,12 @@ static int cortex_m3_endreset_event(struct target *target) int i; uint32_t dcb_demcr; 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; - /* FIXME handling of DEMCR clobbers vector_catch config ... */ + /* 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); @@ -204,21 +205,14 @@ 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; trap hard and bus faults. - * - * REVISIT why trap those two? And why trash the vector_catch - * config, instead of preserving it? Catching HARDERR and BUSERR - * will interfere with code that handles those itself... - */ - mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR); - - /* Monitor bus faults as such (instead of as generic HARDERR), but - * leave memory management and usage faults disabled. + /* Enable features controlled by ITM and DWT blocks, and catch only + * the vectors we were told to pay attention to. * - * REVISIT setting BUSFAULTENA interferes with code which relies - * on the default setting. Why do it? + * 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, NVIC_SHCSR, SHCSR_BUSFAULTENA); + 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... @@ -422,6 +416,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 */ @@ -533,7 +542,7 @@ static int cortex_m3_soft_reset_halt(struct target *target) uint32_t dcb_dhcsr = 0; int retval, timeout = 0; - /* Enter debug state on reset; see end_reset_event() */ + /* Enter debug state on reset; restore DEMCR in endreset_event() */ mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); @@ -644,6 +653,16 @@ static int cortex_m3_resume(struct target *target, int current, 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(r->value, 0, 32); armv7m_restore_context(target); @@ -696,6 +715,7 @@ static int cortex_m3_step(struct target *target, int current, struct swjdp_common *swjdp = &armv7m->swjdp_info; struct breakpoint *breakpoint = NULL; struct reg *pc = armv7m->core_cache->reg_list + 15; + bool bkpt_inst_found = false; if (target->state != TARGET_HALTED) { @@ -715,14 +735,23 @@ static int cortex_m3_step(struct target *target, int current, 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 */ @@ -741,6 +770,7 @@ static int cortex_m3_step(struct target *target, int current, LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr); + return ERROR_OK; } @@ -782,14 +812,15 @@ static int cortex_m3_assert_reset(struct target *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() */ + /* 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); } @@ -1659,8 +1690,8 @@ static int cortex_m3_examine(struct target *target) return retval; if (((cpuid >> 4) & 0xc3f) == 0xc23) - LOG_DEBUG("Cortex-M3 r%dp%d processor detected", - (cpuid >> 20) & 0xf, (cpuid >> 0) & 0xf); + 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. */ @@ -1938,12 +1969,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++) @@ -1989,24 +2028,24 @@ 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, + .handler = handle_cortex_m3_disassemble_command, .mode = COMMAND_EXEC, .help = "disassemble Thumb2 instructions", - .usage = "
[]", + .usage = "address [count]", }, { .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 };