X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fcortex_m.c;h=e2960391c21b44d5d79217576da9277d57dbd31c;hp=06e1c1c754ce5f0716a227445a121f1f15f7fa2f;hb=02cd1e39cc710a6a6592486238c15f7b42c7d21c;hpb=d140fb27c6afbfa1fe609b5f0db274d4a5273483 diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 06e1c1c754..e2960391c2 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -136,6 +136,83 @@ static int cortex_m_write_debug_halt_mask(struct target *target, 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; } @@ -405,6 +481,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) @@ -510,7 +590,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; } @@ -611,6 +694,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; @@ -764,6 +851,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; @@ -826,10 +914,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. * @@ -868,25 +958,38 @@ 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); + /* 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 */ @@ -914,12 +1017,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); } } } @@ -1021,8 +1126,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); @@ -1094,7 +1198,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); @@ -1154,7 +1258,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; @@ -1170,7 +1274,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); @@ -1185,7 +1289,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]; @@ -1244,23 +1348,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, - breakpoint->orig_instr); - if (retval != ERROR_OK) - return retval; - } else { - retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 2, 1, + retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, + breakpoint->length, 1, breakpoint->orig_instr); - if (retval != ERROR_OK) - return retval; - } + if (retval != ERROR_OK) + return retval; } breakpoint->set = false; @@ -1269,13 +1367,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; @@ -1286,29 +1377,15 @@ 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) @@ -1341,7 +1418,7 @@ 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; @@ -1398,7 +1475,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); @@ -2037,12 +2114,15 @@ int cortex_m_examine(struct target *target) 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); @@ -2117,7 +2197,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; @@ -2259,21 +2338,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); @@ -2283,11 +2368,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; @@ -2321,7 +2406,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; @@ -2376,7 +2461,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"); } @@ -2393,17 +2478,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; } @@ -2412,16 +2498,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; } @@ -2433,7 +2514,7 @@ 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; @@ -2466,7 +2547,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; } @@ -2477,7 +2558,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",