* Copyright (C) 2011 by Mathias Kuester *
* Mathias Kuester <kesmtp@freenet.de> *
* *
+ * Copyright (C) 2011 by Spencer Oliver *
+ * spen@spen-soft.co.uk *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "jtag/jtag.h"
+#include "jtag/stlink/stlink_transport.h"
#include "jtag/stlink/stlink_interface.h"
#include "jtag/stlink/stlink_layout.h"
#include "register.h"
#include "target_type.h"
#include "armv7m.h"
#include "cortex_m.h"
+#include "arm_semihosting.h"
+
+#define ARMV7M_SCS_DCRSR 0xe000edf4
+#define ARMV7M_SCS_DCRDR 0xe000edf8
static inline struct stlink_interface_s *target_to_stlink(struct target *target)
{
}
static int stm32_stlink_load_core_reg_u32(struct target *target,
- enum armv7m_regtype type,
- uint32_t num, uint32_t *value)
+ enum armv7m_regtype type,
+ uint32_t num, uint32_t *value)
{
int retval;
struct stlink_interface_s *stlink_if = target_to_stlink(target);
switch (num) {
case 0 ... 18:
/* read a normal core register */
- retval =
- stlink_if->layout->api->read_reg(stlink_if->fd, num, value);
+ retval = stlink_if->layout->api->read_reg(stlink_if->fd, num, value);
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);
+ LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value);
+ break;
+
+ case ARMV7M_FPSID:
+ case ARMV7M_FPEXC:
+ *value = 0;
+ break;
+
+ case ARMV7M_FPSCR:
+ /* Floating-point Status and Registers */
+ retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value);
+ if (retval != ERROR_OK)
+ return retval;
+ LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value);
+ break;
+
+ case ARMV7M_S0 ... ARMV7M_S31:
+ /* Floating-point Status and Registers */
+ retval = target_write_u32(target, ARMV7M_SCS_DCRSR, num-ARMV7M_S0+64);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value);
+ if (retval != ERROR_OK)
+ return retval;
+ LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value);
+ break;
+
+ case ARMV7M_D0 ... ARMV7M_D15:
+ value = 0;
break;
case ARMV7M_PRIMASK:
* in one Debug Core register. So say r0 and r2 docs;
* it was removed from r1 docs, but still works.
*/
- retval =
- stlink_if->layout->api->read_reg(stlink_if->fd, 20, value);
+ retval = stlink_if->layout->api->read_reg(stlink_if->fd, 20, value);
+ if (retval != ERROR_OK)
+ return retval;
switch (num) {
case ARMV7M_PRIMASK:
break;
default:
- return ERROR_INVALID_ARGUMENTS;
+ return ERROR_COMMAND_SYNTAX_ERROR;
}
return ERROR_OK;
}
static int stm32_stlink_store_core_reg_u32(struct target *target,
- enum armv7m_regtype type,
- uint32_t num, uint32_t value)
+ enum armv7m_regtype type,
+ uint32_t num, uint32_t value)
{
int retval;
uint32_t reg;
*/
switch (num) {
case 0 ... 18:
- retval =
- stlink_if->layout->api->write_reg(stlink_if->fd, num,
- value);
+ retval = stlink_if->layout->api->write_reg(stlink_if->fd, num, value);
if (retval != ERROR_OK) {
struct reg *r;
r->dirty = r->valid;
return ERROR_JTAG_DEVICE_ERROR;
}
- LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num,
- value);
+ LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
+ break;
+
+ case ARMV7M_FPSID:
+ case ARMV7M_FPEXC:
+ break;
+
+ case ARMV7M_FPSCR:
+ /* Floating-point Status and Registers */
+ retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33 | (1<<16));
+ if (retval != ERROR_OK)
+ return retval;
+ LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
+ break;
+
+ case ARMV7M_S0 ... ARMV7M_S31:
+ /* Floating-point Status and Registers */
+ retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_write_u32(target, ARMV7M_SCS_DCRSR, (num-ARMV7M_S0+64) | (1<<16));
+ if (retval != ERROR_OK)
+ return retval;
+ LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value);
+ break;
+
+ case ARMV7M_D0 ... ARMV7M_D15:
break;
case ARMV7M_PRIMASK:
* in one Debug Core register. So say r0 and r2 docs;
* it was removed from r1 docs, but still works.
*/
- /* cortexm3_dap_read_coreregister_u32(swjdp, ®, 20); */
+
+ stlink_if->layout->api->read_reg(stlink_if->fd, 20, ®);
switch (num) {
case ARMV7M_PRIMASK:
break;
}
- /* cortexm3_dap_write_coreregister_u32(swjdp, reg, 20); */
+ stlink_if->layout->api->write_reg(stlink_if->fd, 20, reg);
- LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num,
- value);
+ LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value);
break;
default:
- return ERROR_INVALID_ARGUMENTS;
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ return ERROR_OK;
+}
+
+static int stm32_stlink_examine_debug_reason(struct target *target)
+{
+ if ((target->debug_reason != DBG_REASON_DBGRQ)
+ && (target->debug_reason != DBG_REASON_SINGLESTEP)) {
+ target->debug_reason = DBG_REASON_BREAKPOINT;
}
return ERROR_OK;
armv7m->load_core_reg_u32 = stm32_stlink_load_core_reg_u32;
armv7m->store_core_reg_u32 = stm32_stlink_store_core_reg_u32;
+ armv7m->examine_debug_reason = stm32_stlink_examine_debug_reason;
+ armv7m->stlink = true;
+
return ERROR_OK;
}
}
static int stm32_stlink_target_create(struct target *target,
- Jim_Interp *interp)
+ Jim_Interp *interp)
{
LOG_DEBUG("%s", __func__);
struct cortex_m3_common *cortex_m3 = calloc(1, sizeof(struct cortex_m3_common));
if (!cortex_m3)
- return ERROR_INVALID_ARGUMENTS;
+ return ERROR_COMMAND_SYNTAX_ERROR;
stm32_stlink_init_arch_info(target, cortex_m3, target->tap);
return ERROR_OK;
}
-static int stm32_stlink_poll(struct target *target);
-
-static int stm32_stlink_examine(struct target *target)
+static int stm32_stlink_load_context(struct target *target)
{
- int retval, i;
- uint32_t cpuid, fpcr;
- struct cortex_m3_common *cortex_m3 = target_to_cm3(target);
-
- LOG_DEBUG("%s", __func__);
-
- if (target->tap->hasidcode == false) {
- LOG_ERROR("no IDCODE present on device");
-
- return ERROR_INVALID_ARGUMENTS;
- }
-
- if (!target_was_examined(target)) {
- target_set_examined(target);
-
- stm32_stlink_poll(target);
-
- LOG_INFO("IDCODE %x", target->tap->idcode);
-
- /* Read from Device Identification Registers */
- retval = target_read_u32(target, CPUID, &cpuid);
- if (retval != ERROR_OK)
- return retval;
-
- if (((cpuid >> 4) & 0xc3f) == 0xc23)
- LOG_DEBUG("Cortex-M3 r%" PRId8 "p%" PRId8 " processor detected",
- (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf));
- LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
-
- /* Setup FPB */
- target_read_u32(target, FP_CTRL, &fpcr);
- cortex_m3->auto_bp_type = 1;
- cortex_m3->fp_num_code = ((fpcr >> 8) & 0x70) |
- ((fpcr >> 4) & 0xF); /* bits [14:12] and [7:4] */
- cortex_m3->fp_num_lit = (fpcr >> 8) & 0xF;
- cortex_m3->fp_code_available = cortex_m3->fp_num_code;
- cortex_m3->fp_comparator_list = calloc(cortex_m3->fp_num_code +
- cortex_m3->fp_num_lit, sizeof(struct cortex_m3_fp_comparator));
- cortex_m3->fpb_enabled = fpcr & 1;
- for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++) {
- cortex_m3->fp_comparator_list[i].type =
- (i < cortex_m3->fp_num_code) ? FPCR_CODE : FPCR_LITERAL;
- cortex_m3->fp_comparator_list[i].fpcr_address = FP_COMP0 + 4 * i;
- }
- LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr,
- cortex_m3->fp_num_code, cortex_m3->fp_num_lit);
-
- /* Setup DWT */
- cortex_m3_dwt_setup(cortex_m3, target);
+ struct armv7m_common *armv7m = target_to_armv7m(target);
+ int num_regs = armv7m->core_cache->num_regs;
- /* These hardware breakpoints only work for code in flash! */
- LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints",
- target_name(target),
- cortex_m3->fp_num_code,
- cortex_m3->dwt_num_comp);
+ for (int i = 0; i < num_regs; i++) {
+ if (!armv7m->core_cache->reg_list[i].valid)
+ armv7m->read_core_reg(target, i);
}
return ERROR_OK;
}
-static int stm32_stlink_load_context(struct target *target)
+static int stlink_debug_entry(struct target *target)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
+ struct arm *arm = &armv7m->arm;
+ struct reg *r;
+ uint32_t xPSR;
+ int retval;
- for (unsigned i = 0; i < 23; i++) {
- if (!armv7m->core_cache->reg_list[i].valid)
- armv7m->read_core_reg(target, i);
+ retval = armv7m->examine_debug_reason(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stm32_stlink_load_context(target);
+
+ r = armv7m->core_cache->reg_list + ARMV7M_xPSR;
+ xPSR = buf_get_u32(r->value, 0, 32);
+
+ /* Are we in an exception handler */
+ if (xPSR & 0x1FF) {
+ armv7m->core_mode = ARMV7M_MODE_HANDLER;
+ armv7m->exception_number = (xPSR & 0x1FF);
+
+ arm->core_mode = ARM_MODE_HANDLER;
+ arm->map = armv7m_msp_reg_map;
+ } else {
+ unsigned control = buf_get_u32(armv7m->core_cache
+ ->reg_list[ARMV7M_CONTROL].value, 0, 2);
+
+ /* is this thread privileged? */
+ armv7m->core_mode = control & 1;
+ arm->core_mode = armv7m->core_mode
+ ? ARM_MODE_USER_THREAD
+ : ARM_MODE_THREAD;
+
+ /* which stack is it using? */
+ if (control & 2)
+ arm->map = armv7m_psp_reg_map;
+ else
+ arm->map = armv7m_msp_reg_map;
+
+ armv7m->exception_number = 0;
}
- return ERROR_OK;
+ LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32 ", target->state: %s",
+ armv7m_mode_strings[armv7m->core_mode],
+ *(uint32_t *)(arm->pc->value),
+ target_state_name(target));
+
+ return retval;
}
static int stm32_stlink_poll(struct target *target)
state = stlink_if->layout->api->state(stlink_if->fd);
if (state == TARGET_UNKNOWN) {
- LOG_ERROR
- ("jtag status contains invalid mode value - communication failure");
+ LOG_ERROR("jtag status contains invalid mode value - communication failure");
return ERROR_TARGET_FAILURE;
}
return ERROR_OK;
if (state == TARGET_HALTED) {
- target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
target->state = state;
- stm32_stlink_load_context(target);
+ int retval = stlink_debug_entry(target);
+ if (retval != ERROR_OK)
+ return retval;
- LOG_INFO("halted: PC: 0x%x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
- }
+ if (arm_semihosting(target, &retval) != 0)
+ return retval;
- return ERROR_OK;
-}
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ LOG_DEBUG("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
+ }
-static int stm32_stlink_arch_state(struct target *target)
-{
- LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
static int stm32_stlink_assert_reset(struct target *target)
{
- int res;
+ int res = ERROR_OK;
struct stlink_interface_s *stlink_if = target_to_stlink(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
+ bool use_srst_fallback = true;
LOG_DEBUG("%s", __func__);
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+ bool srst_asserted = false;
+
+ if (jtag_reset_config & RESET_SRST_NO_GATING) {
+ jtag_add_reset(0, 1);
+ res = stlink_if->layout->api->assert_srst(stlink_if->fd, 0);
+ srst_asserted = true;
+ }
+
+ stlink_if->layout->api->write_debug_reg(stlink_if->fd, DCB_DHCSR, DBGKEY|C_DEBUGEN);
+ stlink_if->layout->api->write_debug_reg(stlink_if->fd, DCB_DEMCR, VC_CORERESET);
+
+ if (jtag_reset_config & RESET_HAS_SRST) {
+ if (!srst_asserted) {
+ jtag_add_reset(0, 1);
+ res = stlink_if->layout->api->assert_srst(stlink_if->fd, 0);
+ }
+ if (res == ERROR_COMMAND_NOTFOUND)
+ LOG_ERROR("Hardware srst not supported, falling back to software reset");
+ else if (res == ERROR_OK) {
+ /* hardware srst supported */
+ use_srst_fallback = false;
+ }
+ }
+
+ if (use_srst_fallback) {
+ /* stlink v1 api does support hardware srst, so we use a software reset fallback */
+ stlink_if->layout->api->write_debug_reg(stlink_if->fd, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ);
+ }
+
res = stlink_if->layout->api->reset(stlink_if->fd);
if (res != ERROR_OK)
return res;
- /* virtual assert reset, we need it for the internal
- * jtag state machine
- */
- jtag_add_reset(1, 1);
-
/* registers are now invalid */
register_cache_invalidate(armv7m->core_cache);
- stm32_stlink_load_context(target);
-
- target->state = TARGET_HALTED;
+ if (target->reset_halt) {
+ target->state = TARGET_RESET;
+ target->debug_reason = DBG_REASON_DBGRQ;
+ } else {
+ target->state = TARGET_HALTED;
+ }
return ERROR_OK;
}
static int stm32_stlink_deassert_reset(struct target *target)
{
int res;
+ struct stlink_interface_s *stlink_if = target_to_stlink(target);
+
+ enum reset_types jtag_reset_config = jtag_get_reset_config();
LOG_DEBUG("%s", __func__);
+ if (jtag_reset_config & RESET_HAS_SRST)
+ stlink_if->layout->api->assert_srst(stlink_if->fd, 1);
+
/* virtual deassert reset, we need it for the internal
* jtag state machine
*/
return ERROR_OK;
}
- if (target->state == TARGET_UNKNOWN) {
- LOG_WARNING
- ("target was in unknown state when halt was requested");
- }
+ if (target->state == TARGET_UNKNOWN)
+ LOG_WARNING("target was in unknown state when halt was requested");
res = stlink_if->layout->api->halt(stlink_if->fd);
}
static int stm32_stlink_resume(struct target *target, int current,
- uint32_t address, int handle_breakpoints,
- int debug_execution)
+ uint32_t address, int handle_breakpoints,
+ int debug_execution)
{
int res;
struct stlink_interface_s *stlink_if = target_to_stlink(target);
struct breakpoint *breakpoint = NULL;
struct reg *pc;
- LOG_DEBUG("%s %d %x %d %d", __func__, current, address,
- handle_breakpoints, debug_execution);
+ LOG_DEBUG("%s %d 0x%08x %d %d", __func__, current, address,
+ handle_breakpoints, debug_execution);
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
breakpoint = breakpoint_find(target, resume_pc);
if (breakpoint) {
LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)",
- breakpoint->address,
- breakpoint->unique_id);
+ breakpoint->address,
+ breakpoint->unique_id);
cortex_m3_unset_breakpoint(target, breakpoint);
res = stlink_if->layout->api->step(stlink_if->fd);
return res;
target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
- target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+ target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
return ERROR_OK;
}
static int stm32_stlink_step(struct target *target, int current,
- uint32_t address, int handle_breakpoints)
+ uint32_t address, int handle_breakpoints)
{
int res;
struct stlink_interface_s *stlink_if = target_to_stlink(target);
return ERROR_TARGET_NOT_HALTED;
}
- pc = armv7m->arm.pc;
if (!current) {
buf_set_u32(pc->value, 0, 32, address);
pc->dirty = true;
if (breakpoint)
cortex_m3_set_breakpoint(target, breakpoint);
- target->debug_reason = DBG_REASON_SINGLESTEP;
+ stlink_debug_entry(target);
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
- stm32_stlink_load_context(target);
-
- LOG_INFO("halted: PC: 0x%x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
+ LOG_INFO("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32));
return ERROR_OK;
}
static int stm32_stlink_read_memory(struct target *target, uint32_t address,
- uint32_t size, uint32_t count,
- uint8_t *buffer)
+ uint32_t size, uint32_t count,
+ uint8_t *buffer)
{
int res;
- uint32_t *dst = (uint32_t *) buffer;
+ uint32_t buffer_threshold = 128;
+ uint32_t addr_increment = 4;
uint32_t c;
struct stlink_interface_s *stlink_if = target_to_stlink(target);
if (!count || !buffer)
- return ERROR_INVALID_ARGUMENTS;
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count);
+
+ /* prepare byte count, buffer threshold
+ * and address increment for none 32bit access
+ */
if (size != 4) {
- LOG_DEBUG("%s %x %d %d", __func__, address, size, count);
- return ERROR_INVALID_ARGUMENTS;
+ count *= size;
+ buffer_threshold = 64;
+ addr_increment = 1;
}
while (count) {
- if (count > 128)
- c = 128;
+ if (count > buffer_threshold)
+ c = buffer_threshold;
else
c = count;
- res =
- stlink_if->layout->api->read_mem32(stlink_if->fd, address,
- c, dst);
+ if (size != 4)
+ res = stlink_if->layout->api->read_mem8(stlink_if->fd,
+ address, c, buffer);
+ else
+ res = stlink_if->layout->api->read_mem32(stlink_if->fd,
+ address, c, buffer);
if (res != ERROR_OK)
return res;
- dst += c;
- address += (c * 4);
+
+ address += (c * addr_increment);
+ buffer += (c * addr_increment);
count -= c;
}
}
static int stm32_stlink_write_memory(struct target *target, uint32_t address,
- uint32_t size, uint32_t count,
- const uint8_t *buffer)
+ uint32_t size, uint32_t count,
+ const uint8_t *buffer)
{
int res;
- uint32_t *dst = (uint32_t *) buffer;
+ uint32_t buffer_threshold = 128;
+ uint32_t addr_increment = 4;
uint32_t c;
struct stlink_interface_s *stlink_if = target_to_stlink(target);
if (!count || !buffer)
- return ERROR_INVALID_ARGUMENTS;
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count);
+
+ /* prepare byte count, buffer threshold
+ * and address increment for none 32bit access
+ */
if (size != 4) {
- LOG_DEBUG("%s %x %d %d", __func__, address, size, count);
- return ERROR_INVALID_ARGUMENTS;
+ count *= size;
+ buffer_threshold = 64;
+ addr_increment = 1;
}
while (count) {
- if (count > 128)
- c = 128;
+ if (count > buffer_threshold)
+ c = buffer_threshold;
else
c = count;
- res =
- stlink_if->layout->api->write_mem32(stlink_if->fd, address,
- c, dst);
+ if (size != 4)
+ res = stlink_if->layout->api->write_mem8(stlink_if->fd,
+ address, c, buffer);
+ else
+ res = stlink_if->layout->api->write_mem32(stlink_if->fd,
+ address, c, buffer);
if (res != ERROR_OK)
return res;
- dst += c;
- address += (c * 4);
+
+ address += (c * addr_increment);
+ buffer += (c * addr_increment);
count -= c;
}
}
static int stm32_stlink_bulk_write_memory(struct target *target,
- uint32_t address, uint32_t count,
- const uint8_t *buffer)
+ uint32_t address, uint32_t count,
+ const uint8_t *buffer)
{
return stm32_stlink_write_memory(target, address, 4, count, buffer);
}
+static const struct command_registration stm32_stlink_command_handlers[] = {
+ {
+ .chain = arm_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
struct target_type stm32_stlink_target = {
.name = "stm32_stlink",
.init_target = stm32_stlink_init_target,
.target_create = stm32_stlink_target_create,
- .examine = stm32_stlink_examine,
+ .examine = cortex_m3_examine,
+ .commands = stm32_stlink_command_handlers,
.poll = stm32_stlink_poll,
- .arch_state = stm32_stlink_arch_state,
+ .arch_state = armv7m_arch_state,
.assert_reset = stm32_stlink_assert_reset,
.deassert_reset = stm32_stlink_deassert_reset,
.read_memory = stm32_stlink_read_memory,
.write_memory = stm32_stlink_write_memory,
.bulk_write_memory = stm32_stlink_bulk_write_memory,
+ .checksum_memory = armv7m_checksum_memory,
+ .blank_check_memory = armv7m_blank_check_memory,
.run_algorithm = armv7m_run_algorithm,
.start_algorithm = armv7m_start_algorithm,