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);
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.
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++) {
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;
}
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)
}
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;
}
}
}
+ /* 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;
/* 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;
}
/* 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;
* 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.
*
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 */
"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);
}
}
}
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);
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;
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);
return retval;
}
- cortex_m->fpb_enabled = 1;
+ cortex_m->fpb_enabled = true;
}
} else if (breakpoint->type == BKPT_SOFT) {
uint8_t code[4];
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;
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;
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)
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;
}
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);
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);
/* 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;
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);
/*--------------------------------------------------------------------------*/
-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;
{ "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;
}
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");
}
{ .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;
}
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;
}
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;
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) {
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;
}
.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",
.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
};
.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,