|
|
@ -60,23 +60,23 @@ const struct command_s cortexm_cmd_list[] = { |
|
|
|
#define SIGSEGV 11 |
|
|
|
#define SIGLOST 29 |
|
|
|
|
|
|
|
static int cortexm_regs_read(struct target_s *target, void *data); |
|
|
|
static int cortexm_regs_write(struct target_s *target, const void *data); |
|
|
|
static int cortexm_pc_write(struct target_s *target, const uint32_t val); |
|
|
|
static uint32_t cortexm_pc_read(struct target_s *target); |
|
|
|
static int cortexm_regs_read(target *t, void *data); |
|
|
|
static int cortexm_regs_write(target *t, const void *data); |
|
|
|
static int cortexm_pc_write(target *t, const uint32_t val); |
|
|
|
static uint32_t cortexm_pc_read(target *t); |
|
|
|
|
|
|
|
static void cortexm_reset(struct target_s *target); |
|
|
|
static int cortexm_halt_wait(struct target_s *target); |
|
|
|
static void cortexm_halt_request(struct target_s *target); |
|
|
|
static int cortexm_fault_unwind(struct target_s *target); |
|
|
|
static void cortexm_reset(target *t); |
|
|
|
static int cortexm_halt_wait(target *t); |
|
|
|
static void cortexm_halt_request(target *t); |
|
|
|
static int cortexm_fault_unwind(target *t); |
|
|
|
|
|
|
|
static int cortexm_set_hw_bp(struct target_s *target, uint32_t addr); |
|
|
|
static int cortexm_clear_hw_bp(struct target_s *target, uint32_t addr); |
|
|
|
static int cortexm_set_hw_bp(target *t, uint32_t addr); |
|
|
|
static int cortexm_clear_hw_bp(target *t, uint32_t addr); |
|
|
|
|
|
|
|
static int cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len); |
|
|
|
static int cortexm_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len); |
|
|
|
static int cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len); |
|
|
|
static int cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len); |
|
|
|
|
|
|
|
static int cortexm_check_hw_wp(struct target_s *target, uint32_t *addr); |
|
|
|
static int cortexm_check_hw_wp(target *t, uint32_t *addr); |
|
|
|
|
|
|
|
#define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */ |
|
|
|
#define CORTEXM_MAX_BREAKPOINTS 6 /* architecture says up to 127, no implementation has > 6 */ |
|
|
@ -207,42 +207,41 @@ static const char tdesc_cortex_mf[] = |
|
|
|
#define REG_PSP 18 |
|
|
|
#define REG_SPECIAL 19 |
|
|
|
|
|
|
|
bool |
|
|
|
cortexm_probe(struct target_s *target) |
|
|
|
bool cortexm_probe(target *t) |
|
|
|
{ |
|
|
|
target->driver = cortexm_driver_str; |
|
|
|
t->driver = cortexm_driver_str; |
|
|
|
|
|
|
|
target->attach = cortexm_attach; |
|
|
|
target->detach = cortexm_detach; |
|
|
|
t->attach = cortexm_attach; |
|
|
|
t->detach = cortexm_detach; |
|
|
|
|
|
|
|
/* Should probe here to make sure it's Cortex-M3 */ |
|
|
|
target->tdesc = tdesc_cortex_m; |
|
|
|
target->regs_read = cortexm_regs_read; |
|
|
|
target->regs_write = cortexm_regs_write; |
|
|
|
target->pc_write = cortexm_pc_write; |
|
|
|
target->pc_read = cortexm_pc_read; |
|
|
|
t->tdesc = tdesc_cortex_m; |
|
|
|
t->regs_read = cortexm_regs_read; |
|
|
|
t->regs_write = cortexm_regs_write; |
|
|
|
t->pc_write = cortexm_pc_write; |
|
|
|
t->pc_read = cortexm_pc_read; |
|
|
|
|
|
|
|
target->reset = cortexm_reset; |
|
|
|
target->halt_request = cortexm_halt_request; |
|
|
|
target->halt_wait = cortexm_halt_wait; |
|
|
|
target->halt_resume = cortexm_halt_resume; |
|
|
|
target->regs_size = sizeof(regnum_cortex_m); |
|
|
|
t->reset = cortexm_reset; |
|
|
|
t->halt_request = cortexm_halt_request; |
|
|
|
t->halt_wait = cortexm_halt_wait; |
|
|
|
t->halt_resume = cortexm_halt_resume; |
|
|
|
t->regs_size = sizeof(regnum_cortex_m); |
|
|
|
|
|
|
|
target->hostio_reply = cortexm_hostio_reply; |
|
|
|
t->hostio_reply = cortexm_hostio_reply; |
|
|
|
|
|
|
|
target_add_commands(target, cortexm_cmd_list, cortexm_driver_str); |
|
|
|
target_add_commands(t, cortexm_cmd_list, cortexm_driver_str); |
|
|
|
|
|
|
|
/* Probe for FP extension */ |
|
|
|
uint32_t cpacr = target_mem_read32(target, CORTEXM_CPACR); |
|
|
|
uint32_t cpacr = target_mem_read32(t, CORTEXM_CPACR); |
|
|
|
cpacr |= 0x00F00000; /* CP10 = 0b11, CP11 = 0b11 */ |
|
|
|
target_mem_write32(target, CORTEXM_CPACR, cpacr); |
|
|
|
if (target_mem_read32(target, CORTEXM_CPACR) == cpacr) { |
|
|
|
target->target_options |= TOPT_FLAVOUR_V7MF; |
|
|
|
target->regs_size += sizeof(regnum_cortex_mf); |
|
|
|
target->tdesc = tdesc_cortex_mf; |
|
|
|
target_mem_write32(t, CORTEXM_CPACR, cpacr); |
|
|
|
if (target_mem_read32(t, CORTEXM_CPACR) == cpacr) { |
|
|
|
t->target_options |= TOPT_FLAVOUR_V7MF; |
|
|
|
t->regs_size += sizeof(regnum_cortex_mf); |
|
|
|
t->tdesc = tdesc_cortex_mf; |
|
|
|
} |
|
|
|
|
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = calloc(1, sizeof(*priv)); |
|
|
|
ap->priv = priv; |
|
|
|
ap->priv_free = free; |
|
|
@ -252,7 +251,7 @@ cortexm_probe(struct target_s *target) |
|
|
|
CORTEXM_DEMCR_VC_CORERESET; |
|
|
|
|
|
|
|
#define PROBE(x) \ |
|
|
|
do { if ((x)(target)) return true; else target_check_error(target); } while (0) |
|
|
|
do { if ((x)(t)) return true; else target_check_error(t); } while (0) |
|
|
|
|
|
|
|
PROBE(stm32f1_probe); |
|
|
|
PROBE(stm32f4_probe); |
|
|
@ -270,62 +269,62 @@ cortexm_probe(struct target_s *target) |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
bool cortexm_attach(struct target_s *target) |
|
|
|
bool cortexm_attach(target *t) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
unsigned i; |
|
|
|
uint32_t r; |
|
|
|
int tries; |
|
|
|
|
|
|
|
/* Clear any pending fault condition */ |
|
|
|
target_check_error(target); |
|
|
|
target_check_error(t); |
|
|
|
|
|
|
|
target_halt_request(target); |
|
|
|
target_halt_request(t); |
|
|
|
tries = 10; |
|
|
|
while(!connect_assert_srst && !target_halt_wait(target) && --tries) |
|
|
|
while(!connect_assert_srst && !target_halt_wait(t) && --tries) |
|
|
|
platform_delay(2); |
|
|
|
if(!tries) |
|
|
|
return false; |
|
|
|
|
|
|
|
/* Request halt on reset */ |
|
|
|
target_mem_write32(target, CORTEXM_DEMCR, priv->demcr); |
|
|
|
target_mem_write32(t, CORTEXM_DEMCR, priv->demcr); |
|
|
|
|
|
|
|
/* Reset DFSR flags */ |
|
|
|
target_mem_write32(target, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL); |
|
|
|
target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL); |
|
|
|
|
|
|
|
/* size the break/watchpoint units */ |
|
|
|
priv->hw_breakpoint_max = CORTEXM_MAX_BREAKPOINTS; |
|
|
|
r = target_mem_read32(target, CORTEXM_FPB_CTRL); |
|
|
|
r = target_mem_read32(t, CORTEXM_FPB_CTRL); |
|
|
|
if (((r >> 4) & 0xf) < priv->hw_breakpoint_max) /* only look at NUM_COMP1 */ |
|
|
|
priv->hw_breakpoint_max = (r >> 4) & 0xf; |
|
|
|
priv->hw_watchpoint_max = CORTEXM_MAX_WATCHPOINTS; |
|
|
|
r = target_mem_read32(target, CORTEXM_DWT_CTRL); |
|
|
|
r = target_mem_read32(t, CORTEXM_DWT_CTRL); |
|
|
|
if ((r >> 28) > priv->hw_watchpoint_max) |
|
|
|
priv->hw_watchpoint_max = r >> 28; |
|
|
|
|
|
|
|
/* Clear any stale breakpoints */ |
|
|
|
for(i = 0; i < priv->hw_breakpoint_max; i++) { |
|
|
|
target_mem_write32(target, CORTEXM_FPB_COMP(i), 0); |
|
|
|
target_mem_write32(t, CORTEXM_FPB_COMP(i), 0); |
|
|
|
priv->hw_breakpoint[i] = 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Clear any stale watchpoints */ |
|
|
|
for(i = 0; i < priv->hw_watchpoint_max; i++) { |
|
|
|
target_mem_write32(target, CORTEXM_DWT_FUNC(i), 0); |
|
|
|
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0); |
|
|
|
priv->hw_watchpoint[i].type = 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* Flash Patch Control Register: set ENABLE */ |
|
|
|
target_mem_write32(target, CORTEXM_FPB_CTRL, |
|
|
|
target_mem_write32(t, CORTEXM_FPB_CTRL, |
|
|
|
CORTEXM_FPB_CTRL_KEY | CORTEXM_FPB_CTRL_ENABLE); |
|
|
|
target->set_hw_bp = cortexm_set_hw_bp; |
|
|
|
target->clear_hw_bp = cortexm_clear_hw_bp; |
|
|
|
t->set_hw_bp = cortexm_set_hw_bp; |
|
|
|
t->clear_hw_bp = cortexm_clear_hw_bp; |
|
|
|
|
|
|
|
/* Data Watchpoint and Trace */ |
|
|
|
target->set_hw_wp = cortexm_set_hw_wp; |
|
|
|
target->clear_hw_wp = cortexm_clear_hw_wp; |
|
|
|
target->check_hw_wp = cortexm_check_hw_wp; |
|
|
|
t->set_hw_wp = cortexm_set_hw_wp; |
|
|
|
t->clear_hw_wp = cortexm_clear_hw_wp; |
|
|
|
t->check_hw_wp = cortexm_check_hw_wp; |
|
|
|
|
|
|
|
if(connect_assert_srst) |
|
|
|
jtagtap_srst(false); |
|
|
@ -333,28 +332,27 @@ bool cortexm_attach(struct target_s *target) |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
void cortexm_detach(struct target_s *target) |
|
|
|
void cortexm_detach(target *t) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
unsigned i; |
|
|
|
|
|
|
|
/* Clear any stale breakpoints */ |
|
|
|
for(i = 0; i < priv->hw_breakpoint_max; i++) |
|
|
|
target_mem_write32(target, CORTEXM_FPB_COMP(i), 0); |
|
|
|
target_mem_write32(t, CORTEXM_FPB_COMP(i), 0); |
|
|
|
|
|
|
|
/* Clear any stale watchpoints */ |
|
|
|
for(i = 0; i < priv->hw_watchpoint_max; i++) |
|
|
|
target_mem_write32(target, CORTEXM_DWT_FUNC(i), 0); |
|
|
|
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0); |
|
|
|
|
|
|
|
/* Disable debug */ |
|
|
|
target_mem_write32(target, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY); |
|
|
|
target_mem_write32(t, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY); |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_regs_read(struct target_s *target, void *data) |
|
|
|
static int cortexm_regs_read(target *t, void *data) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
uint32_t *regs = data; |
|
|
|
unsigned i; |
|
|
|
|
|
|
@ -375,7 +373,7 @@ cortexm_regs_read(struct target_s *target, void *data) |
|
|
|
regnum_cortex_m[i]); |
|
|
|
*regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(2)); |
|
|
|
} |
|
|
|
if (target->target_options & TOPT_FLAVOUR_V7MF) |
|
|
|
if (t->target_options & TOPT_FLAVOUR_V7MF) |
|
|
|
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) { |
|
|
|
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, |
|
|
|
ADIV5_AP_DB(1), |
|
|
@ -386,10 +384,9 @@ cortexm_regs_read(struct target_s *target, void *data) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_regs_write(struct target_s *target, const void *data) |
|
|
|
static int cortexm_regs_write(target *t, const void *data) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
const uint32_t *regs = data; |
|
|
|
unsigned i; |
|
|
|
|
|
|
@ -412,7 +409,7 @@ cortexm_regs_write(struct target_s *target, const void *data) |
|
|
|
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(1), |
|
|
|
0x10000 | regnum_cortex_m[i]); |
|
|
|
} |
|
|
|
if (target->target_options & TOPT_FLAVOUR_V7MF) |
|
|
|
if (t->target_options & TOPT_FLAVOUR_V7MF) |
|
|
|
for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) { |
|
|
|
adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, |
|
|
|
ADIV5_AP_DB(2), *regs++); |
|
|
@ -424,55 +421,51 @@ cortexm_regs_write(struct target_s *target, const void *data) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static uint32_t |
|
|
|
cortexm_pc_read(struct target_s *target) |
|
|
|
static uint32_t cortexm_pc_read(target *t) |
|
|
|
{ |
|
|
|
target_mem_write32(target, CORTEXM_DCRSR, 0x0F); |
|
|
|
return target_mem_read32(target, CORTEXM_DCRDR); |
|
|
|
target_mem_write32(t, CORTEXM_DCRSR, 0x0F); |
|
|
|
return target_mem_read32(t, CORTEXM_DCRDR); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_pc_write(struct target_s *target, const uint32_t val) |
|
|
|
static int cortexm_pc_write(target *t, const uint32_t val) |
|
|
|
{ |
|
|
|
target_mem_write32(target, CORTEXM_DCRDR, val); |
|
|
|
target_mem_write32(target, CORTEXM_DCRSR, CORTEXM_DCRSR_REGWnR | 0x0F); |
|
|
|
target_mem_write32(t, CORTEXM_DCRDR, val); |
|
|
|
target_mem_write32(t, CORTEXM_DCRSR, CORTEXM_DCRSR_REGWnR | 0x0F); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* The following three routines implement target halt/resume
|
|
|
|
* using the core debug registers in the NVIC. */ |
|
|
|
static void |
|
|
|
cortexm_reset(struct target_s *target) |
|
|
|
static void cortexm_reset(target *t) |
|
|
|
{ |
|
|
|
jtagtap_srst(true); |
|
|
|
jtagtap_srst(false); |
|
|
|
|
|
|
|
/* Read DHCSR here to clear S_RESET_ST bit before reset */ |
|
|
|
target_mem_read32(target, CORTEXM_DHCSR); |
|
|
|
target_mem_read32(t, CORTEXM_DHCSR); |
|
|
|
|
|
|
|
/* Request system reset from NVIC: SRST doesn't work correctly */ |
|
|
|
/* This could be VECTRESET: 0x05FA0001 (reset only core)
|
|
|
|
* or SYSRESETREQ: 0x05FA0004 (system reset) |
|
|
|
*/ |
|
|
|
target_mem_write32(target, CORTEXM_AIRCR, |
|
|
|
target_mem_write32(t, CORTEXM_AIRCR, |
|
|
|
CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ); |
|
|
|
|
|
|
|
/* Poll for release from reset */ |
|
|
|
while (target_mem_read32(target, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST); |
|
|
|
while (target_mem_read32(t, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST); |
|
|
|
|
|
|
|
/* Reset DFSR flags */ |
|
|
|
target_mem_write32(target, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL); |
|
|
|
target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL); |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
cortexm_halt_request(struct target_s *target) |
|
|
|
static void cortexm_halt_request(target *t) |
|
|
|
{ |
|
|
|
volatile struct exception e; |
|
|
|
TRY_CATCH (e, EXCEPTION_TIMEOUT) { |
|
|
|
target_mem_write32(target, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY | |
|
|
|
target_mem_write32(t, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY | |
|
|
|
CORTEXM_DHCSR_C_HALT | |
|
|
|
CORTEXM_DHCSR_C_DEBUGEN); |
|
|
|
} |
|
|
@ -481,10 +474,9 @@ cortexm_halt_request(struct target_s *target) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_halt_wait(struct target_s *target) |
|
|
|
static int cortexm_halt_wait(target *t) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
|
|
|
|
uint32_t dhcsr = 0; |
|
|
@ -492,7 +484,7 @@ cortexm_halt_wait(struct target_s *target) |
|
|
|
TRY_CATCH (e, EXCEPTION_ALL) { |
|
|
|
/* If this times out because the target is in WFI then
|
|
|
|
* the target is still running. */ |
|
|
|
dhcsr = target_mem_read32(target, CORTEXM_DHCSR); |
|
|
|
dhcsr = target_mem_read32(t, CORTEXM_DHCSR); |
|
|
|
} |
|
|
|
switch (e.type) { |
|
|
|
case EXCEPTION_ERROR: |
|
|
@ -509,10 +501,10 @@ cortexm_halt_wait(struct target_s *target) |
|
|
|
return 0; |
|
|
|
|
|
|
|
/* We've halted. Let's find out why. */ |
|
|
|
uint32_t dfsr = target_mem_read32(target, CORTEXM_DFSR); |
|
|
|
target_mem_write32(target, CORTEXM_DFSR, dfsr); /* write back to reset */ |
|
|
|
uint32_t dfsr = target_mem_read32(t, CORTEXM_DFSR); |
|
|
|
target_mem_write32(t, CORTEXM_DFSR, dfsr); /* write back to reset */ |
|
|
|
|
|
|
|
if ((dfsr & CORTEXM_DFSR_VCATCH) && cortexm_fault_unwind(target)) |
|
|
|
if ((dfsr & CORTEXM_DFSR_VCATCH) && cortexm_fault_unwind(t)) |
|
|
|
return SIGSEGV; |
|
|
|
|
|
|
|
/* Remember if we stopped on a breakpoint */ |
|
|
@ -520,13 +512,13 @@ cortexm_halt_wait(struct target_s *target) |
|
|
|
if (priv->on_bkpt) { |
|
|
|
/* If we've hit a programmed breakpoint, check for semihosting
|
|
|
|
* call. */ |
|
|
|
uint32_t pc = cortexm_pc_read(target); |
|
|
|
uint32_t pc = cortexm_pc_read(t); |
|
|
|
uint16_t bkpt_instr; |
|
|
|
bkpt_instr = target_mem_read16(target, pc); |
|
|
|
bkpt_instr = target_mem_read16(t, pc); |
|
|
|
if (bkpt_instr == 0xBEAB) { |
|
|
|
int n = cortexm_hostio_request(target); |
|
|
|
int n = cortexm_hostio_request(t); |
|
|
|
if (n > 0) { |
|
|
|
target_halt_resume(target, priv->stepping); |
|
|
|
target_halt_resume(t, priv->stepping); |
|
|
|
return 0; |
|
|
|
} else if (n < 0) { |
|
|
|
return -1; |
|
|
@ -544,9 +536,9 @@ cortexm_halt_wait(struct target_s *target) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void cortexm_halt_resume(struct target_s *target, bool step) |
|
|
|
void cortexm_halt_resume(target *t, bool step) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
uint32_t dhcsr = CORTEXM_DHCSR_DBGKEY | CORTEXM_DHCSR_C_DEBUGEN; |
|
|
|
|
|
|
@ -555,42 +547,42 @@ void cortexm_halt_resume(struct target_s *target, bool step) |
|
|
|
|
|
|
|
/* Disable interrupts while single stepping... */ |
|
|
|
if(step != priv->stepping) { |
|
|
|
target_mem_write32(target, CORTEXM_DHCSR, dhcsr | CORTEXM_DHCSR_C_HALT); |
|
|
|
target_mem_write32(t, CORTEXM_DHCSR, dhcsr | CORTEXM_DHCSR_C_HALT); |
|
|
|
priv->stepping = step; |
|
|
|
} |
|
|
|
|
|
|
|
if (priv->on_bkpt) { |
|
|
|
uint32_t pc = cortexm_pc_read(target); |
|
|
|
if ((target_mem_read16(target, pc) & 0xFF00) == 0xBE00) |
|
|
|
cortexm_pc_write(target, pc + 2); |
|
|
|
uint32_t pc = cortexm_pc_read(t); |
|
|
|
if ((target_mem_read16(t, pc) & 0xFF00) == 0xBE00) |
|
|
|
cortexm_pc_write(t, pc + 2); |
|
|
|
} |
|
|
|
|
|
|
|
target_mem_write32(target, CORTEXM_DHCSR, dhcsr); |
|
|
|
target_mem_write32(t, CORTEXM_DHCSR, dhcsr); |
|
|
|
} |
|
|
|
|
|
|
|
static int cortexm_fault_unwind(struct target_s *target) |
|
|
|
static int cortexm_fault_unwind(target *t) |
|
|
|
{ |
|
|
|
uint32_t hfsr = target_mem_read32(target, CORTEXM_HFSR); |
|
|
|
uint32_t cfsr = target_mem_read32(target, CORTEXM_CFSR); |
|
|
|
target_mem_write32(target, CORTEXM_HFSR, hfsr);/* write back to reset */ |
|
|
|
target_mem_write32(target, CORTEXM_CFSR, cfsr);/* write back to reset */ |
|
|
|
uint32_t hfsr = target_mem_read32(t, CORTEXM_HFSR); |
|
|
|
uint32_t cfsr = target_mem_read32(t, CORTEXM_CFSR); |
|
|
|
target_mem_write32(t, CORTEXM_HFSR, hfsr);/* write back to reset */ |
|
|
|
target_mem_write32(t, CORTEXM_CFSR, cfsr);/* write back to reset */ |
|
|
|
/* We check for FORCED in the HardFault Status Register or
|
|
|
|
* for a configurable fault to avoid catching core resets */ |
|
|
|
if((hfsr & CORTEXM_HFSR_FORCED) || cfsr) { |
|
|
|
/* Unwind exception */ |
|
|
|
uint32_t regs[target->regs_size / 4]; |
|
|
|
uint32_t regs[t->regs_size / 4]; |
|
|
|
uint32_t stack[8]; |
|
|
|
uint32_t retcode, framesize; |
|
|
|
/* Read registers for post-exception stack pointer */ |
|
|
|
target_regs_read(target, regs); |
|
|
|
target_regs_read(t, regs); |
|
|
|
/* save retcode currently in lr */ |
|
|
|
retcode = regs[REG_LR]; |
|
|
|
bool spsel = retcode & (1<<2); |
|
|
|
bool fpca = !(retcode & (1<<4)); |
|
|
|
/* Read stack for pre-exception registers */ |
|
|
|
uint32_t sp = spsel ? regs[REG_PSP] : regs[REG_MSP]; |
|
|
|
target_mem_read(target, stack, sp, sizeof(stack)); |
|
|
|
if (target_check_error(target)) |
|
|
|
target_mem_read(t, stack, sp, sizeof(stack)); |
|
|
|
if (target_check_error(t)) |
|
|
|
return 0; |
|
|
|
regs[REG_LR] = stack[5]; /* restore LR to pre-exception state */ |
|
|
|
regs[REG_PC] = stack[6]; /* restore PC to pre-exception state */ |
|
|
@ -616,22 +608,22 @@ static int cortexm_fault_unwind(struct target_s *target) |
|
|
|
/* Reset exception state to allow resuming from restored
|
|
|
|
* state. |
|
|
|
*/ |
|
|
|
target_mem_write32(target, CORTEXM_AIRCR, |
|
|
|
target_mem_write32(t, CORTEXM_AIRCR, |
|
|
|
CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_VECTCLRACTIVE); |
|
|
|
|
|
|
|
/* Write pre-exception registers back to core */ |
|
|
|
target_regs_write(target, regs); |
|
|
|
target_regs_write(t, regs); |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int cortexm_run_stub(struct target_s *target, uint32_t loadaddr, |
|
|
|
int cortexm_run_stub(target *t, uint32_t loadaddr, |
|
|
|
const uint16_t *stub, uint32_t stublen, |
|
|
|
uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3) |
|
|
|
{ |
|
|
|
uint32_t regs[target->regs_size / 4]; |
|
|
|
uint32_t regs[t->regs_size / 4]; |
|
|
|
|
|
|
|
memset(regs, 0, sizeof(regs)); |
|
|
|
regs[0] = r0; |
|
|
@ -642,19 +634,19 @@ int cortexm_run_stub(struct target_s *target, uint32_t loadaddr, |
|
|
|
regs[16] = 0x1000000; |
|
|
|
regs[19] = 0; |
|
|
|
|
|
|
|
target_mem_write(target, loadaddr, stub, stublen); |
|
|
|
cortexm_regs_write(target, regs); |
|
|
|
target_mem_write(t, loadaddr, stub, stublen); |
|
|
|
cortexm_regs_write(t, regs); |
|
|
|
|
|
|
|
if (target_check_error(target)) |
|
|
|
if (target_check_error(t)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
/* Execute the stub */ |
|
|
|
cortexm_halt_resume(target, 0); |
|
|
|
while (!cortexm_halt_wait(target)) |
|
|
|
cortexm_halt_resume(t, 0); |
|
|
|
while (!cortexm_halt_wait(t)) |
|
|
|
; |
|
|
|
|
|
|
|
uint32_t pc = cortexm_pc_read(target); |
|
|
|
uint16_t bkpt_instr = target_mem_read16(target, pc); |
|
|
|
uint32_t pc = cortexm_pc_read(t); |
|
|
|
uint16_t bkpt_instr = target_mem_read16(t, pc); |
|
|
|
if (bkpt_instr >> 8 != 0xbe) |
|
|
|
return -2; |
|
|
|
|
|
|
@ -664,10 +656,9 @@ int cortexm_run_stub(struct target_s *target, uint32_t loadaddr, |
|
|
|
/* The following routines implement hardware breakpoints.
|
|
|
|
* The Flash Patch and Breakpoint (FPB) system is used. */ |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_set_hw_bp(struct target_s *target, uint32_t addr) |
|
|
|
static int cortexm_set_hw_bp(target *t, uint32_t addr) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
uint32_t val = addr & 0x1FFFFFFC; |
|
|
|
unsigned i; |
|
|
@ -682,15 +673,14 @@ cortexm_set_hw_bp(struct target_s *target, uint32_t addr) |
|
|
|
|
|
|
|
priv->hw_breakpoint[i] = addr | 1; |
|
|
|
|
|
|
|
target_mem_write32(target, CORTEXM_FPB_COMP(i), val); |
|
|
|
target_mem_write32(t, CORTEXM_FPB_COMP(i), val); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_clear_hw_bp(struct target_s *target, uint32_t addr) |
|
|
|
static int cortexm_clear_hw_bp(target *t, uint32_t addr) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
unsigned i; |
|
|
|
|
|
|
@ -701,7 +691,7 @@ cortexm_clear_hw_bp(struct target_s *target, uint32_t addr) |
|
|
|
|
|
|
|
priv->hw_breakpoint[i] = 0; |
|
|
|
|
|
|
|
target_mem_write32(target, CORTEXM_FPB_COMP(i), 0); |
|
|
|
target_mem_write32(t, CORTEXM_FPB_COMP(i), 0); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
@ -710,9 +700,9 @@ cortexm_clear_hw_bp(struct target_s *target, uint32_t addr) |
|
|
|
* The Data Watch and Trace (DWT) system is used. */ |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len) |
|
|
|
cortexm_set_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
unsigned i; |
|
|
|
|
|
|
@ -734,7 +724,7 @@ cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t |
|
|
|
|
|
|
|
for(i = 0; i < priv->hw_watchpoint_max; i++) |
|
|
|
if((priv->hw_watchpoint[i].type == 0) && |
|
|
|
((target_mem_read32(target, CORTEXM_DWT_FUNC(i)) & 0xF) == 0)) |
|
|
|
((target_mem_read32(t, CORTEXM_DWT_FUNC(i)) & 0xF) == 0)) |
|
|
|
break; |
|
|
|
|
|
|
|
if(i == priv->hw_watchpoint_max) return -2; |
|
|
@ -743,18 +733,18 @@ cortexm_set_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t |
|
|
|
priv->hw_watchpoint[i].addr = addr; |
|
|
|
priv->hw_watchpoint[i].size = len; |
|
|
|
|
|
|
|
target_mem_write32(target, CORTEXM_DWT_COMP(i), addr); |
|
|
|
target_mem_write32(target, CORTEXM_DWT_MASK(i), len); |
|
|
|
target_mem_write32(target, CORTEXM_DWT_FUNC(i), type | |
|
|
|
((target->target_options & TOPT_FLAVOUR_V6M) ? 0: CORTEXM_DWT_FUNC_DATAVSIZE_WORD)); |
|
|
|
target_mem_write32(t, CORTEXM_DWT_COMP(i), addr); |
|
|
|
target_mem_write32(t, CORTEXM_DWT_MASK(i), len); |
|
|
|
target_mem_write32(t, CORTEXM_DWT_FUNC(i), type | |
|
|
|
((t->target_options & TOPT_FLAVOUR_V6M) ? 0: CORTEXM_DWT_FUNC_DATAVSIZE_WORD)); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_t len) |
|
|
|
cortexm_clear_hw_wp(target *t, uint8_t type, uint32_t addr, uint8_t len) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
unsigned i; |
|
|
|
|
|
|
@ -783,22 +773,21 @@ cortexm_clear_hw_wp(struct target_s *target, uint8_t type, uint32_t addr, uint8_ |
|
|
|
|
|
|
|
priv->hw_watchpoint[i].type = 0; |
|
|
|
|
|
|
|
target_mem_write32(target, CORTEXM_DWT_FUNC(i), 0); |
|
|
|
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
cortexm_check_hw_wp(struct target_s *target, uint32_t *addr) |
|
|
|
static int cortexm_check_hw_wp(target *t, uint32_t *addr) |
|
|
|
{ |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(target); |
|
|
|
ADIv5_AP_t *ap = adiv5_target_ap(t); |
|
|
|
struct cortexm_priv *priv = ap->priv; |
|
|
|
unsigned i; |
|
|
|
|
|
|
|
for(i = 0; i < priv->hw_watchpoint_max; i++) |
|
|
|
/* if SET and MATCHED then break */ |
|
|
|
if(priv->hw_watchpoint[i].type && |
|
|
|
(target_mem_read32(target, CORTEXM_DWT_FUNC(i)) & |
|
|
|
(target_mem_read32(t, CORTEXM_DWT_FUNC(i)) & |
|
|
|
CORTEXM_DWT_FUNC_MATCHED)) |
|
|
|
break; |
|
|
|
|
|
|
|