uint32_t num, uint32_t value);
static void cortex_m_dwt_free(struct target *target);
-static int cortexm_dap_read_coreregister_u32(struct target *target,
- uint32_t *value, int regnum)
+static int cortex_m_load_core_reg_u32(struct target *target,
+ uint32_t regsel, uint32_t *value)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
int retval;
return retval;
}
- retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regnum);
+ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel);
if (retval != ERROR_OK)
return retval;
return retval;
}
-static int cortexm_dap_write_coreregister_u32(struct target *target,
- uint32_t value, int regnum)
+static int cortex_m_store_core_reg_u32(struct target *target,
+ uint32_t regsel, uint32_t value)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
int retval;
if (retval != ERROR_OK)
return retval;
- retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRSR, regnum | DCRSR_WnR);
+ retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRSR, regsel | DCRSR_WnR);
if (retval != ERROR_OK)
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);
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 */
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;
arm->map = armv7m_msp_reg_map;
} else {
unsigned control = buf_get_u32(arm->core_cache
- ->reg_list[ARMV7M_CONTROL].value, 0, 2);
+ ->reg_list[ARMV7M_CONTROL].value, 0, 3);
/* is this thread privileged? */
arm->core_mode = control & 1
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) {
}
}
- /* REVISIT when S_SLEEP is set, it's in a Sleep or DeepSleep state.
- * How best to model low power modes?
- */
-
if (target->state == TARGET_UNKNOWN) {
- /* check if processor is retiring instructions */
- if (cortex_m->dcb_dhcsr & S_RETIRE_ST) {
+ /* check if processor is retiring instructions or sleeping */
+ if (cortex_m->dcb_dhcsr & S_RETIRE_ST || cortex_m->dcb_dhcsr & S_SLEEP) {
target->state = TARGET_RUNNING;
retval = ERROR_OK;
}
* 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
return cortex_m_unset_breakpoint(target, breakpoint);
}
-int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint)
+static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint)
{
int dwt_num = 0;
struct cortex_m_common *cortex_m = target_to_cm(target);
return ERROR_OK;
}
-int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint)
+static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint)
{
struct cortex_m_common *cortex_m = target_to_cm(target);
struct cortex_m_dwt_comparator *comparator;
}
}
-static int cortex_m_load_core_reg_u32(struct target *target,
- uint32_t num, uint32_t *value)
-{
- int retval;
-
- /* NOTE: we "know" here that the register identifiers used
- * in the v7m header match the Cortex-M3 Debug Core Register
- * Selector values for R0..R15, xPSR, MSP, and PSP.
- */
- switch (num) {
- case 0 ... 18:
- /* read a normal core register */
- retval = cortexm_dap_read_coreregister_u32(target, value, num);
-
- if (retval != ERROR_OK) {
- LOG_ERROR("JTAG failure %i", retval);
- return ERROR_JTAG_DEVICE_ERROR;
- }
- LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value);
- break;
-
- case ARMV7M_FPSCR:
- /* Floating-point Status and Registers */
- retval = target_write_u32(target, DCB_DCRSR, 0x21);
- if (retval != ERROR_OK)
- return retval;
- retval = target_read_u32(target, DCB_DCRDR, value);
- if (retval != ERROR_OK)
- return retval;
- LOG_DEBUG("load from FPSCR value 0x%" PRIx32, *value);
- break;
-
- case ARMV7M_S0 ... ARMV7M_S31:
- /* Floating-point Status and Registers */
- retval = target_write_u32(target, DCB_DCRSR, num - ARMV7M_S0 + 0x40);
- if (retval != ERROR_OK)
- return retval;
- retval = target_read_u32(target, DCB_DCRDR, value);
- if (retval != ERROR_OK)
- return retval;
- LOG_DEBUG("load from FPU reg S%d value 0x%" PRIx32,
- (int)(num - ARMV7M_S0), *value);
- break;
-
- case ARMV7M_PRIMASK:
- case ARMV7M_BASEPRI:
- case ARMV7M_FAULTMASK:
- case ARMV7M_CONTROL:
- /* Cortex-M3 packages these four registers as bitfields
- * in one Debug Core register. So say r0 and r2 docs;
- * it was removed from r1 docs, but still works.
- */
- cortexm_dap_read_coreregister_u32(target, value, 20);
-
- switch (num) {
- case ARMV7M_PRIMASK:
- *value = buf_get_u32((uint8_t *)value, 0, 1);
- break;
-
- case ARMV7M_BASEPRI:
- *value = buf_get_u32((uint8_t *)value, 8, 8);
- break;
-
- case ARMV7M_FAULTMASK:
- *value = buf_get_u32((uint8_t *)value, 16, 1);
- break;
-
- case ARMV7M_CONTROL:
- *value = buf_get_u32((uint8_t *)value, 24, 2);
- break;
- }
-
- LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", (int)num, *value);
- break;
-
- default:
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- return ERROR_OK;
-}
-
-static int cortex_m_store_core_reg_u32(struct target *target,
- uint32_t num, uint32_t value)
-{
- int retval;
- uint32_t reg;
- struct armv7m_common *armv7m = target_to_armv7m(target);
-
- /* NOTE: we "know" here that the register identifiers used
- * in the v7m header match the Cortex-M3 Debug Core Register
- * Selector values for R0..R15, xPSR, MSP, and PSP.
- */
- switch (num) {
- case 0 ... 18:
- retval = cortexm_dap_write_coreregister_u32(target, value, num);
- if (retval != ERROR_OK) {
- struct reg *r;
-
- LOG_ERROR("JTAG failure");
- r = armv7m->arm.core_cache->reg_list + num;
- r->dirty = r->valid;
- return ERROR_JTAG_DEVICE_ERROR;
- }
- LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
- break;
-
- case ARMV7M_FPSCR:
- /* Floating-point Status and Registers */
- retval = target_write_u32(target, DCB_DCRDR, value);
- if (retval != ERROR_OK)
- return retval;
- retval = target_write_u32(target, DCB_DCRSR, 0x21 | (1<<16));
- if (retval != ERROR_OK)
- return retval;
- LOG_DEBUG("write FPSCR value 0x%" PRIx32, value);
- break;
-
- case ARMV7M_S0 ... ARMV7M_S31:
- /* Floating-point Status and Registers */
- retval = target_write_u32(target, DCB_DCRDR, value);
- if (retval != ERROR_OK)
- return retval;
- retval = target_write_u32(target, DCB_DCRSR, (num - ARMV7M_S0 + 0x40) | (1<<16));
- if (retval != ERROR_OK)
- return retval;
- LOG_DEBUG("write FPU reg S%d value 0x%" PRIx32,
- (int)(num - ARMV7M_S0), value);
- break;
-
- case ARMV7M_PRIMASK:
- case ARMV7M_BASEPRI:
- case ARMV7M_FAULTMASK:
- case ARMV7M_CONTROL:
- /* Cortex-M3 packages these four registers as bitfields
- * in one Debug Core register. So say r0 and r2 docs;
- * it was removed from r1 docs, but still works.
- */
- cortexm_dap_read_coreregister_u32(target, ®, 20);
-
- switch (num) {
- case ARMV7M_PRIMASK:
- buf_set_u32((uint8_t *)®, 0, 1, value);
- break;
-
- case ARMV7M_BASEPRI:
- buf_set_u32((uint8_t *)®, 8, 8, value);
- break;
-
- case ARMV7M_FAULTMASK:
- buf_set_u32((uint8_t *)®, 16, 1, value);
- break;
-
- case ARMV7M_CONTROL:
- buf_set_u32((uint8_t *)®, 24, 2, value);
- break;
- }
-
- cortexm_dap_write_coreregister_u32(target, reg, 20);
-
- LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value);
- break;
-
- default:
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- return ERROR_OK;
-}
-
static int cortex_m_read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
struct timeval timeout, now;
struct armv7m_common *armv7m = target_to_armv7m(target);
uint32_t reg_value;
- bool use_pcsr = false;
- int retval = ERROR_OK;
- struct reg *reg;
-
- gettimeofday(&timeout, NULL);
- timeval_add_time(&timeout, seconds, 0);
+ int retval;
retval = target_read_u32(target, DWT_PCSR, ®_value);
if (retval != ERROR_OK) {
LOG_ERROR("Error while reading PCSR");
return retval;
}
-
- if (reg_value != 0) {
- use_pcsr = true;
- LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can...");
- } else {
- LOG_INFO("Starting profiling. Halting and resuming the"
- " target as often as we can...");
- reg = register_get_by_name(target->reg_cache, "pc", 1);
+ if (reg_value == 0) {
+ LOG_INFO("PCSR sampling not supported on this processor.");
+ return target_profiling_default(target, samples, max_num_samples, num_samples, seconds);
}
+ gettimeofday(&timeout, NULL);
+ timeval_add_time(&timeout, seconds, 0);
+
+ LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can...");
+
/* Make sure the target is running */
target_poll(target);
if (target->state == TARGET_HALTED)
uint32_t sample_count = 0;
for (;;) {
- if (use_pcsr) {
- if (armv7m && armv7m->debug_ap) {
- uint32_t read_count = max_num_samples - sample_count;
- if (read_count > 1024)
- read_count = 1024;
-
- retval = mem_ap_read_buf_noincr(armv7m->debug_ap,
- (void *)&samples[sample_count],
- 4, read_count, DWT_PCSR);
- sample_count += read_count;
- } else {
- target_read_u32(target, DWT_PCSR, &samples[sample_count++]);
- }
+ if (armv7m && armv7m->debug_ap) {
+ uint32_t read_count = max_num_samples - sample_count;
+ if (read_count > 1024)
+ read_count = 1024;
+
+ retval = mem_ap_read_buf_noincr(armv7m->debug_ap,
+ (void *)&samples[sample_count],
+ 4, read_count, DWT_PCSR);
+ sample_count += read_count;
} else {
- target_poll(target);
- if (target->state == TARGET_HALTED) {
- reg_value = buf_get_u32(reg->value, 0, 32);
- /* current pc, addr = 0, do not handle breakpoints, not debugging */
- retval = target_resume(target, 1, 0, 0, 0);
- samples[sample_count++] = reg_value;
- target_poll(target);
- alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
- } else if (target->state == TARGET_RUNNING) {
- /* We want to quickly sample the PC. */
- retval = target_halt(target);
- } else {
- LOG_INFO("Target not halted or running");
- retval = ERROR_OK;
- break;
- }
+ target_read_u32(target, DWT_PCSR, &samples[sample_count++]);
}
if (retval != ERROR_OK) {
- LOG_ERROR("Error while reading %s", use_pcsr ? "PCSR" : "target pc");
+ LOG_ERROR("Error while reading PCSR");
return retval;
}
r->type = &dwt_reg_type;
}
-void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target)
+static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target)
{
uint32_t dwtcr;
struct reg_cache *cache;
/* 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 floating point feature FPv4_SP found", i);
armv7m->fp_feature = FPv4_SP;
}
- } else if (i == 7 || i == 33) {
+ } else if (i == 7 || i == 33 || i == 35 || i == 55) {
target_read_u32(target, MVFR0, &mvfr0);
target_read_u32(target, MVFR1, &mvfr1);
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)
if (retval != ERROR_OK)
return retval;
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_FAIL;
+ }
+
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &demcr);
if (retval != ERROR_OK)
return retval;