aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/flash/nand/lpc32xx.c20
-rw-r--r--src/flash/nor/atsame5.c4
-rw-r--r--src/flash/nor/cfi.c14
-rw-r--r--src/flash/nor/numicro.c6
-rw-r--r--src/flash/nor/stm32l4x.c697
-rw-r--r--src/flash/nor/stm32l4x.h6
-rw-r--r--src/flash/nor/stmqspi.c227
-rw-r--r--src/flash/startup.tcl11
-rw-r--r--src/helper/Makefile.am7
-rw-r--r--src/helper/command.c34
-rw-r--r--src/helper/ioutil.c534
-rw-r--r--src/helper/ioutil.h25
-rw-r--r--src/helper/ioutil_stubs.c28
-rw-r--r--src/helper/options.c10
-rw-r--r--src/jtag/Makefile.am36
-rw-r--r--src/jtag/adapter.c4
-rw-r--r--src/jtag/aice/Makefile.am2
-rw-r--r--src/jtag/core.c8
-rw-r--r--src/jtag/drivers/Makefile.am7
-rw-r--r--src/jtag/drivers/arm-jtag-ew.c46
-rw-r--r--src/jtag/drivers/cmsis_dap.c272
-rw-r--r--src/jtag/drivers/cmsis_dap.h6
-rw-r--r--src/jtag/drivers/cmsis_dap_usb_bulk.c42
-rw-r--r--src/jtag/drivers/cmsis_dap_usb_hid.c47
-rw-r--r--src/jtag/drivers/jtag_usb_common.c4
-rw-r--r--src/jtag/drivers/nulink_usb.c4
-rw-r--r--src/jtag/drivers/rlink.c200
-rw-r--r--src/jtag/drivers/stlink_usb.c725
-rw-r--r--src/jtag/drivers/usb_blaster/ublast2_access_libusb.c29
-rw-r--r--src/jtag/drivers/usb_common.c57
-rw-r--r--src/jtag/drivers/usb_common.h26
-rw-r--r--src/jtag/drivers/usbprog.c50
-rw-r--r--src/jtag/hla/hla_interface.c34
-rw-r--r--src/jtag/hla/hla_interface.h4
-rw-r--r--src/jtag/interface.h2
-rw-r--r--src/jtag/interfaces.c15
-rw-r--r--src/jtag/jtag.h14
-rw-r--r--src/jtag/minidriver.h2
-rw-r--r--src/jtag/minidriver/minidriver_imp.h30
-rw-r--r--src/jtag/minidummy/jtag_minidriver.h21
-rw-r--r--src/jtag/minidummy/minidummy.c176
-rw-r--r--src/jtag/startup.tcl47
-rw-r--r--src/jtag/zy1000/jtag_minidriver.h182
-rw-r--r--src/jtag/zy1000/zy1000.c1259
-rw-r--r--src/openocd.c11
-rw-r--r--src/rtos/FreeRTOS.c6
-rw-r--r--src/rtos/ThreadX.c6
-rw-r--r--src/rtos/chibios.c6
-rw-r--r--src/rtos/chromium-ec.c4
-rw-r--r--src/rtos/eCos.c6
-rw-r--r--src/rtos/embKernel.c6
-rw-r--r--src/rtos/hwthread.c6
-rw-r--r--src/rtos/linux.c6
-rw-r--r--src/rtos/mqx.c4
-rw-r--r--src/rtos/nuttx.c6
-rw-r--r--src/rtos/riot.c6
-rw-r--r--src/rtos/rtos.c8
-rw-r--r--src/rtos/rtos.h8
-rw-r--r--src/rtos/uCOS-III.c4
-rw-r--r--src/server/gdb_server.c4
-rw-r--r--src/server/rtt_server.c2
-rw-r--r--src/server/server.c7
-rw-r--r--src/server/server.h2
-rw-r--r--src/server/tcl_server.c2
-rw-r--r--src/server/telnet_server.c8
-rw-r--r--src/target/Makefile.am10
-rw-r--r--src/target/aarch64.c330
-rw-r--r--src/target/aarch64.h5
-rw-r--r--src/target/arc.c6
-rw-r--r--src/target/arc.h49
-rw-r--r--src/target/arc_cmd.c4
-rw-r--r--src/target/arm11_dbgtap.c21
-rw-r--r--src/target/arm720t.c79
-rw-r--r--src/target/arm920t.c89
-rw-r--r--src/target/arm_semihosting.c57
-rw-r--r--src/target/arm_tpiu_swo.c1189
-rw-r--r--src/target/arm_tpiu_swo.h21
-rw-r--r--src/target/armv7m.c8
-rw-r--r--src/target/armv7m_trace.c354
-rw-r--r--src/target/armv7m_trace.h53
-rw-r--r--src/target/armv8.c7
-rw-r--r--src/target/armv8_dpm.c6
-rw-r--r--src/target/armv8_dpm.h7
-rw-r--r--src/target/cortex_a.c1
-rw-r--r--src/target/cortex_m.c14
-rw-r--r--src/target/cortex_m.h2
-rw-r--r--src/target/embeddedice.c4
-rw-r--r--src/target/etm.c8
-rw-r--r--src/target/hla_target.c8
-rw-r--r--src/target/image.c2
-rw-r--r--src/target/mem_ap.c93
-rw-r--r--src/target/mips32_pracc.c2
-rw-r--r--src/target/mips32_pracc.h6
-rw-r--r--src/target/mips64_pracc.c10
-rw-r--r--src/target/mips_ejtag.c2
-rw-r--r--src/target/oocd_trace.c417
-rw-r--r--src/target/oocd_trace.h53
-rw-r--r--src/target/openrisc/jsp_server.c3
-rw-r--r--src/target/riscv/riscv.c6
-rw-r--r--src/target/startup.tcl17
-rw-r--r--src/target/target.c36
-rw-r--r--src/target/target_type.h1
-rw-r--r--src/transport/transport.h2
104 files changed, 3790 insertions, 4285 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 41153fb..ac2381e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -69,6 +69,7 @@ BUILT_SOURCES += %D%/startup_tcl.inc
# Convert .tcl to c-array
%D%/startup_tcl.inc: $(STARTUP_TCL_SRCS)
+ mkdir -p %D%
cat $^ | $(BIN2C) > $@ || { rm -f $@; false; }
# add generated files to make clean list
diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c
index d516522..6443beb 100644
--- a/src/flash/nand/lpc32xx.c
+++ b/src/flash/nand/lpc32xx.c
@@ -60,14 +60,14 @@ static const int lp_ooblayout[] = {
58, 59, 60, 61, 62, 63
};
-typedef struct {
+struct dmac_ll {
volatile uint32_t dma_src;
volatile uint32_t dma_dest;
volatile uint32_t next_lli;
volatile uint32_t next_ctrl;
-} dmac_ll_t;
+};
-static dmac_ll_t dmalist[(2048/256) * 2 + 1];
+static struct dmac_ll dmalist[(2048/256) * 2 + 1];
/* nand device lpc32xx <target#> <oscillator_frequency>
*/
@@ -867,14 +867,14 @@ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size,
dmalist[i*2].dma_src = (do_read ? dmasrc : (dmasrc + i * 256));
dmalist[i*2].dma_dest = (do_read ? (dmadst + i * 256) : dmadst);
dmalist[i*2].next_lli =
- target_mem_base + (i*2 + 1) * sizeof(dmac_ll_t);
+ target_mem_base + (i*2 + 1) * sizeof(struct dmac_ll);
dmalist[i*2].next_ctrl = ctrl;
dmalist[(i*2) + 1].dma_src = 0x20020034;/* SLC_ECC */
dmalist[(i*2) + 1].dma_dest =
target_mem_base + ECC_OFFS + i * 4;
dmalist[(i*2) + 1].next_lli =
- target_mem_base + (i*2 + 2) * sizeof(dmac_ll_t);
+ target_mem_base + (i*2 + 2) * sizeof(struct dmac_ll);
dmalist[(i*2) + 1].next_ctrl = ecc_ctrl;
}
@@ -1063,7 +1063,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand,
XXX: Assumes host and target have same byte sex.
*/
retval = target_write_memory(target, target_mem_base, 4,
- nll * sizeof(dmac_ll_t) / 4,
+ nll * sizeof(struct dmac_ll) / 4,
(uint8_t *)dmalist);
if (ERROR_OK != retval) {
LOG_ERROR("Could not write DMA descriptors to IRAM");
@@ -1104,7 +1104,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand,
/* Write first descriptor to DMA controller */
retval = target_write_memory(target, 0x31000100, 4,
- sizeof(dmac_ll_t) / 4,
+ sizeof(struct dmac_ll) / 4,
(uint8_t *)dmalist);
if (ERROR_OK != retval) {
LOG_ERROR("Could not write DMA descriptor to DMAC");
@@ -1161,7 +1161,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand,
/* Write OOB descriptor to DMA controller */
retval = target_write_memory(target, 0x31000100, 4,
- sizeof(dmac_ll_t) / 4,
+ sizeof(struct dmac_ll) / 4,
(uint8_t *)(&dmalist[nll-1]));
if (ERROR_OK != retval) {
LOG_ERROR("Could not write OOB DMA descriptor to DMAC");
@@ -1460,7 +1460,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand,
XXX: Assumes host and target have same byte sex.
*/
retval = target_write_memory(target, target_mem_base, 4,
- nll * sizeof(dmac_ll_t) / 4,
+ nll * sizeof(struct dmac_ll) / 4,
(uint8_t *)dmalist);
if (ERROR_OK != retval) {
LOG_ERROR("Could not write DMA descriptors to IRAM");
@@ -1489,7 +1489,7 @@ static int lpc32xx_read_page_slc(struct nand_device *nand,
/* Write first descriptor to DMA controller */
retval = target_write_memory(target, 0x31000100, 4,
- sizeof(dmac_ll_t) / 4, (uint8_t *)dmalist);
+ sizeof(struct dmac_ll) / 4, (uint8_t *)dmalist);
if (ERROR_OK != retval) {
LOG_ERROR("Could not write DMA descriptor to DMAC");
return retval;
diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c
index ed0bef4..50e56a7 100644
--- a/src/flash/nor/atsame5.c
+++ b/src/flash/nor/atsame5.c
@@ -113,7 +113,7 @@ struct samd_part {
};
/* See SAM D5x/E5x Family Silicon Errata and Data Sheet Clarification
- * DS80000748B */
+ * DS80000748K */
/* Known SAMD51 parts. */
static const struct samd_part samd51_parts[] = {
{ 0x00, "SAMD51P20A", 1024, 256 },
@@ -134,6 +134,8 @@ static const struct samd_part same51_parts[] = {
{ 0x02, "SAME51J19A", 512, 192 },
{ 0x03, "SAME51J18A", 256, 128 },
{ 0x04, "SAME51J20A", 1024, 256 },
+ { 0x05, "SAME51G19A", 512, 192 }, /* New in rev D */
+ { 0x06, "SAME51G18A", 256, 128 }, /* New in rev D */
};
/* Known SAME53 parts. */
diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c
index 5f5071e..c9eb38b 100644
--- a/src/flash/nor/cfi.c
+++ b/src/flash/nor/cfi.c
@@ -832,17 +832,13 @@ int cfi_flash_bank_cmd(struct flash_bank *bank, unsigned int argc, const char **
return ERROR_FLASH_BANK_INVALID;
}
- cfi_info = malloc(sizeof(struct cfi_flash_bank));
- cfi_info->probed = false;
- cfi_info->erase_region_info = NULL;
- cfi_info->pri_ext = NULL;
+ cfi_info = calloc(1, sizeof(struct cfi_flash_bank));
+ if (cfi_info == NULL) {
+ LOG_ERROR("No memory for flash bank info");
+ return ERROR_FAIL;
+ }
bank->driver_priv = cfi_info;
- cfi_info->x16_as_x8 = false;
- cfi_info->jedec_probe = false;
- cfi_info->not_cfi = false;
- cfi_info->data_swap = false;
-
for (unsigned i = 6; i < argc; i++) {
if (strcmp(argv[i], "x16_as_x8") == 0)
cfi_info->x16_as_x8 = true;
diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c
index 7609fa8..1971daa 100644
--- a/src/flash/nor/numicro.c
+++ b/src/flash/nor/numicro.c
@@ -1243,7 +1243,7 @@ static uint32_t numicro_fmc_cmd(struct target *target, uint32_t cmd, uint32_t ad
retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("status: 0x%" PRIx32 "", status);
+ LOG_DEBUG("status: 0x%" PRIx32 "", status);
if ((status & (ISPTRG_ISPGO)) == 0)
break;
if (timeout-- <= 0) {
@@ -1512,7 +1512,7 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first,
retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("status: 0x%" PRIx32 "", status);
+ LOG_DEBUG("status: 0x%" PRIx32 "", status);
if (status == 0)
break;
if (timeout-- <= 0) {
@@ -1601,7 +1601,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer,
retval = target_read_u32(target, NUMICRO_FLASH_ISPTRG, &status);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("status: 0x%" PRIx32 "", status);
+ LOG_DEBUG("status: 0x%" PRIx32 "", status);
if (status == 0)
break;
if (timeout-- <= 0) {
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index 55a8d8f..594bce0 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -116,6 +116,19 @@
#define FLASH_ERASE_TIMEOUT 250
+
+/* relevant STM32L4 flags ****************************************************/
+#define F_NONE 0
+/* this flag indicates if the device flash is with dual bank architecture */
+#define F_HAS_DUAL_BANK BIT(0)
+/* this flags is used for dual bank devices only, it indicates if the
+ * 4 WRPxx are usable if the device is configured in single-bank mode */
+#define F_USE_ALL_WRPXX BIT(1)
+/* this flag indicates if the device embeds a TrustZone security feature */
+#define F_HAS_TZ BIT(2)
+/* end of STM32L4 flags ******************************************************/
+
+
enum stm32l4_flash_reg_index {
STM32_FLASH_ACR_INDEX,
STM32_FLASH_KEYR_INDEX,
@@ -130,6 +143,13 @@ enum stm32l4_flash_reg_index {
STM32_FLASH_REG_INDEX_NUM,
};
+enum stm32l4_rdp {
+ RDP_LEVEL_0 = 0xAA,
+ RDP_LEVEL_0_5 = 0x55, /* for devices with TrustZone enabled */
+ RDP_LEVEL_1 = 0x00,
+ RDP_LEVEL_2 = 0xCC
+};
+
static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
[STM32_FLASH_ACR_INDEX] = 0x000,
[STM32_FLASH_KEYR_INDEX] = 0x008,
@@ -167,10 +187,12 @@ struct stm32l4_part_info {
const struct stm32l4_rev *revs;
const size_t num_revs;
const uint16_t max_flash_size_kb;
- const bool has_dual_bank;
+ const uint32_t flags; /* one bit per feature, see STM32L4 flags: macros F_XXX */
const uint32_t flash_regs_base;
const uint32_t *default_flash_regs;
const uint32_t fsize_addr;
+ const uint32_t otp_base;
+ const uint32_t otp_size;
};
struct stm32l4_flash_bank {
@@ -183,6 +205,24 @@ struct stm32l4_flash_bank {
uint32_t wrpxxr_mask;
const struct stm32l4_part_info *part_info;
const uint32_t *flash_regs;
+ bool otp_enabled;
+ enum stm32l4_rdp rdp;
+ bool tzen;
+};
+
+enum stm32_bank_id {
+ STM32_BANK1,
+ STM32_BANK2,
+ STM32_ALL_BANKS
+};
+
+struct stm32l4_wrp {
+ enum stm32l4_flash_reg_index reg_idx;
+ uint32_t value;
+ bool used;
+ int first;
+ int last;
+ int offset;
};
/* human readable list of families this drivers supports (sorted alphabetically) */
@@ -259,10 +299,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_415_revs),
.device_str = "STM32L47/L48xx",
.max_flash_size_kb = 1024,
- .has_dual_bank = true,
+ .flags = F_HAS_DUAL_BANK,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x435,
@@ -270,10 +312,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_435_revs),
.device_str = "STM32L43/L44xx",
.max_flash_size_kb = 256,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x460,
@@ -281,10 +325,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_460_revs),
.device_str = "STM32G07/G08xx",
.max_flash_size_kb = 128,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x461,
@@ -292,10 +338,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_461_revs),
.device_str = "STM32L49/L4Axx",
.max_flash_size_kb = 1024,
- .has_dual_bank = true,
+ .flags = F_HAS_DUAL_BANK,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x462,
@@ -303,10 +351,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_462_revs),
.device_str = "STM32L45/L46xx",
.max_flash_size_kb = 512,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x464,
@@ -314,10 +364,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_464_revs),
.device_str = "STM32L41/L42xx",
.max_flash_size_kb = 128,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x466,
@@ -325,10 +377,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_466_revs),
.device_str = "STM32G03/G04xx",
.max_flash_size_kb = 64,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x468,
@@ -336,10 +390,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_468_revs),
.device_str = "STM32G43/G44xx",
.max_flash_size_kb = 128,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x469,
@@ -347,10 +403,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_469_revs),
.device_str = "STM32G47/G48xx",
.max_flash_size_kb = 512,
- .has_dual_bank = true,
+ .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x470,
@@ -358,10 +416,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_470_revs),
.device_str = "STM32L4R/L4Sxx",
.max_flash_size_kb = 2048,
- .has_dual_bank = true,
+ .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x471,
@@ -369,10 +429,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_471_revs),
.device_str = "STM32L4P5/L4Q5x",
.max_flash_size_kb = 1024,
- .has_dual_bank = true,
+ .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x472,
@@ -380,10 +442,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_472_revs),
.device_str = "STM32L55/L56xx",
.max_flash_size_kb = 512,
- .has_dual_bank = true,
+ .flags = F_HAS_DUAL_BANK | F_USE_ALL_WRPXX | F_HAS_TZ,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l5_ns_flash_regs,
.fsize_addr = 0x0BFA05E0,
+ .otp_base = 0x0BFA0000,
+ .otp_size = 512,
},
{
.id = 0x479,
@@ -391,10 +455,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_479_revs),
.device_str = "STM32G49/G4Axx",
.max_flash_size_kb = 512,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x40022000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x495,
@@ -402,10 +468,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_495_revs),
.device_str = "STM32WB5x",
.max_flash_size_kb = 1024,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x58004000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x496,
@@ -413,10 +481,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_496_revs),
.device_str = "STM32WB3x",
.max_flash_size_kb = 512,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x58004000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
{
.id = 0x497,
@@ -424,10 +494,12 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32_497_revs),
.device_str = "STM32WLEx",
.max_flash_size_kb = 256,
- .has_dual_bank = false,
+ .flags = F_NONE,
.flash_regs_base = 0x58004000,
.default_flash_regs = stm32l4_flash_regs,
.fsize_addr = 0x1FFF75E0,
+ .otp_base = 0x1FFF7000,
+ .otp_size = 1024,
},
};
@@ -439,7 +511,11 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
- stm32l4_info = malloc(sizeof(struct stm32l4_flash_bank));
+ /* fix-up bank base address: 0 is used for normal flash memory */
+ if (bank->base == 0)
+ bank->base = STM32_FLASH_BANK_BASE;
+
+ stm32l4_info = calloc(1, sizeof(struct stm32l4_flash_bank));
if (!stm32l4_info)
return ERROR_FAIL; /* Checkme: What better error to use?*/
bank->driver_priv = stm32l4_info;
@@ -449,11 +525,129 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
bank->write_start_alignment = bank->write_end_alignment = 8;
stm32l4_info->probed = false;
+ stm32l4_info->otp_enabled = false;
stm32l4_info->user_bank_size = bank->size;
return ERROR_OK;
}
+/* bitmap helper extension */
+struct range {
+ unsigned int start;
+ unsigned int end;
+};
+
+static void bitmap_to_ranges(unsigned long *bitmap, unsigned int nbits,
+ struct range *ranges, unsigned int *ranges_count) {
+ *ranges_count = 0;
+ bool last_bit = 0, cur_bit;
+ for (unsigned int i = 0; i < nbits; i++) {
+ cur_bit = test_bit(i, bitmap);
+
+ if (cur_bit && !last_bit) {
+ (*ranges_count)++;
+ ranges[*ranges_count - 1].start = i;
+ ranges[*ranges_count - 1].end = i;
+ } else if (cur_bit && last_bit) {
+ /* update (increment) the end this range */
+ ranges[*ranges_count - 1].end = i;
+ }
+
+ last_bit = cur_bit;
+ }
+}
+
+static inline int range_print_one(struct range *range, char *str)
+{
+ if (range->start == range->end)
+ return sprintf(str, "[%d]", range->start);
+
+ return sprintf(str, "[%d,%d]", range->start, range->end);
+}
+
+static char *range_print_alloc(struct range *ranges, unsigned int ranges_count)
+{
+ /* each range will be printed like the following: [start,end]
+ * start and end, both are unsigned int, an unsigned int takes 10 characters max
+ * plus 3 characters for '[', ',' and ']'
+ * thus means each range can take maximum 23 character
+ * after each range we add a ' ' as separator and finally we need the '\0'
+ * if the ranges_count is zero we reserve one char for '\0' to return an empty string */
+ char *str = calloc(1, ranges_count * (24 * sizeof(char)) + 1);
+ char *ptr = str;
+
+ for (unsigned int i = 0; i < ranges_count; i++) {
+ ptr += range_print_one(&(ranges[i]), ptr);
+
+ if (i < ranges_count - 1)
+ *(ptr++) = ' ';
+ }
+
+ return str;
+}
+
+/* end of bitmap helper extension */
+
+static inline bool stm32l4_is_otp(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ return bank->base == stm32l4_info->part_info->otp_base;
+}
+
+static int stm32l4_otp_enable(struct flash_bank *bank, bool enable)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ if (!stm32l4_is_otp(bank))
+ return ERROR_FAIL;
+
+ char *op_str = enable ? "enabled" : "disabled";
+
+ LOG_INFO("OTP memory (bank #%d) is %s%s for write commands",
+ bank->bank_number,
+ stm32l4_info->otp_enabled == enable ? "already " : "",
+ op_str);
+
+ stm32l4_info->otp_enabled = enable;
+
+ return ERROR_OK;
+}
+
+static inline bool stm32l4_otp_is_enabled(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ return stm32l4_info->otp_enabled;
+}
+
+static void stm32l4_sync_rdp_tzen(struct flash_bank *bank, uint32_t optr_value)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ bool tzen = false;
+
+ if (stm32l4_info->part_info->flags & F_HAS_TZ)
+ tzen = (optr_value & FLASH_TZEN) != 0;
+
+ uint32_t rdp = optr_value & FLASH_RDP_MASK;
+
+ /* for devices without TrustZone:
+ * RDP level 0 and 2 values are to 0xAA and 0xCC
+ * Any other value corresponds to RDP level 1
+ * for devices with TrusZone:
+ * RDP level 0 and 2 values are 0xAA and 0xCC
+ * RDP level 0.5 value is 0x55 only if TZEN = 1
+ * Any other value corresponds to RDP level 1, including 0x55 if TZEN = 0
+ */
+
+ if (rdp != RDP_LEVEL_0 && rdp != RDP_LEVEL_2) {
+ if (!tzen || (tzen && rdp != RDP_LEVEL_0_5))
+ rdp = RDP_LEVEL_1;
+ }
+
+ stm32l4_info->tzen = tzen;
+ stm32l4_info->rdp = rdp;
+}
+
static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
@@ -635,53 +829,125 @@ err_lock:
return retval2;
}
-static int stm32l4_protect_check(struct flash_bank *bank)
+static int stm32l4_get_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy,
+ enum stm32l4_flash_reg_index reg_idx, int offset)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ int ret;
- uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
- stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1AR_INDEX, &wrp1ar);
- stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1BR_INDEX, &wrp1br);
- if (stm32l4_info->part_info->has_dual_bank) {
- stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2AR_INDEX, &wrp2ar);
- stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2BR_INDEX, &wrp2br);
- } else {
- /* prevent uninitialized errors */
- wrp2ar = 0;
- wrp2br = 0;
+ wrpxy->reg_idx = reg_idx;
+ wrpxy->offset = offset;
+
+ ret = stm32l4_read_flash_reg_by_index(bank, wrpxy->reg_idx , &wrpxy->value);
+ if (ret != ERROR_OK)
+ return ret;
+
+ wrpxy->first = (wrpxy->value & stm32l4_info->wrpxxr_mask) + wrpxy->offset;
+ wrpxy->last = ((wrpxy->value >> 16) & stm32l4_info->wrpxxr_mask) + wrpxy->offset;
+ wrpxy->used = wrpxy->first <= wrpxy->last;
+
+ return ERROR_OK;
+}
+
+static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev_bank_id,
+ struct stm32l4_wrp *wrpxy, unsigned int *n_wrp)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ int ret;
+
+ *n_wrp = 0;
+
+ /* for single bank devices there is 2 WRP regions.
+ * for dual bank devices there is 2 WRP regions per bank,
+ * if configured as single bank only 2 WRP are usable
+ * except for STM32L4R/S/P/Q, G4 cat3, L5 ... all 4 WRP are usable
+ * note: this should be revised, if a device will have the SWAP banks option
+ */
+
+ int wrp2y_sectors_offset = -1; /* -1 : unused */
+
+ /* if bank_id is BANK1 or ALL_BANKS */
+ if (dev_bank_id != STM32_BANK2) {
+ /* get FLASH_WRP1AR */
+ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1AR_INDEX, 0);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* get WRP1BR */
+ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP1BR_INDEX, 0);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* for some devices (like STM32L4R/S) in single-bank mode, the 4 WRPxx are usable */
+ if ((stm32l4_info->part_info->flags & F_USE_ALL_WRPXX) && !stm32l4_info->dual_bank_mode)
+ wrp2y_sectors_offset = 0;
}
- const uint8_t wrp1a_start = wrp1ar & stm32l4_info->wrpxxr_mask;
- const uint8_t wrp1a_end = (wrp1ar >> 16) & stm32l4_info->wrpxxr_mask;
- const uint8_t wrp1b_start = wrp1br & stm32l4_info->wrpxxr_mask;
- const uint8_t wrp1b_end = (wrp1br >> 16) & stm32l4_info->wrpxxr_mask;
- const uint8_t wrp2a_start = wrp2ar & stm32l4_info->wrpxxr_mask;
- const uint8_t wrp2a_end = (wrp2ar >> 16) & stm32l4_info->wrpxxr_mask;
- const uint8_t wrp2b_start = wrp2br & stm32l4_info->wrpxxr_mask;
- const uint8_t wrp2b_end = (wrp2br >> 16) & stm32l4_info->wrpxxr_mask;
+ /* if bank_id is BANK2 or ALL_BANKS */
+ if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode)
+ wrp2y_sectors_offset = stm32l4_info->bank1_sectors;
- for (unsigned int i = 0; i < bank->num_sectors; i++) {
- if (i < stm32l4_info->bank1_sectors) {
- if (((i >= wrp1a_start) &&
- (i <= wrp1a_end)) ||
- ((i >= wrp1b_start) &&
- (i <= wrp1b_end)))
- bank->sectors[i].is_protected = 1;
- else
- bank->sectors[i].is_protected = 0;
- } else {
- assert(stm32l4_info->part_info->has_dual_bank == true);
- uint8_t snb;
- snb = i - stm32l4_info->bank1_sectors;
- if (((snb >= wrp2a_start) &&
- (snb <= wrp2a_end)) ||
- ((snb >= wrp2b_start) &&
- (snb <= wrp2b_end)))
- bank->sectors[i].is_protected = 1;
- else
- bank->sectors[i].is_protected = 0;
+ if (wrp2y_sectors_offset > -1) {
+ /* get WRP2AR */
+ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2AR_INDEX, wrp2y_sectors_offset);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* get WRP2BR */
+ ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2BR_INDEX, wrp2y_sectors_offset);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ return ERROR_OK;
+}
+
+static int stm32l4_write_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+ int wrp_start = wrpxy->first - wrpxy->offset;
+ int wrp_end = wrpxy->last - wrpxy->offset;
+
+ uint32_t wrp_value = (wrp_start & stm32l4_info->wrpxxr_mask) | ((wrp_end & stm32l4_info->wrpxxr_mask) << 16);
+
+ return stm32l4_write_option(bank, stm32l4_info->flash_regs[wrpxy->reg_idx], wrp_value, 0xffffffff);
+}
+
+static int stm32l4_write_all_wrpxy(struct flash_bank *bank, struct stm32l4_wrp *wrpxy, unsigned int n_wrp)
+{
+ int ret;
+
+ for (unsigned int i = 0; i < n_wrp; i++) {
+ ret = stm32l4_write_one_wrpxy(bank, &wrpxy[i]);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ return ERROR_OK;
+}
+
+static int stm32l4_protect_check(struct flash_bank *bank)
+{
+ unsigned int n_wrp;
+ struct stm32l4_wrp wrpxy[4];
+
+ int ret = stm32l4_get_all_wrpxy(bank, STM32_ALL_BANKS, wrpxy, &n_wrp);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* initialize all sectors as unprotected */
+ for (unsigned int i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_protected = 0;
+
+ /* now check WRPxy and mark the protected sectors */
+ for (unsigned int i = 0; i < n_wrp; i++) {
+ if (wrpxy[i].used) {
+ for (int s = wrpxy[i].first; s <= wrpxy[i].last; s++)
+ bank->sectors[s].is_protected = 1;
}
}
+
return ERROR_OK;
}
@@ -693,6 +959,11 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first,
assert((first <= last) && (last < bank->num_sectors));
+ if (stm32l4_is_otp(bank)) {
+ LOG_ERROR("cannot erase OTP memory");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -743,40 +1014,133 @@ err_lock:
return retval2;
}
-static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
- unsigned int last)
+static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
{
struct target *target = bank->target;
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ int ret = ERROR_OK;
+ unsigned int i;
+
+ if (stm32l4_is_otp(bank)) {
+ LOG_ERROR("cannot protect/unprotect OTP memory");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- int ret = ERROR_OK;
- /* Bank 2 */
- uint32_t reg_value = 0xFF; /* Default to bank un-protected */
+ /* the requested sectors could be located into bank1 and/or bank2 */
+ bool use_bank2 = false;
if (last >= stm32l4_info->bank1_sectors) {
- if (set == 1) {
- uint8_t begin = first > stm32l4_info->bank1_sectors ? first : 0x00;
- reg_value = ((last & 0xFF) << 16) | begin;
+ if (first < stm32l4_info->bank1_sectors) {
+ /* the requested sectors for (un)protection are shared between
+ * bank 1 and 2, then split the operation */
+
+ /* 1- deal with bank 1 sectors */
+ LOG_DEBUG("The requested sectors for %s are shared between bank 1 and 2",
+ set ? "protection" : "unprotection");
+ ret = stm32l4_protect(bank, set, first, stm32l4_info->bank1_sectors - 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* 2- then continue with bank 2 sectors */
+ first = stm32l4_info->bank1_sectors;
}
- ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP2AR_INDEX], reg_value, 0xffffffff);
+ use_bank2 = true;
+ }
+
+ /* refresh the sectors' protection */
+ ret = stm32l4_protect_check(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* check if the desired protection is already configured */
+ for (i = first; i <= last; i++) {
+ if (bank->sectors[i].is_protected != set)
+ break;
+ else if (i == last) {
+ LOG_INFO("The specified sectors are already %s", set ? "protected" : "unprotected");
+ return ERROR_OK;
+ }
}
- /* Bank 1 */
- reg_value = 0xFF; /* Default to bank un-protected */
- if (first < stm32l4_info->bank1_sectors) {
- if (set == 1) {
- uint8_t end = last >= stm32l4_info->bank1_sectors ? 0xFF : last;
- reg_value = (end << 16) | (first & 0xFF);
+
+ /* all sectors from first to last (or part of them) could have different
+ * protection other than the requested */
+ unsigned int n_wrp;
+ struct stm32l4_wrp wrpxy[4];
+
+ ret = stm32l4_get_all_wrpxy(bank, use_bank2 ? STM32_BANK2 : STM32_BANK1, wrpxy, &n_wrp);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* use bitmap and range helpers to optimize the WRP usage */
+ DECLARE_BITMAP(pages, bank->num_sectors);
+ bitmap_zero(pages, bank->num_sectors);
+
+ for (i = 0; i < n_wrp; i++) {
+ if (wrpxy[i].used) {
+ for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++)
+ set_bit(p, pages);
}
+ }
- ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP1AR_INDEX], reg_value, 0xffffffff);
+ /* we have at most 'n_wrp' WRP areas
+ * add one range if the user is trying to protect a fifth range */
+ struct range ranges[n_wrp + 1];
+ unsigned int ranges_count = 0;
+
+ bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count);
+
+ /* pretty-print the currently protected ranges */
+ if (ranges_count > 0) {
+ char *ranges_str = range_print_alloc(ranges, ranges_count);
+ LOG_DEBUG("current protected areas: %s", ranges_str);
+ free(ranges_str);
+ } else
+ LOG_DEBUG("current protected areas: none");
+
+ if (set) { /* flash protect */
+ for (i = first; i <= last; i++)
+ set_bit(i, pages);
+ } else { /* flash unprotect */
+ for (i = first; i <= last; i++)
+ clear_bit(i, pages);
}
- return ret;
+ /* check the ranges_count after the user request */
+ bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count);
+
+ /* pretty-print the requested areas for protection */
+ if (ranges_count > 0) {
+ char *ranges_str = range_print_alloc(ranges, ranges_count);
+ LOG_DEBUG("requested areas for protection: %s", ranges_str);
+ free(ranges_str);
+ } else
+ LOG_DEBUG("requested areas for protection: none");
+
+ if (ranges_count > n_wrp) {
+ LOG_ERROR("cannot set the requested protection "
+ "(only %u write protection areas are available)" , n_wrp);
+ return ERROR_FAIL;
+ }
+
+ /* re-init all WRPxy as disabled (first > last)*/
+ for (i = 0; i < n_wrp; i++) {
+ wrpxy[i].first = wrpxy[i].offset + 1;
+ wrpxy[i].last = wrpxy[i].offset;
+ }
+
+ /* then configure WRPxy areas */
+ for (i = 0; i < ranges_count; i++) {
+ wrpxy[i].first = ranges[i].start;
+ wrpxy[i].last = ranges[i].end;
+ }
+
+ /* finally write WRPxy registers */
+ return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp);
}
/* Count is in double-words */
@@ -883,6 +1247,11 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
{
int retval = ERROR_OK, retval2;
+ if (stm32l4_is_otp(bank) && !stm32l4_otp_is_enabled(bank)) {
+ LOG_ERROR("OTP memory is disabled for write commands");
+ return ERROR_FAIL;
+ }
+
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -1001,6 +1370,44 @@ static int stm32l4_probe(struct flash_bank *bank)
LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, device_info);
+ /* read flash option register */
+ retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &options);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stm32l4_sync_rdp_tzen(bank, options);
+
+ if (part_info->flags & F_HAS_TZ)
+ LOG_INFO("TZEN = %d : TrustZone %s by option bytes",
+ stm32l4_info->tzen,
+ stm32l4_info->tzen ? "enabled" : "disabled");
+
+ LOG_INFO("RDP level %s (0x%02X)",
+ stm32l4_info->rdp == RDP_LEVEL_0 ? "0" : stm32l4_info->rdp == RDP_LEVEL_0_5 ? "0.5" : "1",
+ stm32l4_info->rdp);
+
+ if (stm32l4_is_otp(bank)) {
+ bank->size = part_info->otp_size;
+
+ LOG_INFO("OTP size is %d bytes, base address is " TARGET_ADDR_FMT, bank->size, bank->base);
+
+ /* OTP memory is considered as one sector */
+ free(bank->sectors);
+ bank->num_sectors = 1;
+ bank->sectors = alloc_block_array(0, part_info->otp_size, 1);
+
+ if (!bank->sectors) {
+ LOG_ERROR("failed to allocate bank sectors");
+ return ERROR_FAIL;
+ }
+
+ stm32l4_info->probed = true;
+ return ERROR_OK;
+ } else if (bank->base != STM32_FLASH_BANK_BASE) {
+ LOG_ERROR("invalid bank base address");
+ return ERROR_FAIL;
+ }
+
/* get flash size from target. */
retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb);
@@ -1025,11 +1432,6 @@ static int stm32l4_probe(struct flash_bank *bank)
/* did we assign a flash size? */
assert((flash_size_kb != 0xffff) && flash_size_kb);
- /* read flash option register */
- retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &options);
- if (retval != ERROR_OK)
- return retval;
-
stm32l4_info->bank1_sectors = 0;
stm32l4_info->hole_sectors = 0;
@@ -1175,7 +1577,6 @@ static int stm32l4_probe(struct flash_bank *bank)
free(bank->sectors);
bank->size = (flash_size_kb + gap_size_kb) * 1024;
- bank->base = STM32_FLASH_BANK_BASE;
bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (bank->sectors == NULL) {
@@ -1227,6 +1628,7 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
if (stm32l4_info->probed)
snprintf(buf + buf_len, buf_size - buf_len, " - %s-bank",
+ stm32l4_is_otp(bank) ? "OTP" :
stm32l4_info->dual_bank_mode ? "Flash dual" : "Flash single");
return ERROR_OK;
@@ -1244,9 +1646,14 @@ static int stm32l4_mass_erase(struct flash_bank *bank)
struct target *target = bank->target;
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ if (stm32l4_is_otp(bank)) {
+ LOG_ERROR("cannot erase OTP memory");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
uint32_t action = FLASH_MER1;
- if (stm32l4_info->part_info->has_dual_bank)
+ if (stm32l4_info->part_info->flags & F_HAS_DUAL_BANK)
action |= FLASH_MER2;
if (target->state != TARGET_HALTED) {
@@ -1410,6 +1817,11 @@ COMMAND_HANDLER(stm32l4_handle_lock_command)
if (ERROR_OK != retval)
return retval;
+ if (stm32l4_is_otp(bank)) {
+ LOG_ERROR("cannot lock/unlock OTP memory");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
target = bank->target;
if (target->state != TARGET_HALTED) {
@@ -1419,7 +1831,8 @@ COMMAND_HANDLER(stm32l4_handle_lock_command)
/* set readout protection level 1 by erasing the RDP option byte */
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
- if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], 0, 0x000000FF) != ERROR_OK) {
+ if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX],
+ RDP_LEVEL_1, FLASH_RDP_MASK) != ERROR_OK) {
command_print(CMD, "%s failed to lock device", bank->driver->name);
return ERROR_OK;
}
@@ -1439,6 +1852,11 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
if (ERROR_OK != retval)
return retval;
+ if (stm32l4_is_otp(bank)) {
+ LOG_ERROR("cannot lock/unlock OTP memory");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
target = bank->target;
if (target->state != TARGET_HALTED) {
@@ -1448,7 +1866,7 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX],
- RDP_LEVEL_0, 0x000000FF) != ERROR_OK) {
+ RDP_LEVEL_0, FLASH_RDP_MASK) != ERROR_OK) {
command_print(CMD, "%s failed to unlock device", bank->driver->name);
return ERROR_OK;
}
@@ -1456,6 +1874,105 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
return ERROR_OK;
}
+COMMAND_HANDLER(stm32l4_handle_wrp_info_command)
+{
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (stm32l4_is_otp(bank)) {
+ LOG_ERROR("OTP memory does not have write protection areas");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ enum stm32_bank_id dev_bank_id = STM32_ALL_BANKS;
+ if (CMD_ARGC == 2) {
+ if (strcmp(CMD_ARGV[1], "bank1") == 0)
+ dev_bank_id = STM32_BANK1;
+ else if (strcmp(CMD_ARGV[1], "bank2") == 0)
+ dev_bank_id = STM32_BANK2;
+ else
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ if (dev_bank_id == STM32_BANK2) {
+ if (!(stm32l4_info->part_info->flags & F_HAS_DUAL_BANK)) {
+ LOG_ERROR("this device has no second bank");
+ return ERROR_FAIL;
+ } else if (!stm32l4_info->dual_bank_mode) {
+ LOG_ERROR("this device is configured in single bank mode");
+ return ERROR_FAIL;
+ }
+ }
+
+ int ret;
+ unsigned int n_wrp, i;
+ struct stm32l4_wrp wrpxy[4];
+
+ ret = stm32l4_get_all_wrpxy(bank, dev_bank_id, wrpxy, &n_wrp);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* use bitmap and range helpers to better describe protected areas */
+ DECLARE_BITMAP(pages, bank->num_sectors);
+ bitmap_zero(pages, bank->num_sectors);
+
+ for (i = 0; i < n_wrp; i++) {
+ if (wrpxy[i].used) {
+ for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++)
+ set_bit(p, pages);
+ }
+ }
+
+ /* we have at most 'n_wrp' WRP areas */
+ struct range ranges[n_wrp];
+ unsigned int ranges_count = 0;
+
+ bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count);
+
+ if (ranges_count > 0) {
+ /* pretty-print the protected ranges */
+ char *ranges_str = range_print_alloc(ranges, ranges_count);
+ command_print(CMD, "protected areas: %s", ranges_str);
+ free(ranges_str);
+ } else
+ command_print(CMD, "no protected areas");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32l4_handle_otp_command)
+{
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (!stm32l4_is_otp(bank)) {
+ command_print(CMD, "the specified bank is not an OTP memory");
+ return ERROR_FAIL;
+ }
+ if (strcmp(CMD_ARGV[1], "enable") == 0)
+ stm32l4_otp_enable(bank, true);
+ else if (strcmp(CMD_ARGV[1], "disable") == 0)
+ stm32l4_otp_enable(bank, false);
+ else if (strcmp(CMD_ARGV[1], "show") == 0)
+ command_print(CMD, "OTP memory bank #%d is %s for write commands.",
+ bank->bank_number, stm32l4_otp_is_enabled(bank) ? "enabled" : "disabled");
+ else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ return ERROR_OK;
+}
+
static const struct command_registration stm32l4_exec_command_handlers[] = {
{
.name = "lock",
@@ -1493,12 +2010,26 @@ static const struct command_registration stm32l4_exec_command_handlers[] = {
.help = "Write device option bit fields with provided value.",
},
{
+ .name = "wrp_info",
+ .handler = stm32l4_handle_wrp_info_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id [bank1|bank2]",
+ .help = "list the protected areas using WRP",
+ },
+ {
.name = "option_load",
.handler = stm32l4_handle_option_load_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Force re-load of device options (will cause device reset).",
},
+ {
+ .name = "otp",
+ .handler = stm32l4_handle_otp_command,
+ .mode = COMMAND_EXEC,
+ .usage = "<bank_id> <enable|disable|show>",
+ .help = "OTP (One Time Programmable) memory write enable/disable",
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h
index 3e810a0..41b5ff8 100644
--- a/src/flash/nor/stm32l4x.h
+++ b/src/flash/nor/stm32l4x.h
@@ -56,9 +56,9 @@
#define OPTKEY1 0x08192A3B
#define OPTKEY2 0x4C5D6E7F
-#define RDP_LEVEL_0 0xAA
-#define RDP_LEVEL_1 0xBB
-#define RDP_LEVEL_2 0xCC
+/* FLASH_OPTR register bits */
+#define FLASH_RDP_MASK 0xFF
+#define FLASH_TZEN (1 << 31)
/* other registers */
#define DBGMCU_IDCODE_G0 0x40015800
diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c
index a013336..11aa438 100644
--- a/src/flash/nor/stmqspi.c
+++ b/src/flash/nor/stmqspi.c
@@ -52,14 +52,6 @@
#undef SPIFLASH_READ
#undef SPIFLASH_PAGE_PROGRAM
-#define READ_REG(a) \
-({ \
- uint32_t _result; \
- \
- retval = target_read_u32(target, io_base + (a), &_result); \
- (retval == ERROR_OK) ? _result : 0x0; \
-})
-
/* saved mode settings */
#define QSPI_MODE (stmqspi_info->saved_ccr & \
(0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4))
@@ -156,23 +148,6 @@
#define OPI_CMD(cmd) ((OPI_MODE ? ((((uint16_t)(cmd)) << 8) | (~(cmd) & 0xFFU)) : (cmd)))
-#define OCTOSPI_CMD(mode, ccr, ir) \
-({ \
- retval = target_write_u32(target, io_base + OCTOSPI_CR, \
- OCTOSPI_MODE | (mode)); \
- if (retval == ERROR_OK) \
- retval = target_write_u32(target, io_base + OCTOSPI_TCR, \
- (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | \
- ((OPI_MODE && ((mode) == OCTOSPI_READ_MODE)) ? \
- (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0)); \
- if (retval == ERROR_OK) \
- retval = target_write_u32(target, io_base + OCTOSPI_CCR, ccr); \
- if (retval == ERROR_OK) \
- retval = target_write_u32(target, io_base + OCTOSPI_IR, \
- OPI_CMD(ir)); \
- retval; \
-})
-
/* convert uint32_t into 4 uint8_t in little endian byte order */
static inline uint32_t h_to_le_32(uint32_t val)
{
@@ -208,6 +183,35 @@ struct stmqspi_flash_bank {
unsigned int sfdp_dummy2; /* number of dummy bytes for SFDP read for flash2 */
};
+static inline int octospi_cmd(struct flash_bank *bank, uint32_t mode,
+ uint32_t ccr, uint32_t ir)
+{
+ struct target *target = bank->target;
+ const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv;
+ const uint32_t io_base = stmqspi_info->io_base;
+
+ int retval = target_write_u32(target, io_base + OCTOSPI_CR,
+ OCTOSPI_MODE | mode);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = target_write_u32(target, io_base + OCTOSPI_TCR,
+ (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) |
+ ((OPI_MODE && (mode == OCTOSPI_READ_MODE)) ?
+ (OPI_DUMMY << OCTOSPI_DCYC_POS) : 0));
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = target_write_u32(target, io_base + OCTOSPI_CCR, ccr);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ return target_write_u32(target, io_base + OCTOSPI_IR, OPI_CMD(ir));
+}
+
FLASH_BANK_COMMAND_HANDLER(stmqspi_flash_bank_command)
{
struct stmqspi_flash_bank *stmqspi_info;
@@ -242,19 +246,19 @@ static int poll_busy(struct flash_bank *bank, int timeout)
struct target *target = bank->target;
struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv;
uint32_t io_base = stmqspi_info->io_base;
- uint32_t spi_sr;
- int retval;
long long endtime;
endtime = timeval_ms() + timeout;
do {
- spi_sr = READ_REG(SPI_SR);
- if ((spi_sr & BIT(SPI_BUSY)) == 0) {
- if (retval == ERROR_OK) {
- /* Clear transmit finished flag */
- retval = target_write_u32(target, io_base + SPI_FCR, BIT(SPI_TCF));
- }
+ uint32_t spi_sr;
+ int retval = target_read_u32(target, io_base + SPI_SR, &spi_sr);
+
+ if (retval != ERROR_OK)
return retval;
+
+ if ((spi_sr & BIT(SPI_BUSY)) == 0) {
+ /* Clear transmit finished flag */
+ return target_write_u32(target, io_base + SPI_FCR, BIT(SPI_TCF));
} else
LOG_DEBUG("busy: 0x%08X", spi_sr);
alive_sleep(1);
@@ -264,6 +268,21 @@ static int poll_busy(struct flash_bank *bank, int timeout)
return ERROR_FLASH_OPERATION_FAILED;
}
+static int stmqspi_abort(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ const struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv;
+ const uint32_t io_base = stmqspi_info->io_base;
+ uint32_t cr;
+
+ int retval = target_read_u32(target, io_base + SPI_CR, &cr);
+
+ if (retval != ERROR_OK)
+ cr = 0;
+
+ return target_write_u32(target, io_base + SPI_CR, cr | BIT(SPI_ABORT));
+}
+
/* Set to memory-mapped mode, e.g. after an error */
static int set_mm_mode(struct flash_bank *bank)
{
@@ -278,8 +297,7 @@ static int set_mm_mode(struct flash_bank *bank)
return retval;
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -321,8 +339,7 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status)
int count, retval;
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -340,7 +357,8 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status)
/* Read status */
if (IS_OCTOSPI) {
- retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_STATUS, SPIFLASH_READ_STATUS);
+ retval = octospi_cmd(bank, OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_STATUS,
+ SPIFLASH_READ_STATUS);
if (OPI_MODE) {
/* Dummy address 0, only required for 8-line mode */
retval = target_write_u32(target, io_base + SPI_AR, 0);
@@ -355,7 +373,8 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status)
*status = 0;
/* for debugging only */
- (void)READ_REG(SPI_SR);
+ uint32_t dummy;
+ (void)target_read_u32(target, io_base + SPI_SR, &dummy);
for ( ; count > 0; --count) {
if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH)))
@@ -416,8 +435,7 @@ static int qspi_write_enable(struct flash_bank *bank)
int retval;
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -428,7 +446,8 @@ static int qspi_write_enable(struct flash_bank *bank)
/* Send write enable command */
if (IS_OCTOSPI) {
- retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_WRITE_ENABLE, SPIFLASH_WRITE_ENABLE);
+ retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_WRITE_ENABLE,
+ SPIFLASH_WRITE_ENABLE);
if (OPI_MODE) {
/* Dummy address 0, only required for 8-line mode */
retval = target_write_u32(target, io_base + SPI_AR, 0);
@@ -527,7 +546,7 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command)
/* Send Mass Erase command */
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_MASS_ERASE,
+ retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_MASS_ERASE,
stmqspi_info->dev.chip_erase_cmd);
else
retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_MASS_ERASE);
@@ -714,10 +733,15 @@ COMMAND_HANDLER(stmqspi_handle_set)
bank->size = stmqspi_info->dev.size_in_bytes << dual;
io_base = stmqspi_info->io_base;
- fsize = (READ_REG(SPI_DCR) >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1);
+
+ uint32_t dcr;
+ retval = target_read_u32(target, io_base + SPI_DCR, &dcr);
+
if (retval != ERROR_OK)
return retval;
+ fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1);
+
LOG_DEBUG("FSIZE = 0x%04x", fsize);
if (bank->size == BIT(fsize + 1))
LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1.");
@@ -823,8 +847,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd)
}
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -842,7 +865,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd)
goto err;
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE,
+ retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE,
(OCTOSPI_MODE_CCR & OCTOSPI_NO_ALTB & OCTOSPI_NO_ADDR &
((num_write == 1) ? OCTOSPI_NO_DATA : ~0U)), cmd_byte);
else
@@ -879,7 +902,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd)
if (retval != ERROR_OK)
goto err;
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_READ_MODE,
+ retval = octospi_cmd(bank, OCTOSPI_READ_MODE,
(OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & OCTOSPI_NO_ALTB & ~OCTOSPI_ADDR4 &
((num_write == 1) ? OCTOSPI_NO_ADDR : ~0U)) |
(((num_write - 2) & 0x3U) << SPI_ADSIZE_POS), cmd_byte);
@@ -930,7 +953,7 @@ static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector)
/* Send Sector Erase command */
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_SECTOR_ERASE,
+ retval = octospi_cmd(bank, OCTOSPI_WRITE_MODE, OCTOSPI_CCR_SECTOR_ERASE,
stmqspi_info->dev.erase_cmd);
else
retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_SECTOR_ERASE);
@@ -1059,7 +1082,6 @@ static int stmqspi_blank_check(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv;
- uint32_t io_base = stmqspi_info->io_base;
struct duration bench;
struct reg_param reg_params[2];
struct armv7m_algorithm armv7m_info;
@@ -1082,8 +1104,7 @@ static int stmqspi_blank_check(struct flash_bank *bank)
}
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -1568,7 +1589,6 @@ static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer,
{
struct target *target = bank->target;
struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv;
- uint32_t io_base = stmqspi_info->io_base;
int retval;
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
@@ -1590,8 +1610,7 @@ static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer,
}
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -1608,7 +1627,6 @@ static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer,
{
struct target *target = bank->target;
struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv;
- uint32_t io_base = stmqspi_info->io_base;
unsigned int dual, sector;
bool octal_dtr;
int retval;
@@ -1653,8 +1671,7 @@ static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer,
}
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -1671,7 +1688,6 @@ static int stmqspi_verify(struct flash_bank *bank, const uint8_t *buffer,
{
struct target *target = bank->target;
struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv;
- uint32_t io_base = stmqspi_info->io_base;
unsigned int dual;
bool octal_dtr;
int retval;
@@ -1704,8 +1720,7 @@ static int stmqspi_verify(struct flash_bank *bank, const uint8_t *buffer,
}
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -1757,8 +1772,8 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len)
/* Read SFDP block */
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len),
- SPIFLASH_READ_SFDP);
+ retval = octospi_cmd(bank, OCTOSPI_READ_MODE,
+ OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP);
else
retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP);
if (retval != ERROR_OK)
@@ -1804,8 +1819,7 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len)
err:
/* Abort operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
return retval;
}
@@ -1880,8 +1894,8 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr,
/* Read SFDP block */
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len),
- SPIFLASH_READ_SFDP);
+ retval = octospi_cmd(bank, OCTOSPI_READ_MODE,
+ OCTOSPI_CCR_READ_SFDP(len), SPIFLASH_READ_SFDP);
else
retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP);
if (retval != ERROR_OK)
@@ -1959,8 +1973,7 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2)
/* SPIFLASH_READ_MID causes device in octal mode to go berserk, so don't use in this case */
for (type = (IS_OCTOSPI && OPI_MODE) ? 1 : 0; type < 2 ; type++) {
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
goto err;
@@ -1986,14 +1999,16 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2)
switch (type) {
case 0:
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID);
+ retval = octospi_cmd(bank, OCTOSPI_READ_MODE,
+ OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID);
else
retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_MID);
break;
case 1:
if (IS_OCTOSPI)
- retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID);
+ retval = octospi_cmd(bank, OCTOSPI_READ_MODE,
+ OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID);
else
retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_ID);
break;
@@ -2013,7 +2028,8 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2)
}
/* for debugging only */
- (void)READ_REG(SPI_SR);
+ uint32_t dummy;
+ (void)target_read_u32(target, io_base + SPI_SR, &dummy);
/* Read ID from Data Register */
for (len1 = 0, len2 = 0; count > 0; --count) {
@@ -2092,8 +2108,7 @@ static int stmqspi_probe(struct flash_bank *bank)
}
/* Abort any previous operation */
- retval = target_write_u32(target, io_base + SPI_CR,
- READ_REG(SPI_CR) | BIT(SPI_ABORT));
+ retval = stmqspi_abort(bank);
if (retval != ERROR_OK)
return retval;
@@ -2112,43 +2127,59 @@ static int stmqspi_probe(struct flash_bank *bank)
if (data == magic) {
LOG_DEBUG("QSPI_ABR register present");
stmqspi_info->octo = false;
- } else if (READ_REG(OCTOSPI_MAGIC) == OCTO_MAGIC_ID) {
- LOG_DEBUG("OCTOSPI_MAGIC present");
- stmqspi_info->octo = true;
} else {
- LOG_ERROR("No QSPI, no OCTOSPI at 0x%08" PRIx32, io_base);
- stmqspi_info->probed = false;
- stmqspi_info->dev.name = "none";
- return ERROR_FAIL;
+ uint32_t magic_id;
+
+ retval = target_read_u32(target, io_base + OCTOSPI_MAGIC, &magic_id);
+
+ if (retval == ERROR_OK && magic_id == OCTO_MAGIC_ID) {
+ LOG_DEBUG("OCTOSPI_MAGIC present");
+ stmqspi_info->octo = true;
+ } else {
+ LOG_ERROR("No QSPI, no OCTOSPI at 0x%08" PRIx32, io_base);
+ stmqspi_info->probed = false;
+ stmqspi_info->dev.name = "none";
+ return ERROR_FAIL;
+ }
}
/* save current FSEL and DFM bits in QSPI/OCTOSPI_CR, current QSPI/OCTOSPI_CCR value */
- stmqspi_info->saved_cr = READ_REG(SPI_CR);
+ retval = target_read_u32(target, io_base + SPI_CR, &stmqspi_info->saved_cr);
if (retval == ERROR_OK)
- stmqspi_info->saved_ccr = READ_REG(SPI_CCR);
+ retval = target_read_u32(target, io_base + SPI_CCR, &stmqspi_info->saved_ccr);
if (IS_OCTOSPI) {
- uint32_t mtyp;
+ uint32_t dcr1;
+
+ retval = target_read_u32(target, io_base + OCTOSPI_DCR1, &dcr1);
- mtyp = ((READ_REG(OCTOSPI_DCR1) & OCTOSPI_MTYP_MASK)) >> OCTOSPI_MTYP_POS;
if (retval == ERROR_OK)
- stmqspi_info->saved_tcr = READ_REG(OCTOSPI_TCR);
+ retval = target_read_u32(target, io_base + OCTOSPI_TCR,
+ &stmqspi_info->saved_tcr);
+
if (retval == ERROR_OK)
- stmqspi_info->saved_ir = READ_REG(OCTOSPI_IR);
+ retval = target_read_u32(target, io_base + OCTOSPI_IR,
+ &stmqspi_info->saved_ir);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("No OCTOSPI at io_base 0x%08" PRIx32, io_base);
+ stmqspi_info->probed = false;
+ stmqspi_info->dev.name = "none";
+ return ERROR_FAIL;
+ }
+
+ const uint32_t mtyp = (dcr1 & OCTOSPI_MTYP_MASK) >> OCTOSPI_MTYP_POS;
+
if ((mtyp != 0x0) && (mtyp != 0x1)) {
- retval = ERROR_FAIL;
LOG_ERROR("Only regular SPI protocol supported in OCTOSPI");
- }
- if (retval == ERROR_OK) {
- LOG_DEBUG("OCTOSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", OCTOSPI_CR 0x%08"
- PRIx32 ", OCTOSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base,
- stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE);
- } else {
- LOG_ERROR("No OCTOSPI at io_base 0x%08" PRIx32, io_base);
stmqspi_info->probed = false;
stmqspi_info->dev.name = "none";
return ERROR_FAIL;
}
+
+ LOG_DEBUG("OCTOSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", OCTOSPI_CR 0x%08"
+ PRIx32 ", OCTOSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base,
+ stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE);
} else {
if (retval == ERROR_OK) {
LOG_DEBUG("QSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", QSPI_CR 0x%08"
@@ -2301,10 +2332,14 @@ static int stmqspi_probe(struct flash_bank *bank)
/* Set correct size value */
bank->size = stmqspi_info->dev.size_in_bytes << dual;
- fsize = ((READ_REG(SPI_DCR) >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1));
+ uint32_t dcr;
+ retval = target_read_u32(target, io_base + SPI_DCR, &dcr);
+
if (retval != ERROR_OK)
goto err;
+ fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1);
+
LOG_DEBUG("FSIZE = 0x%04x", fsize);
if (bank->size == BIT((fsize + 1)))
LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1.");
diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl
index 280a059..7d9dbc7 100644
--- a/src/flash/startup.tcl
+++ b/src/flash/startup.tcl
@@ -119,14 +119,3 @@ proc stm32g4x args { eval stm32l4x $args }
proc stm32l5x args { eval stm32l4x $args }
proc stm32wbx args { eval stm32l4x $args }
proc stm32wlx args { eval stm32l4x $args }
-
-# ease migration to updated flash driver
-proc stm32x args {
- echo "DEPRECATED! use 'stm32f1x $args' not 'stm32x $args'"
- eval stm32f1x $args
-}
-
-proc stm32f2xxx args {
- echo "DEPRECATED! use 'stm32f2x $args' not 'stm32f2xxx $args'"
- eval stm32f2x $args
-}
diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am
index ad6ec11..f54d9de 100644
--- a/src/helper/Makefile.am
+++ b/src/helper/Makefile.am
@@ -18,7 +18,6 @@ noinst_LTLIBRARIES += %D%/libhelper.la
%D%/binarybuffer.h \
%D%/bits.h \
%D%/configuration.h \
- %D%/ioutil.h \
%D%/list.h \
%D%/util.h \
%D%/types.h \
@@ -34,12 +33,6 @@ noinst_LTLIBRARIES += %D%/libhelper.la
%D%/base64.c \
%D%/base64.h
-if IOUTIL
-%C%_libhelper_la_SOURCES += %D%/ioutil.c
-else
-%C%_libhelper_la_SOURCES += %D%/ioutil_stubs.c
-endif
-
%C%_libhelper_la_CFLAGS = $(AM_CFLAGS)
if IS_MINGW
# FD_* macros are sloppy with their signs on MinGW32 platform
diff --git a/src/helper/command.c b/src/helper/command.c
index 96b1244..fdf1bbe 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -117,6 +117,40 @@ static void command_log_capture_finish(struct log_capture_state *state)
free(state);
}
+/*
+ * FIXME: workaround for memory leak in jimtcl 0.80
+ * Jim API Jim_CreateCommand() converts the command name in a Jim object and
+ * does not free the object. Fixed for jimtcl 0.81 by e4416cf86f0b
+ * Use the internal jimtcl API Jim_CreateCommandObj, not exported by jim.h,
+ * and override the bugged API through preprocessor's macro.
+ * This workaround works only when jimtcl is compiled as OpenOCD submodule.
+ * If jimtcl is linked-in from a precompiled library, either static or dynamic,
+ * the symbol Jim_CreateCommandObj is not exported and the build will use the
+ * bugged API.
+ * To be removed when OpenOCD will switch to jimtcl 0.81
+ */
+#if JIM_VERSION == 80
+static int workaround_createcommand(Jim_Interp *interp, const char *cmdName,
+ Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc);
+int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
+ Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
+__attribute__((weak, alias("workaround_createcommand")));
+static int workaround_createcommand(Jim_Interp *interp, const char *cmdName,
+ Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
+{
+ if ((void *)Jim_CreateCommandObj == (void *)workaround_createcommand)
+ return Jim_CreateCommand(interp, cmdName, cmdProc, privData, delProc);
+
+ Jim_Obj *cmd_name = Jim_NewStringObj(interp, cmdName, -1);
+ Jim_IncrRefCount(cmd_name);
+ int retval = Jim_CreateCommandObj(interp, cmd_name, cmdProc, privData, delProc);
+ Jim_DecrRefCount(interp, cmd_name);
+ return retval;
+}
+#define Jim_CreateCommand workaround_createcommand
+#endif /* JIM_VERSION == 80 */
+/* FIXME: end of workaround for memory leak in jimtcl 0.80 */
+
static int command_retval_set(Jim_Interp *interp, int retval)
{
int *return_retval = Jim_GetAssocData(interp, "retval");
diff --git a/src/helper/ioutil.c b/src/helper/ioutil.c
deleted file mode 100644
index ffdeca8..0000000
--- a/src/helper/ioutil.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2007-2010 by Øyvind Harboe *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-/* this file contains various functionality useful to standalone systems */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "log.h"
-#include "time_support.h"
-
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#endif
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#endif
-
-/* loads a file and returns a pointer to it in memory. The file contains
- * a 0 byte(sentinel) after len bytes - the length of the file. */
-static int load_file(const char *fileName, char **data, size_t *len)
-{
- /* ensure returned length is always sane */
- *len = 0;
-
- FILE *pFile;
- pFile = fopen(fileName, "rb");
- if (pFile == NULL) {
- LOG_ERROR("Can't open %s", fileName);
- return ERROR_FAIL;
- }
- if (fseek(pFile, 0, SEEK_END) != 0) {
- LOG_ERROR("Can't open %s", fileName);
- fclose(pFile);
- return ERROR_FAIL;
- }
- long fsize = ftell(pFile);
- if (fsize == -1) {
- LOG_ERROR("Can't open %s", fileName);
- fclose(pFile);
- return ERROR_FAIL;
- }
- *len = fsize;
-
- if (fseek(pFile, 0, SEEK_SET) != 0) {
- LOG_ERROR("Can't open %s", fileName);
- fclose(pFile);
- return ERROR_FAIL;
- }
- *data = malloc(*len + 1);
- if (*data == NULL) {
- LOG_ERROR("Can't open %s", fileName);
- fclose(pFile);
- return ERROR_FAIL;
- }
-
- if (fread(*data, 1, *len, pFile) != *len) {
- fclose(pFile);
- free(*data);
- LOG_ERROR("Can't open %s", fileName);
- return ERROR_FAIL;
- }
- fclose(pFile);
-
- /* 0-byte after buffer (not included in *len) serves as a sentinel */
- (*data)[*len] = 0;
-
- return ERROR_OK;
-}
-
-COMMAND_HANDLER(handle_cat_command)
-{
- if (CMD_ARGC != 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- /* NOTE!!! we only have line printing capability so we print the entire file as a single
- * line. */
- char *data;
- size_t len;
-
- int retval = load_file(CMD_ARGV[0], &data, &len);
- if (retval == ERROR_OK) {
- command_print(CMD, "%s", data);
- free(data);
- } else
- command_print(CMD, "%s not found", CMD_ARGV[0]);
-
- return ERROR_OK;
-}
-
-COMMAND_HANDLER(handle_trunc_command)
-{
- if (CMD_ARGC != 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- FILE *config_file = NULL;
- config_file = fopen(CMD_ARGV[0], "w");
- if (config_file != NULL)
- fclose(config_file);
-
- return ERROR_OK;
-}
-
-#ifdef HAVE_MALLOC_H
-COMMAND_HANDLER(handle_meminfo_command)
-{
- static int prev;
- struct mallinfo info;
-
- if (CMD_ARGC != 0)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- info = mallinfo();
-
- if (prev > 0)
- command_print(CMD, "Diff: %d", prev - info.fordblks);
- prev = info.fordblks;
-
- command_print(CMD, "Available ram: %d", info.fordblks);
-
- return ERROR_OK;
-}
-#endif
-
-COMMAND_HANDLER(handle_append_command)
-{
- if (CMD_ARGC < 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- int retval = ERROR_FAIL;
- FILE *config_file = NULL;
-
- config_file = fopen(CMD_ARGV[0], "a");
- if (config_file != NULL) {
- fseek(config_file, 0, SEEK_END);
-
- unsigned i;
- for (i = 1; i < CMD_ARGC; i++) {
- if (fwrite(CMD_ARGV[i], 1, strlen(CMD_ARGV[i]),
- config_file) != strlen(CMD_ARGV[i]))
- break;
- if (i != CMD_ARGC - 1) {
- if (fwrite(" ", 1, 1, config_file) != 1)
- break;
- }
- }
- if ((i == CMD_ARGC) && (fwrite("\n", 1, 1, config_file) == 1))
- retval = ERROR_OK;
-
- fclose(config_file);
- }
-
- return retval;
-}
-
-COMMAND_HANDLER(handle_cp_command)
-{
- if (CMD_ARGC != 2)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- /* NOTE!!! we only have line printing capability so we print the entire file as a single
- * line. */
- char *data;
- size_t len;
-
- int retval = load_file(CMD_ARGV[0], &data, &len);
- if (retval != ERROR_OK)
- return retval;
-
- FILE *f = fopen(CMD_ARGV[1], "wb");
- if (f == NULL)
- retval = ERROR_COMMAND_SYNTAX_ERROR;
-
- size_t pos = 0;
- for (;; ) {
- size_t chunk = len - pos;
- static const size_t maxChunk = 512 * 1024; /* ~1/sec */
- if (chunk > maxChunk)
- chunk = maxChunk;
-
- if ((retval == ERROR_OK) && (fwrite(data + pos, 1, chunk, f) != chunk))
- retval = ERROR_COMMAND_SYNTAX_ERROR;
-
- if (retval != ERROR_OK)
- break;
-
- command_print(CMD, "%zu", len - pos);
-
- pos += chunk;
-
- if (pos == len)
- break;
- }
-
- if (retval == ERROR_OK)
- command_print(CMD, "Copied %s to %s", CMD_ARGV[0], CMD_ARGV[1]);
- else
- command_print(CMD, "copy failed");
-
- free(data);
- if (f != NULL)
- fclose(f);
-
- if (retval != ERROR_OK)
- unlink(CMD_ARGV[1]);
-
- return retval;
-}
-
-COMMAND_HANDLER(handle_rm_command)
-{
- if (CMD_ARGC != 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- bool del = false;
- if (rmdir(CMD_ARGV[0]) == 0)
- del = true;
- else if (unlink(CMD_ARGV[0]) == 0)
- del = true;
-
- return del ? ERROR_OK : ERROR_FAIL;
-}
-
-static int ioutil_Jim_Command_ls(Jim_Interp *interp,
- int argc,
- Jim_Obj * const *argv)
-{
- if (argc != 2) {
- Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?");
- return JIM_ERR;
- }
-
- const char *name = Jim_GetString(argv[1], NULL);
-
- DIR *dirp = NULL;
- dirp = opendir(name);
- if (dirp == NULL)
- return JIM_ERR;
- Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
-
- for (;; ) {
- struct dirent *entry = NULL;
- entry = readdir(dirp);
- if (entry == NULL)
- break;
-
- if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0))
- continue;
-
- Jim_ListAppendElement(interp, objPtr,
- Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name)));
- }
- closedir(dirp);
-
- Jim_SetResult(interp, objPtr);
-
- return JIM_OK;
-}
-
-static int ioutil_Jim_Command_peek(Jim_Interp *interp,
- int argc,
- Jim_Obj *const *argv)
-{
- if (argc != 2) {
- Jim_WrongNumArgs(interp, 1, argv, "peek ?address?");
- return JIM_ERR;
- }
-
- long address;
- if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
- return JIM_ERR;
-
- int value = *((volatile int *) address);
-
- Jim_SetResult(interp, Jim_NewIntObj(interp, value));
-
- return JIM_OK;
-}
-
-static int ioutil_Jim_Command_poke(Jim_Interp *interp,
- int argc,
- Jim_Obj *const *argv)
-{
- if (argc != 3) {
- Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?");
- return JIM_ERR;
- }
-
- long address;
- if (Jim_GetLong(interp, argv[1], &address) != JIM_OK)
- return JIM_ERR;
- long value;
- if (Jim_GetLong(interp, argv[2], &value) != JIM_OK)
- return JIM_ERR;
-
- *((volatile int *) address) = value;
-
- return JIM_OK;
-}
-
-/* not so pretty code to fish out ip number*/
-static int ioutil_Jim_Command_ip(Jim_Interp *interp, int argc,
- Jim_Obj *const *argv)
-{
-#if !defined(__CYGWIN__)
- Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
-
- struct ifaddrs *ifa = NULL, *ifp = NULL;
-
- if (getifaddrs(&ifp) < 0)
- return JIM_ERR;
-
- for (ifa = ifp; ifa; ifa = ifa->ifa_next) {
- char ip[200];
- socklen_t salen;
-
- if (ifa->ifa_addr->sa_family == AF_INET)
- salen = sizeof(struct sockaddr_in);
- else if (ifa->ifa_addr->sa_family == AF_INET6)
- salen = sizeof(struct sockaddr_in6);
- else
- continue;
-
- if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0,
- NI_NUMERICHOST) < 0)
- continue;
-
- Jim_AppendString(interp, tclOutput, ip, strlen(ip));
- break;
-
- }
-
- freeifaddrs(ifp);
-#else
- Jim_Obj *tclOutput = Jim_NewStringObj(interp, "fixme!!!", 0);
- LOG_ERROR("NOT IMPLEMENTED!!!");
-#endif
- Jim_SetResult(interp, tclOutput);
-
- return JIM_OK;
-}
-
-#ifdef HAVE_SYS_IOCTL_H
-#ifdef SIOCGIFHWADDR
-/* not so pretty code to fish out eth0 mac address */
-static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc,
- Jim_Obj *const *argv)
-{
- struct ifreq *ifr, *ifend;
- struct ifreq ifreq;
- struct ifconf ifc;
- struct ifreq ifs[5];
- int SockFD;
-
- SockFD = socket(AF_INET, SOCK_DGRAM, 0);
- if (SockFD < 0)
- return JIM_ERR;
-
- ifc.ifc_len = sizeof(ifs);
- ifc.ifc_req = ifs;
- if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) {
- close(SockFD);
- return JIM_ERR;
- }
-
- ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
- for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
- /* if (ifr->ifr_addr.sa_family == AF_INET) */
- {
- if (strcmp("eth0", ifr->ifr_name) != 0)
- continue;
- strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1);
- if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
- close(SockFD);
- return JIM_ERR;
- }
-
- close(SockFD);
-
- Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
-
- char buffer[256];
- sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x",
- ifreq.ifr_hwaddr.sa_data[0]&0xff,
- ifreq.ifr_hwaddr.sa_data[1]&0xff,
- ifreq.ifr_hwaddr.sa_data[2]&0xff,
- ifreq.ifr_hwaddr.sa_data[3]&0xff,
- ifreq.ifr_hwaddr.sa_data[4]&0xff,
- ifreq.ifr_hwaddr.sa_data[5]&0xff);
-
- Jim_AppendString(interp, tclOutput, buffer, strlen(buffer));
-
- Jim_SetResult(interp, tclOutput);
-
- return JIM_OK;
- }
- }
- close(SockFD);
-
- return JIM_ERR;
-
-}
-#endif
-#endif
-
-static const struct command_registration ioutil_command_handlers[] = {
- {
- .name = "cat",
- .handler = handle_cat_command,
- .mode = COMMAND_ANY,
- .help = "display text file content",
- .usage = "file_name",
- },
- {
- .name = "trunc",
- .handler = handle_trunc_command,
- .mode = COMMAND_ANY,
- .help = "truncate a file to zero length",
- .usage = "file_name",
- },
- {
- .name = "cp",
- .handler = handle_cp_command,
- .mode = COMMAND_ANY,
- .help = "copy a file",
- .usage = "src_file_name dst_file_name",
- },
- {
- .name = "append_file",
- .handler = handle_append_command,
- .mode = COMMAND_ANY,
- .help = "append a variable number of strings to a file",
- .usage = "file_name [<string1>, [<string2>, ...]]",
- },
-#ifdef HAVE_MALLOC_H
- {
- .name = "meminfo",
- .handler = handle_meminfo_command,
- .mode = COMMAND_ANY,
- .help = "display free heap space",
- .usage = "",
- },
-#endif
- {
- .name = "rm",
- .mode = COMMAND_ANY,
- .handler = handle_rm_command,
- .help = "remove a directory or file",
- .usage = "file_name",
- },
-
- /*
- * Peek and poke are security holes -- they manipulate
- * server-internal addresses.
- */
-
- /* jim handlers */
- {
- .name = "peek",
- .mode = COMMAND_ANY,
- .jim_handler = ioutil_Jim_Command_peek,
- .help = "peek at a memory address",
- .usage = "address",
- },
- {
- .name = "poke",
- .mode = COMMAND_ANY,
- .jim_handler = ioutil_Jim_Command_poke,
- .help = "poke at a memory address",
- .usage = "address value",
- },
- {
- .name = "ls",
- .mode = COMMAND_ANY,
- .jim_handler = ioutil_Jim_Command_ls,
- .help = "show a listing of files",
- .usage = "dirname",
- },
-#ifdef HAVE_SYS_IOCTL_H
-#ifdef SIOCGIFHWADDR
- {
- .name = "mac",
- .mode = COMMAND_ANY,
- .jim_handler = ioutil_Jim_Command_mac,
- .help = "show MAC address",
- },
-#endif
-#endif
- {
- .name = "ip",
- .jim_handler = ioutil_Jim_Command_ip,
- .mode = COMMAND_ANY,
- .help = "show IP address",
- },
- COMMAND_REGISTRATION_DONE
-};
-
-int ioutil_init(struct command_context *cmd_ctx)
-{
- return register_commands(cmd_ctx, NULL, ioutil_command_handlers);
-}
diff --git a/src/helper/ioutil.h b/src/helper/ioutil.h
deleted file mode 100644
index f060aab..0000000
--- a/src/helper/ioutil.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifndef OPENOCD_HELPER_IOUTIL_H
-#define OPENOCD_HELPER_IOUTIL_H
-
-struct command_context;
-
-int ioutil_init(struct command_context *cmd_ctx);
-
-#endif /* OPENOCD_HELPER_IOUTIL_H */
diff --git a/src/helper/ioutil_stubs.c b/src/helper/ioutil_stubs.c
deleted file mode 100644
index 0d81fe6..0000000
--- a/src/helper/ioutil_stubs.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include "ioutil.h"
-#include "log.h"
-
-int ioutil_init(struct command_context *cmd_ctx)
-{
- LOG_DEBUG("libocdhelper was built without I/O utility support");
- return ERROR_OK;
-}
diff --git a/src/helper/options.c b/src/helper/options.c
index 246c6a8..f996749 100644
--- a/src/helper/options.c
+++ b/src/helper/options.c
@@ -55,7 +55,6 @@ static const struct option long_options[] = {
{"search", required_argument, 0, 's'},
{"log_output", required_argument, 0, 'l'},
{"command", required_argument, 0, 'c'},
- {"pipe", no_argument, 0, 'p'},
{0, 0, 0, 0}
};
@@ -282,7 +281,7 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
/* getopt_long stores the option index here. */
int option_index = 0;
- c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index);
+ c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
@@ -322,13 +321,6 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
if (optarg)
add_config_command(optarg);
break;
- case 'p':
- /* to replicate the old syntax this needs to be synchronous
- * otherwise the gdb stdin will overflow with the warning message */
- command_run_line(cmd_ctx, "gdb_port pipe; log_output openocd.log");
- LOG_WARNING("deprecated option: -p/--pipe. Use '-c \"gdb_port pipe; "
- "log_output openocd.log\"' instead.");
- break;
default: /* '?' */
/* getopt will emit an error message, all we have to do is bail. */
return ERROR_FAIL;
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am
index b82914b..4ed5e7a 100644
--- a/src/jtag/Makefile.am
+++ b/src/jtag/Makefile.am
@@ -3,33 +3,6 @@ noinst_LTLIBRARIES += %D%/libjtag.la
JTAG_SRCS = %D%/commands.c
%C%_libjtag_la_LIBADD =
-BUILT_SOURCES += %D%/minidriver_imp.h
-CLEANFILES += %D%/minidriver_imp.h
-
-if MINIDRIVER
-
-if ZY1000
-JTAG_SRCS += %D%/zy1000/zy1000.c
-JTAG_MINIDRIVER_DIR = %D%/zy1000
-endif
-if MINIDRIVER_DUMMY
-JTAG_SRCS += %D%/minidummy/minidummy.c
-JTAG_MINIDRIVER_DIR = %D%/minidummy
-endif
-
-MINIDRIVER_IMP_DIR = %D%/minidriver
-
-%D%/jtag_minidriver.h: $(JTAG_MINIDRIVER_DIR)/jtag_minidriver.h
- cp $< $@
-
-BUILT_SOURCES += %D%/jtag_minidriver.h
-
-CLEANFILES += %D%/jtag_minidriver.h
-
-else
-
-MINIDRIVER_IMP_DIR = %D%/drivers
-
if HLADAPTER
include %D%/hla/Makefile.am
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/hla/libocdhla.la
@@ -43,13 +16,6 @@ endif
include %D%/drivers/Makefile.am
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/drivers/libocdjtagdrivers.la
-endif
-# endif // MINIDRIVER
-
-%D%/minidriver_imp.h: $(MINIDRIVER_IMP_DIR)/minidriver_imp.h
- cp $< $@
-
-
%C%_libjtag_la_SOURCES = \
%D%/adapter.c \
%D%/core.c \
@@ -63,8 +29,6 @@ endif
%D%/interfaces.h \
%D%/minidriver.h \
%D%/jtag.h \
- %D%/minidriver/minidriver_imp.h \
- %D%/minidummy/jtag_minidriver.h \
%D%/swd.h \
%D%/swim.h \
%D%/tcl.h \
diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c
index 13368ab..97ede50 100644
--- a/src/jtag/adapter.c
+++ b/src/jtag/adapter.c
@@ -493,7 +493,6 @@ COMMAND_HANDLER(handle_adapter_reset_de_assert)
(srst == VALUE_DEASSERT) ? SRST_DEASSERT : SRST_ASSERT);
}
-#ifndef HAVE_JTAG_MINIDRIVER_H
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
COMMAND_HANDLER(handle_usb_location_command)
{
@@ -518,7 +517,6 @@ static const struct command_registration adapter_usb_command_handlers[] = {
#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
COMMAND_REGISTRATION_DONE
};
-#endif /* MINIDRIVER */
static const struct command_registration adapter_srst_command_handlers[] = {
{
@@ -584,7 +582,6 @@ static const struct command_registration adapter_command_handlers[] = {
.help = "Declare transports the adapter supports.",
.usage = "transport ... ",
},
-#ifndef HAVE_JTAG_MINIDRIVER_H
{
.name = "usb",
.mode = COMMAND_ANY,
@@ -592,7 +589,6 @@ static const struct command_registration adapter_command_handlers[] = {
.usage = "",
.chain = adapter_usb_command_handlers,
},
-#endif /* MINIDRIVER */
{
.name = "assert",
.handler = handle_adapter_reset_de_assert,
diff --git a/src/jtag/aice/Makefile.am b/src/jtag/aice/Makefile.am
index 97e3825..b6a7ba9 100644
--- a/src/jtag/aice/Makefile.am
+++ b/src/jtag/aice/Makefile.am
@@ -1,6 +1,6 @@
noinst_LTLIBRARIES += %D%/libocdaice.la
-%C%_libocdaice_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS) $(LIBUSB0_CFLAGS)
+%C%_libocdaice_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS)
%C%_libocdaice_la_SOURCES = \
%D%/aice_transport.c \
%D%/aice_interface.c \
diff --git a/src/jtag/core.c b/src/jtag/core.c
index ac58906..37924aa 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -427,7 +427,6 @@ static void jtag_add_scan_check(struct jtag_tap *active, void (*jtag_add_scan)(
for (int i = 0; i < in_num_fields; i++) {
if ((in_fields[i].check_value != NULL) && (in_fields[i].in_value != NULL)) {
- /* this is synchronous for a minidriver */
jtag_add_callback4(jtag_check_value_mask_callback,
(jtag_callback_data_t)in_fields[i].in_value,
(jtag_callback_data_t)in_fields[i].check_value,
@@ -954,12 +953,6 @@ int default_interface_jtag_execute_queue(void)
int result = jtag->jtag_ops->execute_queue();
-#if !HAVE_JTAG_MINIDRIVER_H
- /* Only build this if we use a regular driver with a command queue.
- * Otherwise jtag_command_queue won't be found at compile/link time. Its
- * definition is in jtag/commands.c, which is only built/linked by
- * jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables
- * aren't accessible here. Use HAVE_JTAG_MINIDRIVER_H */
struct jtag_command *cmd = jtag_command_queue;
while (debug_level >= LOG_LVL_DEBUG_IO && cmd) {
switch (cmd->type) {
@@ -1018,7 +1011,6 @@ int default_interface_jtag_execute_queue(void)
}
cmd = cmd->next;
}
-#endif
return result;
}
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index f7a54b0..da60f36 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -27,12 +27,6 @@ DRIVERFILES += %D%/libusb_helper.c
%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB1_LIBS)
endif
-if USE_LIBUSB0
-DRIVERFILES += %D%/usb_common.c
-%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBUSB0_CFLAGS)
-%C%_libocdjtagdrivers_la_LIBADD += $(LIBUSB0_LIBS)
-endif
-
if USE_LIBFTDI
%C%_libocdjtagdrivers_la_CPPFLAGS += $(LIBFTDI_CFLAGS)
%C%_libocdjtagdrivers_la_LIBADD += $(LIBFTDI_LIBS)
@@ -203,7 +197,6 @@ DRIVERHEADERS = \
%D%/rlink_dtc_cmd.h \
%D%/rlink_ep1_cmd.h \
%D%/rlink_st7.h \
- %D%/usb_common.h \
%D%/versaloon/usbtoxxx/usbtoxxx.h \
%D%/versaloon/usbtoxxx/usbtoxxx_internal.h \
%D%/versaloon/versaloon.h \
diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c
index 754f937..b98beae 100644
--- a/src/jtag/drivers/arm-jtag-ew.c
+++ b/src/jtag/drivers/arm-jtag-ew.c
@@ -24,7 +24,7 @@
#include <jtag/commands.h>
#include "helper/system.h"
#include <usb.h>
-#include "usb_common.h"
+#include "libusb_helper.h"
#define USB_VID 0x15ba
#define USB_PID 0x001e
@@ -76,7 +76,7 @@ static void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_c
/* ARM-JTAG-EW lowlevel functions */
struct armjtagew {
- struct usb_dev_handle *usb_handle;
+ struct libusb_device_handle *usb_handle;
};
static struct armjtagew *armjtagew_usb_open(void);
@@ -685,35 +685,37 @@ static int armjtagew_tap_execute(void)
static struct armjtagew *armjtagew_usb_open(void)
{
- usb_init();
-
const uint16_t vids[] = { USB_VID, 0 };
const uint16_t pids[] = { USB_PID, 0 };
- struct usb_dev_handle *dev;
- if (jtag_usb_open(vids, pids, &dev) != ERROR_OK)
+ struct libusb_device_handle *dev;
+
+ if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK)
return NULL;
struct armjtagew *result = malloc(sizeof(struct armjtagew));
result->usb_handle = dev;
#if 0
- /* usb_set_configuration required under win32 */
- usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+ /* libusb_set_configuration required under win32 */
+ struct libusb_config_descriptor *config;
+ struct libusb_device *usb_dev = libusb_get_device(dev);
+ libusb_get_config_descriptor(usb_dev, 0, &config);
+ libusb_set_configuration(dev, config->bConfigurationValue);
#endif
- usb_claim_interface(dev, 0);
+ libusb_claim_interface(dev, 0);
#if 0
/*
* This makes problems under Mac OS X. And is not needed
* under Windows. Hopefully this will not break a linux build
*/
- usb_set_altinterface(dev, 0);
+ libusb_set_interface_alt_setting(dev, 0, 0);
#endif
return result;
}
static void armjtagew_usb_close(struct armjtagew *armjtagew)
{
- usb_close(armjtagew->usb_handle);
+ libusb_close(armjtagew->usb_handle);
free(armjtagew);
}
@@ -726,13 +728,13 @@ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, in
if (result == out_length) {
result = armjtagew_usb_read(armjtagew, in_length);
if (result != in_length) {
- LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)",
+ LOG_ERROR("jtag_libusb_bulk_read failed (requested=%d, result=%d)",
in_length,
result);
return -1;
}
} else {
- LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result);
+ LOG_ERROR("jtag_libusb_bulk_write failed (requested=%d, result=%d)", out_length, result);
return -1;
}
return 0;
@@ -742,6 +744,7 @@ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, in
static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
{
int result;
+ int transferred;
if (out_length > ARMJTAGEW_OUT_BUFFER_SIZE) {
LOG_ERROR("armjtagew_write illegal out_length=%d (max=%d)",
@@ -750,29 +753,34 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
return -1;
}
- result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT,
- (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT);
+ result = jtag_libusb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT,
+ (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT, &transferred);
LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result);
#ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer(usb_out_buffer, out_length);
#endif
- return result;
+ if (result != ERROR_OK)
+ return -1;
+ return transferred;
}
/* Read data from USB into in_buffer. */
static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length)
{
- int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN,
- (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT);
+ int transferred;
+ int result = jtag_libusb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN,
+ (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT, &transferred);
LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result);
#ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer(usb_in_buffer, result);
#endif
- return result;
+ if (result != ERROR_OK)
+ return -1;
+ return transferred;
}
#ifdef _DEBUG_USB_COMMS_
diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c
index e2762e1..6d60b71 100644
--- a/src/jtag/drivers/cmsis_dap.c
+++ b/src/jtag/drivers/cmsis_dap.c
@@ -170,10 +170,6 @@ static const char * const info_caps_str[] = {
"JTAG Supported"
};
-/* max clock speed (kHz) */
-#define DAP_MAX_CLOCK 5000
-
-
struct pending_transfer_result {
uint8_t cmd;
uint32_t data;
@@ -230,16 +226,12 @@ static int cmsis_dap_open(void)
{
const struct cmsis_dap_backend *backend = NULL;
- struct cmsis_dap *dap = malloc(sizeof(struct cmsis_dap));
+ struct cmsis_dap *dap = calloc(1, sizeof(struct cmsis_dap));
if (dap == NULL) {
LOG_ERROR("unable to allocate memory");
return ERROR_FAIL;
}
- dap->caps = 0;
- dap->mode = 0;
- dap->packet_size = 0; /* initialized by backend */
-
if (cmsis_dap_backend >= 0) {
/* Use forced backend */
backend = cmsis_dap_backends[cmsis_dap_backend];
@@ -262,17 +254,7 @@ static int cmsis_dap_open(void)
return ERROR_FAIL;
}
- assert(dap->packet_size > 0);
-
dap->backend = backend;
- dap->packet_buffer = malloc(dap->packet_size);
-
- if (dap->packet_buffer == NULL) {
- LOG_ERROR("unable to allocate memory");
- dap->backend->close(dap);
- free(dap);
- return ERROR_FAIL;
- }
cmsis_dap_handle = dap;
@@ -326,17 +308,14 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen)
static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay, uint8_t *input)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
-
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_SWJ_PINS;
- buffer[2] = pins;
- buffer[3] = mask;
- buffer[4] = delay & 0xff;
- buffer[5] = (delay >> 8) & 0xff;
- buffer[6] = (delay >> 16) & 0xff;
- buffer[7] = (delay >> 24) & 0xff;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 8);
+ uint8_t *command = cmsis_dap_handle->command;
+
+ command[0] = CMD_DAP_SWJ_PINS;
+ command[1] = pins;
+ command[2] = mask;
+ h_u32_to_le(&command[3], delay);
+
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 7);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed.");
@@ -344,7 +323,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay
}
if (input)
- *input = buffer[1];
+ *input = cmsis_dap_handle->response[1];
return ERROR_OK;
}
@@ -352,19 +331,17 @@ static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay
static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
/* set clock in Hz */
swj_clock *= 1000;
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_SWJ_CLOCK;
- buffer[2] = swj_clock & 0xff;
- buffer[3] = (swj_clock >> 8) & 0xff;
- buffer[4] = (swj_clock >> 16) & 0xff;
- buffer[5] = (swj_clock >> 24) & 0xff;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 6);
- if (retval != ERROR_OK || buffer[1] != DAP_OK) {
+ command[0] = CMD_DAP_SWJ_CLOCK;
+ h_u32_to_le(&command[1], swj_clock);
+
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 5);
+
+ if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -376,7 +353,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock)
static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
#ifdef CMSIS_DAP_JTAG_DEBUG
LOG_DEBUG("cmsis-dap TMS sequence: len=%d", s_len);
@@ -386,14 +363,12 @@ static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence
printf("\n");
#endif
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_SWJ_SEQ;
- buffer[2] = s_len;
- bit_copy(&buffer[3], 0, sequence, 0, s_len);
-
- retval = cmsis_dap_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3);
+ command[0] = CMD_DAP_SWJ_SEQ;
+ command[1] = s_len;
+ bit_copy(&command[2], 0, sequence, 0, s_len);
- if (retval != ERROR_OK || buffer[1] != DAP_OK)
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 2 + DIV_ROUND_UP(s_len, 8));
+ if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK)
return ERROR_FAIL;
return ERROR_OK;
@@ -402,19 +377,19 @@ static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence
static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_INFO;
- buffer[2] = info;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
+ command[0] = CMD_DAP_INFO;
+ command[1] = info;
+
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 2);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command CMD_INFO failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
- *data = &(buffer[1]);
+ *data = &cmsis_dap_handle->response[1];
return ERROR_OK;
}
@@ -422,15 +397,15 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data)
static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
+
+ command[0] = CMD_DAP_LED;
+ command[1] = led;
+ command[2] = state;
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_LED;
- buffer[2] = led;
- buffer[3] = state;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 4);
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
- if (retval != ERROR_OK || buffer[1] != 0x00) {
+ if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_LED failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -441,19 +416,19 @@ static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state)
static int cmsis_dap_cmd_DAP_Connect(uint8_t mode)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_CONNECT;
- buffer[2] = mode;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
+ command[0] = CMD_DAP_CONNECT;
+ command[1] = mode;
+
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 2);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
- if (buffer[1] != mode) {
+ if (cmsis_dap_handle->response[1] != mode) {
LOG_ERROR("CMSIS-DAP failed to connect in mode (%d)", mode);
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -464,13 +439,13 @@ static int cmsis_dap_cmd_DAP_Connect(uint8_t mode)
static int cmsis_dap_cmd_DAP_Disconnect(void)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_DISCONNECT;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 2);
+ command[0] = CMD_DAP_DISCONNECT;
+
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 1);
- if (retval != ERROR_OK || buffer[1] != DAP_OK) {
+ if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -481,18 +456,16 @@ static int cmsis_dap_cmd_DAP_Disconnect(void)
static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count, uint16_t match_retry)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
-
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_TFER_CONFIGURE;
- buffer[2] = idle;
- buffer[3] = retry_count & 0xff;
- buffer[4] = (retry_count >> 8) & 0xff;
- buffer[5] = match_retry & 0xff;
- buffer[6] = (match_retry >> 8) & 0xff;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 7);
+ uint8_t *command = cmsis_dap_handle->command;
+
+ command[0] = CMD_DAP_TFER_CONFIGURE;
+ command[1] = idle;
+ h_u16_to_le(&command[2], retry_count);
+ h_u16_to_le(&command[4], match_retry);
+
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 6);
- if (retval != ERROR_OK || buffer[1] != DAP_OK) {
+ if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -503,14 +476,14 @@ static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count,
static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_SWD_CONFIGURE;
- buffer[2] = cfg;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
+ command[0] = CMD_DAP_SWD_CONFIGURE;
+ command[1] = cfg;
+
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 2);
- if (retval != ERROR_OK || buffer[1] != DAP_OK) {
+ if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -522,15 +495,14 @@ static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg)
static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
{
int retval;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
+
+ command[0] = CMD_DAP_DELAY;
+ h_u16_to_le(&command[1], delay_us);
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_DELAY;
- buffer[2] = delay_us & 0xff;
- buffer[3] = (delay_us >> 8) & 0xff;
- retval = cmsis_dap_xfer(cmsis_dap_handle, 4);
+ retval = cmsis_dap_xfer(cmsis_dap_handle, 3);
- if (retval != ERROR_OK || buffer[1] != DAP_OK) {
+ if (retval != ERROR_OK || cmsis_dap_handle->response[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_Delay failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -541,7 +513,7 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
{
- uint8_t *buffer = dap->packet_buffer;
+ uint8_t *command = cmsis_dap_handle->command;
struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx];
LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx);
@@ -554,11 +526,10 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
if (block->transfer_count == 0)
goto skip;
- size_t idx = 0;
- buffer[idx++] = 0; /* report number */
- buffer[idx++] = CMD_DAP_TFER;
- buffer[idx++] = 0x00; /* DAP Index */
- buffer[idx++] = block->transfer_count;
+ command[0] = CMD_DAP_TFER;
+ command[1] = 0x00; /* DAP Index */
+ command[2] = block->transfer_count;
+ size_t idx = 3;
for (int i = 0; i < block->transfer_count; i++) {
struct pending_transfer_result *transfer = &(block->transfers[i]);
@@ -589,12 +560,10 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
data &= ~CORUNDETECT;
}
- buffer[idx++] = (cmd >> 1) & 0x0f;
+ command[idx++] = (cmd >> 1) & 0x0f;
if (!(cmd & SWD_CMD_RnW)) {
- buffer[idx++] = (data) & 0xff;
- buffer[idx++] = (data >> 8) & 0xff;
- buffer[idx++] = (data >> 16) & 0xff;
- buffer[idx++] = (data >> 24) & 0xff;
+ h_u32_to_le(&command[idx], data);
+ idx += 4;
}
}
@@ -620,7 +589,6 @@ skip:
static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
{
- uint8_t *buffer = dap->packet_buffer;
struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx];
if (pending_fifo_block_count == 0)
@@ -637,30 +605,33 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
goto skip;
}
- if (buffer[2] & 0x08) {
- LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", buffer[1]);
+ uint8_t *resp = dap->response;
+ uint8_t transfer_count = resp[1];
+ uint8_t ack = resp[2] & 0x07;
+ if (resp[2] & 0x08) {
+ LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", transfer_count);
queued_retval = ERROR_FAIL;
goto skip;
}
- uint8_t ack = buffer[2] & 0x07;
if (ack != SWD_ACK_OK) {
- LOG_DEBUG("SWD ack not OK @ %d %s", buffer[1],
+ LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count,
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
goto skip;
}
- if (block->transfer_count != buffer[1])
+ if (block->transfer_count != transfer_count)
LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d",
- block->transfer_count, buffer[1]);
+ block->transfer_count, transfer_count);
- LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", buffer[1], pending_fifo_get_idx);
+ LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d",
+ transfer_count, pending_fifo_get_idx);
size_t idx = 3;
- for (int i = 0; i < buffer[1]; i++) {
+ for (int i = 0; i < transfer_count; i++) {
struct pending_transfer_result *transfer = &(block->transfers[i]);
if (transfer->cmd & SWD_CMD_RnW) {
static uint32_t last_read;
- uint32_t data = le_to_h_u32(&buffer[idx]);
+ uint32_t data = le_to_h_u32(&resp[idx]);
uint32_t tmp = data;
idx += 4;
@@ -934,24 +905,20 @@ static int cmsis_dap_init(void)
if (data[0] == 2) { /* short */
uint16_t pkt_sz = data[1] + (data[2] << 8);
+ if (pkt_sz != cmsis_dap_handle->packet_size) {
- /* 4 bytes of command header + 5 bytes per register
- * write. For bulk read sequences just 4 bytes are
- * needed per transfer, so this is suboptimal. */
- pending_queue_len = (pkt_sz - 4) / 5;
-
- if (cmsis_dap_handle->packet_size != pkt_sz + 1) {
- /* reallocate buffer */
- cmsis_dap_handle->packet_size = pkt_sz + 1;
- cmsis_dap_handle->packet_buffer = realloc(cmsis_dap_handle->packet_buffer,
- cmsis_dap_handle->packet_size);
- if (cmsis_dap_handle->packet_buffer == NULL) {
- LOG_ERROR("unable to reallocate memory");
- return ERROR_FAIL;
- }
- }
+ /* 4 bytes of command header + 5 bytes per register
+ * write. For bulk read sequences just 4 bytes are
+ * needed per transfer, so this is suboptimal. */
+ pending_queue_len = (pkt_sz - 4) / 5;
- LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRId16, pkt_sz);
+ free(cmsis_dap_handle->packet_buffer);
+ retval = cmsis_dap_handle->backend->packet_buffer_alloc(cmsis_dap_handle, pkt_sz);
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_DEBUG("CMSIS-DAP: Packet Size = %" PRIu16, pkt_sz);
+ }
}
/* INFO_ID_PKT_CNT - byte */
@@ -1168,20 +1135,21 @@ static void cmsis_dap_flush(void)
LOG_DEBUG_IO("Flushing %d queued sequences (%d bytes) with %d pending scan results to capture",
queued_seq_count, queued_seq_buf_end, pending_scan_result_count);
- /* prep CMSIS-DAP packet */
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
- buffer[0] = 0; /* report number */
- buffer[1] = CMD_DAP_JTAG_SEQ;
- buffer[2] = queued_seq_count;
- memcpy(buffer + 3, queued_seq_buf, queued_seq_buf_end);
+ /* prepare CMSIS-DAP packet */
+ uint8_t *command = cmsis_dap_handle->command;
+ command[0] = CMD_DAP_JTAG_SEQ;
+ command[1] = queued_seq_count;
+ memcpy(&command[2], queued_seq_buf, queued_seq_buf_end);
#ifdef CMSIS_DAP_JTAG_DEBUG
- debug_parse_cmsis_buf(buffer, queued_seq_buf_end + 3);
+ debug_parse_cmsis_buf(command, queued_seq_buf_end + 2);
#endif
/* send command to USB device */
- int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 3);
- if (retval != ERROR_OK || buffer[1] != DAP_OK) {
+ int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 2);
+
+ uint8_t *resp = cmsis_dap_handle->response;
+ if (retval != ERROR_OK || resp[1] != DAP_OK) {
LOG_ERROR("CMSIS-DAP command CMD_DAP_JTAG_SEQ failed.");
exit(-1);
}
@@ -1189,7 +1157,7 @@ static void cmsis_dap_flush(void)
#ifdef CMSIS_DAP_JTAG_DEBUG
LOG_DEBUG_IO("USB response buf:");
for (int c = 0; c < queued_seq_buf_end + 3; ++c)
- printf("%02X ", buffer[c]);
+ printf("%02X ", resp[c]);
printf("\n");
#endif
@@ -1200,10 +1168,10 @@ static void cmsis_dap_flush(void)
i, pending_scan_result_count, scan->length, scan->first + 2, scan->buffer_offset);
#ifdef CMSIS_DAP_JTAG_DEBUG
for (uint32_t b = 0; b < DIV_ROUND_UP(scan->length, 8); ++b)
- printf("%02X ", buffer[2+scan->first+b]);
+ printf("%02X ", resp[2+scan->first+b]);
printf("\n");
#endif
- bit_copy(scan->buffer, scan->buffer_offset, buffer + 2 + scan->first, 0, scan->length);
+ bit_copy(scan->buffer, scan->buffer_offset, &resp[2 + scan->first], 0, scan->length);
}
/* reset */
@@ -1545,9 +1513,6 @@ static int cmsis_dap_execute_queue(void)
static int cmsis_dap_speed(int speed)
{
- if (speed > DAP_MAX_CLOCK)
- LOG_INFO("High speed (adapter speed %d) may be limited by adapter firmware.", speed);
-
if (speed == 0) {
LOG_ERROR("RTCK not supported. Set nonzero \"adapter speed\".");
return ERROR_JTAG_NOT_IMPLEMENTED;
@@ -1580,22 +1545,21 @@ COMMAND_HANDLER(cmsis_dap_handle_cmd_command)
{
int retval;
unsigned i;
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
-
- buffer[0] = 0; /* report number */
+ uint8_t *command = cmsis_dap_handle->command;
for (i = 0; i < CMD_ARGC; i++)
- buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16);
+ command[i] = strtoul(CMD_ARGV[i], NULL, 16);
- retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC + 1);
+ retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
+ uint8_t *resp = cmsis_dap_handle->response;
LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8,
- buffer[1], buffer[2], buffer[3], buffer[4]);
+ resp[1], resp[2], resp[3], resp[4]);
return ERROR_OK;
}
diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h
index 054621c..c9f24c8 100644
--- a/src/jtag/drivers/cmsis_dap.h
+++ b/src/jtag/drivers/cmsis_dap.h
@@ -13,6 +13,9 @@ struct cmsis_dap {
uint16_t packet_size;
int packet_count;
uint8_t *packet_buffer;
+ uint16_t packet_buffer_size;
+ uint8_t *command;
+ uint8_t *response;
uint8_t caps;
uint8_t mode;
};
@@ -23,10 +26,13 @@ struct cmsis_dap_backend {
void (*close)(struct cmsis_dap *dap);
int (*read)(struct cmsis_dap *dap, int timeout_ms);
int (*write)(struct cmsis_dap *dap, int len, int timeout_ms);
+ int (*packet_buffer_alloc)(struct cmsis_dap *dap, unsigned int pkt_sz);
};
extern const struct cmsis_dap_backend cmsis_dap_hid_backend;
extern const struct cmsis_dap_backend cmsis_dap_usb_backend;
extern const struct command_registration cmsis_dap_usb_subcommand_handlers[];
+#define REPORT_ID_SIZE 1
+
#endif
diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c
index 9c76449..28f8e3a 100644
--- a/src/jtag/drivers/cmsis_dap_usb_bulk.c
+++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c
@@ -51,6 +51,9 @@ struct cmsis_dap_backend_data {
static int cmsis_dap_usb_interface = -1;
+static void cmsis_dap_usb_close(struct cmsis_dap *dap);
+static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
+
static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
{
int err;
@@ -357,12 +360,24 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p
return ERROR_FAIL;
}
- dap->packet_size = packet_size + 1; /* "+ 1" for compatibility with the HID backend */
+ dap->packet_size = packet_size;
+ dap->packet_buffer_size = packet_size;
dap->bdata->usb_ctx = ctx;
dap->bdata->dev_handle = dev_handle;
dap->bdata->ep_out = ep_out;
dap->bdata->ep_in = ep_in;
dap->bdata->interface = interface_num;
+
+ dap->packet_buffer = malloc(dap->packet_buffer_size);
+ if (dap->packet_buffer == NULL) {
+ LOG_ERROR("unable to allocate memory");
+ cmsis_dap_usb_close(dap);
+ return ERROR_FAIL;
+ }
+
+ dap->command = dap->packet_buffer;
+ dap->response = dap->packet_buffer;
+
return ERROR_OK;
}
@@ -382,6 +397,8 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
libusb_exit(dap->bdata->usb_ctx);
free(dap->bdata);
dap->bdata = NULL;
+ free(dap->packet_buffer);
+ dap->packet_buffer = NULL;
}
static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms)
@@ -400,7 +417,7 @@ static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms)
}
}
- memset(&dap->packet_buffer[transferred], 0, dap->packet_size - transferred);
+ memset(&dap->packet_buffer[transferred], 0, dap->packet_buffer_size - transferred);
return transferred;
}
@@ -412,7 +429,7 @@ static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
/* skip the first byte that is only used by the HID backend */
err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_out,
- dap->packet_buffer + 1, txlen - 1, &transferred, timeout_ms);
+ dap->packet_buffer, txlen, &transferred, timeout_ms);
if (err) {
if (err == LIBUSB_ERROR_TIMEOUT) {
return ERROR_TIMEOUT_REACHED;
@@ -425,6 +442,24 @@ static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
return transferred;
}
+static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
+{
+ uint8_t *buf = malloc(pkt_sz);
+ if (buf == NULL) {
+ LOG_ERROR("unable to allocate CMSIS-DAP packet buffer");
+ return ERROR_FAIL;
+ }
+
+ dap->packet_buffer = buf;
+ dap->packet_size = pkt_sz;
+ dap->packet_buffer_size = pkt_sz;
+
+ dap->command = dap->packet_buffer;
+ dap->response = dap->packet_buffer;
+
+ return ERROR_OK;
+}
+
COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command)
{
if (CMD_ARGC == 1)
@@ -452,4 +487,5 @@ const struct cmsis_dap_backend cmsis_dap_usb_backend = {
.close = cmsis_dap_usb_close,
.read = cmsis_dap_usb_read,
.write = cmsis_dap_usb_write,
+ .packet_buffer_alloc = cmsis_dap_usb_alloc,
};
diff --git a/src/jtag/drivers/cmsis_dap_usb_hid.c b/src/jtag/drivers/cmsis_dap_usb_hid.c
index 681aef1..e83ad1f 100644
--- a/src/jtag/drivers/cmsis_dap_usb_hid.c
+++ b/src/jtag/drivers/cmsis_dap_usb_hid.c
@@ -40,12 +40,13 @@
#include "cmsis_dap.h"
-#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */
-
struct cmsis_dap_backend_data {
hid_device *dev_handle;
};
+static void cmsis_dap_hid_close(struct cmsis_dap *dap);
+static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
+
static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
{
hid_device *dev = NULL;
@@ -145,7 +146,7 @@ static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p
* without this info we cannot communicate with the adapter.
* For the moment we have to hard code the packet size */
- dap->packet_size = PACKET_SIZE;
+ unsigned int packet_size = 64;
/* atmel cmsis-dap uses 512 byte reports */
/* except when it doesn't e.g. with mEDBG on SAMD10 Xplained
@@ -153,10 +154,18 @@ static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p
/* TODO: HID report descriptor should be parsed instead of
* hardcoding a match by VID */
if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175)
- dap->packet_size = 512 + 1;
+ packet_size = 512;
dap->bdata->dev_handle = dev;
+ int retval = cmsis_dap_hid_alloc(dap, packet_size);
+ if (retval != ERROR_OK) {
+ cmsis_dap_hid_close(dap);
+ return ERROR_FAIL;
+ }
+
+ dap->command = dap->packet_buffer + REPORT_ID_SIZE;
+ dap->response = dap->packet_buffer;
return ERROR_OK;
}
@@ -166,11 +175,13 @@ static void cmsis_dap_hid_close(struct cmsis_dap *dap)
hid_exit();
free(dap->bdata);
dap->bdata = NULL;
+ free(dap->packet_buffer);
+ dap->packet_buffer = NULL;
}
static int cmsis_dap_hid_read(struct cmsis_dap *dap, int timeout_ms)
{
- int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms);
+ int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size, timeout_ms);
if (retval == 0) {
return ERROR_TIMEOUT_REACHED;
@@ -186,11 +197,13 @@ static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
{
(void) timeout_ms;
+ dap->packet_buffer[0] = 0; /* HID report number */
+
/* Pad the rest of the TX buffer with 0's */
- memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen);
+ memset(dap->command + txlen, 0, dap->packet_size - txlen);
/* write data to device */
- int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size);
+ int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_buffer_size);
if (retval == -1) {
LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle));
return ERROR_FAIL;
@@ -199,10 +212,30 @@ static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms)
return retval;
}
+static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
+{
+ unsigned int packet_buffer_size = pkt_sz + REPORT_ID_SIZE;
+ uint8_t *buf = malloc(packet_buffer_size);
+ if (buf == NULL) {
+ LOG_ERROR("unable to allocate CMSIS-DAP packet buffer");
+ return ERROR_FAIL;
+ }
+
+ dap->packet_buffer = buf;
+ dap->packet_size = pkt_sz;
+ dap->packet_buffer_size = packet_buffer_size;
+
+ dap->command = dap->packet_buffer + REPORT_ID_SIZE;
+ dap->response = dap->packet_buffer;
+
+ return ERROR_OK;
+}
+
const struct cmsis_dap_backend cmsis_dap_hid_backend = {
.name = "hid",
.open = cmsis_dap_hid_open,
.close = cmsis_dap_hid_close,
.read = cmsis_dap_hid_read,
.write = cmsis_dap_hid_write,
+ .packet_buffer_alloc = cmsis_dap_hid_alloc,
};
diff --git a/src/jtag/drivers/jtag_usb_common.c b/src/jtag/drivers/jtag_usb_common.c
index f18ea54..fdd7137 100644
--- a/src/jtag/drivers/jtag_usb_common.c
+++ b/src/jtag/drivers/jtag_usb_common.c
@@ -51,7 +51,7 @@ bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path,
goto done;
}
- string_length -= 1;
+ string_length -= strnlen(ptr, string_length);
/* check bus mismatch */
if (atoi(ptr) != dev_bus)
goto done;
@@ -69,7 +69,7 @@ bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path,
break;
path_step++;
- string_length -= 2;
+ string_length -= strnlen(ptr, string_length) + 1;
};
/* walked the full path, all elements match */
diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c
index 00738ee..48a5c79 100644
--- a/src/jtag/drivers/nulink_usb.c
+++ b/src/jtag/drivers/nulink_usb.c
@@ -253,7 +253,7 @@ static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
{
struct nulink_usb_handle_s *h = handle;
- LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 "0x%08" PRIX32, addr, val);
+ LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 " 0x%08" PRIX32, addr, val);
nulink_usb_init_buffer(handle, 8 + 12 * 1);
/* set command ID */
@@ -503,7 +503,7 @@ static int nulink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
aligned_addr = aligned_addr * 4;
offset = addr - aligned_addr;
LOG_DEBUG("nulink_usb_read_mem8: unaligned address addr 0x%08" PRIx32
- "/aligned addr 0x%08" PRIx32 "offset %" PRIu32,
+ "/aligned addr 0x%08" PRIx32 " offset %" PRIu32,
addr, aligned_addr, offset);
addr = aligned_addr;
diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c
index d15dba7..41f36c1 100644
--- a/src/jtag/drivers/rlink.c
+++ b/src/jtag/drivers/rlink.c
@@ -34,7 +34,7 @@
#include "rlink_st7.h"
#include "rlink_ep1_cmd.h"
#include "rlink_dtc_cmd.h"
-#include "usb_common.h"
+#include "libusb_helper.h"
/* This feature is made useless by running the DTC all the time. When automatic, the LED is on
*whenever the DTC is running. Otherwise, USB messages are sent to turn it on and off. */
@@ -97,19 +97,20 @@
#define ST7_PC_TDO ST7_PC_IO9
#define ST7_PA_DBGACK ST7_PA_IO10
-static usb_dev_handle *pHDev;
+static libusb_device_handle *pHDev;
/*
* ep1 commands are up to USB_EP1OUT_SIZE bytes in length.
* This function takes care of zeroing the unused bytes before sending the packet.
* Any reply packet is not handled by this function.
*/
-static int ep1_generic_commandl(usb_dev_handle *pHDev_param, size_t length, ...)
+static int ep1_generic_commandl(libusb_device_handle *pHDev_param, size_t length, ...)
{
uint8_t usb_buffer[USB_EP1OUT_SIZE];
uint8_t *usb_buffer_p;
va_list ap;
int usb_ret;
+ int transferred;
if (length > sizeof(usb_buffer))
length = sizeof(usb_buffer);
@@ -128,25 +129,29 @@ static int ep1_generic_commandl(usb_dev_handle *pHDev_param, size_t length, ...)
sizeof(usb_buffer) - (usb_buffer_p - usb_buffer)
);
- usb_ret = usb_bulk_write(
+ usb_ret = jtag_libusb_bulk_write(
pHDev_param,
USB_EP1OUT_ADDR,
(char *)usb_buffer, sizeof(usb_buffer),
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
- return usb_ret;
+ if (usb_ret != ERROR_OK)
+ return usb_ret;
+ return transferred;
}
#if 0
static ssize_t ep1_memory_read(
- usb_dev_handle *pHDev, uint16_t addr,
+ libusb_device_handle *pHDev_param, uint16_t addr,
size_t length, uint8_t *buffer)
{
uint8_t usb_buffer[USB_EP1OUT_SIZE];
int usb_ret;
size_t remain;
ssize_t count;
+ int transferred;
usb_buffer[0] = EP1_CMD_MEMORY_READ;
memset(
@@ -168,22 +173,24 @@ static ssize_t ep1_memory_read(
usb_buffer[2] = addr;
usb_buffer[3] = length;
- usb_ret = usb_bulk_write(
- pHDev, USB_EP1OUT_ADDR,
- usb_buffer, sizeof(usb_buffer),
- USB_TIMEOUT_MS
+ usb_ret = jtag_libusb_bulk_write(
+ pHDev_param, USB_EP1OUT_ADDR,
+ (char *)usb_buffer, sizeof(usb_buffer),
+ USB_TIMEOUT_MS,
+ &transferred
);
- if (usb_ret < sizeof(usb_buffer))
+ if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer))
break;
- usb_ret = usb_bulk_read(
- pHDev, USB_EP1IN_ADDR,
- buffer, length,
- USB_TIMEOUT_MS
+ usb_ret = jtag_libusb_bulk_read(
+ pHDev_param, USB_EP1IN_ADDR,
+ (char *)buffer, length,
+ USB_TIMEOUT_MS,
+ &transferred
);
- if (usb_ret < length)
+ if (usb_ret != ERROR_OK || transferred < (int)length)
break;
addr += length;
@@ -196,7 +203,7 @@ static ssize_t ep1_memory_read(
}
#endif
-static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr,
+static ssize_t ep1_memory_write(libusb_device_handle *pHDev_param, uint16_t addr,
size_t length, uint8_t const *buffer)
{
uint8_t usb_buffer[USB_EP1OUT_SIZE];
@@ -229,13 +236,16 @@ static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr,
sizeof(usb_buffer) - 4 - length
);
- usb_ret = usb_bulk_write(
+ int transferred;
+
+ usb_ret = jtag_libusb_bulk_write(
pHDev_param, USB_EP1OUT_ADDR,
(char *)usb_buffer, sizeof(usb_buffer),
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
- if ((size_t)usb_ret < sizeof(usb_buffer))
+ if (usb_ret != ERROR_OK || transferred < (int)sizeof(usb_buffer))
break;
addr += length;
@@ -249,7 +259,7 @@ static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr,
#if 0
-static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr,
+static ssize_t ep1_memory_writel(libusb_device_handle *pHDev_param, uint16_t addr,
size_t length, ...)
{
uint8_t buffer[USB_EP1OUT_SIZE - 4];
@@ -269,7 +279,7 @@ static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr,
remain--;
}
- return ep1_memory_write(pHDev, addr, length, buffer);
+ return ep1_memory_write(pHDev_param, addr, length, buffer);
}
#endif
@@ -286,7 +296,7 @@ static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr,
static uint8_t dtc_entry_download;
/* The buffer is specially formatted to represent a valid image to load into the DTC. */
-static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buffer,
+static int dtc_load_from_buffer(libusb_device_handle *pHDev_param, const uint8_t *buffer,
size_t length)
{
struct header_s {
@@ -401,6 +411,7 @@ static int dtc_start_download(void)
{
int usb_err;
uint8_t ep2txr;
+ int transferred;
/* set up for download mode and make sure EP2 is set up to transmit */
usb_err = ep1_generic_commandl(
@@ -418,12 +429,13 @@ static int dtc_start_download(void)
return usb_err;
/* read back ep2txr */
- usb_err = usb_bulk_read(
+ usb_err = jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)&ep2txr, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
- if (usb_err < 0)
+ if (usb_err != ERROR_OK)
return usb_err;
usb_err = ep1_generic_commandl(
@@ -447,17 +459,18 @@ static int dtc_start_download(void)
return usb_err;
/* wait for completion */
- usb_err = usb_bulk_read(
+ usb_err = jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)&ep2txr, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
return usb_err;
}
static int dtc_run_download(
- usb_dev_handle *pHDev_param,
+ libusb_device_handle *pHDev_param,
uint8_t *command_buffer,
int command_buffer_size,
uint8_t *reply_buffer,
@@ -467,14 +480,16 @@ static int dtc_run_download(
char dtc_status;
int usb_err;
int i;
+ int transferred;
LOG_DEBUG("%d/%d", command_buffer_size, reply_buffer_size);
- usb_err = usb_bulk_write(
+ usb_err = jtag_libusb_bulk_write(
pHDev_param,
USB_EP2OUT_ADDR,
(char *)command_buffer, USB_EP2BANK_SIZE,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
if (usb_err < 0)
return usb_err;
@@ -493,11 +508,12 @@ static int dtc_run_download(
if (usb_err < 0)
return usb_err;
- usb_err = usb_bulk_read(
+ usb_err = jtag_libusb_bulk_read(
pHDev_param,
USB_EP1IN_ADDR,
&dtc_status, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
if (usb_err < 0)
return usb_err;
@@ -507,20 +523,21 @@ static int dtc_run_download(
if (!--i) {
LOG_ERROR("too many retries waiting for DTC status");
- return -ETIMEDOUT;
+ return LIBUSB_ERROR_TIMEOUT;
}
}
if (reply_buffer && reply_buffer_size) {
- usb_err = usb_bulk_read(
+ usb_err = jtag_libusb_bulk_read(
pHDev_param,
USB_EP2IN_ADDR,
(char *)reply_buffer, reply_buffer_size,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
- if (usb_err < reply_buffer_size) {
+ if (usb_err != ERROR_OK || transferred < reply_buffer_size) {
LOG_ERROR("Read of endpoint 2 returned %d, expected %d",
usb_err, reply_buffer_size
);
@@ -644,7 +661,7 @@ static int dtc_queue_run(void)
reply_buffer, sizeof(reply_buffer)
);
if (usb_err < 0) {
- LOG_ERROR("dtc_run_download: %s", usb_strerror());
+ LOG_ERROR("dtc_run_download: %s", libusb_error_name(usb_err));
exit(1);
}
@@ -919,6 +936,7 @@ static void rlink_reset(int trst, int srst)
{
uint8_t bitmap;
int usb_err;
+ int transferred;
/* Read port A for bit op */
usb_err = ep1_generic_commandl(
@@ -929,17 +947,18 @@ static void rlink_reset(int trst, int srst)
1
);
if (usb_err < 0) {
- LOG_ERROR("%s", usb_strerror());
+ LOG_ERROR("%s", libusb_error_name(usb_err));
exit(1);
}
- usb_err = usb_bulk_read(
+ usb_err = jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)&bitmap, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
- if (usb_err < 1) {
- LOG_ERROR("%s", usb_strerror());
+ if (usb_err != ERROR_OK || transferred < 1) {
+ LOG_ERROR("%s", libusb_error_name(usb_err));
exit(1);
}
@@ -964,17 +983,18 @@ static void rlink_reset(int trst, int srst)
1
);
if (usb_err < 0) {
- LOG_ERROR("%s", usb_strerror());
+ LOG_ERROR("%s", libusb_error_name(usb_err));
exit(1);
}
- usb_err = usb_bulk_read(
+ usb_err = jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)&bitmap, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
- if (usb_err < 1) {
- LOG_ERROR("%s", usb_strerror());
+ if (usb_err != ERROR_OK || transferred < 1) {
+ LOG_ERROR("%s", libusb_error_name(usb_err));
exit(1);
}
@@ -994,17 +1014,18 @@ static void rlink_reset(int trst, int srst)
EP1_CMD_DTC_GET_CACHED_STATUS
);
if (usb_err < 0) {
- LOG_ERROR("%s", usb_strerror());
+ LOG_ERROR("%s", libusb_error_name(usb_err));
exit(1);
}
- usb_err = usb_bulk_read(
+ usb_err = jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)&bitmap, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
- if (usb_err < 1) {
- LOG_ERROR("%s", usb_strerror());
+ if (usb_err != ERROR_OK || transferred < 1) {
+ LOG_ERROR("%s", libusb_error_name(usb_err));
exit(1);
}
}
@@ -1391,8 +1412,9 @@ static int rlink_speed(int speed)
exit(1);
}
- if (dtc_start_download() < 0) {
- LOG_ERROR("starting DTC: %s", usb_strerror());
+ int ret = dtc_start_download();
+ if (ret < 0) {
+ LOG_ERROR("starting DTC: %s", libusb_error_name(ret));
exit(1);
}
@@ -1444,19 +1466,28 @@ static int rlink_init(void)
{
int i, j, retries;
uint8_t reply_buffer[USB_EP1IN_SIZE];
+ int transferred;
- usb_init();
const uint16_t vids[] = { USB_IDVENDOR, 0 };
const uint16_t pids[] = { USB_IDPRODUCT, 0 };
- if (jtag_usb_open(vids, pids, &pHDev) != ERROR_OK)
+ if (jtag_libusb_open(vids, pids, NULL, &pHDev, NULL) != ERROR_OK)
return ERROR_FAIL;
- struct usb_device *dev = usb_device(pHDev);
- if (dev->descriptor.bNumConfigurations > 1) {
+ struct libusb_device_descriptor descriptor;
+ struct libusb_device *usb_dev = libusb_get_device(pHDev);
+ int r = libusb_get_device_descriptor(usb_dev, &descriptor);
+ if (r < 0) {
+ LOG_ERROR("error %d getting device descriptor", r);
+ return ERROR_FAIL;
+ }
+
+ if (descriptor.bNumConfigurations > 1) {
LOG_ERROR("Whoops! NumConfigurations is not 1, don't know what to do...");
return ERROR_FAIL;
}
- if (dev->config->bNumInterfaces > 1) {
+ struct libusb_config_descriptor *config;
+ libusb_get_config_descriptor(usb_dev, 0, &config);
+ if (config->bNumInterfaces > 1) {
LOG_ERROR("Whoops! NumInterfaces is not 1, don't know what to do...");
return ERROR_FAIL;
}
@@ -1464,29 +1495,27 @@ static int rlink_init(void)
LOG_DEBUG("Opened device, pHDev = %p", pHDev);
/* usb_set_configuration required under win32 */
- usb_set_configuration(pHDev, dev->config[0].bConfigurationValue);
+ libusb_set_configuration(pHDev, config->bConfigurationValue);
retries = 3;
do {
- i = usb_claim_interface(pHDev, 0);
- if (i) {
- LOG_ERROR("usb_claim_interface: %s", usb_strerror());
-#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
- j = usb_detach_kernel_driver_np(pHDev, 0);
- if (j)
- LOG_ERROR("detach kernel driver: %s", usb_strerror());
-#endif
+ i = libusb_claim_interface(pHDev, 0);
+ if (i != LIBUSB_SUCCESS) {
+ LOG_ERROR("usb_claim_interface: %s", libusb_error_name(i));
+ j = libusb_detach_kernel_driver(pHDev, 0);
+ if (j != LIBUSB_SUCCESS)
+ LOG_ERROR("detach kernel driver: %s", libusb_error_name(j));
} else {
LOG_DEBUG("interface claimed!");
break;
}
} while (--retries);
- if (i) {
+ if (i != LIBUSB_SUCCESS) {
LOG_ERROR("Initialisation failed.");
return ERROR_FAIL;
}
- if (usb_set_altinterface(pHDev, 0) != 0) {
+ if (libusb_set_interface_alt_setting(pHDev, 0, 0) != LIBUSB_SUCCESS) {
LOG_ERROR("Failed to set interface.");
return ERROR_FAIL;
}
@@ -1506,20 +1535,21 @@ static int rlink_init(void)
EP1_CMD_GET_FWREV
);
if (j < USB_EP1OUT_SIZE) {
- LOG_ERROR("USB write error: %s", usb_strerror());
+ LOG_ERROR("USB write error: %s", libusb_error_name(j));
return ERROR_FAIL;
}
- j = usb_bulk_read(
+ j = jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)reply_buffer, sizeof(reply_buffer),
- 200
+ 200,
+ &transferred
);
- if (j != -ETIMEDOUT)
+ if (j != LIBUSB_ERROR_TIMEOUT)
break;
}
- if (j < (int)sizeof(reply_buffer)) {
- LOG_ERROR("USB read error: %s", usb_strerror());
+ if (j != ERROR_OK || transferred != (int)sizeof(reply_buffer)) {
+ LOG_ERROR("USB read error: %s", libusb_error_name(j));
return ERROR_FAIL;
}
LOG_DEBUG(INTERFACE_NAME " firmware version: %d.%d.%d",
@@ -1552,10 +1582,11 @@ static int rlink_init(void)
ST7_PE_ADAPTER_SENSE_OUT
);
- usb_bulk_read(
+ jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)reply_buffer, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) != 0)
@@ -1576,10 +1607,11 @@ static int rlink_init(void)
0x00 /* OR */
);
- usb_bulk_read(
+ jtag_libusb_bulk_read(
pHDev, USB_EP1IN_ADDR,
(char *)reply_buffer, 1,
- USB_TIMEOUT_MS
+ USB_TIMEOUT_MS,
+ &transferred
);
@@ -1655,8 +1687,8 @@ static int rlink_quit(void)
~0
);
- usb_release_interface(pHDev, 0);
- usb_close(pHDev);
+ libusb_release_interface(pHDev, 0);
+ libusb_close(pHDev);
return ERROR_OK;
}
diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c
index a6d7c3a..a43ef8e 100644
--- a/src/jtag/drivers/stlink_usb.c
+++ b/src/jtag/drivers/stlink_usb.c
@@ -1,4 +1,7 @@
/***************************************************************************
+ * Copyright (C) 2020 by Tarek Bochkati *
+ * Tarek Bochkati <tarek.bouchkati@gmail.com> *
+ * *
* SWIM contributions by Ake Rehnman *
* Copyright (C) 2017 Ake Rehnman *
* ake.rehnman(at)gmail.com *
@@ -43,6 +46,16 @@
#include <target/cortex_m.h>
+#include <helper/system.h>
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
#include "libusb_helper.h"
#ifdef HAVE_LIBUSB1
@@ -120,12 +133,48 @@ struct stlink_usb_version {
uint32_t flags;
};
-/** */
-struct stlink_usb_handle_s {
+struct stlink_usb_priv_s {
/** */
struct libusb_device_handle *fd;
/** */
struct libusb_transfer *trans;
+};
+
+struct stlink_tcp_priv_s {
+ /** */
+ int fd;
+ /** */
+ bool connected;
+ /** */
+ uint32_t device_id;
+ /** */
+ uint32_t connect_id;
+ /** */
+ uint8_t *send_buf;
+ /** */
+ uint8_t *recv_buf;
+};
+
+struct stlink_backend_s {
+ /** */
+ int (*open)(void *handle, struct hl_interface_param_s *param);
+ /** */
+ int (*close)(void *handle);
+ /** */
+ int (*xfer_noerrcheck)(void *handle, const uint8_t *buf, int size);
+ /** */
+ int (*read_trace)(void *handle, const uint8_t *buf, int size);
+};
+
+/** */
+struct stlink_usb_handle_s {
+ /** */
+ struct stlink_backend_s *backend;
+ /** */
+ union {
+ struct stlink_usb_priv_s usb_backend_priv;
+ struct stlink_tcp_priv_s tcp_backend_priv;
+ };
/** */
uint8_t rx_ep;
/** */
@@ -133,13 +182,13 @@ struct stlink_usb_handle_s {
/** */
uint8_t trace_ep;
/** */
- uint8_t cmdbuf[STLINK_SG_SIZE];
+ uint8_t *cmdbuf;
/** */
uint8_t cmdidx;
/** */
uint8_t direction;
/** */
- uint8_t databuf[STLINK_DATA_SIZE];
+ uint8_t *databuf;
/** */
uint32_t max_mem_packet;
/** */
@@ -162,6 +211,26 @@ struct stlink_usb_handle_s {
bool reconnect_pending;
};
+/** */
+static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param)
+{
+ struct stlink_usb_handle_s *h = handle;
+ return h->backend->open(handle, param);
+}
+
+/** */
+static inline int stlink_usb_close(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+ return h->backend->close(handle);
+}
+/** */
+static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
+{
+ struct stlink_usb_handle_s *h = handle;
+ return h->backend->xfer_noerrcheck(handle, buf, size);
+}
+
#define STLINK_SWIM_ERR_OK 0x00
#define STLINK_SWIM_BUSY 0x01
#define STLINK_DEBUG_ERR_OK 0x80
@@ -307,6 +376,39 @@ struct stlink_usb_handle_s {
#define REQUEST_SENSE 0x03
#define REQUEST_SENSE_LENGTH 18
+/* STLINK TCP commands */
+#define STLINK_TCP_CMD_REFRESH_DEVICE_LIST 0x00
+#define STLINK_TCP_CMD_GET_NB_DEV 0x01
+#define STLINK_TCP_CMD_GET_DEV_INFO 0x02
+#define STLINK_TCP_CMD_OPEN_DEV 0x03
+#define STLINK_TCP_CMD_CLOSE_DEV 0x04
+#define STLINK_TCP_CMD_SEND_USB_CMD 0x05
+#define STLINK_TCP_CMD_GET_SERVER_VERSION 0x06
+#define STLINK_TCP_CMD_GET_NB_OF_DEV_CLIENTS 0x07
+
+/* STLINK TCP constants */
+#define OPENOCD_STLINK_TCP_API_VERSION 1
+#define STLINK_TCP_REQUEST_WRITE 0
+#define STLINK_TCP_REQUEST_READ 1
+#define STLINK_TCP_REQUEST_READ_SWO 3
+#define STLINK_TCP_SS_SIZE 4
+#define STLINK_TCP_USB_CMD_SIZE 32
+#define STLINK_TCP_SERIAL_SIZE 32
+#define STLINK_TCP_SEND_BUFFER_SIZE 10240
+#define STLINK_TCP_RECV_BUFFER_SIZE 10240
+
+/* STLINK TCP command status */
+#define STLINK_TCP_SS_OK 0x00000001
+#define STLINK_TCP_SS_MEMORY_PROBLEM 0x00001000
+#define STLINK_TCP_SS_TIMEOUT 0x00001001
+#define STLINK_TCP_SS_BAD_PARAMETER 0x00001002
+#define STLINK_TCP_SS_OPEN_ERR 0x00001003
+#define STLINK_TCP_SS_TRUNCATED_DATA 0x00001052
+#define STLINK_TCP_SS_CMD_NOT_AVAILABLE 0x00001053
+#define STLINK_TCP_SS_TCP_ERROR 0x00002001
+#define STLINK_TCP_SS_TCP_CANT_CONNECT 0x00002002
+#define STLINK_TCP_SS_WIN32_ERROR 0x00010000
+
/*
* Map the relevant features, quirks and workaround for specific firmware
* version of stlink
@@ -381,8 +483,6 @@ static unsigned int stlink_usb_block(void *handle)
return STLINK_MAX_RW8;
}
-
-
#ifdef USE_LIBUSB_ASYNCIO
static LIBUSB_CALL void sync_transfer_cb(struct libusb_transfer *transfer)
@@ -546,7 +646,7 @@ static int stlink_usb_xfer_v1_get_status(void *handle)
/* read status */
memset(h->cmdbuf, 0, STLINK_SG_SIZE);
- ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)h->cmdbuf, 13,
+ ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)h->cmdbuf, 13,
STLINK_READ_TIMEOUT, &tr);
if (ret || tr != 13)
return ERROR_FAIL;
@@ -603,7 +703,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
}
return jtag_libusb_bulk_transfer_n(
- h->fd,
+ h->usb_backend_priv.fd,
transfers,
n_transfers,
STLINK_WRITE_TIMEOUT);
@@ -616,20 +716,20 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
assert(handle != NULL);
- ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)h->cmdbuf,
+ ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)h->cmdbuf,
cmdsize, STLINK_WRITE_TIMEOUT, &tr);
if (ret || tr != cmdsize)
return ERROR_FAIL;
if (h->direction == h->tx_ep && size) {
- ret = jtag_libusb_bulk_write(h->fd, h->tx_ep, (char *)buf,
+ ret = jtag_libusb_bulk_write(h->usb_backend_priv.fd, h->tx_ep, (char *)buf,
size, STLINK_WRITE_TIMEOUT, &tr);
if (ret || tr != size) {
LOG_DEBUG("bulk write failed");
return ERROR_FAIL;
}
} else if (h->direction == h->rx_ep && size) {
- ret = jtag_libusb_bulk_read(h->fd, h->rx_ep, (char *)buf,
+ ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->rx_ep, (char *)buf,
size, STLINK_READ_TIMEOUT, &tr);
if (ret || tr != size) {
LOG_DEBUG("bulk read failed");
@@ -668,13 +768,29 @@ static int stlink_usb_xfer_v1_get_sense(void *handle)
return ERROR_OK;
}
+/** */
+static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int tr, ret;
+
+ ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size,
+ STLINK_READ_TIMEOUT, &tr);
+ if (ret || tr != size) {
+ LOG_ERROR("bulk trace read failed");
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
/*
transfers block in cmdbuf
<size> indicates number of bytes in the following
data phase.
Ignore the (eventual) error code in the received packet.
*/
-static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
+static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
{
int err, cmdsize = STLINK_CMD_SIZE_V2;
struct stlink_usb_handle_s *h = handle;
@@ -707,6 +823,117 @@ static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size
return ERROR_OK;
}
+
+static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool check_tcp_status)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ assert(handle != NULL);
+
+ /* send the TCP command */
+ int sent_size = send(h->tcp_backend_priv.fd, (void *)h->tcp_backend_priv.send_buf, send_size, 0);
+ if (sent_size != send_size) {
+ LOG_ERROR("failed to send USB CMD");
+ if (sent_size == -1)
+ LOG_DEBUG("socket send error: %s (errno %d)", strerror(errno), errno);
+ else
+ LOG_DEBUG("sent size %d (expected %d)", sent_size, send_size);
+ return ERROR_FAIL;
+ }
+
+ keep_alive();
+
+ /* read the TCP response */
+ int received_size = recv(h->tcp_backend_priv.fd, (void *)h->tcp_backend_priv.recv_buf, recv_size, 0);
+ if (received_size != recv_size) {
+ LOG_ERROR("failed to receive USB CMD response");
+ if (received_size == -1)
+ LOG_DEBUG("socket recv error: %s (errno %d)", strerror(errno), errno);
+ else
+ LOG_DEBUG("received size %d (expected %d)", received_size, recv_size);
+ return ERROR_FAIL;
+ }
+
+ if (check_tcp_status) {
+ uint32_t tcp_ss = le_to_h_u32(h->tcp_backend_priv.recv_buf);
+ if (tcp_ss != STLINK_TCP_SS_OK) {
+ LOG_ERROR("TCP error status 0x%X", tcp_ss);
+ return ERROR_FAIL;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ int send_size = STLINK_TCP_USB_CMD_SIZE;
+ int recv_size = STLINK_TCP_SS_SIZE;
+
+ assert(handle != NULL);
+
+ /* prepare the TCP command */
+ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_SEND_USB_CMD;
+ memset(&h->tcp_backend_priv.send_buf[1], 0, 3); /* reserved for alignment and future use, must be zero */
+ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id);
+ /* tcp_backend_priv.send_buf[8..23] already contains the constructed stlink command */
+ h->tcp_backend_priv.send_buf[24] = h->direction;
+ memset(&h->tcp_backend_priv.send_buf[25], 0, 3); /* reserved for alignment and future use, must be zero */
+
+ h_u32_to_le(&h->tcp_backend_priv.send_buf[28], size);
+
+ /*
+ * if the xfer is a write request (tx_ep)
+ * > then buf content will be copied
+ * into &cmdbuf[32].
+ * else : the xfer is a read or trace read request (rx_ep or trace_ep)
+ * > the buf content will be filled from &databuf[4].
+ *
+ * note : if h->direction is trace_ep, h->cmdbuf is zeros.
+ */
+
+ if (h->direction == h->tx_ep) { /* STLINK_TCP_REQUEST_WRITE */
+ send_size += size;
+ if (send_size > STLINK_TCP_SEND_BUFFER_SIZE) {
+ LOG_ERROR("STLINK_TCP command buffer overflow");
+ return ERROR_FAIL;
+ }
+ memcpy(&h->tcp_backend_priv.send_buf[32], buf, size);
+ } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */
+ recv_size += size;
+ if (recv_size > STLINK_TCP_RECV_BUFFER_SIZE) {
+ LOG_ERROR("STLINK_TCP data buffer overflow");
+ return ERROR_FAIL;
+ }
+ }
+
+ int ret = stlink_tcp_send_cmd(h, send_size, recv_size, true);
+ if (ret != ERROR_OK)
+ return ret;
+
+ if (h->direction != h->tx_ep) {
+ /* the read data is located in tcp_backend_priv.recv_buf[4] */
+ /* most of the case it will be copying the data from tcp_backend_priv.recv_buf[4]
+ * to handle->cmd_buff which are the same, so let's avoid unnecessary copying */
+ if (buf != &h->tcp_backend_priv.recv_buf[4])
+ memcpy((uint8_t *)buf, &h->tcp_backend_priv.recv_buf[4], size);
+ }
+
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ stlink_usb_init_buffer(h, h->trace_ep, 0);
+ return stlink_tcp_xfer_noerrcheck(handle, buf, size);
+}
+
/**
Converts an STLINK status code held in the first byte of a response
to an openocd error, logs any error/wait status as debug output.
@@ -853,20 +1080,12 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
{
struct stlink_usb_handle_s *h = handle;
- int tr, ret;
assert(handle != NULL);
assert(h->version.flags & STLINK_F_HAS_TRACE);
- ret = jtag_libusb_bulk_read(h->fd, h->trace_ep, (char *)buf, size,
- STLINK_READ_TIMEOUT, &tr);
- if (ret || tr != size) {
- LOG_ERROR("bulk trace read failed");
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
+ return h->backend->read_trace(handle, buf, size);
}
/*
@@ -1749,7 +1968,7 @@ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size)
return res;
size_t bytes_avail = le_to_h_u16(h->databuf);
- *size = bytes_avail < *size ? bytes_avail : *size - 1;
+ *size = bytes_avail < *size ? bytes_avail : *size;
if (*size > 0) {
res = stlink_usb_read_trace(handle, buf, *size);
@@ -2716,18 +2935,68 @@ static int stlink_speed(void *handle, int khz, bool query)
}
/** */
-static int stlink_usb_close(void *handle)
+static int stlink_usb_usb_close(void *handle)
{
struct stlink_usb_handle_s *h = handle;
- if (h && h->fd) {
+ if (!h)
+ return ERROR_OK;
+
+ if (h->usb_backend_priv.fd) {
stlink_usb_exit_mode(h);
/* do not check return code, it prevent
us from closing jtag_libusb */
- jtag_libusb_close(h->fd);
+ jtag_libusb_close(h->usb_backend_priv.fd);
}
- free(h);
+ free(h->cmdbuf);
+ free(h->databuf);
+
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_tcp_close(void *handle)
+{
+ struct stlink_usb_handle_s *h = handle;
+
+ if (!h)
+ return ERROR_OK;
+
+ int ret = ERROR_OK;
+ if (h->tcp_backend_priv.connected) {
+ if (h->tcp_backend_priv.connect_id) {
+ stlink_usb_exit_mode(h);
+
+ /* close the stlink */
+ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_CLOSE_DEV;
+ memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */
+ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.connect_id);
+ ret = stlink_tcp_send_cmd(h, 8, 4, true);
+ if (ret != ERROR_OK)
+ LOG_ERROR("cannot close the STLINK");
+ }
+
+ if (close_socket(h->tcp_backend_priv.fd) != 0)
+ LOG_ERROR("error closing the socket, errno: %s", strerror(errno));
+ }
+
+ free(h->tcp_backend_priv.send_buf);
+ free(h->tcp_backend_priv.recv_buf);
+
+ return ret;
+}
+
+/** */
+static int stlink_close(void *handle)
+{
+ if (handle != NULL) {
+ struct stlink_usb_handle_s *h = handle;
+
+ stlink_usb_close(handle);
+
+ free(h);
+ }
return ERROR_OK;
}
@@ -2812,27 +3081,16 @@ static char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
}
/** */
-static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
+static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param)
{
+ struct stlink_usb_handle_s *h = handle;
int err, retry_count = 1;
- struct stlink_usb_handle_s *h;
-
- LOG_DEBUG("stlink_usb_open");
- h = calloc(1, sizeof(struct stlink_usb_handle_s));
+ h->cmdbuf = malloc(STLINK_SG_SIZE);
+ h->databuf = malloc(STLINK_DATA_SIZE);
- if (h == 0) {
- LOG_DEBUG("malloc failed");
+ if (h->cmdbuf == NULL || h->databuf == NULL)
return ERROR_FAIL;
- }
-
- h->st_mode = mode;
-
- for (unsigned i = 0; param->vid[i]; i++) {
- LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
- h->st_mode, param->vid[i], param->pid[i],
- param->serial ? param->serial : "");
- }
/*
On certain host USB configurations(e.g. MacBook Air)
@@ -2845,25 +3103,25 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
*/
do {
if (jtag_libusb_open(param->vid, param->pid, param->serial,
- &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
+ &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
LOG_ERROR("open failed");
- goto error_open;
+ return ERROR_FAIL;
}
- jtag_libusb_set_configuration(h->fd, 0);
+ jtag_libusb_set_configuration(h->usb_backend_priv.fd, 0);
- if (libusb_claim_interface(h->fd, 0) != ERROR_OK) {
+ if (libusb_claim_interface(h->usb_backend_priv.fd, 0) != ERROR_OK) {
LOG_DEBUG("claim interface failed");
- goto error_open;
+ return ERROR_FAIL;
}
/* RX EP is common for all versions */
h->rx_ep = STLINK_RX_EP;
uint16_t pid;
- if (jtag_libusb_get_pid(libusb_get_device(h->fd), &pid) != ERROR_OK) {
+ if (jtag_libusb_get_pid(libusb_get_device(h->usb_backend_priv.fd), &pid) != ERROR_OK) {
LOG_DEBUG("libusb_get_pid failed");
- goto error_open;
+ return ERROR_FAIL;
}
/* wrap version for first read */
@@ -2903,21 +3161,21 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
} else if (h->version.stlink == 1 ||
retry_count == 0) {
LOG_ERROR("read version failed");
- goto error_open;
+ return ERROR_FAIL;
} else {
- err = libusb_release_interface(h->fd, 0);
+ err = libusb_release_interface(h->usb_backend_priv.fd, 0);
if (err != ERROR_OK) {
LOG_ERROR("release interface failed");
- goto error_open;
+ return ERROR_FAIL;
}
- err = libusb_reset_device(h->fd);
+ err = libusb_reset_device(h->usb_backend_priv.fd);
if (err != ERROR_OK) {
LOG_ERROR("reset device failed");
- goto error_open;
+ return ERROR_FAIL;
}
- jtag_libusb_close(h->fd);
+ jtag_libusb_close(h->usb_backend_priv.fd);
/*
Give the device one second to settle down and
reenumerate.
@@ -2927,8 +3185,265 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
}
} while (1);
+ return ERROR_OK;
+}
+
+/** */
+static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param)
+{
+ struct stlink_usb_handle_s *h = handle;
+ int ret;
+
+ /* SWIM is not supported using stlink-server */
+ if (h->st_mode == STLINK_MODE_DEBUG_SWIM) {
+ LOG_ERROR("stlink-server does not support SWIM mode");
+ return ERROR_FAIL;
+ }
+
+ h->tcp_backend_priv.send_buf = malloc(STLINK_TCP_SEND_BUFFER_SIZE);
+ h->tcp_backend_priv.recv_buf = malloc(STLINK_TCP_RECV_BUFFER_SIZE);
+
+ if (h->tcp_backend_priv.send_buf == NULL || h->tcp_backend_priv.recv_buf == NULL)
+ return ERROR_FAIL;
+
+ h->cmdbuf = &h->tcp_backend_priv.send_buf[8];
+ h->databuf = &h->tcp_backend_priv.recv_buf[4];
+
+ /* configure directions */
+ h->rx_ep = STLINK_TCP_REQUEST_READ;
+ h->tx_ep = STLINK_TCP_REQUEST_WRITE;
+ h->trace_ep = STLINK_TCP_REQUEST_READ_SWO;
+
+ h->tcp_backend_priv.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ h->tcp_backend_priv.connected = false;
+ h->tcp_backend_priv.device_id = 0;
+ h->tcp_backend_priv.connect_id = 0;
+
+ if (h->tcp_backend_priv.fd == -1) {
+ LOG_ERROR("error creating the socket, errno: %s", strerror(errno));
+ return ERROR_FAIL;
+ }
+
+ struct sockaddr_in serv;
+ memset(&serv, 0, sizeof(struct sockaddr_in));
+ serv.sin_family = AF_INET;
+ serv.sin_port = htons(param->stlink_tcp_port);
+ serv.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ LOG_DEBUG("socket : %x", h->tcp_backend_priv.fd);
+
+ int optval = 1;
+ if (setsockopt(h->tcp_backend_priv.fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, sizeof(int)) == -1) {
+ LOG_ERROR("cannot set sock option 'TCP_NODELAY', errno: %s", strerror(errno));
+ return ERROR_FAIL;
+ }
+
+ optval = STLINK_TCP_RECV_BUFFER_SIZE;
+ if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_RCVBUF, (const void *)&optval, sizeof(int)) == -1) {
+ LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", strerror(errno));
+ return ERROR_FAIL;
+ }
+
+ optval = STLINK_TCP_SEND_BUFFER_SIZE;
+ if (setsockopt(h->tcp_backend_priv.fd, SOL_SOCKET, SO_SNDBUF, (const void *)&optval, sizeof(int)) == -1) {
+ LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", strerror(errno));
+ return ERROR_FAIL;
+ }
+
+ if (connect(h->tcp_backend_priv.fd, (const struct sockaddr *)&serv, sizeof(serv)) == -1) {
+ LOG_ERROR("cannot connect to stlink server, errno: %s", strerror(errno));
+ return ERROR_FAIL;
+ }
+
+ h->tcp_backend_priv.connected = true;
+
+ LOG_INFO("connected to stlink-server");
+
+ /* print stlink-server version */
+ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION;
+ h->tcp_backend_priv.send_buf[1] = OPENOCD_STLINK_TCP_API_VERSION;
+ memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */
+ ret = stlink_tcp_send_cmd(h, 4, 16, false);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("cannot get the stlink-server version");
+ return ERROR_FAIL;
+ }
+
+ uint32_t api_ver = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]);
+ uint32_t ver_major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]);
+ uint32_t ver_minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]);
+ uint32_t ver_build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]);
+ LOG_INFO("stlink-server API v%d, version %d.%d.%d",
+ api_ver, ver_major, ver_minor, ver_build);
+
+ /* in stlink-server API v1 sending more than 1428 bytes will cause stlink-server
+ * to crash in windows: select a safe default value (1K) */
+ if (api_ver < 2)
+ h->max_mem_packet = (1 << 10);
+
+ /* refresh stlink list (re-enumerate) */
+ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST;
+ h->tcp_backend_priv.send_buf[1] = 0; /* don't clear the list, just refresh it */
+ ret = stlink_tcp_send_cmd(h, 2, 4, true);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* get the number of connected stlinks */
+ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_NB_DEV;
+ ret = stlink_tcp_send_cmd(h, 1, 4, false);
+ if (ret != ERROR_OK)
+ return ret;
+
+ uint32_t connected_stlinks = le_to_h_u32(h->tcp_backend_priv.recv_buf);
+
+ if (connected_stlinks == 0) {
+ LOG_ERROR("no ST-LINK detected");
+ return ERROR_FAIL;
+ }
+
+ LOG_DEBUG("%d ST-LINK detected", connected_stlinks);
+
+ if (connected_stlinks > 255) {
+ LOG_WARNING("STLink server cannot handle more than 255 ST-LINK connected");
+ connected_stlinks = 255;
+ }
+
+ /* list all connected ST-Link and seek for the requested vid:pid and serial */
+ char serial[STLINK_TCP_SERIAL_SIZE + 1] = {0};
+ uint8_t stlink_used;
+ bool stlink_id_matched = false;
+ bool stlink_serial_matched = (param->serial == NULL);
+
+ for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; stlink_id++) {
+ /* get the stlink info */
+ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_GET_DEV_INFO;
+ h->tcp_backend_priv.send_buf[1] = (uint8_t)stlink_id;
+ memset(&h->tcp_backend_priv.send_buf[2], 0, 2); /* reserved */
+ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], 41); /* size of TDeviceInfo2 */
+ ret = stlink_tcp_send_cmd(h, 8, 45, true);
+ if (ret != ERROR_OK)
+ return ret;
+
+ h->tcp_backend_priv.device_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]);
+ memcpy(serial, &h->tcp_backend_priv.recv_buf[8], STLINK_TCP_SERIAL_SIZE);
+ h->vid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[40]);
+ h->pid = le_to_h_u16(&h->tcp_backend_priv.recv_buf[42]);
+ stlink_used = h->tcp_backend_priv.recv_buf[44];
+
+ /* check the vid:pid */
+ for (int i = 0; param->vid[i]; i++) {
+ if (param->vid[i] == h->vid && param->pid[i] == h->pid) {
+ stlink_id_matched = true;
+ break;
+ }
+ }
+
+ if (!stlink_id_matched)
+ continue;
+
+ /* check the serial if specified */
+ if (param->serial) {
+ /* ST-Link server fixes the buggy serial returned by old ST-Link DFU
+ * for further details refer to stlink_usb_get_alternate_serial
+ * so if the user passes the buggy serial, we need to fix it before
+ * comparing with the serial returned by ST-Link server */
+ if (strlen(param->serial) == STLINK_SERIAL_LEN / 2) {
+ char fixed_serial[STLINK_SERIAL_LEN + 1];
+
+ for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2)
+ sprintf(fixed_serial + i, "%02X", param->serial[i / 2]);
+
+ fixed_serial[STLINK_SERIAL_LEN] = '\0';
+
+ stlink_serial_matched = strcmp(fixed_serial, serial) == 0;
+ } else
+ stlink_serial_matched = strcmp(param->serial, serial) == 0;
+ }
+
+ if (!stlink_serial_matched)
+ LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'",
+ serial, param->serial);
+ else /* exit the search loop if there is match */
+ break;
+ }
+
+ if (!stlink_id_matched) {
+ LOG_ERROR("ST-LINK open failed (vid/pid mismatch)");
+ return ERROR_FAIL;
+ }
+
+ if (!stlink_serial_matched) {
+ LOG_ERROR("ST-LINK open failed (serial mismatch)");
+ return ERROR_FAIL;
+ }
+
+ /* check if device is 'exclusively' used by another application */
+ if (stlink_used) {
+ LOG_ERROR("the selected device is already used");
+ return ERROR_FAIL;
+ }
+
+ LOG_DEBUG("transport: vid: 0x%04x pid: 0x%04x serial: %s", h->vid, h->pid, serial);
+
+ /* now let's open the stlink */
+ h->tcp_backend_priv.send_buf[0] = STLINK_TCP_CMD_OPEN_DEV;
+ memset(&h->tcp_backend_priv.send_buf[1], 0, 4); /* reserved */
+ h_u32_to_le(&h->tcp_backend_priv.send_buf[4], h->tcp_backend_priv.device_id);
+ ret = stlink_tcp_send_cmd(h, 8, 8, true);
+ if (ret != ERROR_OK)
+ return ret;
+
+ h->tcp_backend_priv.connect_id = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]);
+
+ /* get stlink version */
+ return stlink_usb_version(h);
+}
+
+static struct stlink_backend_s stlink_usb_backend = {
+ .open = stlink_usb_usb_open,
+ .close = stlink_usb_usb_close,
+ .xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck,
+ .read_trace = stlink_usb_usb_read_trace,
+};
+
+static struct stlink_backend_s stlink_tcp_backend = {
+ .open = stlink_tcp_open,
+ .close = stlink_tcp_close,
+ .xfer_noerrcheck = stlink_tcp_xfer_noerrcheck,
+ .read_trace = stlink_tcp_read_trace,
+};
+
+static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
+{
+ struct stlink_usb_handle_s *h;
+
+ LOG_DEBUG("stlink_open");
+
+ h = calloc(1, sizeof(struct stlink_usb_handle_s));
+
+ if (h == 0) {
+ LOG_DEBUG("malloc failed");
+ return ERROR_FAIL;
+ }
+
+ h->st_mode = mode;
+
+ for (unsigned i = 0; param->vid[i]; i++) {
+ LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
+ h->st_mode, param->vid[i], param->pid[i],
+ param->serial ? param->serial : "");
+ }
+
+ if (param->use_stlink_tcp)
+ h->backend = &stlink_tcp_backend;
+ else
+ h->backend = &stlink_usb_backend;
+
+ if (stlink_usb_open(h, param) != ERROR_OK)
+ goto error_open;
+
/* check if mode is supported */
- err = ERROR_OK;
+ int err = ERROR_OK;
switch (h->st_mode) {
case STLINK_MODE_DEBUG_SWD:
@@ -2972,37 +3487,39 @@ static int stlink_usb_open(struct hl_interface_param_s *param, enum stlink_mode
return ERROR_OK;
}
- /* get cpuid, so we can determine the max page size
- * start with a safe default */
- h->max_mem_packet = (1 << 10);
+ /* set max_mem_packet if it was not set by the low-level interface */
+ if (h->max_mem_packet == 0) {
+ /* get cpuid, so we can determine the max page size
+ * start with a safe default */
+ h->max_mem_packet = (1 << 10);
- uint8_t buffer[4];
- stlink_usb_open_ap(h, 0);
- err = stlink_usb_read_mem32(h, CPUID, 4, buffer);
- if (err == ERROR_OK) {
- uint32_t cpuid = le_to_h_u32(buffer);
- int i = (cpuid >> 4) & 0xf;
- if (i == 4 || i == 3) {
- /* Cortex-M3/M4 has 4096 bytes autoincrement range */
- h->max_mem_packet = (1 << 12);
+ uint8_t buffer[4];
+ stlink_usb_open_ap(h, 0);
+ err = stlink_usb_read_mem32(h, CPUID, 4, buffer);
+ if (err == ERROR_OK) {
+ uint32_t cpuid = le_to_h_u32(buffer);
+ int i = (cpuid >> 4) & 0xf;
+ if (i == 4 || i == 3) {
+ /* Cortex-M3/M4 has 4096 bytes autoincrement range */
+ h->max_mem_packet = (1 << 12);
+ }
}
- }
- LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet);
+ LOG_DEBUG("Using TAR autoincrement: %" PRIu32, h->max_mem_packet);
+ }
*fd = h;
return ERROR_OK;
error_open:
- stlink_usb_close(h);
-
+ stlink_close(h);
return ERROR_FAIL;
}
static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
{
- return stlink_usb_open(param, stlink_get_mode(param->transport), fd);
+ return stlink_open(param, stlink_get_mode(param->transport), fd);
}
static int stlink_config_trace(void *handle, bool enabled,
@@ -3012,8 +3529,20 @@ static int stlink_config_trace(void *handle, bool enabled,
{
struct stlink_usb_handle_s *h = handle;
- if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) ||
- pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) {
+ if (!(h->version.flags & STLINK_F_HAS_TRACE)) {
+ LOG_ERROR("The attached ST-LINK version doesn't support trace");
+ return ERROR_FAIL;
+ }
+
+ if (!enabled) {
+ stlink_usb_trace_disable(h);
+ return ERROR_OK;
+ }
+
+ assert(trace_freq != NULL);
+ assert(prescaler != NULL);
+
+ if (pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART) {
LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
return ERROR_FAIL;
}
@@ -3022,14 +3551,12 @@ static int stlink_config_trace(void *handle, bool enabled,
STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ;
/* Only concern ourselves with the frequency if the STlink is processing it. */
- if (enabled && *trace_freq > max_trace_freq) {
+ if (*trace_freq > max_trace_freq) {
LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u",
max_trace_freq);
return ERROR_FAIL;
}
- stlink_usb_trace_disable(h);
-
if (!*trace_freq)
*trace_freq = max_trace_freq;
@@ -3051,8 +3578,7 @@ static int stlink_config_trace(void *handle, bool enabled,
*prescaler = presc;
- if (!enabled)
- return ERROR_OK;
+ stlink_usb_trace_disable(h);
h->trace.source_hz = *trace_freq;
@@ -3152,7 +3678,7 @@ struct hl_layout_api_s stlink_usb_layout_api = {
/** */
.open = stlink_usb_hl_open,
/** */
- .close = stlink_usb_close,
+ .close = stlink_close,
/** */
.idcode = stlink_usb_idcode,
/** */
@@ -3672,6 +4198,32 @@ COMMAND_HANDLER(stlink_dap_vid_pid)
}
/** */
+COMMAND_HANDLER(stlink_dap_backend_command)
+{
+ /* default values */
+ bool use_stlink_tcp = false;
+ uint16_t stlink_tcp_port = 7184;
+
+ if (CMD_ARGC == 0 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ else if (strcmp(CMD_ARGV[0], "usb") == 0) {
+ if (CMD_ARGC > 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ /* else use_stlink_tcp = false (already the case ) */
+ } else if (strcmp(CMD_ARGV[0], "tcp") == 0) {
+ use_stlink_tcp = true;
+ if (CMD_ARGC == 2)
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port);
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ stlink_dap_param.use_stlink_tcp = use_stlink_tcp;
+ stlink_dap_param.stlink_tcp_port = stlink_tcp_port;
+
+ return ERROR_OK;
+}
+
+/** */
static const struct command_registration stlink_dap_subcommand_handlers[] = {
{
.name = "serial",
@@ -3687,6 +4239,13 @@ static const struct command_registration stlink_dap_subcommand_handlers[] = {
.help = "USB VID and PID of the adapter",
.usage = "(vid pid)+",
},
+ {
+ .name = "backend",
+ .handler = &stlink_dap_backend_command,
+ .mode = COMMAND_CONFIG,
+ .help = "select which ST-Link backend to use",
+ .usage = "usb | tcp [port]",
+ },
COMMAND_REGISTRATION_DONE
};
@@ -3729,7 +4288,7 @@ static int stlink_dap_init(void)
return ERROR_FAIL;
}
- retval = stlink_usb_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
+ retval = stlink_open(&stlink_dap_param, mode, (void **)&stlink_dap_handle);
if (retval != ERROR_OK)
return retval;
@@ -3749,7 +4308,7 @@ static int stlink_dap_quit(void)
free((void *)stlink_dap_param.serial);
stlink_dap_param.serial = NULL;
- return stlink_usb_close(stlink_dap_handle);
+ return stlink_close(stlink_dap_handle);
}
/** */
diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
index 15028b7..d55bf85 100644
--- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
+++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c
@@ -134,13 +134,18 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
return ERROR_FAIL;
}
+ if (libusb_claim_interface(libusb_dev, 0)) {
+ LOG_ERROR("unable to claim interface");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
ublast2_firmware_image.base_address = 0;
ublast2_firmware_image.base_address_set = false;
int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex");
if (ret != ERROR_OK) {
LOG_ERROR("Could not load firmware image");
- return ret;
+ goto error_release_usb;
}
/** A host loader program must write 0x01 to the CPUCS register
@@ -168,7 +173,7 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
&ublast2_firmware_image, i);
if (ret != ERROR_OK) {
LOG_ERROR("Error while downloading the firmware");
- return ret;
+ goto error_close_firmware;
}
}
@@ -183,9 +188,18 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev,
1,
100);
+error_close_firmware:
image_close(&ublast2_firmware_image);
- return ERROR_OK;
+error_release_usb:
+ /*
+ * Release claimed interface. Most probably it is already disconnected
+ * and re-enumerated as new devices after firmware upload, so we do
+ * not need to care about errors.
+ */
+ libusb_release_interface(libusb_dev, 0);
+
+ return ret;
}
static int ublast2_libusb_init(struct ublast_lowlevel *low)
@@ -229,6 +243,12 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
}
}
+ if (libusb_claim_interface(low->libusb_dev, 0)) {
+ LOG_ERROR("unable to claim interface");
+ jtag_libusb_close(low->libusb_dev);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
char buffer[5];
jtag_libusb_control_transfer(low->libusb_dev,
LIBUSB_REQUEST_TYPE_VENDOR |
@@ -247,6 +267,9 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
static int ublast2_libusb_quit(struct ublast_lowlevel *low)
{
+ if (libusb_release_interface(low->libusb_dev, 0))
+ LOG_ERROR("usb release interface failed");
+
jtag_libusb_close(low->libusb_dev);
return ERROR_OK;
};
diff --git a/src/jtag/drivers/usb_common.c b/src/jtag/drivers/usb_common.c
deleted file mode 100644
index 1b7602d..0000000
--- a/src/jtag/drivers/usb_common.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "usb_common.h"
-#include "log.h"
-
-
-static bool jtag_usb_match(struct usb_device *dev,
- const uint16_t vids[], const uint16_t pids[])
-{
- for (unsigned i = 0; vids[i] && pids[i]; i++) {
- if (dev->descriptor.idVendor == vids[i] &&
- dev->descriptor.idProduct == pids[i])
- return true;
- }
- return false;
-}
-
-int jtag_usb_open(const uint16_t vids[], const uint16_t pids[],
- struct usb_dev_handle **out)
-{
- usb_find_busses();
- usb_find_devices();
-
- struct usb_bus *busses = usb_get_busses();
- for (struct usb_bus *bus = busses; bus; bus = bus->next) {
- for (struct usb_device *dev = bus->devices; dev; dev = dev->next) {
- if (!jtag_usb_match(dev, vids, pids))
- continue;
-
- *out = usb_open(dev);
- if (NULL == *out) {
- LOG_ERROR("usb_open() failed with %s", usb_strerror());
- return ERROR_FAIL;
- }
- return ERROR_OK;
- }
- }
- return ERROR_FAIL;
-}
diff --git a/src/jtag/drivers/usb_common.h b/src/jtag/drivers/usb_common.h
deleted file mode 100644
index 4d2bd26..0000000
--- a/src/jtag/drivers/usb_common.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifndef OPENOCD_JTAG_DRIVERS_USB_COMMON_H
-#define OPENOCD_JTAG_DRIVERS_USB_COMMON_H
-
-#include <usb.h>
-
-int jtag_usb_open(const uint16_t vids[], const uint16_t pids[],
- struct usb_dev_handle **out);
-
-#endif /* OPENOCD_JTAG_DRIVERS_USB_COMMON_H */
diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c
index 627e465..44db61e 100644
--- a/src/jtag/drivers/usbprog.c
+++ b/src/jtag/drivers/usbprog.c
@@ -34,7 +34,7 @@
#include <jtag/interface.h>
#include <jtag/commands.h>
-#include "usb_common.h"
+#include "libusb_helper.h"
#define VID 0x1781
#define PID 0x0c63
@@ -64,7 +64,7 @@ static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int
#define WRITE_TMS_CHAIN 0x0A
struct usbprog_jtag {
- struct usb_dev_handle *usb_handle;
+ struct libusb_device_handle *usb_handle;
};
static struct usbprog_jtag *usbprog_jtag_handle;
@@ -350,21 +350,19 @@ struct usb_bus *busses;
struct usbprog_jtag *usbprog_jtag_open(void)
{
- usb_set_debug(10);
- usb_init();
-
const uint16_t vids[] = { VID, 0 };
const uint16_t pids[] = { PID, 0 };
- struct usb_dev_handle *dev;
- if (jtag_usb_open(vids, pids, &dev) != ERROR_OK)
+ struct libusb_device_handle *dev;
+
+ if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK)
return NULL;
struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag));
tmp->usb_handle = dev;
- usb_set_configuration(dev, 1);
- usb_claim_interface(dev, 0);
- usb_set_altinterface(dev, 0);
+ libusb_set_configuration(dev, 1);
+ libusb_claim_interface(dev, 0);
+ libusb_set_interface_alt_setting(dev, 0, 0);
return tmp;
}
@@ -372,21 +370,23 @@ struct usbprog_jtag *usbprog_jtag_open(void)
#if 0
static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag)
{
- usb_close(usbprog_jtag->usb_handle);
+ libusb_close(usbprog_jtag->usb_handle);
free(usbprog_jtag);
}
#endif
static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen)
{
- int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100);
+ int transferred;
+
+ int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100, &transferred);
if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) ||
(msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9))
return 1;
- if (res == msglen) {
+ if (res == ERROR_OK && transferred == msglen) {
/* LOG_INFO("HALLLLOOO %i",(int)msg[0]); */
- res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100);
- if (res > 0)
+ res = jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100, &transferred);
+ if (res == ERROR_OK && transferred > 0)
return (unsigned char)msg[1];
else
return -1;
@@ -428,11 +428,13 @@ static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char
bufindex++;
}
- if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64) {
+ int transferred;
+ int res = jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred);
+ if (res == ERROR_OK && transferred == 64) {
/* LOG_INFO("HALLLLOOO2 %i",(int)tmp[0]); */
usleep(1);
int timeout = 0;
- while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1) {
+ while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000, &transferred) != ERROR_OK) {
timeout++;
if (timeout > 10)
break;
@@ -469,12 +471,13 @@ static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char *buffe
tmp[1] = (char)(send_bits >> 8); /* high */
tmp[2] = (char)(send_bits); /* low */
- usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000);
+ int transferred;
+ jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000, &transferred);
/* LOG_INFO("HALLLLOOO3 %i",(int)tmp[0]); */
int timeout = 0;
usleep(1);
- while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1) {
+ while (jtag_libusb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10, &transferred) != ERROR_OK) {
timeout++;
if (timeout > 10)
break;
@@ -513,7 +516,8 @@ static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char *buff
tmp[3 + i] = buffer[bufindex];
bufindex++;
}
- usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000);
+ int transferred;
+ jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000, &transferred);
}
}
@@ -582,15 +586,15 @@ static void usbprog_jtag_tms_collect(char tms_scan)
static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag)
{
- int i;
/* LOG_INFO("TMS SEND"); */
if (tms_chain_index > 0) {
char tmp[tms_chain_index + 2];
tmp[0] = WRITE_TMS_CHAIN;
tmp[1] = (char)(tms_chain_index);
- for (i = 0; i < tms_chain_index + 1; i++)
+ for (int i = 0; i < tms_chain_index + 1; i++)
tmp[2 + i] = tms_chain[i];
- usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000);
+ int transferred;
+ jtag_libusb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000, &transferred);
tms_chain_index = 0;
}
}
diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c
index 6691a9a..04e01d2 100644
--- a/src/jtag/hla/hla_interface.c
+++ b/src/jtag/hla/hla_interface.c
@@ -35,7 +35,7 @@
#include <target/target.h>
-static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 };
+static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1, false, 7184}, 0, 0 };
int hl_interface_open(enum hl_transports tr)
{
@@ -292,6 +292,31 @@ COMMAND_HANDLER(hl_interface_handle_vid_pid_command)
return ERROR_OK;
}
+COMMAND_HANDLER(hl_interface_handle_stlink_backend_command)
+{
+ /* default values */
+ bool use_stlink_tcp = false;
+ uint16_t stlink_tcp_port = 7184;
+
+ if (CMD_ARGC == 0 || CMD_ARGC > 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ else if (strcmp(CMD_ARGV[0], "usb") == 0) {
+ if (CMD_ARGC > 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ /* else use_stlink_tcp = false (already the case ) */
+ } else if (strcmp(CMD_ARGV[0], "tcp") == 0) {
+ use_stlink_tcp = true;
+ if (CMD_ARGC == 2)
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], stlink_tcp_port);
+ } else
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ hl_if.param.use_stlink_tcp = use_stlink_tcp;
+ hl_if.param.stlink_tcp_port = stlink_tcp_port;
+
+ return ERROR_OK;
+}
+
COMMAND_HANDLER(interface_handle_hla_command)
{
if (CMD_ARGC != 1)
@@ -336,6 +361,13 @@ static const struct command_registration hl_interface_command_handlers[] = {
.help = "the vendor and product ID of the adapter",
.usage = "(vid pid)* ",
},
+ {
+ .name = "hla_stlink_backend",
+ .handler = &hl_interface_handle_stlink_backend_command,
+ .mode = COMMAND_CONFIG,
+ .help = "select which ST-Link backend to use",
+ .usage = "usb | tcp [port]",
+ },
{
.name = "hla_command",
.handler = &interface_handle_hla_command,
diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h
index b6e4a8b..a1c95cd 100644
--- a/src/jtag/hla/hla_interface.h
+++ b/src/jtag/hla/hla_interface.h
@@ -46,6 +46,10 @@ struct hl_interface_param_s {
bool connect_under_reset;
/** Initial interface clock clock speed */
int initial_interface_speed;
+ /** */
+ bool use_stlink_tcp;
+ /** */
+ uint16_t stlink_tcp_port;
};
struct hl_interface_s {
diff --git a/src/jtag/interface.h b/src/jtag/interface.h
index 0884868..58bfd02 100644
--- a/src/jtag/interface.h
+++ b/src/jtag/interface.h
@@ -27,7 +27,7 @@
#include <jtag/jtag.h>
#include <jtag/swim.h>
-#include <target/armv7m_trace.h>
+#include <target/arm_tpiu_swo.h>
/* @file
* The "Cable Helper API" is what the cable drivers can use to help
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 061a78f..63faa95 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -42,11 +42,6 @@
* that contain an adapter_driver structure that can added to this list.
*/
-#if BUILD_ZY1000 == 1
-extern struct adapter_driver zy1000_adapter_driver;
-#elif defined(BUILD_MINIDRIVER_DUMMY)
-extern struct adapter_driver minidummy_adapter_driver;
-#else /* standard drivers */
#if BUILD_PARPORT == 1
extern struct adapter_driver parport_adapter_driver;
#endif
@@ -152,21 +147,12 @@ extern struct adapter_driver stlink_dap_adapter_driver;
#if BUILD_RSHIM == 1
extern struct adapter_driver rshim_dap_adapter_driver;
#endif
-#endif /* standard drivers */
/**
* The list of built-in JTAG interfaces, containing entries for those
* drivers that were enabled by the @c configure script.
- *
- * The list should be defined to contain either one minidriver interface
- * or some number of standard driver interfaces, never both.
*/
struct adapter_driver *adapter_drivers[] = {
-#if BUILD_ZY1000 == 1
- &zy1000_adapter_driver,
-#elif defined(BUILD_MINIDRIVER_DUMMY)
- &minidummy_adapter_driver,
-#else /* standard drivers */
#if BUILD_PARPORT == 1
&parport_adapter_driver,
#endif
@@ -272,6 +258,5 @@ struct adapter_driver *adapter_drivers[] = {
#if BUILD_RSHIM == 1
&rshim_dap_adapter_driver,
#endif
-#endif /* standard drivers */
NULL,
};
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
index cc403df..feb4614 100644
--- a/src/jtag/jtag.h
+++ b/src/jtag/jtag.h
@@ -47,15 +47,6 @@
typedef enum tap_state {
TAP_INVALID = -1,
-#if BUILD_ZY1000
- /* These are the old numbers. Leave as-is for now... */
- TAP_RESET = 0, TAP_IDLE = 8,
- TAP_DRSELECT = 1, TAP_DRCAPTURE = 2, TAP_DRSHIFT = 3, TAP_DREXIT1 = 4,
- TAP_DRPAUSE = 5, TAP_DREXIT2 = 6, TAP_DRUPDATE = 7,
- TAP_IRSELECT = 9, TAP_IRCAPTURE = 10, TAP_IRSHIFT = 11, TAP_IREXIT1 = 12,
- TAP_IRPAUSE = 13, TAP_IREXIT2 = 14, TAP_IRUPDATE = 15,
-
-#else
/* Proper ARM recommended numbers */
TAP_DREXIT2 = 0x0,
TAP_DREXIT1 = 0x1,
@@ -73,8 +64,6 @@ typedef enum tap_state {
TAP_IRUPDATE = 0xd,
TAP_IRCAPTURE = 0xe,
TAP_RESET = 0x0f,
-
-#endif
} tap_state_t;
/**
@@ -636,9 +625,6 @@ bool jtag_poll_get_enabled(void);
*/
void jtag_poll_set_enabled(bool value);
-
-/* The minidriver may have inline versions of some of the low
- * level APIs that are used in inner loops. */
#include <jtag/minidriver.h>
int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
diff --git a/src/jtag/minidriver.h b/src/jtag/minidriver.h
index ad830cc..c6fdfaf 100644
--- a/src/jtag/minidriver.h
+++ b/src/jtag/minidriver.h
@@ -45,7 +45,7 @@
/* this header will be provided by the minidriver implementation, */
/* and it may provide additional declarations that must be defined. */
-#include <jtag/minidriver_imp.h>
+#include <jtag/drivers/minidriver_imp.h>
int interface_jtag_add_ir_scan(struct jtag_tap *active,
const struct scan_field *fields,
diff --git a/src/jtag/minidriver/minidriver_imp.h b/src/jtag/minidriver/minidriver_imp.h
deleted file mode 100644
index 11d0fae..0000000
--- a/src/jtag/minidriver/minidriver_imp.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
- * Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
- * Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifndef OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H
-#define OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H
-
-#include <jtag/jtag_minidriver.h>
-
-#define jtag_add_callback(callback, in) interface_jtag_add_callback(callback, in)
-
-#define jtag_add_callback4(callback, in, data1, data2, data3) \
- interface_jtag_add_callback4(callback, in, data1, data2, data3)
-
-#endif /* OPENOCD_JTAG_MINIDRIVER_MINIDRIVER_IMP_H */
diff --git a/src/jtag/minidummy/jtag_minidriver.h b/src/jtag/minidummy/jtag_minidriver.h
deleted file mode 100644
index 1708356..0000000
--- a/src/jtag/minidummy/jtag_minidriver.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2007-2008 by Øyvind Harboe *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#define interface_jtag_add_callback(callback, in) callback(in)
-
-#define interface_jtag_add_callback4(callback, in, data1, data2, data3) \
- jtag_set_error(callback(in, data1, data2, data3))
diff --git a/src/jtag/minidummy/minidummy.c b/src/jtag/minidummy/minidummy.c
deleted file mode 100644
index 7ee2067..0000000
--- a/src/jtag/minidummy/minidummy.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2007-2008 by Øyvind Harboe *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <jtag/jtag.h>
-#include <target/embeddedice.h>
-#include <jtag/minidriver.h>
-#include <jtag/interface.h>
-
-static struct jtag_interface minidummy_interface = {
- .execute_queue = NULL,
-};
-
-struct adapter_driver minidummy_adapter_driver = {
- .name = "minidummy",
- .transports = jtag_only,
- .commands = NULL,
-
- .init = NULL,
- .quit = NULL,
- .speed = NULL,
- .khz = NULL,
- .speed_div = NULL,
- .power_dropout = NULL,
- .srst_asserted = NULL,
-
- .jtag_ops = &minidummy_interface,
-};
-
-int interface_jtag_execute_queue(void)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields,
- tap_state_t state)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits,
- uint8_t *in_bits, tap_state_t state)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_dr_scan(struct jtag_tap *active, int num_fields,
- const struct scan_field *fields, tap_state_t state)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits,
- uint8_t *in_bits, tap_state_t state)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_tlr(void)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_reset(int req_trst, int req_srst)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_clocks(int num_cycles)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_sleep(uint32_t us)
-{
- jtag_sleep(us);
- return ERROR_OK;
-}
-
-int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
-{
- int state_count;
- int tms = 0;
-
- state_count = 0;
-
- tap_state_t cur_state = cmd_queue_cur_state;
-
- while (num_states) {
- if (tap_state_transition(cur_state, false) == path[state_count])
- tms = 0;
- else if (tap_state_transition(cur_state, true) == path[state_count])
- tms = 1;
- else {
- LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
- tap_state_name(cur_state), tap_state_name(path[state_count]));
- exit(-1);
- }
-
- /* synchronously do the operation here */
-
- cur_state = path[state_count];
- state_count++;
- num_states--;
- }
-
-
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state)
-{
- /* synchronously do the operation here */
-
- return ERROR_OK;
-}
-
-void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer,
- int little, int count)
-{
- int i;
- for (i = 0; i < count; i++) {
- embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little));
- buffer += 4;
- }
-}
-
-int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode,
- uint32_t *data, size_t count)
-{
- int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap,
- uint32_t opcode, uint32_t *data, size_t count);
- return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count);
-}
diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl
index 82327a3..f1e69e5 100644
--- a/src/jtag/startup.tcl
+++ b/src/jtag/startup.tcl
@@ -29,7 +29,7 @@ proc init_reset { mode } {
#########
# TODO: power_restore and power_dropout are currently neither
-# documented nor supported except on ZY1000.
+# documented nor supported.
proc power_restore {} {
echo "Sensed power restore, running reset init and halting GDB."
@@ -55,7 +55,7 @@ proc power_dropout {} {
#########
# TODO: srst_deasserted and srst_asserted are currently neither
-# documented nor supported except on ZY1000.
+# documented nor supported.
proc srst_deasserted {} {
echo "Sensed nSRST deasserted, running reset init and halting GDB."
@@ -117,23 +117,8 @@ proc jtag_ntrst_assert_width args {
# JTAG-specific names despite the fact that the operations were not
# specific to JTAG, or otherwise had troublesome/misleading names.
#
-# FIXME phase these aids out after about April 2011
+# FIXME phase these aids out after some releases
#
-proc jtag_khz args {
- echo "DEPRECATED! use 'adapter speed' not 'jtag_khz'"
- eval adapter speed $args
-}
-
-proc jtag_nsrst_delay args {
- echo "DEPRECATED! use 'adapter srst delay' not 'jtag_nsrst_delay'"
- eval adapter srst delay $args
-}
-
-proc jtag_nsrst_assert_width args {
- echo "DEPRECATED! use 'adapter srst pulse_width' not 'jtag_nsrst_assert_width'"
- eval adapter srst pulse_width $args
-}
-
proc jtag_reset args {
echo "DEPRECATED! use 'adapter \[de\]assert' not 'jtag_reset'"
switch $args {
@@ -150,32 +135,6 @@ proc jtag_reset args {
}
}
-# stlink migration helpers
-proc stlink_device_desc args {
- echo "DEPRECATED! use 'hla_device_desc' not 'stlink_device_desc'"
- eval hla_device_desc $args
-}
-
-proc stlink_serial args {
- echo "DEPRECATED! use 'hla_serial' not 'stlink_serial'"
- eval hla_serial $args
-}
-
-proc stlink_layout args {
- echo "DEPRECATED! use 'hla_layout' not 'stlink_layout'"
- eval hla_layout $args
-}
-
-proc stlink_vid_pid args {
- echo "DEPRECATED! use 'hla_vid_pid' not 'stlink_vid_pid'"
- eval hla_vid_pid $args
-}
-
-proc stlink args {
- echo "DEPRECATED! use 'hla' not 'stlink'"
- eval hla $args
-}
-
proc adapter_khz args {
echo "DEPRECATED! use 'adapter speed' not 'adapter_khz'"
eval adapter speed $args
diff --git a/src/jtag/zy1000/jtag_minidriver.h b/src/jtag/zy1000/jtag_minidriver.h
deleted file mode 100644
index 7d1ede5..0000000
--- a/src/jtag/zy1000/jtag_minidriver.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2007-2010 by Øyvind Harboe *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-/* used to test manual mode */
-#define TEST_MANUAL() 0
-#define VERBOSE(a)
-
-#if BUILD_ZY1000_MASTER
-
-#define ZY1000_PEEK(a, b) do {b = *((volatile uint32_t *)(a)); } while (0)
-#define ZY1000_POKE(a, b) do {*((volatile uint32_t *)(a)) = b; } while (0)
-extern volatile void *zy1000_jtag_master;
-#define ZY1000_JTAG_BASE ((unsigned long)zy1000_jtag_master)
-
-#else
-
-/* redirect this to TCP/IP */
-#define ZY1000_JTAG_BASE 0
-extern void zy1000_tcpout(uint32_t address, uint32_t data);
-extern uint32_t zy1000_tcpin(uint32_t address);
-#define ZY1000_PEEK(a, b) b = zy1000_tcpin(a)
-#define ZY1000_POKE(a, b) zy1000_tcpout(a, b)
-
-#endif
-
-#if BUILD_ZY1000_MASTER
-/* FIFO empty? */
-static inline void waitIdle(void)
-{
- uint32_t empty;
- do {
- ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty);
- } while ((empty & 0x100) == 0);
-}
-
-static inline void zy1000_flush_readqueue(void)
-{
- /* Not used w/hardware fifo */
-}
-static inline void zy1000_flush_callbackqueue(void)
-{
- /* Not used w/hardware fifo */
-}
-#else
-extern void waitIdle(void);
-void zy1000_flush_readqueue(void);
-void zy1000_flush_callbackqueue(void);
-void zy1000_jtag_add_callback4(jtag_callback_t callback,
- jtag_callback_data_t data0,
- jtag_callback_data_t data1,
- jtag_callback_data_t data2,
- jtag_callback_data_t data3);
-void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0);
-#endif
-
-static inline void waitQueue(void)
-{
-/* waitIdle(); */
-}
-
-static inline void sampleShiftRegister(void)
-{
-#if 0
- uint32_t dummy;
- waitIdle();
- ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, dummy);
-#endif
-}
-
-static inline void setCurrentState(enum tap_state state)
-{
- uint32_t a;
- a = state;
- int repeat = 0;
- if (state == TAP_RESET) {
- /* The FPGA nor we know the current state of the CPU TAP */
- /* controller. This will move it to TAP for sure. */
- /* */
- /* 5 should be enough here, 7 is what OpenOCD uses */
- repeat = 7;
- }
- waitQueue();
- sampleShiftRegister();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | a);
-
-}
-
-/*
- * Enter state and cause repeat transitions *out* of that state. So if the endState != state, then
- * the transition from state to endState counts as a transition out of state.
- */
-static inline void shiftValueInner(const enum tap_state state,
- const enum tap_state endState,
- int repeat,
- uint32_t value)
-{
- uint32_t a, b;
- a = state;
- b = endState;
- waitQueue();
- sampleShiftRegister();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value);
-#if 1
-#if TEST_MANUAL()
- if ((state == TAP_DRSHIFT) && (endState != TAP_DRSHIFT)) {
- int i;
- setCurrentState(state);
- for (i = 0; i < repeat; i++) {
- int tms;
- tms = 0;
- if ((i == repeat-1) && (state != endState))
- tms = 1;
- /* shift out value */
- waitIdle();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, (((value >> i)&1) << 1) | tms);
- }
- waitIdle();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0);
- waitIdle();
- /* ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRSHIFT); // set this state and things
- * break => expected */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRPAUSE); /* set this and things will
- * work => expected. Not
- * setting this is not
- * sufficient to make things
- * break. */
- setCurrentState(endState);
- } else
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b);
-
-#else
- /* fast version */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b);
-#endif
-#else
- /* maximum debug version */
- if ((repeat > 0) && ((state == TAP_DRSHIFT) || (state == TAP_SI))) {
- int i;
- /* sample shift register for every bit. */
- for (i = 0; i < repeat-1; i++) {
- sampleShiftRegister();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value >> i);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 8) | (a << 4) | a);
- }
- sampleShiftRegister();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value >> (repeat-1));
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 8) | (a << 4) | b);
- } else {
- sampleShiftRegister();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (repeat << 8) | (a << 4) | b);
- }
- sampleShiftRegister();
-#endif
-}
-
-#if BUILD_ZY1000_MASTER
-#define interface_jtag_add_callback(callback, in) callback(in)
-#define interface_jtag_add_callback4(callback, in, data1, data2, \
- data3) jtag_set_error(callback(in, data1, data2, data3))
-#else
-#define interface_jtag_add_callback(callback, in) zy1000_jtag_add_callback(callback, in)
-#define interface_jtag_add_callback4(callback, in, data1, data2, data3) zy1000_jtag_add_callback4( \
- callback, \
- in, \
- data1, \
- data2, \
- data3)
-#endif
diff --git a/src/jtag/zy1000/zy1000.c b/src/jtag/zy1000/zy1000.c
deleted file mode 100644
index 669e6f4..0000000
--- a/src/jtag/zy1000/zy1000.c
+++ /dev/null
@@ -1,1259 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2007-2010 by Øyvind Harboe *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-/* This file supports the zy1000 debugger:
- *
- * http://www.ultsol.com/index.php/component/content/article/8/33-zylin-zy1000-jtag-probe
- *
- * The zy1000 is a standalone debugger that has a web interface and
- * requires no drivers on the developer host as all communication
- * is via TCP/IP. The zy1000 gets it performance(~400-700kBytes/s
- * DCC downloads @ 16MHz target) as it has an FPGA to hardware
- * accelerate the JTAG commands, while offering *very* low latency
- * between OpenOCD and the FPGA registers.
- *
- * The disadvantage of the zy1000 is that it has a feeble CPU compared to
- * a PC(ca. 50-500 DMIPS depending on how one counts it), whereas a PC
- * is on the order of 10000 DMIPS(i.e. at a factor of 20-200).
- *
- * The zy1000 revc hardware is using an Altera Nios CPU, whereas the
- * revb is using ARM7 + Xilinx.
- *
- * See Zylin web pages or contact Zylin for more information.
- *
- * The reason this code is in OpenOCD rather than OpenOCD linked with the
- * ZY1000 code is that OpenOCD is the long road towards getting
- * libopenocd into place. libopenocd will support both low performance,
- * low latency systems(embedded) and high performance high latency
- * systems(PCs).
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <pthread.h>
-
-#include <target/embeddedice.h>
-#include <jtag/minidriver.h>
-#include <jtag/interface.h>
-#include <time.h>
-#include <helper/time_support.h>
-
-#include <netinet/tcp.h>
-
-/* Assume we're connecting to a revc w/60MHz clock. */
-#define ZYLIN_KHZ 60000
-
-/* The software needs to check if it's in RCLK mode or not */
-static bool zy1000_rclk;
-
-static int zy1000_khz(int khz, int *jtag_speed)
-{
- if (khz == 0)
- *jtag_speed = 0;
- else {
- int speed;
- /* Round speed up to nearest divisor.
- *
- * E.g. 16000kHz
- * (64000 + 15999) / 16000 = 4
- * (4 + 1) / 2 = 2
- * 2 * 2 = 4
- *
- * 64000 / 4 = 16000
- *
- * E.g. 15999
- * (64000 + 15998) / 15999 = 5
- * (5 + 1) / 2 = 3
- * 3 * 2 = 6
- *
- * 64000 / 6 = 10666
- *
- */
- speed = (ZYLIN_KHZ + (khz - 1)) / khz;
- speed = (speed + 1) / 2;
- speed *= 2;
- if (speed > 8190) {
- /* maximum dividend */
- speed = 8190;
- }
- *jtag_speed = speed;
- }
- return ERROR_OK;
-}
-
-static int zy1000_speed_div(int speed, int *khz)
-{
- if (speed == 0)
- *khz = 0;
- else
- *khz = ZYLIN_KHZ / speed;
-
- return ERROR_OK;
-}
-
-static bool readPowerDropout(void)
-{
- uint32_t state;
- /* sample and clear power dropout */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x80);
- ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state);
- bool powerDropout;
- powerDropout = (state & 0x80) != 0;
- return powerDropout;
-}
-
-
-static bool readSRST(void)
-{
- uint32_t state;
- /* sample and clear SRST sensing */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000040);
- ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state);
- bool srstAsserted;
- srstAsserted = (state & 0x40) != 0;
- return srstAsserted;
-}
-
-static int zy1000_srst_asserted(int *srst_asserted)
-{
- *srst_asserted = readSRST();
- return ERROR_OK;
-}
-
-static int zy1000_power_dropout(int *dropout)
-{
- *dropout = readPowerDropout();
- return ERROR_OK;
-}
-
-/* Wait for SRST to assert or deassert */
-static void waitSRST(bool asserted)
-{
- bool first = true;
- int64_t start = 0;
- int64_t total = 0;
- const char *mode = asserted ? "assert" : "deassert";
-
- for (;; ) {
- bool srstAsserted = readSRST();
- if ((asserted && srstAsserted) || (!asserted && !srstAsserted)) {
- if (total > 1)
- LOG_USER("SRST took %dms to %s", (int)total, mode);
- break;
- }
-
- if (first) {
- first = false;
- start = timeval_ms();
- }
-
- total = timeval_ms() - start;
-
- keep_alive();
-
- if (total > 5000) {
- LOG_ERROR("SRST took too long to %s: %" PRId64 "ms", mode, total);
- break;
- }
- }
-}
-
-void zy1000_reset(int trst, int srst)
-{
- LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst);
-
- /* flush the JTAG FIFO. Not flushing the queue before messing with
- * reset has such interesting bugs as causing hard to reproduce
- * RCLK bugs as RCLK will stop responding when TRST is asserted
- */
- waitIdle();
-
- if (!srst)
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000001);
- else {
- /* Danger!!! if clk != 0 when in
- * idle in TAP_IDLE, reset halt on str912 will fail.
- */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000001);
-
- waitSRST(true);
- }
-
- if (!trst)
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000002);
- else {
- /* assert reset */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000002);
- }
-
- if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) {
- /* we're now in the RESET state until trst is deasserted */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_RESET);
- } else {
- /* We'll get RCLK failure when we assert TRST, so clear any false positives here */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400);
- }
-
- /* wait for srst to float back up */
- if ((!srst && ((jtag_get_reset_config() & RESET_TRST_PULLS_SRST) == 0)) ||
- (!srst && !trst && (jtag_get_reset_config() & RESET_TRST_PULLS_SRST)))
- waitSRST(false);
-}
-
-int zy1000_speed(int speed)
-{
- /* flush JTAG master FIFO before setting speed */
- waitIdle();
-
- zy1000_rclk = false;
-
- if (speed == 0) {
- /*0 means RCLK*/
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x100);
- zy1000_rclk = true;
- LOG_DEBUG("jtag_speed using RCLK");
- } else {
- if (speed > 8190 || speed < 2) {
- LOG_USER(
- "valid ZY1000 jtag_speed=[8190,2]. With divisor is %dkHz / even values between 8190-2, i.e. min %dHz, max %dMHz",
- ZYLIN_KHZ,
- (ZYLIN_KHZ * 1000) / 8190,
- ZYLIN_KHZ / (2 * 1000));
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- int khz;
- speed &= ~1;
- zy1000_speed_div(speed, &khz);
- LOG_USER("jtag_speed %d => JTAG clk=%d kHz", speed, khz);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x100);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x1c, speed);
- }
- return ERROR_OK;
-}
-
-static bool savePower;
-
-static void setPower(bool power)
-{
- savePower = power;
- if (power)
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x8);
- else
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x8);
-}
-
-COMMAND_HANDLER(handle_power_command)
-{
- switch (CMD_ARGC) {
- case 1: {
- bool enable;
- COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
- setPower(enable);
- }
- /* fall through */
- case 0:
- LOG_INFO("Target power %s", savePower ? "on" : "off");
- break;
- default:
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
-
- return ERROR_OK;
-}
-
-#if !BUILD_ZY1000_MASTER
-static char *tcp_server = "notspecified";
-static int jim_zy1000_server(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
-{
- if (argc != 2)
- return JIM_ERR;
-
- tcp_server = strdup(Jim_GetString(argv[1], NULL));
-
- return JIM_OK;
-}
-#endif
-
-static int zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp,
- int argc,
- Jim_Obj * const *argv)
-{
- if (argc != 1) {
- Jim_WrongNumArgs(interp, 1, argv, "powerstatus");
- return JIM_ERR;
- }
-
- bool dropout = readPowerDropout();
-
- Jim_SetResult(interp, Jim_NewIntObj(interp, dropout));
-
- return JIM_OK;
-}
-
-int zy1000_quit(void)
-{
-
- return ERROR_OK;
-}
-
-int interface_jtag_execute_queue(void)
-{
- uint32_t empty;
-
- waitIdle();
-
- /* We must make sure to write data read back to memory location before we return
- * from this fn
- */
- zy1000_flush_readqueue();
-
- /* and handle any callbacks... */
- zy1000_flush_callbackqueue();
-
- if (zy1000_rclk) {
- /* Only check for errors when using RCLK to speed up
- * jtag over TCP/IP
- */
- ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty);
- /* clear JTAG error register */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400);
-
- if ((empty&0x400) != 0) {
- LOG_WARNING("RCLK timeout");
- /* the error is informative only as we don't want to break the firmware if there
- * is a false positive.
- */
- /* return ERROR_FAIL; */
- }
- }
- return ERROR_OK;
-}
-
-static void writeShiftValue(uint8_t *data, int bits);
-
-/* here we shuffle N bits out/in */
-static inline void scanBits(const uint8_t *out_value,
- uint8_t *in_value,
- int num_bits,
- bool pause_now,
- tap_state_t shiftState,
- tap_state_t end_state)
-{
- tap_state_t pause_state = shiftState;
- for (int j = 0; j < num_bits; j += 32) {
- int k = num_bits - j;
- if (k > 32) {
- k = 32;
- /* we have more to shift out */
- } else if (pause_now) {
- /* this was the last to shift out this time */
- pause_state = end_state;
- }
-
- /* we have (num_bits + 7)/8 bytes of bits to toggle out. */
- /* bits are pushed out LSB to MSB */
- uint32_t value;
- value = 0;
- if (out_value != NULL) {
- for (int l = 0; l < k; l += 8)
- value |= out_value[(j + l)/8]<<l;
- }
- /* mask away unused bits for easier debugging */
- if (k < 32)
- value &= ~(((uint32_t)0xffffffff) << k);
- else {
- /* Shifting by >= 32 is not defined by the C standard
- * and will in fact shift by &0x1f bits on nios */
- }
-
- shiftValueInner(shiftState, pause_state, k, value);
-
- if (in_value != NULL)
- writeShiftValue(in_value + (j/8), k);
- }
-}
-
-static inline void scanFields(int num_fields,
- const struct scan_field *fields,
- tap_state_t shiftState,
- tap_state_t end_state)
-{
- for (int i = 0; i < num_fields; i++) {
- scanBits(fields[i].out_value,
- fields[i].in_value,
- fields[i].num_bits,
- (i == num_fields-1),
- shiftState,
- end_state);
- }
-}
-
-int interface_jtag_add_ir_scan(struct jtag_tap *active,
- const struct scan_field *fields,
- tap_state_t state)
-{
- int scan_size = 0;
- struct jtag_tap *tap, *nextTap;
- tap_state_t pause_state = TAP_IRSHIFT;
-
- for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) {
- nextTap = jtag_tap_next_enabled(tap);
- if (nextTap == NULL)
- pause_state = state;
- scan_size = tap->ir_length;
-
- /* search the list */
- if (tap == active) {
- scanFields(1, fields, TAP_IRSHIFT, pause_state);
- /* update device information */
- buf_cpy(fields[0].out_value, tap->cur_instr, scan_size);
-
- tap->bypass = 0;
- } else {
- /* if a device isn't listed, set it to BYPASS */
- assert(scan_size <= 32);
- shiftValueInner(TAP_IRSHIFT, pause_state, scan_size, 0xffffffff);
-
- /* Optimization code will check what the cur_instr is set to, so
- * we must set it to bypass value.
- */
- buf_set_ones(tap->cur_instr, tap->ir_length);
-
- tap->bypass = 1;
- }
- }
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_plain_ir_scan(int num_bits,
- const uint8_t *out_bits,
- uint8_t *in_bits,
- tap_state_t state)
-{
- scanBits(out_bits, in_bits, num_bits, true, TAP_IRSHIFT, state);
- return ERROR_OK;
-}
-
-int interface_jtag_add_dr_scan(struct jtag_tap *active,
- int num_fields,
- const struct scan_field *fields,
- tap_state_t state)
-{
- struct jtag_tap *tap, *nextTap;
- tap_state_t pause_state = TAP_DRSHIFT;
- for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) {
- nextTap = jtag_tap_next_enabled(tap);
- if (nextTap == NULL)
- pause_state = state;
-
- /* Find a range of fields to write to this tap */
- if (tap == active) {
- assert(!tap->bypass);
-
- scanFields(num_fields, fields, TAP_DRSHIFT, pause_state);
- } else {
- /* Shift out a 0 for disabled tap's */
- assert(tap->bypass);
- shiftValueInner(TAP_DRSHIFT, pause_state, 1, 0);
- }
- }
- return ERROR_OK;
-}
-
-int interface_jtag_add_plain_dr_scan(int num_bits,
- const uint8_t *out_bits,
- uint8_t *in_bits,
- tap_state_t state)
-{
- scanBits(out_bits, in_bits, num_bits, true, TAP_DRSHIFT, state);
- return ERROR_OK;
-}
-
-int interface_jtag_add_tlr(void)
-{
- setCurrentState(TAP_RESET);
- return ERROR_OK;
-}
-
-int interface_jtag_add_reset(int req_trst, int req_srst)
-{
- zy1000_reset(req_trst, req_srst);
- return ERROR_OK;
-}
-
-static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate)
-{
- /* num_cycles can be 0 */
- setCurrentState(clockstate);
-
- /* execute num_cycles, 32 at the time. */
- int i;
- for (i = 0; i < num_cycles; i += 32) {
- int num;
- num = 32;
- if (num_cycles-i < num)
- num = num_cycles-i;
- shiftValueInner(clockstate, clockstate, num, 0);
- }
-
-#if !TEST_MANUAL()
- /* finish in end_state */
- setCurrentState(state);
-#else
- tap_state_t t = TAP_IDLE;
- /* test manual drive code on any target */
- int tms;
- uint8_t tms_scan = tap_get_tms_path(t, state);
- int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
-
- for (i = 0; i < tms_count; i++) {
- tms = (tms_scan >> i) & 1;
- waitIdle();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms);
- }
- waitIdle();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state);
-#endif
-
- return ERROR_OK;
-}
-
-int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
-{
- return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE);
-}
-
-int interface_jtag_add_clocks(int num_cycles)
-{
- return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_cur_state);
-}
-
-int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state)
-{
- /*wait for the fifo to be empty*/
- waitIdle();
-
- for (unsigned i = 0; i < num_bits; i++) {
- int tms;
-
- if (((seq[i/8] >> (i % 8)) & 1) == 0)
- tms = 0;
- else
- tms = 1;
-
- waitIdle();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms);
- }
-
- waitIdle();
- if (state != TAP_INVALID)
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state);
- else {
- /* this would be normal if
- * we are switching to SWD mode */
- }
- return ERROR_OK;
-}
-
-int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
-{
- int state_count;
- int tms = 0;
-
- state_count = 0;
-
- tap_state_t cur_state = cmd_queue_cur_state;
-
- uint8_t seq[16];
- memset(seq, 0, sizeof(seq));
- assert(num_states < (int)((sizeof(seq) * 8)));
-
- while (num_states) {
- if (tap_state_transition(cur_state, false) == path[state_count])
- tms = 0;
- else if (tap_state_transition(cur_state, true) == path[state_count])
- tms = 1;
- else {
- LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
- tap_state_name(cur_state), tap_state_name(path[state_count]));
- exit(-1);
- }
-
- seq[state_count/8] = seq[state_count/8] | (tms << (state_count % 8));
-
- cur_state = path[state_count];
- state_count++;
- num_states--;
- }
-
- return interface_add_tms_seq(state_count, seq, cur_state);
-}
-
-static void jtag_pre_post_bits(struct jtag_tap *tap, int *pre, int *post)
-{
- /* bypass bits before and after */
- int pre_bits = 0;
- int post_bits = 0;
-
- bool found = false;
- struct jtag_tap *cur_tap, *nextTap;
- for (cur_tap = jtag_tap_next_enabled(NULL); cur_tap != NULL; cur_tap = nextTap) {
- nextTap = jtag_tap_next_enabled(cur_tap);
- if (cur_tap == tap)
- found = true;
- else {
- if (found)
- post_bits++;
- else
- pre_bits++;
- }
- }
- *pre = pre_bits;
- *post = post_bits;
-}
-
-void embeddedice_write_dcc(struct jtag_tap *tap,
- int reg_addr,
- const uint8_t *buffer,
- int little,
- int count)
-{
-#if 0
- int i;
- for (i = 0; i < count; i++) {
- embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer,
- little));
- buffer += 4;
- }
-#else
- int pre_bits;
- int post_bits;
- jtag_pre_post_bits(tap, &pre_bits, &post_bits);
-
- if ((pre_bits > 32) || (post_bits + 6 > 32)) {
- int i;
- for (i = 0; i < count; i++) {
- embeddedice_write_reg_inner(tap, reg_addr,
- fast_target_buffer_get_u32(buffer, little));
- buffer += 4;
- }
- } else {
- int i;
- for (i = 0; i < count; i++) {
- /* Fewer pokes means we get to use the FIFO more efficiently */
- shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0);
- shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32,
- fast_target_buffer_get_u32(buffer, little));
- /* Danger! here we need to exit into the TAP_IDLE state to make
- * DCC pick up this value.
- */
- shiftValueInner(TAP_DRSHIFT, TAP_IDLE, 6 + post_bits,
- (reg_addr | (1 << 5)));
- buffer += 4;
- }
- }
-#endif
-}
-
-int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap,
- uint32_t opcode,
- uint32_t *data,
- size_t count)
-{
- /* bypass bits before and after */
- int pre_bits;
- int post_bits;
- jtag_pre_post_bits(tap, &pre_bits, &post_bits);
- post_bits += 2;
-
- if ((pre_bits > 32) || (post_bits > 32)) {
- int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap,
- uint32_t opcode, uint32_t *data, size_t count);
- return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count);
- } else {
- static const uint8_t zero;
-
- /* FIX!!!!!! the target_write_memory() API started this nasty problem
- * with unaligned uint32_t * pointers... */
- const uint8_t *t = (const uint8_t *)data;
-
- while (--count > 0) {
-#if 1
- /* Danger! This code doesn't update cmd_queue_cur_state, so
- * invoking jtag_add_pathmove() before jtag_add_dr_scan() after
- * this loop would fail!
- */
- shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0);
-
- uint32_t value;
- value = *t++;
- value |= (*t++<<8);
- value |= (*t++<<16);
- value |= (*t++<<24);
-
- shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, value);
- /* minimum 2 bits */
- shiftValueInner(TAP_DRSHIFT, TAP_DRPAUSE, post_bits, 0);
-
- /* copy & paste from arm11_dbgtap.c */
- /* TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT,
- * TAP_DRCAPTURE, TAP_DRSHIFT */
- /* KLUDGE! we have to flush the fifo or the Nios CPU locks up.
- * This is probably a bug in the Avalon bus(cross clocking bridge?)
- * or in the jtag registers module.
- */
- waitIdle();
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0);
- /* we don't have to wait for the queue to empty here */
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRSHIFT);
- waitIdle();
-#else
- static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = {
- TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE,
- TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT
- };
-
- struct scan_field fields[2] = {
- { .num_bits = 32, .out_value = t },
- { .num_bits = 2, .out_value = &zero },
- };
- t += 4;
-
- jtag_add_dr_scan(tap,
- 2,
- fields,
- TAP_IDLE);
-
- jtag_add_pathmove(ARRAY_SIZE(arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay),
- arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay);
-#endif
- }
-
- struct scan_field fields[2] = {
- { .num_bits = 32, .out_value = t },
- { .num_bits = 2, .out_value = &zero },
- };
-
- /* This will happen on the last iteration updating cmd_queue_cur_state
- * so we don't have to track it during the common code path
- */
- jtag_add_dr_scan(tap,
- 2,
- fields,
- TAP_IDLE);
-
- return jtag_execute_queue();
- }
-}
-
-static const struct command_registration zy1000_commands[] = {
- {
- .name = "power",
- .handler = handle_power_command,
- .mode = COMMAND_ANY,
- .help = "Turn power switch to target on/off. "
- "With no arguments, prints status.",
- .usage = "('on'|'off)",
- },
-#if !BUILD_ZY1000_MASTER
- {
- .name = "zy1000_server",
- .mode = COMMAND_ANY,
- .jim_handler = jim_zy1000_server,
- .help = "Tcpip address for ZY1000 server.",
- .usage = "address",
- },
-#endif
- {
- .name = "powerstatus",
- .mode = COMMAND_ANY,
- .jim_handler = zylinjtag_Jim_Command_powerstatus,
- .help = "Returns power status of target",
- },
- COMMAND_REGISTRATION_DONE
-};
-
-#if !BUILD_ZY1000_MASTER
-
-static int tcp_ip = -1;
-
-/* Write large packets if we can */
-static size_t out_pos;
-static uint8_t out_buffer[16384];
-static size_t in_pos;
-static size_t in_write;
-static uint8_t in_buffer[16384];
-
-static bool flush_writes(void)
-{
- bool ok = (write(tcp_ip, out_buffer, out_pos) == (int)out_pos);
- out_pos = 0;
- return ok;
-}
-
-static bool writeLong(uint32_t l)
-{
- int i;
- for (i = 0; i < 4; i++) {
- uint8_t c = (l >> (i*8))&0xff;
- out_buffer[out_pos++] = c;
- if (out_pos >= sizeof(out_buffer)) {
- if (!flush_writes())
- return false;
- }
- }
- return true;
-}
-
-static bool readLong(uint32_t *out_data)
-{
- uint32_t data = 0;
- int i;
- for (i = 0; i < 4; i++) {
- uint8_t c;
- if (in_pos == in_write) {
- /* If we have some data that we can send, send them before
- * we wait for more data
- */
- if (out_pos > 0) {
- if (!flush_writes())
- return false;
- }
-
- /* read more */
- int t;
- t = read(tcp_ip, in_buffer, sizeof(in_buffer));
- if (t < 1)
- return false;
- in_write = (size_t) t;
- in_pos = 0;
- }
- c = in_buffer[in_pos++];
-
- data |= (c << (i*8));
- }
- *out_data = data;
- return true;
-}
-
-enum ZY1000_CMD {
- ZY1000_CMD_POKE = 0x0,
- ZY1000_CMD_PEEK = 0x8,
- ZY1000_CMD_SLEEP = 0x1,
- ZY1000_CMD_WAITIDLE = 2
-};
-
-#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
-#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
-
-/* We initialize this late since we need to know the server address
- * first.
- */
-static void tcpip_open(void)
-{
- if (tcp_ip >= 0)
- return;
-
- struct sockaddr_in echoServAddr;/* Echo server address */
-
- /* Create a reliable, stream socket using TCP */
- tcp_ip = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (tcp_ip < 0) {
- fprintf(stderr, "Failed to connect to zy1000 server\n");
- exit(-1);
- }
-
- /* Construct the server address structure */
- memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
- echoServAddr.sin_family = AF_INET; /* Internet address family */
- echoServAddr.sin_addr.s_addr = inet_addr(tcp_server); /* Server IP address */
- echoServAddr.sin_port = htons(7777); /* Server port */
-
- /* Establish the connection to the echo server */
- if (connect(tcp_ip, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) {
- fprintf(stderr, "Failed to connect to zy1000 server\n");
- exit(-1);
- }
-
- int flag = 1;
- setsockopt(tcp_ip, /* socket affected */
- IPPROTO_TCP, /* set option at TCP level */
- TCP_NODELAY, /* name of option */
- (char *)&flag, /* the cast is historical cruft */
- sizeof(int)); /* length of option value */
-
-}
-
-/* send a poke */
-void zy1000_tcpout(uint32_t address, uint32_t data)
-{
- tcpip_open();
- if (!writeLong((ZY1000_CMD_POKE << 24) | address) || !writeLong(data)) {
- fprintf(stderr, "Could not write to zy1000 server\n");
- exit(-1);
- }
-}
-
-/* By sending the wait to the server, we avoid a readback
- * of status. Radically improves performance for this operation
- * with long ping times.
- */
-void waitIdle(void)
-{
- tcpip_open();
- if (!writeLong((ZY1000_CMD_WAITIDLE << 24))) {
- fprintf(stderr, "Could not write to zy1000 server\n");
- exit(-1);
- }
-}
-
-uint32_t zy1000_tcpin(uint32_t address)
-{
- tcpip_open();
-
- zy1000_flush_readqueue();
-
- uint32_t data;
- if (!writeLong((ZY1000_CMD_PEEK << 24) | address) || !readLong(&data)) {
- fprintf(stderr, "Could not read from zy1000 server\n");
- exit(-1);
- }
- return data;
-}
-
-int interface_jtag_add_sleep(uint32_t us)
-{
- tcpip_open();
- if (!writeLong((ZY1000_CMD_SLEEP << 24)) || !writeLong(us)) {
- fprintf(stderr, "Could not read from zy1000 server\n");
- exit(-1);
- }
- return ERROR_OK;
-}
-
-/* queue a readback */
-#define readqueue_size 16384
-static struct {
- uint8_t *dest;
- int bits;
-} readqueue[readqueue_size];
-
-static int readqueue_pos;
-
-/* flush the readqueue, this means reading any data that
- * we're expecting and store them into the final position
- */
-void zy1000_flush_readqueue(void)
-{
- if (readqueue_pos == 0) {
- /* simply debugging by allowing easy breakpoints when there
- * is something to do. */
- return;
- }
- int i;
- tcpip_open();
- for (i = 0; i < readqueue_pos; i++) {
- uint32_t value;
- if (!readLong(&value)) {
- fprintf(stderr, "Could not read from zy1000 server\n");
- exit(-1);
- }
-
- uint8_t *in_value = readqueue[i].dest;
- int k = readqueue[i].bits;
-
- /* we're shifting in data to MSB, shift data to be aligned for returning the value */
- value >>= 32-k;
-
- for (int l = 0; l < k; l += 8)
- in_value[l/8] = (value >> l)&0xff;
- }
- readqueue_pos = 0;
-}
-
-/* By queuing the callback's we avoid flushing the
- * read queue until jtag_execute_queue(). This can
- * reduce latency dramatically for cases where
- * callbacks are used extensively.
-*/
-#define callbackqueue_size 128
-static struct callbackentry {
- jtag_callback_t callback;
- jtag_callback_data_t data0;
- jtag_callback_data_t data1;
- jtag_callback_data_t data2;
- jtag_callback_data_t data3;
-} callbackqueue[callbackqueue_size];
-
-static int callbackqueue_pos;
-
-void zy1000_jtag_add_callback4(jtag_callback_t callback,
- jtag_callback_data_t data0,
- jtag_callback_data_t data1,
- jtag_callback_data_t data2,
- jtag_callback_data_t data3)
-{
- if (callbackqueue_pos >= callbackqueue_size)
- zy1000_flush_callbackqueue();
-
- callbackqueue[callbackqueue_pos].callback = callback;
- callbackqueue[callbackqueue_pos].data0 = data0;
- callbackqueue[callbackqueue_pos].data1 = data1;
- callbackqueue[callbackqueue_pos].data2 = data2;
- callbackqueue[callbackqueue_pos].data3 = data3;
- callbackqueue_pos++;
-
- /* KLUDGE!
- * make callbacks synchronous for now as minidriver requires callback
- * to be synchronous.
- *
- * We can get away with making read and writes asynchronous so we
- * don't completely kill performance.
- */
- zy1000_flush_callbackqueue();
-}
-
-static int zy1000_jtag_convert_to_callback4(jtag_callback_data_t data0,
- jtag_callback_data_t data1,
- jtag_callback_data_t data2,
- jtag_callback_data_t data3)
-{
- ((jtag_callback1_t)data1)(data0);
- return ERROR_OK;
-}
-
-void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0)
-{
- zy1000_jtag_add_callback4(zy1000_jtag_convert_to_callback4,
- data0,
- (jtag_callback_data_t)callback,
- 0,
- 0);
-}
-
-void zy1000_flush_callbackqueue(void)
-{
- /* we have to flush the read queue so we have access to
- the data the callbacks will use
- */
- zy1000_flush_readqueue();
- int i;
- for (i = 0; i < callbackqueue_pos; i++) {
- struct callbackentry *entry = &callbackqueue[i];
- jtag_set_error(entry->callback(entry->data0, entry->data1, entry->data2,
- entry->data3));
- }
- callbackqueue_pos = 0;
-}
-
-static void writeShiftValue(uint8_t *data, int bits)
-{
- waitIdle();
-
- if (!writeLong((ZY1000_CMD_PEEK << 24) | (ZY1000_JTAG_BASE + 0xc))) {
- fprintf(stderr, "Could not read from zy1000 server\n");
- exit(-1);
- }
-
- if (readqueue_pos >= readqueue_size)
- zy1000_flush_readqueue();
-
- readqueue[readqueue_pos].dest = data;
- readqueue[readqueue_pos].bits = bits;
- readqueue_pos++;
-
- /* KLUDGE!!! minidriver requires readqueue to be synchronous */
- zy1000_flush_readqueue();
-}
-
-#else
-
-static void writeShiftValue(uint8_t *data, int bits)
-{
- uint32_t value;
- waitIdle();
- ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, value);
- VERBOSE(LOG_INFO("getShiftValue %08x", value));
-
- /* data in, LSB to MSB */
- /* we're shifting in data to MSB, shift data to be aligned for returning the value */
- value >>= 32 - bits;
-
- for (int l = 0; l < bits; l += 8)
- data[l/8] = (value >> l)&0xff;
-}
-
-#endif
-
-#if BUILD_ZY1000_MASTER
-
-#ifdef WATCHDOG_BASE
-/* If we connect to port 8888 we must send a char every 10s or the board resets itself */
-static void watchdog_server(cyg_addrword_t data)
-{
- int so_reuseaddr_option = 1;
-
- int fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd == -1) {
- LOG_ERROR("error creating socket: %s", strerror(errno));
- exit(-1);
- }
-
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &so_reuseaddr_option,
- sizeof(int));
-
- struct sockaddr_in sin;
- unsigned int address_size;
- address_size = sizeof(sin);
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(8888);
-
- if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
- LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
- exit(-1);
- }
-
- if (listen(fd, 1) == -1) {
- LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
- exit(-1);
- }
-
-
- for (;; ) {
- int watchdog_ip = accept(fd, (struct sockaddr *) &sin, &address_size);
-
- /* Start watchdog, must be reset every 10 seconds. */
- HAL_WRITE_UINT32(WATCHDOG_BASE + 4, 4);
-
- if (watchdog_ip < 0) {
- LOG_ERROR("couldn't open watchdog socket: %s", strerror(errno));
- exit(-1);
- }
-
- int flag = 1;
- setsockopt(watchdog_ip, /* socket affected */
- IPPROTO_TCP, /* set option at TCP level */
- TCP_NODELAY, /* name of option */
- (char *)&flag, /* the cast is historical cruft */
- sizeof(int)); /* length of option value */
-
-
- char buf;
- for (;; ) {
- if (read(watchdog_ip, &buf, 1) == 1) {
- /* Reset timer */
- HAL_WRITE_UINT32(WATCHDOG_BASE + 8, 0x1234);
- /* Echo so we can telnet in and see that resetting works */
- write(watchdog_ip, &buf, 1);
- } else {
- /* Stop tickling the watchdog, the CPU will reset in < 10 seconds
- * now.
- */
- return;
- }
-
- }
-
- /* Never reached */
- }
-}
-#endif
-
-#endif
-
-#if BUILD_ZY1000_MASTER
-int interface_jtag_add_sleep(uint32_t us)
-{
- jtag_sleep(us);
- return ERROR_OK;
-}
-#endif
-
-#if BUILD_ZY1000_MASTER
-volatile void *zy1000_jtag_master;
-#include <sys/mman.h>
-#endif
-
-int zy1000_init(void)
-{
-#if BUILD_ZY1000_MASTER
- int fd = open("/dev/mem", O_RDWR | O_SYNC);
- if (fd == -1) {
- LOG_ERROR("No access to /dev/mem");
- return ERROR_FAIL;
- }
-#ifndef REGISTERS_BASE
-#define REGISTERS_BASE 0x9002000
-#define REGISTERS_SPAN 128
-#endif
-
- zy1000_jtag_master = mmap(0,
- REGISTERS_SPAN,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd,
- REGISTERS_BASE);
-
- if (zy1000_jtag_master == (void *) -1) {
- close(fd);
- LOG_ERROR("No access to /dev/mem");
- return ERROR_FAIL;
- }
-#endif
-
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x30); /* Turn on LED1 & LED2 */
-
- setPower(true); /* on by default */
-
- /* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */
- zy1000_reset(0, 0);
-
- return ERROR_OK;
-}
-
-static struct jtag_interface zy1000_interface = {
- .supported = DEBUG_CAP_TMS_SEQ,
- .execute_queue = NULL,
-};
-
-struct adapter_driver zy1000_adapter_driver = {
- .name = "ZY1000",
- .transports = jtag_only,
- .commands = zy1000_commands,
-
- .init = zy1000_init,
- .quit = zy1000_quit,
- .speed = zy1000_speed,
- .khz = zy1000_khz,
- .speed_div = zy1000_speed_div,
- .power_dropout = zy1000_power_dropout,
- .srst_asserted = zy1000_srst_asserted,
-
- .jtag_ops = &zy1000_interface,
-};
diff --git a/src/openocd.c b/src/openocd.c
index 83c3545..fcefdbe 100644
--- a/src/openocd.c
+++ b/src/openocd.c
@@ -30,7 +30,6 @@
#include <jtag/driver.h>
#include <jtag/jtag.h>
#include <transport/transport.h>
-#include <helper/ioutil.h>
#include <helper/util.h>
#include <helper/configuration.h>
#include <flash/nor/core.h>
@@ -38,6 +37,7 @@
#include <pld/pld.h>
#include <target/arm_cti.h>
#include <target/arm_adi_v5.h>
+#include <target/arm_tpiu_swo.h>
#include <rtt/rtt.h>
#include <server/server.h>
@@ -173,6 +173,10 @@ COMMAND_HANDLER(handle_init_command)
return ERROR_FAIL;
command_context_mode(CMD_CTX, COMMAND_EXEC);
+ /* in COMMAND_EXEC, after target_examine(), only tpiu or only swo */
+ if (command_run_line(CMD_CTX, "tpiu init") != ERROR_OK)
+ return ERROR_FAIL;
+
/* initialize telnet subsystem */
gdb_target_add_all(all_targets);
@@ -255,6 +259,7 @@ static struct command_context *setup_command_handler(Jim_Interp *interp)
&pld_register_commands,
&cti_register_commands,
&dap_register_commands,
+ &arm_tpiu_swo_register_commands,
NULL
};
for (unsigned i = 0; NULL != command_registrants[i]; i++) {
@@ -335,9 +340,6 @@ int openocd_main(int argc, char *argv[])
if (util_init(cmd_ctx) != ERROR_OK)
return EXIT_FAILURE;
- if (ioutil_init(cmd_ctx) != ERROR_OK)
- return EXIT_FAILURE;
-
if (rtt_init() != ERROR_OK)
return EXIT_FAILURE;
@@ -355,6 +357,7 @@ int openocd_main(int argc, char *argv[])
flash_free_all_banks();
gdb_service_free();
+ arm_tpiu_swo_cleanup_all();
server_free();
unregister_all_commands(cmd_ctx, NULL);
diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c
index 215f55d..5334b0d 100644
--- a/src/rtos/FreeRTOS.c
+++ b/src/rtos/FreeRTOS.c
@@ -215,7 +215,7 @@ static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, threadid_t thread_id,
static int FreeRTOS_get_thread_reg(struct rtos *rtos, threadid_t thread_id,
uint32_t reg_num, struct rtos_reg *reg);
static int FreeRTOS_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
-static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int FreeRTOS_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct rtos_type FreeRTOS_rtos = {
.name = "FreeRTOS",
@@ -790,11 +790,11 @@ static int FreeRTOS_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_va
reg_num, reg_value);
}
-static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int FreeRTOS_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
unsigned int i;
*symbol_list = calloc(
- ARRAY_SIZE(FreeRTOS_symbol_list), sizeof(symbol_table_elem_t));
+ ARRAY_SIZE(FreeRTOS_symbol_list), sizeof(struct symbol_table_elem));
for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++) {
(*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i].name;
diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c
index 53788c7..4041332 100644
--- a/src/rtos/ThreadX.c
+++ b/src/rtos/ThreadX.c
@@ -39,7 +39,7 @@ static bool ThreadX_detect_rtos(struct target *target);
static int ThreadX_create(struct target *target);
static int ThreadX_update_threads(struct rtos *rtos);
static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
-static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int ThreadX_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
@@ -477,11 +477,11 @@ static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs);
}
-static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int ThreadX_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
unsigned int i;
*symbol_list = calloc(
- ARRAY_SIZE(ThreadX_symbol_list), sizeof(symbol_table_elem_t));
+ ARRAY_SIZE(ThreadX_symbol_list), sizeof(struct symbol_table_elem));
for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++)
(*symbol_list)[i].symbol_name = ThreadX_symbol_list[i];
diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c
index a56d3ce..29abede 100644
--- a/src/rtos/chibios.c
+++ b/src/rtos/chibios.c
@@ -107,7 +107,7 @@ static int chibios_create(struct target *target);
static int chibios_update_threads(struct rtos *rtos);
static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
-static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct rtos_type chibios_rtos = {
.name = "chibios",
@@ -131,7 +131,7 @@ enum chibios_symbol_values {
CHIBIOS_VAL_CH_DEBUG = 2
};
-static symbol_table_elem_t chibios_symbol_list[] = {
+static struct symbol_table_elem chibios_symbol_list[] = {
{ "rlist", 0, true}, /* Thread ready list */
{ "ch", 0, true}, /* System data structure */
{ "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */
@@ -497,7 +497,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
}
-static int chibios_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
*symbol_list = malloc(sizeof(chibios_symbol_list));
diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c
index ae12a3b..1476f19 100644
--- a/src/rtos/chromium-ec.c
+++ b/src/rtos/chromium-ec.c
@@ -360,12 +360,12 @@ static int chromium_ec_get_thread_reg_list(struct rtos *rtos,
stack_ptr, reg_list, num_regs);
}
-static int chromium_ec_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int chromium_ec_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
size_t s;
*symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list),
- sizeof(symbol_table_elem_t));
+ sizeof(struct symbol_table_elem));
if (!(*symbol_list)) {
LOG_ERROR("Chromium-EC: out of memory");
return ERROR_FAIL;
diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c
index e6b7073..9501a55 100644
--- a/src/rtos/eCos.c
+++ b/src/rtos/eCos.c
@@ -31,7 +31,7 @@ static bool eCos_detect_rtos(struct target *target);
static int eCos_create(struct target *target);
static int eCos_update_threads(struct rtos *rtos);
static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
-static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int eCos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct eCos_thread_state {
int value;
@@ -351,11 +351,11 @@ static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
return -1;
}
-static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int eCos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
unsigned int i;
*symbol_list = calloc(
- ARRAY_SIZE(eCos_symbol_list), sizeof(symbol_table_elem_t));
+ ARRAY_SIZE(eCos_symbol_list), sizeof(struct symbol_table_elem));
for (i = 0; i < ARRAY_SIZE(eCos_symbol_list); i++)
(*symbol_list)[i].symbol_name = eCos_symbol_list[i];
diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c
index 2f04963..994cbc0 100644
--- a/src/rtos/embKernel.c
+++ b/src/rtos/embKernel.c
@@ -36,7 +36,7 @@ static int embKernel_create(struct target *target);
static int embKernel_update_threads(struct rtos *rtos);
static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
-static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int embKernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct rtos_type embKernel_rtos = {
.name = "embKernel",
@@ -330,10 +330,10 @@ static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
}
-static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int embKernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
unsigned int i;
- *symbol_list = calloc(ARRAY_SIZE(embKernel_symbol_list), sizeof(symbol_table_elem_t));
+ *symbol_list = calloc(ARRAY_SIZE(embKernel_symbol_list), sizeof(struct symbol_table_elem));
for (i = 0; i < ARRAY_SIZE(embKernel_symbol_list); i++)
(*symbol_list)[i].symbol_name = embKernel_symbol_list[i];
diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c
index 4051a5d..a1a048a 100644
--- a/src/rtos/hwthread.c
+++ b/src/rtos/hwthread.c
@@ -35,7 +35,7 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
uint32_t reg_num, struct rtos_reg *rtos_reg);
static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
-static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
static int hwthread_smp_init(struct target *target);
static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id);
@@ -338,10 +338,10 @@ static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_va
return reg->type->set(reg, reg_value);
}
-static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
/* return an empty list, we don't have any symbols to look up */
- *symbol_list = calloc(1, sizeof(symbol_table_elem_t));
+ *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
(*symbol_list)[0].symbol_name = NULL;
return 0;
}
diff --git a/src/rtos/linux.c b/src/rtos/linux.c
index 0cb4b54..4b96a93 100644
--- a/src/rtos/linux.c
+++ b/src/rtos/linux.c
@@ -246,11 +246,11 @@ static const char * const linux_symbol_list[] = {
NULL
};
-static int linux_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int linux_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
unsigned int i;
- *symbol_list = (symbol_table_elem_t *)
- calloc(ARRAY_SIZE(linux_symbol_list), sizeof(symbol_table_elem_t));
+ *symbol_list = (struct symbol_table_elem *)
+ calloc(ARRAY_SIZE(linux_symbol_list), sizeof(struct symbol_table_elem));
for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++)
(*symbol_list)[i].symbol_name = linux_symbol_list[i];
diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c
index f45c15d..0914e31 100644
--- a/src/rtos/mqx.c
+++ b/src/rtos/mqx.c
@@ -540,9 +540,9 @@ static int mqx_get_thread_reg_list(
}
/* API function, export list of required symbols */
-static int mqx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
- *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(symbol_table_elem_t));
+ *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem));
if (NULL == *symbol_list)
return ERROR_FAIL;
/* export required symbols */
diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c
index df5dbe1..e637d05 100644
--- a/src/rtos/nuttx.c
+++ b/src/rtos/nuttx.c
@@ -378,12 +378,12 @@ static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
(uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
}
-static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
unsigned int i;
- *symbol_list = (symbol_table_elem_t *) calloc(1,
- sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list));
+ *symbol_list = (struct symbol_table_elem *) calloc(1,
+ sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list));
for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
(*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
diff --git a/src/rtos/riot.c b/src/rtos/riot.c
index 15cbb0f..dcba838 100644
--- a/src/rtos/riot.c
+++ b/src/rtos/riot.c
@@ -35,7 +35,7 @@ static int riot_create(struct target *target);
static int riot_update_threads(struct rtos *rtos);
static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
-static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
+static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct riot_thread_state {
int value;
@@ -360,9 +360,9 @@ static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
num_regs);
}
-static int riot_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
- *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(symbol_table_elem_t));
+ *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem));
if (*symbol_list == NULL) {
LOG_ERROR("RIOT: out of memory");
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 9a470c6..8e1b7e9 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -184,9 +184,9 @@ int gdb_thread_packet(struct connection *connection, char const *packet, int pac
return target->rtos->gdb_thread_packet(connection, packet, packet_size);
}
-static symbol_table_elem_t *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr)
+static struct symbol_table_elem *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr)
{
- symbol_table_elem_t *s;
+ struct symbol_table_elem *s;
if (!os->symbols)
os->type->get_symbol_list_to_lookup(&os->symbols);
@@ -208,7 +208,7 @@ static symbol_table_elem_t *next_symbol(struct rtos *os, char *cur_symbol, uint6
* if 'symbol' is not declared optional */
static bool is_symbol_mandatory(const struct rtos *os, const char *symbol)
{
- for (symbol_table_elem_t *s = os->symbols; s->symbol_name; ++s) {
+ for (struct symbol_table_elem *s = os->symbols; s->symbol_name; ++s) {
if (!strcmp(s->symbol_name, symbol))
return !s->optional;
}
@@ -240,7 +240,7 @@ int rtos_qsymbol(struct connection *connection, char const *packet, int packet_s
uint64_t addr = 0;
size_t reply_len;
char reply[GDB_BUFFER_SIZE + 1], cur_sym[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
- symbol_table_elem_t *next_sym = NULL;
+ struct symbol_table_elem *next_sym = NULL;
struct target *target = get_target_from_connection(connection);
struct rtos *os = target->rtos;
diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h
index 9d8ccfe..7609a9f 100644
--- a/src/rtos/rtos.h
+++ b/src/rtos/rtos.h
@@ -31,11 +31,11 @@ struct reg;
/**
* Table should be terminated by an element with NULL in symbol_name
*/
-typedef struct symbol_table_elem_struct {
+struct symbol_table_elem {
const char *symbol_name;
symbol_address_t address;
bool optional;
-} symbol_table_elem_t;
+};
struct thread_detail {
threadid_t threadid;
@@ -47,7 +47,7 @@ struct thread_detail {
struct rtos {
const struct rtos_type *type;
- symbol_table_elem_t *symbols;
+ struct symbol_table_elem *symbols;
struct target *target;
/* add a context variable instead of global variable */
/* The thread currently selected by gdb. */
@@ -81,7 +81,7 @@ struct rtos_type {
struct rtos_reg **reg_list, int *num_regs);
int (*get_thread_reg)(struct rtos *rtos, threadid_t thread_id,
uint32_t reg_num, struct rtos_reg *reg);
- int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]);
+ int (*get_symbol_list_to_lookup)(struct symbol_table_elem *symbol_list[]);
int (*clean)(struct target *target);
char * (*ps_command)(struct target *target);
int (*set_reg)(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c
index 304d07c..d62a219 100644
--- a/src/rtos/uCOS-III.c
+++ b/src/rtos/uCOS-III.c
@@ -508,9 +508,9 @@ static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
num_regs);
}
-static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+static int uCOS_III_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
- *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(symbol_table_elem_t));
+ *symbol_list = calloc(ARRAY_SIZE(uCOS_III_symbol_list), sizeof(struct symbol_table_elem));
if (*symbol_list == NULL) {
LOG_ERROR("uCOS-III: out of memory");
return ERROR_FAIL;
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index ac00dd0..d9f5d08 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -726,7 +726,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
{
struct gdb_connection *gdb_connection = connection->priv;
char sig_reply[65];
- char stop_reason[20];
+ char stop_reason[32];
char current_thread[25];
int sig_reply_len;
int signal_var;
@@ -3617,7 +3617,7 @@ static int gdb_target_start(struct target *target, const char *port)
ret = add_service("gdb",
port, target->gdb_max_connections, &gdb_new_connection, &gdb_input,
- &gdb_connection_closed, gdb_service, NULL);
+ &gdb_connection_closed, gdb_service);
/* initialize all targets gdb service with the same pointer */
{
struct target_list *head;
diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c
index 3c885cc..d49e4d0 100644
--- a/src/server/rtt_server.c
+++ b/src/server/rtt_server.c
@@ -126,7 +126,7 @@ COMMAND_HANDLER(handle_rtt_start_command)
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel);
ret = add_service("rtt", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED,
- rtt_new_connection, rtt_input, rtt_connection_closed, service, NULL);
+ rtt_new_connection, rtt_input, rtt_connection_closed, service);
if (ret != ERROR_OK) {
free(service);
diff --git a/src/server/server.c b/src/server/server.c
index 4de9889..d47b812 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -211,8 +211,7 @@ int add_service(char *name,
new_connection_handler_t new_connection_handler,
input_handler_t input_handler,
connection_closed_handler_t connection_closed_handler,
- void *priv,
- struct service **new_service)
+ void *priv)
{
struct service *c, **p;
struct hostent *hp;
@@ -348,10 +347,6 @@ int add_service(char *name,
;
*p = c;
- /* if new_service is not NULL, return the created service into it */
- if (new_service)
- *new_service = c;
-
return ERROR_OK;
}
diff --git a/src/server/server.h b/src/server/server.h
index 4ae6e95..de18d2b 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -78,7 +78,7 @@ struct service {
int add_service(char *name, const char *port,
int max_connections, new_connection_handler_t new_connection_handler,
input_handler_t in_handler, connection_closed_handler_t close_handler,
- void *priv, struct service **new_service);
+ void *priv);
int remove_service(const char *name, const char *port);
int server_host_os_entry(void);
diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c
index 07213ae..1ecb827 100644
--- a/src/server/tcl_server.c
+++ b/src/server/tcl_server.c
@@ -285,7 +285,7 @@ int tcl_init(void)
return add_service("tcl", tcl_port, CONNECTION_LIMIT_UNLIMITED,
&tcl_new_connection, &tcl_input,
- &tcl_closed, NULL, NULL);
+ &tcl_closed, NULL);
}
COMMAND_HANDLER(handle_tcl_port_command)
diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c
index 4f88d3a..e9de4f0 100644
--- a/src/server/telnet_server.c
+++ b/src/server/telnet_server.c
@@ -596,6 +596,12 @@ static int telnet_input(struct connection *connection)
telnet_history_up(connection);
} else if (*buf_p == 'B') { /* cursor down */
telnet_history_down(connection);
+ } else if (*buf_p == 'F') { /* end key */
+ telnet_move_cursor(connection, t_con->line_size);
+ t_con->state = TELNET_STATE_DATA;
+ } else if (*buf_p == 'H') { /* home key */
+ telnet_move_cursor(connection, 0);
+ t_con->state = TELNET_STATE_DATA;
} else if (*buf_p == '3')
t_con->last_escape = *buf_p;
else
@@ -694,7 +700,7 @@ int telnet_init(char *banner)
int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED,
telnet_new_connection, telnet_input, telnet_connection_closed,
- telnet_service, NULL);
+ telnet_service);
if (ret != ERROR_OK) {
free(telnet_service);
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 1d30747..34a7851 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -1,9 +1,3 @@
-if OOCD_TRACE
-OOCD_TRACE_FILES = %D%/oocd_trace.c
-else
-OOCD_TRACE_FILES =
-endif
-
%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \
%D%/riscv/libriscv.la
@@ -111,8 +105,8 @@ ARM_DEBUG_SRC = \
%D%/trace.c \
%D%/etb.c \
%D%/etm.c \
- $(OOCD_TRACE_FILES) \
%D%/etm_dummy.c \
+ %D%/arm_tpiu_swo.c \
%D%/arm_cti.c
AVR32_SRC = \
@@ -214,6 +208,7 @@ ARC_SRC = \
%D%/etb.h \
%D%/etm.h \
%D%/etm_dummy.h \
+ %D%/arm_tpiu_swo.h \
%D%/image.h \
%D%/mips32.h \
%D%/mips64.h \
@@ -223,7 +218,6 @@ ARC_SRC = \
%D%/mips32_pracc.h \
%D%/mips32_dmaacc.h \
%D%/mips64_pracc.h \
- %D%/oocd_trace.h \
%D%/register.h \
%D%/target.h \
%D%/target_type.h \
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index d111a05..d6b12cd 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -1651,7 +1651,6 @@ static int aarch64_add_hybrid_breakpoint(struct target *target,
return aarch64_set_hybrid_breakpoint(target, breakpoint); /* ??? */
}
-
static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
{
struct aarch64_common *aarch64 = target_to_aarch64(target);
@@ -1673,26 +1672,307 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b
return ERROR_OK;
}
+/* Setup hardware Watchpoint Register Pair */
+static int aarch64_set_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ int retval;
+ int wp_i = 0;
+ uint32_t control, offset, length;
+ struct aarch64_common *aarch64 = target_to_aarch64(target);
+ struct armv8_common *armv8 = &aarch64->armv8_common;
+ struct aarch64_brp *wp_list = aarch64->wp_list;
+
+ if (watchpoint->set) {
+ LOG_WARNING("watchpoint already set");
+ return ERROR_OK;
+ }
+
+ while (wp_list[wp_i].used && (wp_i < aarch64->wp_num))
+ wp_i++;
+ if (wp_i >= aarch64->wp_num) {
+ LOG_ERROR("ERROR Can not find free Watchpoint Register Pair");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ control = (1 << 0) /* enable */
+ | (3 << 1) /* both user and privileged access */
+ | (1 << 13); /* higher mode control */
+
+ switch (watchpoint->rw) {
+ case WPT_READ:
+ control |= 1 << 3;
+ break;
+ case WPT_WRITE:
+ control |= 2 << 3;
+ break;
+ case WPT_ACCESS:
+ control |= 3 << 3;
+ break;
+ }
+
+ /* Match up to 8 bytes. */
+ offset = watchpoint->address & 7;
+ length = watchpoint->length;
+ if (offset + length > sizeof(uint64_t)) {
+ length = sizeof(uint64_t) - offset;
+ LOG_WARNING("Adjust watchpoint match inside 8-byte boundary");
+ }
+ for (; length > 0; offset++, length--)
+ control |= (1 << offset) << 5;
+
+ wp_list[wp_i].value = watchpoint->address & 0xFFFFFFFFFFFFFFF8ULL;
+ wp_list[wp_i].control = control;
+
+ retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base
+ + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].BRPn,
+ (uint32_t)(wp_list[wp_i].value & 0xFFFFFFFF));
+ if (retval != ERROR_OK)
+ return retval;
+ retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base
+ + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].BRPn,
+ (uint32_t)(wp_list[wp_i].value >> 32));
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base
+ + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].BRPn,
+ control);
+ if (retval != ERROR_OK)
+ return retval;
+ LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, wp_i,
+ wp_list[wp_i].control, wp_list[wp_i].value);
+
+ /* Ensure that halting debug mode is enable */
+ retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE);
+ if (retval != ERROR_OK) {
+ LOG_DEBUG("Failed to set DSCR.HDE");
+ return retval;
+ }
+
+ wp_list[wp_i].used = 1;
+ watchpoint->set = wp_i + 1;
+
+ return ERROR_OK;
+}
+
+/* Clear hardware Watchpoint Register Pair */
+static int aarch64_unset_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ int retval, wp_i;
+ struct aarch64_common *aarch64 = target_to_aarch64(target);
+ struct armv8_common *armv8 = &aarch64->armv8_common;
+ struct aarch64_brp *wp_list = aarch64->wp_list;
+
+ if (!watchpoint->set) {
+ LOG_WARNING("watchpoint not set");
+ return ERROR_OK;
+ }
+
+ wp_i = watchpoint->set - 1;
+ if ((wp_i < 0) || (wp_i >= aarch64->wp_num)) {
+ LOG_DEBUG("Invalid WP number in watchpoint");
+ return ERROR_OK;
+ }
+ LOG_DEBUG("rwp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, wp_i,
+ wp_list[wp_i].control, wp_list[wp_i].value);
+ wp_list[wp_i].used = 0;
+ wp_list[wp_i].value = 0;
+ wp_list[wp_i].control = 0;
+ retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base
+ + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].BRPn,
+ wp_list[wp_i].control);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base
+ + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].BRPn,
+ wp_list[wp_i].value);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base
+ + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].BRPn,
+ (uint32_t)wp_list[wp_i].value);
+ if (retval != ERROR_OK)
+ return retval;
+ watchpoint->set = 0;
+
+ return ERROR_OK;
+}
+
+static int aarch64_add_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ int retval;
+ struct aarch64_common *aarch64 = target_to_aarch64(target);
+
+ if (aarch64->wp_num_available < 1) {
+ LOG_INFO("no hardware watchpoint available");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ retval = aarch64_set_watchpoint(target, watchpoint);
+ if (retval == ERROR_OK)
+ aarch64->wp_num_available--;
+
+ return retval;
+}
+
+static int aarch64_remove_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ struct aarch64_common *aarch64 = target_to_aarch64(target);
+
+ if (watchpoint->set) {
+ aarch64_unset_watchpoint(target, watchpoint);
+ aarch64->wp_num_available++;
+ }
+
+ return ERROR_OK;
+}
+
+/**
+ * find out which watchpoint hits
+ * get exception address and compare the address to watchpoints
+ */
+int aarch64_hit_watchpoint(struct target *target,
+ struct watchpoint **hit_watchpoint)
+{
+ if (target->debug_reason != DBG_REASON_WATCHPOINT)
+ return ERROR_FAIL;
+
+ struct armv8_common *armv8 = target_to_armv8(target);
+
+ uint64_t exception_address;
+ struct watchpoint *wp;
+
+ exception_address = armv8->dpm.wp_pc;
+
+ if (exception_address == 0xFFFFFFFF)
+ return ERROR_FAIL;
+
+ /**********************************************************/
+ /* see if a watchpoint address matches a value read from */
+ /* the EDWAR register. Testing shows that on some ARM CPUs*/
+ /* the EDWAR value needs to have 8 added to it so we add */
+ /* that check as well not sure if that is a core bug) */
+ /**********************************************************/
+ for (exception_address = armv8->dpm.wp_pc; exception_address <= (armv8->dpm.wp_pc + 8);
+ exception_address += 8) {
+ for (wp = target->watchpoints; wp; wp = wp->next) {
+ if ((exception_address >= wp->address) && (exception_address < (wp->address + wp->length))) {
+ *hit_watchpoint = wp;
+ if (exception_address != armv8->dpm.wp_pc)
+ LOG_DEBUG("watchpoint hit required EDWAR to be increased by 8");
+ return ERROR_OK;
+ }
+ }
+ }
+
+ return ERROR_FAIL;
+}
+
/*
* Cortex-A8 Reset functions
*/
+static int aarch64_enable_reset_catch(struct target *target, bool enable)
+{
+ struct armv8_common *armv8 = target_to_armv8(target);
+ uint32_t edecr;
+ int retval;
+
+ retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+ armv8->debug_base + CPUV8_DBG_EDECR, &edecr);
+ LOG_DEBUG("EDECR = 0x%08" PRIx32 ", enable=%d", edecr, enable);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (enable)
+ edecr |= ECR_RCE;
+ else
+ edecr &= ~ECR_RCE;
+
+ return mem_ap_write_atomic_u32(armv8->debug_ap,
+ armv8->debug_base + CPUV8_DBG_EDECR, edecr);
+}
+
+static int aarch64_clear_reset_catch(struct target *target)
+{
+ struct armv8_common *armv8 = target_to_armv8(target);
+ uint32_t edesr;
+ int retval;
+ bool was_triggered;
+
+ /* check if Reset Catch debug event triggered as expected */
+ retval = mem_ap_read_atomic_u32(armv8->debug_ap,
+ armv8->debug_base + CPUV8_DBG_EDESR, &edesr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ was_triggered = !!(edesr & ESR_RC);
+ LOG_DEBUG("Reset Catch debug event %s",
+ was_triggered ? "triggered" : "NOT triggered!");
+
+ if (was_triggered) {
+ /* clear pending Reset Catch debug event */
+ edesr &= ~ESR_RC;
+ retval = mem_ap_write_atomic_u32(armv8->debug_ap,
+ armv8->debug_base + CPUV8_DBG_EDESR, edesr);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
static int aarch64_assert_reset(struct target *target)
{
struct armv8_common *armv8 = target_to_armv8(target);
+ enum reset_types reset_config = jtag_get_reset_config();
+ int retval;
LOG_DEBUG(" ");
- /* FIXME when halt is requested, make it work somehow... */
-
/* Issue some kind of warm reset. */
if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT))
target_handle_event(target, TARGET_EVENT_RESET_ASSERT);
- else if (jtag_get_reset_config() & RESET_HAS_SRST) {
+ else if (reset_config & RESET_HAS_SRST) {
+ bool srst_asserted = false;
+
+ if (target->reset_halt) {
+ if (target_was_examined(target)) {
+
+ if (reset_config & RESET_SRST_NO_GATING) {
+ /*
+ * SRST needs to be asserted *before* Reset Catch
+ * debug event can be set up.
+ */
+ adapter_assert_reset();
+ srst_asserted = true;
+
+ /* make sure to clear all sticky errors */
+ mem_ap_write_atomic_u32(armv8->debug_ap,
+ armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE);
+ }
+
+ /* set up Reset Catch debug event to halt the CPU after reset */
+ retval = aarch64_enable_reset_catch(target, true);
+ if (retval != ERROR_OK)
+ LOG_WARNING("%s: Error enabling Reset Catch debug event; the CPU will not halt immediately after reset!",
+ target_name(target));
+ } else {
+ LOG_WARNING("%s: Target not examined, will not halt immediately after reset!",
+ target_name(target));
+ }
+ }
+
/* REVISIT handle "pulls" cases, if there's
* hardware that needs them to work.
*/
- adapter_assert_reset();
+ if (!srst_asserted)
+ adapter_assert_reset();
} else {
LOG_ERROR("%s: how to reset?", target_name(target));
return ERROR_FAIL;
@@ -1721,23 +2001,37 @@ static int aarch64_deassert_reset(struct target *target)
if (!target_was_examined(target))
return ERROR_OK;
- retval = aarch64_poll(target);
+ retval = aarch64_init_debug_access(target);
if (retval != ERROR_OK)
return retval;
- retval = aarch64_init_debug_access(target);
+ retval = aarch64_poll(target);
if (retval != ERROR_OK)
return retval;
if (target->reset_halt) {
+ /* clear pending Reset Catch debug event */
+ retval = aarch64_clear_reset_catch(target);
+ if (retval != ERROR_OK)
+ LOG_WARNING("%s: Clearing Reset Catch debug event failed",
+ target_name(target));
+
+ /* disable Reset Catch debug event */
+ retval = aarch64_enable_reset_catch(target, false);
+ if (retval != ERROR_OK)
+ LOG_WARNING("%s: Disabling Reset Catch debug event failed",
+ target_name(target));
+
if (target->state != TARGET_HALTED) {
LOG_WARNING("%s: ran after reset and before halt ...",
target_name(target));
retval = target_halt(target);
+ if (retval != ERROR_OK)
+ return retval;
}
}
- return retval;
+ return ERROR_OK;
}
static int aarch64_write_cpu_memory_slow(struct target *target,
@@ -2367,7 +2661,20 @@ static int aarch64_examine_first(struct target *target)
aarch64->brp_list[i].BRPn = i;
}
- LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num);
+ /* Setup Watchpoint Register Pairs */
+ aarch64->wp_num = (uint32_t)((debug >> 20) & 0x0F) + 1;
+ aarch64->wp_num_available = aarch64->wp_num;
+ aarch64->wp_list = calloc(aarch64->wp_num, sizeof(struct aarch64_brp));
+ for (i = 0; i < aarch64->wp_num; i++) {
+ aarch64->wp_list[i].used = 0;
+ aarch64->wp_list[i].type = BRP_NORMAL;
+ aarch64->wp_list[i].value = 0;
+ aarch64->wp_list[i].control = 0;
+ aarch64->wp_list[i].BRPn = i;
+ }
+
+ LOG_DEBUG("Configured %i hw breakpoints, %i watchpoints",
+ aarch64->brp_num, aarch64->wp_num);
target->state = TARGET_UNKNOWN;
target->debug_reason = DBG_REASON_NOTHALTED;
@@ -2883,8 +3190,9 @@ struct target_type aarch64_target = {
.add_context_breakpoint = aarch64_add_context_breakpoint,
.add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint,
.remove_breakpoint = aarch64_remove_breakpoint,
- .add_watchpoint = NULL,
- .remove_watchpoint = NULL,
+ .add_watchpoint = aarch64_add_watchpoint,
+ .remove_watchpoint = aarch64_remove_watchpoint,
+ .hit_watchpoint = aarch64_hit_watchpoint,
.commands = aarch64_command_handlers,
.target_create = aarch64_target_create,
diff --git a/src/target/aarch64.h b/src/target/aarch64.h
index d7886a3..7c0ddf8 100644
--- a/src/target/aarch64.h
+++ b/src/target/aarch64.h
@@ -62,6 +62,11 @@ struct aarch64_common {
int brp_num_available;
struct aarch64_brp *brp_list;
+ /* Watchpoint register pairs */
+ int wp_num;
+ int wp_num_available;
+ struct aarch64_brp *wp_list;
+
struct armv8_common armv8_common;
enum aarch64_isrmasking_mode isrmasking_mode;
diff --git a/src/target/arc.c b/src/target/arc.c
index 8e56845..694ac6f 100644
--- a/src/target/arc.c
+++ b/src/target/arc.c
@@ -227,7 +227,7 @@ static int arc_get_register(struct reg *reg)
if (desc->is_core) {
/* Accessing to R61/R62 registers causes Jtag hang */
- if (desc->arch_num == CORE_R61_NUM || desc->arch_num == CORE_R62_NUM) {
+ if (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62) {
LOG_ERROR("It is forbidden to read core registers 61 and 62.");
return ERROR_FAIL;
}
@@ -267,8 +267,8 @@ static int arc_set_register(struct reg *reg, uint8_t *buf)
return ERROR_TARGET_NOT_HALTED;
/* Accessing to R61/R62 registers causes Jtag hang */
- if (desc->is_core && (desc->arch_num == CORE_R61_NUM ||
- desc->arch_num == CORE_R62_NUM)) {
+ if (desc->is_core && (desc->arch_num == ARC_R61 ||
+ desc->arch_num == ARC_R62)) {
LOG_ERROR("It is forbidden to write core registers 61 and 62.");
return ERROR_FAIL;
}
diff --git a/src/target/arc.h b/src/target/arc.h
index aeb326c..8d44bfa 100644
--- a/src/target/arc.h
+++ b/src/target/arc.h
@@ -45,9 +45,52 @@
#define AUX_STATUS32_REG_HALT_BIT BIT(0)
#define AUX_STATUS32_REG_IE_BIT BIT(31) /* STATUS32[31] = IE field */
-/* Reserved core registers */
-#define CORE_R61_NUM (61)
-#define CORE_R62_NUM (62)
+/* ARC register numbers */
+enum {
+ ARC_R0,
+ ARC_R1,
+ ARC_R2,
+ ARC_R3,
+ ARC_R4,
+ ARC_R5,
+ ARC_R6,
+ ARC_R7,
+ ARC_R8,
+ ARC_R9,
+ ARC_R10,
+ ARC_R11,
+ ARC_R12,
+ ARC_R13,
+ ARC_R14,
+ ARC_R15,
+ ARC_R16,
+ ARC_R17,
+ ARC_R18,
+ ARC_R19,
+ ARC_R20,
+ ARC_R21,
+ ARC_R22,
+ ARC_R23,
+ ARC_R24,
+ ARC_R25,
+ ARC_GP = 26,
+ ARC_FP = 27,
+ ARC_SP = 28,
+ ARC_ILINK = 29,
+ ARC_R30,
+ ARC_BLINK = 31,
+ ARC_LP_COUNT = 60,
+
+ /* Reserved registers */
+ ARC_R61 = 61,
+ ARC_R62 = 62,
+
+ ARC_PCL = 63,
+ ARC_PC = 64,
+ ARC_LP_START = 65,
+ ARC_LP_END = 66,
+ ARC_STATUS32 = 67,
+};
#define CORE_REG_MAX_NUMBER (63)
diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c
index 18f5cb8..5c5247b 100644
--- a/src/target/arc_cmd.c
+++ b/src/target/arc_cmd.c
@@ -382,7 +382,7 @@ static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *a
/* Register number */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
- if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
+ if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) {
Jim_SetResultFormatted(goi.interp, "Core register number %i "
"is invalid. Must less then 64 and not 61 and 62.", regnum);
return JIM_ERR;
@@ -425,7 +425,7 @@ static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *a
/* Register number */
JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
- if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
+ if (regnum > CORE_REG_MAX_NUMBER || regnum == ARC_R61 || regnum == ARC_R62) {
Jim_SetResultFormatted(goi.interp, "Core register number %i "
"is invalid. Must less then 64 and not 61 and 62.", regnum);
return JIM_ERR;
diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c
index 60be009..823ce5c 100644
--- a/src/target/arm11_dbgtap.c
+++ b/src/target/arm11_dbgtap.c
@@ -562,11 +562,7 @@ static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = {
TAP_DRSHIFT
};
-/* This inner loop can be implemented by the minidriver, oftentimes in hardware... The
- * minidriver can call the default implementation as a fallback or implement it
- * from scratch.
- */
-int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap,
+static int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap,
uint32_t opcode,
uint32_t *data,
size_t count)
@@ -629,21 +625,6 @@ int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap,
return retval;
}
-int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap,
- uint32_t opcode,
- uint32_t *data,
- size_t count);
-
-#ifndef HAVE_JTAG_MINIDRIVER_H
-int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap,
- uint32_t opcode,
- uint32_t *data,
- size_t count)
-{
- return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count);
-}
-#endif
-
/** Execute one instruction via ITR repeatedly while
* passing data to the core via DTR on each execution.
*
diff --git a/src/target/arm720t.c b/src/target/arm720t.c
index e04cab2..daa44e4 100644
--- a/src/target/arm720t.c
+++ b/src/target/arm720t.c
@@ -233,16 +233,6 @@ static void arm720t_pre_restore_context(struct target *target)
arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg);
}
-static int arm720t_verify_pointer(struct command_invocation *cmd,
- struct arm720t_common *arm720t)
-{
- if (arm720t->common_magic != ARM720T_COMMON_MAGIC) {
- command_print(cmd, "target is not an ARM720");
- return ERROR_TARGET_INVALID;
- }
- return ERROR_OK;
-}
-
static int arm720t_arch_state(struct target *target)
{
struct arm720t_common *arm720t = target_to_arm720(target);
@@ -441,55 +431,6 @@ static int arm720t_target_create(struct target *target, Jim_Interp *interp)
return arm720t_init_arch_info(target, arm720t, target->tap);
}
-COMMAND_HANDLER(arm720t_handle_cp15_command)
-{
- int retval;
- struct target *target = get_current_target(CMD_CTX);
- struct arm720t_common *arm720t = target_to_arm720(target);
-
- retval = arm720t_verify_pointer(CMD, arm720t);
- if (retval != ERROR_OK)
- return retval;
-
- if (target->state != TARGET_HALTED) {
- command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME);
- return ERROR_OK;
- }
-
- /* one or more argument, access a single register (write if second argument is given */
- if (CMD_ARGC >= 1) {
- uint32_t opcode;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode);
-
- if (CMD_ARGC == 1) {
- uint32_t value;
- retval = arm720t_read_cp15(target, opcode, &value);
- if (retval != ERROR_OK) {
- command_print(CMD, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode);
- return ERROR_OK;
- }
-
- retval = jtag_execute_queue();
- if (retval != ERROR_OK)
- return retval;
-
- command_print(CMD, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value);
- } else if (CMD_ARGC == 2) {
- uint32_t value;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
-
- retval = arm720t_write_cp15(target, opcode, value);
- if (retval != ERROR_OK) {
- command_print(CMD, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode);
- return ERROR_OK;
- }
- command_print(CMD, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value);
- }
- }
-
- return ERROR_OK;
-}
-
static int arm720t_mrc(struct target *target, int cpnum,
uint32_t op1, uint32_t op2,
uint32_t CRn, uint32_t CRm,
@@ -523,30 +464,10 @@ static int arm720t_mcr(struct target *target, int cpnum,
value);
}
-static const struct command_registration arm720t_exec_command_handlers[] = {
- {
- .name = "cp15",
- .handler = arm720t_handle_cp15_command,
- .mode = COMMAND_EXEC,
- /* prefer using less error-prone "arm mcr" or "arm mrc" */
- .help = "display/modify cp15 register using ARM opcode"
- " (DEPRECATED)",
- .usage = "instruction [value]",
- },
- COMMAND_REGISTRATION_DONE
-};
-
static const struct command_registration arm720t_command_handlers[] = {
{
.chain = arm7_9_command_handlers,
},
- {
- .name = "arm720t",
- .mode = COMMAND_ANY,
- .help = "arm720t command group",
- .usage = "",
- .chain = arm720t_exec_command_handlers,
- },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/target/arm920t.c b/src/target/arm920t.c
index c96975a..a45dc64 100644
--- a/src/target/arm920t.c
+++ b/src/target/arm920t.c
@@ -245,8 +245,8 @@ static int arm920t_read_cp15_interpreted(struct target *target,
uint32_t cp15_opcode, uint32_t address, uint32_t *value)
{
struct arm *arm = target_to_arm(target);
- uint32_t *regs_p[1];
- uint32_t regs[2];
+ uint32_t *regs_p[16];
+ uint32_t regs[16];
uint32_t cp15c15 = 0x0;
struct reg *r = arm->core_cache->reg_list;
@@ -295,7 +295,7 @@ int arm920t_write_cp15_interpreted(struct target *target,
{
uint32_t cp15c15 = 0x0;
struct arm *arm = target_to_arm(target);
- uint32_t regs[2];
+ uint32_t regs[16];
struct reg *r = arm->core_cache->reg_list;
/* load value, address into R0, R1 */
@@ -1511,80 +1511,6 @@ COMMAND_HANDLER(arm920t_handle_cp15_command)
return ERROR_OK;
}
-COMMAND_HANDLER(arm920t_handle_cp15i_command)
-{
- int retval;
- struct target *target = get_current_target(CMD_CTX);
- struct arm920t_common *arm920t = target_to_arm920(target);
-
- retval = arm920t_verify_pointer(CMD, arm920t);
- if (retval != ERROR_OK)
- return retval;
-
-
- if (target->state != TARGET_HALTED) {
- command_print(CMD, "target must be stopped for "
- "\"%s\" command", CMD_NAME);
- return ERROR_OK;
- }
-
- /* one argument, read a register.
- * two arguments, write it.
- */
- if (CMD_ARGC >= 1) {
- uint32_t opcode;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode);
-
- if (CMD_ARGC == 1) {
- uint32_t value;
- retval = arm920t_read_cp15_interpreted(target,
- opcode, 0x0, &value);
- if (retval != ERROR_OK) {
- command_print(CMD,
- "couldn't execute %8.8" PRIx32,
- opcode);
- /* REVISIT why lie? "return retval"? */
- return ERROR_OK;
- }
-
- command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32,
- opcode, value);
- } else if (CMD_ARGC == 2) {
- uint32_t value;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
- retval = arm920t_write_cp15_interpreted(target,
- opcode, value, 0);
- if (retval != ERROR_OK) {
- command_print(CMD,
- "couldn't execute %8.8" PRIx32,
- opcode);
- /* REVISIT why lie? "return retval"? */
- return ERROR_OK;
- }
- command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32,
- opcode, value);
- } else if (CMD_ARGC == 3) {
- uint32_t value;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
- uint32_t address;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
- retval = arm920t_write_cp15_interpreted(target,
- opcode, value, address);
- if (retval != ERROR_OK) {
- command_print(CMD,
- "couldn't execute %8.8" PRIx32, opcode);
- /* REVISIT why lie? "return retval"? */
- return ERROR_OK;
- }
- command_print(CMD, "%8.8" PRIx32 ": %8.8" PRIx32
- " %8.8" PRIx32, opcode, value, address);
- }
- } else
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- return ERROR_OK;
-}
-
COMMAND_HANDLER(arm920t_handle_cache_info_command)
{
int retval;
@@ -1641,15 +1567,6 @@ static const struct command_registration arm920t_exec_command_handlers[] = {
.usage = "regnum [value]",
},
{
- .name = "cp15i",
- .handler = arm920t_handle_cp15i_command,
- .mode = COMMAND_EXEC,
- /* prefer using less error-prone "arm mcr" or "arm mrc" */
- .help = "display/modify cp15 register using ARM opcode"
- " (DEPRECATED)",
- .usage = "instruction [value [address]]",
- },
- {
.name = "cache_info",
.handler = arm920t_handle_cache_info_command,
.mode = COMMAND_EXEC,
diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c
index 723be57..9de7048 100644
--- a/src/target/arm_semihosting.c
+++ b/src/target/arm_semihosting.c
@@ -123,6 +123,22 @@ static int post_result(struct target *target)
uint64_t pc = buf_get_u64(arm->core_cache->reg_list[32].value, 0, 64);
buf_set_u64(arm->pc->value, 0, 64, pc + 4);
arm->pc->dirty = true;
+ } else if (arm->core_state == ARM_STATE_ARM) {
+ /* return value in R0 */
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result);
+ arm->core_cache->reg_list[0].dirty = true;
+
+ uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32);
+ buf_set_u32(arm->pc->value, 0, 32, pc + 4);
+ arm->pc->dirty = true;
+ } else if (arm->core_state == ARM_STATE_THUMB) {
+ /* return value in R0 */
+ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result);
+ arm->core_cache->reg_list[0].dirty = true;
+
+ uint32_t pc = buf_get_u32(arm->core_cache->reg_list[32].value, 0, 32);
+ buf_set_u32(arm->pc->value, 0, 32, pc + 2);
+ arm->pc->dirty = true;
}
} else {
/* resume execution, this will be pc+2 to skip over the
@@ -275,6 +291,16 @@ int arm_semihosting(struct target *target, int *retval)
if (target->debug_reason != DBG_REASON_BREAKPOINT)
return 0;
+ /* According to ARM Semihosting for AArch32 and AArch64:
+ * The HLT encodings are new in version 2.0 of the semihosting specification.
+ * Where possible, have semihosting callers continue to use the previously
+ * existing trap instructions to ensure compatibility with legacy semihosting
+ * implementations.
+ * These trap instructions are HLT for A64, SVC on A+R profile A32 or T32,
+ * and BKPT on M profile.
+ * However, it is necessary to change from SVC to HLT instructions to support
+ * AArch32 semihosting properly in a mixed AArch32/AArch64 system. */
+
if (arm->core_state == ARM_STATE_AARCH64) {
uint32_t insn = 0;
r = arm->pc;
@@ -284,9 +310,38 @@ int arm_semihosting(struct target *target, int *retval)
if (*retval != ERROR_OK)
return 1;
- /* bkpt 0xAB */
+ /* HLT 0xF000 */
if (insn != 0xD45E0000)
return 0;
+ } else if (arm->core_state == ARM_STATE_ARM) {
+ r = arm->pc;
+ pc = buf_get_u32(arm->pc->value, 0, 32);
+
+ /* A32 instruction => check for HLT 0xF000 (0xE10F0070) */
+ uint32_t insn = 0;
+
+ *retval = target_read_u32(target, pc, &insn);
+
+ if (*retval != ERROR_OK)
+ return 1;
+
+ /* HLT 0xF000*/
+ if (insn != 0xE10F0070)
+ return 0;
+ } else if (arm->core_state == ARM_STATE_THUMB) {
+ r = arm->pc;
+ pc = buf_get_u32(arm->pc->value, 0, 32);
+
+ /* T32 instruction => check for HLT 0x3C (0xBABC) */
+ uint16_t insn = 0;
+ *retval = target_read_u16(target, pc, &insn);
+
+ if (*retval != ERROR_OK)
+ return 1;
+
+ /* HLT 0x3C*/
+ if (insn != 0xBABC)
+ return 0;
} else
return 1;
} else {
diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c
new file mode 100644
index 0000000..2da52e8
--- /dev/null
+++ b/src/target/arm_tpiu_swo.c
@@ -0,0 +1,1189 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/**
+ * @file
+ * This file implements support for the ARM CoreSight components Trace Port
+ * Interface Unit (TPIU) and Serial Wire Output (SWO). It also supports the
+ * CoreSight TPIU-Lite and the special TPIU version present with Cortex-M3
+ * and Cortex-M4 (that includes SWO).
+ */
+
+/*
+ * Relevant specifications from ARM include:
+ *
+ * CoreSight(tm) Components Technical Reference Manual ARM DDI 0314H
+ * CoreSight(tm) TPIU-Lite Technical Reference Manual ARM DDI 0317A
+ * Cortex(tm)-M3 Technical Reference Manual ARM DDI 0337G
+ * Cortex(tm)-M4 Technical Reference Manual ARM DDI 0439B
+ * CoreSight(tm) SoC-400 Technical Reference Manual ARM DDI 0480F
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <jim.h>
+
+#include <helper/bits.h>
+#include <helper/command.h>
+#include <helper/jim-nvp.h>
+#include <helper/list.h>
+#include <helper/log.h>
+#include <helper/types.h>
+#include <jtag/interface.h>
+#include <server/server.h>
+#include <target/arm_adi_v5.h>
+#include <target/target.h>
+#include <transport/transport.h>
+#include "arm_tpiu_swo.h"
+
+/* START_DEPRECATED_TPIU */
+#include <target/cortex_m.h>
+#include <target/target_type.h>
+#define MSG "DEPRECATED \'tpiu config\' command: "
+/* END_DEPRECATED_TPIU */
+
+#define TCP_SERVICE_NAME "tpiu_swo_trace"
+
+/* default for Cortex-M3 and Cortex-M4 specific TPIU */
+#define TPIU_SWO_DEFAULT_BASE 0xE0040000
+
+#define TPIU_SSPSR_OFFSET 0x000
+#define TPIU_CSPSR_OFFSET 0x004
+#define TPIU_ACPR_OFFSET 0x010
+#define TPIU_SPPR_OFFSET 0x0F0
+#define TPIU_FFSR_OFFSET 0x300
+#define TPIU_FFCR_OFFSET 0x304
+#define TPIU_FSCR_OFFSET 0x308
+#define TPIU_DEVID_OFFSET 0xfc8
+
+#define TPIU_ACPR_MAX_PRESCALER 0x1fff
+#define TPIU_SPPR_PROTOCOL_SYNC (TPIU_PIN_PROTOCOL_SYNC)
+#define TPIU_SPPR_PROTOCOL_MANCHESTER (TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER)
+#define TPIU_SPPR_PROTOCOL_UART (TPIU_PIN_PROTOCOL_ASYNC_UART)
+#define TPIU_DEVID_NOSUPPORT_SYNC BIT(9)
+#define TPIU_DEVID_SUPPORT_MANCHESTER BIT(10)
+#define TPIU_DEVID_SUPPORT_UART BIT(11)
+
+enum arm_tpiu_swo_event {
+ TPIU_SWO_EVENT_PRE_ENABLE,
+ TPIU_SWO_EVENT_POST_ENABLE,
+ TPIU_SWO_EVENT_PRE_DISABLE,
+ TPIU_SWO_EVENT_POST_DISABLE,
+};
+
+static const Jim_Nvp nvp_arm_tpiu_swo_event[] = {
+ { .value = TPIU_SWO_EVENT_PRE_ENABLE, .name = "pre-enable" },
+ { .value = TPIU_SWO_EVENT_POST_ENABLE, .name = "post-enable" },
+ { .value = TPIU_SWO_EVENT_PRE_DISABLE, .name = "pre-disable" },
+ { .value = TPIU_SWO_EVENT_POST_DISABLE, .name = "post-disable" },
+};
+
+struct arm_tpiu_swo_event_action {
+ enum arm_tpiu_swo_event event;
+ Jim_Interp *interp;
+ Jim_Obj *body;
+ struct arm_tpiu_swo_event_action *next;
+};
+
+struct arm_tpiu_swo_object {
+ struct list_head lh;
+ struct adiv5_mem_ap_spot spot;
+ char *name;
+ struct arm_tpiu_swo_event_action *event_action;
+ /* record enable before init */
+ bool deferred_enable;
+ bool enabled;
+ bool en_capture;
+ /** Handle to output trace data in INTERNAL capture mode */
+ /** Synchronous output port width */
+ uint32_t port_width;
+ FILE *file;
+ /** output mode */
+ unsigned int pin_protocol;
+ /** Enable formatter */
+ bool en_formatter;
+ /** frequency of TRACECLKIN (usually matches HCLK) */
+ unsigned int traceclkin_freq;
+ /** SWO pin frequency */
+ unsigned int swo_pin_freq;
+ /** where to dump the captured output trace data */
+ char *out_filename;
+ /** track TCP connections */
+ struct list_head connections;
+ /* START_DEPRECATED_TPIU */
+ bool recheck_ap_cur_target;
+ /* END_DEPRECATED_TPIU */
+};
+
+struct arm_tpiu_swo_connection {
+ struct list_head lh;
+ struct connection *connection;
+};
+
+struct arm_tpiu_swo_priv_connection {
+ struct arm_tpiu_swo_object *obj;
+};
+
+static LIST_HEAD(all_tpiu_swo);
+
+#define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096
+
+static int arm_tpiu_swo_poll_trace(void *priv)
+{
+ struct arm_tpiu_swo_object *obj = priv;
+ uint8_t buf[ARM_TPIU_SWO_TRACE_BUF_SIZE];
+ size_t size = sizeof(buf);
+ struct arm_tpiu_swo_connection *c;
+
+ int retval = adapter_poll_trace(buf, &size);
+ if (retval != ERROR_OK || !size)
+ return retval;
+
+ target_call_trace_callbacks(/*target*/NULL, size, buf);
+
+ if (obj->file) {
+ if (fwrite(buf, 1, size, obj->file) == size) {
+ fflush(obj->file);
+ } else {
+ LOG_ERROR("Error writing to the SWO trace destination file");
+ return ERROR_FAIL;
+ }
+ }
+
+ if (obj->out_filename && obj->out_filename[0] == ':')
+ list_for_each_entry(c, &obj->connections, lh)
+ if (connection_write(c->connection, buf, size) != (int)size)
+ retval = ERROR_FAIL;
+
+ return ERROR_OK;
+}
+
+static void arm_tpiu_swo_handle_event(struct arm_tpiu_swo_object *obj, enum arm_tpiu_swo_event event)
+{
+ for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) {
+ if (ea->event != event)
+ continue;
+
+ LOG_DEBUG("TPIU/SWO: %s event: %s (%d) action : %s",
+ obj->name,
+ Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name,
+ event,
+ Jim_GetString(ea->body, NULL));
+
+ /* prevent event execution to change current target */
+ struct command_context *cmd_ctx = current_command_context(ea->interp);
+ struct target *saved_target = cmd_ctx->current_target;
+ int retval = Jim_EvalObj(ea->interp, ea->body);
+ cmd_ctx->current_target = saved_target;
+
+ if (retval == JIM_RETURN)
+ retval = ea->interp->returnCode;
+ if (retval == JIM_OK || retval == ERROR_COMMAND_CLOSE_CONNECTION)
+ return;
+
+ Jim_MakeErrorMessage(ea->interp);
+ LOG_USER("Error executing event %s on TPIU/SWO %s:\n%s",
+ Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, event)->name,
+ obj->name,
+ Jim_GetString(Jim_GetResult(ea->interp), NULL));
+ /* clean both error code and stacktrace before return */
+ Jim_Eval(ea->interp, "error \"\" \"\"");
+ return;
+ }
+}
+
+static void arm_tpiu_swo_close_output(struct arm_tpiu_swo_object *obj)
+{
+ if (obj->file) {
+ fclose(obj->file);
+ obj->file = NULL;
+ }
+ if (obj->out_filename && obj->out_filename[0] == ':')
+ remove_service(TCP_SERVICE_NAME, &obj->out_filename[1]);
+}
+
+int arm_tpiu_swo_cleanup_all(void)
+{
+ struct arm_tpiu_swo_object *obj, *tmp;
+
+ list_for_each_entry_safe(obj, tmp, &all_tpiu_swo, lh) {
+ if (obj->enabled)
+ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
+
+ arm_tpiu_swo_close_output(obj);
+
+ if (obj->en_capture) {
+ target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
+
+ int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
+ if (retval != ERROR_OK)
+ LOG_ERROR("Failed to stop adapter's trace");
+ }
+
+ if (obj->enabled)
+ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
+
+ struct arm_tpiu_swo_event_action *ea = obj->event_action;
+ while (ea) {
+ struct arm_tpiu_swo_event_action *next = ea->next;
+ Jim_DecrRefCount(ea->interp, ea->body);
+ free(ea);
+ ea = next;
+ }
+
+ free(obj->name);
+ free(obj->out_filename);
+ free(obj);
+ }
+
+ return ERROR_OK;
+}
+
+static int arm_tpiu_swo_service_new_connection(struct connection *connection)
+{
+ struct arm_tpiu_swo_priv_connection *priv = connection->service->priv;
+ struct arm_tpiu_swo_object *obj = priv->obj;
+ struct arm_tpiu_swo_connection *c = malloc(sizeof(*c));
+ if (!c) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ c->connection = connection;
+ list_add(&c->lh, &obj->connections);
+ return ERROR_OK;
+}
+
+static int arm_tpiu_swo_service_input(struct connection *connection)
+{
+ /* read a dummy buffer to check if the connection is still active */
+ long dummy;
+ int bytes_read = connection_read(connection, &dummy, sizeof(dummy));
+
+ if (bytes_read == 0) {
+ return ERROR_SERVER_REMOTE_CLOSED;
+ } else if (bytes_read == -1) {
+ LOG_ERROR("error during read: %s", strerror(errno));
+ return ERROR_SERVER_REMOTE_CLOSED;
+ }
+
+ return ERROR_OK;
+}
+
+static int arm_tpiu_swo_service_connection_closed(struct connection *connection)
+{
+ struct arm_tpiu_swo_priv_connection *priv = connection->service->priv;
+ struct arm_tpiu_swo_object *obj = priv->obj;
+ struct arm_tpiu_swo_connection *c, *tmp;
+
+ list_for_each_entry_safe(c, tmp, &obj->connections, lh)
+ if (c->connection == connection) {
+ list_del(&c->lh);
+ free(c);
+ return ERROR_OK;
+ }
+ LOG_ERROR("Failed to find connection to close!");
+ return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(handle_arm_tpiu_swo_event_list)
+{
+ struct arm_tpiu_swo_object *obj = CMD_DATA;
+
+ command_print(CMD, "Event actions for TPIU/SWO %s\n", obj->name);
+ command_print(CMD, "%-25s | Body", "Event");
+ command_print(CMD, "------------------------- | "
+ "----------------------------------------");
+
+ for (struct arm_tpiu_swo_event_action *ea = obj->event_action; ea; ea = ea->next) {
+ Jim_Nvp *opt = Jim_Nvp_value2name_simple(nvp_arm_tpiu_swo_event, ea->event);
+ command_print(CMD, "%-25s | %s",
+ opt->name, Jim_GetString(ea->body, NULL));
+ }
+ command_print(CMD, "***END***");
+ return ERROR_OK;
+}
+
+enum arm_tpiu_swo_cfg_param {
+ CFG_PORT_WIDTH,
+ CFG_PROTOCOL,
+ CFG_FORMATTER,
+ CFG_TRACECLKIN,
+ CFG_BITRATE,
+ CFG_OUTFILE,
+ CFG_EVENT,
+};
+
+static const Jim_Nvp nvp_arm_tpiu_swo_config_opts[] = {
+ { .name = "-port-width", .value = CFG_PORT_WIDTH },
+ { .name = "-protocol", .value = CFG_PROTOCOL },
+ { .name = "-formatter", .value = CFG_FORMATTER },
+ { .name = "-traceclk", .value = CFG_TRACECLKIN },
+ { .name = "-pin-freq", .value = CFG_BITRATE },
+ { .name = "-output", .value = CFG_OUTFILE },
+ { .name = "-event", .value = CFG_EVENT },
+ /* handled by mem_ap_spot, added for Jim_GetOpt_NvpUnknown() */
+ { .name = "-dap", .value = -1 },
+ { .name = "-ap-num", .value = -1 },
+ { .name = "-baseaddr", .value = -1 },
+ { .name = NULL, .value = -1 },
+};
+
+static const Jim_Nvp nvp_arm_tpiu_swo_protocol_opts[] = {
+ { .name = "sync", .value = TPIU_SPPR_PROTOCOL_SYNC },
+ { .name = "uart", .value = TPIU_SPPR_PROTOCOL_UART },
+ { .name = "manchester", .value = TPIU_SPPR_PROTOCOL_MANCHESTER },
+ { .name = NULL, .value = -1 },
+};
+
+static const Jim_Nvp nvp_arm_tpiu_swo_bool_opts[] = {
+ { .name = "on", .value = 1 },
+ { .name = "yes", .value = 1 },
+ { .name = "1", .value = 1 },
+ { .name = "true", .value = 1 },
+ { .name = "off", .value = 0 },
+ { .name = "no", .value = 0 },
+ { .name = "0", .value = 0 },
+ { .name = "false", .value = 0 },
+ { .name = NULL, .value = -1 },
+};
+
+static int arm_tpiu_swo_configure(Jim_GetOptInfo *goi, struct arm_tpiu_swo_object *obj)
+{
+ assert(obj != NULL);
+
+ if (goi->isconfigure && obj->enabled) {
+ Jim_SetResultFormatted(goi->interp, "Cannot configure TPIU/SWO; %s is enabled!", obj->name);
+ return JIM_ERR;
+ }
+
+ /* parse config or cget options ... */
+ while (goi->argc > 0) {
+ Jim_SetEmptyResult(goi->interp);
+
+ int e = adiv5_jim_mem_ap_spot_configure(&obj->spot, goi);
+ if (e == JIM_OK)
+ continue;
+ if (e == JIM_ERR)
+ return e;
+
+ Jim_Nvp *n;
+ e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_config_opts, &n);
+ if (e != JIM_OK) {
+ Jim_GetOpt_NvpUnknown(goi, nvp_arm_tpiu_swo_config_opts, 0);
+ return e;
+ }
+
+ switch (n->value) {
+ case CFG_PORT_WIDTH:
+ if (goi->isconfigure) {
+ jim_wide port_width;
+ e = Jim_GetOpt_Wide(goi, &port_width);
+ if (e != JIM_OK)
+ return e;
+ if (port_width < 1 || port_width > 32) {
+ Jim_SetResultString(goi->interp, "Invalid port width!", -1);
+ return JIM_ERR;
+ }
+ obj->port_width = (uint32_t)port_width;
+ } else {
+ if (goi->argc)
+ goto err_no_params;
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->port_width));
+ }
+ break;
+ case CFG_PROTOCOL:
+ if (goi->isconfigure) {
+ Jim_Nvp *p;
+ e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_protocol_opts, &p);
+ if (e != JIM_OK)
+ return e;
+ obj->pin_protocol = p->value;
+ } else {
+ if (goi->argc)
+ goto err_no_params;
+ Jim_Nvp *p;
+ e = Jim_Nvp_value2name(goi->interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
+ if (e != JIM_OK) {
+ Jim_SetResultString(goi->interp, "protocol error", -1);
+ return JIM_ERR;
+ }
+ Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1));
+ }
+ break;
+ case CFG_FORMATTER:
+ if (goi->isconfigure) {
+ Jim_Nvp *p;
+ e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_bool_opts, &p);
+ if (e != JIM_OK)
+ return e;
+ obj->en_formatter = p->value;
+ } else {
+ if (goi->argc)
+ goto err_no_params;
+ Jim_Nvp *p;
+ e = Jim_Nvp_value2name(goi->interp, nvp_arm_tpiu_swo_bool_opts, obj->en_formatter, &p);
+ if (e != JIM_OK) {
+ Jim_SetResultString(goi->interp, "formatter error", -1);
+ return JIM_ERR;
+ }
+ Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, p->name, -1));
+ }
+ break;
+ case CFG_TRACECLKIN:
+ if (goi->isconfigure) {
+ jim_wide clk;
+ e = Jim_GetOpt_Wide(goi, &clk);
+ if (e != JIM_OK)
+ return e;
+ obj->traceclkin_freq = clk;
+ } else {
+ if (goi->argc)
+ goto err_no_params;
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->traceclkin_freq));
+ }
+ break;
+ case CFG_BITRATE:
+ if (goi->isconfigure) {
+ jim_wide clk;
+ e = Jim_GetOpt_Wide(goi, &clk);
+ if (e != JIM_OK)
+ return e;
+ obj->swo_pin_freq = clk;
+ } else {
+ if (goi->argc)
+ goto err_no_params;
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, obj->swo_pin_freq));
+ }
+ break;
+ case CFG_OUTFILE:
+ if (goi->isconfigure) {
+ const char *s;
+ e = Jim_GetOpt_String(goi, &s, NULL);
+ if (e != JIM_OK)
+ return e;
+ if (s[0] == ':') {
+ char *end;
+ long port = strtol(s + 1, &end, 0);
+ if (port <= 0 || port > UINT16_MAX || *end != '\0') {
+ Jim_SetResultFormatted(goi->interp, "Invalid TCP port \'%s\'", s + 1);
+ return JIM_ERR;
+ }
+ }
+ free(obj->out_filename);
+ obj->out_filename = strdup(s);
+ if (!obj->out_filename) {
+ LOG_ERROR("Out of memory");
+ return JIM_ERR;
+ }
+ } else {
+ if (goi->argc)
+ goto err_no_params;
+ if (obj->out_filename)
+ Jim_SetResult(goi->interp, Jim_NewStringObj(goi->interp, obj->out_filename, -1));
+ }
+ break;
+ case CFG_EVENT:
+ if (goi->isconfigure) {
+ if (goi->argc < 2) {
+ Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
+ return JIM_ERR;
+ }
+ } else {
+ if (goi->argc != 1) {
+ Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?");
+ return JIM_ERR;
+ }
+ }
+
+ {
+ Jim_Nvp *p;
+ Jim_Obj *o;
+ struct arm_tpiu_swo_event_action *ea = obj->event_action;
+
+ e = Jim_GetOpt_Nvp(goi, nvp_arm_tpiu_swo_event, &p);
+ if (e != JIM_OK) {
+ Jim_GetOpt_NvpUnknown(goi, nvp_arm_tpiu_swo_event, 1);
+ return e;
+ }
+
+ while (ea) {
+ /* replace existing? */
+ if (ea->event == (enum arm_tpiu_swo_event)p->value)
+ break;
+ ea = ea->next;
+ }
+
+ if (goi->isconfigure) {
+ if (!ea) {
+ ea = calloc(1, sizeof(*ea));
+ if (!ea) {
+ LOG_ERROR("Out of memory");
+ return JIM_ERR;
+ }
+ ea->next = obj->event_action;
+ obj->event_action = ea;
+ }
+ if (ea->body)
+ Jim_DecrRefCount(ea->interp, ea->body);
+ ea->event = p->value;
+ ea->interp = goi->interp;
+ Jim_GetOpt_Obj(goi, &o);
+ ea->body = Jim_DuplicateObj(goi->interp, o);
+ Jim_IncrRefCount(ea->body);
+ } else {
+ if (ea)
+ Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, ea->body));
+ }
+ }
+ break;
+ }
+ }
+
+ return JIM_OK;
+
+err_no_params:
+ Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS");
+ return JIM_ERR;
+}
+
+static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+ Jim_GetOptInfo goi;
+
+ Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+ goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure");
+ if (goi.argc < 1) {
+ Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
+ "missing: -option ...");
+ return JIM_ERR;
+ }
+ struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
+ return arm_tpiu_swo_configure(&goi, obj);
+}
+
+static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap,
+ target_addr_t address, uint32_t value)
+{
+ if (transport_is_hla())
+ return target_write_u32(target, address, value);
+ else
+ return mem_ap_write_atomic_u32(tpiu_ap, address, value);
+}
+
+static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap,
+ target_addr_t address, uint32_t *value)
+{
+ if (transport_is_hla())
+ return target_read_u32(target, address, value);
+ else
+ return mem_ap_read_atomic_u32(tpiu_ap, address, value);
+}
+
+static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
+ struct command_context *cmd_ctx = current_command_context(interp);
+ struct adiv5_ap *tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
+ uint32_t value;
+ int retval;
+
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
+ return JIM_ERR;
+ }
+
+ if (cmd_ctx->mode == COMMAND_CONFIG) {
+ LOG_DEBUG("%s: enable deferred", obj->name);
+ obj->deferred_enable = true;
+ return JIM_OK;
+ }
+
+ if (obj->enabled)
+ return JIM_OK;
+
+ if (transport_is_hla() && obj->spot.ap_num > 0) {
+ LOG_ERROR("Invalid access port %d. Only AP#0 allowed with hla transport", obj->spot.ap_num);
+ return JIM_ERR;
+ }
+
+ if (!obj->traceclkin_freq) {
+ LOG_ERROR("Trace clock-in frequency not set");
+ return JIM_ERR;
+ }
+
+ if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART)
+ if (!obj->swo_pin_freq) {
+ LOG_ERROR("SWO pin frequency not set");
+ return JIM_ERR;
+ }
+
+ struct target *target = get_current_target(cmd_ctx);
+
+ /* START_DEPRECATED_TPIU */
+ if (obj->recheck_ap_cur_target) {
+ if (strcmp(target->type->name, "cortex_m") &&
+ strcmp(target->type->name, "hla_target")) {
+ LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA");
+ return JIM_ERR;
+ }
+ if (!target_was_examined(target)) {
+ LOG_ERROR(MSG "Current target not examined yet");
+ return JIM_ERR;
+ }
+ struct cortex_m_common *cm = target_to_cm(target);
+ obj->recheck_ap_cur_target = false;
+ obj->spot.ap_num = cm->armv7m.debug_ap->ap_num;
+ tpiu_ap = dap_ap(obj->spot.dap, obj->spot.ap_num);
+ if (obj->spot.ap_num == 0)
+ LOG_INFO(MSG "Confirmed TPIU %s is on AP 0", obj->name);
+ else
+ LOG_INFO(MSG "Target %s is on AP %d. Revised command is "
+ "\'tpiu create %s -dap %s -ap-num %d\'",
+ target_name(target), obj->spot.ap_num,
+ obj->name, adiv5_dap_name(obj->spot.dap), obj->spot.ap_num);
+ }
+ /* END_DEPRECATED_TPIU */
+
+ /* trigger the event before any attempt to R/W in the TPIU/SWO */
+ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_ENABLE);
+
+ retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_DEVID_OFFSET, &value);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Unable to read %s", obj->name);
+ return JIM_ERR;
+ }
+ switch (obj->pin_protocol) {
+ case TPIU_SPPR_PROTOCOL_SYNC:
+ value = !(value & TPIU_DEVID_NOSUPPORT_SYNC);
+ break;
+ case TPIU_SPPR_PROTOCOL_UART:
+ value &= TPIU_DEVID_SUPPORT_UART;
+ break;
+ case TPIU_SPPR_PROTOCOL_MANCHESTER:
+ value &= TPIU_DEVID_SUPPORT_MANCHESTER;
+ break;
+ default:
+ value = 0;
+ }
+ if (!value) {
+ Jim_Nvp *p;
+ Jim_Nvp_value2name(interp, nvp_arm_tpiu_swo_protocol_opts, obj->pin_protocol, &p);
+ LOG_ERROR("%s does not support protocol %s", obj->name, p->name);
+ return JIM_ERR;
+ }
+
+ if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_SYNC) {
+ retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_SSPSR_OFFSET, &value);
+ if (!(value & BIT(obj->port_width - 1))) {
+ LOG_ERROR("TPIU does not support port-width of %d bits", obj->port_width);
+ return JIM_ERR;
+ }
+ }
+
+ uint16_t prescaler = 1; /* dummy value */
+ unsigned int swo_pin_freq = obj->swo_pin_freq; /* could be replaced */
+
+ if (obj->out_filename && strcmp(obj->out_filename, "external") && obj->out_filename[0]) {
+ if (obj->out_filename[0] == ':') {
+ struct arm_tpiu_swo_priv_connection *priv = malloc(sizeof(*priv));
+ if (!priv) {
+ LOG_ERROR("Out of memory");
+ return JIM_ERR;
+ }
+ priv->obj = obj;
+ LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]);
+ retval = add_service("tpiu_swo_trace", &obj->out_filename[1],
+ CONNECTION_LIMIT_UNLIMITED, arm_tpiu_swo_service_new_connection,
+ arm_tpiu_swo_service_input, arm_tpiu_swo_service_connection_closed,
+ priv);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]);
+ return JIM_ERR;
+ }
+ } else if (strcmp(obj->out_filename, "-")) {
+ obj->file = fopen(obj->out_filename, "ab");
+ if (!obj->file) {
+ LOG_ERROR("Can't open trace destination file \"%s\"", obj->out_filename);
+ return JIM_ERR;
+ }
+ }
+
+ retval = adapter_config_trace(true, obj->pin_protocol, obj->port_width,
+ &swo_pin_freq, obj->traceclkin_freq, &prescaler);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to start adapter's trace");
+ arm_tpiu_swo_close_output(obj);
+ return JIM_ERR;
+ }
+
+ if (obj->swo_pin_freq != swo_pin_freq)
+ LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq);
+ obj->swo_pin_freq = swo_pin_freq;
+
+ target_register_timer_callback(arm_tpiu_swo_poll_trace, 1,
+ TARGET_TIMER_TYPE_PERIODIC, obj);
+
+ obj->en_capture = true;
+ } else if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) {
+ prescaler = (obj->traceclkin_freq + obj->swo_pin_freq / 2) / obj->swo_pin_freq;
+ if (prescaler > TPIU_ACPR_MAX_PRESCALER)
+ prescaler = TPIU_ACPR_MAX_PRESCALER;
+ swo_pin_freq = obj->traceclkin_freq / prescaler;
+
+ if (obj->swo_pin_freq != swo_pin_freq)
+ LOG_INFO("SWO pin data rate adjusted to %d Hz", swo_pin_freq);
+ obj->swo_pin_freq = swo_pin_freq;
+ }
+
+ retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_CSPSR_OFFSET, BIT(obj->port_width - 1));
+ if (retval != ERROR_OK)
+ goto error_exit;
+
+ retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_ACPR_OFFSET, prescaler - 1);
+ if (retval != ERROR_OK)
+ goto error_exit;
+
+ retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_SPPR_OFFSET, obj->pin_protocol);
+ if (retval != ERROR_OK)
+ goto error_exit;
+
+ retval = wrap_read_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, &value);
+ if (retval != ERROR_OK)
+ goto error_exit;
+ if (obj->en_formatter)
+ value |= BIT(1);
+ else
+ value &= ~BIT(1);
+ retval = wrap_write_u32(target, tpiu_ap, obj->spot.base + TPIU_FFCR_OFFSET, value);
+ if (retval != ERROR_OK)
+ goto error_exit;
+
+ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_ENABLE);
+
+ obj->enabled = true;
+ return JIM_OK;
+
+error_exit:
+ LOG_ERROR("Error!");
+
+ if (obj->en_capture) {
+ obj->en_capture = false;
+
+ arm_tpiu_swo_close_output(obj);
+
+ target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
+
+ retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to stop adapter's trace");
+ return JIM_ERR;
+ }
+ }
+ return JIM_ERR;
+}
+
+static int jim_arm_tpiu_swo_disable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct arm_tpiu_swo_object *obj = Jim_CmdPrivData(interp);
+
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
+ return JIM_ERR;
+ }
+
+ if (!obj->enabled)
+ return JIM_OK;
+ obj->enabled = false;
+
+ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_PRE_DISABLE);
+
+ if (obj->en_capture) {
+ obj->en_capture = false;
+
+ arm_tpiu_swo_close_output(obj);
+
+ target_unregister_timer_callback(arm_tpiu_swo_poll_trace, obj);
+
+ int retval = adapter_config_trace(false, 0, 0, NULL, 0, NULL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to stop adapter's trace");
+ return JIM_ERR;
+ }
+ }
+
+ arm_tpiu_swo_handle_event(obj, TPIU_SWO_EVENT_POST_DISABLE);
+ return JIM_OK;
+}
+
+static const struct command_registration arm_tpiu_swo_instance_command_handlers[] = {
+ {
+ .name = "configure",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_arm_tpiu_swo_configure,
+ .help = "configure a new TPIU/SWO for use",
+ .usage = "[attribute value ...]",
+ },
+ {
+ .name = "cget",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_arm_tpiu_swo_configure,
+ .help = "returns the specified TPIU/SWO attribute",
+ .usage = "attribute",
+ },
+ {
+ .name = "eventlist",
+ .mode = COMMAND_ANY,
+ .handler = handle_arm_tpiu_swo_event_list,
+ .help = "displays a table of events defined for this TPIU/SWO",
+ .usage = "",
+ },
+ {
+ .name = "enable",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_arm_tpiu_swo_enable,
+ .usage = "",
+ .help = "Enables the TPIU/SWO output",
+ },
+ {
+ .name = "disable",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_arm_tpiu_swo_disable,
+ .usage = "",
+ .help = "Disables the TPIU/SWO output",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj)
+{
+ struct command_context *cmd_ctx;
+ Jim_Cmd *cmd;
+ int e;
+
+ cmd_ctx = current_command_context(interp);
+ assert(cmd_ctx != NULL);
+
+ /* does this command exist? */
+ cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_ERRMSG);
+ if (cmd) {
+ Jim_SetResultFormatted(interp, "Command: %s Exists", obj->name);
+ return JIM_ERR;
+ }
+
+ /* now - create the new tpiu/swo name command */
+ const struct command_registration obj_commands[] = {
+ {
+ .name = obj->name,
+ .mode = COMMAND_ANY,
+ .help = "tpiu/swo instance command group",
+ .usage = "",
+ .chain = arm_tpiu_swo_instance_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+ };
+ e = register_commands(cmd_ctx, NULL, obj_commands);
+ if (ERROR_OK != e)
+ return JIM_ERR;
+
+ struct command *c = command_find_in_context(cmd_ctx, obj->name);
+ assert(c);
+ command_set_handler_data(c, obj);
+
+ list_add_tail(&obj->lh, &all_tpiu_swo);
+
+ return JIM_OK;
+}
+
+static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_GetOptInfo goi;
+ Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+ if (goi.argc < 1) {
+ Jim_WrongNumArgs(goi.interp, 1, goi.argv, "?name? ..options...");
+ return JIM_ERR;
+ }
+
+ struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object));
+ if (!obj) {
+ LOG_ERROR("Out of memory");
+ return JIM_ERR;
+ }
+ INIT_LIST_HEAD(&obj->connections);
+ adiv5_mem_ap_spot_init(&obj->spot);
+ obj->spot.base = TPIU_SWO_DEFAULT_BASE;
+ obj->port_width = 1;
+
+ Jim_Obj *n;
+ Jim_GetOpt_Obj(&goi, &n);
+ obj->name = strdup(Jim_GetString(n, NULL));
+ if (!obj->name) {
+ LOG_ERROR("Out of memory");
+ free(obj);
+ return JIM_ERR;
+ }
+
+ /* Do the rest as "configure" options */
+ goi.isconfigure = 1;
+ int e = arm_tpiu_swo_configure(&goi, obj);
+ if (e != JIM_OK)
+ goto err_exit;
+
+ if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) {
+ Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1);
+ goto err_exit;
+ }
+
+ e = arm_tpiu_swo_create(goi.interp, obj);
+ if (e != JIM_OK)
+ goto err_exit;
+
+ return JIM_OK;
+
+err_exit:
+ free(obj->name);
+ free(obj->out_filename);
+ free(obj);
+ return JIM_ERR;
+}
+
+static int jim_arm_tpiu_swo_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct arm_tpiu_swo_object *obj;
+
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+ list_for_each_entry(obj, &all_tpiu_swo, lh) {
+ Jim_ListAppendElement(interp, Jim_GetResult(interp),
+ Jim_NewStringObj(interp, obj->name, -1));
+ }
+ return JIM_OK;
+}
+
+static int jim_arm_tpiu_swo_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct command_context *cmd_ctx = current_command_context(interp);
+ struct arm_tpiu_swo_object *obj;
+ int retval = JIM_OK;
+
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
+ return JIM_ERR;
+ }
+ list_for_each_entry(obj, &all_tpiu_swo, lh) {
+ if (!obj->deferred_enable)
+ continue;
+ LOG_DEBUG("%s: running enable during init", obj->name);
+ int retval2 = command_run_linef(cmd_ctx, "%s enable", obj->name);
+ if (retval2 != ERROR_OK)
+ retval = JIM_ERR;
+ }
+ return retval;
+}
+
+/* START_DEPRECATED_TPIU */
+/* DEPRECATED: emulation of old command 'tpiu config' */
+COMMAND_HANDLER(handle_tpiu_deprecated_config_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct arm_tpiu_swo_object *obj = NULL;
+ int retval;
+
+ if (strcmp(target->type->name, "cortex_m") &&
+ strcmp(target->type->name, "hla_target")) {
+ LOG_ERROR(MSG "Current target is not a Cortex-M nor a HLA");
+ return ERROR_FAIL;
+ }
+
+ if (!list_empty(&all_tpiu_swo)) {
+ obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh);
+ LOG_INFO(MSG "Using %s", obj->name);
+ } else {
+ struct cortex_m_common *cm = target_to_cm(target);
+ struct adiv5_private_config *pc = target->private_config;
+ struct adiv5_dap *dap = pc->dap;
+ int ap_num = pc->ap_num;
+ bool set_recheck_ap_cur_target = false;
+
+ LOG_INFO(MSG "Adding a TPIU \'%s.tpiu\' in the configuration", target_name(target));
+
+ if (ap_num == DP_APSEL_INVALID && transport_is_hla())
+ ap_num = 0; /* HLA should only support AP 0 */
+
+ if (ap_num == DP_APSEL_INVALID && target_was_examined(target))
+ ap_num = cm->armv7m.debug_ap->ap_num;
+
+ if (ap_num == DP_APSEL_INVALID) {
+ LOG_INFO(MSG "Target %s uses AP autodetection. Adding TPIU on AP 0; can be revised later",
+ target_name(target));
+ ap_num = 0;
+ set_recheck_ap_cur_target = true;
+ }
+
+ LOG_INFO(MSG "Running: \'tpiu create %s.tpiu -dap %s -ap-num %d\'",
+ target_name(target), adiv5_dap_name(dap), ap_num);
+
+ retval = command_run_linef(CMD_CTX, "tpiu create %s.tpiu -dap %s -ap-num %d",
+ target_name(target), adiv5_dap_name(dap), ap_num);
+ if (retval != ERROR_OK)
+ return retval;
+
+ obj = list_first_entry(&all_tpiu_swo, typeof(*obj), lh);
+ if (set_recheck_ap_cur_target)
+ obj->recheck_ap_cur_target = true;
+ }
+
+ unsigned int cmd_idx = 0;
+ if (CMD_ARGC == cmd_idx)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
+ if (CMD_ARGC != cmd_idx + 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ LOG_INFO(MSG "Running: \'%s disable\'", obj->name);
+ return command_run_linef(CMD_CTX, "%s disable", obj->name);
+ }
+
+ const char *output = NULL;
+ const char *protocol;
+ const char *formatter = NULL;
+ const char *port_width = NULL;
+ const char *trace_clk;
+ const char *pin_clk = NULL;
+ if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
+ cmd_idx++;
+ if (CMD_ARGC == cmd_idx)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ output = CMD_ARGV[cmd_idx];
+ } else if (strcmp(CMD_ARGV[cmd_idx], "external"))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ cmd_idx++;
+ if (CMD_ARGC == cmd_idx)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
+ protocol = CMD_ARGV[cmd_idx];
+ cmd_idx++;
+ if (CMD_ARGC == cmd_idx)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ port_width = CMD_ARGV[cmd_idx];
+ } else {
+ if (strcmp(CMD_ARGV[cmd_idx], "manchester") && strcmp(CMD_ARGV[cmd_idx], "uart"))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ protocol = CMD_ARGV[cmd_idx];
+ cmd_idx++;
+ if (CMD_ARGC == cmd_idx)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ formatter = CMD_ARGV[cmd_idx];
+ }
+ cmd_idx++;
+ if (CMD_ARGC == cmd_idx)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ trace_clk = CMD_ARGV[cmd_idx];
+ cmd_idx++;
+ if (CMD_ARGC != cmd_idx) {
+ pin_clk = CMD_ARGV[cmd_idx];
+ cmd_idx++;
+ }
+ if (CMD_ARGC != cmd_idx)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ LOG_INFO(MSG "Running: \'%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s\'",
+ obj->name, protocol, trace_clk,
+ pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "",
+ output ? " -output " : "", output ? output : "",
+ formatter ? " -formatter " : "", formatter ? formatter : "",
+ port_width ? " -port-width " : "", port_width ? port_width : "");
+
+ retval = command_run_linef(CMD_CTX,
+ "%s configure -protocol %s -traceclk %s" "%s%s" "%s%s" "%s%s" "%s%s",
+ obj->name, protocol, trace_clk,
+ pin_clk ? " -pin-freq " : "", pin_clk ? pin_clk : "",
+ output ? " -output " : "", output ? output : "",
+ formatter ? " -formatter " : "", formatter ? formatter : "",
+ port_width ? " -port-width " : "", port_width ? port_width : "");
+ if (retval != ERROR_OK)
+ return retval;
+
+ LOG_INFO(MSG "Running: \'%s enable\'", obj->name);
+ retval = command_run_linef(CMD_CTX, "%s enable", obj->name);
+ if (retval != ERROR_OK)
+ return retval;
+
+ target_handle_event(target, TARGET_EVENT_TRACE_CONFIG);
+ return ERROR_OK;
+}
+
+static const struct command_registration arm_tpiu_deprecated_subcommand_handlers[] = {
+ {
+ .name = "config",
+ .handler = handle_tpiu_deprecated_config_command,
+ .mode = COMMAND_ANY,
+ .help = "Configure TPIU features, DEPRECATED, use \'tpiu create\'",
+ .usage = "(disable | "
+ "((external | internal (<filename> | <:port> | -)) "
+ "(sync <port width> | ((manchester | uart) <formatter enable>)) "
+ "<TRACECLKIN freq> [<trace freq>]))",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration arm_tpiu_deprecated_command_handlers[] = {
+ {
+ .name = "tpiu",
+ .chain = arm_tpiu_deprecated_subcommand_handlers,
+ .usage = "",
+ .help = "tpiu command group",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+/* END_DEPRECATED_TPIU */
+
+static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = {
+ {
+ .name = "create",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_arm_tpiu_swo_create,
+ .usage = "name [-dap dap] [-ap-num num] [-address baseaddr]",
+ .help = "Creates a new TPIU or SWO object",
+ },
+ {
+ .name = "names",
+ .mode = COMMAND_ANY,
+ .jim_handler = jim_arm_tpiu_swo_names,
+ .usage = "",
+ .help = "Lists all registered TPIU and SWO objects by name",
+ },
+ {
+ .name = "init",
+ .mode = COMMAND_EXEC,
+ .jim_handler = jim_arm_tpiu_swo_init,
+ .usage = "",
+ .help = "Initialize TPIU and SWO",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration arm_tpiu_swo_command_handlers[] = {
+ {
+ .name = "tpiu",
+ .chain = arm_tpiu_swo_subcommand_handlers,
+ .usage = "",
+ .help = "tpiu command group",
+ },
+ {
+ .name = "swo",
+ .chain = arm_tpiu_swo_subcommand_handlers,
+ .usage = "",
+ .help = "swo command group",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx)
+{
+ return register_commands(cmd_ctx, NULL, arm_tpiu_swo_command_handlers);
+}
diff --git a/src/target/arm_tpiu_swo.h b/src/target/arm_tpiu_swo.h
new file mode 100644
index 0000000..5904ce2
--- /dev/null
+++ b/src/target/arm_tpiu_swo.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENOCD_TARGET_ARM_TPIU_SWO_H
+#define OPENOCD_TARGET_ARM_TPIU_SWO_H
+
+/* Values should match TPIU_SPPR_PROTOCOL_xxx */
+enum tpiu_pin_protocol {
+ TPIU_PIN_PROTOCOL_SYNC = 0, /**< synchronous trace output */
+ TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER = 1, /**< asynchronous output with Manchester coding */
+ TPIU_PIN_PROTOCOL_ASYNC_UART = 2, /**< asynchronous output with NRZ coding */
+};
+
+/* START_DEPRECATED_TPIU */
+/* DEPRECATED: emulation of old command 'tpiu config' */
+extern const struct command_registration arm_tpiu_deprecated_command_handlers[];
+/* END_DEPRECATED_TPIU */
+
+int arm_tpiu_swo_register_commands(struct command_context *cmd_ctx);
+int arm_tpiu_swo_cleanup_all(void);
+
+#endif /* OPENOCD_TARGET_ARM_TPIU_SWO_H */
diff --git a/src/target/armv7m.c b/src/target/armv7m.c
index f14ce0d..101094a 100644
--- a/src/target/armv7m.c
+++ b/src/target/armv7m.c
@@ -166,10 +166,10 @@ int armv7m_restore_context(struct target *target)
* packing of ARMV7M_PMSK_BPRI_FLTMSK_CTRL!
* See also comments in the register table above */
for (i = cache->num_regs - 1; i >= 0; i--) {
- if (cache->reg_list[i].dirty) {
- armv7m->arm.write_core_reg(target, &cache->reg_list[i], i,
- ARM_MODE_ANY, cache->reg_list[i].value);
- }
+ struct reg *r = &cache->reg_list[i];
+
+ if (r->exist && r->dirty)
+ armv7m->arm.write_core_reg(target, r, i, ARM_MODE_ANY, r->value);
}
return ERROR_OK;
diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c
index 10f1422..74ffaf5 100644
--- a/src/target/armv7m_trace.c
+++ b/src/target/armv7m_trace.c
@@ -24,143 +24,44 @@
#include <target/cortex_m.h>
#include <target/armv7m_trace.h>
#include <jtag/interface.h>
+#include <helper/time_support.h>
-#define TRACE_BUF_SIZE 4096
-
-static int armv7m_poll_trace(void *target)
-{
- struct armv7m_common *armv7m = target_to_armv7m(target);
- uint8_t buf[TRACE_BUF_SIZE];
- size_t size = sizeof(buf);
- int retval;
-
- retval = adapter_poll_trace(buf, &size);
- if (retval != ERROR_OK || !size)
- return retval;
-
- target_call_trace_callbacks(target, size, buf);
-
- switch (armv7m->trace_config.internal_channel) {
- case TRACE_INTERNAL_CHANNEL_FILE:
- if (armv7m->trace_config.trace_file != NULL) {
- if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size)
- fflush(armv7m->trace_config.trace_file);
- else {
- LOG_ERROR("Error writing to the trace destination file");
- return ERROR_FAIL;
- }
- }
- break;
- case TRACE_INTERNAL_CHANNEL_TCP:
- if (armv7m->trace_config.trace_service != NULL) {
- /* broadcast to all service connections */
- struct connection *connection = armv7m->trace_config.trace_service->connections;
- retval = ERROR_OK;
- while (connection) {
- if (connection_write(connection, buf, size) != (int) size)
- retval = ERROR_FAIL;
-
- connection = connection->next;
- }
-
- if (retval != ERROR_OK) {
- LOG_ERROR("Error streaming the trace to TCP/IP port");
- return ERROR_FAIL;
- }
- }
- break;
- case TRACE_INTERNAL_CHANNEL_TCL_ONLY:
- /* nothing to do :
- * the trace data is sent to TCL by calling the target_call_trace_callbacks
- **/
- break;
- default:
- LOG_ERROR("unsupported trace internal channel");
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
-}
-
-int armv7m_trace_tpiu_config(struct target *target)
+int armv7m_trace_itm_config(struct target *target)
{
struct armv7m_common *armv7m = target_to_armv7m(target);
struct armv7m_trace_config *trace_config = &armv7m->trace_config;
- uint16_t prescaler;
int retval;
- target_unregister_timer_callback(armv7m_poll_trace, target);
-
- retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
- trace_config->pin_protocol, trace_config->port_size,
- &trace_config->trace_freq, trace_config->traceclkin_freq, &prescaler);
-
- if (retval != ERROR_OK)
- return retval;
-
- if (trace_config->config_type == TRACE_CONFIG_TYPE_EXTERNAL) {
- prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
-
- if (trace_config->traceclkin_freq % trace_config->trace_freq) {
- prescaler++;
-
- int trace_freq = trace_config->traceclkin_freq / prescaler;
- LOG_INFO("Can not obtain %u trace port frequency from %u "
- "TRACECLKIN frequency, using %u instead",
- trace_config->trace_freq, trace_config->traceclkin_freq,
- trace_freq);
-
- trace_config->trace_freq = trace_freq;
- }
- }
-
- if (!trace_config->trace_freq) {
- LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
- return ERROR_FAIL;
- }
-
- retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
- if (retval != ERROR_OK)
- return retval;
-
- retval = target_write_u32(target, TPIU_ACPR, prescaler - 1);
- if (retval != ERROR_OK)
- return retval;
-
- retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol);
+ retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
if (retval != ERROR_OK)
return retval;
- uint32_t ffcr;
- retval = target_read_u32(target, TPIU_FFCR, &ffcr);
+ /* pg315 of CoreSight Components
+ * It is recommended that the ITMEn bit is cleared and waits for the
+ * ITMBusy bit to be cleared, before changing any fields in the
+ * Control Register, otherwise the behavior can be unpredictable.
+ */
+ uint32_t itm_tcr;
+ retval = target_read_u32(target, ITM_TCR, &itm_tcr);
if (retval != ERROR_OK)
return retval;
- if (trace_config->formatter)
- ffcr |= (1 << 1);
- else
- ffcr &= ~(1 << 1);
- retval = target_write_u32(target, TPIU_FFCR, ffcr);
+ retval = target_write_u32(target,
+ ITM_TCR,
+ itm_tcr & ~ITM_TCR_ITMENA_BIT
+ );
if (retval != ERROR_OK)
return retval;
- if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
- target_register_timer_callback(armv7m_poll_trace, 1,
- TARGET_TIMER_TYPE_PERIODIC, target);
-
- target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
-
- return ERROR_OK;
-}
-
-int armv7m_trace_itm_config(struct target *target)
-{
- struct armv7m_common *armv7m = target_to_armv7m(target);
- struct armv7m_trace_config *trace_config = &armv7m->trace_config;
- int retval;
-
- retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
- if (retval != ERROR_OK)
- return retval;
+ int64_t then = timeval_ms() + 1000;
+ do {
+ retval = target_read_u32(target, ITM_TCR, &itm_tcr);
+ if (retval != ERROR_OK)
+ return retval;
+ if (timeval_ms() > then) {
+ LOG_ERROR("timeout waiting for ITM_TCR_BUSY_BIT");
+ return ERROR_FAIL;
+ }
+ } while (itm_tcr & ITM_TCR_BUSY_BIT);
/* Enable ITM, TXENA, set TraceBusID and other parameters */
retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) |
@@ -182,182 +83,6 @@ int armv7m_trace_itm_config(struct target *target)
return ERROR_OK;
}
-static void close_trace_channel(struct armv7m_common *armv7m)
-{
- switch (armv7m->trace_config.internal_channel) {
- case TRACE_INTERNAL_CHANNEL_FILE:
- if (armv7m->trace_config.trace_file)
- fclose(armv7m->trace_config.trace_file);
- armv7m->trace_config.trace_file = NULL;
- break;
- case TRACE_INTERNAL_CHANNEL_TCP:
- if (armv7m->trace_config.trace_service)
- remove_service(armv7m->trace_config.trace_service->name, armv7m->trace_config.trace_service->port);
- armv7m->trace_config.trace_service = NULL;
- break;
- case TRACE_INTERNAL_CHANNEL_TCL_ONLY:
- /* nothing to do:
- * the trace polling is disabled in the beginning of armv7m_trace_tpiu_config
- **/
- break;
- default:
- LOG_ERROR("unsupported trace internal channel");
- }
-}
-
-static int trace_new_connection(struct connection *connection)
-{
- /* nothing to do */
- return ERROR_OK;
-}
-
-static int trace_input(struct connection *connection)
-{
- /* create a dummy buffer to check if the connection is still active */
- const int buf_len = 100;
- unsigned char buf[buf_len];
- int bytes_read = connection_read(connection, buf, buf_len);
-
- if (bytes_read == 0)
- return ERROR_SERVER_REMOTE_CLOSED;
- else if (bytes_read == -1) {
- LOG_ERROR("error during read: %s", strerror(errno));
- return ERROR_SERVER_REMOTE_CLOSED;
- }
-
- return ERROR_OK;
-}
-
-static int trace_connection_closed(struct connection *connection)
-{
- /* nothing to do, no connection->priv to free */
- return ERROR_OK;
-}
-
-extern struct command_context *global_cmd_ctx;
-
-int armv7m_trace_tpiu_exit(struct target *target)
-{
- struct armv7m_common *armv7m = target_to_armv7m(target);
-
- if (global_cmd_ctx->mode == COMMAND_CONFIG ||
- armv7m->trace_config.config_type == TRACE_CONFIG_TYPE_DISABLED)
- return ERROR_OK;
-
- close_trace_channel(armv7m);
- armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
- return armv7m_trace_tpiu_config(target);
-}
-
-COMMAND_HANDLER(handle_tpiu_config_command)
-{
- struct target *target = get_current_target(CMD_CTX);
- struct armv7m_common *armv7m = target_to_armv7m(target);
-
- unsigned int cmd_idx = 0;
-
- if (CMD_ARGC == cmd_idx)
- return ERROR_COMMAND_SYNTAX_ERROR;
- if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
- if (CMD_ARGC == cmd_idx + 1) {
- close_trace_channel(armv7m);
-
- armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
- if (CMD_CTX->mode == COMMAND_EXEC)
- return armv7m_trace_tpiu_config(target);
- else
- return ERROR_OK;
- }
- } else if (!strcmp(CMD_ARGV[cmd_idx], "external") ||
- !strcmp(CMD_ARGV[cmd_idx], "internal")) {
- close_trace_channel(armv7m);
-
- armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
- if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
- cmd_idx++;
- if (CMD_ARGC == cmd_idx)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
- armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCL_ONLY;
-
- if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
- if (CMD_ARGV[cmd_idx][0] == ':') {
- armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCP;
-
- int ret = add_service("armv7m_trace", &(CMD_ARGV[cmd_idx][1]),
- CONNECTION_LIMIT_UNLIMITED, trace_new_connection, trace_input,
- trace_connection_closed, NULL, &armv7m->trace_config.trace_service);
- if (ret != ERROR_OK) {
- LOG_ERROR("Can't configure trace TCP port");
- return ERROR_FAIL;
- }
- } else {
- armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_FILE;
- armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
- if (!armv7m->trace_config.trace_file) {
- LOG_ERROR("Can't open trace destination file");
- return ERROR_FAIL;
- }
- }
- }
- }
- cmd_idx++;
- if (CMD_ARGC == cmd_idx)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
- armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
-
- cmd_idx++;
- if (CMD_ARGC == cmd_idx)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
- } else {
- if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
- armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
- else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
- armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
- else
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- cmd_idx++;
- if (CMD_ARGC == cmd_idx)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter);
- }
-
- cmd_idx++;
- if (CMD_ARGC == cmd_idx)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq);
-
- cmd_idx++;
- if (CMD_ARGC != cmd_idx) {
- COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
- cmd_idx++;
- } else {
- if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
- LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
- armv7m->trace_config.trace_freq = 0;
- }
-
- if (CMD_ARGC == cmd_idx) {
- if (CMD_CTX->mode == COMMAND_EXEC)
- return armv7m_trace_tpiu_config(target);
- else
- return ERROR_OK;
- }
- }
-
- return ERROR_COMMAND_SYNTAX_ERROR;
-}
-
COMMAND_HANDLER(handle_itm_port_command)
{
struct target *target = get_current_target(CMD_CTX);
@@ -380,8 +105,9 @@ COMMAND_HANDLER(handle_itm_port_command)
if (CMD_CTX->mode == COMMAND_EXEC)
return armv7m_trace_itm_config(target);
- else
- return ERROR_OK;
+
+ armv7m->trace_config.itm_deferred_config = true;
+ return ERROR_OK;
}
COMMAND_HANDLER(handle_itm_ports_command)
@@ -399,23 +125,10 @@ COMMAND_HANDLER(handle_itm_ports_command)
if (CMD_CTX->mode == COMMAND_EXEC)
return armv7m_trace_itm_config(target);
- else
- return ERROR_OK;
-}
-static const struct command_registration tpiu_command_handlers[] = {
- {
- .name = "config",
- .handler = handle_tpiu_config_command,
- .mode = COMMAND_ANY,
- .help = "Configure TPIU features",
- .usage = "(disable | "
- "((external | internal (<filename> | <:port> | -)) "
- "(sync <port width> | ((manchester | uart) <formatter enable>)) "
- "<TRACECLKIN freq> [<trace freq>]))",
- },
- COMMAND_REGISTRATION_DONE
-};
+ armv7m->trace_config.itm_deferred_config = true;
+ return ERROR_OK;
+}
static const struct command_registration itm_command_handlers[] = {
{
@@ -437,13 +150,6 @@ static const struct command_registration itm_command_handlers[] = {
const struct command_registration armv7m_trace_command_handlers[] = {
{
- .name = "tpiu",
- .mode = COMMAND_ANY,
- .help = "tpiu command group",
- .usage = "",
- .chain = tpiu_command_handlers,
- },
- {
.name = "itm",
.mode = COMMAND_ANY,
.help = "itm command group",
diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h
index cdf79e7..eaee6a4 100644
--- a/src/target/armv7m_trace.h
+++ b/src/target/armv7m_trace.h
@@ -18,33 +18,14 @@
#ifndef OPENOCD_TARGET_ARMV7M_TRACE_H
#define OPENOCD_TARGET_ARMV7M_TRACE_H
-#include <server/server.h>
#include <target/target.h>
#include <command.h>
/**
* @file
- * Holds the interface to TPIU, ITM and DWT configuration functions.
+ * Holds the interface to ITM and DWT configuration functions.
*/
-enum trace_config_type {
- TRACE_CONFIG_TYPE_DISABLED, /**< tracing is disabled */
- TRACE_CONFIG_TYPE_EXTERNAL, /**< trace output is captured externally */
- TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */
-};
-
-enum trace_internal_channel {
- TRACE_INTERNAL_CHANNEL_TCL_ONLY, /** trace data is sent only to 'tcl_trace' */
- TRACE_INTERNAL_CHANNEL_FILE, /** trace data is appended to a file */
- TRACE_INTERNAL_CHANNEL_TCP /** trace data is appended to a TCP/IP port*/
-};
-
-enum tpiu_pin_protocol {
- TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */
- TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */
- TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */
-};
-
enum itm_ts_prescaler {
ITM_TS_PRESCALE1, /**< no prescaling for the timestamp counter */
ITM_TS_PRESCALE4, /**< refclock divided by 4 for the timestamp counter */
@@ -53,19 +34,6 @@ enum itm_ts_prescaler {
};
struct armv7m_trace_config {
- /** Currently active trace capture mode */
- enum trace_config_type config_type;
-
- /** The used channel when internal mode is selected */
- enum trace_internal_channel internal_channel;
-
- /** Currently active trace output mode */
- enum tpiu_pin_protocol pin_protocol;
- /** TPIU formatter enable/disable (in async mode) */
- bool formatter;
- /** Synchronous output port width */
- uint32_t port_size;
-
/** Bitmask of currently enabled ITM stimuli */
uint32_t itm_ter[8];
/** Identifier for multi-source trace stream formatting */
@@ -78,28 +46,13 @@ struct armv7m_trace_config {
bool itm_async_timestamps;
/** Enable synchronisation packet transmission (for sync port only) */
bool itm_synchro_packets;
-
- /** Current frequency of TRACECLKIN (usually matches HCLK) */
- unsigned int traceclkin_freq;
- /** Current frequency of trace port */
- unsigned int trace_freq;
- /** Handle to output trace data in INTERNAL capture mode via file */
- FILE *trace_file;
- /** Handle to output trace data in INTERNAL capture mode via tcp */
- struct service *trace_service;
+ /** Config ITM after target examine */
+ bool itm_deferred_config;
};
extern const struct command_registration armv7m_trace_command_handlers[];
/**
- * Configure hardware accordingly to the current TPIU target settings
- */
-int armv7m_trace_tpiu_config(struct target *target);
-/**
- * Disable TPIU data gathering at exit
- */
-int armv7m_trace_tpiu_exit(struct target *target);
-/**
* Configure hardware accordingly to the current ITM target settings
*/
int armv7m_trace_itm_config(struct target *target);
diff --git a/src/target/armv8.c b/src/target/armv8.c
index 95efdc9..6bf3b11 100644
--- a/src/target/armv8.c
+++ b/src/target/armv8.c
@@ -1098,13 +1098,6 @@ int armv8_handle_cache_info_command(struct command_invocation *cmd,
static int armv8_setup_semihosting(struct target *target, int enable)
{
- struct arm *arm = target_to_arm(target);
-
- if (arm->core_state != ARM_STATE_AARCH64) {
- LOG_ERROR("semihosting only supported in AArch64 state\n");
- return ERROR_FAIL;
- }
-
return ERROR_OK;
}
diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c
index 1e88a44..e7d0f86 100644
--- a/src/target/armv8_dpm.c
+++ b/src/target/armv8_dpm.c
@@ -1465,8 +1465,10 @@ int armv8_dpm_setup(struct arm_dpm *dpm)
}
/* watchpoint setup */
- target->type->add_watchpoint = dpmv8_add_watchpoint;
- target->type->remove_watchpoint = dpmv8_remove_watchpoint;
+ if (!target->type->add_watchpoint) {
+ target->type->add_watchpoint = dpmv8_add_watchpoint;
+ target->type->remove_watchpoint = dpmv8_remove_watchpoint;
+ }
/* FIXME add vector catch support */
diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h
index ee6f699..a6cade3 100644
--- a/src/target/armv8_dpm.h
+++ b/src/target/armv8_dpm.h
@@ -16,6 +16,7 @@
#define OPENOCD_TARGET_ARMV8_DPM_H
#include "arm_dpm.h"
+#include "helper/bits.h"
/* forward-declare struct armv8_common */
struct armv8_common;
@@ -96,6 +97,12 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t wfar);
#define DRCR_RESTART (1 << 1)
#define DRCR_CLEAR_EXCEPTIONS (1 << 2)
+/* ECR (Execution Control Register) bits */
+#define ECR_RCE BIT(1)
+
+/* ESR (Event Status Register) bits */
+#define ESR_RC BIT(1)
+
/* PRSR (processor debug status register) bits */
#define PRSR_PU (1 << 0)
#define PRSR_SPD (1 << 1)
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index d27c298..5018a91 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -3143,7 +3143,6 @@ static const struct command_registration cortex_a_command_handlers[] = {
struct target_type cortexa_target = {
.name = "cortex_a",
- .deprecated_name = "cortex_a8",
.poll = cortex_a_poll,
.arch_state = armv7a_arch_state,
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index ce2c426..6dc33c8 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -521,7 +521,7 @@ static int cortex_m_debug_entry(struct target *target)
for (i = 0; i < num_regs; i++) {
r = &armv7m->arm.core_cache->reg_list[i];
- if (!r->valid)
+ if (r->exist && !r->valid)
arm->read_core_reg(target, r, i, ARM_MODE_ANY);
}
@@ -1648,8 +1648,6 @@ void cortex_m_deinit_target(struct target *target)
{
struct cortex_m_common *cortex_m = target_to_cm(target);
- armv7m_trace_tpiu_exit(target);
-
free(cortex_m->fp_comparator_list);
cortex_m_dwt_free(target);
@@ -2082,10 +2080,8 @@ int cortex_m_examine(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_DISABLED) {
- armv7m_trace_tpiu_config(target);
+ if (armv7m->trace_config.itm_deferred_config)
armv7m_trace_itm_config(target);
- }
/* NOTE: FPB and DWT are both optional. */
@@ -2485,6 +2481,11 @@ static const struct command_registration cortex_m_command_handlers[] = {
{
.chain = armv7m_trace_command_handlers,
},
+ /* START_DEPRECATED_TPIU */
+ {
+ .chain = arm_tpiu_deprecated_command_handlers,
+ },
+ /* END_DEPRECATED_TPIU */
{
.name = "cortex_m",
.mode = COMMAND_EXEC,
@@ -2500,7 +2501,6 @@ static const struct command_registration cortex_m_command_handlers[] = {
struct target_type cortexm_target = {
.name = "cortex_m",
- .deprecated_name = "cortex_m3",
.poll = cortex_m_poll,
.arch_state = armv7m_arch_state,
diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h
index b470fbd..1e2197b 100644
--- a/src/target/cortex_m.h
+++ b/src/target/cortex_m.h
@@ -35,6 +35,8 @@
#define ITM_TER0 0xE0000E00
#define ITM_TPR 0xE0000E40
#define ITM_TCR 0xE0000E80
+#define ITM_TCR_ITMENA_BIT BIT(0)
+#define ITM_TCR_BUSY_BIT BIT(23)
#define ITM_LAR 0xE0000FB0
#define ITM_LAR_KEY 0xC5ACCE55
diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c
index 7c53c45..a29508b 100644
--- a/src/target/embeddedice.c
+++ b/src/target/embeddedice.c
@@ -645,7 +645,6 @@ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeou
return ERROR_TARGET_TIMEOUT;
}
-#ifndef HAVE_JTAG_MINIDRIVER_H
/**
* This is an inner loop of the open loop DCC write of data to target
*/
@@ -660,6 +659,3 @@ void embeddedice_write_dcc(struct jtag_tap *tap,
buffer += 4;
}
}
-#else
-/* provided by minidriver */
-#endif
diff --git a/src/target/etm.c b/src/target/etm.c
index faa941f..19f3691 100644
--- a/src/target/etm.c
+++ b/src/target/etm.c
@@ -27,11 +27,6 @@
#include "register.h"
#include "etm_dummy.h"
-#if BUILD_OOCD_TRACE == 1
-#include "oocd_trace.h"
-#endif
-
-
/*
* ARM "Embedded Trace Macrocell" (ETM) support -- direct JTAG access.
*
@@ -642,9 +637,6 @@ static int etm_write_reg(struct reg *reg, uint32_t value)
static struct etm_capture_driver *etm_capture_drivers[] = {
&etb_capture_driver,
&etm_dummy_capture_driver,
-#if BUILD_OOCD_TRACE == 1
- &oocd_trace_capture_driver,
-#endif
NULL
};
diff --git a/src/target/hla_target.c b/src/target/hla_target.c
index 3d41387..cd57dd2 100644
--- a/src/target/hla_target.c
+++ b/src/target/hla_target.c
@@ -226,7 +226,7 @@ static int adapter_load_context(struct target *target)
for (int i = 0; i < num_regs; i++) {
struct reg *r = &armv7m->arm.core_cache->reg_list[i];
- if (!r->valid)
+ if (r->exist && !r->valid)
armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY);
}
@@ -630,12 +630,16 @@ static const struct command_registration adapter_command_handlers[] = {
{
.chain = rtt_target_command_handlers,
},
+ /* START_DEPRECATED_TPIU */
+ {
+ .chain = arm_tpiu_deprecated_command_handlers,
+ },
+ /* END_DEPRECATED_TPIU */
COMMAND_REGISTRATION_DONE
};
struct target_type hla_target = {
.name = "hla_target",
- .deprecated_name = "stm32_stlink",
.init_target = adapter_init_target,
.deinit_target = cortex_m_deinit_target,
diff --git a/src/target/image.c b/src/target/image.c
index fd5eff8..e63cd0f 100644
--- a/src/target/image.c
+++ b/src/target/image.c
@@ -1052,7 +1052,7 @@ int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *c
keep_alive();
}
- LOG_DEBUG("Calculating checksum done; checksum=0x%x", crc);
+ LOG_DEBUG("Calculating checksum done; checksum=0x%" PRIx32, crc);
*checksum = crc;
return ERROR_OK;
diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c
index 7ed41c6..89c0c02 100644
--- a/src/target/mem_ap.c
+++ b/src/target/mem_ap.c
@@ -20,6 +20,7 @@
#include "target_type.h"
#include "arm.h"
#include "arm_adi_v5.h"
+#include "register.h"
#include <jtag/jtag.h>
@@ -55,6 +56,9 @@ static int mem_ap_target_create(struct target *target, Jim_Interp *interp)
target->arch_info = mem_ap;
+ if (!target->gdb_port_override)
+ target->gdb_port_override = strdup("disabled");
+
return ERROR_OK;
}
@@ -62,6 +66,7 @@ static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *ta
{
LOG_DEBUG("%s", __func__);
target->state = TARGET_UNKNOWN;
+ target->debug_reason = DBG_REASON_UNDEFINED;
return ERROR_OK;
}
@@ -82,8 +87,10 @@ static int mem_ap_arch_state(struct target *target)
static int mem_ap_poll(struct target *target)
{
- if (target->state == TARGET_UNKNOWN)
+ if (target->state == TARGET_UNKNOWN) {
target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
+ }
return ERROR_OK;
}
@@ -92,6 +99,8 @@ static int mem_ap_halt(struct target *target)
{
LOG_DEBUG("%s", __func__);
target->state = TARGET_HALTED;
+ target->debug_reason = DBG_REASON_DBGRQ;
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
return ERROR_OK;
}
@@ -100,6 +109,7 @@ static int mem_ap_resume(struct target *target, int current, target_addr_t addre
{
LOG_DEBUG("%s", __func__);
target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
return ERROR_OK;
}
@@ -108,12 +118,15 @@ static int mem_ap_step(struct target *target, int current, target_addr_t address
{
LOG_DEBUG("%s", __func__);
target->state = TARGET_HALTED;
+ target->debug_reason = DBG_REASON_DBGRQ;
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
return ERROR_OK;
}
static int mem_ap_assert_reset(struct target *target)
{
target->state = TARGET_RESET;
+ target->debug_reason = DBG_REASON_UNDEFINED;
LOG_DEBUG("%s", __func__);
return ERROR_OK;
@@ -127,6 +140,7 @@ static int mem_ap_examine(struct target *target)
mem_ap->ap = dap_ap(mem_ap->arm.dap, mem_ap->ap_num);
target_set_examined(target);
target->state = TARGET_UNKNOWN;
+ target->debug_reason = DBG_REASON_UNDEFINED;
return mem_ap_init(mem_ap->ap);
}
@@ -135,15 +149,85 @@ static int mem_ap_examine(struct target *target)
static int mem_ap_deassert_reset(struct target *target)
{
- if (target->reset_halt)
+ if (target->reset_halt) {
target->state = TARGET_HALTED;
- else
+ target->debug_reason = DBG_REASON_DBGRQ;
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ } else {
target->state = TARGET_RUNNING;
+ target->debug_reason = DBG_REASON_NOTHALTED;
+ }
LOG_DEBUG("%s", __func__);
return ERROR_OK;
}
+static int mem_ap_reg_get(struct reg *reg)
+{
+ return ERROR_OK;
+}
+
+static int mem_ap_reg_set(struct reg *reg, uint8_t *buf)
+{
+ return ERROR_OK;
+}
+
+static struct reg_arch_type mem_ap_reg_arch_type = {
+ .get = mem_ap_reg_get,
+ .set = mem_ap_reg_set,
+};
+
+const char *mem_ap_get_gdb_arch(struct target *target)
+{
+ return "arm";
+}
+
+/*
+ * Dummy ARM register emulation:
+ * reg[0..15]: 32 bits, r0~r12, sp, lr, pc
+ * reg[16..23]: 96 bits, f0~f7
+ * reg[24]: 32 bits, fps
+ * reg[25]: 32 bits, cpsr
+ *
+ * Set 'exist' only to reg[0..15], so initial response to GDB is correct
+ */
+#define NUM_REGS 26
+#define MAX_REG_SIZE 96
+#define REG_EXIST(n) ((n) < 16)
+#define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32)
+
+struct mem_ap_alloc_reg_list {
+ /* reg_list must be the first field */
+ struct reg *reg_list[NUM_REGS];
+ struct reg regs[NUM_REGS];
+ uint8_t regs_value[MAX_REG_SIZE / 8];
+};
+
+static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
+{
+ struct mem_ap_alloc_reg_list *mem_ap_alloc = calloc(1, sizeof(struct mem_ap_alloc_reg_list));
+ if (!mem_ap_alloc) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ *reg_list = mem_ap_alloc->reg_list;
+ *reg_list_size = NUM_REGS;
+ struct reg *regs = mem_ap_alloc->regs;
+
+ for (int i = 0; i < NUM_REGS; i++) {
+ regs[i].number = i;
+ regs[i].value = mem_ap_alloc->regs_value;
+ regs[i].size = REG_SIZE(i);
+ regs[i].exist = REG_EXIST(i);
+ regs[i].type = &mem_ap_reg_arch_type;
+ (*reg_list)[i] = &regs[i];
+ }
+
+ return ERROR_OK;
+}
+
static int mem_ap_read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
@@ -192,6 +276,9 @@ struct target_type mem_ap_target = {
.assert_reset = mem_ap_assert_reset,
.deassert_reset = mem_ap_deassert_reset,
+ .get_gdb_arch = mem_ap_get_gdb_arch,
+ .get_gdb_reg_list = mem_ap_get_gdb_reg_list,
+
.read_memory = mem_ap_read_memory,
.write_memory = mem_ap_write_memory,
};
diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c
index d6bd1c5..f8643fa 100644
--- a/src/target/mips32_pracc.c
+++ b/src/target/mips32_pracc.c
@@ -317,7 +317,7 @@ void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr)
if (ctx->retval != ERROR_OK) /* On previous out of memory, return */
return;
if (ctx->code_count == ctx->max_code) {
- void *p = realloc(ctx->pracc_list, sizeof(pa_list) * (ctx->max_code + PRACC_BLOCK));
+ void *p = realloc(ctx->pracc_list, sizeof(struct pa_list) * (ctx->max_code + PRACC_BLOCK));
if (p) {
ctx->max_code += PRACC_BLOCK;
ctx->pracc_list = p;
diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h
index 911a69c..30edaec 100644
--- a/src/target/mips32_pracc.h
+++ b/src/target/mips32_pracc.h
@@ -47,10 +47,10 @@
#define PRACC_BLOCK 128 /* 1 Kbyte */
-typedef struct {
+struct pa_list {
uint32_t instr;
uint32_t addr;
-} pa_list;
+};
struct pracc_queue_info {
struct mips_ejtag *ejtag_info;
@@ -59,7 +59,7 @@ struct pracc_queue_info {
int code_count;
int store_count;
int max_code; /* max instructions with currently allocated memory */
- pa_list *pracc_list; /* Code and store addresses at dmseg */
+ struct pa_list *pracc_list; /* Code and store addresses at dmseg */
};
void pracc_queue_init(struct pracc_queue_info *ctx);
diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c
index 3080046..dbad248 100644
--- a/src/target/mips64_pracc.c
+++ b/src/target/mips64_pracc.c
@@ -24,7 +24,7 @@
#define STACK_DEPTH 32
-typedef struct {
+struct mips64_pracc_context {
uint64_t *local_iparam;
unsigned num_iparam;
uint64_t *local_oparam;
@@ -34,7 +34,7 @@ typedef struct {
uint64_t stack[STACK_DEPTH];
unsigned stack_offset;
struct mips_ejtag *ejtag_info;
-} mips64_pracc_context;
+};
static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
{
@@ -61,7 +61,7 @@ static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
return ERROR_OK;
}
-static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address)
+static int mips64_pracc_exec_read(struct mips64_pracc_context *ctx, uint64_t address)
{
struct mips_ejtag *ejtag_info = ctx->ejtag_info;
unsigned offset;
@@ -149,7 +149,7 @@ static int mips64_pracc_exec_read(mips64_pracc_context *ctx, uint64_t address)
return jtag_execute_queue();
}
-static int mips64_pracc_exec_write(mips64_pracc_context *ctx, uint64_t address)
+static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t address)
{
uint32_t ejtag_ctrl;
uint64_t data;
@@ -214,7 +214,7 @@ int mips64_pracc_exec(struct mips_ejtag *ejtag_info,
{
uint32_t ejtag_ctrl;
uint64_t address = 0, address_prev = 0, data;
- mips64_pracc_context ctx;
+ struct mips64_pracc_context ctx;
int retval;
int pass = 0;
bool first_time_call = true;
diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c
index 4b049fb..d4c019f 100644
--- a/src/target/mips_ejtag.c
+++ b/src/target/mips_ejtag.c
@@ -268,7 +268,7 @@ error:
int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info)
{
- pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0};
+ struct pa_list pracc_list = {.instr = MIPS32_DRET(ejtag_info->isa), .addr = 0};
struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = &pracc_list, .code_count = 1, .store_count = 0};
/* execute our dret instruction */
diff --git a/src/target/oocd_trace.c b/src/target/oocd_trace.c
deleted file mode 100644
index f38916a..0000000
--- a/src/target/oocd_trace.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2007 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "arm.h"
-#include "etm.h"
-#include "oocd_trace.h"
-
-/*
- * This is "proof of concept" code, for prototype hardware:
- * https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html
- */
-
-static int oocd_trace_read_reg(struct oocd_trace *oocd_trace, int reg, uint32_t *value)
-{
- size_t bytes_written, bytes_read, bytes_to_read;
- uint8_t cmd;
-
- cmd = 0x10 | (reg & 0x7);
- bytes_written = write(oocd_trace->tty_fd, &cmd, 1);
- if (bytes_written < 1)
- return ERROR_FAIL;
-
- bytes_to_read = 4;
- while (bytes_to_read > 0) {
- bytes_read = read(oocd_trace->tty_fd, ((uint8_t *)value) + 4 - bytes_to_read, bytes_to_read);
- bytes_to_read -= bytes_read;
- }
-
- LOG_DEBUG("reg #%i: 0x%8.8x", reg, *value);
-
- return ERROR_OK;
-}
-
-static int oocd_trace_write_reg(struct oocd_trace *oocd_trace, int reg, uint32_t value)
-{
- size_t bytes_written;
- uint8_t data[5];
-
- data[0] = 0x18 | (reg & 0x7);
- data[1] = value & 0xff;
- data[2] = (value & 0xff00) >> 8;
- data[3] = (value & 0xff0000) >> 16;
- data[4] = (value & 0xff000000) >> 24;
-
- bytes_written = write(oocd_trace->tty_fd, data, 5);
- if (bytes_written < 5)
- return ERROR_FAIL;
-
- LOG_DEBUG("reg #%i: 0x%8.8x", reg, value);
-
- return ERROR_OK;
-}
-
-static int oocd_trace_read_memory(struct oocd_trace *oocd_trace, uint8_t *data, uint32_t address, uint32_t size)
-{
- size_t bytes_written, bytes_to_read;
- ssize_t bytes_read;
- uint8_t cmd;
-
- oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, address);
- oocd_trace_write_reg(oocd_trace, OOCD_TRACE_SDRAM_COUNTER, size);
-
- cmd = 0x20;
- bytes_written = write(oocd_trace->tty_fd, &cmd, 1);
- if (bytes_written < 1)
- return ERROR_FAIL;
-
- bytes_to_read = size * 16;
- while (bytes_to_read > 0) {
- bytes_read = read(oocd_trace->tty_fd,
- ((uint8_t *)data) + (size * 16) - bytes_to_read, bytes_to_read);
- if (bytes_read < 0)
- LOG_DEBUG("read() returned %zi (%s)", bytes_read, strerror(errno));
- else
- bytes_to_read -= bytes_read;
- }
-
- return ERROR_OK;
-}
-
-static int oocd_trace_init(struct etm_context *etm_ctx)
-{
- uint8_t trash[256];
- struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
- size_t bytes_read;
-
- oocd_trace->tty_fd = open(oocd_trace->tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
-
- if (oocd_trace->tty_fd < 0) {
- LOG_ERROR("can't open tty");
- return ERROR_ETM_CAPTURE_INIT_FAILED;
- }
-
- /* clear input & output buffers, then switch to "blocking mode" */
- tcflush(oocd_trace->tty_fd, TCOFLUSH);
- tcflush(oocd_trace->tty_fd, TCIFLUSH);
- fcntl(oocd_trace->tty_fd, F_SETFL, fcntl(oocd_trace->tty_fd, F_GETFL) & ~O_NONBLOCK);
-
- tcgetattr(oocd_trace->tty_fd, &oocd_trace->oldtio); /* save current port settings */
-
- bzero(&oocd_trace->newtio, sizeof(oocd_trace->newtio));
- oocd_trace->newtio.c_cflag = CS8 | CLOCAL | CREAD | B2500000;
-
- oocd_trace->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF;
- oocd_trace->newtio.c_oflag = 0;
-
- /* set input mode (non-canonical, no echo,...) */
- oocd_trace->newtio.c_lflag = 0;
-
- cfmakeraw(&oocd_trace->newtio);
- oocd_trace->newtio.c_cc[VTIME] = 1; /* inter-character timer used */
- oocd_trace->newtio.c_cc[VMIN] = 0; /* blocking read until 0 chars received */
-
- tcflush(oocd_trace->tty_fd, TCIFLUSH);
- tcsetattr(oocd_trace->tty_fd, TCSANOW, &oocd_trace->newtio);
-
- /* occasionally one bogus character is left in the input buffer
- * read up any leftover characters to ensure communication is in sync */
- do {
- bytes_read = read(oocd_trace->tty_fd, trash, sizeof(trash));
- if (bytes_read)
- LOG_DEBUG("%zi bytes read", bytes_read);
- } while (bytes_read > 0);
-
- return ERROR_OK;
-}
-
-static trace_status_t oocd_trace_status(struct etm_context *etm_ctx)
-{
- struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
- uint32_t status;
-
- oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
-
- /* if tracing is currently idle, return this information */
- if (etm_ctx->capture_status == TRACE_IDLE)
- return etm_ctx->capture_status;
- else if (etm_ctx->capture_status & TRACE_RUNNING) {
- /* check Full bit to identify an overflow */
- if (status & 0x4)
- etm_ctx->capture_status |= TRACE_OVERFLOWED;
-
- /* check Triggered bit to identify trigger condition */
- if (status & 0x2)
- etm_ctx->capture_status |= TRACE_TRIGGERED;
-
- if (status & 0x1) {
- etm_ctx->capture_status &= ~TRACE_RUNNING;
- etm_ctx->capture_status |= TRACE_COMPLETED;
- }
- }
-
- return etm_ctx->capture_status;
-}
-
-static int oocd_trace_read_trace(struct etm_context *etm_ctx)
-{
- struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
- uint32_t status, address;
- uint32_t first_frame = 0x0;
- uint32_t num_frames = 1048576;
- uint8_t *trace_data;
- uint32_t i;
-
- oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
- oocd_trace_read_reg(oocd_trace, OOCD_TRACE_ADDRESS, &address);
-
- /* check if we overflowed, and adjust first frame of the trace accordingly
- * if we didn't overflow, read only up to the frame that would be written next,
- * i.e. don't read invalid entries
- */
- if (status & 0x4)
- first_frame = address;
- else
- num_frames = address;
-
- /* read data into temporary array for unpacking
- * one frame from OpenOCD + trace corresponds to 16 trace cycles
- */
- trace_data = malloc(sizeof(uint8_t) * num_frames * 16);
- oocd_trace_read_memory(oocd_trace, trace_data, first_frame, num_frames);
-
- if (etm_ctx->trace_depth > 0)
- free(etm_ctx->trace_data);
-
- etm_ctx->trace_depth = num_frames * 16;
- etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth);
-
- for (i = 0; i < num_frames * 16; i++) {
- etm_ctx->trace_data[i].pipestat = (trace_data[i] & 0x7);
- etm_ctx->trace_data[i].packet = (trace_data[i] & 0x78) >> 3;
- etm_ctx->trace_data[i].flags = 0;
-
- if ((trace_data[i] & 0x80) >> 7)
- etm_ctx->trace_data[i].flags |= ETMV1_TRACESYNC_CYCLE;
-
- if (etm_ctx->trace_data[i].pipestat == STAT_TR) {
- etm_ctx->trace_data[i].pipestat = etm_ctx->trace_data[i].packet & 0x7;
- etm_ctx->trace_data[i].flags |= ETMV1_TRIGGER_CYCLE;
- }
- }
-
- free(trace_data);
-
- return ERROR_OK;
-}
-
-static int oocd_trace_start_capture(struct etm_context *etm_ctx)
-{
- struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
- uint32_t control = 0x1; /* 0x1: enabled */
- uint32_t trigger_count;
-
- if (((etm_ctx->control & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL)
- || ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT)) {
- LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode");
- return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
- }
-
- if ((etm_ctx->control & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK)
- control |= 0x2; /* half rate clock, capture at twice the clock rate */
-
- /* OpenOCD + trace holds up to 16 million samples,
- * but trigger counts is set in multiples of 16 */
- trigger_count = (1048576 * /* trigger_percent */ 50) / 100;
-
- /* capturing always starts at address zero */
- oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, 0x0);
- oocd_trace_write_reg(oocd_trace, OOCD_TRACE_TRIGGER_COUNTER, trigger_count);
- oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, control);
-
- /* we're starting a new trace, initialize capture status */
- etm_ctx->capture_status = TRACE_RUNNING;
-
- return ERROR_OK;
-}
-
-static int oocd_trace_stop_capture(struct etm_context *etm_ctx)
-{
- struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv;
-
- /* trace stopped, just clear running flag, but preserve others */
- etm_ctx->capture_status &= ~TRACE_RUNNING;
-
- oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, 0x0);
-
- return ERROR_OK;
-}
-
-COMMAND_HANDLER(handle_oocd_trace_config_command)
-{
- struct target *target;
- struct arm *arm;
-
- if (CMD_ARGC != 2)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- target = get_current_target(CMD_CTX);
- arm = target_to_arm(target);
- if (!is_arm(arm)) {
- command_print(CMD, "current target isn't an ARM");
- return ERROR_FAIL;
- }
-
- if (arm->etm) {
- struct oocd_trace *oocd_trace = malloc(sizeof(struct oocd_trace));
-
- arm->etm->capture_driver_priv = oocd_trace;
- oocd_trace->etm_ctx = arm->etm;
-
- /* copy name of TTY device used to communicate with OpenOCD + trace */
- oocd_trace->tty = strndup(CMD_ARGV[1], 256);
- } else
- LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured");
-
- return ERROR_OK;
-}
-
-COMMAND_HANDLER(handle_oocd_trace_status_command)
-{
- struct target *target;
- struct arm *arm;
- struct oocd_trace *oocd_trace;
- uint32_t status;
-
- target = get_current_target(CMD_CTX);
-
- arm = target_to_arm(target);
- if (!is_arm(arm)) {
- command_print(CMD, "current target isn't an ARM");
- return ERROR_FAIL;
- }
-
- if (!arm->etm) {
- command_print(CMD, "current target doesn't have an ETM configured");
- return ERROR_FAIL;
- }
-
- if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) {
- command_print(CMD, "current target's ETM capture driver isn't 'oocd_trace'");
- return ERROR_FAIL;
- }
-
- oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv;
-
- oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
-
- if (status & 0x8)
- command_print(CMD, "trace clock locked");
- else
- command_print(CMD, "no trace clock");
-
- return ERROR_OK;
-}
-
-COMMAND_HANDLER(handle_oocd_trace_resync_command)
-{
- struct target *target;
- struct arm *arm;
- struct oocd_trace *oocd_trace;
- size_t bytes_written;
- uint8_t cmd_array[1];
-
- target = get_current_target(CMD_CTX);
-
- arm = target_to_arm(target);
- if (!is_arm(arm)) {
- command_print(CMD, "current target isn't an ARM");
- return ERROR_FAIL;
- }
-
- if (!arm->etm) {
- command_print(CMD, "current target doesn't have an ETM configured");
- return ERROR_FAIL;
- }
-
- if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) {
- command_print(CMD, "current target's ETM capture driver isn't 'oocd_trace'");
- return ERROR_FAIL;
- }
-
- oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv;
-
- cmd_array[0] = 0xf0;
-
- bytes_written = write(oocd_trace->tty_fd, cmd_array, 1);
- if (bytes_written < 1)
- return ERROR_FAIL;
-
- command_print(CMD, "requesting traceclock resync");
- LOG_DEBUG("resyncing traceclk pll");
-
- return ERROR_OK;
-}
-
-static const struct command_registration oocd_trace_all_command_handlers[] = {
- {
- .name = "config",
- .handler = handle_oocd_trace_config_command,
- .mode = COMMAND_CONFIG,
- .usage = "<target> <tty>",
- },
- {
- .name = "status",
- .handler = handle_oocd_trace_status_command,
- .mode = COMMAND_EXEC,
- .usage = "",
- .help = "display OpenOCD + trace status",
- },
- {
- .name = "resync",
- .handler = handle_oocd_trace_resync_command,
- .mode = COMMAND_EXEC,
- .usage = "",
- .help = "resync OpenOCD + trace capture clock",
- },
- COMMAND_REGISTRATION_DONE
-};
-static const struct command_registration oocd_trace_command_handlers[] = {
- {
- .name = "oocd_trace",
- .mode = COMMAND_ANY,
- .help = "OpenOCD trace capture driver command group",
- .usage = "",
- .chain = oocd_trace_all_command_handlers,
- },
- COMMAND_REGISTRATION_DONE
-};
-
-struct etm_capture_driver oocd_trace_capture_driver = {
- .name = "oocd_trace",
- .commands = oocd_trace_command_handlers,
- .init = oocd_trace_init,
- .status = oocd_trace_status,
- .start_capture = oocd_trace_start_capture,
- .stop_capture = oocd_trace_stop_capture,
- .read_trace = oocd_trace_read_trace,
-};
diff --git a/src/target/oocd_trace.h b/src/target/oocd_trace.h
deleted file mode 100644
index e7584e4..0000000
--- a/src/target/oocd_trace.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2007 by Dominic Rath *
- * Dominic.Rath@gmx.de *
- * *
- * 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 *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program. If not, see <http://www.gnu.org/licenses/>. *
- ***************************************************************************/
-
-#ifndef OPENOCD_TARGET_OOCD_TRACE_H
-#define OPENOCD_TARGET_OOCD_TRACE_H
-
-#include <termios.h>
-
-/* registers */
-enum {
- OOCD_TRACE_ID = 0x7,
- OOCD_TRACE_ADDRESS = 0x0,
- OOCD_TRACE_TRIGGER_COUNTER = 0x01,
- OOCD_TRACE_CONTROL = 0x2,
- OOCD_TRACE_STATUS = 0x3,
- OOCD_TRACE_SDRAM_COUNTER = 0x4,
-};
-
-/* commands */
-enum {
- OOCD_TRACE_NOP = 0x0,
- OOCD_TRACE_READ_REG = 0x10,
- OOCD_TRACE_WRITE_REG = 0x18,
- OOCD_TRACE_READ_RAM = 0x20,
-/* OOCD_TRACE_WRITE_RAM = 0x28, */
- OOCD_TRACE_RESYNC = 0xf0,
-};
-
-struct oocd_trace {
- struct etm_context *etm_ctx;
- char *tty;
- int tty_fd;
- struct termios oldtio, newtio;
-};
-
-extern struct etm_capture_driver oocd_trace_capture_driver;
-
-#endif /* OPENOCD_TARGET_OOCD_TRACE_H */
diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c
index b4b2566..4dbe635 100644
--- a/src/target/openrisc/jsp_server.c
+++ b/src/target/openrisc/jsp_server.c
@@ -207,8 +207,7 @@ int jsp_init(struct or1k_jtag *jtag_info, char *banner)
jsp_new_connection,
jsp_input,
jsp_connection_closed,
- jsp_service,
- NULL);
+ jsp_service);
}
COMMAND_HANDLER(handle_jsp_port_command)
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index ef05118..4b8b804 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -1918,7 +1918,7 @@ static int riscv_checksum_memory(struct target *target,
struct reg_param reg_params[2];
int retval;
- LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%x", address, count);
+ LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%" PRIx32, address, count);
static const uint8_t riscv32_crc_code[] = {
#include "../../contrib/loaders/checksum/riscv32_crc.inc"
@@ -1929,7 +1929,7 @@ static int riscv_checksum_memory(struct target *target,
static const uint8_t *crc_code;
- int xlen = riscv_xlen(target);
+ unsigned xlen = riscv_xlen(target);
unsigned crc_code_size;
if (xlen == 32) {
crc_code = riscv32_crc_code;
@@ -1991,7 +1991,7 @@ static int riscv_checksum_memory(struct target *target,
target_free_working_area(target, crc_algorithm);
- LOG_DEBUG("checksum=0x%x, result=%d", *checksum, retval);
+ LOG_DEBUG("checksum=0x%" PRIx32 ", result=%d", *checksum, retval);
return retval;
}
diff --git a/src/target/startup.tcl b/src/target/startup.tcl
index ca39b18..a8f78ab 100644
--- a/src/target/startup.tcl
+++ b/src/target/startup.tcl
@@ -179,12 +179,6 @@ proc using_hla {} {
#########
-# Temporary migration aid. May be removed starting in January 2011.
-proc armv4_5 params {
- echo "DEPRECATED! use 'arm $params' not 'armv4_5 $params'"
- arm $params
-}
-
# Target/chain configuration scripts can either execute commands directly
# or define a procedure which is executed once all configuration
# scripts have completed.
@@ -212,14 +206,3 @@ proc init_target_events {} {
# Additionally board config scripts can define a procedure init_board that will be executed after init and init_targets
proc init_board {} {
}
-
-# deprecated target name cmds
-proc cortex_m3 args {
- echo "DEPRECATED! use 'cortex_m' not 'cortex_m3'"
- eval cortex_m $args
-}
-
-proc cortex_a8 args {
- echo "DEPRECATED! use 'cortex_a' not 'cortex_a8'"
- eval cortex_a $args
-}
diff --git a/src/target/target.c b/src/target/target.c
index 86178a0..84c74e5 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -637,7 +637,18 @@ int target_resume(struct target *target, int current, target_addr_t address,
* we poll. The CPU can even halt at the current PC as a result of
* a software breakpoint being inserted by (a bug?) the application.
*/
+ /*
+ * resume() triggers the event 'resumed'. The execution of TCL commands
+ * in the event handler causes the polling of targets. If the target has
+ * already halted for a breakpoint, polling will run the 'halted' event
+ * handler before the pending 'resumed' handler.
+ * Disable polling during resume() to guarantee the execution of handlers
+ * in the correct order.
+ */
+ bool save_poll = jtag_poll_get_enabled();
+ jtag_poll_set_enabled(false);
retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution);
+ jtag_poll_set_enabled(save_poll);
if (retval != ERROR_OK)
return retval;
@@ -4087,7 +4098,7 @@ COMMAND_HANDLER(handle_wp_command)
}
enum watchpoint_rw type = WPT_ACCESS;
- uint32_t addr = 0;
+ target_addr_t addr = 0;
uint32_t length = 0;
uint32_t data_value = 0x0;
uint32_t data_mask = 0xffffffff;
@@ -4117,7 +4128,7 @@ COMMAND_HANDLER(handle_wp_command)
/* fall through */
case 2:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr);
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
break;
default:
@@ -4137,8 +4148,8 @@ COMMAND_HANDLER(handle_rwp_command)
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
- uint32_t addr;
- COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr);
+ target_addr_t addr;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
struct target *target = get_current_target(CMD_CTX);
watchpoint_remove(target, addr);
@@ -4966,6 +4977,11 @@ no_params:
}
if (goi->isconfigure) {
+ /* START_DEPRECATED_TPIU */
+ if (n->value == TARGET_EVENT_TRACE_CONFIG)
+ LOG_INFO("DEPRECATED target event %s", n->name);
+ /* END_DEPRECATED_TPIU */
+
bool replace = true;
if (teap == NULL) {
/* create new */
@@ -5694,15 +5710,6 @@ static int target_create(Jim_GetOptInfo *goi)
/* found */
break;
}
-
- /* check for deprecated name */
- if (target_types[x]->deprecated_name) {
- if (0 == strcmp(cp, target_types[x]->deprecated_name)) {
- /* found */
- LOG_WARNING("target name is deprecated use: \'%s\'", target_types[x]->name);
- break;
- }
- }
}
if (target_types[x] == NULL) {
Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp);
@@ -5742,9 +5749,6 @@ static int target_create(Jim_GetOptInfo *goi)
memcpy(target->type, target_types[x], sizeof(struct target_type));
- /* will be set by "-endian" */
- target->endianness = TARGET_ENDIAN_UNKNOWN;
-
/* default to first core, override with -coreid */
target->coreid = 0;
diff --git a/src/target/target_type.h b/src/target/target_type.h
index 87ef829..f7b4c94 100644
--- a/src/target/target_type.h
+++ b/src/target/target_type.h
@@ -40,7 +40,6 @@ struct target_type {
* field directly, use target_type_name() instead.
*/
const char *name;
- const char *deprecated_name;
/* poll current target status */
int (*poll)(struct target *target);
diff --git a/src/transport/transport.h b/src/transport/transport.h
index 6bf6aac..e04f780 100644
--- a/src/transport/transport.h
+++ b/src/transport/transport.h
@@ -98,7 +98,7 @@ bool transport_is_dapdirect_jtag(void);
bool transport_is_dapdirect_swd(void);
bool transport_is_swim(void);
-#if BUILD_HLADAPTER && !HAVE_JTAG_MINIDRIVER_H
+#if BUILD_HLADAPTER
bool transport_is_hla(void);
#else
static inline bool transport_is_hla(void)