X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fcortex_m.c;h=6558252270a95959da1cb797cb437cb3d93fcfa8;hp=5deb9bf4ae6c08be34a7e7ab4f38b853e156cc46;hb=0dcf95c7171b702d70ec326f8c1a63cbc9255b6f;hpb=c4e6034e26b40cc440356eb35b3372b220806e5e diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 5deb9bf4ae..6558252270 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -118,6 +118,33 @@ static int cortex_m_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value); static void cortex_m_dwt_free(struct target *target); +/** DCB DHCSR register contains S_RETIRE_ST and S_RESET_ST bits cleared + * on a read. Call this helper function each time DHCSR is read + * to preserve S_RESET_ST state in case of a reset event was detected. + */ +static inline void cortex_m_cumulate_dhcsr_sticky(struct cortex_m_common *cortex_m, + uint32_t dhcsr) +{ + cortex_m->dcb_dhcsr_cumulated_sticky |= dhcsr; +} + +/** Read DCB DHCSR register to cortex_m->dcb_dhcsr and cumulate + * sticky bits in cortex_m->dcb_dhcsr_cumulated_sticky + */ +static int cortex_m_read_dhcsr_atomic_sticky(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = target_to_armv7m(target); + + int retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, + &cortex_m->dcb_dhcsr); + if (retval != ERROR_OK) + return retval; + + cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); + return ERROR_OK; +} + static int cortex_m_load_core_reg_u32(struct target *target, uint32_t regsel, uint32_t *value) { @@ -301,7 +328,6 @@ static int cortex_m_clear_halt(struct target *target) static int cortex_m_single_step_core(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); - struct armv7m_common *armv7m = &cortex_m->armv7m; int retval; /* Mask interrupts before clearing halt, if not done already. This avoids @@ -309,13 +335,11 @@ static int cortex_m_single_step_core(struct target *target) * HALT can put the core into an unknown state. */ if (!(cortex_m->dcb_dhcsr & C_MASKINTS)) { - retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, - DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0); if (retval != ERROR_OK) return retval; } - retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, - DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); if (retval != ERROR_OK) return retval; LOG_DEBUG(" "); @@ -365,11 +389,12 @@ static int cortex_m_endreset_event(struct target *target) if (retval != ERROR_OK) return retval; - /* Enable debug requests */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; + if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { + /* Enable debug requests */ retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); if (retval != ERROR_OK) return retval; @@ -431,7 +456,9 @@ static int cortex_m_endreset_event(struct target *target) register_cache_invalidate(armv7m->arm.core_cache); /* make sure we have latest dhcsr flags */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); + if (retval != ERROR_OK) + return retval; return retval; } @@ -555,7 +582,8 @@ static int cortex_m_debug_entry(struct target *target) cortex_m_set_maskints_for_halt(target); cortex_m_clear_halt(target); - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; @@ -639,7 +667,7 @@ static int cortex_m_poll(struct target *target) struct armv7m_common *armv7m = &cortex_m->armv7m; /* Read from Debug Halting Control and Status Register */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; @@ -660,12 +688,13 @@ static int cortex_m_poll(struct target *target) detected_failure = ERROR_FAIL; /* refresh status bits */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; } - if (cortex_m->dcb_dhcsr & S_RESET_ST) { + if (cortex_m->dcb_dhcsr_cumulated_sticky & S_RESET_ST) { + cortex_m->dcb_dhcsr_cumulated_sticky &= ~S_RESET_ST; if (target->state != TARGET_RESET) { target->state = TARGET_RESET; LOG_INFO("%s: external reset detected", target_name(target)); @@ -712,7 +741,12 @@ static int cortex_m_poll(struct target *target) } if (target->state == TARGET_UNKNOWN) { - /* check if processor is retiring instructions or sleeping */ + /* Check if processor is retiring instructions or sleeping. + * Unlike S_RESET_ST here we test if the target *is* running now, + * not if it has been running (possibly in the past). Instructions are + * typically processed much faster than OpenOCD polls DHCSR so S_RETIRE_ST + * is read always 1. That's the reason not to use dcb_dhcsr_cumulated_sticky. + */ if (cortex_m->dcb_dhcsr & S_RETIRE_ST || cortex_m->dcb_dhcsr & S_SLEEP) { target->state = TARGET_RUNNING; retval = ERROR_OK; @@ -779,7 +813,6 @@ static int cortex_m_soft_reset_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; - uint32_t dcb_dhcsr = 0; int retval, timeout = 0; /* on single cortex_m MCU soft_reset_halt should be avoided as same functionality @@ -815,25 +848,23 @@ static int cortex_m_soft_reset_halt(struct target *target) register_cache_invalidate(cortex_m->armv7m.arm.core_cache); while (timeout < 100) { - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval == ERROR_OK) { retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_DFSR, &cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; - if ((dcb_dhcsr & S_HALT) + if ((cortex_m->dcb_dhcsr & S_HALT) && (cortex_m->nvic_dfsr & DFSR_VCATCH)) { - LOG_DEBUG("system reset-halted, DHCSR 0x%08x, " - "DFSR 0x%08x", - (unsigned) dcb_dhcsr, - (unsigned) cortex_m->nvic_dfsr); + LOG_DEBUG("system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32, + cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr); cortex_m_poll(target); /* FIXME restore user's vector catch config */ return ERROR_OK; } else LOG_DEBUG("waiting for system reset-halt, " - "DHCSR 0x%08x, %d ms", - (unsigned) dcb_dhcsr, timeout); + "DHCSR 0x%08" PRIx32 ", %d ms", + cortex_m->dcb_dhcsr, timeout); } timeout++; alive_sleep(1); @@ -1082,9 +1113,7 @@ static int cortex_m_step(struct target *target, int current, /* Wait for pending handlers to complete or timeout */ do { - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, - DCB_DHCSR, - &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; @@ -1119,7 +1148,7 @@ static int cortex_m_step(struct target *target, int current, } } - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + retval = cortex_m_read_dhcsr_atomic_sticky(target); if (retval != ERROR_OK) return retval; @@ -1197,8 +1226,8 @@ static int cortex_m_assert_reset(struct target *target) } /* Enable debug requests */ - int retval; - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr); + int retval = cortex_m_read_dhcsr_atomic_sticky(target); + /* Store important errors instead of failing and proceed to reset assert */ if (retval != ERROR_OK || !(cortex_m->dcb_dhcsr & C_DEBUGEN)) @@ -2082,8 +2111,12 @@ int cortex_m_examine(struct target *target) armv7m->arm.arch = cortex_m->core_info->arch; - LOG_DEBUG("%s r%" PRId8 "p%" PRId8 " processor detected", - cortex_m->core_info->name, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); + LOG_INFO("%s: %s r%" PRId8 "p%" PRId8 " processor detected", + target_name(target), + cortex_m->core_info->name, + (uint8_t)((cpuid >> 20) & 0xf), + (uint8_t)((cpuid >> 0) & 0xf)); + cortex_m->maskints_erratum = false; if (core_partno == CORTEX_M7_PARTNO) { uint8_t rev, patch; @@ -2138,11 +2171,13 @@ int cortex_m_examine(struct target *target) armv7m->debug_ap->tar_autoincr_block = (1 << 12); } - /* Enable debug requests */ retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr); if (retval != ERROR_OK) return retval; + cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr); + if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { + /* Enable debug requests */ uint32_t dhcsr = (cortex_m->dcb_dhcsr | C_DEBUGEN) & ~(C_HALT | C_STEP | C_MASKINTS); retval = target_write_u32(target, DCB_DHCSR, DBGKEY | (dhcsr & 0x0000FFFFUL)); @@ -2192,7 +2227,7 @@ int cortex_m_examine(struct target *target) cortex_m_dwt_setup(cortex_m, target); /* These hardware breakpoints only work for code in flash! */ - LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", + LOG_INFO("%s: target has %d breakpoints, %d watchpoints", target_name(target), cortex_m->fp_num_code, cortex_m->dwt_num_comp);