diff options
Diffstat (limited to 'src')
102 files changed, 2767 insertions, 2102 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 6d79cd6..4d1c1a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,8 +17,12 @@ bin_PROGRAMS += %D%/openocd if INTERNAL_JIMTCL %C%_openocd_LDADD += $(top_builddir)/jimtcl/libjim.a else +if HAVE_JIMTCL_PKG_CONFIG +%C%_openocd_LDADD += $(JIMTCL_LIBS) +else %C%_openocd_LDADD += -ljim endif +endif %C%_libopenocd_la_CPPFLAGS = diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index c590081..a6ac906 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -85,6 +85,9 @@ #define SAME_SERIES_51 0x01 #define SAME_SERIES_53 0x03 #define SAME_SERIES_54 0x04 +#define PIC32CXSG_SERIES_41 0x07 +#define PIC32CXSG_SERIES_60 0x00 +#define PIC32CXSG_SERIES_61 0x02 /* Device ID macros */ #define SAMD_GET_PROCESSOR(id) (id >> 28) @@ -148,6 +151,27 @@ static const struct samd_part same54_parts[] = { { 0x03, "SAME54N19A", 512, 192 }, }; +/* See PIC32CX SG41/SG60/SG61 Family Silicon Errata and Datasheet Clarifications + * DS80000985G */ +/* Known PIC32CX-SG41 parts. */ +static const struct samd_part pic32cxsg41_parts[] = { + { 0x00, "PIC32CX1025SG41128", 1024, 256 }, + { 0x01, "PIC32CX1025SG41100", 1024, 256 }, + { 0x02, "PIC32CX1025SG41064", 1024, 256 }, +}; + +/* Known PIC32CX-SG60 parts. */ +static const struct samd_part pic32cxsg60_parts[] = { + { 0x00, "PIC32CX1025SG60128", 1024, 256 }, + { 0x01, "PIC32CX1025SG60100", 1024, 256 }, +}; + +/* Known PIC32CX-SG61 parts. */ +static const struct samd_part pic32cxsg61_parts[] = { + { 0x00, "PIC32CX1025SG61128", 1024, 256 }, + { 0x01, "PIC32CX1025SG61100", 1024, 256 }, +}; + /* Each family of parts contains a parts table in the DEVSEL field of DID. The * processor ID, family ID, and series ID are used to determine which exact * family this is and then we can use the corresponding table. */ @@ -169,6 +193,12 @@ static const struct samd_family samd_families[] = { same53_parts, ARRAY_SIZE(same53_parts) }, { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54, same54_parts, ARRAY_SIZE(same54_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_41, + pic32cxsg41_parts, ARRAY_SIZE(pic32cxsg41_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_60, + pic32cxsg60_parts, ARRAY_SIZE(pic32cxsg60_parts) }, + { SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_61, + pic32cxsg61_parts, ARRAY_SIZE(pic32cxsg61_parts) }, }; struct samd_info { diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index 043494c..207346f 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -709,7 +709,7 @@ static int em357_probe(struct flash_bank *bank) em357_info->ppage_size = 4; - LOG_INFO("flash size = %d KiB", num_pages*page_size/1024); + LOG_INFO("flash size = %d KiB", num_pages * page_size / 1024); free(bank->sectors); diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index fee3644..2d0a753 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -1038,6 +1038,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) bank->target = k_chip->target; bank->driver = &kinetis_flash; bank->default_padded_value = bank->erased_value = 0xff; + bank->minimal_write_gap = FLASH_WRITE_GAP_SECTOR; snprintf(name, sizeof(name), "%s.%s%s", base_name, class, num); diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index f07433e..5cb552a 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -117,20 +117,24 @@ struct nrf5_map { struct nrf5_info { unsigned int refcount; + bool chip_probed; struct nrf5_bank { struct nrf5_info *chip; bool probed; } bank[2]; + struct target *target; - /* chip identification stored in nrf5_probe() for use in nrf5_info() */ + /* chip identification stored in nrf5_probe_chip() + * for use in nrf5_info() and nrf5_setup_bank() */ bool ficr_info_valid; struct nrf52_ficr_info ficr_info; const struct nrf5_device_spec *spec; uint16_t hwid; enum nrf5_features features; - unsigned int flash_size_kb; + uint32_t flash_page_size; + uint32_t flash_num_sectors; unsigned int ram_size_kb; const struct nrf5_map *map; @@ -341,16 +345,19 @@ const struct flash_driver nrf5_flash, nrf51_flash; static bool nrf5_bank_is_probed(const struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); - return nbank->probed; } -static bool nrf5_bank_is_uicr(const struct nrf5_bank *nbank) +static bool nrf5_chip_is_probed(const struct flash_bank *bank) { + struct nrf5_bank *nbank = bank->driver_priv; struct nrf5_info *chip = nbank->chip; - assert(chip); + return chip->chip_probed; +} +static bool nrf5_bank_is_uicr(const struct nrf5_bank *nbank) +{ + struct nrf5_info *chip = nbank->chip; return nbank == &chip->bank[1]; } @@ -470,9 +477,7 @@ static int nrf51_protect_check_clenr0(struct flash_bank *bank) uint32_t clenr0; struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); res = target_read_u32(chip->target, NRF51_FICR_CLENR0, &clenr0); @@ -501,9 +506,7 @@ static int nrf51_protect_check_clenr0(struct flash_bank *bank) static int nrf52_protect_check_bprot(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); static uint32_t nrf5_bprot_offsets[4] = { 0x600, 0x604, 0x610, 0x614 }; uint32_t bprot_reg = 0; @@ -528,9 +531,7 @@ static int nrf52_protect_check_bprot(struct flash_bank *bank) static int nrf5_protect_check(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); /* UICR cannot be write protected so just return early */ if (nrf5_bank_is_uicr(nbank)) @@ -554,9 +555,7 @@ static int nrf51_protect_clenr0(struct flash_bank *bank, int set, unsigned int f uint32_t clenr0, ppfc; struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); if (first != 0) { LOG_ERROR("Code region 0 must start at the beginning of the bank"); @@ -614,9 +613,7 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); /* UICR cannot be write protected so just bail out early */ if (nrf5_bank_is_uicr(nbank)) { @@ -701,16 +698,15 @@ static int nrf5_get_chip_type_str(const struct nrf5_info *chip, char *buf, unsig static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); char chip_type_str[256]; if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; + unsigned int flash_size_kb = chip->flash_num_sectors * chip->flash_page_size / 1024; command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM", - chip_type_str, chip->flash_size_kb, chip->ram_size_kb); + chip_type_str, flash_size_kb, chip->ram_size_kb); return ERROR_OK; } @@ -838,14 +834,12 @@ static int nrf51_get_ram_size(struct target *target, uint32_t *ram_size) return res; } -static int nrf5_probe(struct flash_bank *bank) +static int nrf5_probe_chip(struct flash_bank *bank) { int res = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); struct target *target = chip->target; chip->spec = NULL; @@ -968,9 +962,8 @@ static int nrf5_probe(struct flash_bank *bank) } /* The value stored in FICR CODEPAGESIZE is the number of bytes in one page of FLASH. */ - uint32_t flash_page_size; res = target_read_u32(chip->target, ficr_base + ficr_offsets->codepagesize, - &flash_page_size); + &chip->flash_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); return res; @@ -978,69 +971,93 @@ static int nrf5_probe(struct flash_bank *bank) /* Note the register name is misleading, * FICR CODESIZE is the number of pages in flash memory, not the number of bytes! */ - uint32_t num_sectors; res = target_read_u32(chip->target, ficr_base + ficr_offsets->codesize, - &num_sectors); + &chip->flash_num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; } - chip->flash_size_kb = num_sectors * flash_page_size / 1024; + char chip_type_str[256]; + if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + return ERROR_FAIL; - if (!chip->bank[0].probed && !chip->bank[1].probed) { - char chip_type_str[256]; - if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) - return ERROR_FAIL; - const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); - LOG_INFO("%s%s %ukB Flash, %ukB RAM", - device_is_unknown ? "Unknown device: " : "", - chip_type_str, - chip->flash_size_kb, - chip->ram_size_kb); - } + unsigned int flash_size_kb = chip->flash_num_sectors * chip->flash_page_size / 1024; + const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid); + LOG_INFO("%s%s %ukB Flash, %ukB RAM", + device_is_unknown ? "Unknown device: " : "", + chip_type_str, + flash_size_kb, + chip->ram_size_kb); - free(bank->sectors); + chip->chip_probed = true; + return ERROR_OK; +} + +static int nrf5_setup_bank(struct flash_bank *bank) +{ + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; if (bank->base == chip->map->flash_base) { + unsigned int flash_size_kb = chip->flash_num_sectors * chip->flash_page_size / 1024; /* Sanity check */ - if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb) + if (chip->spec && flash_size_kb != chip->spec->flash_size_kb) LOG_WARNING("Chip's reported Flash capacity does not match expected one"); - if (chip->ficr_info_valid && chip->flash_size_kb != chip->ficr_info.flash) + if (chip->ficr_info_valid && flash_size_kb != chip->ficr_info.flash) LOG_WARNING("Chip's reported Flash capacity does not match FICR INFO.FLASH"); - bank->num_sectors = num_sectors; - bank->size = num_sectors * flash_page_size; + bank->num_sectors = chip->flash_num_sectors; + bank->size = chip->flash_num_sectors * chip->flash_page_size; - bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + bank->sectors = alloc_block_array(0, chip->flash_page_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; chip->bank[0].probed = true; - } else { + } else if (bank->base == chip->map->uicr_base) { /* UICR bank */ bank->num_sectors = 1; - bank->size = flash_page_size; + bank->size = chip->flash_page_size; - bank->sectors = alloc_block_array(0, flash_page_size, num_sectors); + bank->sectors = alloc_block_array(0, chip->flash_page_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; bank->sectors[0].is_protected = 0; chip->bank[1].probed = true; + } else { + LOG_ERROR("Invalid nRF bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FLASH_BANK_INVALID; } return ERROR_OK; } +static int nrf5_probe(struct flash_bank *bank) +{ + /* probe always reads actual info from the device */ + int res = nrf5_probe_chip(bank); + if (res != ERROR_OK) + return res; + + return nrf5_setup_bank(bank); +} + static int nrf5_auto_probe(struct flash_bank *bank) { if (nrf5_bank_is_probed(bank)) return ERROR_OK; - return nrf5_probe(bank); + if (!nrf5_chip_is_probed(bank)) { + int res = nrf5_probe_chip(bank); + if (res != ERROR_OK) + return res; + } + + return nrf5_setup_bank(bank); } @@ -1214,9 +1231,7 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, } struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); assert(offset % 4 == 0); assert(count % 4 == 0); @@ -1276,9 +1291,7 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, } struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); /* UICR CLENR0 based protection used on nRF51 prevents erase * absolutely silently. NVMC has no flag to indicate the protection @@ -1322,7 +1335,6 @@ error: static void nrf5_free_driver_priv(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; if (!chip) return; @@ -1372,8 +1384,8 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) case NRF53NET_UICR_BASE: break; default: - LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); - return ERROR_FAIL; + LOG_ERROR("Invalid nRF bank address " TARGET_ADDR_FMT, bank->base); + return ERROR_FLASH_BANK_INVALID; } chip = nrf5_get_chip(bank->target); @@ -1418,17 +1430,13 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) if (res != ERROR_OK) return res; - assert(bank); - if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct nrf5_bank *nbank = bank->driver_priv; - assert(nbank); struct nrf5_info *chip = nbank->chip; - assert(chip); if (chip->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 859b3e9..47f3ac6 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -223,6 +223,8 @@ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_ { int hr; uint32_t reg_val; + struct armv7m_common *armv7m = target_to_armv7m(target); + bool is_cm0 = (armv7m->arm.arch == ARM_ARCH_V6M); struct timeout to; timeout_init(&to, IPC_TIMEOUT_MS); @@ -244,7 +246,7 @@ static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_ return ERROR_OK; } - if (target->coreid) { + if (!is_cm0) { LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. " "Please perform all Flash-related operations via CM0+ target on dual-core devices."); } @@ -886,7 +888,8 @@ static int handle_reset_halt(struct target *target) { int hr; uint32_t reset_addr; - bool is_cm0 = (target->coreid == 0); + struct armv7m_common *armv7m = target_to_armv7m(target); + bool is_cm0 = (armv7m->arm.arch == ARM_ARCH_V6M); /* Halt target device */ if (target->state != TARGET_HALTED) { diff --git a/src/flash/nor/sfdp.c b/src/flash/nor/sfdp.c index 5bfb541..917f162 100644 --- a/src/flash/nor/sfdp.c +++ b/src/flash/nor/sfdp.c @@ -12,7 +12,6 @@ #include "spi.h" #include "sfdp.h" -#define SFDP_MAGIC 0x50444653 #define SFDP_ACCESS_PROT 0xFF #define SFDP_BASIC_FLASH 0xFF00 #define SFDP_4BYTE_ADDR 0xFF84 @@ -100,7 +99,7 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, goto err; for (k = 0; k < nph; k++) { - uint8_t words = (pheaders[k].revision >> 24) & 0xFF; + unsigned int words = (pheaders[k].revision >> 24) & 0xFF; uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF); uint32_t ptr = pheaders[k].ptr & 0xFFFFFF; diff --git a/src/flash/nor/sfdp.h b/src/flash/nor/sfdp.h index 1c9af32..0d43519 100644 --- a/src/flash/nor/sfdp.h +++ b/src/flash/nor/sfdp.h @@ -7,6 +7,8 @@ #ifndef OPENOCD_FLASH_NOR_SFDP_H #define OPENOCD_FLASH_NOR_SFDP_H +#define SFDP_MAGIC 0x50444653 + /* per JESD216D 'addr' is *byte* based but must be word aligned, * 'buffer' is word based, word aligned and always little-endian encoded, * in the flash, 'addr_len' is 3 or 4, 'dummy' ***usually*** 8 @@ -16,7 +18,7 @@ * * buffer contents is supposed to be returned in ***host*** endianness */ typedef int (*read_sfdp_block_t)(struct flash_bank *bank, uint32_t addr, - uint32_t words, uint32_t *buffer); + unsigned int words, uint32_t *buffer); extern int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, read_sfdp_block_t read_sfdp_block); diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 0399385..9235dd7 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -120,6 +120,12 @@ * http://www.st.com/resource/en/reference_manual/dm00346336.pdf */ +/* STM32U5xxx series for reference. + * + * RM0456 (STM32U5xx) + * http://www.st.com/resource/en/reference_manual/dm00477635.pdf + */ + /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 @@ -344,9 +350,17 @@ static const struct stm32l4_rev stm32g49_g4axx_revs[] = { { 0x1000, "A" }, }; +static const struct stm32l4_rev stm32u53_u54xx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + static const struct stm32l4_rev stm32u57_u58xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" }, - { 0x2001, "X" }, { 0x3000, "C" }, + { 0x2001, "X" }, { 0x3000, "C" }, { 0x3001, "W" }, +}; + +static const struct stm32l4_rev stm32u59_u5axx_revs[] = { + { 0x3001, "X" }, }; static const struct stm32l4_rev stm32wba5x_revs[] = { @@ -419,6 +433,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { + .id = DEVID_STM32U53_U54XX, + .revs = stm32u53_u54xx_revs, + .num_revs = ARRAY_SIZE(stm32u53_u54xx_revs), + .device_str = "STM32U535/U545", + .max_flash_size_kb = 512, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, + { .id = DEVID_STM32G05_G06XX, .revs = stm32g05_g06xx_revs, .num_revs = ARRAY_SIZE(stm32g05_g06xx_revs), @@ -575,6 +601,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_size = 1024, }, { + .id = DEVID_STM32U59_U5AXX, + .revs = stm32u59_u5axx_revs, + .num_revs = ARRAY_SIZE(stm32u59_u5axx_revs), + .device_str = "STM32U59/U5Axx", + .max_flash_size_kb = 4096, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, + { .id = DEVID_STM32U57_U58XX, .revs = stm32u57_u58xx_revs, .num_revs = ARRAY_SIZE(stm32u57_u58xx_revs), @@ -2000,10 +2038,22 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->bank1_sectors = num_pages / 2; } break; + case DEVID_STM32U53_U54XX: case DEVID_STM32U57_U58XX: - /* if flash size is max (2M) the device is always dual bank - * otherwise check DUALBANK + case DEVID_STM32U59_U5AXX: + /* according to RM0456 Rev 4, Chapter 7.3.1 and 7.9.13 + * U53x/U54x have 512K max flash size: + * 512K variants are always in DUAL BANK mode + * 256K and 128K variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set + * U57x/U58x have 2M max flash size: + * 2M variants are always in DUAL BANK mode + * 1M variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set + * U59x/U5Ax have 4M max flash size: + * 4M variants are always in DUAL BANK mode + * 2M variants can be in DUAL BANK mode if FLASH_OPTR:DUALBANK is set + * Note: flash banks are always contiguous */ + page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; @@ -2572,7 +2622,7 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .name = "option_write", .handler = stm32l4_handle_option_write_command, .mode = COMMAND_EXEC, - .usage = "bank_id reg_offset value mask", + .usage = "bank_id reg_offset value [mask]", .help = "Write device option bit fields with provided value.", }, { diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 3dc0909..5f3bc26 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -89,6 +89,7 @@ #define DEVID_STM32L43_L44XX 0x435 #define DEVID_STM32C01XX 0x443 #define DEVID_STM32C03XX 0x453 +#define DEVID_STM32U53_U54XX 0x455 #define DEVID_STM32G05_G06XX 0x456 #define DEVID_STM32G07_G08XX 0x460 #define DEVID_STM32L49_L4AXX 0x461 @@ -102,6 +103,7 @@ #define DEVID_STM32L4P_L4QXX 0x471 #define DEVID_STM32L55_L56XX 0x472 #define DEVID_STM32G49_G4AXX 0x479 +#define DEVID_STM32U59_U5AXX 0x481 #define DEVID_STM32U57_U58XX 0x482 #define DEVID_STM32WBA5X 0x492 #define DEVID_STM32WB1XX 0x494 diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index a1e1d34..df58f6c 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -1807,7 +1807,7 @@ err: /* Read SFDP parameter block */ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, - uint32_t words, uint32_t *buffer) + unsigned int words, uint32_t *buffer) { struct target *target = bank->target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; @@ -1848,7 +1848,7 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, } } - LOG_DEBUG("%s: addr=0x%08" PRIx32 " words=0x%08" PRIx32 " dummy=%u", + LOG_DEBUG("%s: addr=0x%08" PRIx32 " words=0x%08x dummy=%u", __func__, addr, words, *dummy); /* Abort any previous operation */ diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index 654f201..0dd84ef 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -5,7 +5,7 @@ # # program utility proc # usage: program filename -# optional args: verify, reset, exit and address +# optional args: preverify, verify, reset, exit and address # lappend _telnet_autocomplete_skip program_error @@ -101,8 +101,8 @@ proc program {filename args} { return } -add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional" -add_usage_text program "<filename> \[address\] \[pre-verify\] \[verify\] \[reset\] \[exit\]" +add_help_text program "write an image to flash, address is only required for binary images. preverify, verify, reset, exit are optional" +add_usage_text program "<filename> \[address\] \[preverify\] \[verify\] \[reset\] \[exit\]" # stm32[f0x|f3x] uses the same flash driver as the stm32f1x proc stm32f0x args { eval stm32f1x $args } diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c index 5f38b43..a7ca5af 100644 --- a/src/helper/binarybuffer.c +++ b/src/helper/binarybuffer.c @@ -57,20 +57,20 @@ void *buf_cpy(const void *from, void *_to, unsigned size) return _to; } -static bool buf_cmp_masked(uint8_t a, uint8_t b, uint8_t m) +static bool buf_eq_masked(uint8_t a, uint8_t b, uint8_t m) { - return (a & m) != (b & m); + return (a & m) == (b & m); } -static bool buf_cmp_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing) +static bool buf_eq_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing) { uint8_t mask = (1 << trailing) - 1; - return buf_cmp_masked(a, b, mask & m); + return buf_eq_masked(a, b, mask & m); } -bool buf_cmp(const void *_buf1, const void *_buf2, unsigned size) +bool buf_eq(const void *_buf1, const void *_buf2, unsigned size) { if (!_buf1 || !_buf2) - return _buf1 != _buf2; + return _buf1 == _buf2; unsigned last = size / 8; if (memcmp(_buf1, _buf2, last) != 0) @@ -78,31 +78,30 @@ bool buf_cmp(const void *_buf1, const void *_buf2, unsigned size) unsigned trailing = size % 8; if (!trailing) - return false; + return true; const uint8_t *buf1 = _buf1, *buf2 = _buf2; - return buf_cmp_trailing(buf1[last], buf2[last], 0xff, trailing); + return buf_eq_trailing(buf1[last], buf2[last], 0xff, trailing); } -bool buf_cmp_mask(const void *_buf1, const void *_buf2, +bool buf_eq_mask(const void *_buf1, const void *_buf2, const void *_mask, unsigned size) { if (!_buf1 || !_buf2) - return _buf1 != _buf2 || _buf1 != _mask; + return _buf1 == _buf2 && _buf1 == _mask; const uint8_t *buf1 = _buf1, *buf2 = _buf2, *mask = _mask; unsigned last = size / 8; for (unsigned i = 0; i < last; i++) { - if (buf_cmp_masked(buf1[i], buf2[i], mask[i])) - return true; + if (!buf_eq_masked(buf1[i], buf2[i], mask[i])) + return false; } unsigned trailing = size % 8; if (!trailing) - return false; - return buf_cmp_trailing(buf1[last], buf2[last], mask[last], trailing); + return true; + return buf_eq_trailing(buf1[last], buf2[last], mask[last], trailing); } - void *buf_set_ones(void *_buf, unsigned size) { uint8_t *buf = _buf; @@ -176,19 +175,6 @@ uint32_t flip_u32(uint32_t value, unsigned int num) return c; } -static int ceil_f_to_u32(float x) -{ - if (x < 0) /* return zero for negative numbers */ - return 0; - - uint32_t y = x; /* cut off fraction */ - - if ((x - y) > 0.0) /* if there was a fractional part, increase by one */ - y++; - - return y; -} - char *buf_to_hex_str(const void *_buf, unsigned buf_len) { unsigned len_bytes = DIV_ROUND_UP(buf_len, 8); @@ -206,94 +192,96 @@ char *buf_to_hex_str(const void *_buf, unsigned buf_len) return str; } -/** identify radix, and skip radix-prefix (0, 0x or 0X) */ -static void str_radix_guess(const char **_str, unsigned *_str_len, - unsigned *_radix) -{ - unsigned radix = *_radix; - if (radix != 0) - return; - const char *str = *_str; - unsigned str_len = *_str_len; - if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { - radix = 16; - str += 2; - str_len -= 2; - } else if ((str[0] == '0') && (str_len != 1)) { - radix = 8; - str += 1; - str_len -= 1; - } else - radix = 10; - *_str = str; - *_str_len = str_len; - *_radix = radix; -} - -int str_to_buf(const char *str, unsigned str_len, - void *_buf, unsigned buf_len, unsigned radix) +/* + * TCL standard prefix is '0b', '0o', '0d' or '0x' respectively for binary, + * octal, decimal or hexadecimal. + * The prefix '0' is interpreted by TCL <= 8.6 as octal, but is ignored and + * interpreted as part of a decimal number by JimTCL and by TCL >= 9. + */ +int str_to_buf(const char *str, void *_buf, unsigned int buf_bitsize) { - str_radix_guess(&str, &str_len, &radix); - - float factor; - if (radix == 16) - factor = 0.5; /* log(16) / log(256) = 0.5 */ - else if (radix == 10) - factor = 0.41524; /* log(10) / log(256) = 0.41524 */ - else if (radix == 8) - factor = 0.375; /* log(8) / log(256) = 0.375 */ - else - return 0; + assert(str); + assert(_buf); + assert(buf_bitsize > 0); - /* copy to zero-terminated buffer */ - char *charbuf = strndup(str, str_len); - - /* number of digits in base-256 notation */ - unsigned b256_len = ceil_f_to_u32(str_len * factor); - uint8_t *b256_buf = calloc(b256_len, 1); + uint8_t *buf = _buf; + unsigned int radix = 10; /* default when no prefix */ + + if (str[0] == '0') { + switch (str[1]) { + case 'b': + case 'B': + radix = 2; + str += 2; + break; + case 'o': + case 'O': + radix = 8; + str += 2; + break; + case 'd': + case 'D': + radix = 10; + str += 2; + break; + case 'x': + case 'X': + radix = 16; + str += 2; + break; + default: + break; + } + } - /* go through zero terminated buffer - * input digits (ASCII) */ - unsigned i; - for (i = 0; charbuf[i]; i++) { - uint32_t tmp = charbuf[i]; - if ((tmp >= '0') && (tmp <= '9')) - tmp = (tmp - '0'); - else if ((tmp >= 'a') && (tmp <= 'f')) - tmp = (tmp - 'a' + 10); - else if ((tmp >= 'A') && (tmp <= 'F')) - tmp = (tmp - 'A' + 10); - else - continue; /* skip characters other than [0-9,a-f,A-F] */ + const size_t str_len = strlen(str); + if (str_len == 0) + return ERROR_INVALID_NUMBER; + + const size_t buf_len = DIV_ROUND_UP(buf_bitsize, 8); + memset(buf, 0, buf_len); + + /* Go through the zero-terminated buffer + * of input digits (ASCII) */ + for (; *str; str++) { + unsigned int tmp; + const char c = *str; + + if ((c >= '0') && (c <= '9')) { + tmp = c - '0'; + } else if ((c >= 'a') && (c <= 'f')) { + tmp = c - 'a' + 10; + } else if ((c >= 'A') && (c <= 'F')) { + tmp = c - 'A' + 10; + } else { + /* Characters other than [0-9,a-f,A-F] are invalid */ + return ERROR_INVALID_NUMBER; + } + /* Error on invalid digit for current radix */ if (tmp >= radix) - continue; /* skip digits invalid for the current radix */ + return ERROR_INVALID_NUMBER; - /* base-256 digits */ - for (unsigned j = 0; j < b256_len; j++) { - tmp += (uint32_t)b256_buf[j] * radix; - b256_buf[j] = (uint8_t)(tmp & 0xFF); + /* Add the current digit (tmp) to the intermediate result in buf */ + for (unsigned int j = 0; j < buf_len; j++) { + tmp += buf[j] * radix; + buf[j] = tmp & 0xFFu; tmp >>= 8; } + /* buf should be large enough to contain the whole result. */ + if (tmp != 0) + return ERROR_NUMBER_EXCEEDS_BUFFER; } - uint8_t *buf = _buf; - for (unsigned j = 0; j < DIV_ROUND_UP(buf_len, 8); j++) { - if (j < b256_len) - buf[j] = b256_buf[j]; - else - buf[j] = 0; + /* Check the partial most significant byte */ + if (buf_bitsize % 8) { + const uint8_t mask = 0xFFu << (buf_bitsize % 8); + if ((buf[buf_len - 1] & mask) != 0x0) + return ERROR_NUMBER_EXCEEDS_BUFFER; } - /* mask out bits that don't belong to the buffer */ - if (buf_len % 8) - buf[(buf_len / 8)] &= 0xff >> (8 - (buf_len % 8)); - - free(b256_buf); - free(charbuf); - - return i; + return ERROR_OK; } void bit_copy_queue_init(struct bit_copy_queue *q) diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index 3446296..ed13b98 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -14,6 +14,9 @@ #include <helper/list.h> #include <helper/types.h> +#define ERROR_INVALID_NUMBER (-1700) +#define ERROR_NUMBER_EXCEEDS_BUFFER (-1701) + /** @file * Support functions to access arbitrary bits in a byte array */ @@ -31,6 +34,7 @@ static inline void buf_set_u32(uint8_t *_buffer, unsigned first, unsigned num, uint32_t value) { + assert(num >= 1 && num <= 32); uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { @@ -61,6 +65,7 @@ static inline void buf_set_u32(uint8_t *_buffer, static inline void buf_set_u64(uint8_t *_buffer, unsigned first, unsigned num, uint64_t value) { + assert(num >= 1 && num <= 64); uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { @@ -99,6 +104,7 @@ static inline void buf_set_u64(uint8_t *_buffer, static inline uint32_t buf_get_u32(const uint8_t *_buffer, unsigned first, unsigned num) { + assert(num >= 1 && num <= 32); const uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { @@ -128,6 +134,7 @@ static inline uint32_t buf_get_u32(const uint8_t *_buffer, static inline uint64_t buf_get_u64(const uint8_t *_buffer, unsigned first, unsigned num) { + assert(num >= 1 && num <= 64); const uint8_t *buffer = _buffer; if ((num == 32) && (first == 0)) { @@ -165,8 +172,8 @@ static inline uint64_t buf_get_u64(const uint8_t *_buffer, */ uint32_t flip_u32(uint32_t value, unsigned width); -bool buf_cmp(const void *buf1, const void *buf2, unsigned size); -bool buf_cmp_mask(const void *buf1, const void *buf2, +bool buf_eq(const void *buf1, const void *buf2, unsigned size); +bool buf_eq_mask(const void *buf1, const void *buf2, const void *mask, unsigned size); /** @@ -189,8 +196,17 @@ void *buf_set_ones(void *buf, unsigned size); void *buf_set_buf(const void *src, unsigned src_start, void *dst, unsigned dst_start, unsigned len); -int str_to_buf(const char *str, unsigned len, - void *bin_buf, unsigned buf_size, unsigned radix); +/** + * Parse an unsigned number (provided as a zero-terminated string) + * into a bit buffer whose size is buf_len bits. The base of the + * number is detected between decimal, hexadecimal and octal. + * @param str Input number, zero-terminated string + * @param _buf Output buffer, allocated by the caller + * @param buf_bitsize Output buffer size in bits + * @returns Error on invalid or overflowing number + */ +int str_to_buf(const char *str, void *_buf, unsigned int buf_bitsize); + char *buf_to_hex_str(const void *buf, unsigned size); /* read a uint32_t from a buffer in target memory endianness */ diff --git a/src/helper/command.c b/src/helper/command.c index a775c73..9078693 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -1360,6 +1360,27 @@ int command_parse_bool_arg(const char *in, bool *out) return ERROR_COMMAND_SYNTAX_ERROR; } +COMMAND_HELPER(command_parse_str_to_buf, const char *str, void *buf, unsigned int buf_len) +{ + assert(str); + assert(buf); + + int ret = str_to_buf(str, buf, buf_len); + if (ret == ERROR_OK) + return ret; + + /* Provide a clear error message to the user */ + if (ret == ERROR_INVALID_NUMBER) { + command_print(CMD, "'%s' is not a valid number", str); + } else if (ret == ERROR_NUMBER_EXCEEDS_BUFFER) { + command_print(CMD, "Number %s exceeds %u bits", str, buf_len); + } else { + command_print(CMD, "Could not parse number '%s'", str); + } + + return ERROR_COMMAND_ARGUMENT_INVALID; +} + COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) { switch (CMD_ARGC) { diff --git a/src/helper/command.h b/src/helper/command.h index fc26dda..b224bd0 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -517,6 +517,15 @@ DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); int command_parse_bool_arg(const char *in, bool *out); COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label); +/** + * Parse a number (base 10, base 16 or base 8) and store the result + * into a bit buffer. Use the prefixes '0' and '0x' for base 8 and 16, + * otherwise defaults to base 10. + * + * In case of parsing error, a user-readable error message is produced. + */ +COMMAND_HELPER(command_parse_str_to_buf, const char *str, void *buf, unsigned int buf_len); + /** parses an on/off command argument */ #define COMMAND_PARSE_ON_OFF(in, out) \ COMMAND_PARSE_BOOL(in, out, "on", "off") diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index 958dc4e..b74cda8 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -8,9 +8,7 @@ * identification code list, please visit the JEDEC website at www.jedec.org . */ -/* This file is aligned to revision JEP106BI January 2024. */ - -/* "NXP (Philips)" is reported below, while missing since JEP106BG */ +/* This file is aligned to revision JEP106BJ.01 July 2024. */ [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", @@ -30,7 +28,7 @@ [0][0x10 - 1] = "NEC", [0][0x11 - 1] = "RCA", [0][0x12 - 1] = "Raytheon", -[0][0x13 - 1] = "Conexant (Rockwell)", +[0][0x13 - 1] = "Synaptics", [0][0x14 - 1] = "Seeq", [0][0x15 - 1] = "NXP (Philips)", [0][0x16 - 1] = "Synertek", @@ -1045,7 +1043,7 @@ [8][0x17 - 1] = "Axell Corporation", [8][0x18 - 1] = "Essencore Limited", [8][0x19 - 1] = "Phytium", -[8][0x1a - 1] = "Xi'an UniIC Semiconductors Co Ltd", +[8][0x1a - 1] = "UniIC Semiconductors Co Ltd", [8][0x1b - 1] = "Ambiq Micro", [8][0x1c - 1] = "eveRAM Technology Inc", [8][0x1d - 1] = "Infomax", @@ -1452,7 +1450,7 @@ [11][0x34 - 1] = "Acacia Communications", [11][0x35 - 1] = "Beijinjinshengyihe Technology Co Ltd", [11][0x36 - 1] = "Zyzyx", -[11][0x37 - 1] = "T-HEAD Semiconductor Co Ltd", +[11][0x37 - 1] = "C-SKY Microsystems Co Ltd", [11][0x38 - 1] = "Shenzhen Hystou Technology Co Ltd", [11][0x39 - 1] = "Syzexion", [11][0x3a - 1] = "Kembona", @@ -1938,4 +1936,31 @@ [15][0x22 - 1] = "SkyeChip", [15][0x23 - 1] = "Guangzhou Kaishile Trading Co Ltd", [15][0x24 - 1] = "Jing Pai Digital Technology (Shenzhen) Co", +[15][0x25 - 1] = "Memoritek", +[15][0x26 - 1] = "Zhejiang Hikstor Technology Co Ltd", +[15][0x27 - 1] = "Memoritek PTE Ltd", +[15][0x28 - 1] = "Longsailing Semiconductor Co Ltd", +[15][0x29 - 1] = "LX Semicon", +[15][0x2a - 1] = "Shenzhen Techwinsemi Technology Co Ltd", +[15][0x2b - 1] = "AOC", +[15][0x2c - 1] = "GOEPEL Electronic GmbH", +[15][0x2d - 1] = "Shenzhen G-Bong Technology Co Ltd", +[15][0x2e - 1] = "Openedges Technology Inc", +[15][0x2f - 1] = "EA Semi Shangahi Limited", +[15][0x30 - 1] = "EMBCORF", +[15][0x31 - 1] = "Shenzhen MicroBT Electronics Technology", +[15][0x32 - 1] = "Shanghai Simor Chip Semiconductor Co", +[15][0x33 - 1] = "Xllbyte", +[15][0x34 - 1] = "Guangzhou Maidite Electronics Co Ltd.", +[15][0x35 - 1] = "Zhejiang Changchun Technology Co Ltd", +[15][0x36 - 1] = "Beijing Cloud Security Technology Co Ltd", +[15][0x37 - 1] = "SSTC Technology and Distribution Inc", +[15][0x38 - 1] = "Shenzhen Panmin Technology Co Ltd", +[15][0x39 - 1] = "ITE Tech Inc", +[15][0x3a - 1] = "Beijing Zettastone Technology Co Ltd", +[15][0x3b - 1] = "Powerchip Micro Device", +[15][0x3c - 1] = "Shenzhen Ysemi Computing Co Ltd", +[15][0x3d - 1] = "Shenzhen Titan Micro Electronics Co Ltd", +[15][0x3e - 1] = "Shenzhen Macroflash Technology Co Ltd", +[15][0x3f - 1] = "Advantech Group", /* EOF */ diff --git a/src/jtag/commands.c b/src/jtag/commands.c index a60684c..1bca4e8 100644 --- a/src/jtag/commands.c +++ b/src/jtag/commands.c @@ -166,10 +166,9 @@ void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src) enum scan_type jtag_scan_type(const struct scan_command *cmd) { - int i; int type = 0; - for (i = 0; i < cmd->num_fields; i++) { + for (unsigned int i = 0; i < cmd->num_fields; i++) { if (cmd->fields[i].in_value) type |= SCAN_IN; if (cmd->fields[i].out_value) @@ -179,13 +178,12 @@ enum scan_type jtag_scan_type(const struct scan_command *cmd) return type; } -int jtag_scan_size(const struct scan_command *cmd) +unsigned int jtag_scan_size(const struct scan_command *cmd) { - int bit_count = 0; - int i; + unsigned int bit_count = 0; /* count bits in scan command */ - for (i = 0; i < cmd->num_fields; i++) + for (unsigned int i = 0; i < cmd->num_fields; i++) bit_count += cmd->fields[i].num_bits; return bit_count; @@ -193,19 +191,16 @@ int jtag_scan_size(const struct scan_command *cmd) int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer) { - int bit_count = 0; - int i; - - bit_count = jtag_scan_size(cmd); + unsigned int bit_count = jtag_scan_size(cmd); *buffer = calloc(1, DIV_ROUND_UP(bit_count, 8)); bit_count = 0; - LOG_DEBUG_IO("%s num_fields: %i", + LOG_DEBUG_IO("%s num_fields: %u", cmd->ir_scan ? "IRSCAN" : "DRSCAN", cmd->num_fields); - for (i = 0; i < cmd->num_fields; i++) { + for (unsigned int i = 0; i < cmd->num_fields; i++) { if (cmd->fields[i].out_value) { if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { char *char_buf = buf_to_hex_str(cmd->fields[i].out_value, @@ -213,14 +208,14 @@ int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer) ? DEBUG_JTAG_IOZ : cmd->fields[i].num_bits); - LOG_DEBUG("fields[%i].out_value[%i]: 0x%s", i, + LOG_DEBUG("fields[%u].out_value[%u]: 0x%s", i, cmd->fields[i].num_bits, char_buf); free(char_buf); } buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits); } else { - LOG_DEBUG_IO("fields[%i].out_value[%i]: NULL", + LOG_DEBUG_IO("fields[%u].out_value[%u]: NULL", i, cmd->fields[i].num_bits); } @@ -234,19 +229,18 @@ int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer) int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd) { - int i; int bit_count = 0; int retval; /* we return ERROR_OK, unless a check fails, or a handler reports a problem */ retval = ERROR_OK; - for (i = 0; i < cmd->num_fields; i++) { + for (unsigned int i = 0; i < cmd->num_fields; i++) { /* if neither in_value nor in_handler * are specified we don't have to examine this field */ if (cmd->fields[i].in_value) { - int num_bits = cmd->fields[i].num_bits; + const unsigned int num_bits = cmd->fields[i].num_bits; uint8_t *captured = buf_set_buf(buffer, bit_count, malloc(DIV_ROUND_UP(num_bits, 8)), 0, num_bits); @@ -256,7 +250,7 @@ int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd) ? DEBUG_JTAG_IOZ : num_bits); - LOG_DEBUG("fields[%i].in_value[%i]: 0x%s", + LOG_DEBUG("fields[%u].in_value[%u]: 0x%s", i, num_bits, char_buf); free(char_buf); } diff --git a/src/jtag/commands.h b/src/jtag/commands.h index 8259077..29fa842 100644 --- a/src/jtag/commands.h +++ b/src/jtag/commands.h @@ -36,7 +36,7 @@ struct scan_command { /** instruction/not data scan */ bool ir_scan; /** number of fields in *fields array */ - int num_fields; + unsigned int num_fields; /** pointer to an array of data scan fields */ struct scan_field *fields; /** state in which JTAG commands should finish */ @@ -50,14 +50,14 @@ struct statemove_command { struct pathmove_command { /** number of states in *path */ - int num_states; + unsigned int num_states; /** states that have to be passed */ tap_state_t *path; }; struct runtest_command { /** number of cycles to spend in Run-Test/Idle state */ - int num_cycles; + unsigned int num_cycles; /** state in which JTAG commands should finish */ tap_state_t end_state; }; @@ -65,7 +65,7 @@ struct runtest_command { struct stableclocks_command { /** number of clock cycles that should be sent */ - int num_cycles; + unsigned int num_cycles; }; @@ -100,7 +100,7 @@ struct sleep_command { */ struct tms_command { /** How many bits should be clocked out. */ - unsigned num_bits; + unsigned int num_bits; /** The bits to clock out; the LSB is bit 0 of bits[0]. */ const uint8_t *bits; }; @@ -157,7 +157,7 @@ struct jtag_command *jtag_command_queue_get(void); void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src); enum scan_type jtag_scan_type(const struct scan_command *cmd); -int jtag_scan_size(const struct scan_command *cmd); +unsigned int jtag_scan_size(const struct scan_command *cmd); int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd); int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer); diff --git a/src/jtag/core.c b/src/jtag/core.c index c84d5aa..a6f38a1 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -39,7 +39,7 @@ #include "server/ipdbg.h" /** The number of JTAG queue flushes (for profiling and debugging purposes). */ -static int jtag_flush_queue_count; +static unsigned int jtag_flush_queue_count; /* Sleep this # of ms after flushing the queue */ static int jtag_flush_queue_sleep; @@ -88,14 +88,14 @@ static enum reset_types jtag_reset_config = RESET_NONE; tap_state_t cmd_queue_cur_state = TAP_RESET; static bool jtag_verify_capture_ir = true; -static int jtag_verify = 1; +static bool jtag_verify = true; /* how long the OpenOCD should wait before attempting JTAG communication after reset lines *deasserted (in ms) */ -static int adapter_nsrst_delay; /* default to no nSRST delay */ -static int jtag_ntrst_delay;/* default to no nTRST delay */ -static int adapter_nsrst_assert_width; /* width of assertion */ -static int jtag_ntrst_assert_width; /* width of assertion */ +static unsigned int adapter_nsrst_delay; /* default to no nSRST delay */ +static unsigned int jtag_ntrst_delay;/* default to no nTRST delay */ +static unsigned int adapter_nsrst_assert_width; /* width of assertion */ +static unsigned int jtag_ntrst_assert_width; /* width of assertion */ /** * Contains a single callback along with a pointer that will be passed @@ -186,10 +186,10 @@ struct jtag_tap *jtag_all_taps(void) return __jtag_all_taps; }; -unsigned jtag_tap_count(void) +unsigned int jtag_tap_count(void) { struct jtag_tap *t = jtag_all_taps(); - unsigned n = 0; + unsigned int n = 0; while (t) { n++; t = t->next_tap; @@ -197,10 +197,10 @@ unsigned jtag_tap_count(void) return n; } -unsigned jtag_tap_count_enabled(void) +unsigned int jtag_tap_count_enabled(void) { struct jtag_tap *t = jtag_all_taps(); - unsigned n = 0; + unsigned int n = 0; while (t) { if (t->enabled) n++; @@ -212,7 +212,7 @@ unsigned jtag_tap_count_enabled(void) /** Append a new TAP to the chain of all taps. */ static void jtag_tap_add(struct jtag_tap *t) { - unsigned jtag_num_taps = 0; + unsigned int jtag_num_taps = 0; struct jtag_tap **tap = &__jtag_all_taps; while (*tap) { @@ -499,7 +499,7 @@ void jtag_add_tlr(void) * * @todo Update naming conventions to stop assuming everything is JTAG. */ -int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state) +int jtag_add_tms_seq(unsigned int nbits, const uint8_t *seq, enum tap_state state) { int retval; @@ -514,7 +514,7 @@ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state) return retval; } -void jtag_add_pathmove(int num_states, const tap_state_t *path) +void jtag_add_pathmove(unsigned int num_states, const tap_state_t *path) { tap_state_t cur_state = cmd_queue_cur_state; @@ -525,7 +525,7 @@ void jtag_add_pathmove(int num_states, const tap_state_t *path) return; } - for (int i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { if (path[i] == TAP_RESET) { LOG_ERROR("BUG: TAP_RESET is not a valid state for pathmove sequences"); jtag_set_error(ERROR_JTAG_STATE_INVALID); @@ -567,12 +567,12 @@ int jtag_add_statemove(tap_state_t goal_state) /* nothing to do */; else if (tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state)) { - unsigned tms_bits = tap_get_tms_path(cur_state, goal_state); - unsigned tms_count = tap_get_tms_path_len(cur_state, goal_state); + unsigned int tms_bits = tap_get_tms_path(cur_state, goal_state); + unsigned int tms_count = tap_get_tms_path_len(cur_state, goal_state); tap_state_t moves[8]; assert(tms_count < ARRAY_SIZE(moves)); - for (unsigned i = 0; i < tms_count; i++, tms_bits >>= 1) { + for (unsigned int i = 0; i < tms_count; i++, tms_bits >>= 1) { bool bit = tms_bits & 1; cur_state = tap_state_transition(cur_state, bit); @@ -589,14 +589,14 @@ int jtag_add_statemove(tap_state_t goal_state) return ERROR_OK; } -void jtag_add_runtest(int num_cycles, tap_state_t state) +void jtag_add_runtest(unsigned int num_cycles, tap_state_t state) { jtag_prelude(state); jtag_set_error(interface_jtag_add_runtest(num_cycles, state)); } -void jtag_add_clocks(int num_cycles) +void jtag_add_clocks(unsigned int num_cycles) { if (!tap_is_state_stable(cmd_queue_cur_state)) { LOG_ERROR("jtag_add_clocks() called with TAP in unstable state \"%s\"", @@ -881,9 +881,9 @@ static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, int compare_failed; if (in_check_mask) - compare_failed = buf_cmp_mask(captured, in_check_value, in_check_mask, num_bits); + compare_failed = !buf_eq_mask(captured, in_check_value, in_check_mask, num_bits); else - compare_failed = buf_cmp(captured, in_check_value, num_bits); + compare_failed = !buf_eq(captured, in_check_value, num_bits); if (compare_failed) { char *captured_str, *in_check_value_str; @@ -960,16 +960,16 @@ int default_interface_jtag_execute_queue(void) LOG_DEBUG_IO("JTAG %s SCAN to %s", cmd->cmd.scan->ir_scan ? "IR" : "DR", tap_state_name(cmd->cmd.scan->end_state)); - for (int i = 0; i < cmd->cmd.scan->num_fields; i++) { + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++) { struct scan_field *field = cmd->cmd.scan->fields + i; if (field->out_value) { char *str = buf_to_hex_str(field->out_value, field->num_bits); - LOG_DEBUG_IO(" %db out: %s", field->num_bits, str); + LOG_DEBUG_IO(" %ub out: %s", field->num_bits, str); free(str); } if (field->in_value) { char *str = buf_to_hex_str(field->in_value, field->num_bits); - LOG_DEBUG_IO(" %db in: %s", field->num_bits, str); + LOG_DEBUG_IO(" %ub in: %s", field->num_bits, str); free(str); } } @@ -1029,7 +1029,7 @@ void jtag_execute_queue_noclear(void) } } -int jtag_get_flush_queue_count(void) +unsigned int jtag_get_flush_queue_count(void) { return jtag_flush_queue_count; } @@ -1081,7 +1081,7 @@ void jtag_sleep(uint32_t us) /* a larger IR length than we ever expect to autoprobe */ #define JTAG_IRLEN_MAX 60 -static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode) +static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned int num_idcode) { struct scan_field field = { .num_bits = num_idcode * 32, @@ -1090,7 +1090,7 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod }; /* initialize to the end of chain ID value */ - for (unsigned i = 0; i < num_idcode; i++) + for (unsigned int i = 0; i < num_idcode; i++) buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG); jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); @@ -1098,12 +1098,12 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod return jtag_execute_queue(); } -static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned count) +static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned int count) { uint8_t zero_check = 0x0; uint8_t one_check = 0xff; - for (unsigned i = 0; i < count * 4; i++) { + for (unsigned int i = 0; i < count * 4; i++) { zero_check |= idcodes[i]; one_check &= idcodes[i]; } @@ -1158,7 +1158,8 @@ static bool jtag_idcode_is_final(uint32_t idcode) * with the JTAG chain earlier, gives more helpful/explicit error messages. * Returns TRUE iff garbage was found. */ -static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max) +static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned int count, + unsigned int max) { bool triggered = false; for (; count < max - 31; count += 32) { @@ -1185,26 +1186,26 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap) uint32_t idcode = tap->idcode & mask; /* Loop over the expected identification codes and test for a match */ - for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) { - uint32_t expected = tap->expected_ids[ii] & mask; + for (unsigned int i = 0; i < tap->expected_ids_cnt; i++) { + uint32_t expected = tap->expected_ids[i] & mask; if (idcode == expected) return true; /* treat "-expected-id 0" as a "don't-warn" wildcard */ - if (tap->expected_ids[ii] == 0) + if (tap->expected_ids[i] == 0) return true; } /* If none of the expected ids matched, warn */ jtag_examine_chain_display(LOG_LVL_WARNING, "UNEXPECTED", tap->dotted_name, tap->idcode); - for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) { + for (unsigned int i = 0; i < tap->expected_ids_cnt; i++) { char msg[32]; - snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, tap->expected_ids_cnt); + snprintf(msg, sizeof(msg), "expected %u of %u", i + 1, tap->expected_ids_cnt); jtag_examine_chain_display(LOG_LVL_ERROR, msg, - tap->dotted_name, tap->expected_ids[ii]); + tap->dotted_name, tap->expected_ids[i]); } return false; } @@ -1215,7 +1216,7 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap) static int jtag_examine_chain(void) { int retval; - unsigned max_taps = jtag_tap_count(); + unsigned int max_taps = jtag_tap_count(); /* Autoprobe up to this many. */ if (max_taps < JTAG_MAX_AUTO_TAPS) @@ -1243,9 +1244,9 @@ static int jtag_examine_chain(void) /* Point at the 1st predefined tap, if any */ struct jtag_tap *tap = jtag_tap_next_enabled(NULL); - unsigned bit_count = 0; - unsigned autocount = 0; - for (unsigned i = 0; i < max_taps; i++) { + unsigned int bit_count = 0; + unsigned int autocount = 0; + for (unsigned int i = 0; i < max_taps; i++) { assert(bit_count < max_taps * 32); uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32); @@ -1337,7 +1338,7 @@ static int jtag_validate_ircapture(void) int retval; /* when autoprobing, accommodate huge IR lengths */ - int total_ir_length = 0; + unsigned int total_ir_length = 0; for (tap = jtag_tap_next_enabled(NULL); tap; tap = jtag_tap_next_enabled(tap)) { if (tap->ir_length == 0) total_ir_length += JTAG_IRLEN_MAX; @@ -1396,7 +1397,7 @@ static int jtag_validate_ircapture(void) && tap->ir_length < JTAG_IRLEN_MAX) { tap->ir_length++; } - LOG_WARNING("AUTO %s - use \"jtag newtap %s %s -irlen %d " + LOG_WARNING("AUTO %s - use \"jtag newtap %s %s -irlen %u " "-expected-id 0x%08" PRIx32 "\"", tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode); } @@ -1445,8 +1446,8 @@ done: void jtag_tap_init(struct jtag_tap *tap) { - unsigned ir_len_bits; - unsigned ir_len_bytes; + unsigned int ir_len_bits; + unsigned int ir_len_bytes; /* if we're autoprobing, cope with potentially huge ir_length */ ir_len_bits = tap->ir_length ? tap->ir_length : JTAG_IRLEN_MAX; @@ -1471,8 +1472,8 @@ void jtag_tap_init(struct jtag_tap *tap) jtag_register_event_callback(&jtag_reset_callback, tap); jtag_tap_add(tap); - LOG_DEBUG("Created Tap: %s @ abs position %d, " - "irlen %d, capture: 0x%x mask: 0x%x", tap->dotted_name, + LOG_DEBUG("Created Tap: %s @ abs position %u, " + "irlen %u, capture: 0x%x mask: 0x%x", tap->dotted_name, tap->abs_chain_position, tap->ir_length, (unsigned) tap->ir_capture_value, (unsigned) tap->ir_capture_mask); @@ -1749,37 +1750,36 @@ int jtag_get_srst(void) return jtag_srst == 1; } -void jtag_set_nsrst_delay(unsigned delay) +void jtag_set_nsrst_delay(unsigned int delay) { adapter_nsrst_delay = delay; } -unsigned jtag_get_nsrst_delay(void) +unsigned int jtag_get_nsrst_delay(void) { return adapter_nsrst_delay; } -void jtag_set_ntrst_delay(unsigned delay) +void jtag_set_ntrst_delay(unsigned int delay) { jtag_ntrst_delay = delay; } -unsigned jtag_get_ntrst_delay(void) +unsigned int jtag_get_ntrst_delay(void) { return jtag_ntrst_delay; } - -void jtag_set_nsrst_assert_width(unsigned delay) +void jtag_set_nsrst_assert_width(unsigned int delay) { adapter_nsrst_assert_width = delay; } -unsigned jtag_get_nsrst_assert_width(void) +unsigned int jtag_get_nsrst_assert_width(void) { return adapter_nsrst_assert_width; } -void jtag_set_ntrst_assert_width(unsigned delay) +void jtag_set_ntrst_assert_width(unsigned int delay) { jtag_ntrst_assert_width = delay; } -unsigned jtag_get_ntrst_assert_width(void) +unsigned int jtag_get_ntrst_assert_width(void) { return jtag_ntrst_assert_width; } diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index b28ce62..489cb24 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -203,7 +203,7 @@ static void amt_jtagaccel_state_move(void) tap_set_state(end_state); } -static void amt_jtagaccel_runtest(int num_cycles) +static void amt_jtagaccel_runtest(unsigned int num_cycles) { int i = 0; uint8_t aw_scan_tms_5; diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index 81dd1af..47628fe 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -1836,15 +1836,17 @@ static int angie_reset(int trst, int srst) */ static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd) { - int ret, i, num_states, batch_size, state_count; + int ret, state_count; tap_state_t *path; uint8_t tms_sequence; - num_states = cmd->cmd.pathmove->num_states; + unsigned int num_states = cmd->cmd.pathmove->num_states; path = cmd->cmd.pathmove->path; state_count = 0; while (num_states > 0) { + unsigned int batch_size; + tms_sequence = 0; /* Determine batch size */ @@ -1853,7 +1855,7 @@ static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd) else batch_size = num_states; - for (i = 0; i < batch_size; i++) { + for (unsigned int i = 0; i < batch_size; i++) { if (tap_state_transition(tap_get_state(), false) == path[state_count]) { /* Append '0' transition: clear bit 'i' in tms_sequence */ buf_set_u32(&tms_sequence, i, 1, 0x0); @@ -1908,14 +1910,13 @@ static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd) static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd) { int ret; - unsigned int num_cycles; if (!tap_is_state_stable(tap_get_state())) { LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); return ERROR_FAIL; } - num_cycles = cmd->cmd.stableclocks->num_cycles; + unsigned int num_cycles = cmd->cmd.stableclocks->num_cycles; /* TMS stays either high (Test Logic Reset state) or low (all other states) */ if (tap_get_state() == TAP_RESET) diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 4c50c54..aaed16d 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -44,8 +44,8 @@ static uint8_t usb_out_buffer[ARMJTAGEW_OUT_BUFFER_SIZE]; /* Queue command functions */ static void armjtagew_end_state(tap_state_t state); static void armjtagew_state_move(void); -static void armjtagew_path_move(int num_states, tap_state_t *path); -static void armjtagew_runtest(int num_cycles); +static void armjtagew_path_move(unsigned int num_states, tap_state_t *path); +static void armjtagew_runtest(unsigned int num_cycles); static void armjtagew_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, @@ -95,7 +95,7 @@ static int armjtagew_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); @@ -111,7 +111,7 @@ static int armjtagew_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", + LOG_DEBUG_IO("pathmove: %u states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); @@ -279,11 +279,9 @@ static void armjtagew_state_move(void) tap_set_state(tap_get_end_state()); } -static void armjtagew_path_move(int num_states, tap_state_t *path) +static void armjtagew_path_move(unsigned int num_states, tap_state_t *path) { - int i; - - for (i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { /* * TODO: The ARM-JTAG-EW hardware delays TDI with 3 TCK cycles when in RTCK mode. * Either handle that here, or update the documentation with examples @@ -305,10 +303,8 @@ static void armjtagew_path_move(int num_states, tap_state_t *path) tap_set_end_state(tap_get_state()); } -static void armjtagew_runtest(int num_cycles) +static void armjtagew_runtest(unsigned int num_cycles) { - int i; - tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ @@ -318,7 +314,7 @@ static void armjtagew_runtest(int num_cycles) } /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) armjtagew_tap_append_step(0, 0); /* finish in end_state */ diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index 3d839e6..e416592 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -33,7 +33,7 @@ * this function checks the current stable state to decide on the value of TMS * to use. */ -static int bitbang_stableclocks(int num_cycles); +static int bitbang_stableclocks(unsigned int num_cycles); static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk); @@ -95,7 +95,7 @@ static int bitbang_execute_tms(struct jtag_command *cmd) unsigned num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; - LOG_DEBUG_IO("TMS: %d bits", num_bits); + LOG_DEBUG_IO("TMS: %u bits", num_bits); int tms = 0; for (unsigned i = 0; i < num_bits; i++) { @@ -113,7 +113,7 @@ static int bitbang_execute_tms(struct jtag_command *cmd) static int bitbang_path_move(struct pathmove_command *cmd) { - int num_states = cmd->num_states; + unsigned int num_states = cmd->num_states; int state_count; int tms = 0; @@ -147,10 +147,8 @@ static int bitbang_path_move(struct pathmove_command *cmd) return ERROR_OK; } -static int bitbang_runtest(int num_cycles) +static int bitbang_runtest(unsigned int num_cycles) { - int i; - tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ @@ -161,7 +159,7 @@ static int bitbang_runtest(int num_cycles) } /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) { + for (unsigned int i = 0; i < num_cycles; i++) { if (bitbang_interface->write(0, 0, 0) != ERROR_OK) return ERROR_FAIL; if (bitbang_interface->write(1, 0, 0) != ERROR_OK) @@ -179,13 +177,12 @@ static int bitbang_runtest(int num_cycles) return ERROR_OK; } -static int bitbang_stableclocks(int num_cycles) +static int bitbang_stableclocks(unsigned int num_cycles) { int tms = (tap_get_state() == TAP_RESET ? 1 : 0); - int i; /* send num_cycles clocks onto the cable */ - for (i = 0; i < num_cycles; i++) { + for (unsigned int i = 0; i < num_cycles; i++) { if (bitbang_interface->write(1, tms, 0) != ERROR_OK) return ERROR_FAIL; if (bitbang_interface->write(0, tms, 0) != ERROR_OK) @@ -319,7 +316,7 @@ int bitbang_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %s", + LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); bitbang_end_state(cmd->cmd.runtest->end_state); @@ -343,7 +340,7 @@ int bitbang_execute_queue(struct jtag_command *cmd_queue) return ERROR_FAIL; break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %s", + LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK) diff --git a/src/jtag/drivers/bitq.c b/src/jtag/drivers/bitq.c index 2e5cca2..ef870e6 100644 --- a/src/jtag/drivers/bitq.c +++ b/src/jtag/drivers/bitq.c @@ -18,8 +18,8 @@ struct bitq_interface *bitq_interface; /* low level bit queue interface */ /* state of input queue */ struct bitq_state { struct jtag_command *cmd; /* command currently processed */ - int field_idx; /* index of field currently being processed */ - int bit_pos; /* position of bit currently being processed */ + unsigned int field_idx; /* index of field currently being processed */ + unsigned int bit_pos; /* position of bit currently being processed */ int status; /* processing status */ }; static struct bitq_state bitq_in_state; @@ -108,9 +108,7 @@ static void bitq_state_move(tap_state_t new_state) static void bitq_path_move(struct pathmove_command *cmd) { - int i; - - for (i = 0; i < cmd->num_states; i++) { + for (unsigned int i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) bitq_io(0, 0, 0); else if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) @@ -127,16 +125,14 @@ static void bitq_path_move(struct pathmove_command *cmd) tap_set_end_state(tap_get_state()); } -static void bitq_runtest(int num_cycles) +static void bitq_runtest(unsigned int num_cycles) { - int i; - /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) bitq_state_move(TAP_IDLE); /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) bitq_io(0, 0, 0); /* finish in end_state */ @@ -146,11 +142,10 @@ static void bitq_runtest(int num_cycles) static void bitq_scan_field(struct scan_field *field, int do_pause) { - int bit_cnt; int tdo_req; const uint8_t *out_ptr; - uint8_t out_mask; + uint8_t out_mask; if (field->in_value) tdo_req = 1; @@ -159,7 +154,7 @@ static void bitq_scan_field(struct scan_field *field, int do_pause) if (!field->out_value) { /* just send zeros and request data from TDO */ - for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--) + for (unsigned int i = 0; i < (field->num_bits - 1); i++) bitq_io(0, 0, tdo_req); bitq_io(do_pause, 0, tdo_req); @@ -167,7 +162,7 @@ static void bitq_scan_field(struct scan_field *field, int do_pause) /* send data, and optionally request TDO */ out_mask = 0x01; out_ptr = field->out_value; - for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--) { + for (unsigned int i = 0; i < (field->num_bits - 1); i++) { bitq_io(0, ((*out_ptr) & out_mask) != 0, tdo_req); if (out_mask == 0x80) { out_mask = 0x01; @@ -190,13 +185,12 @@ static void bitq_scan_field(struct scan_field *field, int do_pause) static void bitq_scan(struct scan_command *cmd) { - int i; - if (cmd->ir_scan) bitq_state_move(TAP_IRSHIFT); else bitq_state_move(TAP_DRSHIFT); + unsigned int i; for (i = 0; i < cmd->num_fields - 1; i++) bitq_scan_field(&cmd->fields[i], 0); @@ -226,7 +220,7 @@ int bitq_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); bitq_end_state(cmd->cmd.runtest->end_state); bitq_runtest(cmd->cmd.runtest->num_cycles); break; @@ -238,7 +232,7 @@ int bitq_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, + LOG_DEBUG_IO("pathmove: %u states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); bitq_path_move(cmd->cmd.pathmove); break; diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 3b03337..b01a796 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -27,11 +27,11 @@ static int buspirate_reset(int trst, int srst); static void buspirate_end_state(tap_state_t state); static void buspirate_state_move(void); -static void buspirate_path_move(int num_states, tap_state_t *path); -static void buspirate_runtest(int num_cycles); +static void buspirate_path_move(unsigned int num_states, tap_state_t *path); +static void buspirate_runtest(unsigned int num_cycles); static void buspirate_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); -static void buspirate_stableclocks(int num_cycles); +static void buspirate_stableclocks(unsigned int num_cycles); #define CMD_UNKNOWN 0x00 #define CMD_PORT_MODE 0x01 @@ -162,7 +162,7 @@ static int buspirate_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %s", + LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest ->end_state)); @@ -180,7 +180,7 @@ static int buspirate_execute_queue(struct jtag_command *cmd_queue) buspirate_state_move(); break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %s", + LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove ->path[cmd->cmd.pathmove @@ -210,7 +210,7 @@ static int buspirate_execute_queue(struct jtag_command *cmd_queue) jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_STABLECLOCKS: - LOG_DEBUG_IO("stable clock %i cycles", cmd->cmd.stableclocks->num_cycles); + LOG_DEBUG_IO("stable clock %u cycles", cmd->cmd.stableclocks->num_cycles); buspirate_stableclocks(cmd->cmd.stableclocks->num_cycles); break; default: @@ -580,11 +580,9 @@ static void buspirate_state_move(void) tap_set_state(tap_get_end_state()); } -static void buspirate_path_move(int num_states, tap_state_t *path) +static void buspirate_path_move(unsigned int num_states, tap_state_t *path) { - int i; - - for (i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { if (tap_state_transition(tap_get_state(), false) == path[i]) { buspirate_tap_append(0, 0); } else if (tap_state_transition(tap_get_state(), true) @@ -604,10 +602,8 @@ static void buspirate_path_move(int num_states, tap_state_t *path) tap_set_end_state(tap_get_state()); } -static void buspirate_runtest(int num_cycles) +static void buspirate_runtest(unsigned int num_cycles) { - int i; - tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ @@ -616,7 +612,7 @@ static void buspirate_runtest(int num_cycles) buspirate_state_move(); } - for (i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) buspirate_tap_append(0, 0); LOG_DEBUG_IO("runtest: cur_state %s end_state %s", @@ -658,14 +654,13 @@ static void buspirate_scan(bool ir_scan, enum scan_type type, buspirate_state_move(); } -static void buspirate_stableclocks(int num_cycles) +static void buspirate_stableclocks(unsigned int num_cycles) { - int i; int tms = (tap_get_state() == TAP_RESET ? 1 : 0); buspirate_tap_make_space(0, num_cycles); - for (i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) buspirate_tap_append(tms, 0); } diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index d7367d8..a6dcfcd 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -1752,7 +1752,7 @@ static void cmsis_dap_execute_scan(struct jtag_command *cmd) LOG_DEBUG("discarding trailing empty field"); } - if (cmd->cmd.scan->num_fields == 0) { + if (!cmd->cmd.scan->num_fields) { LOG_DEBUG("empty scan, doing nothing"); return; } @@ -1772,11 +1772,11 @@ static void cmsis_dap_execute_scan(struct jtag_command *cmd) cmsis_dap_end_state(cmd->cmd.scan->end_state); struct scan_field *field = cmd->cmd.scan->fields; - unsigned scan_size = 0; + unsigned int scan_size = 0; - for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; - LOG_DEBUG_IO("%s%s field %d/%d %d bits", + LOG_DEBUG_IO("%s%s field %u/%u %u bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, @@ -1872,16 +1872,16 @@ static void cmsis_dap_execute_pathmove(struct jtag_command *cmd) cmsis_dap_pathmove(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); } -static void cmsis_dap_stableclocks(int num_cycles) +static void cmsis_dap_stableclocks(unsigned int num_cycles) { uint8_t tms = tap_get_state() == TAP_RESET; /* TODO: Perform optimizations? */ /* Execute num_cycles. */ - for (int i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) cmsis_dap_add_tms_sequence(&tms, 1); } -static void cmsis_dap_runtest(int num_cycles) +static void cmsis_dap_runtest(unsigned int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); @@ -1901,7 +1901,7 @@ static void cmsis_dap_runtest(int num_cycles) static void cmsis_dap_execute_runtest(struct jtag_command *cmd) { - LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); cmsis_dap_end_state(cmd->cmd.runtest->end_state); @@ -1910,13 +1910,13 @@ static void cmsis_dap_execute_runtest(struct jtag_command *cmd) static void cmsis_dap_execute_stableclocks(struct jtag_command *cmd) { - LOG_DEBUG_IO("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); + LOG_DEBUG_IO("stableclocks %u cycles", cmd->cmd.runtest->num_cycles); cmsis_dap_stableclocks(cmd->cmd.runtest->num_cycles); } static void cmsis_dap_execute_tms(struct jtag_command *cmd) { - LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); + LOG_DEBUG_IO("TMS: %u bits", cmd->cmd.tms->num_bits); cmsis_dap_cmd_dap_swj_sequence(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); } diff --git a/src/jtag/drivers/cmsis_dap_usb_hid.c b/src/jtag/drivers/cmsis_dap_usb_hid.c index 98ccc3e..aeec685 100644 --- a/src/jtag/drivers/cmsis_dap_usb_hid.c +++ b/src/jtag/drivers/cmsis_dap_usb_hid.c @@ -121,8 +121,12 @@ static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p break; if (cur_dev->serial_number) { - size_t len = (strlen(serial) + 1) * sizeof(wchar_t); - wchar_t *wserial = malloc(len); + size_t len = mbstowcs(NULL, serial, 0) + 1; + wchar_t *wserial = malloc(len * sizeof(wchar_t)); + if (!wserial) { + LOG_ERROR("unable to allocate serial number buffer"); + return ERROR_FAIL; + } mbstowcs(wserial, serial, len); if (wcscmp(wserial, cur_dev->serial_number) == 0) { diff --git a/src/jtag/drivers/driver.c b/src/jtag/drivers/driver.c index e52816d..2aad4a0 100644 --- a/src/jtag/drivers/driver.c +++ b/src/jtag/drivers/driver.c @@ -259,7 +259,7 @@ int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state return ERROR_OK; } -int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) +int interface_jtag_add_pathmove(unsigned int num_states, const tap_state_t *path) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); @@ -272,13 +272,13 @@ int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) cmd->cmd.pathmove->num_states = num_states; cmd->cmd.pathmove->path = cmd_queue_alloc(sizeof(tap_state_t) * num_states); - for (int i = 0; i < num_states; i++) + for (unsigned int i = 0; i < num_states; i++) cmd->cmd.pathmove->path[i] = path[i]; return ERROR_OK; } -int interface_jtag_add_runtest(int num_cycles, tap_state_t state) +int interface_jtag_add_runtest(unsigned int num_cycles, tap_state_t state) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); @@ -294,7 +294,7 @@ int interface_jtag_add_runtest(int num_cycles, tap_state_t state) return ERROR_OK; } -int interface_jtag_add_clocks(int num_cycles) +int interface_jtag_add_clocks(unsigned int num_cycles) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index 766f6dd..a4d072c 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -657,7 +657,7 @@ static int syncbb_execute_tms(struct jtag_command *cmd) unsigned num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; - LOG_DEBUG_IO("TMS: %d bits", num_bits); + LOG_DEBUG_IO("TMS: %u bits", num_bits); int tms = 0; for (unsigned i = 0; i < num_bits; i++) { @@ -672,7 +672,7 @@ static int syncbb_execute_tms(struct jtag_command *cmd) static void syncbb_path_move(struct pathmove_command *cmd) { - int num_states = cmd->num_states; + unsigned int num_states = cmd->num_states; int state_count; int tms = 0; @@ -702,9 +702,8 @@ static void syncbb_path_move(struct pathmove_command *cmd) tap_set_end_state(tap_get_state()); } -static void syncbb_runtest(int num_cycles) +static void syncbb_runtest(unsigned int num_cycles) { - int i; tap_state_t saved_end_state = tap_get_end_state(); @@ -715,7 +714,7 @@ static void syncbb_runtest(int num_cycles) } /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) { + for (unsigned int i = 0; i < num_cycles; i++) { ft232r_write(0, 0, 0); ft232r_write(1, 0, 0); } @@ -735,13 +734,12 @@ static void syncbb_runtest(int num_cycles) * this function checks the current stable state to decide on the value of TMS * to use. */ -static void syncbb_stableclocks(int num_cycles) +static void syncbb_stableclocks(unsigned int num_cycles) { int tms = (tap_get_state() == TAP_RESET ? 1 : 0); - int i; /* send num_cycles clocks onto the cable */ - for (i = 0; i < num_cycles; i++) { + for (unsigned int i = 0; i < num_cycles; i++) { ft232r_write(1, tms, 0); ft232r_write(0, tms, 0); } @@ -832,7 +830,7 @@ static int syncbb_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, + LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); syncbb_end_state(cmd->cmd.runtest->end_state); @@ -854,7 +852,7 @@ static int syncbb_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, + LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); syncbb_path_move(cmd->cmd.pathmove); diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 1793cbf..66d0d50 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -383,10 +383,9 @@ static void ftdi_end_state(tap_state_t state) static void ftdi_execute_runtest(struct jtag_command *cmd) { - int i; - static const uint8_t zero; + uint8_t zero = 0; - LOG_DEBUG_IO("runtest %i cycles, end in %s", + LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); @@ -394,7 +393,7 @@ static void ftdi_execute_runtest(struct jtag_command *cmd) move_to_state(TAP_IDLE); /* TODO: Reuse ftdi_execute_stableclocks */ - i = cmd->cmd.runtest->num_cycles; + unsigned int i = cmd->cmd.runtest->num_cycles; while (i > 0) { /* there are no state transitions in this code, so omit state tracking */ unsigned this_len = i > 7 ? 7 : i; @@ -407,7 +406,7 @@ static void ftdi_execute_runtest(struct jtag_command *cmd) if (tap_get_state() != tap_get_end_state()) move_to_state(tap_get_end_state()); - LOG_DEBUG_IO("runtest: %i, end in %s", + LOG_DEBUG_IO("runtest: %u, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(tap_get_end_state())); } @@ -430,7 +429,7 @@ static void ftdi_execute_statemove(struct jtag_command *cmd) */ static void ftdi_execute_tms(struct jtag_command *cmd) { - LOG_DEBUG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); + LOG_DEBUG_IO("TMS: %u bits", cmd->cmd.tms->num_bits); /* TODO: Missing tap state tracking, also missing from ft2232.c! */ DO_CLOCK_TMS_CS_OUT(mpsse_ctx, @@ -444,9 +443,9 @@ static void ftdi_execute_tms(struct jtag_command *cmd) static void ftdi_execute_pathmove(struct jtag_command *cmd) { tap_state_t *path = cmd->cmd.pathmove->path; - int num_states = cmd->cmd.pathmove->num_states; + unsigned int num_states = cmd->cmd.pathmove->num_states; - LOG_DEBUG_IO("pathmove: %i states, current: %s end: %s", num_states, + LOG_DEBUG_IO("pathmove: %u states, current: %s end: %s", num_states, tap_state_name(tap_get_state()), tap_state_name(path[num_states-1])); @@ -504,7 +503,7 @@ static void ftdi_execute_scan(struct jtag_command *cmd) LOG_DEBUG_IO("discarding trailing empty field"); } - if (cmd->cmd.scan->num_fields == 0) { + if (!cmd->cmd.scan->num_fields) { LOG_DEBUG_IO("empty scan, doing nothing"); return; } @@ -522,9 +521,9 @@ static void ftdi_execute_scan(struct jtag_command *cmd) struct scan_field *field = cmd->cmd.scan->fields; unsigned scan_size = 0; - for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; - LOG_DEBUG_IO("%s%s field %d/%d %d bits", + LOG_DEBUG_IO("%s%s field %u/%u %u bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, @@ -644,7 +643,7 @@ static void ftdi_execute_stableclocks(struct jtag_command *cmd) /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ - int num_cycles = cmd->cmd.stableclocks->num_cycles; + unsigned int num_cycles = cmd->cmd.stableclocks->num_cycles; /* 7 bits of either ones or zeros. */ uint8_t tms = tap_get_state() == TAP_RESET ? 0x7f : 0x00; @@ -658,7 +657,7 @@ static void ftdi_execute_stableclocks(struct jtag_command *cmd) num_cycles -= this_len; } - LOG_DEBUG_IO("clocks %i while in %s", + LOG_DEBUG_IO("clocks %u while in %s", cmd->cmd.stableclocks->num_cycles, tap_state_name(tap_get_state())); } diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index a4c6fd0..d0fe43f 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -185,10 +185,9 @@ static void gw16012_path_move(struct pathmove_command *cmd) tap_set_end_state(tap_get_state()); } -static void gw16012_runtest(int num_cycles) +static void gw16012_runtest(unsigned int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); - int i; /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { @@ -196,7 +195,7 @@ static void gw16012_runtest(int num_cycles) gw16012_state_move(); } - for (i = 0; i < num_cycles; i++) { + for (unsigned int i = 0; i < num_cycles; i++) { gw16012_control(0x0); /* single-bit mode */ gw16012_data(0x0); /* TMS cycle with TMS low */ } @@ -292,7 +291,7 @@ static int gw16012_execute_queue(struct jtag_command *cmd_queue) gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); gw16012_end_state(cmd->cmd.runtest->end_state); gw16012_runtest(cmd->cmd.runtest->num_cycles); diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 1874557..1b2fb4e 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -80,9 +80,9 @@ static struct device_config tmp_config; /* Queue command functions */ static void jlink_end_state(tap_state_t state); static void jlink_state_move(void); -static void jlink_path_move(int num_states, tap_state_t *path); -static void jlink_stableclocks(int num_cycles); -static void jlink_runtest(int num_cycles); +static void jlink_path_move(unsigned int num_states, tap_state_t *path); +static void jlink_stableclocks(unsigned int num_cycles); +static void jlink_runtest(unsigned int num_cycles); static void jlink_reset(int trst, int srst); static int jlink_reset_safe(int trst, int srst); static int jlink_swd_run_queue(void); @@ -140,7 +140,7 @@ static void jlink_execute_statemove(struct jtag_command *cmd) static void jlink_execute_pathmove(struct jtag_command *cmd) { - LOG_DEBUG_IO("pathmove: %i states, end in %i", + LOG_DEBUG_IO("pathmove: %u states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); @@ -159,7 +159,7 @@ static void jlink_execute_scan(struct jtag_command *cmd) LOG_DEBUG("discarding trailing empty field"); } - if (cmd->cmd.scan->num_fields == 0) { + if (!cmd->cmd.scan->num_fields) { LOG_DEBUG("empty scan, doing nothing"); return; } @@ -181,9 +181,9 @@ static void jlink_execute_scan(struct jtag_command *cmd) struct scan_field *field = cmd->cmd.scan->fields; unsigned scan_size = 0; - for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; - LOG_DEBUG_IO("%s%s field %d/%d %d bits", + LOG_DEBUG_IO("%s%s field %u/%u %u bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, @@ -564,6 +564,20 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) { LOG_ERROR("Multiple devices found, specify the desired device"); + LOG_INFO("Found devices:"); + for (size_t i = 0; devs[i]; i++) { + uint32_t serial; + ret = jaylink_device_get_serial_number(devs[i], &serial); + if (ret == JAYLINK_ERR_NOT_AVAILABLE) { + continue; + } else if (ret != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_serial_number() failed: %s", + jaylink_strerror(ret)); + continue; + } + LOG_INFO("Device %zu serial: %" PRIu32, i, serial); + } + jaylink_free_devices(devs, true); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -885,12 +899,11 @@ static void jlink_state_move(void) tap_set_state(tap_get_end_state()); } -static void jlink_path_move(int num_states, tap_state_t *path) +static void jlink_path_move(unsigned int num_states, tap_state_t *path) { - int i; uint8_t tms = 0xff; - for (i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) jlink_clock_data(NULL, 0, NULL, 0, NULL, 0, 1); else if (path[i] == tap_state_transition(tap_get_state(), true)) @@ -907,17 +920,15 @@ static void jlink_path_move(int num_states, tap_state_t *path) tap_set_end_state(tap_get_state()); } -static void jlink_stableclocks(int num_cycles) +static void jlink_stableclocks(unsigned int num_cycles) { - int i; - uint8_t tms = tap_get_state() == TAP_RESET; /* Execute num_cycles. */ - for (i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) jlink_clock_data(NULL, 0, &tms, 0, NULL, 0, 1); } -static void jlink_runtest(int num_cycles) +static void jlink_runtest(unsigned int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); @@ -964,23 +975,18 @@ static int jlink_reset_safe(int trst, int srst) COMMAND_HANDLER(jlink_usb_command) { - int tmp; - if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { - command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); - return ERROR_COMMAND_ARGUMENT_INVALID; - } + unsigned int tmp; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], tmp); - if (tmp < JAYLINK_USB_ADDRESS_0 || tmp > JAYLINK_USB_ADDRESS_3) { + if (tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } usb_address = tmp; - use_usb_address = true; return ERROR_OK; @@ -1038,38 +1044,35 @@ COMMAND_HANDLER(jlink_handle_free_memory_command) COMMAND_HANDLER(jlink_handle_jlink_jtag_command) { - int tmp; - int version; - if (!CMD_ARGC) { + unsigned int version; + switch (jtag_command_version) { - case JAYLINK_JTAG_VERSION_2: - version = 2; - break; - case JAYLINK_JTAG_VERSION_3: - version = 3; - break; - default: - return ERROR_FAIL; + case JAYLINK_JTAG_VERSION_2: + version = 2; + break; + case JAYLINK_JTAG_VERSION_3: + version = 3; + break; + default: + return ERROR_FAIL; } - command_print(CMD, "JTAG command version: %i", version); + command_print(CMD, "JTAG command version: %u", version); } else if (CMD_ARGC == 1) { - if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { - command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_COMMAND_ARGUMENT_INVALID; - } + uint8_t tmp; + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], tmp); switch (tmp) { - case 2: - jtag_command_version = JAYLINK_JTAG_VERSION_2; - break; - case 3: - jtag_command_version = JAYLINK_JTAG_VERSION_3; - break; - default: - command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_COMMAND_ARGUMENT_INVALID; + case 2: + jtag_command_version = JAYLINK_JTAG_VERSION_2; + break; + case 3: + jtag_command_version = JAYLINK_JTAG_VERSION_3; + break; + default: + command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } } else { return ERROR_COMMAND_SYNTAX_ERROR; @@ -1080,10 +1083,7 @@ COMMAND_HANDLER(jlink_handle_jlink_jtag_command) COMMAND_HANDLER(jlink_handle_target_power_command) { - int ret; - int enable; - - if (CMD_ARGC != 1) + if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) { @@ -1092,16 +1092,24 @@ COMMAND_HANDLER(jlink_handle_target_power_command) return ERROR_OK; } - if (!strcmp(CMD_ARGV[0], "on")) { - enable = true; - } else if (!strcmp(CMD_ARGV[0], "off")) { - enable = false; - } else { - command_print(CMD, "Invalid argument: %s", CMD_ARGV[0]); - return ERROR_FAIL; + if (!CMD_ARGC) { + uint32_t state; + int ret = jaylink_get_hardware_info(devh, JAYLINK_HW_INFO_TARGET_POWER, + &state); + + if (ret != JAYLINK_OK) { + command_print(CMD, "Failed to retrieve target power state"); + return ERROR_FAIL; + } + + command_print(CMD, "%d", (bool)state); + return ERROR_OK; } - ret = jaylink_set_target_power(devh, enable); + bool enable; + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); + + int ret = jaylink_set_target_power(devh, enable); if (ret != JAYLINK_OK) { command_print(CMD, "jaylink_set_target_power() failed: %s", @@ -1410,8 +1418,6 @@ static int config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, COMMAND_HANDLER(jlink_handle_config_usb_address_command) { - uint8_t tmp; - if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_READ_CONFIG)) { command_print(CMD, "Reading configuration is not supported by the " "device"); @@ -1421,10 +1427,8 @@ COMMAND_HANDLER(jlink_handle_config_usb_address_command) if (!CMD_ARGC) { show_config_usb_address(CMD); } else if (CMD_ARGC == 1) { - if (sscanf(CMD_ARGV[0], "%" SCNd8, &tmp) != 1) { - command_print(CMD, "Invalid USB address: %s", CMD_ARGV[0]); - return ERROR_COMMAND_ARGUMENT_INVALID; - } + uint8_t tmp; + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], tmp); if (tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD, "Invalid USB address: %u", tmp); @@ -1883,7 +1887,7 @@ static const struct command_registration jlink_subcommand_handlers[] = { .handler = &jlink_handle_target_power_command, .mode = COMMAND_EXEC, .help = "set the target power supply", - .usage = "<on|off>" + .usage = "[0|1|on|off]" }, { .name = "freemem", diff --git a/src/jtag/drivers/jtag_dpi.c b/src/jtag/drivers/jtag_dpi.c index 285f96e..046186a 100644 --- a/src/jtag/drivers/jtag_dpi.c +++ b/src/jtag/drivers/jtag_dpi.c @@ -163,7 +163,7 @@ out: return ret; } -static int jtag_dpi_runtest(int cycles) +static int jtag_dpi_runtest(unsigned int num_cycles) { char buf[20]; uint8_t *data_buf = last_ir_buf, *read_scan; @@ -189,7 +189,7 @@ static int jtag_dpi_runtest(int cycles) return ERROR_FAIL; } snprintf(buf, sizeof(buf), "ib %d\n", num_bits); - while (cycles > 0) { + while (num_cycles > 0) { ret = write_sock(buf, strlen(buf)); if (ret != ERROR_OK) { LOG_ERROR("write_sock() fail, file %s, line %d", @@ -209,7 +209,7 @@ static int jtag_dpi_runtest(int cycles) goto out; } - cycles -= num_bits + 6; + num_cycles -= num_bits + 6; } out: @@ -217,9 +217,9 @@ out: return ret; } -static int jtag_dpi_stableclocks(int cycles) +static int jtag_dpi_stableclocks(unsigned int num_cycles) { - return jtag_dpi_runtest(cycles); + return jtag_dpi_runtest(num_cycles); } static int jtag_dpi_execute_queue(struct jtag_command *cmd_queue) diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index 9dec0d1..a19060c 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -254,7 +254,7 @@ static int jtag_vpi_path_move(struct pathmove_command *cmd) memset(trans, 0, DIV_ROUND_UP(cmd->num_states, 8)); - for (int i = 0; i < cmd->num_states; i++) { + for (unsigned int i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) buf_set_u32(trans, i, 1, 1); tap_set_state(cmd->path[i]); @@ -440,7 +440,7 @@ static int jtag_vpi_scan(struct scan_command *cmd) return ERROR_OK; } -static int jtag_vpi_runtest(int cycles, tap_state_t state) +static int jtag_vpi_runtest(unsigned int num_cycles, tap_state_t state) { int retval; @@ -448,22 +448,20 @@ static int jtag_vpi_runtest(int cycles, tap_state_t state) if (retval != ERROR_OK) return retval; - retval = jtag_vpi_queue_tdi(NULL, cycles, NO_TAP_SHIFT); + retval = jtag_vpi_queue_tdi(NULL, num_cycles, NO_TAP_SHIFT); if (retval != ERROR_OK) return retval; return jtag_vpi_state_move(state); } -static int jtag_vpi_stableclocks(int cycles) +static int jtag_vpi_stableclocks(unsigned int num_cycles) { uint8_t tms_bits[4]; - int cycles_remain = cycles; + unsigned int cycles_remain = num_cycles; int nb_bits; int retval; - const int CYCLES_ONE_BATCH = sizeof(tms_bits) * 8; - - assert(cycles >= 0); + const unsigned int CYCLES_ONE_BATCH = sizeof(tms_bits) * 8; /* use TMS=1 in TAP RESET state, TMS=0 in all other stable states */ memset(&tms_bits, (tap_get_state() == TAP_RESET) ? 0xff : 0x00, sizeof(tms_bits)); diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index f3499e3..3decddb 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -283,6 +283,9 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t vids[], c case 0x3300: ctx->type = TYPE_FT232HP; break; + case 0x3600: + ctx->type = TYPE_FT4232HA; + break; default: LOG_ERROR("unsupported FTDI chip type: 0x%04x", desc.bcdDevice); goto error; diff --git a/src/jtag/drivers/mpsse.h b/src/jtag/drivers/mpsse.h index e92a9bb..737560d 100644 --- a/src/jtag/drivers/mpsse.h +++ b/src/jtag/drivers/mpsse.h @@ -30,6 +30,7 @@ enum ftdi_chip_type { TYPE_FT4232HP, TYPE_FT233HP, TYPE_FT232HP, + TYPE_FT4232HA, }; struct mpsse_ctx; diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 81b74d4..e828d46 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -106,8 +106,8 @@ static int opendous_quit(void); /* Queue command functions */ static void opendous_end_state(tap_state_t state); static void opendous_state_move(void); -static void opendous_path_move(int num_states, tap_state_t *path); -static void opendous_runtest(int num_cycles); +static void opendous_path_move(unsigned int num_states, tap_state_t *path); +static void opendous_runtest(unsigned int num_cycles); static void opendous_scan(int ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void opendous_reset(int trst, int srst); @@ -248,7 +248,7 @@ static int opendous_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); if (cmd->cmd.runtest->end_state != -1) @@ -265,7 +265,7 @@ static int opendous_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", + LOG_DEBUG_IO("pathmove: %u states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); @@ -419,11 +419,9 @@ void opendous_state_move(void) tap_set_state(tap_get_end_state()); } -void opendous_path_move(int num_states, tap_state_t *path) +void opendous_path_move(unsigned int num_states, tap_state_t *path) { - int i; - - for (i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) opendous_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) @@ -440,10 +438,8 @@ void opendous_path_move(int num_states, tap_state_t *path) tap_set_end_state(tap_get_state()); } -void opendous_runtest(int num_cycles) +void opendous_runtest(unsigned int num_cycles) { - int i; - tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ @@ -453,7 +449,7 @@ void opendous_runtest(int num_cycles) } /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) opendous_tap_append_step(0, 0); /* finish in end_state */ diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index ea78ca8..0ae885e 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -760,15 +760,17 @@ static void openjtag_execute_runtest(struct jtag_command *cmd) if (openjtag_variant != OPENJTAG_VARIANT_CY7C65215 || cmd->cmd.runtest->num_cycles) { uint8_t command; - int cycles = cmd->cmd.runtest->num_cycles; + unsigned int num_cycles = cmd->cmd.runtest->num_cycles; do { + const unsigned int num_cycles_cmd = MIN(num_cycles, 16); + command = 7; - command |= (((cycles > 16 ? 16 : cycles) - 1) & 0x0F) << 4; + command |= ((num_cycles_cmd - 1) & 0x0F) << 4; openjtag_add_byte(command); - cycles -= 16; - } while (cycles > 0); + num_cycles -= num_cycles_cmd; + } while (num_cycles > 0); } tap_set_end_state(end_state); diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index 8d4fc90..c41a0e1 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -381,7 +381,7 @@ static int osbdm_quit(void) static int osbdm_add_pathmove( struct queue *queue, tap_state_t *path, - int num_states) + unsigned int num_states) { assert(num_states <= 32); @@ -392,7 +392,7 @@ static int osbdm_add_pathmove( } uint32_t tms = 0; - for (int i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { if (tap_state_transition(tap_get_state(), 1) == path[i]) { tms |= (1 << i); } else if (tap_state_transition(tap_get_state(), 0) == path[i]) { @@ -451,7 +451,7 @@ static int osbdm_add_statemove( static int osbdm_add_stableclocks( struct queue *queue, - int count) + unsigned int count) { if (!tap_is_state_stable(tap_get_state())) { LOG_ERROR("BUG: current state (%s) is not stable", @@ -489,7 +489,7 @@ static int osbdm_add_tms( static int osbdm_add_scan( struct queue *queue, struct scan_field *fields, - int num_fields, + unsigned int num_fields, tap_state_t end_state, bool ir_scan) { @@ -508,7 +508,7 @@ static int osbdm_add_scan( /* Add scan */ tap_set_end_state(end_state); - for (int idx = 0; idx < num_fields; idx++) { + for (unsigned int idx = 0; idx < num_fields; idx++) { struct sequence *next = queue_add_tail(queue, fields[idx].num_bits); if (!next) { LOG_ERROR("Can't allocate bit sequence"); @@ -536,7 +536,7 @@ static int osbdm_add_scan( static int osbdm_add_runtest( struct queue *queue, - int num_cycles, + unsigned int num_cycles, tap_state_t end_state) { if (osbdm_add_statemove(queue, TAP_IDLE, 0) != ERROR_OK) diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index afdf16e..f4a4fcb 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -869,7 +869,7 @@ static void rlink_state_move(void) static void rlink_path_move(struct pathmove_command *cmd) { - int num_states = cmd->num_states; + unsigned int num_states = cmd->num_states; int state_count; int tms = 0; @@ -896,10 +896,8 @@ static void rlink_path_move(struct pathmove_command *cmd) tap_set_end_state(tap_get_state()); } -static void rlink_runtest(int num_cycles) +static void rlink_runtest(unsigned int num_cycles) { - int i; - tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in RTI */ @@ -909,7 +907,7 @@ static void rlink_runtest(int num_cycles) } /* execute num_cycles */ - for (i = 0; i < num_cycles; i++) + for (unsigned int i = 0; i < num_cycles; i++) tap_state_queue_append(0); /* finish in end_state */ @@ -1323,7 +1321,7 @@ static int rlink_execute_queue(struct jtag_command *cmd_queue) rlink_state_move(); break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", + LOG_DEBUG_IO("pathmove: %u states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); rlink_path_move(cmd->cmd.pathmove); diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 0fe8989..ad3bc6e 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -1701,15 +1701,17 @@ static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) */ static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) { - int ret, i, num_states, batch_size, state_count; + int ret, state_count; tap_state_t *path; uint8_t tms_sequence; - num_states = cmd->cmd.pathmove->num_states; + unsigned int num_states = cmd->cmd.pathmove->num_states; path = cmd->cmd.pathmove->path; state_count = 0; while (num_states > 0) { + unsigned int batch_size; + tms_sequence = 0; /* Determine batch size */ @@ -1718,7 +1720,7 @@ static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) else batch_size = num_states; - for (i = 0; i < batch_size; i++) { + for (unsigned int i = 0; i < batch_size; i++) { if (tap_state_transition(tap_get_state(), false) == path[state_count]) { /* Append '0' transition: clear bit 'i' in tms_sequence */ buf_set_u32(&tms_sequence, i, 1, 0x0); @@ -1774,14 +1776,13 @@ static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) { int ret; - unsigned num_cycles; if (!tap_is_state_stable(tap_get_state())) { LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); return ERROR_FAIL; } - num_cycles = cmd->cmd.stableclocks->num_cycles; + unsigned int num_cycles = cmd->cmd.stableclocks->num_cycles; /* TMS stays either high (Test Logic Reset state) or low (all other states) */ if (tap_get_state() == TAP_RESET) diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index c84055c..53dd158 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -474,11 +474,9 @@ static void ublast_tms(struct tms_command *cmd) */ static void ublast_path_move(struct pathmove_command *cmd) { - int i; - - LOG_DEBUG_IO("(num_states=%d, last_state=%d)", + LOG_DEBUG_IO("(num_states=%u, last_state=%d)", cmd->num_states, cmd->path[cmd->num_states - 1]); - for (i = 0; i < cmd->num_states; i++) { + for (unsigned int i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) ublast_clock_tms(0); if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) @@ -675,19 +673,19 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) ublast_idle_clock(); } -static void ublast_runtest(int cycles, tap_state_t state) +static void ublast_runtest(unsigned int num_cycles, tap_state_t state) { - LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); + LOG_DEBUG_IO("%s(cycles=%u, end_state=%d)", __func__, num_cycles, state); ublast_state_move(TAP_IDLE, 0); - ublast_queue_tdi(NULL, cycles, SCAN_OUT); + ublast_queue_tdi(NULL, num_cycles, SCAN_OUT); ublast_state_move(state, 0); } -static void ublast_stableclocks(int cycles) +static void ublast_stableclocks(unsigned int num_cycles) { - LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles); - ublast_queue_tdi(NULL, cycles, SCAN_OUT); + LOG_DEBUG_IO("%s(cycles=%u)", __func__, num_cycles); + ublast_queue_tdi(NULL, num_cycles, SCAN_OUT); } /** diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 2d666d0..6e3b3ba 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -37,7 +37,7 @@ static void usbprog_end_state(tap_state_t state); static void usbprog_state_move(void); static void usbprog_path_move(struct pathmove_command *cmd); -static void usbprog_runtest(int num_cycles); +static void usbprog_runtest(unsigned int num_cycles); static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size); #define UNKNOWN_COMMAND 0x00 @@ -101,7 +101,7 @@ static int usbprog_execute_queue(struct jtag_command *cmd_queue) usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); usbprog_end_state(cmd->cmd.runtest->end_state); @@ -113,7 +113,7 @@ static int usbprog_execute_queue(struct jtag_command *cmd_queue) usbprog_state_move(); break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", + LOG_DEBUG_IO("pathmove: %u states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); usbprog_path_move(cmd->cmd.pathmove); @@ -189,7 +189,7 @@ static void usbprog_state_move(void) static void usbprog_path_move(struct pathmove_command *cmd) { - int num_states = cmd->num_states; + unsigned int num_states = cmd->num_states; int state_count; /* There may be queued transitions, and before following a specified @@ -222,10 +222,8 @@ static void usbprog_path_move(struct pathmove_command *cmd) tap_set_end_state(tap_get_state()); } -static void usbprog_runtest(int num_cycles) +static void usbprog_runtest(unsigned int num_cycles) { - int i; - /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { usbprog_end_state(TAP_IDLE); @@ -241,7 +239,7 @@ static void usbprog_runtest(int num_cycles) /* LOG_INFO("NUM CYCLES %i",num_cycles); */ } - for (i = 0; i < num_cycles; i++) { + for (unsigned int i = 0; i < num_cycles; i++) { usbprog_write(1, 0, 0); usbprog_write(0, 0, 0); } diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c index f1fc453..691e576 100644 --- a/src/jtag/drivers/vdebug.c +++ b/src/jtag/drivers/vdebug.c @@ -931,11 +931,11 @@ static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) static int vdebug_jtag_path_move(struct pathmove_command *cmd, uint8_t f_flush) { uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)]; - LOG_DEBUG_IO("path num states %d", cmd->num_states); + LOG_DEBUG_IO("path num states %u", cmd->num_states); memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); - for (uint8_t i = 0; i < cmd->num_states; i++) { + for (unsigned int i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) buf_set_u32(tms, i, 1, 1); tap_set_state(cmd->path[i]); @@ -970,10 +970,10 @@ static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) uint8_t num_pre = tap_get_tms_path_len(cur, state); uint8_t tms_post = tap_get_tms_path(state, cmd->end_state); uint8_t num_post = tap_get_tms_path_len(state, cmd->end_state); - int num_bits = jtag_scan_size(cmd); - LOG_DEBUG_IO("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", + const unsigned int num_bits = jtag_scan_size(cmd); + LOG_DEBUG_IO("scan len:%u fields:%u ir/!dr:%d state cur:%x end:%x", num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state); - for (int i = 0; i < cmd->num_fields; i++) { + for (unsigned int i = 0; i < cmd->num_fields; i++) { uint8_t cur_num_pre = i == 0 ? num_pre : 0; uint8_t cur_tms_pre = i == 0 ? tms_pre : 0; uint8_t cur_num_post = i == cmd->num_fields - 1 ? num_post : 0; @@ -992,24 +992,24 @@ static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) return rc; } -static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) +static int vdebug_jtag_runtest(unsigned int num_cycles, tap_state_t state, uint8_t f_flush) { tap_state_t cur = tap_get_state(); uint8_t tms_pre = tap_get_tms_path(cur, state); uint8_t num_pre = tap_get_tms_path_len(cur, state); - LOG_DEBUG_IO("idle len:%d state cur:%x end:%x", cycles, cur, state); - int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush); + LOG_DEBUG_IO("idle len:%u state cur:%x end:%x", num_cycles, cur, state); + int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, num_cycles, NULL, 0, 0, NULL, f_flush); if (cur != state) tap_set_state(state); return rc; } -static int vdebug_jtag_stableclocks(int num, uint8_t f_flush) +static int vdebug_jtag_stableclocks(unsigned int num_cycles, uint8_t f_flush) { - LOG_DEBUG("stab len:%d state cur:%x", num, tap_get_state()); + LOG_DEBUG("stab len:%u state cur:%x", num_cycles, tap_get_state()); - return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush); + return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num_cycles, NULL, 0, 0, NULL, f_flush); } static int vdebug_sleep(int us) diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index 34525d5..ca14217 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -43,10 +43,10 @@ static struct pending_scan_result /* Queue command functions */ static void vsllink_end_state(tap_state_t state); static void vsllink_state_move(void); -static void vsllink_path_move(int num_states, tap_state_t *path); +static void vsllink_path_move(unsigned int num_states, tap_state_t *path); static void vsllink_tms(int num_bits, const uint8_t *bits); -static void vsllink_runtest(int num_cycles); -static void vsllink_stableclocks(int num_cycles, int tms); +static void vsllink_runtest(unsigned int num_cycles); +static void vsllink_stableclocks(unsigned int num_cycles, int tms); static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static int vsllink_reset(int trst, int srst); @@ -98,7 +98,7 @@ static int vsllink_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %s", + LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); @@ -115,7 +115,7 @@ static int vsllink_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %s", + LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); @@ -161,7 +161,7 @@ static int vsllink_execute_queue(struct jtag_command *cmd_queue) break; case JTAG_STABLECLOCKS: - LOG_DEBUG_IO("add %d clocks", + LOG_DEBUG_IO("add %u clocks", cmd->cmd.stableclocks->num_cycles); switch (tap_get_state()) { @@ -371,9 +371,9 @@ static void vsllink_state_move(void) tap_set_state(tap_get_end_state()); } -static void vsllink_path_move(int num_states, tap_state_t *path) +static void vsllink_path_move(unsigned int num_states, tap_state_t *path) { - for (int i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) vsllink_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) @@ -397,7 +397,7 @@ static void vsllink_tms(int num_bits, const uint8_t *bits) vsllink_tap_append_step((bits[i / 8] >> (i % 8)) & 1, 0); } -static void vsllink_stableclocks(int num_cycles, int tms) +static void vsllink_stableclocks(unsigned int num_cycles, int tms) { while (num_cycles > 0) { vsllink_tap_append_step(tms, 0); @@ -405,7 +405,7 @@ static void vsllink_stableclocks(int num_cycles, int tms) } } -static void vsllink_runtest(int num_cycles) +static void vsllink_runtest(unsigned int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index 11fbaaa..f252087 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -1669,7 +1669,6 @@ static void xds110_execute_tlr_reset(struct jtag_command *cmd) static void xds110_execute_pathmove(struct jtag_command *cmd) { - uint32_t i; uint32_t num_states; uint8_t *path; @@ -1685,7 +1684,7 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) } /* Convert requested path states into XDS API states */ - for (i = 0; i < num_states; i++) + for (unsigned int i = 0; i < num_states; i++) path[i] = (uint8_t)xds_jtag_state[cmd->cmd.pathmove->path[i]]; if (xds110.firmware >= OCD_FIRMWARE_VERSION) { @@ -1704,7 +1703,6 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) static void xds110_queue_scan(struct jtag_command *cmd) { - int i; uint32_t offset; uint32_t total_fields; uint32_t total_bits; @@ -1715,7 +1713,7 @@ static void xds110_queue_scan(struct jtag_command *cmd) /* Calculate the total number of bits to scan */ total_bits = 0; total_fields = 0; - for (i = 0; i < cmd->cmd.scan->num_fields; i++) { + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++) { total_fields++; total_bits += (uint32_t)cmd->cmd.scan->fields[i].num_bits; } @@ -1756,7 +1754,7 @@ static void xds110_queue_scan(struct jtag_command *cmd) buffer = &xds110.txn_requests[xds110.txn_request_size]; /* Clear data out buffer to default value of all zeros */ memset((void *)buffer, 0x00, total_bytes); - for (i = 0; i < cmd->cmd.scan->num_fields; i++) { + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++) { if (cmd->cmd.scan->fields[i].out_value) { /* Copy over data to scan out into request buffer */ bit_copy(buffer, offset, cmd->cmd.scan->fields[i].out_value, 0, @@ -1775,7 +1773,7 @@ static void xds110_queue_scan(struct jtag_command *cmd) static void xds110_queue_runtest(struct jtag_command *cmd) { - uint32_t clocks = (uint32_t)cmd->cmd.stableclocks->num_cycles; + uint32_t clocks = cmd->cmd.stableclocks->num_cycles; uint8_t end_state = (uint8_t)xds_jtag_state[cmd->cmd.runtest->end_state]; /* Check if new request would be too large to fit */ @@ -1794,7 +1792,7 @@ static void xds110_queue_runtest(struct jtag_command *cmd) static void xds110_queue_stableclocks(struct jtag_command *cmd) { - uint32_t clocks = (uint32_t)cmd->cmd.stableclocks->num_cycles; + uint32_t clocks = cmd->cmd.stableclocks->num_cycles; /* Check if new request would be too large to fit */ if ((xds110.txn_request_size + 1 + sizeof(clocks) + 1) > MAX_DATA_BLOCK) diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c index 233ade3..b5c7e2f 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -128,7 +128,7 @@ static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) size_t write; int err; - LOG_DEBUG("stableclocks %i cycles", cmd->cmd.runtest->num_cycles); + LOG_DEBUG("stableclocks %u cycles", cmd->cmd.runtest->num_cycles); while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); @@ -167,7 +167,7 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) { int err = ERROR_OK; - LOG_DEBUG("runtest %i cycles, end in %i", + LOG_DEBUG("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); @@ -200,16 +200,15 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) { - size_t num_states = cmd->cmd.pathmove->num_states; + unsigned int num_states = cmd->cmd.pathmove->num_states; tap_state_t *path = cmd->cmd.pathmove->path; int err = ERROR_OK; - size_t i; - LOG_DEBUG("pathmove: %i states, end in %i", + LOG_DEBUG("pathmove: %u states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - for (i = 0; i < num_states; i++) { + for (unsigned int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) { err = xlnx_pcie_xvc_transact(1, 1, 0, NULL); } else if (path[i] == tap_state_transition(tap_get_state(), true)) { diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 6ac6801..c73f6c8 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -319,37 +319,37 @@ COMMAND_HANDLER(interface_handle_hla_command) return ERROR_OK; } -static const struct command_registration hl_interface_command_handlers[] = { +static const struct command_registration hl_interface_subcommand_handlers[] = { { - .name = "hla_device_desc", + .name = "device_desc", .handler = &hl_interface_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the device description of the adapter", .usage = "description_string", }, { - .name = "hla_layout", + .name = "layout", .handler = &hl_interface_handle_layout_command, .mode = COMMAND_CONFIG, .help = "set the layout of the adapter", .usage = "layout_name", }, { - .name = "hla_vid_pid", + .name = "vid_pid", .handler = &hl_interface_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor and product ID of the adapter", .usage = "(vid pid)*", }, { - .name = "hla_stlink_backend", + .name = "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", + .name = "command", .handler = &interface_handle_hla_command, .mode = COMMAND_EXEC, .help = "execute a custom adapter-specific command", @@ -358,6 +358,17 @@ static const struct command_registration hl_interface_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration hl_interface_command_handlers[] = { + { + .name = "hla", + .mode = COMMAND_ANY, + .help = "perform hla management", + .chain = hl_interface_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + struct adapter_driver hl_adapter_driver = { .name = "hla", .transports = hl_transports, diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 470ae18..6ba118f 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -86,7 +86,7 @@ extern tap_state_t cmd_queue_cur_state; */ struct scan_field { /** The number of bits this field specifies */ - int num_bits; + unsigned int num_bits; /** A pointer to value to be scanned into the device */ const uint8_t *out_value; /** A pointer to a 32-bit memory location for data scanned out */ @@ -102,12 +102,12 @@ struct jtag_tap { char *chip; char *tapname; char *dotted_name; - int abs_chain_position; + unsigned int abs_chain_position; /** Is this TAP disabled after JTAG reset? */ bool disabled_after_reset; /** Is this TAP currently enabled? */ bool enabled; - int ir_length; /**< size of instruction register */ + unsigned int ir_length; /**< size of instruction register */ uint32_t ir_capture_value; uint8_t *expected; /**< Capture-IR expected value */ uint32_t ir_capture_mask; @@ -150,10 +150,11 @@ struct jtag_tap *jtag_all_taps(void); const char *jtag_tap_name(const struct jtag_tap *tap); struct jtag_tap *jtag_tap_by_string(const char *dotted_name); struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *obj); -struct jtag_tap *jtag_tap_by_position(unsigned abs_position); +struct jtag_tap *jtag_tap_by_position(unsigned int abs_position); +/* FIXME: "jtag_tap_next_enabled()" should accept a const pointer. */ struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p); -unsigned jtag_tap_count_enabled(void); -unsigned jtag_tap_count(void); +unsigned int jtag_tap_count_enabled(void); +unsigned int jtag_tap_count(void); /* * - TRST_ASSERTED triggers two sets of callbacks, after operations to @@ -229,17 +230,17 @@ enum reset_types { enum reset_types jtag_get_reset_config(void); void jtag_set_reset_config(enum reset_types type); -void jtag_set_nsrst_delay(unsigned delay); -unsigned jtag_get_nsrst_delay(void); +void jtag_set_nsrst_delay(unsigned int delay); +unsigned int jtag_get_nsrst_delay(void); -void jtag_set_ntrst_delay(unsigned delay); -unsigned jtag_get_ntrst_delay(void); +void jtag_set_ntrst_delay(unsigned int delay); +unsigned int jtag_get_ntrst_delay(void); -void jtag_set_nsrst_assert_width(unsigned delay); -unsigned jtag_get_nsrst_assert_width(void); +void jtag_set_nsrst_assert_width(unsigned int delay); +unsigned int jtag_get_nsrst_assert_width(void); -void jtag_set_ntrst_assert_width(unsigned delay); -unsigned jtag_get_ntrst_assert_width(void); +void jtag_set_ntrst_assert_width(unsigned int delay); +unsigned int jtag_get_ntrst_assert_width(void); /** @returns The current state of TRST. */ int jtag_get_trst(void); @@ -436,7 +437,7 @@ void jtag_add_tlr(void); * - ERROR_JTAG_TRANSITION_INVALID -- The path includes invalid * state transitions. */ -void jtag_add_pathmove(int num_states, const tap_state_t *path); +void jtag_add_pathmove(unsigned int num_states, const tap_state_t *path); /** * jtag_add_statemove() moves from the current state to @a goal_state. @@ -459,7 +460,7 @@ int jtag_add_statemove(tap_state_t goal_state); * via TAP_IDLE. * @param endstate The final state. */ -void jtag_add_runtest(int num_cycles, tap_state_t endstate); +void jtag_add_runtest(unsigned int num_cycles, tap_state_t endstate); /** * A reset of the TAP state machine can be requested. @@ -488,14 +489,14 @@ void jtag_add_reset(int req_tlr_or_trst, int srst); void jtag_add_sleep(uint32_t us); -int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state t); +int jtag_add_tms_seq(unsigned int nbits, const uint8_t *seq, enum tap_state t); /** * Function jtag_add_clocks * first checks that the state in which the clocks are to be issued is * stable, then queues up num_cycles clocks for transmission. */ -void jtag_add_clocks(int num_cycles); +void jtag_add_clocks(unsigned int num_cycles); /** * For software FIFO implementations, the queued commands can be executed @@ -523,7 +524,7 @@ int jtag_execute_queue(void); void jtag_execute_queue_noclear(void); /** @returns the number of times the scan queue has been flushed */ -int jtag_get_flush_queue_count(void); +unsigned int jtag_get_flush_queue_count(void); /** Report Tcl event to all TAPs */ void jtag_notify_event(enum jtag_event); diff --git a/src/jtag/minidriver.h b/src/jtag/minidriver.h index a40cffa..45b0bf6 100644 --- a/src/jtag/minidriver.h +++ b/src/jtag/minidriver.h @@ -51,8 +51,8 @@ int interface_jtag_add_plain_dr_scan( tap_state_t endstate); int interface_jtag_add_tlr(void); -int interface_jtag_add_pathmove(int num_states, const tap_state_t *path); -int interface_jtag_add_runtest(int num_cycles, tap_state_t endstate); +int interface_jtag_add_pathmove(unsigned int num_states, const tap_state_t *path); +int interface_jtag_add_runtest(unsigned int num_cycles, tap_state_t endstate); int interface_add_tms_seq(unsigned num_bits, const uint8_t *bits, enum tap_state state); @@ -67,7 +67,7 @@ int interface_add_tms_seq(unsigned num_bits, */ int interface_jtag_add_reset(int trst, int srst); int interface_jtag_add_sleep(uint32_t us); -int interface_jtag_add_clocks(int num_cycles); +int interface_jtag_add_clocks(unsigned int num_cycles); int interface_jtag_execute_queue(void); /** diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 41db38e..2d8ebf0 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -1126,6 +1126,36 @@ proc "cmsis_dap_usb" {args} { eval cmsis-dap usb $args } +lappend _telnet_autocomplete_skip "hla_layout" +proc "hla_layout" {layout} { + echo "DEPRECATED! use 'hla layout', not 'hla_layout'" + eval hla layout $layout +} + +lappend _telnet_autocomplete_skip "hla_device_desc" +proc "hla_device_desc" {desc} { + echo "DEPRECATED! use 'hla device_desc', not 'hla_device_desc'" + eval hla device_desc $desc +} + +lappend _telnet_autocomplete_skip "hla_vid_pid" +proc "hla_vid_pid" {args} { + echo "DEPRECATED! use 'hla vid_pid', not 'hla_vid_pid'" + eval hla vid_pid $args +} + +lappend _telnet_autocomplete_skip "hla_command" +proc "hla_command" {command} { + echo "DEPRECATED! use 'hla command', not 'hla_command'" + eval hla command $command +} + +lappend _telnet_autocomplete_skip "hla_stlink_backend" +proc "hla_stlink_backend" {args} { + echo "DEPRECATED! use 'hla stlink_backend', not 'hla_stlink_backend'" + eval hla stlink_backend $args +} + lappend _telnet_autocomplete_skip "kitprog_init_acquire_psoc" proc "kitprog_init_acquire_psoc" {} { echo "DEPRECATED! use 'kitprog init_acquire_psoc', not 'kitprog_init_acquire_psoc'" diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 1a4c4b7..624b4e4 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -87,8 +87,11 @@ static COMMAND_HELPER(handle_jtag_command_drscan_fields, struct scan_field *fiel LOG_ERROR("Out of memory"); return ERROR_FAIL; } + fields[field_count].out_value = t; - str_to_buf(CMD_ARGV[i + 1], strlen(CMD_ARGV[i + 1]), t, bits, 0); + int ret = CALL_COMMAND_HANDLER(command_parse_str_to_buf, CMD_ARGV[i + 1], t, bits); + if (ret != ERROR_OK) + return ret; fields[field_count].in_value = t; field_count++; } @@ -209,8 +212,8 @@ COMMAND_HANDLER(handle_jtag_flush_count) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - int count = jtag_get_flush_queue_count(); - command_print_sameline(CMD, "%d", count); + const unsigned int count = jtag_get_flush_queue_count(); + command_print_sameline(CMD, "%u", count); return ERROR_OK; } @@ -445,11 +448,11 @@ static COMMAND_HELPER(handle_jtag_newtap_args, struct jtag_tap *tap) if (!CMD_ARGC) return ERROR_COMMAND_ARGUMENT_INVALID; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tap->ir_length); + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], tap->ir_length); CMD_ARGC--; CMD_ARGV++; - if (tap->ir_length > (int)(8 * sizeof(tap->ir_capture_value))) - LOG_WARNING("%s: huge IR length %d", tap->dotted_name, tap->ir_length); + if (tap->ir_length > (8 * sizeof(tap->ir_capture_value))) + LOG_WARNING("%s: huge IR length %u", tap->dotted_name, tap->ir_length); break; case NTAP_OPT_IRMASK: @@ -811,13 +814,13 @@ COMMAND_HANDLER(handle_scan_chain_command) expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length); command_print(CMD, - "%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x", + "%2u %-18s %c 0x%08x %s %5u 0x%02x 0x%02x", tap->abs_chain_position, tap->dotted_name, tap->enabled ? 'Y' : 'n', (unsigned int)(tap->idcode), expected_id, - (unsigned int)(tap->ir_length), + tap->ir_length, (unsigned int)(expected), (unsigned int)(expected_mask)); @@ -969,7 +972,7 @@ COMMAND_HANDLER(handle_irscan_command) if (retval != ERROR_OK) goto error_return; - int field_size = tap->ir_length; + unsigned int field_size = tap->ir_length; fields[i].num_bits = field_size; uint8_t *v = calloc(1, DIV_ROUND_UP(field_size, 8)); if (!v) { diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index f256bc2..e82ab6f 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -36,7 +36,18 @@ struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address, static inline threadid_t threadid_from_target(const struct target *target) { - return target->coreid + 1; + if (!target->smp) + return 1; + + threadid_t threadid = 1; + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + if (target == head->target) + return threadid; + ++threadid; + } + assert(0 && "Target is not found in it's own SMP group!"); + return -1; } const struct rtos_type hwthread_rtos = { @@ -59,14 +70,13 @@ struct hwthread_params { int dummy_param; }; -static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num) +static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num, threadid_t tid) { char tmp_str[HW_THREAD_NAME_STR_SIZE]; - threadid_t tid = threadid_from_target(curr); memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE); - /* thread-id is the core-id of this core inside the SMP group plus 1 */ + /* thread-id is the index of this core inside the SMP group plus 1 */ rtos->thread_details[thread_num].threadid = tid; /* create the thread name */ rtos->thread_details[thread_num].exists = true; @@ -131,8 +141,7 @@ static int hwthread_update_threads(struct rtos *rtos) continue; threadid_t tid = threadid_from_target(curr); - - hwthread_fill_thread(rtos, curr, threads_found); + hwthread_fill_thread(rtos, curr, threads_found, tid); /* find an interesting thread to set as current */ switch (current_reason) { @@ -189,8 +198,8 @@ static int hwthread_update_threads(struct rtos *rtos) threads_found++; } } else { - hwthread_fill_thread(rtos, target, threads_found); - current_thread = threadid_from_target(target); + current_thread = 1; + hwthread_fill_thread(rtos, target, threads_found, current_thread); threads_found++; } @@ -213,19 +222,17 @@ static int hwthread_smp_init(struct target *target) return hwthread_update_threads(target->rtos); } -static struct target *hwthread_find_thread(struct target *target, int64_t thread_id) +static struct target *hwthread_find_thread(struct target *target, threadid_t thread_id) { - /* Find the thread with that thread_id */ - if (!target) - return NULL; - if (target->smp) { - struct target_list *head; - foreach_smp_target(head, target->smp_targets) { - if (thread_id == threadid_from_target(head->target)) - return head->target; - } - } else if (thread_id == threadid_from_target(target)) { + /* Find the thread with that thread_id (index in SMP group plus 1)*/ + if (!(target && target->smp)) return target; + struct target_list *head; + threadid_t tid = 1; + foreach_smp_target(head, target->smp_targets) { + if (thread_id == tid) + return head->target; + ++tid; } return NULL; } @@ -304,7 +311,7 @@ static int hwthread_get_thread_reg_value(struct rtos *rtos, int64_t thread_id, } if (!target_was_examined(curr)) { - LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid); + LOG_TARGET_ERROR(curr, "Target hasn't been examined yet."); return ERROR_FAIL; } @@ -392,9 +399,9 @@ static int hwthread_thread_packet(struct connection *connection, const char *pac return ERROR_FAIL; } target->rtos->current_thread = current_threadid; - } else - if (current_threadid == 0 || current_threadid == -1) + } else if (current_threadid == 0 || current_threadid == -1) { target->rtos->current_thread = threadid_from_target(target); + } target->rtos->current_threadid = current_threadid; diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 9100148..821e550 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -32,7 +32,6 @@ struct nuttx_params { const char *target_name; const struct rtos_register_stacking *stacking; - const struct rtos_register_stacking *(*select_stackinfo)(struct target *target); }; /* @@ -56,19 +55,12 @@ struct symbols { bool optional; }; -/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */ -enum nuttx_symbol_vals { - NX_SYM_READYTORUN = 0, - NX_SYM_PIDHASH, - NX_SYM_NPIDHASH, - NX_SYM_TCB_INFO, -}; - static const struct symbols nuttx_symbol_list[] = { { "g_readytorun", false }, { "g_pidhash", false }, { "g_npidhash", false }, { "g_tcbinfo", false }, + { "g_reg_offs", false}, { NULL, false } }; @@ -86,18 +78,14 @@ static char *task_state_str[] = { "STOPPED", }; -static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target); - static const struct nuttx_params nuttx_params_list[] = { { .target_name = "cortex_m", - .stacking = NULL, - .select_stackinfo = cortexm_select_stackinfo, + .stacking = &nuttx_stacking_cortex_m, }, { .target_name = "hla_target", - .stacking = NULL, - .select_stackinfo = cortexm_select_stackinfo, + .stacking = &nuttx_stacking_cortex_m, }, { .target_name = "esp32", @@ -117,28 +105,6 @@ static const struct nuttx_params nuttx_params_list[] = { }, }; -static bool cortexm_hasfpu(struct target *target) -{ - uint32_t cpacr; - struct armv7m_common *armv7m_target = target_to_armv7m(target); - - if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE) - return false; - - int retval = target_read_u32(target, FPU_CPACR, &cpacr); - if (retval != ERROR_OK) { - LOG_ERROR("Could not read CPACR register to check FPU state"); - return false; - } - - return cpacr & 0x00F00000; -} - -static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target) -{ - return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m; -} - static bool nuttx_detect_rtos(struct target *target) { if (target->rtos->symbols && @@ -371,29 +337,25 @@ static int nuttx_getreg_current_thread(struct rtos *rtos, static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs) { - uint16_t xcpreg_off; + uint16_t regs_off; uint32_t regsaddr; const struct nuttx_params *priv = rtos->rtos_specific_params; const struct rtos_register_stacking *stacking = priv->stacking; if (!stacking) { - if (priv->select_stackinfo) { - stacking = priv->select_stackinfo(rtos->target); - } else { - LOG_ERROR("Can't find a way to get stacking info"); - return ERROR_FAIL; - } + LOG_ERROR("Can't find a way to get stacking info"); + return ERROR_FAIL; } int ret = target_read_u16(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off), - &xcpreg_off); + ®s_off); if (ret != ERROR_OK) { LOG_ERROR("Failed to read registers' offset: ret = %d", ret); return ERROR_FAIL; } - ret = target_read_u32(rtos->target, thread_id + xcpreg_off, ®saddr); + ret = target_read_u32(rtos->target, thread_id + regs_off, ®saddr); if (ret != ERROR_OK) { LOG_ERROR("Failed to read registers' address: ret = %d", ret); return ERROR_FAIL; diff --git a/src/rtos/rtos_nuttx_stackings.c b/src/rtos/rtos_nuttx_stackings.c index b70cccb..6faa56a 100644 --- a/src/rtos/rtos_nuttx_stackings.c +++ b/src/rtos/rtos_nuttx_stackings.c @@ -9,60 +9,100 @@ #include "rtos_nuttx_stackings.h" #include "rtos_standard_stackings.h" #include <target/riscv/riscv.h> +#include <helper/bits.h> -/* see arch/arm/include/armv7-m/irq_cmnvector.h */ +/* The cortex_m target uses nuttx_tcbinfo_stack_read which uses a symbol + * provided by Nuttx to read the registers from memory and place them directly + * in the order we need. This is because the register offsets change with + * different versions of Nuttx, FPU vs non-FPU and ARMv7 vs ARMv8. + * This allows a single function to work with many versions. + */ static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = { - { ARMV7M_R0, 0x28, 32 }, /* r0 */ - { ARMV7M_R1, 0x2c, 32 }, /* r1 */ - { ARMV7M_R2, 0x30, 32 }, /* r2 */ - { ARMV7M_R3, 0x34, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x38, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x3c, 32 }, /* lr */ - { ARMV7M_PC, 0x40, 32 }, /* pc */ - { ARMV7M_XPSR, 0x44, 32 }, /* xPSR */ + { ARMV7M_R0, 0, 32 }, /* r0 */ + { ARMV7M_R1, 4, 32 }, /* r1 */ + { ARMV7M_R2, 8, 32 }, /* r2 */ + { ARMV7M_R3, 12, 32 }, /* r3 */ + { ARMV7M_R4, 16, 32 }, /* r4 */ + { ARMV7M_R5, 20, 32 }, /* r5 */ + { ARMV7M_R6, 24, 32 }, /* r6 */ + { ARMV7M_R7, 28, 32 }, /* r7 */ + { ARMV7M_R8, 32, 32 }, /* r8 */ + { ARMV7M_R9, 36, 32 }, /* r9 */ + { ARMV7M_R10, 40, 32 }, /* r10 */ + { ARMV7M_R11, 44, 32 }, /* r11 */ + { ARMV7M_R12, 48, 32 }, /* r12 */ + { ARMV7M_R13, 52, 32 }, /* sp */ + { ARMV7M_R14, 56, 32 }, /* lr */ + { ARMV7M_PC, 60, 32 }, /* pc */ + { ARMV7M_XPSR, 64, 32 }, /* xPSR */ }; -const struct rtos_register_stacking nuttx_stacking_cortex_m = { - .stack_registers_size = 0x48, - .stack_growth_direction = -1, - .num_output_registers = 17, - .register_offsets = nuttx_stack_offsets_cortex_m, -}; +/* The Nuttx stack frame for most architectures has some registers placed + * by hardware and some by software. The hardware register order and number does not change + * but the software registers may change with different versions of Nuttx. + * For example with ARMv7, nuttx-12.3.0 added a new register which changed all + * the offsets. We can either create separate offset tables for each version of Nuttx + * which will break again in the future, or read the offsets from the TCB info. + * Nuttx provides a symbol (g_reg_offs) which holds all the offsets for each stored register. + * This offset table is stored in GDB org.gnu.gdb.xxx feature order. + * The same order we need. + * Please refer: + * https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Features.html + * https://sourceware.org/gdb/current/onlinedocs/gdb/RISC_002dV-Features.html + */ +static int nuttx_cortex_m_tcbinfo_stack_read(struct target *target, + int64_t stack_ptr, const struct rtos_register_stacking *stacking, + uint8_t *stack_data) +{ + struct rtos *rtos = target->rtos; + target_addr_t xcpreg_off = rtos->symbols[NX_SYM_REG_OFFSETS].address; -static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = { - { ARMV7M_R0, 0x6c, 32 }, /* r0 */ - { ARMV7M_R1, 0x70, 32 }, /* r1 */ - { ARMV7M_R2, 0x74, 32 }, /* r2 */ - { ARMV7M_R3, 0x78, 32 }, /* r3 */ - { ARMV7M_R4, 0x08, 32 }, /* r4 */ - { ARMV7M_R5, 0x0c, 32 }, /* r5 */ - { ARMV7M_R6, 0x10, 32 }, /* r6 */ - { ARMV7M_R7, 0x14, 32 }, /* r7 */ - { ARMV7M_R8, 0x18, 32 }, /* r8 */ - { ARMV7M_R9, 0x1c, 32 }, /* r9 */ - { ARMV7M_R10, 0x20, 32 }, /* r10 */ - { ARMV7M_R11, 0x24, 32 }, /* r11 */ - { ARMV7M_R12, 0x7c, 32 }, /* r12 */ - { ARMV7M_R13, 0, 32 }, /* sp */ - { ARMV7M_R14, 0x80, 32 }, /* lr */ - { ARMV7M_PC, 0x84, 32 }, /* pc */ - { ARMV7M_XPSR, 0x88, 32 }, /* xPSR */ -}; + for (int i = 0; i < stacking->num_output_registers; ++i) { + uint16_t stack_reg_offset; + int ret = target_read_u16(rtos->target, xcpreg_off + 2 * i, &stack_reg_offset); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read stack_reg_offset: ret = %d", ret); + return ret; + } + if (stack_reg_offset != UINT16_MAX && stacking->register_offsets[i].offset >= 0) { + ret = target_read_buffer(target, + stack_ptr + stack_reg_offset, + stacking->register_offsets[i].width_bits / 8, + &stack_data[stacking->register_offsets[i].offset]); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read register: ret = %d", ret); + return ret; + } + } + } + + /* Offset match nuttx_stack_offsets_cortex_m */ + const int XPSR_OFFSET = 64; + const int SP_OFFSET = 52; + /* Nuttx stack frames (produced in exception_common) store the SP of the ISR minus + * the hardware stack frame size. This SP may include an additional 4 byte alignment + * depending in xPSR[9]. The Nuttx stack frame stores post alignment since the + * hardware will add/remove automatically on both enter/exit. + * We need to adjust the SP to get the real SP of the stack. + * See Arm Reference manual "Stack alignment on exception entry" + */ + uint32_t xpsr = target_buffer_get_u32(target, &stack_data[XPSR_OFFSET]); + if (xpsr & BIT(9)) { + uint32_t sp = target_buffer_get_u32(target, &stack_data[SP_OFFSET]); + target_buffer_set_u32(target, &stack_data[SP_OFFSET], sp - 4 * stacking->stack_growth_direction); + } -const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = { - .stack_registers_size = 0x8c, + return ERROR_OK; +} + +const struct rtos_register_stacking nuttx_stacking_cortex_m = { + /* nuttx_tcbinfo_stack_read transforms the stack into just output registers */ + .stack_registers_size = ARRAY_SIZE(nuttx_stack_offsets_cortex_m) * 4, .stack_growth_direction = -1, - .num_output_registers = 17, - .register_offsets = nuttx_stack_offsets_cortex_m_fpu, + .num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_cortex_m), + .read_stack = nuttx_cortex_m_tcbinfo_stack_read, + .calculate_process_stack = NULL, /* Stack alignment done in nuttx_cortex_m_tcbinfo_stack_read */ + .register_offsets = nuttx_stack_offsets_cortex_m, }; static const struct stack_register_offset nuttx_stack_offsets_riscv[] = { diff --git a/src/rtos/rtos_nuttx_stackings.h b/src/rtos/rtos_nuttx_stackings.h index 213a060..5d55e75 100644 --- a/src/rtos/rtos_nuttx_stackings.h +++ b/src/rtos/rtos_nuttx_stackings.h @@ -5,6 +5,15 @@ #include "rtos.h" +/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */ +enum nuttx_symbol_vals { + NX_SYM_READYTORUN = 0, + NX_SYM_PIDHASH, + NX_SYM_NPIDHASH, + NX_SYM_TCB_INFO, + NX_SYM_REG_OFFSETS, +}; + extern const struct rtos_register_stacking nuttx_stacking_cortex_m; extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu; extern const struct rtos_register_stacking nuttx_riscv_stacking; diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c index 0ca664f..360ae9b 100644 --- a/src/rtos/rtos_standard_stackings.c +++ b/src/rtos/rtos_standard_stackings.c @@ -327,9 +327,7 @@ target_addr_t rtos_cortex_m_stack_align(struct target *target, new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; - xpsr = (target->endianness == TARGET_LITTLE_ENDIAN) ? - le_to_h_u32(&stack_data[xpsr_offset]) : - be_to_h_u32(&stack_data[xpsr_offset]); + xpsr = target_buffer_get_u32(target, &stack_data[xpsr_offset]); if ((xpsr & ALIGN_NEEDED) != 0) { LOG_DEBUG("XPSR(0x%08" PRIx32 ") indicated stack alignment was necessary\r\n", xpsr); diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c index 2b8822f..bae71b6 100644 --- a/src/rtt/tcl.c +++ b/src/rtt/tcl.c @@ -19,8 +19,14 @@ COMMAND_HANDLER(handle_rtt_setup_command) { struct rtt_source source; - if (CMD_ARGC != 3) + const char *DEFAULT_ID = "SEGGER RTT"; + const char *selected_id; + if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; + if (CMD_ARGC == 2) + selected_id = DEFAULT_ID; + else + selected_id = CMD_ARGV[2]; source.find_cb = &target_rtt_find_control_block; source.read_cb = &target_rtt_read_control_block; @@ -38,7 +44,7 @@ COMMAND_HANDLER(handle_rtt_setup_command) rtt_register_source(source, get_current_target(CMD_CTX)); - if (rtt_setup(address, size, CMD_ARGV[2]) != ERROR_OK) + if (rtt_setup(address, size, selected_id) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; @@ -218,7 +224,7 @@ static const struct command_registration rtt_subcommand_handlers[] = { .handler = handle_rtt_setup_command, .mode = COMMAND_ANY, .help = "setup RTT", - .usage = "<address> <size> <ID>" + .usage = "<address> <size> [ID]" }, { .name = "start", diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f4ce5df..8553137 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1599,7 +1599,7 @@ static int gdb_read_memory_packet(struct connection *connection, * cmd = view%20audit-trail&database = gdb&pr = 2395 * * For now, the default is to fix up things to make current GDB versions work. - * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command. + * This can be overwritten using the "gdb report_data_abort <'enable'|'disable'>" command. */ memset(buffer, 0, len); retval = ERROR_OK; @@ -1838,18 +1838,9 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, return ERROR_FAIL; } retval = breakpoint_add(target, address, size, bp_type); - if (retval == ERROR_NOT_IMPLEMENTED) { - /* Send empty reply to report that breakpoints of this type are not supported */ - gdb_put_packet(connection, "", 0); - } else if (retval != ERROR_OK) { - retval = gdb_error(connection, retval); - if (retval != ERROR_OK) - return retval; - } else - gdb_put_packet(connection, "OK", 2); } else { - breakpoint_remove(target, address); - gdb_put_packet(connection, "OK", 2); + assert(packet[0] == 'z'); + retval = breakpoint_remove(target, address); } break; case 2: @@ -1858,26 +1849,26 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection, { if (packet[0] == 'Z') { retval = watchpoint_add(target, address, size, wp_type, 0, WATCHPOINT_IGNORE_DATA_VALUE_MASK); - if (retval == ERROR_NOT_IMPLEMENTED) { - /* Send empty reply to report that watchpoints of this type are not supported */ - gdb_put_packet(connection, "", 0); - } else if (retval != ERROR_OK) { - retval = gdb_error(connection, retval); - if (retval != ERROR_OK) - return retval; - } else - gdb_put_packet(connection, "OK", 2); } else { - watchpoint_remove(target, address); - gdb_put_packet(connection, "OK", 2); + assert(packet[0] == 'z'); + retval = watchpoint_remove(target, address); } break; } default: + { + retval = ERROR_NOT_IMPLEMENTED; break; + } } - return ERROR_OK; + if (retval == ERROR_NOT_IMPLEMENTED) { + /* Send empty reply to report that watchpoints of this type are not supported */ + return gdb_put_packet(connection, "", 0); + } + if (retval != ERROR_OK) + return gdb_error(connection, retval); + return gdb_put_packet(connection, "OK", 2); } /* print out a string and allocate more space as needed, @@ -4034,7 +4025,7 @@ COMMAND_HANDLER(handle_gdb_sync_command) if (!current_gdb_connection) { command_print(CMD, - "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\""); + "gdb sync command can only be run from within gdb using \"monitor gdb sync\""); return ERROR_FAIL; } @@ -4043,7 +4034,6 @@ COMMAND_HANDLER(handle_gdb_sync_command) return ERROR_OK; } -/* daemon configuration command gdb_port */ COMMAND_HANDLER(handle_gdb_port_command) { int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port); @@ -4090,7 +4080,6 @@ COMMAND_HANDLER(handle_gdb_report_register_access_error) return ERROR_OK; } -/* gdb_breakpoint_override */ COMMAND_HANDLER(handle_gdb_breakpoint_override_command) { if (CMD_ARGC == 0) { @@ -4167,9 +4156,9 @@ out: return retval; } -static const struct command_registration gdb_command_handlers[] = { +static const struct command_registration gdb_subcommand_handlers[] = { { - .name = "gdb_sync", + .name = "sync", .handler = handle_gdb_sync_command, .mode = COMMAND_ANY, .help = "next stepi will return immediately allowing " @@ -4178,7 +4167,7 @@ static const struct command_registration gdb_command_handlers[] = { .usage = "" }, { - .name = "gdb_port", + .name = "port", .handler = handle_gdb_port_command, .mode = COMMAND_CONFIG, .help = "Normally gdb listens to a TCP/IP port. Each subsequent GDB " @@ -4191,35 +4180,35 @@ static const struct command_registration gdb_command_handlers[] = { .usage = "[port_num]", }, { - .name = "gdb_memory_map", + .name = "memory_map", .handler = handle_gdb_memory_map_command, .mode = COMMAND_CONFIG, .help = "enable or disable memory map", .usage = "('enable'|'disable')" }, { - .name = "gdb_flash_program", + .name = "flash_program", .handler = handle_gdb_flash_program_command, .mode = COMMAND_CONFIG, .help = "enable or disable flash program", .usage = "('enable'|'disable')" }, { - .name = "gdb_report_data_abort", + .name = "report_data_abort", .handler = handle_gdb_report_data_abort_command, .mode = COMMAND_CONFIG, .help = "enable or disable reporting data aborts", .usage = "('enable'|'disable')" }, { - .name = "gdb_report_register_access_error", + .name = "report_register_access_error", .handler = handle_gdb_report_register_access_error, .mode = COMMAND_CONFIG, .help = "enable or disable reporting register access errors", .usage = "('enable'|'disable')" }, { - .name = "gdb_breakpoint_override", + .name = "breakpoint_override", .handler = handle_gdb_breakpoint_override_command, .mode = COMMAND_ANY, .help = "Display or specify type of breakpoint " @@ -4227,14 +4216,14 @@ static const struct command_registration gdb_command_handlers[] = { .usage = "('hard'|'soft'|'disable')" }, { - .name = "gdb_target_description", + .name = "target_description", .handler = handle_gdb_target_description_command, .mode = COMMAND_CONFIG, .help = "enable or disable target description", .usage = "('enable'|'disable')" }, { - .name = "gdb_save_tdesc", + .name = "save_tdesc", .handler = handle_gdb_save_tdesc_command, .mode = COMMAND_EXEC, .help = "Save the target description file", @@ -4243,6 +4232,17 @@ static const struct command_registration gdb_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration gdb_command_handlers[] = { + { + .name = "gdb", + .mode = COMMAND_ANY, + .help = "GDB commands", + .chain = gdb_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + int gdb_register_commands(struct command_context *cmd_ctx) { gdb_port = strdup("3333"); diff --git a/src/server/startup.tcl b/src/server/startup.tcl index 1d30b1d..cf3eca3 100644 --- a/src/server/startup.tcl +++ b/src/server/startup.tcl @@ -41,3 +41,81 @@ proc _telnet_autocomplete_helper pattern { return [lsort $cmds] } + +lappend _telnet_autocomplete_skip "gdb_sync" +proc "gdb_sync" {} { + echo "DEPRECATED! use 'gdb sync', not 'gdb_sync'" + eval gdb sync +} + +lappend _telnet_autocomplete_skip "gdb_port" +proc "gdb_port" {args} { + echo "DEPRECATED! use 'gdb port', not 'gdb_port'" + eval gdb port $args +} + +lappend _telnet_autocomplete_skip "gdb_memory_map" +proc "gdb_memory_map" {state} { + echo "DEPRECATED! use 'gdb memory_map', not 'gdb_memory_map'" + eval gdb memory_map $state +} + +lappend _telnet_autocomplete_skip "gdb_flash_program" +proc "gdb_flash_program" {state} { + echo "DEPRECATED! use 'gdb flash_program', not 'gdb_flash_program'" + eval gdb flash_program $state +} + +lappend _telnet_autocomplete_skip "gdb_report_data_abort" +proc "gdb_report_data_abort" {state} { + echo "DEPRECATED! use 'gdb report_data_abort', not 'gdb_report_data_abort'" + eval gdb report_data_abort $state +} + +lappend _telnet_autocomplete_skip "gdb_report_register_access_error" +proc "gdb_report_register_access_error" {state} { + echo "DEPRECATED! use 'gdb report_register_access_error', not 'gdb_report_register_access_error'" + eval gdb report_register_access_error $state +} + +lappend _telnet_autocomplete_skip "gdb_breakpoint_override" +proc "gdb_breakpoint_override" {override} { + echo "DEPRECATED! use 'gdb breakpoint_override', not 'gdb_breakpoint_override'" + eval gdb breakpoint_override $override +} + +lappend _telnet_autocomplete_skip "gdb_target_description" +proc "gdb_target_description" {state} { + echo "DEPRECATED! use 'gdb target_description', not 'gdb_target_description'" + eval gdb target_description $state +} + +lappend _telnet_autocomplete_skip "gdb_save_tdesc" +proc "gdb_save_tdesc" {} { + echo "DEPRECATED! use 'gdb save_tdesc', not 'gdb_save_tdesc'" + eval gdb save_tdesc +} + +lappend _telnet_autocomplete_skip "tcl_port" +proc "tcl_port" {args} { + echo "DEPRECATED! use 'tcl port' not 'tcl_port'" + eval tcl port $args +} + +lappend _telnet_autocomplete_skip "tcl_notifications" +proc "tcl_notifications" {state} { + echo "DEPRECATED! use 'tcl notifications' not 'tcl_notifications'" + eval tcl notifications $state +} + +lappend _telnet_autocomplete_skip "tcl_trace" +proc "tcl_trace" {state} { + echo "DEPRECATED! use 'tcl trace' not 'tcl_trace'" + eval tcl trace $state +} + +lappend _telnet_autocomplete_skip "telnet_port" +proc "telnet_port" {args} { + echo "DEPRECATED! use 'telnet port', not 'telnet_port'" + eval telnet port $args +} diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 16cbedc..16cc55e 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -323,25 +323,25 @@ COMMAND_HANDLER(handle_tcl_trace_command) } } -static const struct command_registration tcl_command_handlers[] = { +static const struct command_registration tcl_subcommand_handlers[] = { { - .name = "tcl_port", + .name = "port", .handler = handle_tcl_port_command, .mode = COMMAND_CONFIG, .help = "Specify port on which to listen " "for incoming Tcl syntax. " - "Read help on 'gdb_port'.", + "Read help on 'gdb port'.", .usage = "[port_num]", }, { - .name = "tcl_notifications", + .name = "notifications", .handler = handle_tcl_notifications_command, .mode = COMMAND_EXEC, .help = "Target Notification output", .usage = "[on|off]", }, { - .name = "tcl_trace", + .name = "trace", .handler = handle_tcl_trace_command, .mode = COMMAND_EXEC, .help = "Target trace output", @@ -350,6 +350,17 @@ static const struct command_registration tcl_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration tcl_command_handlers[] = { + { + .name = "tcl", + .mode = COMMAND_ANY, + .help = "tcl command group", + .usage = "", + .chain = tcl_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + int tcl_register_commands(struct command_context *cmd_ctx) { tcl_port = strdup("6666"); diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 938bc5b..a596afe 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -967,7 +967,6 @@ int telnet_init(char *banner) return ERROR_OK; } -/* daemon configuration command telnet_port */ COMMAND_HANDLER(handle_telnet_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port); @@ -978,22 +977,33 @@ COMMAND_HANDLER(handle_exit_command) return ERROR_COMMAND_CLOSE_CONNECTION; } +static const struct command_registration telnet_subcommand_handlers[] = { + { + .name = "port", + .handler = handle_telnet_port_command, + .mode = COMMAND_CONFIG, + .help = "Specify port on which to listen " + "for incoming telnet connections. " + "Read help on 'gdb port'.", + .usage = "[port_num]", + }, + COMMAND_REGISTRATION_DONE +}; + static const struct command_registration telnet_command_handlers[] = { { .name = "exit", .handler = handle_exit_command, - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .usage = "", .help = "exit telnet session", }, { - .name = "telnet_port", - .handler = handle_telnet_port_command, + .name = "telnet", + .chain = telnet_subcommand_handlers, .mode = COMMAND_CONFIG, - .help = "Specify port on which to listen " - "for incoming telnet connections. " - "Read help on 'gdb_port'.", - .usage = "[port_num]", + .help = "telnet commands", + .usage = "", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/svf/svf.c b/src/svf/svf.c index dd3d517..4708899 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -932,7 +932,7 @@ static int svf_check_tdo(void) index_var = svf_check_tdo_para[i].buffer_offset; len = svf_check_tdo_para[i].bit_len; if ((svf_check_tdo_para[i].enabled) - && buf_cmp_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var], + && !buf_eq_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var], &svf_mask_buffer[index_var], len)) { LOG_ERROR("tdo check error at line %d", svf_check_tdo_para[i].line_num); diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 6a70b2d..f0d486f 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -193,6 +193,20 @@ static int aarch64_mmu_modify(struct target *target, int enable) return retval; } +static int aarch64_read_prsr(struct target *target, uint32_t *prsr) +{ + struct armv8_common *armv8 = target_to_armv8(target); + int retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRSR, prsr); + if (retval != ERROR_OK) + return retval; + + armv8->sticky_reset |= *prsr & PRSR_SR; + return ERROR_OK; +} + /* * Basic debug access, very low level assumes state is saved */ @@ -213,8 +227,7 @@ static int aarch64_init_debug_access(struct target *target) /* Clear Sticky Power Down status Bit in PRSR to enable access to the registers in the Core Power Domain */ - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &dummy); + retval = aarch64_read_prsr(target, &dummy); if (retval != ERROR_OK) return retval; @@ -281,12 +294,10 @@ static int aarch64_set_dscr_bits(struct target *target, unsigned long bit_mask, static int aarch64_check_state_one(struct target *target, uint32_t mask, uint32_t val, int *p_result, uint32_t *p_prsr) { - struct armv8_common *armv8 = target_to_armv8(target); uint32_t prsr; int retval; - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &prsr); + retval = aarch64_read_prsr(target, &prsr); if (retval != ERROR_OK) return retval; @@ -506,16 +517,28 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug static int aarch64_poll(struct target *target) { + struct armv8_common *armv8 = target_to_armv8(target); enum target_state prev_target_state; int retval = ERROR_OK; - int halted; + uint32_t prsr; - retval = aarch64_check_state_one(target, - PRSR_HALT, PRSR_HALT, &halted, NULL); + retval = aarch64_read_prsr(target, &prsr); if (retval != ERROR_OK) return retval; - if (halted) { + if (armv8->sticky_reset) { + armv8->sticky_reset = false; + if (target->state != TARGET_RESET) { + target->state = TARGET_RESET; + LOG_TARGET_INFO(target, "external reset detected"); + if (armv8->arm.core_cache) { + register_cache_invalidate(armv8->arm.core_cache); + register_cache_invalidate(armv8->arm.core_cache->next); + } + } + } + + if (prsr & PRSR_HALT) { prev_target_state = target->state; if (prev_target_state != TARGET_HALTED) { enum target_debug_reason debug_reason = target->debug_reason; @@ -546,8 +569,11 @@ static int aarch64_poll(struct target *target) break; } } - } else + } else if (prsr & PRSR_RESET) { + target->state = TARGET_RESET; + } else { target->state = TARGET_RUNNING; + } return retval; } @@ -663,8 +689,7 @@ static int aarch64_prepare_restart_one(struct target *target) if (retval == ERROR_OK) { /* clear sticky bits in PRSR, SDR is now 0 */ - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &tmp); + retval = aarch64_read_prsr(target, &tmp); } return retval; diff --git a/src/target/arm.h b/src/target/arm.h index 486666b..0de322a 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -58,11 +58,12 @@ enum arm_arch { ARM_ARCH_V8M, }; -/** Known ARM implementor IDs */ -enum arm_implementor { - ARM_IMPLEMENTOR_ARM = 0x41, - ARM_IMPLEMENTOR_INFINEON = 0x49, - ARM_IMPLEMENTOR_REALTEK = 0x72, +/** Known ARM implementer IDs */ +enum arm_implementer { + ARM_IMPLEMENTER_ARM = 0x41, + ARM_IMPLEMENTER_INFINEON = 0x49, + ARM_IMPLEMENTER_ARM_CHINA = 0x63, + ARM_IMPLEMENTER_REALTEK = 0x72, }; /** diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 9129ace..3a5afc6 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -795,11 +795,12 @@ int dap_dp_init(struct adiv5_dap *dap) dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; /* - * This write operation clears the sticky error bit in jtag mode only and - * is ignored in swd mode. It also powers-up system and debug domains in - * both jtag and swd modes, if not done before. + * This write operation clears the sticky error and overrun bits in jtag + * mode only and is ignored in swd mode. It also powers-up system and + * debug domains in both jtag and swd modes, if not done before. */ - retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR); + retval = dap_queue_dp_write(dap, DP_CTRL_STAT, + dap->dp_ctrl_stat | SSTICKYERR | SSTICKYORUN); if (retval != ERROR_OK) return retval; @@ -1453,11 +1454,13 @@ static const struct dap_part_nums { { ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", }, { ARM_ID, 0x4b5, "Cortex-R5 ROM", "(ROM Table)", }, { ARM_ID, 0x4b8, "Cortex-R52 ROM", "(ROM Table)", }, + { ARM_ID, 0x4bd, "Cortex-R52+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", }, { ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", }, { ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", }, { ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", }, + { ARM_ID, 0x4c9, "STAR ROM", "(ROM Table)", }, { ARM_ID, 0x4e0, "Cortex-A35 ROM", "(v7 Memory Map ROM Table)", }, { ARM_ID, 0x4e4, "Cortex-A76 ROM", "(ROM Table)", }, { ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", }, @@ -1499,6 +1502,7 @@ static const struct dap_part_nums { { ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9b6, "Cortex-R52 PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, + { ARM_ID, 0x9bb, "Cortex-R52+ PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, { ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", }, @@ -1533,6 +1537,10 @@ static const struct dap_part_nums { { ARM_ID, 0xd0b, "Cortex-A76 Debug", "(Debug Unit)", }, { ARM_ID, 0xd0c, "Neoverse N1", "(Debug Unit)", }, { ARM_ID, 0xd13, "Cortex-R52 Debug", "(Debug Unit)", }, + { ARM_ID, 0xd16, "Cortex-R52+ Debug", "(Debug Unit)", }, + { ARM_ID, 0xd21, "STAR Debug", "(Debug Unit)", }, + { ARM_ID, 0xd22, "Cortex-M55 Debug", "(Debug Unit)", }, + { ARM_ID, 0xd43, "Cortex-A65AE Debug", "(Debug Unit)", }, { ARM_ID, 0xd49, "Neoverse N2", "(Debug Unit)", }, { 0x017, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */ { 0x017, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */ @@ -1552,6 +1560,9 @@ static const struct dap_part_nums { { 0x1eb, 0x211, "Tegra 210 ROM", "(ROM Table)", }, { 0x1eb, 0x302, "Denver Debug", "(Debug Unit)", }, { 0x1eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", }, + { 0x575, 0x132, "STAR SCS", "(System Control Space)", }, + { 0x575, 0x4d2, "Cortex-M52 ROM", "(ROM Table)", }, + { 0x575, 0xd24, "Cortex-M52 Debug", "(Debug Unit)", }, }; static const struct dap_part_nums *pidr_to_part_num(unsigned int designer_id, unsigned int part_num) diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 7637ad0..97d1fb3 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -157,48 +157,44 @@ int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel) return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel)); } -static uint32_t cti_regs[28]; - static const struct { uint32_t offset; const char *label; - uint32_t *p_val; } cti_names[] = { - { CTI_CTR, "CTR", &cti_regs[0] }, - { CTI_GATE, "GATE", &cti_regs[1] }, - { CTI_INEN0, "INEN0", &cti_regs[2] }, - { CTI_INEN1, "INEN1", &cti_regs[3] }, - { CTI_INEN2, "INEN2", &cti_regs[4] }, - { CTI_INEN3, "INEN3", &cti_regs[5] }, - { CTI_INEN4, "INEN4", &cti_regs[6] }, - { CTI_INEN5, "INEN5", &cti_regs[7] }, - { CTI_INEN6, "INEN6", &cti_regs[8] }, - { CTI_INEN7, "INEN7", &cti_regs[9] }, - { CTI_INEN8, "INEN8", &cti_regs[10] }, - { CTI_OUTEN0, "OUTEN0", &cti_regs[11] }, - { CTI_OUTEN1, "OUTEN1", &cti_regs[12] }, - { CTI_OUTEN2, "OUTEN2", &cti_regs[13] }, - { CTI_OUTEN3, "OUTEN3", &cti_regs[14] }, - { CTI_OUTEN4, "OUTEN4", &cti_regs[15] }, - { CTI_OUTEN5, "OUTEN5", &cti_regs[16] }, - { CTI_OUTEN6, "OUTEN6", &cti_regs[17] }, - { CTI_OUTEN7, "OUTEN7", &cti_regs[18] }, - { CTI_OUTEN8, "OUTEN8", &cti_regs[19] }, - { CTI_TRIN_STATUS, "TRIN", &cti_regs[20] }, - { CTI_TROUT_STATUS, "TROUT", &cti_regs[21] }, - { CTI_CHIN_STATUS, "CHIN", &cti_regs[22] }, - { CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] }, - { CTI_APPSET, "APPSET", &cti_regs[24] }, - { CTI_APPCLEAR, "APPCLR", &cti_regs[25] }, - { CTI_APPPULSE, "APPPULSE", &cti_regs[26] }, - { CTI_INACK, "INACK", &cti_regs[27] }, + { CTI_CTR, "CTR" }, + { CTI_GATE, "GATE" }, + { CTI_INEN0, "INEN0" }, + { CTI_INEN1, "INEN1" }, + { CTI_INEN2, "INEN2" }, + { CTI_INEN3, "INEN3" }, + { CTI_INEN4, "INEN4" }, + { CTI_INEN5, "INEN5" }, + { CTI_INEN6, "INEN6" }, + { CTI_INEN7, "INEN7" }, + { CTI_INEN8, "INEN8" }, + { CTI_OUTEN0, "OUTEN0" }, + { CTI_OUTEN1, "OUTEN1" }, + { CTI_OUTEN2, "OUTEN2" }, + { CTI_OUTEN3, "OUTEN3" }, + { CTI_OUTEN4, "OUTEN4" }, + { CTI_OUTEN5, "OUTEN5" }, + { CTI_OUTEN6, "OUTEN6" }, + { CTI_OUTEN7, "OUTEN7" }, + { CTI_OUTEN8, "OUTEN8" }, + { CTI_TRIN_STATUS, "TRIN" }, + { CTI_TROUT_STATUS, "TROUT" }, + { CTI_CHIN_STATUS, "CHIN" }, + { CTI_CHOU_STATUS, "CHOUT" }, + { CTI_APPSET, "APPSET" }, + { CTI_APPCLEAR, "APPCLR" }, + { CTI_APPPULSE, "APPPULSE" }, + { CTI_INACK, "INACK" }, + { CTI_DEVCTL, "DEVCTL" }, }; static int cti_find_reg_offset(const char *name) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cti_names); i++) { + for (size_t i = 0; i < ARRAY_SIZE(cti_names); i++) { if (!strcmp(name, cti_names[i].label)) return cti_names[i].offset; } @@ -226,10 +222,11 @@ COMMAND_HANDLER(handle_cti_dump) struct arm_cti *cti = CMD_DATA; struct adiv5_ap *ap = cti->ap; int retval = ERROR_OK; + uint32_t values[ARRAY_SIZE(cti_names)]; - for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) + for (size_t i = 0; (retval == ERROR_OK) && (i < ARRAY_SIZE(cti_names)); i++) retval = mem_ap_read_u32(ap, - cti->spot.base + cti_names[i].offset, cti_names[i].p_val); + cti->spot.base + cti_names[i].offset, &values[i]); if (retval == ERROR_OK) retval = dap_run(ap->dap); @@ -237,9 +234,9 @@ COMMAND_HANDLER(handle_cti_dump) if (retval != ERROR_OK) return JIM_ERR; - for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++) + for (size_t i = 0; i < ARRAY_SIZE(cti_names); i++) command_print(CMD, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32, - cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val); + cti_names[i].label, cti_names[i].offset, values[i]); return JIM_OK; } @@ -323,7 +320,6 @@ COMMAND_HANDLER(handle_cti_ack) int retval = arm_cti_ack_events(cti, 1 << event); - if (retval != ERROR_OK) return retval; @@ -437,6 +433,7 @@ static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) return JIM_OK; } + static int cti_create(struct jim_getopt_info *goi) { struct command_context *cmd_ctx; @@ -538,7 +535,6 @@ COMMAND_HANDLER(cti_handle_names) return ERROR_OK; } - static const struct command_registration cti_subcommand_handlers[] = { { .name = "create", diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h index cfcde65..1513f02 100644 --- a/src/target/arm_cti.h +++ b/src/target/arm_cti.h @@ -39,6 +39,7 @@ #define CTI_CHIN_STATUS 0x138 #define CTI_CHOU_STATUS 0x13C #define CTI_GATE 0x140 +#define CTI_DEVCTL 0x150 #define CTI_UNLOCK 0xFB0 #define CTI_CHNL(x) (1 << x) diff --git a/src/target/armv8.h b/src/target/armv8.h index f5aa211..156b5f8 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -213,6 +213,8 @@ struct armv8_common { /* True if OpenOCD provides pointer auth related info to GDB */ bool enable_pauth; + bool sticky_reset; + /* last run-control command issued to this target (resume, halt, step) */ enum run_control_op last_run_control_op; diff --git a/src/target/avrt.c b/src/target/avrt.c index 61bef32..8886a46 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -31,10 +31,10 @@ static int avr_assert_reset(struct target *target); static int avr_deassert_reset(struct target *target); /* IR and DR functions */ -static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti); -static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti); -static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti); -static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti); +static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len); +static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len); +static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len); +static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len); struct target_type avr_target = { .name = "avr", @@ -137,23 +137,23 @@ static int avr_deassert_reset(struct target *target) int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len) { - return mcu_write_dr_u32(tap, dr_in, dr_out, len, 1); + return mcu_write_dr_u32(tap, dr_in, dr_out, len); } int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) { - return mcu_write_ir_u8(tap, ir_in, ir_out, AVR_JTAG_INS_LEN, 1); + return mcu_write_ir_u8(tap, ir_in, ir_out, AVR_JTAG_INS_LEN); } /* IR and DR functions */ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, - int ir_len, int rti) + int ir_len) { if (!tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } - if (ir_len != tap->ir_length) { + if ((unsigned int)ir_len != tap->ir_length) { LOG_ERROR("invalid ir_len"); return ERROR_FAIL; } @@ -166,7 +166,7 @@ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, } static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, - int dr_len, int rti) + int dr_len) { if (!tap) { LOG_ERROR("invalid tap"); @@ -181,27 +181,27 @@ static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, } static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, - uint8_t ir_out, int ir_len, int rti) + uint8_t ir_out, int ir_len) { if (ir_len > 8) { LOG_ERROR("ir_len overflow, maximum is 8"); return ERROR_FAIL; } - mcu_write_ir(tap, ir_in, &ir_out, ir_len, rti); + mcu_write_ir(tap, ir_in, &ir_out, ir_len); return ERROR_OK; } static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in, - uint32_t dr_out, int dr_len, int rti) + uint32_t dr_out, int dr_len) { if (dr_len > 32) { LOG_ERROR("dr_len overflow, maximum is 32"); return ERROR_FAIL; } - mcu_write_dr(tap, (uint8_t *)dr_in, (uint8_t *)&dr_out, dr_len, rti); + mcu_write_dr(tap, (uint8_t *)dr_in, (uint8_t *)&dr_out, dr_len); return ERROR_OK; } diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 77f7673..0427ba3 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -39,7 +39,7 @@ static int bpwp_unique_id; static int breakpoint_add_internal(struct target *target, target_addr_t address, - uint32_t length, + unsigned int length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; @@ -102,7 +102,7 @@ fail: static int context_breakpoint_add_internal(struct target *target, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; @@ -152,7 +152,7 @@ static int context_breakpoint_add_internal(struct target *target, static int hybrid_breakpoint_add_internal(struct target *target, target_addr_t address, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; @@ -208,7 +208,7 @@ static int hybrid_breakpoint_add_internal(struct target *target, int breakpoint_add(struct target *target, target_addr_t address, - uint32_t length, + unsigned int length, enum breakpoint_type type) { if (target->smp && type == BKPT_HARD) { @@ -232,7 +232,7 @@ int breakpoint_add(struct target *target, int context_breakpoint_add(struct target *target, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { if (target->smp) { @@ -256,7 +256,7 @@ int context_breakpoint_add(struct target *target, int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { if (target->smp) { @@ -542,7 +542,7 @@ struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) } static int watchpoint_add_internal(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) + unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; @@ -598,7 +598,7 @@ bye: } LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT - " of length 0x%8.8" PRIx32 " (WPID: %d)", + " of length 0x%8.8x (WPID: %d)", watchpoint_rw_strings[(*watchpoint_p)->rw], (*watchpoint_p)->address, (*watchpoint_p)->length, @@ -608,7 +608,7 @@ bye: } int watchpoint_add(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) + unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { if (target->smp) { struct target_list *head; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 0ec65de..ac5d701 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -26,7 +26,7 @@ enum watchpoint_rw { struct breakpoint { target_addr_t address; uint32_t asid; - int length; + unsigned int length; enum breakpoint_type type; bool is_set; unsigned int number; @@ -40,7 +40,7 @@ struct breakpoint { struct watchpoint { target_addr_t address; - uint32_t length; + unsigned int length; uint64_t mask; uint64_t value; enum watchpoint_rw rw; @@ -52,11 +52,12 @@ struct watchpoint { int breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, - target_addr_t address, uint32_t length, enum breakpoint_type type); + target_addr_t address, unsigned int length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, - uint32_t asid, uint32_t length, enum breakpoint_type type); + uint32_t asid, unsigned int length, enum breakpoint_type type); int hybrid_breakpoint_add(struct target *target, - target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); + target_addr_t address, uint32_t asid, unsigned int length, + enum breakpoint_type type); int breakpoint_remove(struct target *target, target_addr_t address); int breakpoint_remove_all(struct target *target); @@ -70,7 +71,7 @@ static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int int watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, - target_addr_t address, uint32_t length, + target_addr_t address, unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask); int watchpoint_remove(struct target *target, target_addr_t address); int watchpoint_remove_all(struct target *target); diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 34c7cd4..3b95b64 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -100,6 +100,12 @@ static const struct cortex_m_part_info cortex_m_parts[] = { .flags = CORTEX_M_F_HAS_FPV5, }, { + .impl_part = CORTEX_M52_PARTNO, + .name = "Cortex-M52", + .arch = ARM_ARCH_V8M, + .flags = CORTEX_M_F_HAS_FPV5, + }, + { .impl_part = CORTEX_M55_PARTNO, .name = "Cortex-M55", .arch = ARM_ARCH_V8M, @@ -273,7 +279,8 @@ static int cortex_m_fast_read_all_regs(struct target *target) /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ - if (target->dbg_msg_enabled) { + bool dbg_msg_enabled = target->dbg_msg_enabled; + if (dbg_msg_enabled) { retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr); if (retval != ERROR_OK) return retval; @@ -326,7 +333,7 @@ static int cortex_m_fast_read_all_regs(struct target *target) if (retval != ERROR_OK) return retval; - if (target->dbg_msg_enabled) { + if (dbg_msg_enabled) { /* restore DCB_DCRDR - this needs to be in a separate * transaction otherwise the emulated DCC channel breaks */ retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr); @@ -797,6 +804,42 @@ static int cortex_m_examine_exception_reason(struct target *target) return retval; } +/* Errata 3092511 workaround + * Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ +static int cortex_m_erratum_check_breakpoint(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = &cortex_m->armv7m; + struct arm *arm = &armv7m->arm; + + uint32_t pc = buf_get_u32(arm->pc->value, 0, 32); + + /* To reduce the workaround processing cost we assume FPB is in sync + * with OpenOCD breakpoints. If the target app writes to FPB + * OpenOCD will resume after the break set by app */ + struct breakpoint *bkpt = breakpoint_find(target, pc); + if (bkpt) { + LOG_TARGET_DEBUG(target, "Erratum 3092511: breakpoint confirmed"); + return ERROR_OK; + } + if (pc >= 0xe0000000u) + /* not executable area, do not read instruction @ pc */ + return ERROR_OK; + + uint16_t insn; + int retval = target_read_u16(target, pc, &insn); + if (retval != ERROR_OK) + return ERROR_OK; /* do not propagate the error, just avoid workaround */ + + if ((insn & 0xff00) == (ARMV5_T_BKPT(0) & 0xff00)) { + LOG_TARGET_DEBUG(target, "Erratum 3092511: breakpoint embedded in code confirmed"); + return ERROR_OK; + } + LOG_TARGET_DEBUG(target, "Erratum 3092511: breakpoint not found, proceed with resume"); + return ERROR_TARGET_HALTED_DO_RESUME; +} + static int cortex_m_debug_entry(struct target *target) { uint32_t xpsr; @@ -883,6 +926,17 @@ static int cortex_m_debug_entry(struct target *target) secure_state ? "Secure" : "Non-Secure", target_state_name(target)); + /* Errata 3092511 workaround + * Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ + if (cortex_m->incorrect_halt_erratum + && armv7m->exception_number + && cortex_m->nvic_dfsr == (DFSR_BKPT | DFSR_HALTED)) { + retval = cortex_m_erratum_check_breakpoint(target); + if (retval != ERROR_OK) + return retval; + } + if (armv7m->post_debug_entry) { retval = armv7m->post_debug_entry(target); if (retval != ERROR_OK) @@ -960,6 +1014,28 @@ static int cortex_m_poll_one(struct target *target) if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) { retval = cortex_m_debug_entry(target); + /* Errata 3092511 workaround + * Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ + if (retval == ERROR_TARGET_HALTED_DO_RESUME) { + struct arm *arm = &armv7m->arm; + LOG_TARGET_INFO(target, "Resuming after incorrect halt @ PC 0x%08" PRIx32 + ", ARM Cortex-M7 erratum 3092511", + buf_get_u32(arm->pc->value, 0, 32)); + /* We don't need to restore registers, just restart the core */ + cortex_m_set_maskints_for_run(target); + retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT); + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_NOTHALTED; + /* registers are now invalid */ + register_cache_invalidate(armv7m->arm.core_cache); + + target->state = TARGET_RUNNING; + return ERROR_OK; + } + /* arm_semihosting needs to know registers, don't run if debug entry returned error */ if (retval == ERROR_OK && arm_semihosting(target, &retval) != 0) return retval; @@ -1582,7 +1658,7 @@ static int cortex_m_step(struct target *target, int current, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); retval = cortex_m_debug_entry(target); - if (retval != ERROR_OK) + if (retval != ERROR_OK && retval != ERROR_TARGET_HALTED_DO_RESUME) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); @@ -2537,8 +2613,8 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - /* Inspect implementor/part to look for recognized cores */ - unsigned int impl_part = cpuid & (ARM_CPUID_IMPLEMENTOR_MASK | ARM_CPUID_PARTNO_MASK); + /* Inspect implementer/part to look for recognized cores */ + unsigned int impl_part = cpuid & (ARM_CPUID_IMPLEMENTER_MASK | ARM_CPUID_PARTNO_MASK); for (unsigned int n = 0; n < ARRAY_SIZE(cortex_m_parts); n++) { if (impl_part == cortex_m_parts[n].impl_part) { @@ -2560,14 +2636,22 @@ int cortex_m_examine(struct target *target) (uint8_t)((cpuid >> 0) & 0xf)); cortex_m->maskints_erratum = false; + cortex_m->incorrect_halt_erratum = false; if (impl_part == CORTEX_M7_PARTNO) { uint8_t rev, patch; rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; if ((rev == 0) && (patch < 2)) { - LOG_TARGET_WARNING(target, "Silicon bug: single stepping may enter pending exception handler!"); + LOG_TARGET_WARNING(target, "Erratum 702596: single stepping may enter pending exception handler!"); cortex_m->maskints_erratum = true; } + /* TODO: add revision check when a Cortex-M7 revision with fixed 3092511 is out */ + LOG_TARGET_WARNING(target, "Erratum 3092511: Cortex-M7 can halt in an incorrect address when breakpoint and exception occurs simultaneously"); + cortex_m->incorrect_halt_erratum = true; + if (armv7m->is_hla_target) + LOG_WARNING("No erratum 3092511 workaround on hla adapter"); + else + LOG_INFO("The erratum 3092511 workaround will resume after an incorrect halt"); } LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index a585b78..144f245 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -31,35 +31,36 @@ #define CPUID 0xE000ED00 -#define ARM_CPUID_IMPLEMENTOR_POS 24 -#define ARM_CPUID_IMPLEMENTOR_MASK (0xFF << ARM_CPUID_IMPLEMENTOR_POS) +#define ARM_CPUID_IMPLEMENTER_POS 24 +#define ARM_CPUID_IMPLEMENTER_MASK (0xFF << ARM_CPUID_IMPLEMENTER_POS) #define ARM_CPUID_PARTNO_POS 4 #define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) -#define ARM_MAKE_CPUID(impl, partno) ((((impl) << ARM_CPUID_IMPLEMENTOR_POS) & ARM_CPUID_IMPLEMENTOR_MASK) | \ +#define ARM_MAKE_CPUID(impl, partno) ((((impl) << ARM_CPUID_IMPLEMENTER_POS) & ARM_CPUID_IMPLEMENTER_MASK) | \ (((partno) << ARM_CPUID_PARTNO_POS) & ARM_CPUID_PARTNO_MASK)) /** Known Arm Cortex masked CPU Ids - * This includes the implementor and part number, but _not_ the revision or + * This includes the implementer and part number, but _not_ the revision or * patch fields. */ enum cortex_m_impl_part { CORTEX_M_PARTNO_INVALID, - STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ - CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), - CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), - CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), - CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), - CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), - CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), - CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), - CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), - CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), - CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), - CORTEX_M85_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD23), - INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_INFINEON, 0xDB0), - REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), - REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), + STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM_CHINA, 0x132), + CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC20), + CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC21), + CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC23), + CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC24), + CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC27), + CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC60), + CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD20), + CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD21), + CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD31), + CORTEX_M52_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM_CHINA, 0xD24), + CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD22), + CORTEX_M85_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD23), + INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_INFINEON, 0xDB0), + REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_REALTEK, 0xd20), + REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_REALTEK, 0xd22), }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ @@ -149,6 +150,7 @@ struct cortex_m_part_info { #define VC_CORERESET BIT(0) /* DCB_DSCSR bit and field definitions */ +#define DSCSR_CDSKEY BIT(17) #define DSCSR_CDS BIT(16) /* NVIC registers */ @@ -256,6 +258,10 @@ struct cortex_m_common { /* Whether this target has the erratum that makes C_MASKINTS not apply to * already pending interrupts */ bool maskints_erratum; + + /* Errata 3092511 Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ + bool incorrect_halt_erratum; }; static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) diff --git a/src/target/esirisc.c b/src/target/esirisc.c index 0f76b59..14d34ff 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -483,7 +483,7 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea * The default linker scripts provided by the eSi-RISC toolchain do * not specify attributes on memory regions, which results in * incorrect application of software breakpoints by GDB. Targets - * must be configured with `gdb_breakpoint_override hard` as + * must be configured with `gdb breakpoint_override hard` as * software breakpoints are not supported. */ if (breakpoint->type != BKPT_HARD) diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c index 1ec1726..5960e26 100644 --- a/src/target/esirisc_jtag.c +++ b/src/target/esirisc_jtag.c @@ -58,11 +58,12 @@ static int esirisc_jtag_get_padding(void) return padding; } -static int esirisc_jtag_count_bits(int num_fields, struct scan_field *fields) +static int esirisc_jtag_count_bits(unsigned int num_fields, + struct scan_field *fields) { int bit_count = 0; - for (int i = 0; i < num_fields; ++i) + for (unsigned int i = 0; i < num_fields; ++i) bit_count += fields[i].num_bits; return bit_count; diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 22e1630..2afb4b0 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -421,4 +421,5 @@ struct target_type esp32s3_target = { .deinit_target = esp_xtensa_target_deinit, .commands = esp32s3_command_handlers, + .profiling = esp_xtensa_profiling, }; diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index 11895d2..9b57f34 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -179,3 +179,75 @@ int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *break return xtensa_breakpoint_remove(target, breakpoint); /* flash breakpoints will be handled in another patch */ } + +int esp_xtensa_profiling(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) +{ + struct timeval timeout, now; + struct xtensa *xtensa = target_to_xtensa(target); + int retval = ERROR_OK; + int res; + + /* Vary samples per pass to avoid sampling a periodic function periodically */ + #define MIN_PASS 200 + #define MAX_PASS 1000 + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, seconds, 0); + + uint8_t buf[sizeof(uint32_t) * MAX_PASS]; + + /* Capture one sample to verify the register is present and working */ + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DEBUGPC, buf); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_INFO(target, "Failed to read DEBUGPC, fallback to stop-and-go"); + return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); + } else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) { + LOG_TARGET_INFO(target, "NULL DEBUGPC, fallback to stop-and-go"); + return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); + } + + LOG_TARGET_INFO(target, "Starting XTENSA DEBUGPC profiling. Sampling as fast as we can..."); + + /* Make sure the target is running */ + target_poll(target); + if (target->state == TARGET_HALTED) + retval = target_resume(target, 1, 0, 0, 0); + + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Error while resuming target"); + return retval; + } + + uint32_t sample_count = 0; + + for (;;) { + uint32_t remaining = max_num_samples - sample_count; + uint32_t this_pass = rand() % (MAX_PASS - MIN_PASS) + MIN_PASS; + this_pass = this_pass > remaining ? remaining : this_pass; + for (uint32_t i = 0; i < this_pass; ++i) + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DEBUGPC, buf + i * sizeof(uint32_t)); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read DEBUGPC!"); + return res; + } + + for (uint32_t i = 0; i < this_pass; ++i) { + uint32_t sample32 = buf_get_u32(buf + i * sizeof(uint32_t), 0, 32); + samples[sample_count++] = sample32; + } + gettimeofday(&now, NULL); + if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { + LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); + break; + } + } + + *num_samples = sample_count; + return retval; + + #undef MIN_PASS + #undef MAX_PASS +} diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h index 00f67a3..56c903f 100644 --- a/src/target/espressif/esp_xtensa.h +++ b/src/target/espressif/esp_xtensa.h @@ -37,6 +37,9 @@ void esp_xtensa_queue_tdi_idle(struct target *target); int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_poll(struct target *target); +int esp_xtensa_profiling(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); + int esp_xtensa_on_halt(struct target *target); #endif /* OPENOCD_TARGET_ESP_XTENSA_H */ diff --git a/src/target/lakemont.c b/src/target/lakemont.c index 6c0964b..1fcd642 100644 --- a/src/target/lakemont.c +++ b/src/target/lakemont.c @@ -224,10 +224,10 @@ static int irscan(struct target *t, uint8_t *out, if (ir_len != t->tap->ir_length) { retval = ERROR_FAIL; if (t->tap->enabled) - LOG_ERROR("%s tap enabled but tap irlen=%d", + LOG_ERROR("%s tap enabled but tap irlen=%u", __func__, t->tap->ir_length); else - LOG_ERROR("%s tap not enabled and irlen=%d", + LOG_ERROR("%s tap not enabled and irlen=%u", __func__, t->tap->ir_length); return retval; } diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index bb1070a..349820a 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -6,6 +6,7 @@ #include "batch.h" #include "debug_defines.h" +#include "debug_reg_printer.h" #include "riscv.h" #include "field_helpers.h" @@ -131,15 +132,141 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_ } static int get_delay(const struct riscv_batch *batch, size_t scan_idx, - const struct riscv_scan_delays *delays) + const struct riscv_scan_delays *delays, bool resets_delays, + size_t reset_delays_after) { assert(batch); assert(scan_idx < batch->used_scans); + const bool delays_were_reset = resets_delays + && (scan_idx >= reset_delays_after); const enum riscv_scan_delay_class delay_class = batch->delay_classes[scan_idx]; const unsigned int delay = riscv_scan_get_delay(delays, delay_class); assert(delay <= INT_MAX); - return delay; + return delays_were_reset ? 0 : delay; +} + +static unsigned int decode_dmi(const struct riscv_batch *batch, char *text, + uint32_t address, uint32_t data) +{ + static const struct { + uint32_t address; + enum riscv_debug_reg_ordinal ordinal; + } description[] = { + {DM_DMCONTROL, DM_DMCONTROL_ORDINAL}, + {DM_DMSTATUS, DM_DMSTATUS_ORDINAL}, + {DM_ABSTRACTCS, DM_ABSTRACTCS_ORDINAL}, + {DM_COMMAND, DM_COMMAND_ORDINAL}, + {DM_SBCS, DM_SBCS_ORDINAL} + }; + + for (unsigned int i = 0; i < ARRAY_SIZE(description); i++) { + if (riscv_get_dmi_address(batch->target, description[i].address) + == address) { + const riscv_debug_reg_ctx_t context = { + .XLEN = { .value = 0, .is_set = false }, + .DXLEN = { .value = 0, .is_set = false }, + .abits = { .value = 0, .is_set = false }, + }; + return riscv_debug_reg_to_s(text, description[i].ordinal, + context, data, RISCV_DEBUG_REG_HIDE_ALL_0); + } + } + if (text) + text[0] = '\0'; + return 0; +} + +static void log_dmi_decoded(const struct riscv_batch *batch, bool write, + uint32_t address, uint32_t data) +{ + const size_t size = decode_dmi(batch, /* text */ NULL, address, data) + 1; + char * const decoded = malloc(size); + if (!decoded) { + LOG_ERROR("Not enough memory to allocate %zu bytes.", size); + return; + } + decode_dmi(batch, decoded, address, data); + LOG_DEBUG("%s: %s", write ? "write" : "read", decoded); + free(decoded); +} + +static void log_batch(const struct riscv_batch *batch, size_t start_idx, + const struct riscv_scan_delays *delays, bool resets_delays, + size_t reset_delays_after) +{ + if (debug_level < LOG_LVL_DEBUG) + return; + + const unsigned int scan_bits = batch->fields->num_bits; + assert(scan_bits == (unsigned int)riscv_get_dmi_scan_length(batch->target)); + const unsigned int abits = scan_bits - DTM_DMI_OP_LENGTH + - DTM_DMI_DATA_LENGTH; + + /* Determine the "op" and "address" of the scan that preceded the first + * executed scan. + * FIXME: The code here assumes that there were no DMI operations between + * the last execution of the batch and the current one. + * Caching the info about the last executed DMI scan in "dm013_info_t" + * would be a more robust solution. + */ + bool last_scan_was_read = false; + uint32_t last_scan_address = -1 /* to silence maybe-uninitialized */; + if (start_idx > 0) { + const struct scan_field * const field = &batch->fields[start_idx - 1]; + assert(field->out_value); + last_scan_was_read = buf_get_u32(field->out_value, DTM_DMI_OP_OFFSET, + DTM_DMI_OP_LENGTH) == DTM_DMI_OP_READ; + last_scan_address = buf_get_u32(field->out_value, + DTM_DMI_ADDRESS_OFFSET, abits); + } + + /* Decode and log every executed scan */ + for (size_t i = start_idx; i < batch->used_scans; ++i) { + static const char * const op_string[] = {"-", "r", "w", "?"}; + const int delay = get_delay(batch, i, delays, resets_delays, + reset_delays_after); + const struct scan_field * const field = &batch->fields[i]; + + assert(field->out_value); + const unsigned int out_op = buf_get_u32(field->out_value, + DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); + const uint32_t out_data = buf_get_u32(field->out_value, + DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); + const uint32_t out_address = buf_get_u32(field->out_value, + DTM_DMI_ADDRESS_OFFSET, abits); + if (field->in_value) { + static const char * const status_string[] = { + "+", "?", "F", "b" + }; + const unsigned int in_op = buf_get_u32(field->in_value, + DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); + const uint32_t in_data = buf_get_u32(field->in_value, + DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); + const uint32_t in_address = buf_get_u32(field->in_value, + DTM_DMI_ADDRESS_OFFSET, abits); + + LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 + " -> %s %08" PRIx32 " @%02" PRIx32 "; %di", + field->num_bits, op_string[out_op], out_data, out_address, + status_string[in_op], in_data, in_address, delay); + + if (last_scan_was_read && in_op == DTM_DMI_OP_SUCCESS) + log_dmi_decoded(batch, /*write*/ false, + last_scan_address, in_data); + } else { + LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> ?; %di", + field->num_bits, op_string[out_op], out_data, out_address, + delay); + } + + if (out_op == DTM_DMI_OP_WRITE) + log_dmi_decoded(batch, /*write*/ true, out_address, + out_data); + + last_scan_was_read = out_op == DTM_DMI_OP_READ; + last_scan_address = out_address; + } } int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, @@ -147,6 +274,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, size_t reset_delays_after) { assert(batch->used_scans); + assert(start_idx < batch->used_scans); assert(batch->last_scan == RISCV_SCAN_TYPE_NOP); assert(!batch->was_run || riscv_batch_was_scan_busy(batch, start_idx)); assert(start_idx == 0 || !riscv_batch_was_scan_busy(batch, start_idx - 1)); @@ -157,17 +285,16 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, LOG_TARGET_DEBUG(batch->target, "Running batch of scans [%zu, %zu)", start_idx, batch->used_scans); + unsigned int delay = 0 /* to silence maybe-uninitialized */; for (size_t i = start_idx; i < batch->used_scans; ++i) { if (bscan_tunnel_ir_width != 0) riscv_add_bscan_tunneled_scan(batch->target, batch->fields + i, batch->bscan_ctxt + i); else jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); - const bool delays_were_reset = resets_delays - && (i >= reset_delays_after); - const int delay = get_delay(batch, i, delays); - - if (!delays_were_reset) + delay = get_delay(batch, i, delays, resets_delays, + reset_delays_after); + if (delay > 0) jtag_add_runtest(delay, TAP_IDLE); } @@ -188,25 +315,20 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, } } - for (size_t i = start_idx; i < batch->used_scans; ++i) { - const int delay = get_delay(batch, i, delays); - riscv_log_dmi_scan(batch->target, delay, batch->fields + i, - /*discard_in*/ false); - } - + log_batch(batch, start_idx, delays, resets_delays, reset_delays_after); batch->was_run = true; - batch->last_scan_delay = get_delay(batch, batch->used_scans - 1, delays); + batch->last_scan_delay = delay; return ERROR_OK; } -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_write(batch->target, (char *)field->out_value, address, data); + riscv_fill_dmi_write(batch->target, (char *)field->out_value, address, data); if (read_back) { field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); riscv_fill_dm_nop(batch->target, (char *)field->in_value); @@ -218,7 +340,7 @@ void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint3 batch->used_scans++; } -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address, enum riscv_scan_delay_class delay_class) { assert(batch->used_scans < batch->allocated_scans); @@ -226,7 +348,7 @@ size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_read(batch->target, (char *)field->out_value, address); + riscv_fill_dmi_read(batch->target, (char *)field->out_value, address); riscv_fill_dm_nop(batch->target, (char *)field->in_value); batch->delay_classes[batch->used_scans] = delay_class; batch->last_scan = RISCV_SCAN_TYPE_READ; diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 1a39939..6fcfeb2 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -190,14 +190,32 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, size_t riscv_batch_finished_scans(const struct riscv_batch *batch); /* Adds a DM register write to this batch. */ -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class); +static inline void +riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, + bool read_back, enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_write(batch, + riscv_get_dmi_address(batch->target, address), data, + read_back, delay_type); +} + /* DM register reads must be handled in two parts: the first one schedules a read and * provides a key, the second one actually obtains the result of the read - * status (op) and the actual data. */ -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address, enum riscv_scan_delay_class delay_class); + +static inline size_t +riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, + enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_read(batch, + riscv_get_dmi_address(batch->target, address), delay_type); +} + unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key); uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key); @@ -210,10 +228,4 @@ size_t riscv_batch_available_scans(struct riscv_batch *batch); /* Return true iff the last scan in the batch returned DMI_OP_BUSY. */ bool riscv_batch_was_batch_busy(const struct riscv_batch *batch); -/* TODO: The function is defined in `riscv-013.c`. This is done to reduce the - * diff of the commit. The intention is to move the function definition to - * a separate module (e.g. `riscv013-jtag-dtm.c/h`) in another commit. */ -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, - bool discard_in); - #endif /* OPENOCD_TARGET_RISCV_BATCH_H */ diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index 99ae90f..1164bd6 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -194,26 +194,26 @@ static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLD; } -static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused)); -static uint32_t fmv_x_w(unsigned dest, unsigned src) +static uint32_t fmv_x_w(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_x_w(unsigned int dest, unsigned int src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_W; } -static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused)); -static uint32_t fmv_x_d(unsigned dest, unsigned src) +static uint32_t fmv_x_d(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_x_d(unsigned int dest, unsigned int src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_D; } -static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused)); -static uint32_t fmv_w_x(unsigned dest, unsigned src) +static uint32_t fmv_w_x(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_w_x(unsigned int dest, unsigned int src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_W_X; } -static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused)); -static uint32_t fmv_d_x(unsigned dest, unsigned src) +static uint32_t fmv_d_x(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_d_x(unsigned int dest, unsigned int src) { return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_D_X; } diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index c4ffb3f..6246d00 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -30,7 +30,7 @@ int riscv_program_init(struct riscv_program *p, struct target *target) int riscv_program_write(struct riscv_program *program) { - for (unsigned i = 0; i < program->instruction_count; ++i) { + for (unsigned int i = 0; i < program->instruction_count; ++i) { LOG_TARGET_DEBUG(program->target, "progbuf[%02x] = DASM(0x%08x)", i, program->progbuf[i]); if (riscv_write_progbuf(program->target, i, program->progbuf[i]) != ERROR_OK) @@ -183,8 +183,8 @@ int riscv_program_ebreak(struct riscv_program *p) { struct target *target = p->target; RISCV_INFO(r); - if (p->instruction_count == riscv_progbuf_size(p->target) && - r->impebreak) { + if (p->instruction_count == riscv_progbuf_size(target) && + r->get_impebreak(target)) { return ERROR_OK; } return riscv_program_insert(p, ebreak()); diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index cd30a52..0e635b3 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -273,38 +273,6 @@ static uint16_t dram_address(unsigned int index) return 0x40 + index - 0x10; } -static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) -{ - struct scan_field field; - uint8_t in_value[4]; - uint8_t out_value[4] = { 0 }; - - buf_set_u32(out_value, 0, 32, out); - - jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); - - field.num_bits = 32; - field.out_value = out_value; - field.in_value = in_value; - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); - - /* Always return to dbus. */ - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - - int retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("failed jtag scan: %d", retval); - return retval; - } - - uint32_t in = buf_get_u32(field.in_value, 0, 32); - LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); - - if (in_ptr) - *in_ptr = in; - return ERROR_OK; -} - static uint32_t idcode_scan(struct target *target) { struct scan_field field; @@ -408,7 +376,7 @@ static void dump_field(const struct scan_field *field) log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", - "%db %s %c%c:%08x @%02x -> %s %c%c:%08x @%02x", + "%ub %s %c%c:%08x @%02x -> %s %c%c:%08x @%02x", field->num_bits, op_string[out_op], out_interrupt, out_haltnot, out_data, out_address, @@ -475,7 +443,7 @@ static uint64_t dbus_read(struct target *target, uint16_t address) * While somewhat nonintuitive, this is an efficient way to get the data. */ - unsigned i = 0; + unsigned int i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); if (status == DBUS_STATUS_BUSY) @@ -496,7 +464,7 @@ static uint64_t dbus_read(struct target *target, uint16_t address) static void dbus_write(struct target *target, uint16_t address, uint64_t value) { dbus_status_t status = DBUS_STATUS_BUSY; - unsigned i = 0; + unsigned int i = 0; while (status == DBUS_STATUS_BUSY && i++ < 256) { status = dbus_scan(target, NULL, NULL, DBUS_OP_WRITE, address, value); if (status == DBUS_STATUS_BUSY) @@ -657,13 +625,13 @@ static void scans_add_read(scans_t *scans, slot_t slot, bool set_interrupt) } static uint32_t scans_get_u32(scans_t *scans, unsigned int index, - unsigned first, unsigned num) + unsigned int first, unsigned int num) { return buf_get_u32(scans->in + scans->scan_size * index, first, num); } static uint64_t scans_get_u64(scans_t *scans, unsigned int index, - unsigned first, unsigned num) + unsigned int first, unsigned int num) { return buf_get_u64(scans->in + scans->scan_size * index, first, num); } @@ -695,7 +663,7 @@ static int read_bits(struct target *target, bits_t *result) riscv011_info_t *info = get_info(target); do { - unsigned i = 0; + unsigned int i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, 0, 0); if (status == DBUS_STATUS_BUSY) { @@ -741,7 +709,7 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first) if (!bits.interrupt) return ERROR_OK; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out waiting for debug int to clear." "Increase timeout with riscv set_command_timeout_sec."); return ERROR_FAIL; @@ -1025,7 +993,7 @@ static int wait_for_state(struct target *target, enum target_state state) return result; if (target->state == state) return ERROR_OK; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out waiting for state %d. " "Increase timeout with riscv set_command_timeout_sec.", state); return ERROR_FAIL; @@ -1186,7 +1154,7 @@ static int full_step(struct target *target, bool announce) return result; if (target->state != TARGET_DEBUG_RUNNING) break; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out waiting for step to complete." "Increase timeout with riscv set_command_timeout_sec"); return ERROR_FAIL; @@ -1289,7 +1257,7 @@ static int register_write(struct target *target, unsigned int number, int result = update_mstatus_actual(target); if (result != ERROR_OK) return result; - unsigned i = 0; + unsigned int i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); cache_set_load(target, i++, S0, SLOT1); @@ -1350,7 +1318,7 @@ int riscv011_get_register(struct target *target, riscv_reg_t *value, int result = update_mstatus_actual(target); if (result != ERROR_OK) return result; - unsigned i = 0; + unsigned int i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); cache_set_load(target, i++, S0, SLOT1); @@ -1554,7 +1522,7 @@ static int examine(struct target *target) /* 0x00000000 0x00000000:00000003 0x00000000:00000003:ffffffff:ffffffff */ cache_set32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4)); cache_set_jump(target, 5); - for (unsigned i = 6; i < info->dramsize; i++) + for (unsigned int i = 6; i < info->dramsize; i++) cache_set32(target, i, i * 0x01020304); cache_write(target, 0, false); @@ -1585,7 +1553,7 @@ static int examine(struct target *target) LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target)); if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) { - const unsigned old_csr_misa = 0xf10; + const unsigned int old_csr_misa = 0xf10; LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA, old_csr_misa); if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) { @@ -1664,7 +1632,7 @@ static riscv_error_t handle_halt_routine(struct target *target) unsigned int dbus_busy = 0; unsigned int interrupt_set = 0; - unsigned result = 0; + unsigned int result = 0; uint64_t value = 0; reg_cache_set(target, 0, 0); /* The first scan result is the result from something old we don't care @@ -2036,7 +2004,7 @@ static int read_memory(struct target *target, target_addr_t address, cache_write(target, CACHE_NO_READ, false); riscv011_info_t *info = get_info(target); - const unsigned max_batch_size = 256; + const unsigned int max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); if (!scans) return ERROR_FAIL; @@ -2194,7 +2162,7 @@ static int write_memory(struct target *target, target_addr_t address, if (setup_write_memory(target, size) != ERROR_OK) return ERROR_FAIL; - const unsigned max_batch_size = 256; + const unsigned int max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); if (!scans) return ERROR_FAIL; @@ -2344,10 +2312,10 @@ static int wait_for_authbusy(struct target *target) uint32_t dminfo = dbus_read(target, DMINFO); if (!get_field(dminfo, DMINFO_AUTHBUSY)) break; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, + riscv_get_command_timeout_sec(), dminfo); return ERROR_FAIL; } @@ -2388,6 +2356,16 @@ static int riscv011_authdata_write(struct target *target, uint32_t value, unsign return ERROR_OK; } +static bool riscv011_get_impebreak(const struct target *target) +{ + return false; +} + +static unsigned int riscv011_get_progbufsize(const struct target *target) +{ + return 0; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -2397,6 +2375,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->authdata_read = &riscv011_authdata_read; generic_info->authdata_write = &riscv011_authdata_write; generic_info->print_info = &riscv011_print_info; + generic_info->get_impebreak = &riscv011_get_impebreak; + generic_info->get_progbufsize = &riscv011_get_progbufsize; generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); if (!generic_info->version_specific) diff --git a/src/target/riscv/riscv-011_reg.c b/src/target/riscv/riscv-011_reg.c index 7f29064..44ea1a4 100644 --- a/src/target/riscv/riscv-011_reg.c +++ b/src/target/riscv/riscv-011_reg.c @@ -38,7 +38,9 @@ static const struct reg_arch_type *riscv011_gdb_regno_reg_type(uint32_t regno) static int riscv011_init_reg(struct target *target, uint32_t regno) { - return riscv_reg_impl_init_one(target, regno, riscv011_gdb_regno_reg_type(regno)); + return riscv_reg_impl_init_cache_entry(target, regno, + riscv_reg_impl_gdb_regno_exist(target, regno), + riscv011_gdb_regno_reg_type(regno)); } int riscv011_reg_init_all(struct target *target) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 07b6da0..85125c9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -16,6 +16,7 @@ #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" +#include <helper/align.h> #include <helper/log.h> #include "jtag/jtag.h" #include "target/register.h" @@ -56,10 +57,7 @@ static int riscv013_invalidate_cached_progbuf(struct target *target); static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr); static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a); -static void riscv013_fill_dmi_nop(struct target *target, char *buf); static int riscv013_get_dmi_scan_length(struct target *target); -static void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -static void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a); static void riscv013_fill_dm_nop(struct target *target, char *buf); static unsigned int register_size(struct target *target, enum gdb_regno number); static int register_read_direct(struct target *target, riscv_reg_t *value, @@ -70,6 +68,8 @@ static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); +static bool riscv013_get_impebreak(const struct target *target); +static unsigned int riscv013_get_progbufsize(const struct target *target); typedef enum { HALT_GROUP, @@ -115,7 +115,7 @@ typedef enum { typedef struct { struct list_head list; - int abs_chain_position; + unsigned int abs_chain_position; /* The base address to access this DM on DMI */ uint32_t base; /* The number of harts connected to this DM. */ @@ -150,13 +150,15 @@ typedef struct { typedef struct { /* The indexed used to address this hart in its DM. */ - unsigned index; + unsigned int index; /* Number of address bits in the dbus register. */ - unsigned abits; + unsigned int abits; /* Number of abstract command data registers. */ - unsigned datacount; + unsigned int datacount; /* Number of words in the Program Buffer. */ - unsigned progbufsize; + unsigned int progbufsize; + /* Hart contains an implicit ebreak at the end of the program buffer. */ + bool impebreak; /* We cache the read-only bits of sbcs here. */ uint32_t sbcs; @@ -223,7 +225,7 @@ static dm013_info_t *get_dm(struct target *target) if (info->dm) return info->dm; - int abs_chain_position = target->tap->abs_chain_position; + unsigned int abs_chain_position = target->tap->abs_chain_position; dm013_info_t *entry; dm013_info_t *dm = NULL; @@ -347,82 +349,6 @@ static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index) return initial; } -static unsigned int decode_dmi(const struct target *target, char *text, uint32_t address, uint32_t data) -{ - static const struct { - uint32_t address; - enum riscv_debug_reg_ordinal ordinal; - } description[] = { - {DM_DMCONTROL, DM_DMCONTROL_ORDINAL}, - {DM_DMSTATUS, DM_DMSTATUS_ORDINAL}, - {DM_ABSTRACTCS, DM_ABSTRACTCS_ORDINAL}, - {DM_COMMAND, DM_COMMAND_ORDINAL}, - {DM_SBCS, DM_SBCS_ORDINAL} - }; - - for (unsigned i = 0; i < ARRAY_SIZE(description); i++) { - if (riscv_get_dmi_address(target, description[i].address) == address) { - const riscv_debug_reg_ctx_t context = { - .XLEN = { .value = 0, .is_set = false }, - .DXLEN = { .value = 0, .is_set = false }, - .abits = { .value = 0, .is_set = false }, - }; - return riscv_debug_reg_to_s(text, description[i].ordinal, - context, data, RISCV_DEBUG_REG_HIDE_ALL_0); - } - } - if (text) - text[0] = '\0'; - return 0; -} - -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, bool discard_in) -{ - static const char * const op_string[] = {"-", "r", "w", "?"}; - static const char * const status_string[] = {"+", "?", "F", "b"}; - - if (debug_level < LOG_LVL_DEBUG) - return; - - assert(field->out_value); - const uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); - const unsigned int out_op = get_field(out, DTM_DMI_OP); - const uint32_t out_data = get_field(out, DTM_DMI_DATA); - const uint32_t out_address = out >> DTM_DMI_ADDRESS_OFFSET; - - if (field->in_value) { - const uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); - const unsigned int in_op = get_field(in, DTM_DMI_OP); - const uint32_t in_data = get_field(in, DTM_DMI_DATA); - const uint32_t in_address = in >> DTM_DMI_ADDRESS_OFFSET; - - LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> %s %08" PRIx32 " @%02" PRIx32 "; %di", - field->num_bits, op_string[out_op], out_data, out_address, - status_string[in_op], in_data, in_address, idle); - - if (!discard_in && in_op == DTM_DMI_OP_SUCCESS) { - char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1]; - decode_dmi(target, in_decoded, in_address, in_data); - /* FIXME: The current code assumes that the hardware - * provides the read address in the dmi.address field - * when returning the dmi.data. That is however not - * required by the spec, and therefore not guaranteed. - * See https://github.com/riscv-collab/riscv-openocd/issues/1043 - */ - LOG_DEBUG("read: %s", in_decoded); - } - } else { - LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> ?; %di", - field->num_bits, op_string[out_op], out_data, out_address, - idle); - } - if (out_op == DTM_DMI_OP_WRITE) { - char out_decoded[decode_dmi(target, NULL, out_address, out_data) + 1]; - decode_dmi(target, out_decoded, out_address, out_data); - LOG_DEBUG("write: %s", out_decoded); - } -} - /*** Utility functions. ***/ static void select_dmi(struct target *target) @@ -431,42 +357,31 @@ static void select_dmi(struct target *target) select_dmi_via_bscan(target); return; } - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); -} - -static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) -{ - struct scan_field field; - uint8_t in_value[4]; - uint8_t out_value[4] = { 0 }; - - if (bscan_tunnel_ir_width != 0) - return dtmcontrol_scan_via_bscan(target, out, in_ptr); - - buf_set_u32(out_value, 0, 32, out); - - jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); - - field.num_bits = 32; - field.out_value = out_value; - field.in_value = in_value; - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); - - /* Always return to dmi. */ - select_dmi(target); - - int retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("failed jtag scan: %d", retval); - return retval; + if (!target->tap->enabled) + LOG_TARGET_ERROR(target, "BUG: Target's TAP '%s' is disabled!", + jtag_tap_name(target->tap)); + + bool need_ir_scan = false; + /* FIXME: make "tap" a const pointer. */ + for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); + tap; tap = jtag_tap_next_enabled(tap)) { + if (tap != target->tap) { + /* Different TAP than ours - check if it is in bypass */ + if (!tap->bypass) { + need_ir_scan = true; + break; + } + } else { + /* Our TAP - check if the correct instruction is already loaded */ + if (!buf_eq(target->tap->cur_instr, select_dbus.out_value, target->tap->ir_length)) { + need_ir_scan = true; + break; + } + } } - uint32_t in = buf_get_u32(field.in_value, 0, 32); - LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); - - if (in_ptr) - *in_ptr = in; - return ERROR_OK; + if (need_ir_scan) + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); } static int increase_dmi_busy_delay(struct target *target) @@ -506,220 +421,6 @@ static void decrement_reset_delays_counter(struct target *target, size_t finishe "resetting learned delays (reset_delays_wait counter expired)"); reset_learned_delays(target); } -/** - * exec: If this is set, assume the scan results in an execution, so more - * run-test/idle cycles may be required. - */ -static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, - uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out, - bool exec) -{ - riscv013_info_t *info = get_info(target); - unsigned num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH; - size_t num_bytes = (num_bits + 7) / 8; - uint8_t in[num_bytes]; - uint8_t out[num_bytes]; - struct scan_field field = { - .num_bits = num_bits, - .out_value = out, - .in_value = in - }; - riscv_bscan_tunneled_scan_context_t bscan_ctxt; - - decrement_reset_delays_counter(target, 1); - - memset(in, 0, num_bytes); - memset(out, 0, num_bytes); - - if (info->abits == 0) { - LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0."); - return DMI_STATUS_FAILED; - } - - buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); - buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); - buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); - - /* I wanted to place this code in a different function, but the way JTAG command - queueing works in the jtag handling functions, the scan fields either have to be - heap allocated, global/static, or else they need to stay on the stack until - the jtag_execute_queue() call. Heap or static fields in this case doesn't seem - the best fit. Declaring stack based field values in a subsidiary function call wouldn't - work. */ - if (bscan_tunnel_ir_width != 0) { - riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt); - } else { - /* Assume dbus is already selected. */ - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); - } - - int idle_count = exec - ? riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_ABSTRACT_COMMAND) - : riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_BASE); - - if (idle_count) - jtag_add_runtest(idle_count, TAP_IDLE); - - int retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("dmi_scan failed jtag scan"); - if (data_in) - *data_in = ~0; - return DMI_STATUS_FAILED; - } - - if (bscan_tunnel_ir_width != 0) { - /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ - buffer_shr(in, num_bytes, 1); - } - - if (data_in) - *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); - - if (address_in) - *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); - riscv_log_dmi_scan(target, idle_count, &field, /*discard_in*/ !data_in); - return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); -} - -/** - * @param target - * @param data_in The data we received from the target. - * @param dmi_busy_encountered - * If non-NULL, will be updated to reflect whether DMI busy was - * encountered while executing this operation or not. - * @param op The operation to perform (read/write/nop). - * @param address The address argument to that operation. - * @param data_out The data to send to the target. - * @param timeout_sec - * @param exec When true, this scan will execute something, so extra RTI - * cycles may be added. - * @param ensure_success - * Scan a nop after the requested operation, ensuring the - * DMI operation succeeded. - */ -static int dmi_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) -{ - select_dmi(target); - - dmi_status_t status; - - if (dmi_busy_encountered) - *dmi_busy_encountered = false; - - const char *op_name; - switch (op) { - case DMI_OP_NOP: - op_name = "nop"; - break; - case DMI_OP_READ: - op_name = "read"; - break; - case DMI_OP_WRITE: - op_name = "write"; - break; - default: - LOG_ERROR("Invalid DMI operation: %d", op); - return ERROR_FAIL; - } - - keep_alive(); - - time_t start = time(NULL); - /* This first loop performs the request. Note that if for some reason this - * stays busy, it is actually due to the previous access. */ - while (1) { - status = dmi_scan(target, NULL, NULL, op, address, data_out, - exec); - if (status == DMI_STATUS_BUSY) { - int result = increase_dmi_busy_delay(target); - if (result != ERROR_OK) - return result; - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - break; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - - if (status != DMI_STATUS_SUCCESS) { - LOG_TARGET_ERROR(target, "Failed DMI %s at 0x%x; status=%d", op_name, address, status); - return ERROR_FAIL; - } - - if (ensure_success) { - /* This second loop ensures the request succeeded, and gets back data. - * Note that NOP can result in a 'busy' result as well, but that would be - * noticed on the next DMI access we do. */ - while (1) { - status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0, - false); - if (status == DMI_STATUS_BUSY) { - int result = increase_dmi_busy_delay(target); - if (result != ERROR_OK) - return result; - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - if (data_in) { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; value=0x%x, status=%d", - op_name, address, *data_in, status); - } else { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; status=%d", op_name, address, - status); - } - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - return ERROR_FAIL; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - } - - return ERROR_OK; -} - -static int dmi_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) -{ - int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, op, - address, data_out, riscv_command_timeout_sec, exec, ensure_success); - if (result == ERROR_TIMEOUT_REACHED) { - LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. The target is " - "either really slow or broken. You could increase the " - "timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec); - return ERROR_FAIL; - } - return result; -} - -static int dmi_read(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true); -} - -static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true); -} - -static int dmi_write(struct target *target, uint32_t address, uint32_t value) -{ - return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true); -} static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t address) { @@ -731,34 +432,22 @@ static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t a return address + base; } -static int dm_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_op_timeout(target, data_in, dmi_busy_encountered, op, address + dm->base, - data_out, timeout_sec, exec, ensure_success); -} +static int batch_run_timeout(struct target *target, struct riscv_batch *batch); -static int dm_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_op(target, data_in, dmi_busy_encountered, op, address + dm->base, - data_out, exec, ensure_success); + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_read(batch, address, RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; } static int dm_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_read(target, value, address + dm->base); + return dmi_read(target, value, riscv013_get_dmi_address(target, address)); } static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address) @@ -766,16 +455,29 @@ static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dm_read(batch, address, RISCV_DELAY_ABSTRACT_COMMAND); dm->abstract_cmd_maybe_busy = true; - return dmi_read_exec(target, value, address + dm->base); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; +} + +static int dmi_write(struct target *target, uint32_t address, uint32_t value) +{ + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_write(batch, address, value, /*read_back*/ true, + RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int dm_write(struct target *target, uint32_t address, uint32_t value) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_write(target, address + dm->base, value); + return dmi_write(target, riscv013_get_dmi_address(target, address), value); } static bool check_dbgbase_exists(struct target *target) @@ -805,11 +507,10 @@ static bool check_dbgbase_exists(struct target *target) return false; } -static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, - bool authenticated, unsigned timeout_sec) +static int dmstatus_read(struct target *target, uint32_t *dmstatus, + bool authenticated) { - int result = dm_op_timeout(target, dmstatus, NULL, DMI_OP_READ, - DM_DMSTATUS, 0, timeout_sec, false, true); + int result = dm_read(target, dmstatus, DM_DMSTATUS); if (result != ERROR_OK) return result; int dmstatus_version = get_field(*dmstatus, DM_DMSTATUS_VERSION); @@ -827,19 +528,6 @@ static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus, return ERROR_OK; } -static int dmstatus_read(struct target *target, uint32_t *dmstatus, - bool authenticated) -{ - int result = dmstatus_read_timeout(target, dmstatus, authenticated, - riscv_command_timeout_sec); - if (result == ERROR_TIMEOUT_REACHED) - LOG_TARGET_ERROR(target, "DMSTATUS read didn't complete in %d seconds. The target is " - "either really slow or broken. You could increase the " - "timeout with `riscv set_command_timeout_sec`.", - riscv_command_timeout_sec); - return result; -} - static int increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); @@ -847,7 +535,7 @@ static int increase_ac_busy_delay(struct target *target) RISCV_DELAY_ABSTRACT_COMMAND); } -static uint32_t __attribute__((unused)) abstract_register_size(unsigned width) +static uint32_t __attribute__((unused)) abstract_register_size(unsigned int width) { switch (width) { case 32: @@ -890,12 +578,12 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) dm->abstract_cmd_maybe_busy = false; return ERROR_OK; } - } while ((time(NULL) - start) < riscv_command_timeout_sec); + } while ((time(NULL) - start) < riscv_get_command_timeout_sec()); LOG_TARGET_ERROR(target, "Timed out after %ds waiting for busy to go low (abstractcs=0x%" PRIx32 "). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, + riscv_get_command_timeout_sec(), *abstractcs); if (!dm->abstract_cmd_maybe_busy) @@ -955,9 +643,7 @@ clear_cmderr: return res; } -static int batch_run_timeout(struct target *target, struct riscv_batch *batch); - -static int execute_abstract_command(struct target *target, uint32_t command, +int riscv013_execute_abstract_command(struct target *target, uint32_t command, uint32_t *cmderr) { assert(cmderr); @@ -1073,10 +759,10 @@ static void abstract_data_write_fill_batch(struct riscv_batch *batch, } /* TODO: reuse "abstract_data_write_fill_batch()" here*/ -static int write_abstract_arg(struct target *target, unsigned index, - riscv_reg_t value, unsigned size_bits) +static int write_abstract_arg(struct target *target, unsigned int index, + riscv_reg_t value, unsigned int size_bits) { - unsigned offset = index * size_bits / 32; + unsigned int offset = index * size_bits / 32; switch (size_bits) { default: LOG_TARGET_ERROR(target, "Unsupported size: %d bits", size_bits); @@ -1093,8 +779,8 @@ static int write_abstract_arg(struct target *target, unsigned index, /** * @par size in bits */ -static uint32_t access_register_command(struct target *target, uint32_t number, - unsigned size, uint32_t flags) +uint32_t riscv013_access_register_command(struct target *target, uint32_t number, + unsigned int size, uint32_t flags) { uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0); switch (size) { @@ -1150,11 +836,11 @@ static int register_read_abstract_with_size(struct target *target, if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) return ERROR_FAIL; - uint32_t command = access_register_command(target, number, size, + uint32_t command = riscv013_access_register_command(target, number, size, AC_ACCESS_REGISTER_TRANSFER); uint32_t cmderr; - int result = execute_abstract_command(target, command, &cmderr); + int result = riscv013_execute_abstract_command(target, command, &cmderr); if (result != ERROR_OK) { if (cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { @@ -1199,7 +885,7 @@ static int register_write_abstract(struct target *target, enum gdb_regno number, return ERROR_FAIL; const unsigned int size_bits = register_size(target, number); - const uint32_t command = access_register_command(target, number, size_bits, + const uint32_t command = riscv013_access_register_command(target, number, size_bits, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command); @@ -1242,7 +928,7 @@ cleanup: * Sets the AAMSIZE field of a memory access abstract command based on * the width (bits). */ -static uint32_t abstract_memory_size(unsigned width) +static uint32_t abstract_memory_size(unsigned int width) { switch (width) { case 8: @@ -1424,7 +1110,7 @@ typedef struct { static int scratch_reserve(struct target *target, scratch_mem_t *scratch, struct riscv_program *program, - unsigned size_bytes) + unsigned int size_bytes) { riscv_addr_t alignment = 1; while (alignment < size_bytes) @@ -1456,7 +1142,7 @@ static int scratch_reserve(struct target *target, return ERROR_FAIL; /* Allow for ebreak at the end of the program. */ - unsigned program_size = (program->instruction_count + 1) * 4; + unsigned int program_size = (program->instruction_count + 1) * 4; scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & ~(alignment - 1); if ((info->progbuf_writable == YNM_YES) && @@ -1572,12 +1258,10 @@ static unsigned int register_size(struct target *target, enum gdb_regno number) return riscv_xlen(target); } -static bool has_sufficient_progbuf(struct target *target, unsigned size) +static bool has_sufficient_progbuf(struct target *target, unsigned int size) { RISCV013_INFO(info); - RISCV_INFO(r); - - return info->progbufsize + r->impebreak >= size; + return info->progbufsize + info->impebreak >= size; } /** @@ -1898,10 +1582,10 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) *dmstatus = value; if (!get_field(value, DM_DMSTATUS_AUTHBUSY)) break; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, + riscv_get_command_timeout_sec(), value); return ERROR_FAIL; } @@ -2091,11 +1775,10 @@ static int reset_dm(struct target *target) if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_reset_timeout_sec) { - /* TODO: Introduce a separate timeout for this. */ + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "DM didn't acknowledge reset in %d s. " - "Increase the timeout with 'riscv set_reset_timeout_sec'.", - riscv_reset_timeout_sec); + "Increase the timeout with 'riscv set_command_timeout_sec'.", + riscv_get_command_timeout_sec()); return ERROR_TIMEOUT_REACHED; } } while (get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE)); @@ -2114,11 +1797,10 @@ static int reset_dm(struct target *target) if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_reset_timeout_sec) { - /* TODO: Introduce a separate timeout for this. */ + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Debug Module did not become active in %d s. " - "Increase the timeout with 'riscv set_reset_timeout_sec'.", - riscv_reset_timeout_sec); + "Increase the timeout with 'riscv set_command_timeout_sec'.", + riscv_get_command_timeout_sec()); return ERROR_TIMEOUT_REACHED; } } while (!get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE)); @@ -2304,14 +1986,13 @@ static int examine(struct target *target) LOG_TARGET_INFO(target, "datacount=%d progbufsize=%d", info->datacount, info->progbufsize); - RISCV_INFO(r); - r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); + info->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); if (!has_sufficient_progbuf(target, 2)) { LOG_TARGET_WARNING(target, "We won't be able to execute fence instructions on this " "target. Memory may not always appear consistent. " "(progbufsize=%d, impebreak=%d)", info->progbufsize, - r->impebreak); + info->impebreak); } if (info->progbufsize < 4 && riscv_enable_virtual) { @@ -2327,6 +2008,8 @@ static int examine(struct target *target) enum riscv_hart_state state_at_examine_start; if (riscv_get_hart_state(target, &state_at_examine_start) != ERROR_OK) return ERROR_FAIL; + + RISCV_INFO(r); const bool hart_halted_at_examine_start = state_at_examine_start == RISCV_STATE_HALTED; if (!hart_halted_at_examine_start) { r->prepped = true; @@ -2340,74 +2023,9 @@ static int examine(struct target *target) target->state = TARGET_HALTED; target->debug_reason = hart_halted_at_examine_start ? DBG_REASON_UNDEFINED : DBG_REASON_DBGRQ; - /* Without knowing anything else we can at least mess with the - * program buffer. */ - r->progbuf_size = info->progbufsize; - - result = register_read_abstract_with_size(target, NULL, GDB_REGNO_S0, 64); - if (result == ERROR_OK) - r->xlen = 64; - else - r->xlen = 32; - - /* Save s0 and s1. The register cache hasn't be initialized yet so we - * need to take care of this manually. */ - uint64_t s0, s1; - if (register_read_abstract(target, &s0, GDB_REGNO_S0) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read s0."); - return ERROR_FAIL; - } - if (register_read_abstract(target, &s1, GDB_REGNO_S1) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read s1."); - return ERROR_FAIL; - } - - if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read MISA."); - return ERROR_FAIL; - } - - uint64_t value; - if (register_read_direct(target, &value, GDB_REGNO_VLENB) != ERROR_OK) { - if (riscv_supports_extension(target, 'V')) - LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work."); - r->vlenb = 0; - } else { - r->vlenb = value; - LOG_TARGET_INFO(target, "Vector support with vlenb=%d", r->vlenb); - } - - if (register_read_direct(target, &value, GDB_REGNO_MTOPI) == ERROR_OK) { - r->mtopi_readable = true; - - if (register_read_direct(target, &value, GDB_REGNO_MTOPEI) == ERROR_OK) { - LOG_TARGET_INFO(target, "S?aia detected with IMSIC"); - r->mtopei_readable = true; - } else { - r->mtopei_readable = false; - LOG_TARGET_INFO(target, "S?aia detected without IMSIC"); - } - } else { - r->mtopi_readable = false; - } - - /* Display this as early as possible to help people who are using - * really slow simulators. */ - LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); - - /* Restore s0 and s1. */ - if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to write back s0."); - return ERROR_FAIL; - } - if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to write back s1."); - return ERROR_FAIL; - } - - /* Now init registers based on what we discovered. */ - if (riscv013_reg_init_all(target) != ERROR_OK) - return ERROR_FAIL; + result = riscv013_reg_examine_all(target); + if (result != ERROR_OK) + return result; if (set_dcsr_ebreak(target, false) != ERROR_OK) return ERROR_FAIL; @@ -2488,13 +2106,13 @@ static int riscv013_authdata_write(struct target *target, uint32_t value, unsign } /* Try to find out the widest memory access size depending on the selected memory access methods. */ -static unsigned riscv013_data_bits(struct target *target) +static unsigned int riscv013_data_bits(struct target *target) { RISCV013_INFO(info); RISCV_INFO(r); - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { - int method = r->mem_access_methods[i]; + for (unsigned int i = 0; i < r->num_enabled_mem_access_methods; i++) { + riscv_mem_access_method_t method = r->mem_access_methods[i]; if (method == RISCV_MEM_ACCESS_PROGBUF) { if (has_sufficient_progbuf(target, 3)) @@ -2515,9 +2133,9 @@ static unsigned riscv013_data_bits(struct target *target) * take those into account as well. For now we assume abstract commands * support XLEN-wide accesses. */ return riscv_xlen(target); - } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) - /* No further mem access method to try. */ - break; + } else { + assert(false); + } } LOG_TARGET_ERROR(target, "Unable to determine supported data bits on this target. Assuming 32 bits."); return 32; @@ -2743,21 +2361,42 @@ static uint32_t sb_sbaccess(unsigned int size_bytes) return 0; } -static int sb_write_address(struct target *target, target_addr_t address, - bool ensure_success) +static unsigned int get_sbaadress_reg_count(const struct target *target) { RISCV013_INFO(info); - unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + const unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + return DIV_ROUND_UP(sbasize, 32); +} + +static void batch_fill_sb_write_address(const struct target *target, + struct riscv_batch *batch, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) +{ /* There currently is no support for >64-bit addresses in OpenOCD. */ - if (sbasize > 96) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); - if (sbasize > 64) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); - if (sbasize > 32) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, - (uint32_t)(address >> 32), false, false); - return dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, - (uint32_t)address, false, ensure_success); + assert(sizeof(target_addr_t) == sizeof(uint64_t)); + const uint32_t addresses[] = {DM_SBADDRESS0, DM_SBADDRESS1, DM_SBADDRESS2, DM_SBADDRESS3}; + const uint32_t values[] = {(uint32_t)address, (uint32_t)(address >> 32), 0, 0}; + const unsigned int reg_count = get_sbaadress_reg_count(target); + assert(reg_count > 0); + assert(reg_count <= ARRAY_SIZE(addresses)); + assert(ARRAY_SIZE(addresses) == ARRAY_SIZE(values)); + + for (unsigned int i = reg_count - 1; i > 0; --i) + riscv_batch_add_dm_write(batch, addresses[i], values[i], /* read back */ true, + RISCV_DELAY_BASE); + riscv_batch_add_dm_write(batch, addresses[0], values[0], /* read back */ true, + sbaddr0_delay); +} + +static int sb_write_address(struct target *target, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) +{ + struct riscv_batch *batch = riscv_batch_alloc(target, + get_sbaadress_reg_count(target)); + batch_fill_sb_write_address(target, batch, address, sbaddr0_delay); + const int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int batch_run(struct target *target, struct riscv_batch *batch) @@ -2769,12 +2408,16 @@ static int batch_run(struct target *target, struct riscv_batch *batch) const int result = riscv_batch_run_from(batch, 0, &info->learned_delays, /*resets_delays*/ r->reset_delays_wait >= 0, r->reset_delays_wait); + if (result != ERROR_OK) + return result; /* TODO: To use `riscv_batch_finished_scans()` here, it is needed for * all scans to not discard input, meaning * "riscv_batch_add_dm_write(..., false)" should not be used. */ const size_t finished_scans = batch->used_scans; decrement_reset_delays_counter(target, finished_scans); - return result; + if (riscv_batch_was_batch_busy(batch)) + return increase_dmi_busy_delay(target); + return ERROR_OK; } /* It is expected that during creation of the batch @@ -2797,12 +2440,12 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) &info->learned_delays, /*resets_delays*/ r->reset_delays_wait >= 0, r->reset_delays_wait); + if (result != ERROR_OK) + return result; const size_t new_finished_scans = riscv_batch_finished_scans(batch); assert(new_finished_scans >= finished_scans); decrement_reset_delays_counter(target, new_finished_scans - finished_scans); finished_scans = new_finished_scans; - if (result != ERROR_OK) - return result; if (!riscv_batch_was_batch_busy(batch)) { assert(finished_scans == batch->used_scans); return ERROR_OK; @@ -2810,7 +2453,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) result = increase_dmi_busy_delay(target); if (result != ERROR_OK) return result; - } while (time(NULL) - start < riscv_command_timeout_sec); + } while (time(NULL) - start < riscv_get_command_timeout_sec()); assert(result == ERROR_OK); assert(riscv_batch_was_batch_busy(batch)); @@ -2825,7 +2468,7 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. " "The target is either really slow or broken. You could increase " "the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec); + riscv_get_command_timeout_sec()); return ERROR_TIMEOUT_REACHED; } @@ -3108,8 +2751,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->write_progbuf = &riscv013_write_progbuf; generic_info->execute_progbuf = &riscv013_execute_progbuf; generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf; - generic_info->fill_dm_write = &riscv013_fill_dm_write; - generic_info->fill_dm_read = &riscv013_fill_dm_read; + generic_info->fill_dmi_write = &riscv013_fill_dmi_write; + generic_info->fill_dmi_read = &riscv013_fill_dmi_read; generic_info->fill_dm_nop = &riscv013_fill_dm_nop; generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length; generic_info->authdata_read = &riscv013_authdata_read; @@ -3120,6 +2763,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->read_memory = read_memory; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; + generic_info->get_impebreak = &riscv013_get_impebreak; + generic_info->get_progbufsize = &riscv013_get_progbufsize; generic_info->handle_became_unavailable = &handle_became_unavailable; generic_info->tick = &tick; @@ -3225,21 +2870,15 @@ static int deassert_reset(struct target *target) time_t start = time(NULL); LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset."); do { - result = dmstatus_read_timeout(target, &dmstatus, true, - riscv_reset_timeout_sec); - if (result == ERROR_TIMEOUT_REACHED) - LOG_TARGET_ERROR(target, "Hart didn't complete a DMI read coming " - "out of reset in %ds; Increase the timeout with riscv " - "set_reset_timeout_sec.", - riscv_reset_timeout_sec); + result = dmstatus_read(target, &dmstatus, true); if (result != ERROR_OK) return result; - if (time(NULL) - start > riscv_reset_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Hart didn't leave reset in %ds; " "dmstatus=0x%x (allunavail=%s, allhavereset=%s); " - "Increase the timeout with riscv set_reset_timeout_sec.", - riscv_reset_timeout_sec, dmstatus, + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_get_command_timeout_sec(), dmstatus, get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) ? "true" : "false", get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET) ? "true" : "false"); return ERROR_TIMEOUT_REACHED; @@ -3404,7 +3043,7 @@ static int read_memory_bus_word(struct target *target, target_addr_t address, static target_addr_t sb_read_address(struct target *target) { RISCV013_INFO(info); - unsigned sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); target_addr_t address = 0; uint32_t v; if (sbasize > 32) { @@ -3425,10 +3064,10 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) return ERROR_FAIL; if (!get_field(*sbcs, DM_SBCS_SBBUSY)) return ERROR_OK; - if (time(NULL) - start > riscv_command_timeout_sec) { + if (time(NULL) - start > riscv_get_command_timeout_sec()) { LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). " "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, *sbcs); + riscv_get_command_timeout_sec(), *sbcs); return ERROR_FAIL; } } @@ -3562,6 +3201,9 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_NOT_IMPLEMENTED; } + assert(size <= 16); + assert(IS_PWR_OF_2(size)); + dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; @@ -3570,6 +3212,9 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, target_addr_t next_address = address; target_addr_t end_address = address + (increment ? count : 1) * size; + /* TODO: Reading all the elements in a single batch will boost the + * performance. + */ while (next_address < end_address) { uint32_t sbcs_write = set_field(0, DM_SBCS_SBREADONADDR, 1); sbcs_write |= sb_sbaccess(size); @@ -3581,96 +3226,50 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; /* This address write will trigger the first read. */ - if (sb_write_address(target, next_address, true) != ERROR_OK) + if (sb_write_address(target, next_address, RISCV_DELAY_SYSBUS_READ) != ERROR_OK) return ERROR_FAIL; - unsigned int bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays, - RISCV_DELAY_SYSBUS_READ); - if (bus_master_read_delay) { - LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", - bus_master_read_delay); - jtag_add_runtest(bus_master_read_delay, TAP_IDLE); - if (jtag_execute_queue() != ERROR_OK) { - LOG_TARGET_ERROR(target, "Failed to scan idle sequence"); - return ERROR_FAIL; - } - } - /* First read has been started. Optimistically assume that it has * completed. */ static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3}; + /* TODO: The only purpose of "sbvalue" is to be passed to + * "log_memory_access()". If "log_memory_access()" were to + * accept "uint8_t *" instead of "uint32_t *", "sbvalue" would + * be unnecessary. + */ uint32_t sbvalue[4] = {0}; - assert(size <= 16); - target_addr_t next_read = address - 1; - uint32_t buffer_offset = 0; - int next_read_j = 0; for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { - for (int j = (size - 1) / 4; j >= 0; j--) { - unsigned attempt = 0; - while (1) { - if (attempt++ > 100) { - LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory" - " just past " TARGET_ADDR_FMT, next_read); - return ERROR_FAIL; - } - keep_alive(); - dmi_status_t status = dmi_scan(target, NULL, &sbvalue[next_read_j], - DMI_OP_READ, sbdata[j] + dm->base, 0, false); - /* By reading from sbdata0, we have just initiated another system bus read. - * If necessary add a delay so the read can finish. */ - bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays, - RISCV_DELAY_SYSBUS_READ); - if (j == 0 && bus_master_read_delay) { - LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", - bus_master_read_delay); - jtag_add_runtest(bus_master_read_delay, TAP_IDLE); - if (jtag_execute_queue() != ERROR_OK) { - LOG_TARGET_ERROR(target, "Failed to scan idle sequence"); - return ERROR_FAIL; - } - } + const uint32_t size_in_words = DIV_ROUND_UP(size, 4); + struct riscv_batch *batch = riscv_batch_alloc(target, size_in_words); + /* Read of sbdata0 must be performed as last because it + * starts the new bus data transfer + * (in case "sbcs.sbreadondata" was set above). + * We don't want to start the next bus read before we + * fetch all the data from the last bus read. */ + for (uint32_t j = size_in_words - 1; j > 0; --j) + riscv_batch_add_dm_read(batch, sbdata[j], RISCV_DELAY_BASE); + riscv_batch_add_dm_read(batch, sbdata[0], RISCV_DELAY_SYSBUS_READ); + + int res = batch_run_timeout(target, batch); + if (res != ERROR_OK) { + riscv_batch_free(batch); + return res; + } - if (status == DMI_STATUS_BUSY) - increase_dmi_busy_delay(target); - else if (status == DMI_STATUS_SUCCESS) - break; - else - return ERROR_FAIL; - } - if (next_read != address - 1) { - buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[next_read_j]); - if (next_read_j == 0) { - log_memory_access(next_read, sbvalue, size, true); - memset(sbvalue, 0, size); - } - } - next_read_j = j; - next_read = address + i * increment + next_read_j * 4; - buffer_offset = i * size + next_read_j * 4; + const size_t last_key = batch->read_keys_used - 1; + for (size_t k = 0; k <= last_key; ++k) { + sbvalue[k] = riscv_batch_get_dmi_read_data(batch, last_key - k); + buf_set_u32(buffer + i * size + k * 4, 0, MIN(32, 8 * size), sbvalue[k]); } + + riscv_batch_free(batch); + const target_addr_t read_addr = address + i * increment; + log_memory_access(read_addr, sbvalue, size, true); } uint32_t sbcs_read = 0; if (count > 1) { - unsigned attempt = 0; - while (1) { - if (attempt++ > 100) { - LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory" - " just past " TARGET_ADDR_FMT, next_read); - return ERROR_FAIL; - } - dmi_status_t status = dmi_scan(target, NULL, &sbvalue[0], DMI_OP_NOP, 0, 0, false); - if (status == DMI_STATUS_BUSY) - increase_dmi_busy_delay(target); - else if (status == DMI_STATUS_SUCCESS) - break; - else - return ERROR_FAIL; - } - buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[0]); - log_memory_access(next_read, sbvalue, size, true); - /* "Writes to sbcs while sbbusy is high result in undefined behavior. * A debugger must not write to sbcs until it reads sbbusy as 0." */ if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK) @@ -3718,7 +3317,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, continue; } - unsigned error = get_field(sbcs_read, DM_SBCS_SBERROR); + unsigned int error = get_field(sbcs_read, DM_SBCS_SBERROR); if (error == DM_SBCS_SBERROR_NONE) { next_address = end_address; } else { @@ -3733,7 +3332,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_OK; } -static void log_mem_access_result(struct target *target, bool success, int method, bool is_read) +static void log_mem_access_result(struct target *target, bool success, riscv_mem_access_method_t method, bool is_read) { RISCV_INFO(r); bool warn = false; @@ -3748,18 +3347,8 @@ static void log_mem_access_result(struct target *target, bool success, int metho /* Determine the log message severity. Show warnings only once. */ if (!success) { - if (method == RISCV_MEM_ACCESS_PROGBUF) { - warn = r->mem_access_progbuf_warn; - r->mem_access_progbuf_warn = false; - } - if (method == RISCV_MEM_ACCESS_SYSBUS) { - warn = r->mem_access_sysbus_warn; - r->mem_access_sysbus_warn = false; - } - if (method == RISCV_MEM_ACCESS_ABSTRACT) { - warn = r->mem_access_abstract_warn; - r->mem_access_abstract_warn = false; - } + warn = r->mem_access_warn[method]; + r->mem_access_warn[method] = false; } if (warn) @@ -3768,101 +3357,180 @@ static void log_mem_access_result(struct target *target, bool success, int metho LOG_TARGET_DEBUG(target, "%s", msg); } -static bool mem_should_skip_progbuf(struct target *target, target_addr_t address, - uint32_t size, bool is_read, char **skip_reason) +typedef enum { + MEM_ACCESS_RESULT_TYPE_OK, + MEM_ACCESS_RESULT_TYPE_DISABLED, + MEM_ACCESS_RESULT_TYPE_SKIPPED, + MEM_ACCESS_RESULT_TYPE_FAILED +} mem_access_result_type_t; + +#define LIST_OF_MEM_ACCESS_RESULTS \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_OK, \ + MEM_ACCESS_RESULT_TYPE_OK, "ok") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_DISABLED, \ + MEM_ACCESS_RESULT_TYPE_DISABLED, "disabled") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (abstract access cmderr)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_PROGBUF_NOT_PRESENT, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (progbuf not present)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_PROGBUF_INSUFFICIENT, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (insufficient progbuf)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (unsupported access size)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_XLEN_TOO_SHORT, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (xlen too short)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_TARGET_NOT_HALTED, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (target not halted)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (address too large)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_UNSUPPORTED_INCREMENT_SIZE, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (increment size not supported)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_TARGET_SELECT_FAILED, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (dm target select failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED, \ + MEM_ACCESS_RESULT_TYPE_SKIPPED, "skipped (fence execution failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED, \ + MEM_ACCESS_RESULT_TYPE_FAILED, "failed") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_DM_ACCESS_FAILED, \ + MEM_ACCESS_RESULT_TYPE_FAILED, "failed (DM register access failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_PRIV_MOD_FAILED, \ + MEM_ACCESS_RESULT_TYPE_FAILED, "failed (privilege modification failed)") \ + + +#define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) name, +typedef enum { + LIST_OF_MEM_ACCESS_RESULTS +} mem_access_result_t; +#undef MEM_ACCESS_RESULT_HANDLER + +bool is_mem_access_failed(mem_access_result_t status) +{ + #define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) \ + case name: return kind == MEM_ACCESS_RESULT_TYPE_FAILED; + switch (status) { + LIST_OF_MEM_ACCESS_RESULTS + } + #undef MEM_ACCESS_RESULT_HANDLER + LOG_ERROR("Unknown memory access status: %d", status); + assert(false); + return false; +} + +bool is_mem_access_skipped(mem_access_result_t status) { - assert(skip_reason); + #define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) \ + case name: return kind == MEM_ACCESS_RESULT_TYPE_SKIPPED; + switch (status) { + LIST_OF_MEM_ACCESS_RESULTS + } + #undef MEM_ACCESS_RESULT_HANDLER + LOG_ERROR("Unknown memory access status: %d", status); + assert(false); + return false; +} + +const char *mem_access_result_to_str(mem_access_result_t status) +{ + #define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) \ + [name] = msg, + static const char * const table[] = { + LIST_OF_MEM_ACCESS_RESULTS + }; + #undef MEM_ACCESS_RESULT_HANDLER + assert(status < ARRAY_SIZE(table)); + return table[status]; +} + +static mem_access_result_t mem_should_skip_progbuf(struct target *target, + target_addr_t address, uint32_t size, bool is_read) +{ + if (!has_sufficient_progbuf(target, 1)) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf " + "- progbuf not present", is_read ? "read" : "write"); + return MEM_ACCESS_SKIPPED_PROGBUF_NOT_PRESENT; + } if (!has_sufficient_progbuf(target, 3)) { LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - insufficient progbuf size.", is_read ? "read" : "write"); - *skip_reason = "skipped (insufficient progbuf)"; - return true; + return MEM_ACCESS_SKIPPED_PROGBUF_INSUFFICIENT; } if (target->state != TARGET_HALTED) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - target not halted.", - is_read ? "read" : "write"); - *skip_reason = "skipped (target not halted)"; - return true; + LOG_TARGET_DEBUG(target, + "Skipping mem %s via progbuf - target not halted.", + is_read ? "read" : "write"); + return MEM_ACCESS_SKIPPED_TARGET_NOT_HALTED; } if (riscv_xlen(target) < size * 8) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - XLEN (%d) is too short for %d-bit memory access.", - is_read ? "read" : "write", riscv_xlen(target), size * 8); - *skip_reason = "skipped (XLEN too short)"; - return true; + LOG_TARGET_DEBUG(target, + "Skipping mem %s via progbuf - " + "XLEN (%d) is too short for %d-bit memory access.", + is_read ? "read" : "write", riscv_xlen(target), size * 8); + return MEM_ACCESS_SKIPPED_XLEN_TOO_SHORT; } if (size > 8) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - unsupported size.", - is_read ? "read" : "write"); - *skip_reason = "skipped (unsupported size)"; - return true; + LOG_TARGET_DEBUG(target, + "Skipping mem %s via progbuf - unsupported size.", + is_read ? "read" : "write"); + return MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE; } if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - progbuf only supports %u-bit address.", - is_read ? "read" : "write", riscv_xlen(target)); - *skip_reason = "skipped (too large address)"; - return true; + LOG_TARGET_DEBUG(target, + "Skipping mem %s via progbuf - progbuf only supports %u-bit address.", + is_read ? "read" : "write", riscv_xlen(target)); + return MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS; } - return false; + return MEM_ACCESS_OK; } -static bool mem_should_skip_sysbus(struct target *target, target_addr_t address, - uint32_t size, uint32_t increment, bool is_read, char **skip_reason) +static mem_access_result_t +mem_should_skip_sysbus(struct target *target, target_addr_t address, + uint32_t size, uint32_t increment, bool is_read) { - assert(skip_reason); - RISCV013_INFO(info); if (!sba_supports_access(target, size)) { LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - unsupported size.", is_read ? "read" : "write"); - *skip_reason = "skipped (unsupported size)"; - return true; + return MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE; } unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); if ((sizeof(address) * 8 > sbasize) && (address >> sbasize)) { LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - sba only supports %u-bit address.", is_read ? "read" : "write", sbasize); - *skip_reason = "skipped (too large address)"; - return true; + return MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS; } if (is_read && increment != size && (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0 || increment != 0)) { LOG_TARGET_DEBUG(target, "Skipping mem read via system bus - " "sba reads only support size==increment or also size==0 for sba v1."); - *skip_reason = "skipped (unsupported increment)"; - return true; + return MEM_ACCESS_SKIPPED_UNSUPPORTED_INCREMENT_SIZE; } - return false; + return MEM_ACCESS_OK; } -static bool mem_should_skip_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t increment, bool is_read, char **skip_reason) +static mem_access_result_t +mem_should_skip_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t increment, bool is_read) { - assert(skip_reason); - if (size > 8) { /* TODO: Add 128b support if it's ever used. Involves modifying read/write_abstract_arg() to work on two 64b values. */ LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - unsupported size: %d bits", is_read ? "read" : "write", size * 8); - *skip_reason = "skipped (unsupported size)"; - return true; + return MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE; } if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - abstract access only supports %u-bit address.", is_read ? "read" : "write", riscv_xlen(target)); - *skip_reason = "skipped (too large address)"; - return true; + return MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS; } if (is_read && size != increment) { LOG_TARGET_ERROR(target, "Skipping mem read via abstract access - " "abstract command reads only support size==increment."); - *skip_reason = "skipped (unsupported increment)"; - return true; + return MEM_ACCESS_SKIPPED_UNSUPPORTED_INCREMENT_SIZE; } - - return false; + return MEM_ACCESS_OK; } /* @@ -3870,12 +3538,16 @@ static bool mem_should_skip_abstract(struct target *target, target_addr_t addres * supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 byte * aamsize fields in the memory access abstract command. */ -static int read_memory_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static mem_access_result_t +read_memory_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { - RISCV013_INFO(info); + mem_access_result_t skip_reason = + mem_should_skip_abstract(target, address, size, increment, /* is_read = */ true); + if (skip_reason != MEM_ACCESS_OK) + return skip_reason; - int result = ERROR_OK; + RISCV013_INFO(info); bool use_aampostincrement = info->has_aampostincrement != YNM_NO; LOG_TARGET_DEBUG(target, "Reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, @@ -3884,13 +3556,14 @@ static int read_memory_abstract(struct target *target, target_addr_t address, memset(buffer, 0, count * size); /* Convert the size (bytes) to width (bits) */ - unsigned width = size << 3; + unsigned int width = size << 3; /* Create the command (physical address, postincrement, read) */ uint32_t command = access_memory_command(target, false, width, use_aampostincrement, false); /* Execute the reads */ uint8_t *p = buffer; + int result = ERROR_OK; bool updateaddr = true; unsigned int width32 = (width < 32) ? 32 : width; for (uint32_t c = 0; c < count; c++) { @@ -3900,13 +3573,13 @@ static int read_memory_abstract(struct target *target, target_addr_t address, result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write arg1."); - return result; + return MEM_ACCESS_FAILED_DM_ACCESS_FAILED; } } /* Execute the command */ uint32_t cmderr; - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); /* TODO: we need to modify error handling here. */ /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ @@ -3916,7 +3589,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address, riscv_reg_t new_address; result = read_abstract_arg(target, &new_address, 1, riscv_xlen(target)); if (result != ERROR_OK) - return result; + return MEM_ACCESS_FAILED_DM_ACCESS_FAILED; if (new_address == address + size) { LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target."); @@ -3928,7 +3601,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address, } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, false); - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); if (result == ERROR_OK) { LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; @@ -3936,14 +3609,17 @@ static int read_memory_abstract(struct target *target, target_addr_t address, } } + /* TODO: + * (1) Only the 1st access can result in a 'skip' + * (2) Analyze cmderr value */ if (result != ERROR_OK) - return result; + return MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR; /* Copy arg0 to buffer (rounded width up to nearest 32) */ riscv_reg_t value; result = read_abstract_arg(target, &value, 0, width32); if (result != ERROR_OK) - return result; + return MEM_ACCESS_FAILED_DM_ACCESS_FAILED; buf_set_u64(p, 0, 8 * size, value); if (info->has_aampostincrement == YNM_YES) @@ -3951,7 +3627,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address, p += size; } - return result; + return MEM_ACCESS_OK; } /* @@ -3959,9 +3635,16 @@ static int read_memory_abstract(struct target *target, target_addr_t address, * sizes supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 * byte aamsize fields in the memory access abstract command. */ -static int write_memory_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static mem_access_result_t +write_memory_abstract(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) { + mem_access_result_t skip_reason = + mem_should_skip_abstract(target, address, size, + /* increment = */ 0, /* is_read = */ false); + if (skip_reason != MEM_ACCESS_OK) + return skip_reason; + RISCV013_INFO(info); int result = ERROR_OK; bool use_aampostincrement = info->has_aampostincrement != YNM_NO; @@ -3970,7 +3653,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, size, address); /* Convert the size (bytes) to width (bits) */ - unsigned width = size << 3; + unsigned int width = size << 3; /* Create the command (physical address, postincrement, write) */ uint32_t command = access_memory_command(target, false, width, use_aampostincrement, true); @@ -3984,7 +3667,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, result = write_abstract_arg(target, 0, value, riscv_xlen(target)); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write arg0."); - return result; + return MEM_ACCESS_FAILED_DM_ACCESS_FAILED; } /* Update the address if it is the first time or aampostincrement is not supported by the target. */ @@ -3993,13 +3676,13 @@ static int write_memory_abstract(struct target *target, target_addr_t address, result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write arg1."); - return result; + return MEM_ACCESS_FAILED_DM_ACCESS_FAILED; } } /* Execute the command */ uint32_t cmderr; - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); /* TODO: we need to modify error handling here. */ /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ @@ -4009,7 +3692,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, riscv_reg_t new_address; result = read_abstract_arg(target, &new_address, 1, riscv_xlen(target)); if (result != ERROR_OK) - return result; + return MEM_ACCESS_FAILED_DM_ACCESS_FAILED; if (new_address == address + size) { LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target."); @@ -4021,7 +3704,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, true); - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); if (result == ERROR_OK) { LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; @@ -4029,15 +3712,18 @@ static int write_memory_abstract(struct target *target, target_addr_t address, } } + /* TODO: + * (1) Only the 1st access can result in a 'skip' + * (2) Analyze cmderr value */ if (result != ERROR_OK) - return result; + return MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR; if (info->has_aampostincrement == YNM_YES) updateaddr = false; p += size; } - return result; + return MEM_ACCESS_OK; } /** @@ -4067,11 +3753,11 @@ static int read_memory_progbuf_inner_startup(struct target *target, /* AC_ACCESS_REGISTER_POSTEXEC is used to trigger first stage of the * pipeline (memory -> s1) whenever this command is executed. */ - const uint32_t startup_command = access_register_command(target, + const uint32_t startup_command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); uint32_t cmderr; - if (execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK) return ERROR_FAIL; /* TODO: we need to modify error handling here. */ /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ @@ -4554,11 +4240,11 @@ static int read_memory_progbuf_inner_one(struct target *target, if (write_abstract_arg(target, 0, access.target_address, riscv_xlen(target)) != ERROR_OK) return ERROR_FAIL; - uint32_t command = access_register_command(target, GDB_REGNO_S1, + uint32_t command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); uint32_t cmderr; - if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK) return ERROR_FAIL; return read_word_from_s1(target, access, 0); @@ -4567,32 +4253,32 @@ static int read_memory_progbuf_inner_one(struct target *target, /** * Read the requested memory, silently handling memory access errors. */ -static int read_memory_progbuf(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static mem_access_result_t +read_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) { - if (riscv_xlen(target) < size * 8) { - LOG_TARGET_ERROR(target, "XLEN (%d) is too short for %" - PRIu32 "-bit memory read.", riscv_xlen(target), size * 8); - return ERROR_FAIL; - } + mem_access_result_t skip_reason = + mem_should_skip_progbuf(target, address, size, /* is_read = */ true); + if (skip_reason != MEM_ACCESS_OK) + return skip_reason; LOG_TARGET_DEBUG(target, "reading %" PRIu32 " elements of %" PRIu32 " bytes from 0x%" TARGET_PRIxADDR, count, size, address); if (dm013_select_target(target) != ERROR_OK) - return ERROR_FAIL; + return MEM_ACCESS_SKIPPED_TARGET_SELECT_FAILED; select_dmi(target); memset(buffer, 0, count*size); if (execute_fence(target) != ERROR_OK) - return ERROR_FAIL; + return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED; uint64_t mstatus = 0; uint64_t mstatus_old = 0; if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) - return ERROR_FAIL; + return MEM_ACCESS_FAILED_PRIV_MOD_FAILED; const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV); const struct memory_access_info access = { @@ -4607,9 +4293,32 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, if (mstatus != mstatus_old && register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old) != ERROR_OK) - return ERROR_FAIL; + return MEM_ACCESS_FAILED; - return result; + return (result == ERROR_OK) ? MEM_ACCESS_OK : MEM_ACCESS_FAILED; +} + +static mem_access_result_t +read_memory_sysbus(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +{ + mem_access_result_t skip_reason = + mem_should_skip_sysbus(target, address, size, increment, /* is_read = */ true); + if (skip_reason != MEM_ACCESS_OK) + return skip_reason; + + int ret = ERROR_FAIL; + uint64_t sbver = get_field(get_info(target)->sbcs, DM_SBCS_SBVERSION); + if (sbver == 0) { + ret = read_memory_bus_v0(target, address, size, count, buffer, increment); + } else if (sbver == 1) { + ret = read_memory_bus_v1(target, address, size, count, buffer, increment); + } else { + LOG_TARGET_ERROR(target, + "Unknown system bus version: %" PRIu64, sbver); + } + + return (ret == ERROR_OK) ? MEM_ACCESS_OK : MEM_ACCESS_FAILED; } static int read_memory(struct target *target, target_addr_t address, @@ -4618,62 +4327,58 @@ static int read_memory(struct target *target, target_addr_t address, if (count == 0) return ERROR_OK; - if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { + if (!IS_PWR_OF_2(size) || size < 1 || size > 16) { LOG_TARGET_ERROR(target, "BUG: Unsupported size for memory read: %d", size); return ERROR_FAIL; } - int ret = ERROR_FAIL; - RISCV_INFO(r); - RISCV013_INFO(info); - - char *progbuf_result = "disabled"; - char *sysbus_result = "disabled"; - char *abstract_result = "disabled"; - - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { - int method = r->mem_access_methods[i]; - - if (method == RISCV_MEM_ACCESS_PROGBUF) { - if (mem_should_skip_progbuf(target, address, size, true, &progbuf_result)) - continue; - - ret = read_memory_progbuf(target, address, size, count, buffer, increment); - - if (ret != ERROR_OK) - progbuf_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_SYSBUS) { - if (mem_should_skip_sysbus(target, address, size, increment, true, &sysbus_result)) - continue; - - if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) - ret = read_memory_bus_v0(target, address, size, count, buffer, increment); - else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) - ret = read_memory_bus_v1(target, address, size, count, buffer, increment); - - if (ret != ERROR_OK) - sysbus_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { - if (mem_should_skip_abstract(target, address, size, increment, true, &abstract_result)) - continue; - - ret = read_memory_abstract(target, address, size, count, buffer, increment); + mem_access_result_t skip_reason[] = { + [RISCV_MEM_ACCESS_PROGBUF] = MEM_ACCESS_DISABLED, + [RISCV_MEM_ACCESS_SYSBUS] = MEM_ACCESS_DISABLED, + [RISCV_MEM_ACCESS_ABSTRACT] = MEM_ACCESS_DISABLED, + }; - if (ret != ERROR_OK) - abstract_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) - /* No further mem access method to try. */ - break; + RISCV_INFO(r); + for (unsigned int i = 0; i < r->num_enabled_mem_access_methods; ++i) { + riscv_mem_access_method_t method = r->mem_access_methods[i]; + switch (method) { + case RISCV_MEM_ACCESS_PROGBUF: + skip_reason[method] = + read_memory_progbuf(target, address, + size, count, buffer, increment); + break; + case RISCV_MEM_ACCESS_SYSBUS: + skip_reason[method] = + read_memory_sysbus(target, address, + size, count, buffer, increment); + break; + case RISCV_MEM_ACCESS_ABSTRACT: + skip_reason[method] = + read_memory_abstract(target, address, + size, count, buffer, increment); + break; + default: + LOG_TARGET_ERROR(target, "Unknown memory access method: %d", method); + assert(false); + return ERROR_FAIL; + } - log_mem_access_result(target, ret == ERROR_OK, method, true); + if (is_mem_access_failed(skip_reason[method])) + goto failure; - if (ret == ERROR_OK) - return ret; + const bool success = (skip_reason[method] == MEM_ACCESS_OK); + log_mem_access_result(target, success, method, /* is_read = */ true); + if (success) + return ERROR_OK; } - LOG_TARGET_ERROR(target, "Failed to read memory (addr=0x%" PRIx64 ")", address); - LOG_TARGET_ERROR(target, " progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); - return ret; +failure: + LOG_TARGET_ERROR(target, "Failed to read memory (addr=0x%" PRIx64 ")\n" + " progbuf=%s, sysbus=%s, abstract=%s", address, + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_PROGBUF]), + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_SYSBUS]), + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_ABSTRACT])); + return ERROR_FAIL; } static int write_memory_bus_v0(struct target *target, target_addr_t address, @@ -4740,9 +4445,10 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, target_addr_t next_address = address; target_addr_t end_address = address + count * size; - int result; + int result = sb_write_address(target, next_address, RISCV_DELAY_BASE); + if (result != ERROR_OK) + return result; - sb_write_address(target, next_address, true); while (next_address < end_address) { LOG_TARGET_DEBUG(target, "Transferring burst starting at address 0x%" TARGET_PRIxADDR, next_address); @@ -4896,14 +4602,14 @@ static int write_memory_progbuf_startup(struct target *target, target_addr_t *ad /* Write and execute command that moves the value from data0 [, data1] * into S1 and executes program buffer. */ - uint32_t command = access_register_command(target, + uint32_t command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); uint32_t cmderr; - if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK) return ERROR_FAIL; log_memory_access64(*address_p, value, size, /*is_read*/ false); @@ -5126,25 +4832,25 @@ static int write_memory_progbuf_inner(struct target *target, target_addr_t start return write_memory_progbuf_teardown(target); } -static int write_memory_progbuf(struct target *target, target_addr_t address, +static mem_access_result_t +write_memory_progbuf(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - if (riscv_xlen(target) < size * 8) { - LOG_TARGET_ERROR(target, "XLEN (%u) is too short for %" PRIu32 "-bit memory write.", - riscv_xlen(target), size * 8); - return ERROR_FAIL; - } + mem_access_result_t skip_reason = + mem_should_skip_progbuf(target, address, size, /* is_read = */ false); + if (skip_reason != MEM_ACCESS_OK) + return skip_reason; LOG_TARGET_DEBUG(target, "writing %" PRIu32 " words of %" PRIu32 " bytes to 0x%" TARGET_PRIxADDR, count, size, address); if (dm013_select_target(target) != ERROR_OK) - return ERROR_FAIL; + return MEM_ACCESS_SKIPPED_TARGET_SELECT_FAILED; uint64_t mstatus = 0; uint64_t mstatus_old = 0; if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) - return ERROR_FAIL; + return MEM_ACCESS_FAILED_PRIV_MOD_FAILED; const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV); @@ -5153,73 +4859,109 @@ static int write_memory_progbuf(struct target *target, target_addr_t address, /* Restore MSTATUS */ if (mstatus != mstatus_old) if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) - return ERROR_FAIL; + return MEM_ACCESS_FAILED; if (execute_fence(target) != ERROR_OK) - return ERROR_FAIL; + return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED; - return result; + return result == ERROR_OK ? MEM_ACCESS_OK : MEM_ACCESS_FAILED; } -static int write_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static mem_access_result_t +write_memory_sysbus(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) { - if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { - LOG_TARGET_ERROR(target, "BUG: Unsupported size for memory write: %d", size); - return ERROR_FAIL; - } + riscv013_info_t *info = get_info(target); + mem_access_result_t skip_reason = + mem_should_skip_sysbus(target, address, size, 0, /* is_read = */ false); + if (skip_reason != MEM_ACCESS_OK) + return skip_reason; + /* TODO: write_memory_bus_* should return mem_access_result_t too*/ int ret = ERROR_FAIL; - RISCV_INFO(r); - RISCV013_INFO(info); - - char *progbuf_result = "disabled"; - char *sysbus_result = "disabled"; - char *abstract_result = "disabled"; - - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { - int method = r->mem_access_methods[i]; + uint64_t sbver = get_field(info->sbcs, DM_SBCS_SBVERSION); + if (sbver == 0) { + ret = write_memory_bus_v0(target, address, size, count, buffer); + } else if (sbver == 1) { + ret = write_memory_bus_v1(target, address, size, count, buffer); + } else { + LOG_TARGET_ERROR(target, + "Unknown system bus version: %" PRIu64, sbver); + } - if (method == RISCV_MEM_ACCESS_PROGBUF) { - if (mem_should_skip_progbuf(target, address, size, false, &progbuf_result)) - continue; + if (ret != ERROR_OK) + skip_reason = MEM_ACCESS_FAILED; - ret = write_memory_progbuf(target, address, size, count, buffer); + return skip_reason; +} - if (ret != ERROR_OK) - progbuf_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_SYSBUS) { - if (mem_should_skip_sysbus(target, address, size, 0, false, &sysbus_result)) - continue; +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + if (!IS_PWR_OF_2(size) || size < 1 || size > 16) { + LOG_TARGET_ERROR(target, "BUG: Unsupported size for memory write: %d", size); + return ERROR_FAIL; + } - if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) - ret = write_memory_bus_v0(target, address, size, count, buffer); - else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) - ret = write_memory_bus_v1(target, address, size, count, buffer); + mem_access_result_t skip_reason[] = { + [RISCV_MEM_ACCESS_PROGBUF] = MEM_ACCESS_DISABLED, + [RISCV_MEM_ACCESS_SYSBUS] = MEM_ACCESS_DISABLED, + [RISCV_MEM_ACCESS_ABSTRACT] = MEM_ACCESS_DISABLED + }; - if (ret != ERROR_OK) - sysbus_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { - if (mem_should_skip_abstract(target, address, size, 0, false, &abstract_result)) - continue; + RISCV_INFO(r); + for (unsigned int i = 0; i < r->num_enabled_mem_access_methods; ++i) { + riscv_mem_access_method_t method = r->mem_access_methods[i]; + switch (method) { + case RISCV_MEM_ACCESS_PROGBUF: + skip_reason[method] = + write_memory_progbuf(target, address, + size, count, buffer); + break; + case RISCV_MEM_ACCESS_SYSBUS: + skip_reason[method] = + write_memory_sysbus(target, address, + size, count, buffer); + break; + case RISCV_MEM_ACCESS_ABSTRACT: + skip_reason[method] = + write_memory_abstract(target, address, + size, count, buffer); + break; + default: + LOG_TARGET_ERROR(target, "Unknown memory access method: %d", method); + assert(false); + return ERROR_FAIL; + } - ret = write_memory_abstract(target, address, size, count, buffer); + if (is_mem_access_failed(skip_reason[method])) + goto failure; - if (ret != ERROR_OK) - abstract_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) - /* No further mem access method to try. */ - break; + const bool success = (skip_reason[method] == MEM_ACCESS_OK); + log_mem_access_result(target, success, method, /* is_read = */ false); + if (success) + return ERROR_OK; + } - log_mem_access_result(target, ret == ERROR_OK, method, false); +failure: + LOG_TARGET_ERROR(target, "Failed to write memory (addr=0x%" PRIx64 ")\n" + "progbuf=%s, sysbus=%s, abstract=%s", address, + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_PROGBUF]), + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_SYSBUS]), + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_ABSTRACT])); + return ERROR_FAIL; +} - if (ret == ERROR_OK) - return ret; - } +static bool riscv013_get_impebreak(const struct target *target) +{ + RISCV013_INFO(r); + return r->impebreak; +} - LOG_TARGET_ERROR(target, "Target %s: Failed to write memory (addr=0x%" PRIx64 ")", target_name(target), address); - LOG_TARGET_ERROR(target, " progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); - return ret; +static unsigned int riscv013_get_progbufsize(const struct target *target) +{ + RISCV013_INFO(r); + return r->progbufsize; } static int arch_state(struct target *target) @@ -5326,13 +5068,13 @@ static int select_prepped_harts(struct target *target) } assert(dm->hart_count); - unsigned hawindow_count = (dm->hart_count + 31) / 32; + unsigned int hawindow_count = (dm->hart_count + 31) / 32; uint32_t *hawindow = calloc(hawindow_count, sizeof(uint32_t)); if (!hawindow) return ERROR_FAIL; target_list_t *entry; - unsigned total_selected = 0; + unsigned int total_selected = 0; unsigned int selected_index = 0; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; @@ -5364,7 +5106,7 @@ static int select_prepped_harts(struct target *target) return ERROR_FAIL; } - for (unsigned i = 0; i < hawindow_count; i++) { + for (unsigned int i = 0; i < hawindow_count; i++) { if (dm_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) { free(hawindow); return ERROR_FAIL; @@ -5561,8 +5303,7 @@ static int riscv013_invalidate_cached_progbuf(struct target *target) } LOG_TARGET_DEBUG(target, "Invalidating progbuf cache"); - for (unsigned int i = 0; i < 15; i++) - dm->progbuf_cache[i] = 0; + memset(dm->progbuf_cache, 0, sizeof(dm->progbuf_cache)); return ERROR_OK; } @@ -5574,7 +5315,7 @@ static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr) run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); - return execute_abstract_command(target, run_program, cmderr); + return riscv013_execute_abstract_command(target, run_program, cmderr); } static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d) @@ -5593,7 +5334,7 @@ static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a) buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } -static void riscv013_fill_dmi_nop(struct target *target, char *buf) +static void riscv013_fill_dm_nop(struct target *target, char *buf) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); @@ -5607,27 +5348,6 @@ static int riscv013_get_dmi_scan_length(struct target *target) return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } -void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_write(target, buf, a + dm->base, d); -} - -void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_read(target, buf, a + dm->base); -} - -void riscv013_fill_dm_nop(struct target *target, char *buf) -{ - riscv013_fill_dmi_nop(target, buf); -} - static int maybe_execute_fence_i(struct target *target) { if (has_sufficient_progbuf(target, 2)) diff --git a/src/target/riscv/riscv-013.h b/src/target/riscv/riscv-013.h index f39393c..ca2d4ae 100644 --- a/src/target/riscv/riscv-013.h +++ b/src/target/riscv/riscv-013.h @@ -19,5 +19,9 @@ int riscv013_set_register(struct target *target, enum gdb_regno rid, riscv_reg_t value); int riscv013_set_register_buf(struct target *target, enum gdb_regno regno, const uint8_t *value); +uint32_t riscv013_access_register_command(struct target *target, uint32_t number, + unsigned int size, uint32_t flags); +int riscv013_execute_abstract_command(struct target *target, uint32_t command, + uint32_t *cmderr); #endif /* OPENOCD_TARGET_RISCV_RISCV_013_H */ diff --git a/src/target/riscv/riscv-013_reg.c b/src/target/riscv/riscv-013_reg.c index a71a01c..514103b 100644 --- a/src/target/riscv/riscv-013_reg.c +++ b/src/target/riscv/riscv-013_reg.c @@ -5,10 +5,12 @@ #endif #include "riscv-013_reg.h" +#include "field_helpers.h" #include "riscv_reg.h" #include "riscv_reg_impl.h" #include "riscv-013.h" +#include "debug_defines.h" #include <helper/time_support.h> static int riscv013_reg_get(struct reg *reg) @@ -44,7 +46,6 @@ static int riscv013_reg_get(struct reg *reg) static int riscv013_reg_set(struct reg *reg, uint8_t *buf) { struct target *target = riscv_reg_impl_get_target(reg); - RISCV_INFO(r); char *str = buf_to_hex_str(buf, reg->size); LOG_TARGET_DEBUG(target, "Write 0x%s to %s (valid=%d).", str, reg->name, @@ -57,17 +58,6 @@ static int riscv013_reg_set(struct reg *reg, uint8_t *buf) buf_get_u64(buf, 0, reg->size) == 0) return ERROR_OK; - if (reg->number == GDB_REGNO_TDATA1 || - reg->number == GDB_REGNO_TDATA2) { - r->manual_hwbp_set = true; - /* When enumerating triggers, we clear any triggers with DMODE set, - * assuming they were left over from a previous debug session. So make - * sure that is done before a user might be setting their own triggers. - */ - if (riscv_enumerate_triggers(target) != ERROR_OK) - return ERROR_FAIL; - } - if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { if (riscv013_set_register_buf(target, reg->number, buf) != ERROR_OK) return ERROR_FAIL; @@ -85,33 +75,277 @@ static int riscv013_reg_set(struct reg *reg, uint8_t *buf) static const struct reg_arch_type *riscv013_gdb_regno_reg_type(uint32_t regno) { - static const struct reg_arch_type riscv011_reg_type = { + static const struct reg_arch_type riscv013_reg_type = { .get = riscv013_reg_get, .set = riscv013_reg_set }; - return &riscv011_reg_type; + return &riscv013_reg_type; } -static int riscv013_init_reg(struct target *target, uint32_t regno) +static int init_cache_entry(struct target *target, uint32_t regno) +{ + struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); + if (riscv_reg_impl_is_initialized(reg)) + return ERROR_OK; + return riscv_reg_impl_init_cache_entry(target, regno, + riscv_reg_impl_gdb_regno_exist(target, regno), + riscv013_gdb_regno_reg_type(regno)); +} + +/** + * Some registers are optional (e.g. "misa"). For such registers it is first + * assumed they exist (via "assume_reg_exist()"), then the read is attempted + * (via the usual "riscv_reg_get()") and if the read fails, the register is + * marked as non-existing (via "riscv_reg_impl_set_exist()"). + */ +static int assume_reg_exist(struct target *target, uint32_t regno) { - return riscv_reg_impl_init_one(target, regno, riscv013_gdb_regno_reg_type(regno)); + return riscv_reg_impl_init_cache_entry(target, regno, + /* exist */ true, riscv013_gdb_regno_reg_type(regno)); } -int riscv013_reg_init_all(struct target *target) +static int examine_xlen(struct target *target) { - if (riscv_reg_impl_init_cache(target) != ERROR_OK) + RISCV_INFO(r); + unsigned int cmderr; + + const uint32_t command = riscv013_access_register_command(target, + GDB_REGNO_S0, /* size */ 64, AC_ACCESS_REGISTER_TRANSFER); + int res = riscv013_execute_abstract_command(target, command, &cmderr); + if (res == ERROR_OK) { + r->xlen = 64; + return ERROR_OK; + } + if (res == ERROR_TIMEOUT_REACHED) return ERROR_FAIL; + r->xlen = 32; + + return ERROR_OK; +} + +static int examine_vlenb(struct target *target) +{ + RISCV_INFO(r); + + /* Reading "vlenb" requires "mstatus.vs" to be set, so "mstatus" should + * be accessible.*/ + int res = init_cache_entry(target, GDB_REGNO_MSTATUS); + if (res != ERROR_OK) + return res; + + res = assume_reg_exist(target, GDB_REGNO_VLENB); + if (res != ERROR_OK) + return res; + + riscv_reg_t vlenb_val; + if (riscv_reg_get(target, &vlenb_val, GDB_REGNO_VLENB) != ERROR_OK) { + if (riscv_supports_extension(target, 'V')) + LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work."); + r->vlenb = 0; + return riscv_reg_impl_set_exist(target, GDB_REGNO_VLENB, false); + } + /* As defined by RISC-V V extension specification: + * https://github.com/riscv/riscv-v-spec/blob/2f68ef7256d6ec53e4d2bd7cb12862f406d64e34/v-spec.adoc?plain=1#L67-L72 */ + const unsigned int vlen_max = 65536; + const unsigned int vlenb_max = vlen_max / 8; + if (vlenb_val > vlenb_max) { + LOG_TARGET_WARNING(target, "'vlenb == %" PRIu64 + "' is greater than maximum allowed by specification (%u); vector register access won't work.", + vlenb_val, vlenb_max); + r->vlenb = 0; + return ERROR_OK; + } + assert(vlenb_max <= UINT_MAX); + r->vlenb = (unsigned int)vlenb_val; + + LOG_TARGET_INFO(target, "Vector support with vlenb=%u", r->vlenb); + return ERROR_OK; +} + +enum misa_mxl { + MISA_MXL_INVALID = 0, + MISA_MXL_32 = 1, + MISA_MXL_64 = 2, + MISA_MXL_128 = 3 +}; + +unsigned int mxl_to_xlen(enum misa_mxl mxl) +{ + switch (mxl) { + case MISA_MXL_32: + return 32; + case MISA_MXL_64: + return 64; + case MISA_MXL_128: + return 128; + case MISA_MXL_INVALID: + assert(0); + } + return 0; +} + +static int check_misa_mxl(const struct target *target) +{ + RISCV_INFO(r); + + if (r->misa == 0) { + LOG_TARGET_WARNING(target, "'misa' register is read as zero." + "OpenOCD will not be able to determine some hart's capabilities."); + return ERROR_OK; + } + const unsigned int dxlen = riscv_xlen(target); + assert(dxlen <= sizeof(riscv_reg_t) * CHAR_BIT); + assert(dxlen >= 2); + const riscv_reg_t misa_mxl_mask = (riscv_reg_t)0x3 << (dxlen - 2); + const unsigned int mxl = get_field(r->misa, misa_mxl_mask); + if (mxl == MISA_MXL_INVALID) { + /* This is not an error! + * Imagine the platform that: + * - Has no abstract access to CSRs, so that CSRs are read + * through Program Buffer via "csrr" instruction. + * - Complies to v1.10 of the Priveleged Spec, so that misa.mxl + * is WARL and MXLEN may be chainged. + * https://github.com/riscv/riscv-isa-manual/commit/9a7dd2fe29011587954560b5dcf1875477b27ad8 + * - DXLEN == MXLEN on reset == 64. + * In a following scenario: + * - misa.mxl was written, so that MXLEN is 32. + * - Debugger connects to the target. + * - Debugger observes DXLEN == 64. + * - Debugger reads misa: + * - Abstract access fails with "cmderr == not supported". + * - Access via Program Buffer involves reading "misa" to an + * "xreg" via "csrr", so that the "xreg" is filled with + * zero-extended value of "misa" (since "misa" is + * MXLEN-wide). + * - Debugger derives "misa.mxl" assumig "misa" is DXLEN-bit + * wide (64) while MXLEN is 32 and therefore erroneously + * assumes "misa.mxl" to be zero (invalid). + */ + LOG_TARGET_WARNING(target, "Detected DXLEN (%u) does not match " + "MXLEN: misa.mxl == 0, misa == 0x%" PRIx64 ".", + dxlen, r->misa); + return ERROR_OK; + } + const unsigned int mxlen = mxl_to_xlen(mxl); + if (dxlen < mxlen) { + LOG_TARGET_ERROR(target, + "MXLEN (%u) reported in misa.mxl field exceeds " + "the detected DXLEN (%u)", + mxlen, dxlen); + return ERROR_FAIL; + } + /* NOTE: + * The value of "misa.mxl" may stil not coincide with "xlen". + * "misa[26:XLEN-3]" bits are marked as WIRI in at least version 1.10 + * of RISC-V Priveleged Spec. Therefore, if "xlen" is erroneously + * assumed to be 32 when it actually is 64, "mxl" will be read from + * this WIRI field and may be equal to "MISA_MXL_32" by coincidence. + * This is not an issue though from the version 1.11 onward, since + * "misa[26:XLEN-3]" became WARL and equal to 0. + */ + + /* Display this as early as possible to help people who are using + * really slow simulators. */ + LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, riscv_xlen(target), r->misa); + return ERROR_OK; +} + +static int examine_misa(struct target *target) +{ + RISCV_INFO(r); + + int res = init_cache_entry(target, GDB_REGNO_MISA); + if (res != ERROR_OK) + return res; + + res = riscv_reg_get(target, &r->misa, GDB_REGNO_MISA); + if (res != ERROR_OK) + return res; + return check_misa_mxl(target); +} + +static int examine_mtopi(struct target *target) +{ + RISCV_INFO(r); + + /* Assume the registers exist */ + r->mtopi_readable = true; + r->mtopei_readable = true; + + int res = assume_reg_exist(target, GDB_REGNO_MTOPI); + if (res != ERROR_OK) + return res; + res = assume_reg_exist(target, GDB_REGNO_MTOPEI); + if (res != ERROR_OK) + return res; + + riscv_reg_t value; + if (riscv_reg_get(target, &value, GDB_REGNO_MTOPI) != ERROR_OK) { + r->mtopi_readable = false; + r->mtopei_readable = false; + } else if (riscv_reg_get(target, &value, GDB_REGNO_MTOPEI) != ERROR_OK) { + LOG_TARGET_INFO(target, "S?aia detected without IMSIC"); + r->mtopei_readable = false; + } else { + LOG_TARGET_INFO(target, "S?aia detected with IMSIC"); + } + res = riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPI, r->mtopi_readable); + if (res != ERROR_OK) + return res; + + return riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPEI, r->mtopei_readable); +} + +/** + * This function assumes target's DM to be initialized (target is able to + * access DMs registers, execute program buffer, etc.) + */ +int riscv013_reg_examine_all(struct target *target) +{ + int res = riscv_reg_impl_init_cache(target); + if (res != ERROR_OK) + return res; init_shared_reg_info(target); + assert(target->state == TARGET_HALTED); + + res = examine_xlen(target); + if (res != ERROR_OK) + return res; + + /* Reading CSRs may clobber "s0", "s1", so it should be possible to + * save them in cache. */ + res = init_cache_entry(target, GDB_REGNO_S0); + if (res != ERROR_OK) + return res; + res = init_cache_entry(target, GDB_REGNO_S1); + if (res != ERROR_OK) + return res; + + res = examine_misa(target); + if (res != ERROR_OK) + return res; + + res = examine_vlenb(target); + if (res != ERROR_OK) + return res; + riscv_reg_impl_init_vector_reg_type(target); - for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) - if (riscv013_init_reg(target, regno) != ERROR_OK) - return ERROR_FAIL; + res = examine_mtopi(target); + if (res != ERROR_OK) + return res; - if (riscv_reg_impl_expose_csrs(target) != ERROR_OK) - return ERROR_FAIL; + for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) { + res = init_cache_entry(target, regno); + if (res != ERROR_OK) + return res; + } + + res = riscv_reg_impl_expose_csrs(target); + if (res != ERROR_OK) + return res; riscv_reg_impl_hide_csrs(target); diff --git a/src/target/riscv/riscv-013_reg.h b/src/target/riscv/riscv-013_reg.h index e7a9447..e542a35 100644 --- a/src/target/riscv/riscv-013_reg.h +++ b/src/target/riscv/riscv-013_reg.h @@ -13,10 +13,11 @@ */ /** - * Init initialize register cache. After this function all registers can be - * safely accessed via functions described here and in `riscv_reg.h`. + * This function assumes target is halted. + * After this function all registers can be safely accessed via functions + * described here and in `riscv_reg.h`. */ -int riscv013_reg_init_all(struct target *target); +int riscv013_reg_examine_all(struct target *target); /** * This function is used to save the value of a register in cache. The register diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 9c4796d..a8d0ef8 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -54,7 +54,8 @@ struct scan_field select_idcode = { }; static bscan_tunnel_type_t bscan_tunnel_type; -int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ +#define BSCAN_TUNNEL_IR_WIDTH_NBITS 7 +uint8_t bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ static int bscan_tunnel_ir_id; /* IR ID of the JTAG TAP to access the tunnel. Valid when not 0 */ static const uint8_t bscan_zero[4] = {0}; @@ -67,7 +68,6 @@ static struct scan_field select_user4 = { }; -static uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */ static struct scan_field _bscan_tunnel_data_register_select_dmi[] = { { .num_bits = 3, @@ -80,8 +80,8 @@ static struct scan_field _bscan_tunnel_data_register_select_dmi[] = { .in_value = NULL, }, { - .num_bits = 7, - .out_value = bscan_tunneled_ir_width, + .num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS, + .out_value = &bscan_tunnel_ir_width, .in_value = NULL, }, { @@ -98,8 +98,8 @@ static struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = { .in_value = NULL, }, { - .num_bits = 7, - .out_value = bscan_tunneled_ir_width, + .num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS, + .out_value = &bscan_tunnel_ir_width, .in_value = NULL, }, { @@ -140,10 +140,15 @@ struct tdata1_cache { }; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ -int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; +static int riscv_command_timeout_sec_value = DEFAULT_COMMAND_TIMEOUT_SEC; -/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ -int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; +/* DEPRECATED Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ +static int riscv_reset_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; + +int riscv_get_command_timeout_sec(void) +{ + return MAX(riscv_command_timeout_sec_value, riscv_reset_timeout_sec); +} static bool riscv_enable_virt2phys = true; @@ -295,7 +300,6 @@ void select_dmi_via_bscan(struct target *target) int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr) { /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */ - uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width}; uint8_t tunneled_dr_width[4] = {32}; uint8_t out_value[5] = {0}; uint8_t in_value[5] = {0}; @@ -311,8 +315,8 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ tunneled_ir[1].num_bits = bscan_tunnel_ir_width; tunneled_ir[1].out_value = ir_dtmcontrol; tunneled_ir[1].in_value = NULL; - tunneled_ir[2].num_bits = 7; - tunneled_ir[2].out_value = tunneled_ir_width; + tunneled_ir[2].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS; + tunneled_ir[2].out_value = &bscan_tunnel_ir_width; tunneled_ir[2].in_value = NULL; tunneled_ir[3].num_bits = 1; tunneled_ir[3].out_value = bscan_zero; @@ -324,7 +328,7 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ tunneled_dr[1].num_bits = 32 + 1; tunneled_dr[1].out_value = out_value; tunneled_dr[1].in_value = in_value; - tunneled_dr[2].num_bits = 7; + tunneled_dr[2].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS; tunneled_dr[2].out_value = tunneled_dr_width; tunneled_dr[2].in_value = NULL; tunneled_dr[3].num_bits = 1; @@ -338,8 +342,8 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ tunneled_ir[2].num_bits = bscan_tunnel_ir_width; tunneled_ir[2].out_value = ir_dtmcontrol; tunneled_ir[1].in_value = NULL; - tunneled_ir[1].num_bits = 7; - tunneled_ir[1].out_value = tunneled_ir_width; + tunneled_ir[1].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS; + tunneled_ir[1].out_value = &bscan_tunnel_ir_width; tunneled_ir[2].in_value = NULL; tunneled_ir[0].num_bits = 1; tunneled_ir[0].out_value = bscan_zero; @@ -378,22 +382,23 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ return ERROR_OK; } -static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) +/* TODO: rename "dtmcontrol"-> "dtmcs" */ +int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) { - struct scan_field field; - uint8_t in_value[4]; - uint8_t out_value[4] = { 0 }; + uint8_t value[4]; if (bscan_tunnel_ir_width != 0) return dtmcontrol_scan_via_bscan(target, out, in_ptr); - buf_set_u32(out_value, 0, 32, out); + buf_set_u32(value, 0, 32, out); jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); - field.num_bits = 32; - field.out_value = out_value; - field.in_value = in_value; + struct scan_field field = { + .num_bits = 32, + .out_value = value, + .in_value = in_ptr ? value : NULL + }; jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); /* Always return to dbus. */ @@ -401,15 +406,18 @@ static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr int retval = jtag_execute_queue(); if (retval != ERROR_OK) { - LOG_TARGET_ERROR(target, "dtmcontrol scan failed, error code = %d", retval); + LOG_TARGET_ERROR(target, "dtmcs scan failed, error code = %d", retval); return retval; } - uint32_t in = buf_get_u32(field.in_value, 0, 32); - LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); - - if (in_ptr) + if (in_ptr) { + assert(field.in_value); + uint32_t in = buf_get_u32(field.in_value, 0, 32); + LOG_TARGET_DEBUG(target, "DTMCS: 0x%" PRIx32 " -> 0x%" PRIx32, out, in); *in_ptr = in; + } else { + LOG_TARGET_DEBUG(target, "DTMCS: 0x%" PRIx32 " -> ?", out); + } return ERROR_OK; } @@ -468,7 +476,6 @@ static int riscv_init_target(struct command_context *cmd_ctx, } h_u32_to_le(ir_user4, ir_user4_raw); select_user4.num_bits = target->tap->ir_length; - bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width; if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width; else /* BSCAN_TUNNEL_NESTED_TAP */ @@ -522,6 +529,8 @@ static void riscv_deinit_target(struct target *target) if (!info) return; + free(info->reserved_triggers); + range_list_t *entry, *tmp; list_for_each_entry_safe(entry, tmp, &info->hide_csr, list) { free(entry->name); @@ -612,9 +621,27 @@ static int find_first_trigger_by_id(struct target *target, int unique_id) return -1; } -static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2, - riscv_reg_t tdata1_ignore_mask) +static unsigned int count_trailing_ones(riscv_reg_t reg) +{ + assert(sizeof(riscv_reg_t) * 8 == 64); + for (unsigned int i = 0; i < 64; i++) { + if ((1 & (reg >> i)) == 0) + return i; + } + return 64; +} + +static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2) { + RISCV_INFO(r); + assert(r->reserved_triggers); + assert(idx < r->trigger_count); + if (r->reserved_triggers[idx]) { + LOG_TARGET_DEBUG(target, + "Trigger %u is reserved by 'reserve_trigger' command.", idx); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + riscv_reg_t tdata1_rb, tdata2_rb; // Select which trigger to use if (riscv_reg_set(target, GDB_REGNO_TSELECT, idx) != ERROR_OK) @@ -637,20 +664,51 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat return ERROR_FAIL; if (riscv_reg_get(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK) return ERROR_FAIL; - bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask); - bool tdata2_config_denied = tdata2 != tdata2_rb; - if (tdata1_config_denied || tdata2_config_denied) { + + const uint32_t type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); + const bool is_mcontrol = type == CSR_TDATA1_TYPE_MCONTROL; + + /* Determine if tdata1 supports what we need. + * For mcontrol triggers, we don't care about + * the value in the read-only "maskmax" field. + */ + const riscv_reg_t tdata1_ignore_mask = is_mcontrol ? CSR_MCONTROL_MASKMAX(riscv_xlen(target)) : 0; + const bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask); + + /* Determine if tdata1.maxmask is sufficient + * (only relevant for mcontrol triggers and NAPOT match type) + */ + bool unsupported_napot_range = false; + riscv_reg_t maskmax_value = 0; + if (!tdata1_config_denied) { + const bool is_napot_match = get_field(tdata1_rb, CSR_MCONTROL_MATCH) == CSR_MCONTROL_MATCH_NAPOT; + if (is_mcontrol && is_napot_match) { + maskmax_value = get_field(tdata1_rb, CSR_MCONTROL_MASKMAX(riscv_xlen(target))); + const unsigned int napot_size = count_trailing_ones(tdata2) + 1; + if (maskmax_value < napot_size) + unsupported_napot_range = true; + } + } + + const bool tdata2_config_denied = tdata2 != tdata2_rb; + if (tdata1_config_denied || tdata2_config_denied || unsupported_napot_range) { LOG_TARGET_DEBUG(target, "Trigger %u doesn't support what we need.", idx); if (tdata1_config_denied) LOG_TARGET_DEBUG(target, - "After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64 "; tdata1_ignore_mask=0x%" PRIx64, - tdata1, tdata1_rb, tdata1_ignore_mask); + "After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); if (tdata2_config_denied) LOG_TARGET_DEBUG(target, - "wrote 0x%" PRIx64 " to tdata2 but read back 0x%" PRIx64, + "After writing 0x%" PRIx64 " to tdata2 it contains 0x%" PRIx64, tdata2, tdata2_rb); + + if (unsupported_napot_range) + LOG_TARGET_DEBUG(target, + "The requested NAPOT match range (tdata2=0x%" PRIx64 ") exceeds maskmax_value=0x%" PRIx64, + tdata2, maskmax_value); + if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -699,7 +757,7 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ tdata2 = trigger->address; - ret = set_trigger(target, idx, tdata1, tdata2, 0); + ret = set_trigger(target, idx, tdata1, tdata2); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = trigger->unique_id; @@ -709,13 +767,11 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) struct trigger_request_info { riscv_reg_t tdata1; riscv_reg_t tdata2; - riscv_reg_t tdata1_ignore_mask; }; static void log_trigger_request_info(struct trigger_request_info trig_info) { - LOG_DEBUG("tdata1=%" PRIx64 ", tdata2=%" PRIx64 ", tdata1_ignore_mask=%" PRIx64, - trig_info.tdata1, trig_info.tdata2, trig_info.tdata1_ignore_mask); + LOG_DEBUG("tdata1=%" PRIx64 ", tdata2=%" PRIx64, trig_info.tdata1, trig_info.tdata2); }; static struct tdata1_cache *tdata1_cache_alloc(struct list_head *tdata1_cache_head, riscv_reg_t tdata1) @@ -798,12 +854,12 @@ static bool wp_triggers_cache_search(struct target *target, unsigned int idx, } static int try_use_trigger_and_cache_result(struct target *target, unsigned int idx, riscv_reg_t tdata1, - riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask) + riscv_reg_t tdata2) { if (wp_triggers_cache_search(target, idx, tdata1, tdata2)) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - int ret = set_trigger(target, idx, tdata1, tdata2, tdata1_ignore_mask); + int ret = set_trigger(target, idx, tdata1, tdata2); /* Add these values to the cache to remember that they are not supported. */ if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -826,8 +882,7 @@ static int try_setup_single_match_trigger(struct target *target, for (unsigned int idx = 0; find_next_free_trigger(target, trigger_type, false, &idx) == ERROR_OK; ++idx) { - ret = try_use_trigger_and_cache_result(target, idx, trig_info.tdata1, trig_info.tdata2, - trig_info.tdata1_ignore_mask); + ret = try_use_trigger_and_cache_result(target, idx, trig_info.tdata1, trig_info.tdata2); if (ret == ERROR_OK) { r->trigger_unique_id[idx] = trigger->unique_id; @@ -855,16 +910,14 @@ static int try_setup_chained_match_triggers(struct target *target, for (unsigned int idx = 0; find_next_free_trigger(target, trigger_type, true, &idx) == ERROR_OK; ++idx) { - ret = try_use_trigger_and_cache_result(target, idx, t1.tdata1, t1.tdata2, - t1.tdata1_ignore_mask); + ret = try_use_trigger_and_cache_result(target, idx, t1.tdata1, t1.tdata2); if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) continue; else if (ret != ERROR_OK) return ret; - ret = try_use_trigger_and_cache_result(target, idx + 1, t2.tdata1, t2.tdata2, - t2.tdata1_ignore_mask); + ret = try_use_trigger_and_cache_result(target, idx + 1, t2.tdata1, t2.tdata2); if (ret == ERROR_OK) { r->trigger_unique_id[idx] = trigger->unique_id; @@ -872,7 +925,7 @@ static int try_setup_chained_match_triggers(struct target *target, return ERROR_OK; } /* Undo the setting of the previous trigger */ - int ret_undo = set_trigger(target, idx, 0, 0, 0); + int ret_undo = set_trigger(target, idx, 0, 0); if (ret_undo != ERROR_OK) return ret_undo; @@ -900,7 +953,6 @@ struct match_triggers_tdata1_fields { riscv_reg_t ge; riscv_reg_t eq; } match; - riscv_reg_t tdata1_ignore_mask; }; static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2(struct target *target, @@ -933,8 +985,7 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2( .lt = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_LT), .ge = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE), .eq = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL) - }, - .tdata1_ignore_mask = CSR_MCONTROL_MASKMAX(riscv_xlen(target)) + } }; return result; } @@ -971,8 +1022,7 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t6( .lt = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_LT), .ge = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE), .eq = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL) - }, - .tdata1_ignore_mask = 0 + } }; return result; } @@ -991,8 +1041,7 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info napot = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.napot, - .tdata2 = trigger->address | ((trigger->length - 1) >> 1), - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address | ((trigger->length - 1) >> 1) }; ret = try_setup_single_match_trigger(target, trigger, napot); if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -1008,14 +1057,12 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info ge_1 = { .tdata1 = fields.common | fields.size.any | fields.chain.enable | fields.match.ge, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; struct trigger_request_info lt_2 = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.lt, - .tdata2 = trigger->address + trigger->length, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address + trigger->length }; ret = try_setup_chained_match_triggers(target, trigger, ge_1, lt_2); if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -1025,14 +1072,12 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info lt_1 = { .tdata1 = fields.common | fields.size.any | fields.chain.enable | fields.match.lt, - .tdata2 = trigger->address + trigger->length, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address + trigger->length }; struct trigger_request_info ge_2 = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.ge, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; ret = try_setup_chained_match_triggers(target, trigger, lt_1, ge_2); if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -1048,8 +1093,7 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info eq = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.eq, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; ret = try_setup_single_match_trigger(target, trigger, eq); if (ret != ERROR_OK) @@ -1086,8 +1130,7 @@ static int maybe_add_trigger_t2_t6_for_bp(struct target *target, struct trigger_request_info eq = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.eq, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; return try_setup_single_match_trigger(target, trigger, eq); @@ -1130,7 +1173,7 @@ static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu, ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ICOUNT, false, &idx); if (ret != ERROR_OK) return ret; - ret = set_trigger(target, idx, tdata1, 0, 0); + ret = set_trigger(target, idx, tdata1, 0); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = unique_id; @@ -1163,7 +1206,7 @@ static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu, ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx); if (ret != ERROR_OK) return ret; - ret = set_trigger(target, idx, tdata1, tdata2, 0); + ret = set_trigger(target, idx, tdata1, tdata2); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = unique_id; @@ -1195,7 +1238,7 @@ static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu, ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx); if (ret != ERROR_OK) return ret; - ret = set_trigger(target, idx, tdata1, tdata2, 0); + ret = set_trigger(target, idx, tdata1, tdata2); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = unique_id; @@ -2448,87 +2491,48 @@ static int riscv_deassert_reset(struct target *target) return tt->deassert_reset(target); } -/* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */ -static int disable_triggers(struct target *target, riscv_reg_t *state) +/* "wp_is_set" array must have at least "r->trigger_count" items. */ +static int disable_watchpoints(struct target *target, bool *wp_is_set) { RISCV_INFO(r); - LOG_TARGET_DEBUG(target, "Disabling triggers."); - if (riscv_enumerate_triggers(target) != ERROR_OK) - return ERROR_FAIL; - - if (r->manual_hwbp_set) { - /* Look at every trigger that may have been set. */ - riscv_reg_t tselect; - if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) - return ERROR_FAIL; - for (unsigned int t = 0; t < r->trigger_count; t++) { - if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK) - return ERROR_FAIL; - riscv_reg_t tdata1; - if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + /* TODO: The algorithm is flawed and may result in a situation described in + * https://github.com/riscv-collab/riscv-openocd/issues/1108 + */ + memset(wp_is_set, false, r->trigger_count); + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_TARGET_DEBUG(target, "Watchpoint %" PRIu32 ": set=%s", + watchpoint->unique_id, + wp_is_set[i] ? "true" : "false"); + wp_is_set[i] = watchpoint->is_set; + if (watchpoint->is_set) { + if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) return ERROR_FAIL; - if (tdata1 & CSR_TDATA1_DMODE(riscv_xlen(target))) { - state[t] = tdata1; - if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) - return ERROR_FAIL; - } - } - if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) - return ERROR_FAIL; - - } else { - /* Just go through the triggers we manage. */ - struct watchpoint *watchpoint = target->watchpoints; - int i = 0; - while (watchpoint) { - LOG_TARGET_DEBUG(target, "Watchpoint %d: set=%d", i, watchpoint->is_set); - state[i] = watchpoint->is_set; - if (watchpoint->is_set) { - if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) - return ERROR_FAIL; - } - watchpoint = watchpoint->next; - i++; } + watchpoint = watchpoint->next; + i++; } return ERROR_OK; } -static int enable_triggers(struct target *target, riscv_reg_t *state) +static int enable_watchpoints(struct target *target, bool *wp_is_set) { - RISCV_INFO(r); - - if (r->manual_hwbp_set) { - /* Look at every trigger that may have been set. */ - riscv_reg_t tselect; - if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) - return ERROR_FAIL; - for (unsigned int t = 0; t < r->trigger_count; t++) { - if (state[t] != 0) { - if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK) - return ERROR_FAIL; - if (riscv_reg_set(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK) - return ERROR_FAIL; - } - } - if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) - return ERROR_FAIL; - - } else { - struct watchpoint *watchpoint = target->watchpoints; - int i = 0; - while (watchpoint) { - LOG_TARGET_DEBUG(target, "Watchpoint %d: cleared=%" PRId64, i, state[i]); - if (state[i]) { - if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK) - return ERROR_FAIL; - } - watchpoint = watchpoint->next; - i++; + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_TARGET_DEBUG(target, "Watchpoint %" PRIu32 + ": %s to be re-enabled.", watchpoint->unique_id, + wp_is_set[i] ? "needs " : "does not need"); + if (wp_is_set[i]) { + if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK) + return ERROR_FAIL; } + watchpoint = watchpoint->next; + i++; } return ERROR_OK; @@ -3294,7 +3298,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, GDB_REGNO_PC, GDB_REGNO_MSTATUS, GDB_REGNO_MEPC, GDB_REGNO_MCAUSE, }; - for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(regnums); i++) { enum gdb_regno regno = regnums[i]; riscv_reg_t reg_value; if (riscv_reg_get(target, ®_value, regno) != ERROR_OK) @@ -3389,8 +3393,8 @@ static int riscv_checksum_memory(struct target *target, static const uint8_t *crc_code; - unsigned xlen = riscv_xlen(target); - unsigned crc_code_size; + unsigned int xlen = riscv_xlen(target); + unsigned int crc_code_size; if (xlen == 32) { crc_code = riscv32_crc_code; crc_code_size = sizeof(riscv32_crc_code); @@ -3776,10 +3780,17 @@ static int riscv_openocd_step_impl(struct target *target, int current, return ERROR_FAIL; } - riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; - if (disable_triggers(target, trigger_state) != ERROR_OK) + if (riscv_enumerate_triggers(target) != ERROR_OK) return ERROR_FAIL; + RISCV_INFO(r); + bool *wps_to_enable = calloc(r->trigger_count, sizeof(*wps_to_enable)); + if (disable_watchpoints(target, wps_to_enable) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to temporarily disable " + "watchpoints before single-step."); + return ERROR_FAIL; + } + bool success = true; uint64_t current_mstatus; RISCV_INFO(info); @@ -3809,9 +3820,10 @@ static int riscv_openocd_step_impl(struct target *target, int current, } _exit: - if (enable_triggers(target, trigger_state) != ERROR_OK) { + if (enable_watchpoints(target, wps_to_enable) != ERROR_OK) { success = false; - LOG_TARGET_ERROR(target, "Unable to enable triggers."); + LOG_TARGET_ERROR(target, "Failed to re-enable watchpoints " + "after single-step."); } if (breakpoint && (riscv_add_breakpoint(target, breakpoint) != ERROR_OK)) { @@ -3853,13 +3865,14 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) return ERROR_FAIL; } - riscv_command_timeout_sec = timeout; + riscv_command_timeout_sec_value = timeout; return ERROR_OK; } COMMAND_HANDLER(riscv_set_reset_timeout_sec) { + LOG_WARNING("The command 'riscv set_reset_timeout_sec' is deprecated! Please, use 'riscv set_command_timeout_sec'."); if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter."); return ERROR_COMMAND_SYNTAX_ERROR; @@ -3882,9 +3895,10 @@ COMMAND_HANDLER(riscv_set_mem_access) int sysbus_cnt = 0; int abstract_cnt = 0; - if (CMD_ARGC < 1 || CMD_ARGC > RISCV_NUM_MEM_ACCESS_METHODS) { - LOG_ERROR("Command takes 1 to %d parameters", RISCV_NUM_MEM_ACCESS_METHODS); - return ERROR_COMMAND_SYNTAX_ERROR; + if (CMD_ARGC < 1 || CMD_ARGC > RISCV_MEM_ACCESS_MAX_METHODS_NUM) { + command_print(CMD, "Command takes 1 to %d parameters", + RISCV_MEM_ACCESS_MAX_METHODS_NUM); + return ERROR_COMMAND_ARGUMENT_INVALID; } /* Check argument validity */ @@ -3907,8 +3921,7 @@ COMMAND_HANDLER(riscv_set_mem_access) } /* Args are valid, store them */ - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) - r->mem_access_methods[i] = RISCV_MEM_ACCESS_UNSPECIFIED; + r->num_enabled_mem_access_methods = CMD_ARGC; for (unsigned int i = 0; i < CMD_ARGC; i++) { if (strcmp("progbuf", CMD_ARGV[i]) == 0) r->mem_access_methods[i] = RISCV_MEM_ACCESS_PROGBUF; @@ -3919,9 +3932,8 @@ COMMAND_HANDLER(riscv_set_mem_access) } /* Reset warning flags */ - r->mem_access_progbuf_warn = true; - r->mem_access_sysbus_warn = true; - r->mem_access_abstract_warn = true; + for (size_t i = 0; i < RISCV_MEM_ACCESS_MAX_METHODS_NUM; ++i) + r->mem_access_warn[i] = true; return ERROR_OK; } @@ -3945,8 +3957,8 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha /* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */ char *arg = strtok(args, ","); while (arg) { - unsigned low = 0; - unsigned high = 0; + unsigned int low = 0; + unsigned int high = 0; char *name = NULL; char *dash = strchr(arg, '-'); @@ -4376,18 +4388,23 @@ COMMAND_HANDLER(riscv_resume_order) COMMAND_HANDLER(riscv_use_bscan_tunnel) { - int irwidth = 0; + uint8_t irwidth = 0; int tunnel_type = BSCAN_TUNNEL_NESTED_TAP; - if (CMD_ARGC > 2) { - LOG_ERROR("Command takes at most two arguments"); + if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; - } else if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); - } else if (CMD_ARGC == 2) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type); + + if (CMD_ARGC >= 1) { + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], irwidth); + assert(BSCAN_TUNNEL_IR_WIDTH_NBITS < 8); + if (irwidth >= (uint8_t)1 << BSCAN_TUNNEL_IR_WIDTH_NBITS) { + command_print(CMD, "'value' does not fit into %d bits.", + BSCAN_TUNNEL_IR_WIDTH_NBITS); + return ERROR_COMMAND_ARGUMENT_OVERFLOW; + } } + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type); if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP) LOG_INFO("Nested Tap based Bscan Tunnel Selected"); else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) @@ -5025,6 +5042,57 @@ COMMAND_HANDLER(riscv_set_enable_trigger_feature) return ERROR_OK; } +static COMMAND_HELPER(report_reserved_triggers, struct target *target) +{ + RISCV_INFO(r); + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + const char *separator = ""; + for (riscv_reg_t t = 0; t < r->trigger_count; ++t) { + if (r->reserved_triggers[t]) { + command_print_sameline(CMD, "%s%" PRIu64, separator, t); + separator = " "; + } + } + command_print_sameline(CMD, "\n"); + return ERROR_OK; +} + +COMMAND_HANDLER(handle_reserve_trigger) +{ + struct target *target = get_current_target(CMD_CTX); + if (CMD_ARGC == 0) + return CALL_COMMAND_HANDLER(report_reserved_triggers, target); + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + riscv_reg_t t; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], t); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + RISCV_INFO(r); + if (r->trigger_count == 0) { + command_print(CMD, "Error: There are no triggers on the target."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + if (t >= r->trigger_count) { + command_print(CMD, "Error: trigger with index %" PRIu64 + " does not exist. There are only %u triggers" + " on the target (with indexes 0 .. %u).", + t, r->trigger_count, r->trigger_count - 1); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + if (r->trigger_unique_id[t] != -1) { + command_print(CMD, "Error: trigger with index %" PRIu64 + " is already in use and can not be reserved.", t); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[1], r->reserved_triggers[t]); + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -5066,7 +5134,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .handler = riscv_set_reset_timeout_sec, .mode = COMMAND_ANY, .usage = "[sec]", - .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" + .help = "DEPRECATED. Use 'riscv set_command_timeout_sec' instead." }, { .name = "set_mem_access", @@ -5189,18 +5257,14 @@ static const struct command_registration riscv_exec_command_handlers[] = { { .name = "use_bscan_tunnel", .handler = riscv_use_bscan_tunnel, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .usage = "value [type]", - .help = "Enable or disable use of a BSCAN tunnel to reach DM. Supply " - "the width of the DM transport TAP's instruction register to " - "enable. Supply a value of 0 to disable. Pass A second argument " - "(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , " - "1: DATA_REGISTER}" + .help = "Enable or disable use of a BSCAN tunnel to reach DM." }, { .name = "set_bscan_tunnel_ir", .handler = riscv_set_bscan_tunnel_ir, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .usage = "value", .help = "Specify the JTAG TAP IR used to access the bscan tunnel. " "By default it is 0x23 << (ir_length - 6), which map some " @@ -5281,6 +5345,14 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "[('eq'|'napot'|'ge_lt'|'all') ('wp'|'none')]", .help = "Control whether OpenOCD is allowed to use certain RISC-V trigger features for watchpoints." }, + { + .name = "reserve_trigger", + .handler = handle_reserve_trigger, + /* TODO: Move this to COMMAND_ANY */ + .mode = COMMAND_EXEC, + .usage = "[index ('on'|'off')]", + .help = "Controls which RISC-V triggers shall not be touched by OpenOCD.", + }, COMMAND_REGISTRATION_DONE }; @@ -5403,9 +5475,9 @@ static void riscv_info_init(struct target *target, struct riscv_info *r) r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS; r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; - r->mem_access_progbuf_warn = true; - r->mem_access_sysbus_warn = true; - r->mem_access_abstract_warn = true; + r->num_enabled_mem_access_methods = RISCV_MEM_ACCESS_MAX_METHODS_NUM; + for (size_t i = 0; i < RISCV_MEM_ACCESS_MAX_METHODS_NUM; ++i) + r->mem_access_warn[i] = true; INIT_LIST_HEAD(&r->expose_csr); INIT_LIST_HEAD(&r->expose_custom); @@ -5506,7 +5578,7 @@ static int riscv_step_rtos_hart(struct target *target) bool riscv_supports_extension(const struct target *target, char letter) { RISCV_INFO(r); - unsigned num; + unsigned int num; if (letter >= 'a' && letter <= 'z') num = letter - 'a'; else if (letter >= 'A' && letter <= 'Z') @@ -5516,7 +5588,7 @@ bool riscv_supports_extension(const struct target *target, char letter) return r->misa & BIT(num); } -unsigned riscv_xlen(const struct target *target) +unsigned int riscv_xlen(const struct target *target) { RISCV_INFO(r); return r->xlen; @@ -5559,7 +5631,7 @@ static enum riscv_halt_reason riscv_halt_reason(struct target *target) size_t riscv_progbuf_size(struct target *target) { RISCV_INFO(r); - return r->progbuf_size; + return r->get_progbufsize(target); } int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn) @@ -5581,16 +5653,16 @@ int riscv_execute_progbuf(struct target *target, uint32_t *cmderr) return r->execute_progbuf(target, cmderr); } -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) +void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d) { RISCV_INFO(r); - r->fill_dm_write(target, buf, a, d); + r->fill_dmi_write(target, buf, a, d); } -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a) +void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a) { RISCV_INFO(r); - r->fill_dm_read(target, buf, a); + r->fill_dmi_read(target, buf, a); } void riscv_fill_dm_nop(struct target *target, char *buf) @@ -5705,6 +5777,8 @@ int riscv_enumerate_triggers(struct target *target) "Assuming that triggers are not implemented."); r->triggers_enumerated = true; r->trigger_count = 0; + free(r->reserved_triggers); + r->reserved_triggers = NULL; return ERROR_OK; } @@ -5739,6 +5813,8 @@ int riscv_enumerate_triggers(struct target *target) r->triggers_enumerated = true; r->trigger_count = t; LOG_TARGET_INFO(target, "Found %d triggers", r->trigger_count); + free(r->reserved_triggers); + r->reserved_triggers = calloc(t, sizeof(*r->reserved_triggers)); create_wp_trigger_cache(target); return ERROR_OK; } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index c13af8e..33afdcd 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -22,8 +22,7 @@ struct riscv_program; #define RISCV_MAX_HWBPS 16 #define RISCV_MAX_DMS 100 -#define DEFAULT_COMMAND_TIMEOUT_SEC 2 -#define DEFAULT_RESET_TIMEOUT_SEC 30 +#define DEFAULT_COMMAND_TIMEOUT_SEC 5 #define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE) #define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN) @@ -33,8 +32,6 @@ struct riscv_program; #define PG_MAX_LEVEL 5 -#define RISCV_NUM_MEM_ACCESS_METHODS 3 - #define RISCV_BATCH_ALLOC_SIZE 128 extern struct target_type riscv011_target; @@ -53,12 +50,12 @@ typedef enum { YNM_NO } yes_no_maybe_t; -enum riscv_mem_access_method { - RISCV_MEM_ACCESS_UNSPECIFIED, +typedef enum riscv_mem_access_method { RISCV_MEM_ACCESS_PROGBUF, RISCV_MEM_ACCESS_SYSBUS, - RISCV_MEM_ACCESS_ABSTRACT -}; + RISCV_MEM_ACCESS_ABSTRACT, + RISCV_MEM_ACCESS_MAX_METHODS_NUM +} riscv_mem_access_method_t; enum riscv_halt_reason { RISCV_HALT_INTERRUPT, @@ -168,12 +165,6 @@ struct riscv_info { * most recent halt was not caused by a trigger, then this is -1. */ int64_t trigger_hit; - /* The number of entries in the program buffer. */ - int progbuf_size; - - /* This hart contains an implicit ebreak at the end of the program buffer. */ - bool impebreak; - bool triggers_enumerated; /* Decremented every scan, and when it reaches 0 we clear the learned @@ -227,8 +218,8 @@ struct riscv_info { int (*execute_progbuf)(struct target *target, uint32_t *cmderr); int (*invalidate_cached_progbuf)(struct target *target); int (*get_dmi_scan_length)(struct target *target); - void (*fill_dm_write)(struct target *target, char *buf, uint64_t a, uint32_t d); - void (*fill_dm_read)(struct target *target, char *buf, uint64_t a); + void (*fill_dmi_write)(struct target *target, char *buf, uint64_t a, uint32_t d); + void (*fill_dmi_read)(struct target *target, char *buf, uint64_t a); void (*fill_dm_nop)(struct target *target, char *buf); int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index); @@ -237,6 +228,9 @@ struct riscv_info { int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); + bool (*get_impebreak)(const struct target *target); + unsigned int (*get_progbufsize)(const struct target *target); + /* Get the DMI address of target's DM's register. * The function should return the passed address * if the target is not assigned a DM yet. @@ -251,7 +245,7 @@ struct riscv_info { int (*read_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); - unsigned (*data_bits)(struct target *target); + unsigned int (*data_bits)(struct target *target); COMMAND_HELPER((*print_info), struct target *target); @@ -273,18 +267,16 @@ struct riscv_info { struct reg_data_type_union vector_union; struct reg_data_type type_vector; - /* Set when trigger registers are changed by the user. This indicates we need - * to beware that we may hit a trigger that we didn't realize had been set. */ - bool manual_hwbp_set; + bool *reserved_triggers; /* Memory access methods to use, ordered by priority, highest to lowest. */ - int mem_access_methods[RISCV_NUM_MEM_ACCESS_METHODS]; + riscv_mem_access_method_t mem_access_methods[RISCV_MEM_ACCESS_MAX_METHODS_NUM]; + + unsigned int num_enabled_mem_access_methods; /* Different memory regions may need different methods but single configuration is applied * for all. Following flags are used to warn only once about failing memory access method. */ - bool mem_access_progbuf_warn; - bool mem_access_sysbus_warn; - bool mem_access_abstract_warn; + bool mem_access_warn[RISCV_MEM_ACCESS_MAX_METHODS_NUM]; /* In addition to the ones in the standard spec, we'll also expose additional * CSRs in this list. */ @@ -328,22 +320,19 @@ typedef struct { typedef struct { const char *name; int level; - unsigned va_bits; + unsigned int va_bits; /* log2(PTESIZE) */ - unsigned pte_shift; - unsigned vpn_shift[PG_MAX_LEVEL]; - unsigned vpn_mask[PG_MAX_LEVEL]; - unsigned pte_ppn_shift[PG_MAX_LEVEL]; - unsigned pte_ppn_mask[PG_MAX_LEVEL]; - unsigned pa_ppn_shift[PG_MAX_LEVEL]; - unsigned pa_ppn_mask[PG_MAX_LEVEL]; + unsigned int pte_shift; + unsigned int vpn_shift[PG_MAX_LEVEL]; + unsigned int vpn_mask[PG_MAX_LEVEL]; + unsigned int pte_ppn_shift[PG_MAX_LEVEL]; + unsigned int pte_ppn_mask[PG_MAX_LEVEL]; + unsigned int pa_ppn_shift[PG_MAX_LEVEL]; + unsigned int pa_ppn_mask[PG_MAX_LEVEL]; } virt2phys_info_t; /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ -extern int riscv_command_timeout_sec; - -/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ -extern int riscv_reset_timeout_sec; +int riscv_get_command_timeout_sec(void); extern bool riscv_enable_virtual; @@ -366,12 +355,13 @@ extern struct scan_field select_dtmcontrol; extern struct scan_field select_dbus; extern struct scan_field select_idcode; +int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr); + extern struct scan_field *bscan_tunneled_select_dmi; extern uint32_t bscan_tunneled_select_dmi_num_fields; typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t; -extern int bscan_tunnel_ir_width; +extern uint8_t bscan_tunnel_ir_width; -int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr); void select_dmi_via_bscan(struct target *target); /*** OpenOCD Interface */ @@ -391,7 +381,7 @@ int riscv_openocd_step( bool riscv_supports_extension(const struct target *target, char letter); /* Returns XLEN for the given (or current) hart. */ -unsigned riscv_xlen(const struct target *target); +unsigned int riscv_xlen(const struct target *target); /* Returns VLENB for the given (or current) hart. */ unsigned int riscv_vlenb(const struct target *target); @@ -412,8 +402,8 @@ int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn); int riscv_execute_progbuf(struct target *target, uint32_t *cmderr); void riscv_fill_dm_nop(struct target *target, char *buf); -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a); +void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); +void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a); int riscv_get_dmi_scan_length(struct target *target); uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address); diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c index f8e5dfe..4f386f4 100644 --- a/src/target/riscv/riscv_reg.c +++ b/src/target/riscv/riscv_reg.c @@ -376,8 +376,19 @@ static bool is_known_standard_csr(unsigned int csr_num) return is_csr_in_buf[csr_num]; } -static bool gdb_regno_exist(const struct target *target, uint32_t regno) -{ +bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) +{ + switch (regno) { + case GDB_REGNO_VLENB: + case GDB_REGNO_MTOPI: + case GDB_REGNO_MTOPEI: + assert(false + && "Existence of other registers is determined " + "depending on existence of these ones, so " + "whether these register exist or not should be " + "set explicitly."); + }; + if (regno <= GDB_REGNO_XPR15 || regno == GDB_REGNO_PC || regno == GDB_REGNO_PRIV) @@ -397,6 +408,13 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_FRM: case CSR_FCSR: return riscv_supports_extension(target, 'F'); + case CSR_VSTART: + case CSR_VXSAT: + case CSR_VXRM: + case CSR_VL: + case CSR_VCSR: + case CSR_VTYPE: + return vlenb_exists(target); case CSR_SCOUNTEREN: case CSR_SSTATUS: case CSR_STVEC: @@ -591,14 +609,15 @@ static int resize_reg(const struct target *target, uint32_t regno, bool exist, return ERROR_OK; } -static int set_reg_exist(const struct target *target, uint32_t regno, bool exist) +int riscv_reg_impl_set_exist(const struct target *target, uint32_t regno, bool exist) { const struct reg *reg = riscv_reg_impl_cache_entry(target, regno); assert(riscv_reg_impl_is_initialized(reg)); return resize_reg(target, regno, exist, reg->size); } -int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct reg_arch_type *reg_type) +int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno, + bool exist, const struct reg_arch_type *reg_type) { struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); if (riscv_reg_impl_is_initialized(reg)) @@ -626,8 +645,7 @@ int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct reg_arch_info->target = target; reg_arch_info->custom_number = gdb_regno_custom_number(target, regno); } - return resize_reg(target, regno, gdb_regno_exist(target, regno), - gdb_regno_size(target, regno)); + return resize_reg(target, regno, exist, gdb_regno_size(target, regno)); } static int init_custom_register_names(struct list_head *expose_custom, @@ -717,7 +735,7 @@ int riscv_reg_impl_expose_csrs(const struct target *target) csr_number); continue; } - if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK) + if (riscv_reg_impl_set_exist(target, regno, /*exist*/ true) != ERROR_OK) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", csr_number, reg->name); @@ -738,7 +756,7 @@ void riscv_reg_impl_hide_csrs(const struct target *target) struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); const unsigned int csr_number = regno - GDB_REGNO_CSR0; if (!reg->exist) { - LOG_TARGET_WARNING(target, + LOG_TARGET_DEBUG(target, "Not hiding CSR %d: register does not exist.", csr_number); continue; @@ -826,15 +844,8 @@ static int riscv_set_or_write_register(struct target *target, return riscv_set_or_write_register(target, GDB_REGNO_DCSR, dcsr, write_through); } - if (!target->reg_cache) { - assert(!target_was_examined(target)); - LOG_TARGET_DEBUG(target, - "No cache, writing to target: %s <- 0x%" PRIx64, - riscv_reg_gdb_regno_name(target, regid), value); - return riscv013_set_register(target, regid, value); - } - struct reg *reg = riscv_reg_impl_cache_entry(target, regid); + assert(riscv_reg_impl_is_initialized(reg)); if (!reg->exist) { LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); @@ -927,21 +938,15 @@ int riscv_reg_get(struct target *target, riscv_reg_t *value, RISCV_INFO(r); assert(r); if (r->dtm_version == DTM_DTMCS_VERSION_0_11) - return riscv013_get_register(target, value, regid); + return riscv011_get_register(target, value, regid); keep_alive(); if (regid == GDB_REGNO_PC) return riscv_reg_get(target, value, GDB_REGNO_DPC); - if (!target->reg_cache) { - assert(!target_was_examined(target)); - LOG_TARGET_DEBUG(target, "No cache, reading %s from target", - riscv_reg_gdb_regno_name(target, regid)); - return riscv013_get_register(target, value, regid); - } - struct reg *reg = riscv_reg_impl_cache_entry(target, regid); + assert(riscv_reg_impl_is_initialized(reg)); if (!reg->exist) { LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); return ERROR_FAIL; diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h index 906a5b6..7a483ad 100644 --- a/src/target/riscv/riscv_reg_impl.h +++ b/src/target/riscv/riscv_reg_impl.h @@ -13,7 +13,7 @@ * This file describes the helpers to use during register cache initialization * of a RISC-V target. Each cache entry proceedes through the following stages: * - not allocated before `riscv_reg_impl_init_cache()` - * - not initialized before the call to `riscv_reg_impl_init_one()` with appropriate regno. + * - not initialized before the call to `riscv_reg_impl_init_cache_entry()` with appropriate regno. * - initialized until `riscv_reg_free_all()` is called. */ static inline bool riscv_reg_impl_is_initialized(const struct reg *reg) @@ -37,8 +37,18 @@ static inline bool riscv_reg_impl_is_initialized(const struct reg *reg) int riscv_reg_impl_init_cache(struct target *target); /** Initialize register. */ -int riscv_reg_impl_init_one(struct target *target, uint32_t regno, - const struct reg_arch_type *reg_type); +int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno, + bool exist, const struct reg_arch_type *reg_type); + +/** + * For most registers, returns whether they exist or not. + * For some registers the "exist" bit should be set explicitly. + */ +bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno); + +/** Mark register as existing or not. */ +int riscv_reg_impl_set_exist(const struct target *target, + uint32_t regno, bool exist); /** Return the entry in the register cache of the target. */ struct reg *riscv_reg_impl_cache_entry(const struct target *target, diff --git a/src/target/target.c b/src/target/target.c index fd9c34f..3f412a0 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3125,11 +3125,18 @@ COMMAND_HANDLER(handle_reg_command) /* set register value */ if (CMD_ARGC == 2) { uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); - if (!buf) + if (!buf) { + LOG_ERROR("Failed to allocate memory"); return ERROR_FAIL; - str_to_buf(CMD_ARGV[1], strlen(CMD_ARGV[1]), buf, reg->size, 0); + } + + int retval = CALL_COMMAND_HANDLER(command_parse_str_to_buf, CMD_ARGV[1], buf, reg->size); + if (retval != ERROR_OK) { + free(buf); + return retval; + } - int retval = reg->type->set(reg, buf); + retval = reg->type->set(reg, buf); if (retval != ERROR_OK) { LOG_ERROR("Could not write to register '%s'", reg->name); } else { @@ -3898,7 +3905,7 @@ static int handle_bp_command_list(struct command_invocation *cmd) while (breakpoint) { if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_hex_str(breakpoint->orig_instr, - breakpoint->length); + breakpoint->length * 8); command_print(cmd, "Software breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, orig_instr=0x%s", breakpoint->address, breakpoint->length, @@ -3927,7 +3934,7 @@ static int handle_bp_command_list(struct command_invocation *cmd) } static int handle_bp_command_set(struct command_invocation *cmd, - target_addr_t addr, uint32_t asid, uint32_t length, int hw) + target_addr_t addr, uint32_t asid, unsigned int length, int hw) { struct target *target = get_current_target(cmd->ctx); int retval; @@ -4044,7 +4051,7 @@ COMMAND_HANDLER(handle_wp_command) while (watchpoint) { char wp_type = (watchpoint->rw == WPT_READ ? 'r' : (watchpoint->rw == WPT_WRITE ? 'w' : 'a')); command_print(CMD, "address: " TARGET_ADDR_FMT - ", len: 0x%8.8" PRIx32 + ", len: 0x%8.8x" ", r/w/a: %c, value: 0x%8.8" PRIx64 ", mask: 0x%8.8" PRIx64, watchpoint->address, @@ -4186,7 +4193,7 @@ static void write_gmon(uint32_t *samples, uint32_t sample_num, const char *filen uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms) { uint32_t i; - FILE *f = fopen(filename, "w"); + FILE *f = fopen(filename, "wb"); if (!f) return; write_string(f, "gmon"); @@ -4772,63 +4779,63 @@ static int target_jim_get_reg(Jim_Interp *interp, int argc, return JIM_OK; } -static int target_jim_set_reg(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(handle_set_reg_command) { - if (argc != 2) { - Jim_WrongNumArgs(interp, 1, argv, "dict"); - return JIM_ERR; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; int tmp; #if JIM_VERSION >= 80 - Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp); + Jim_Obj **dict = Jim_DictPairs(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], &tmp); if (!dict) - return JIM_ERR; + return ERROR_FAIL; #else Jim_Obj **dict; - int ret = Jim_DictPairs(interp, argv[1], &dict, &tmp); + int ret = Jim_DictPairs(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], &dict, &tmp); if (ret != JIM_OK) - return ret; + return ERROR_FAIL; #endif const unsigned int length = tmp; - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - const struct target *target = get_current_target(cmd_ctx); + + const struct target *target = get_current_target(CMD_CTX); + assert(target); for (unsigned int i = 0; i < length; i += 2) { const char *reg_name = Jim_String(dict[i]); const char *reg_value = Jim_String(dict[i + 1]); - struct reg *reg = register_get_by_name(target->reg_cache, reg_name, - false); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); if (!reg || !reg->exist) { - Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); - return JIM_ERR; + command_print(CMD, "unknown register '%s'", reg_name); + return ERROR_FAIL; } uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); - if (!buf) { LOG_ERROR("Failed to allocate memory"); - return JIM_ERR; + return ERROR_FAIL; } - str_to_buf(reg_value, strlen(reg_value), buf, reg->size, 0); - int retval = reg->type->set(reg, buf); + int retval = CALL_COMMAND_HANDLER(command_parse_str_to_buf, reg_value, buf, reg->size); + if (retval != ERROR_OK) { + free(buf); + return retval; + } + + retval = reg->type->set(reg, buf); free(buf); if (retval != ERROR_OK) { - Jim_SetResultFormatted(interp, "failed to set '%s' to register '%s'", + command_print(CMD, "failed to set '%s' to register '%s'", reg_value, reg_name); - return JIM_ERR; + return retval; } } - return JIM_OK; + return ERROR_OK; } /** @@ -5568,7 +5575,7 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "set_reg", .mode = COMMAND_EXEC, - .jim_handler = target_jim_set_reg, + .handler = handle_set_reg_command, .help = "Set target register values", .usage = "dict", }, @@ -5789,7 +5796,7 @@ static int target_create(struct jim_getopt_info *goi) } target->dbgmsg = NULL; - target->dbg_msg_enabled = 0; + target->dbg_msg_enabled = false; target->endianness = TARGET_ENDIAN_UNKNOWN; @@ -6703,7 +6710,7 @@ static const struct command_registration target_exec_command_handlers[] = { { .name = "set_reg", .mode = COMMAND_EXEC, - .jim_handler = target_jim_set_reg, + .handler = handle_set_reg_command, .help = "Set target register values", .usage = "dict", }, diff --git a/src/target/target.h b/src/target/target.h index c74b8c2..9ff2f78 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -163,7 +163,7 @@ struct target { struct watchpoint *watchpoints; /* list of watchpoints */ struct trace *trace_info; /* generic trace information */ struct debug_msg_receiver *dbgmsg; /* list of debug message receivers */ - uint32_t dbg_msg_enabled; /* debug message status */ + bool dbg_msg_enabled; /* debug message status */ void *arch_info; /* architecture specific information */ void *private_config; /* pointer to target specific config data (for jim_configure hook) */ struct target *next; /* next target in list */ @@ -805,6 +805,7 @@ int target_profiling_default(struct target *target, uint32_t *samples, uint32_t #define ERROR_TARGET_ALGO_EXIT (-313) #define ERROR_TARGET_SIZE_NOT_SUPPORTED (-314) #define ERROR_TARGET_PACKING_NOT_SUPPORTED (-315) +#define ERROR_TARGET_HALTED_DO_RESUME (-316) /* used to workaround incorrect debug halt */ extern bool get_target_reset_nag(void); diff --git a/src/target/target_request.c b/src/target/target_request.c index 72c8421..bccae07 100644 --- a/src/target/target_request.c +++ b/src/target/target_request.c @@ -164,7 +164,7 @@ static int add_debug_msg_receiver(struct command_context *cmd_ctx, struct target (*p)->next = NULL; /* enable callback */ - target->dbg_msg_enabled = 1; + target->dbg_msg_enabled = true; return ERROR_OK; } @@ -225,7 +225,7 @@ int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *ta free(c); if (!*p) { /* disable callback */ - target->dbg_msg_enabled = 0; + target->dbg_msg_enabled = false; } return ERROR_OK; } else diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index 702b8fc..8369cc4 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -540,7 +540,7 @@ static void xtensa_queue_exec_ins_wide(struct xtensa *xtensa, uint8_t *ops, uint for (int32_t i = oplenw - 1; i > 0; i--) xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0 + i, - target_buffer_get_u32(xtensa->target, &ops_padded[sizeof(uint32_t)*i])); + target_buffer_get_u32(xtensa->target, &ops_padded[sizeof(uint32_t) * i])); /* Write DIR0EXEC last */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0EXEC, @@ -3966,10 +3966,10 @@ COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa) rptr->type = XT_REG_OTHER; } - /* Register flags */ + /* Register flags: includes intsetN, intclearN for LX8 */ if ((strcmp(rptr->name, "mmid") == 0) || (strcmp(rptr->name, "eraccess") == 0) || - (strcmp(rptr->name, "ddr") == 0) || (strcmp(rptr->name, "intset") == 0) || - (strcmp(rptr->name, "intclear") == 0)) + (strcmp(rptr->name, "ddr") == 0) || (strncmp(rptr->name, "intset", 6) == 0) || + (strncmp(rptr->name, "intclear", 8) == 0) || (strcmp(rptr->name, "mesrclr") == 0)) rptr->flags = XT_REGF_NOREAD; else rptr->flags = 0; diff --git a/src/target/xtensa/xtensa_chip.c b/src/target/xtensa/xtensa_chip.c index ac4a49c..ce6d35c 100644 --- a/src/target/xtensa/xtensa_chip.c +++ b/src/target/xtensa/xtensa_chip.c @@ -103,7 +103,7 @@ static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp) LOG_DEBUG("DAP: ap_num %" PRId64 " DAP %p\n", pc->ap_num, pc->dap); } else { xtensa_chip_dm_cfg.tap = target->tap; - LOG_DEBUG("JTAG: %s:%s pos %d", target->tap->chip, target->tap->tapname, + LOG_DEBUG("JTAG: %s:%s pos %u", target->tap->chip, target->tap->tapname, target->tap->abs_chain_position); } diff --git a/src/target/xtensa/xtensa_debug_module.h b/src/target/xtensa/xtensa_debug_module.h index 495da2a..8391a96 100644 --- a/src/target/xtensa/xtensa_debug_module.h +++ b/src/target/xtensa/xtensa_debug_module.h @@ -75,6 +75,7 @@ enum xtensa_dm_reg { XDMREG_DELAYCNT, XDMREG_MEMADDRSTART, XDMREG_MEMADDREND, + XDMREG_DEBUGPC,/*Unsupported, undocumented, may not be present*/ XDMREG_EXTTIMELO, XDMREG_EXTTIMEHI, XDMREG_TRAXRSVD48, @@ -184,6 +185,7 @@ struct xtensa_dm_reg_offsets { { .nar = 0x07, .apb = 0x001c }, /* XDMREG_DELAYCNT */ \ { .nar = 0x08, .apb = 0x0020 }, /* XDMREG_MEMADDRSTART */ \ { .nar = 0x09, .apb = 0x0024 }, /* XDMREG_MEMADDREND */ \ + { .nar = 0x0f, .apb = 0x003c }, /* XDMREG_DEBUGPC */ \ { .nar = 0x10, .apb = 0x0040 }, /* XDMREG_EXTTIMELO */ \ { .nar = 0x11, .apb = 0x0044 }, /* XDMREG_EXTTIMEHI */ \ { .nar = 0x12, .apb = 0x0048 }, /* XDMREG_TRAXRSVD48 */ \ diff --git a/src/transport/transport.c b/src/transport/transport.c index 81d3d58..bf306e7 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -278,7 +278,6 @@ COMMAND_HANDLER(handle_transport_select) if (session) { if (!strcmp(session->name, CMD_ARGV[0])) { LOG_WARNING("Transport \"%s\" was already selected", session->name); - command_print(CMD, "%s", session->name); return ERROR_OK; } command_print(CMD, "Can't change session's transport after the initial selection was made"); @@ -301,7 +300,6 @@ COMMAND_HANDLER(handle_transport_select) int retval = transport_select(CMD_CTX, CMD_ARGV[0]); if (retval != ERROR_OK) return retval; - command_print(CMD, "%s", session->name); return ERROR_OK; } } |