diff options
author | Tim Newsome <tim@sifive.com> | 2021-04-13 11:22:43 -0700 |
---|---|---|
committer | Tim Newsome <tim@sifive.com> | 2021-04-13 11:26:25 -0700 |
commit | 7420382a4d9453bf4bf72f2e42728136f9a3b7bb (patch) | |
tree | 4aa04d3b401b9b9da8c29fda93e6ff23a70b29f1 /src | |
parent | 05e962e03a9642f883c0a91c38409ba89ad4fa7c (diff) | |
parent | 0f06d943366154963c6f5eb70f52e70f64fe5c71 (diff) | |
download | riscv-openocd-7420382a4d9453bf4bf72f2e42728136f9a3b7bb.zip riscv-openocd-7420382a4d9453bf4bf72f2e42728136f9a3b7bb.tar.gz riscv-openocd-7420382a4d9453bf4bf72f2e42728136f9a3b7bb.tar.bz2 |
Merge branch 'master' into from_upstream
Conflicts:
.github/workflows/snapshot.yml
NEWS
configure.ac
contrib/loaders/checksum/riscv_crc.c
jimtcl
src/helper/time_support.h
src/jtag/drivers/arm-jtag-ew.c
src/rtos/FreeRTOS.c
src/target/image.c
src/target/riscv/riscv.c
Change-Id: I043624ba540d4672fc123dddb2066bcb9c6b5a05
Diffstat (limited to 'src')
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, ®num)); - 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, ®num)); - 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] = ®s[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) |