diff --git a/inc/stlink.h b/inc/stlink.h index 3bc518c..69a4799 100644 --- a/inc/stlink.h +++ b/inc/stlink.h @@ -83,6 +83,19 @@ enum target_state { #define STLINK_F_HAS_DPBANKSEL (1 << 8) #define STLINK_F_HAS_RW8_512BYTES (1 << 9) +/* Error code */ +#define STLINK_DEBUG_ERR_OK 0x80 +#define STLINK_DEBUG_ERR_FAULT 0x81 +#define STLINK_DEBUG_ERR_AP_WAIT 0x10 +#define STLINK_DEBUG_ERR_AP_FAULT 0x11 +#define STLINK_DEBUG_ERR_AP_ERROR 0x12 +#define STLINK_DEBUG_ERR_DP_WAIT 0x14 +#define STLINK_DEBUG_ERR_DP_FAULT 0x15 +#define STLINK_DEBUG_ERR_DP_ERROR 0x16 + +#define CMD_NO_RETRY 0 +#define CMD_USE_RETRY 3 + #define C_BUF_LEN 32 enum stlink_flash_type { diff --git a/src/common.c b/src/common.c index ee91fa4..661ee34 100644 --- a/src/common.c +++ b/src/common.c @@ -1443,12 +1443,10 @@ void stlink_close(stlink_t *sl) { int stlink_exit_debug_mode(stlink_t *sl) { DLOG("*** stlink_exit_debug_mode ***\n"); - if (sl->flash_type != STLINK_FLASH_TYPE_UNKNOWN) { + if (sl->flash_type != STLINK_FLASH_TYPE_UNKNOWN && + sl->core_stat != TARGET_RESET) { // stop debugging if the target has been identified - int ret = stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY); - if (ret == -1) { - return (ret); - } + stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY); } return (sl->backend->exit_debug_mode(sl)); @@ -1684,7 +1682,7 @@ int stlink_load_device_params(stlink_t *sl) { } int stlink_jtag_reset(stlink_t *sl, int value) { - DLOG("*** stlink_jtag_reset ***\n"); + DLOG("*** stlink_jtag_reset %d ***\n", value); return (sl->backend->jtag_reset(sl, value)); } @@ -1768,6 +1766,8 @@ int stlink_reset(stlink_t *sl, enum reset_type type) { DLOG("*** stlink_reset ***\n"); + sl->core_stat = TARGET_RESET; + if (type == RESET_AUTO) { // clear S_RESET_ST in DHCSR register for reset state detection stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); @@ -1781,9 +1781,7 @@ int stlink_reset(stlink_t *sl, enum reset_type type) { usleep(100); stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); } - if (sl->backend->reset(sl)) { - return (-1); - } + sl->backend->reset(sl); usleep(10000); } @@ -1793,8 +1791,8 @@ int stlink_reset(stlink_t *sl, enum reset_type type) { * DDI0337E, p. 10-4, Debug Halting Control and Status Register */ dhcsr = 0; - stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { + int res = stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); + if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0 && !res) { // reset not done yet // try reset through AIRCR so that NRST does not need to be connected @@ -1808,8 +1806,9 @@ int stlink_reset(stlink_t *sl, enum reset_type type) { while (time_ms() < timeout) { dhcsr = STLINK_REG_DHCSR_S_RESET_ST; stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); - if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) + if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { return (0); + } } return (-1); diff --git a/src/stlink-lib/usb.c b/src/stlink-lib/usb.c index bbdc2c2..5e17189 100644 --- a/src/stlink-lib/usb.c +++ b/src/stlink-lib/usb.c @@ -84,50 +84,80 @@ void _stlink_usb_close(stlink_t* sl) { } ssize_t send_recv(struct stlink_libusb* handle, int terminate, - unsigned char* txbuf, size_t txsize, unsigned char* rxbuf, size_t rxsize) { + unsigned char* txbuf, size_t txsize, unsigned char* rxbuf, + size_t rxsize, bool check_error, int retry_cnt) { // Note: txbuf and rxbuf can point to the same area - int res = 0; - int t; + int res, t, retry = 0; + int cmd = read_uint16(txbuf, (handle->protocoll == 1)?15:0); - t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf, (int)txsize, &res, 3000); - - if (t) { - printf("[!] send_recv send request failed: %s\n", libusb_error_name(t)); - return(-1); - } else if ((size_t)res != txsize) { - printf("[!] send_recv send request wrote %u bytes (instead of %u).\n", - (unsigned int)res, (unsigned int)txsize); - } - - if (rxsize != 0) { - t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf, (int)rxsize, &res, 3000); + while (1) { + res = 0; + t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf, (int)txsize, &res, 3000); if (t) { - printf("[!] send_recv read reply failed: %s\n", libusb_error_name(t)); - return(-1); - } - } - - if ((handle->protocoll == 1) && terminate) { - // read the SG reply - unsigned char sg_buf[13]; - t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, sg_buf, 13, &res, 3000); - - if (t) { - printf("[!] send_recv read storage failed: %s\n", libusb_error_name(t)); + ELOG("[!] send_recv send request failed: %s (command 0x%02X)\n", libusb_error_name(t), cmd); return(-1); + } else if ((size_t)res != txsize) { + ELOG("[!] send_recv send request wrote %u bytes, instead of %u (command 0x%02X)\n", + (unsigned int)res, (unsigned int)txsize, cmd); } - // The STLink doesn't seem to evaluate the sequence number. - handle->sg_transfer_idx++; - } + if (rxsize != 0) { + t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf, (int)rxsize, &res, 3000); - return(res); + if (t) { + ELOG("[!] send_recv read reply failed: %s (command 0x%02X)\n", libusb_error_name(t), cmd); + return(-1); + } + + /* Checking the command execution status stored in the first byte of the response */ + if (handle->protocoll != 1 && check_error && + rxbuf[0] != STLINK_DEBUG_ERR_OK) { + switch(rxbuf[0]) { + case STLINK_DEBUG_ERR_AP_WAIT: + case STLINK_DEBUG_ERR_DP_WAIT: + if (retry < retry_cnt) { + unsigned int delay_us = (1<protocoll == 1) && terminate) { + // read the SG reply + unsigned char sg_buf[13]; + t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, sg_buf, 13, &res, 3000); + + if (t) { + ELOG("[!] send_recv read storage failed: %s (command 0x%02X)\n", libusb_error_name(t), cmd); + return(-1); + } + + // The STLink doesn't seem to evaluate the sequence number. + handle->sg_transfer_idx++; + } + + return(res); + } } static inline int send_only(struct stlink_libusb* handle, int terminate, unsigned char* txbuf, size_t txsize) { - return((int)send_recv(handle, terminate, txbuf, txsize, NULL, 0)); + return((int)send_recv(handle, terminate, txbuf, txsize, NULL, 0, false, CMD_NO_RETRY)); } @@ -149,7 +179,6 @@ static int fill_command(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t cmd[i++] = 0; // logical unit cmd[i++] = 0xa; // command length } - return(i); } @@ -172,9 +201,8 @@ int _stlink_usb_version(stlink_t *sl) { cmd[i++] = STLINK_GET_VERSION; } - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, false, CMD_USE_RETRY); if (size != (ssize_t)rep_len) { - printf("[!] send_recv STLINK_GET_VERSION\n"); return((int)size); } @@ -193,10 +221,9 @@ int32_t _stlink_usb_target_voltage(stlink_t *sl) { cmd[i++] = STLINK_GET_TARGET_VOLTAGE; - size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, false, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_GET_TARGET_VOLTAGE\n"); + if (size < 0) { return(-1); } else if (size != 8) { printf("[!] wrong length STLINK_GET_TARGET_VOLTAGE\n"); @@ -221,10 +248,9 @@ int _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_READDEBUGREG; write_uint32(&cmd[i], addr); - size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_APIV2_READDEBUGREG\n"); + if (size < 0) { return((int)size); } @@ -245,10 +271,9 @@ int _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { cmd[i++] = STLINK_DEBUG_APIV2_WRITEDEBUGREG; write_uint32(&cmd[i], addr); write_uint32(&cmd[i + 4], data); - size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_APIV2_WRITEDEBUGREG\n"); + if (size < 0) { return((int)size); } @@ -269,10 +294,10 @@ int _stlink_usb_get_rw_status(stlink_t *sl) { if (sl->version.flags & STLINK_F_HAS_GETLASTRWSTATUS2) { cmd[i++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS2; - ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 12); + ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 12, true, CMD_NO_RETRY); } else { cmd[i++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS; - ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 2); + ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 2, true, CMD_NO_RETRY); } if (ret < 0) { return(-1); } @@ -334,10 +359,9 @@ int _stlink_usb_current_mode(stlink_t * sl) { int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_GET_CURRENT_MODE; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, false, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_GET_CURRENT_MODE\n"); + if (size < 0) { return(-1); } @@ -362,10 +386,9 @@ int _stlink_usb_core_id(stlink_t * sl) { offset = 4; } - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_READCOREID\n"); + if (size < 0) { return(-1); } @@ -408,10 +431,9 @@ int _stlink_usb_status(stlink_t * sl) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_GETSTATUS; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, false, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_GETSTATUS\n"); + if (size < 0) { return((int)size); } @@ -450,10 +472,9 @@ int _stlink_usb_force_debug(stlink_t *sl) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_FORCEDEBUG; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_FORCEDEBUG\n"); + if (size < 0) { return((int)size); } @@ -472,10 +493,9 @@ int _stlink_usb_enter_swd_mode(stlink_t * sl) { // select correct API-Version for entering SWD mode: V1 API (0x20) or V2 API (0x30). cmd[i++] = sl->version.jtag_api == STLINK_JTAG_API_V1 ? STLINK_DEBUG_APIV1_ENTER : STLINK_DEBUG_APIV2_ENTER; cmd[i++] = STLINK_DEBUG_ENTER_SWD; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_ENTER\n"); + if (size < 0) { return((int)size); } @@ -518,10 +538,9 @@ int _stlink_usb_reset(stlink_t * sl) { cmd[i++] = STLINK_DEBUG_APIV2_RESETSYS; } - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_RESETSYS\n"); + if (size < 0) { return((int)size); } @@ -539,10 +558,9 @@ int _stlink_usb_jtag_reset(stlink_t * sl, int value) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_DRIVE_NRST; cmd[i++] = value; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_APIV2_DRIVE_NRST\n"); + if (size < 0) { return((int)size); } @@ -571,10 +589,9 @@ int _stlink_usb_step(stlink_t* sl) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_STEPCORE; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_STEPCORE\n"); + if (size < 0) { return((int)size); } @@ -607,10 +624,9 @@ int _stlink_usb_run(stlink_t* sl, enum run_type type) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_RUNCORE; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_RUNCORE\n"); + if (size < 0) { return((int)size); } @@ -655,10 +671,9 @@ int _stlink_usb_set_swdclk(stlink_t* sl, int clk_freq) { cmd[i++] = STLINK_DEBUG_APIV2_SWD_SET_FREQ; cmd[i++] = clk_divisor & 0xFF; cmd[i++] = (clk_divisor >> 8) & 0xFF; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_APIV2_SWD_SET_FREQ\n"); + if (size < 0) { return((int)size); } @@ -671,10 +686,9 @@ int _stlink_usb_set_swdclk(stlink_t* sl, int clk_freq) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV3_GET_COM_FREQ; cmd[i++] = 0; // SWD mode - size = send_recv(slu, 1, cmd, slu->cmd_len, data, 52); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, 52, true, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_APIV3_GET_COM_FREQ\n"); + if (size < 0) { return((int)size); } @@ -702,10 +716,9 @@ int _stlink_usb_set_swdclk(stlink_t* sl, int clk_freq) { cmd[i++] = (uint8_t)((map[speed_index] >> 16) & 0xFF); cmd[i++] = (uint8_t)((map[speed_index] >> 24) & 0xFF); - size = send_recv(slu, 1, cmd, slu->cmd_len, data, 8); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, 8, true, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_APIV3_SET_COM_FREQ\n"); + if (size < 0) { return((int)size); } @@ -747,10 +760,9 @@ int _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { cmd[i++] = STLINK_DEBUG_READMEM_32BIT; write_uint32(&cmd[i], addr); write_uint16(&cmd[i + 4], len); - size = send_recv(slu, 1, cmd, slu->cmd_len, data, len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, len, false, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_READMEM_32BIT\n"); + if (size < 0) { return((int)size); } @@ -776,10 +788,9 @@ int _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) { cmd[i++] = STLINK_DEBUG_APIV2_READALLREGS; } - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_READALLREGS\n"); + if (size < 0) { return((int)size); } @@ -827,10 +838,9 @@ int _stlink_usb_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) { } cmd[i++] = (uint8_t)r_idx; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_READREG\n"); + if (size < 0) { return((int)size); } @@ -994,10 +1004,9 @@ int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) { cmd[i++] = idx; write_uint32(&cmd[i], reg); - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_USE_RETRY); - if (size == -1) { - printf("[!] send_recv STLINK_DEBUG_WRITEREG\n"); + if (size < 0) { return((int)size); } @@ -1020,10 +1029,9 @@ int _stlink_usb_enable_trace(stlink_t* sl, uint32_t frequency) { write_uint16(&cmd[i + 0], 2 * STLINK_TRACE_BUF_LEN); write_uint32(&cmd[i + 2], frequency); - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_only STLINK_DEBUG_APIV2_START_TRACE_RX\n"); + if (size < 0) { return((int)size); } @@ -1044,10 +1052,9 @@ int _stlink_usb_disable_trace(stlink_t* sl) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, true, CMD_NO_RETRY); - if (size == -1) { - printf("[!] send_only STLINK_DEBUG_APIV2_STOP_TRACE_RX\n"); + if (size < 0) { return((int)size); } @@ -1066,14 +1073,12 @@ int _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, size_t size) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_GET_TRACE_NB; - ssize_t send_size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + ssize_t send_size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, false, CMD_NO_RETRY); - if (send_size == -1) { - printf("[!] send_recv STLINK_DEBUG_APIV2_GET_TRACE_NB\n"); + if (send_size < 0) { return((int)send_size); - } - if (send_size != 2) { - printf("[!] send_recv STLINK_DEBUG_APIV2_GET_TRACE_NB %d\n", (int)send_size); + } else if (send_size != 2) { + ELOG("STLINK_DEBUG_APIV2_GET_TRACE_NB reply size %d\n", (int)send_size); return -1; }