X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fcortex_m.c;h=e52332dd620dfdfcc32185dc561a4f96dd3805bf;hp=07fea51374c1b2475b7810b904c4aee728bc1bd1;hb=762ddcb74948852b0dfb25fcbca0965b09249a2f;hpb=ce8937a987620cb32de0ccad60ea06c296850139 diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 07fea51374..e52332dd62 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -113,7 +113,7 @@ static int cortexm_dap_write_coreregister_u32(struct target *target, return retval; if (target->dbg_msg_enabled) { - /* restore DCB_DCRDR - this needs to be in a seperate + /* restore DCB_DCRDR - this needs to be in a separate * transaction otherwise the emulated DCC channel breaks */ if (retval == ERROR_OK) retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr); @@ -129,13 +129,90 @@ static int cortex_m_write_debug_halt_mask(struct target *target, struct armv7m_common *armv7m = &cortex_m->armv7m; /* mask off status bits */ - cortex_m->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off); + cortex_m->dcb_dhcsr &= ~((0xFFFFul << 16) | mask_off); /* create new register mask */ cortex_m->dcb_dhcsr |= DBGKEY | C_DEBUGEN | mask_on; return mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, cortex_m->dcb_dhcsr); } +static int cortex_m_set_maskints(struct target *target, bool mask) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + if (!!(cortex_m->dcb_dhcsr & C_MASKINTS) != mask) + return cortex_m_write_debug_halt_mask(target, mask ? C_MASKINTS : 0, mask ? 0 : C_MASKINTS); + else + return ERROR_OK; +} + +static int cortex_m_set_maskints_for_halt(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + switch (cortex_m->isrmasking_mode) { + case CORTEX_M_ISRMASK_AUTO: + /* interrupts taken at resume, whether for step or run -> no mask */ + return cortex_m_set_maskints(target, false); + + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); + + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); + + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> mask now if MASKINTS + * erratum, otherwise only mask before stepping */ + return cortex_m_set_maskints(target, cortex_m->maskints_erratum); + } + return ERROR_OK; +} + +static int cortex_m_set_maskints_for_run(struct target *target) +{ + switch (target_to_cm(target)->isrmasking_mode) { + case CORTEX_M_ISRMASK_AUTO: + /* interrupts taken at resume, whether for step or run -> no mask */ + return cortex_m_set_maskints(target, false); + + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); + + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); + + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> no mask */ + return cortex_m_set_maskints(target, false); + } + return ERROR_OK; +} + +static int cortex_m_set_maskints_for_step(struct target *target) +{ + switch (target_to_cm(target)->isrmasking_mode) { + case CORTEX_M_ISRMASK_AUTO: + /* the auto-interrupt should already be done -> mask */ + return cortex_m_set_maskints(target, true); + + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); + + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); + + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> mask */ + return cortex_m_set_maskints(target, true); + } + return ERROR_OK; +} + static int cortex_m_clear_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); @@ -237,11 +314,8 @@ static int cortex_m_endreset_event(struct target *target) return retval; } - /* Restore proper interrupt masking setting. */ - if (cortex_m->isrmasking_mode == CORTEX_M_ISRMASK_ON) - cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0); - else - cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS); + /* Restore proper interrupt masking setting for running CPU. */ + cortex_m_set_maskints_for_run(target); /* Enable features controlled by ITM and DWT blocks, and catch only * the vectors we were told to pay attention to. @@ -265,7 +339,7 @@ static int cortex_m_endreset_event(struct target *target) return retval; } - cortex_m->fpb_enabled = 1; + cortex_m->fpb_enabled = true; /* Restore FPB registers */ for (i = 0; i < cortex_m->fp_num_code + cortex_m->fp_num_lit; i++) { @@ -318,7 +392,9 @@ static int cortex_m_examine_debug_reason(struct target *target) target->debug_reason = DBG_REASON_WATCHPOINT; else if (cortex_m->nvic_dfsr & DFSR_VCATCH) target->debug_reason = DBG_REASON_BREAKPOINT; - else /* EXTERNAL, HALTED */ + else if (cortex_m->nvic_dfsr & DFSR_EXTERNAL) + target->debug_reason = DBG_REASON_DBGRQ; + else /* HALTED */ target->debug_reason = DBG_REASON_UNDEFINED; } @@ -369,6 +445,14 @@ static int cortex_m_examine_exception_reason(struct target *target) if (retval != ERROR_OK) return retval; break; + case 7: /* Secure Fault */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFAR, &except_ar); + if (retval != ERROR_OK) + return retval; + break; case 11: /* SVCall */ break; case 12: /* Debug Monitor */ @@ -405,6 +489,10 @@ static int cortex_m_debug_entry(struct target *target) LOG_DEBUG(" "); + /* Do this really early to minimize the window where the MASKINTS erratum + * can pile up pending interrupts. */ + 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); if (retval != ERROR_OK) @@ -414,6 +502,18 @@ static int cortex_m_debug_entry(struct target *target) if (retval != ERROR_OK) return retval; + /* examine PE security state */ + bool secure_state = false; + if (armv7m->arm.is_armv8m) { + uint32_t dscsr; + + retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DSCSR, &dscsr); + if (retval != ERROR_OK) + return retval; + + secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS; + } + /* Examine target state and mode * First load register accessible through core debug port */ int num_regs = arm->core_cache->num_regs; @@ -460,9 +560,10 @@ static int cortex_m_debug_entry(struct target *target) if (armv7m->exception_number) cortex_m_examine_exception_reason(target); - LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", target->state: %s", + LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", cpu in %s state, target->state: %s", arm_mode_name(arm->core_mode), buf_get_u32(arm->pc->value, 0, 32), + secure_state ? "Secure" : "Non-Secure", target_state_name(target)); if (armv7m->post_debug_entry) { @@ -510,7 +611,10 @@ static int cortex_m_poll(struct target *target) } if (cortex_m->dcb_dhcsr & S_RESET_ST) { - target->state = TARGET_RESET; + if (target->state != TARGET_RESET) { + target->state = TARGET_RESET; + LOG_INFO("%s: external reset detected", target_name(target)); + } return ERROR_OK; } @@ -564,6 +668,17 @@ static int cortex_m_poll(struct target *target) } } + /* Check that target is truly halted, since the target could be resumed externally */ + if ((prev_target_state == TARGET_HALTED) && !(cortex_m->dcb_dhcsr & S_HALT)) { + /* registers are now invalid */ + register_cache_invalidate(armv7m->arm.core_cache); + + target->state = TARGET_RUNNING; + LOG_WARNING("%s: external resume detected", target_name(target)); + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + retval = ERROR_OK; + } + /* Did we detect a failure condition that we cleared? */ if (detected_failure != ERROR_OK) retval = detected_failure; @@ -600,6 +715,10 @@ static int cortex_m_halt(struct target *target) /* Write to Debug Halting Control and Status Register */ cortex_m_write_debug_halt_mask(target, C_HALT, 0); + /* Do this really early to minimize the window where the MASKINTS erratum + * can pile up pending interrupts. */ + cortex_m_set_maskints_for_halt(target); + target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; @@ -612,11 +731,16 @@ static int cortex_m_soft_reset_halt(struct target *target) uint32_t dcb_dhcsr = 0; int retval, timeout = 0; - /* soft_reset_halt is deprecated on cortex_m as the same functionality - * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset' - * As this reset only used VC_CORERESET it would only ever reset the cortex_m + /* on single cortex_m MCU soft_reset_halt should be avoided as same functionality + * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'. + * As this reset only uses VC_CORERESET it would only ever reset the cortex_m * core, not the peripherals */ - LOG_WARNING("soft_reset_halt is deprecated, please use 'reset halt' instead."); + LOG_DEBUG("soft_reset_halt is discouraged, please use 'reset halt' instead."); + + /* Set C_DEBUGEN */ + retval = cortex_m_write_debug_halt_mask(target, 0, C_STEP | C_MASKINTS); + if (retval != ERROR_OK) + return retval; /* Enter debug state on reset; restore DEMCR in endreset_event() */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DEMCR, @@ -753,6 +877,7 @@ static int cortex_m_resume(struct target *target, int current, } /* Restart core */ + cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT); target->debug_reason = DBG_REASON_NOTHALTED; @@ -815,10 +940,12 @@ static int cortex_m_step(struct target *target, int current, * a normal step, otherwise we have to manually step over the bkpt * instruction - as such simulate a step */ if (bkpt_inst_found == false) { - /* Automatic ISR masking mode off: Just step over the next instruction */ - if ((cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO)) + if (cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO) { + /* Automatic ISR masking mode off: Just step over the next + * instruction, with interrupts on or off as appropriate. */ + cortex_m_set_maskints_for_step(target); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); - else { + } else { /* Process interrupts during stepping in a way they don't interfere * debugging. * @@ -845,7 +972,7 @@ static int cortex_m_step(struct target *target, int current, * just step over the instruction with interrupts disabled. * * The documentation has no information about this, it was found by observation - * on STM32F1 and STM32F2. Proper explanation welcome. STM32F0 dosen't seem to + * on STM32F1 and STM32F2. Proper explanation welcome. STM32F0 doesn't seem to * suffer from this problem. * * To add some confusion: pc_value has bit 0 always set, while the breakpoint @@ -857,25 +984,37 @@ static int cortex_m_step(struct target *target, int current, LOG_DEBUG("Stepping over next instruction with interrupts disabled"); cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); - /* Re-enable interrupts */ - cortex_m_write_debug_halt_mask(target, C_HALT, C_MASKINTS); - } - else { + /* Re-enable interrupts if appropriate */ + cortex_m_write_debug_halt_mask(target, C_HALT, 0); + cortex_m_set_maskints_for_halt(target); + } else { /* Set a temporary break point */ - if (breakpoint) + if (breakpoint) { retval = cortex_m_set_breakpoint(target, breakpoint); - else - retval = breakpoint_add(target, pc_value, 2, BKPT_HARD); + } else { + enum breakpoint_type type = BKPT_HARD; + if (cortex_m->fp_rev == 0 && pc_value > 0x1FFFFFFF) { + /* FPB rev.1 cannot handle such addr, try BKPT instr */ + type = BKPT_SOFT; + } + retval = breakpoint_add(target, pc_value, 2, type); + } + bool tmp_bp_set = (retval == ERROR_OK); /* No more breakpoints left, just do a step */ - if (!tmp_bp_set) + if (!tmp_bp_set) { + cortex_m_set_maskints_for_step(target); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); - else { + /* Re-enable interrupts if appropriate */ + cortex_m_write_debug_halt_mask(target, C_HALT, 0); + cortex_m_set_maskints_for_halt(target); + } else { /* Start the core */ LOG_DEBUG("Starting core to serve pending interrupts"); int64_t t_start = timeval_ms(); + cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP); /* Wait for pending handlers to complete or timeout */ @@ -903,12 +1042,14 @@ static int cortex_m_step(struct target *target, int current, "leaving target running"); } else { /* Step over next instruction with interrupts disabled */ + cortex_m_set_maskints_for_step(target); cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); - /* Re-enable interrupts */ - cortex_m_write_debug_halt_mask(target, C_HALT, C_MASKINTS); + /* Re-enable interrupts if appropriate */ + cortex_m_write_debug_halt_mask(target, C_HALT, 0); + cortex_m_set_maskints_for_halt(target); } } } @@ -1010,8 +1151,7 @@ static int cortex_m_assert_reset(struct target *target) if (!target->reset_halt) { /* Set/Clear C_MASKINTS in a separate operation */ - if (cortex_m->dcb_dhcsr & C_MASKINTS) - cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS); + cortex_m_set_maskints_for_run(target); /* clear any debug flags before resuming */ cortex_m_clear_halt(target); @@ -1041,10 +1181,18 @@ static int cortex_m_assert_reset(struct target *target) retval = ERROR_OK; } else { /* Use a standard Cortex-M3 software reset mechanism. - * We default to using VECRESET as it is supported on all current cores. + * We default to using VECRESET as it is supported on all current cores + * (except Cortex-M0, M0+ and M1 which support SYSRESETREQ only!) * This has the disadvantage of not resetting the peripherals, so a * reset-init event handler is needed to perform any peripheral resets. */ + if (!cortex_m->vectreset_supported + && reset_config == CORTEX_M_RESET_VECTRESET) { + reset_config = CORTEX_M_RESET_SYSRESETREQ; + LOG_WARNING("VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); + LOG_WARNING("Set 'cortex_m reset_config sysresetreq'."); + } + LOG_DEBUG("Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) ? "SYSRESETREQ" : "VECTRESET"); @@ -1075,7 +1223,7 @@ static int cortex_m_assert_reset(struct target *target) } target->state = TARGET_RESET; - jtag_add_sleep(50000); + jtag_sleep(50000); register_cache_invalidate(cortex_m->armv7m.arm.core_cache); @@ -1135,7 +1283,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint fp_num++; if (fp_num >= cortex_m->fp_num_code) { LOG_ERROR("Can not find free FPB Comparator!"); - return ERROR_FAIL; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->set = fp_num + 1; fpcr_value = breakpoint->address | 1; @@ -1151,7 +1299,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint LOG_ERROR("Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); return ERROR_FAIL; } - comparator_list[fp_num].used = 1; + comparator_list[fp_num].used = true; comparator_list[fp_num].fpcr_value = fpcr_value; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); @@ -1166,7 +1314,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint return retval; } - cortex_m->fpb_enabled = 1; + cortex_m->fpb_enabled = true; } } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; @@ -1225,23 +1373,17 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi LOG_DEBUG("Invalid FP Comparator number in breakpoint"); return ERROR_OK; } - comparator_list[fp_num].used = 0; + comparator_list[fp_num].used = false; comparator_list[fp_num].fpcr_value = 0; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); } else { /* restore original instruction (kept in target endianness) */ - if (breakpoint->length == 4) { - retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 4, 1, + retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, + breakpoint->length, 1, breakpoint->orig_instr); - if (retval != ERROR_OK) - return retval; - } else { - retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 2, 1, - breakpoint->orig_instr); - if (retval != ERROR_OK) - return retval; - } + if (retval != ERROR_OK) + return retval; } breakpoint->set = false; @@ -1250,13 +1392,6 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { - struct cortex_m_common *cortex_m = target_to_cm(target); - - if ((breakpoint->type == BKPT_HARD) && (cortex_m->fp_code_available < 1)) { - LOG_INFO("no flash patch comparator unit available for hardware breakpoint"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - if (breakpoint->length == 3) { LOG_DEBUG("Using a two byte breakpoint for 32bit Thumb-2 request"); breakpoint->length = 2; @@ -1267,46 +1402,22 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - if (breakpoint->type == BKPT_HARD) - cortex_m->fp_code_available--; - return cortex_m_set_breakpoint(target, breakpoint); } int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { - struct cortex_m_common *cortex_m = target_to_cm(target); - - /* REVISIT why check? FPB can be updated with core running ... */ - if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (breakpoint->set) - cortex_m_unset_breakpoint(target, breakpoint); - - if (breakpoint->type == BKPT_HARD) - cortex_m->fp_code_available++; + if (!breakpoint->set) + return ERROR_OK; - return ERROR_OK; + return cortex_m_unset_breakpoint(target, breakpoint); } int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int dwt_num = 0; - uint32_t mask, temp; struct cortex_m_common *cortex_m = target_to_cm(target); - /* watchpoint params were validated earlier */ - mask = 0; - temp = watchpoint->length; - while (temp) { - temp >>= 1; - mask++; - } - mask--; - /* REVISIT Don't fully trust these "not used" records ... users * may set up breakpoints by hand, e.g. dual-address data value * watchpoint using comparator #1; comparator #0 matching cycle @@ -1322,18 +1433,29 @@ int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint LOG_ERROR("Can not find free DWT Comparator"); return ERROR_FAIL; } - comparator->used = 1; + comparator->used = true; watchpoint->set = dwt_num + 1; comparator->comp = watchpoint->address; target_write_u32(target, comparator->dwt_comparator_address + 0, comparator->comp); - comparator->mask = mask; - target_write_u32(target, comparator->dwt_comparator_address + 4, - comparator->mask); + if ((cortex_m->dwt_devarch & 0x1FFFFF) != DWT_DEVARCH_ARMV8M) { + uint32_t mask = 0, temp; + + /* watchpoint params were validated earlier */ + temp = watchpoint->length; + while (temp) { + temp >>= 1; + mask++; + } + mask--; + + comparator->mask = mask; + target_write_u32(target, comparator->dwt_comparator_address + 4, + comparator->mask); - switch (watchpoint->rw) { + switch (watchpoint->rw) { case WPT_READ: comparator->function = 5; break; @@ -1343,7 +1465,26 @@ int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint case WPT_ACCESS: comparator->function = 7; break; + } + } else { + uint32_t data_size = watchpoint->length >> 1; + comparator->mask = (watchpoint->length >> 1) | 1; + + switch (watchpoint->rw) { + case WPT_ACCESS: + comparator->function = 4; + break; + case WPT_WRITE: + comparator->function = 5; + break; + case WPT_READ: + comparator->function = 6; + break; + } + comparator->function = comparator->function | (1 << 4) | + (data_size << 10); } + target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); @@ -1379,7 +1520,7 @@ int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoi } comparator = cortex_m->dwt_comparator_list + dwt_num; - comparator->used = 0; + comparator->used = false; comparator->function = 0; target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); @@ -1859,7 +2000,7 @@ static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dw { struct dwt_reg_state *state; - state = calloc(1, sizeof *state); + state = calloc(1, sizeof(*state)); if (!state) return; state->addr = d->addr; @@ -1886,6 +2027,9 @@ void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) return; } + target_read_u32(target, DWT_DEVARCH, &cm->dwt_devarch); + LOG_DEBUG("DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); + cm->dwt_num_comp = (dwtcr >> 28) & 0xF; cm->dwt_comp_available = cm->dwt_num_comp; cm->dwt_comparator_list = calloc(cm->dwt_num_comp, @@ -1897,7 +2041,7 @@ fail0: return; } - cache = calloc(1, sizeof *cache); + cache = calloc(1, sizeof(*cache)); if (!cache) { fail1: free(cm->dwt_comparator_list); @@ -1905,7 +2049,7 @@ fail1: } cache->name = "Cortex-M DWT registers"; cache->num_regs = 2 + cm->dwt_num_comp * 3; - cache->reg_list = calloc(cache->num_regs, sizeof *cache->reg_list); + cache->reg_list = calloc(cache->num_regs, sizeof(*cache->reg_list)); if (!cache->reg_list) { free(cache); goto fail1; @@ -1974,6 +2118,15 @@ static void cortex_m_dwt_free(struct target *target) #define MVFR1_DEFAULT_M7_SP 0x11000011 #define MVFR1_DEFAULT_M7_DP 0x12000011 +static int cortex_m_find_mem_ap(struct adiv5_dap *swjdp, + struct adiv5_ap **debug_ap) +{ + if (dap_find_ap(swjdp, AP_TYPE_AHB3_AP, debug_ap) == ERROR_OK) + return ERROR_OK; + + return dap_find_ap(swjdp, AP_TYPE_AHB5_AP, debug_ap); +} + int cortex_m_examine(struct target *target) { int retval; @@ -1988,7 +2141,7 @@ int cortex_m_examine(struct target *target) if (!armv7m->stlink) { if (cortex_m->apsel == DP_APSEL_INVALID) { /* Search for the MEM-AP */ - retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap); + retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not find MEM-AP to control the core"); return retval; @@ -2016,17 +2169,45 @@ int cortex_m_examine(struct target *target) /* Get CPU Type */ i = (cpuid >> 4) & 0xf; + /* Check if it is an ARMv8-M core */ + armv7m->arm.is_armv8m = true; + + switch (cpuid & ARM_CPUID_PARTNO_MASK) { + case CORTEX_M23_PARTNO: + i = 23; + break; + case CORTEX_M33_PARTNO: + i = 33; + break; + case CORTEX_M35P_PARTNO: + i = 35; + break; + case CORTEX_M55_PARTNO: + i = 55; + break; + default: + armv7m->arm.is_armv8m = false; + break; + } + + LOG_DEBUG("Cortex-M%d r%" PRId8 "p%" PRId8 " processor detected", i, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); + cortex_m->maskints_erratum = false; if (i == 7) { uint8_t rev, patch; rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; - if ((rev == 0) && (patch < 2)) - LOG_WARNING("Silicon bug: single stepping will enter pending exception handler!"); + if ((rev == 0) && (patch < 2)) { + LOG_WARNING("Silicon bug: single stepping may enter pending exception handler!"); + cortex_m->maskints_erratum = true; + } } LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid); + /* VECTRESET is not supported on Cortex-M0, M0+ and M1 */ + cortex_m->vectreset_supported = i > 1; + if (i == 4) { target_read_u32(target, MVFR0, &mvfr0); target_read_u32(target, MVFR1, &mvfr1); @@ -2036,7 +2217,7 @@ int cortex_m_examine(struct target *target) LOG_DEBUG("Cortex-M%d floating point feature FPv4_SP found", i); armv7m->fp_feature = FPv4_SP; } - } else if (i == 7) { + } else if (i == 7 || i == 33 || i == 35 || i == 55) { target_read_u32(target, MVFR0, &mvfr0); target_read_u32(target, MVFR1, &mvfr1); @@ -2078,6 +2259,19 @@ int cortex_m_examine(struct target *target) armv7m->debug_ap->tar_autoincr_block = (1 << 10); } + /* Enable debug requests */ + retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr); + if (retval != ERROR_OK) + return retval; + if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { + 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)); + if (retval != ERROR_OK) + return retval; + cortex_m->dcb_dhcsr = dhcsr; + } + /* Configure trace modules */ retval = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr); if (retval != ERROR_OK) @@ -2095,7 +2289,6 @@ int cortex_m_examine(struct target *target) /* bits [14:12] and [7:4] */ cortex_m->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF); cortex_m->fp_num_lit = (fpcr >> 8) & 0xF; - cortex_m->fp_code_available = cortex_m->fp_num_code; /* Detect flash patch revision, see RM DDI 0403E.b page C1-817. Revision is zero base, fp_rev == 1 means Rev.2 ! */ cortex_m->fp_rev = (fpcr >> 28) & 0xf; @@ -2237,21 +2430,27 @@ static int cortex_m_init_arch_info(struct target *target, armv7m->load_core_reg_u32 = cortex_m_load_core_reg_u32; armv7m->store_core_reg_u32 = cortex_m_store_core_reg_u32; - target_register_timer_callback(cortex_m_handle_target_request, 1, 1, target); + target_register_timer_callback(cortex_m_handle_target_request, 1, + TARGET_TIMER_TYPE_PERIODIC, target); return ERROR_OK; } static int cortex_m_target_create(struct target *target, Jim_Interp *interp) { - struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); - cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; struct adiv5_private_config *pc; pc = (struct adiv5_private_config *)target->private_config; if (adiv5_verify_config(pc) != ERROR_OK) return ERROR_FAIL; + struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); + if (cortex_m == NULL) { + LOG_ERROR("No memory creating target"); + return ERROR_FAIL; + } + + cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; cortex_m->apsel = pc->ap_num; cortex_m_init_arch_info(target, cortex_m, pc->dap); @@ -2261,11 +2460,11 @@ static int cortex_m_target_create(struct target *target, Jim_Interp *interp) /*--------------------------------------------------------------------------*/ -static int cortex_m_verify_pointer(struct command_context *cmd_ctx, +static int cortex_m_verify_pointer(struct command_invocation *cmd, struct cortex_m_common *cm) { if (cm->common_magic != CORTEX_M_COMMON_MAGIC) { - command_print(cmd_ctx, "target is not a Cortex-M"); + command_print(cmd, "target is not a Cortex-M"); return ERROR_TARGET_INVALID; } return ERROR_OK; @@ -2299,7 +2498,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) { "reset", VC_CORERESET, }, }; - retval = cortex_m_verify_pointer(CMD_CTX, cortex_m); + retval = cortex_m_verify_pointer(CMD, cortex_m); if (retval != ERROR_OK) return retval; @@ -2354,7 +2553,7 @@ write: } for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) { - command_print(CMD_CTX, "%9s: %s", vec_ids[i].name, + command_print(CMD, "%9s: %s", vec_ids[i].name, (demcr & vec_ids[i].mask) ? "catch" : "ignore"); } @@ -2371,17 +2570,18 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) { .name = "auto", .value = CORTEX_M_ISRMASK_AUTO }, { .name = "off", .value = CORTEX_M_ISRMASK_OFF }, { .name = "on", .value = CORTEX_M_ISRMASK_ON }, + { .name = "steponly", .value = CORTEX_M_ISRMASK_STEPONLY }, { .name = NULL, .value = -1 }, }; const Jim_Nvp *n; - retval = cortex_m_verify_pointer(CMD_CTX, cortex_m); + retval = cortex_m_verify_pointer(CMD, cortex_m); 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, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } @@ -2390,16 +2590,11 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) if (n->name == NULL) return ERROR_COMMAND_SYNTAX_ERROR; cortex_m->isrmasking_mode = n->value; - - - if (cortex_m->isrmasking_mode == CORTEX_M_ISRMASK_ON) - cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); - else - cortex_m_write_debug_halt_mask(target, C_HALT, C_MASKINTS); + cortex_m_set_maskints_for_halt(target); } n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, cortex_m->isrmasking_mode); - command_print(CMD_CTX, "cortex_m interrupt mask %s", n->name); + command_print(CMD, "cortex_m interrupt mask %s", n->name); return ERROR_OK; } @@ -2411,15 +2606,23 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) int retval; char *reset_config; - retval = cortex_m_verify_pointer(CMD_CTX, cortex_m); + retval = cortex_m_verify_pointer(CMD, cortex_m); if (retval != ERROR_OK) return retval; if (CMD_ARGC > 0) { if (strcmp(*CMD_ARGV, "sysresetreq") == 0) cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ; - else if (strcmp(*CMD_ARGV, "vectreset") == 0) - cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; + + else if (strcmp(*CMD_ARGV, "vectreset") == 0) { + if (target_was_examined(target) + && !cortex_m->vectreset_supported) + LOG_WARNING("VECTRESET is not supported on your Cortex-M core!"); + else + cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; + + } else + return ERROR_COMMAND_SYNTAX_ERROR; } switch (cortex_m->soft_reset_config) { @@ -2436,7 +2639,7 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) break; } - command_print(CMD_CTX, "cortex_m reset_config %s", reset_config); + command_print(CMD, "cortex_m reset_config %s", reset_config); return ERROR_OK; } @@ -2447,7 +2650,7 @@ static const struct command_registration cortex_m_exec_command_handlers[] = { .handler = handle_cortex_m_mask_interrupts_command, .mode = COMMAND_EXEC, .help = "mask cortex_m interrupts", - .usage = "['auto'|'on'|'off']", + .usage = "['auto'|'on'|'off'|'steponly']", }, { .name = "vector_catch", @@ -2461,7 +2664,7 @@ static const struct command_registration cortex_m_exec_command_handlers[] = { .handler = handle_cortex_m_reset_config_command, .mode = COMMAND_ANY, .help = "configure software reset handling", - .usage = "['srst'|'sysresetreq'|'vectreset']", + .usage = "['sysresetreq'|'vectreset']", }, COMMAND_REGISTRATION_DONE }; @@ -2499,6 +2702,7 @@ struct target_type cortexm_target = { .deassert_reset = cortex_m_deassert_reset, .soft_reset_halt = cortex_m_soft_reset_halt, + .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = armv7m_get_gdb_reg_list, .read_memory = cortex_m_read_memory,