diff options
82 files changed, 3408 insertions, 2603 deletions
diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml index 00d1d71..11f4271 100644 --- a/.github/workflows/checkpatch.yml +++ b/.github/workflows/checkpatch.yml @@ -23,10 +23,4 @@ jobs: sudo apt-get install patchutils python3-ply python3-git - name: Run checkpatch run: | - git diff --patch FETCH_HEAD \ - | filterdiff \ - -x "a/src/jtag/drivers/libjaylink/*" \ - -x "a/tools/git2cl/*" \ - -x "a/.github/*" \ - -x "a/HACKING" \ - | ./tools/scripts/checkpatch.pl --no-signoff - + ./tools/scripts/checkpatch.pl --no-signoff --git FETCH_HEAD..HEAD diff --git a/contrib/coresight-trace.txt b/contrib/coresight-trace.txt deleted file mode 100644 index 517119b..0000000 --- a/contrib/coresight-trace.txt +++ /dev/null @@ -1,68 +0,0 @@ -+OpenOCD and CoreSight Tracing -+ -Many recent ARM chips (Using e..g. Cortex-M3 and -Cortex-M4 cores) support CoreSight debug/trace. -This note sketches an approach currently planned for those cores -with OpenOCD. - - This tracing data can help debug and tune ARM software, but not -all cores support tracing. Some support more extensive tracing -other cores with trace support +should be able to use the same -approach and maybe some of the same analysis code. - -+the Cortex-M3 is assumed here to be the -+core in use, for simplicity and to reflect current OpenOCD users. - - -This note summarizes a software model to generate, collect, and -analyze such trace data . That is not fully implemented as of early -January 2011, +and thus is not *yet* usable. -+ -+ -+Some microcontroller cores support a low pin-count Single-wire trace, -with a mode where +trace data is emitted (usually to a UART. To use -this mode, +SWD must be in use. -+At this writing, OpenOCD SWD support is not yet complete either. - -(There are also multi-wire trace ports requiring more complex debug -adapters than OpenOCD currently supports, and offering richer data. -+ -+ -+* ENABLING involves activating SWD and (single wire) trace. -+ -+current expectations are that OpenOCD itself will handle enabling; -activating single wire trace involves a debug adapter interaction, and -collecting that trace data requires particular (re)wiring. -+ -+* CONFIGURATION involves setting up ITM and/or ETM modules to emit the -+desired data from the Cortex core. (This might include dumping -+event counters printf-style messages; code profiling; and more. Not all -+cores offer the same trace capabilities. -+ -+current expectations are that Tcl scripts will be used to configure these -+modules for the desired tracing, by direct writes to registers. In some -+cases (as with RTOS event tracking and similar messaging, this might -+be augmented or replaced by user code running on the ARM core. -+ -+COLLECTION involves reading that trace data, probably through UART, and -+saving it in a useful format to analyse For now, deferred analysis modes -are assumed, not than real-time or interactive ones. -+ -+ -+current expectations are to to dump data in text using contrib/itmdump.c -+or derived tools, and to post-process it into reports. Such reports might -+include program messaging (such as application data streams via ITM, maybe -+using printf type messaging; code coverage analysis or so forth. Recent -+versions of CMSIS software reserve some ITM codespace for RTOS event -tracing and include ITM messaging support. -Clearly some of that data would be valuable for interactive debugging. -+ -+Should someone get ambitious, GUI reports should be possible. GNU tools -+for simpler reports like gprof may be simpler to support at first. -+In any case, OpenOCD is not currently GUI-oriented. Accordingly, we now -+expect any such graphics to come from postprocessing. - - measurements for RTOS event timings should also be easy to collect. -+Examples include context and message switch times, as well as times -for application interactions. -+ diff --git a/doc/openocd.texi b/doc/openocd.texi index 8ffbcf3..5bd4e89 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7345,12 +7345,13 @@ flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME @end deffn @deffn {Flash Driver} {nrf5} -All members of the nRF51 microcontroller families from Nordic Semiconductor -include internal flash and use ARM Cortex-M0 core. nRF52 family powered -by ARM Cortex-M4 or M4F core is supported too. nRF52832 is fully supported -including BPROT flash protection scheme. nRF52833 and nRF52840 devices are -supported with the exception of security extensions (flash access control list -- ACL). +Supports all members of the nRF51, nRF52 and nRF53 microcontroller families from +Nordic Semiconductor. nRF91 family is supported too. One driver handles both +the main flash and the UICR area. + +Flash protection is handled on nRF51 family and nRF52805, nRF52810, nRF52811, +nRF52832 devices. Flash access control list (ACL) protection scheme of the newer +devices is not supported. @example flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME @@ -8827,8 +8828,8 @@ The file format must be inferred by the driver. @section PLD/FPGA Drivers, Options, and Commands -Drivers may support PLD-specific options to the @command{pld device} -definition command, and may also define commands usable only with +Drivers may support PLD-specific options to the @command{pld create} +command, and may also define commands usable only with that particular type of PLD. @deffn {FPGA Driver} {virtex2} [@option{-no_jstart}] @@ -8914,13 +8915,12 @@ For the option @option{-family} @var{name} is one of @var{trion|titanium}. @end deffn -@deffn {FPGA Driver} {intel} [@option{-family} <name>] +@deffn {FPGA Driver} {intel} @option{-family} <name> This driver can be used to load the bitstream into Intel (former Altera) FPGAs. -The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10, Arria II are supported. +The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10 and Arria II are supported. @c Arria V and Arria 10, MAX II, MAX V, MAX10) -For the option @option{-family} @var{name} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}. -This is needed when the JTAG ID of the device is ambiguous (same ID is used for chips in different families). +The option @option{-family} @var{name} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}. As input file format the driver supports a '.rbf' (raw bitstream file) file. The '.rbf' file can be generated from a '.sof' file with @verb{|quartus_cpf -c blinker.sof blinker.rbf|} @@ -11290,11 +11290,6 @@ Set the wall-clock timeout (in seconds) for individual commands. The default should work fine for all but the slowest targets (eg. simulators). @end deffn -@deffn {Command} {riscv set_reset_timeout_sec} [seconds] -Set the maximum time to wait for a hart to come out of reset after reset is -deasserted. -@end deffn - @deffn {Command} {riscv set_mem_access} method1 [method2] [method3] Specify which RISC-V memory access method(s) shall be used, and in which order of priority. At least one method must be specified. @@ -11376,7 +11371,6 @@ tunneled DR scan consists of: @item A width+1 stream of bits for the tunneled TDI. The plus one is because there is a one-clock skew between TDI of Xilinx chain and TDO from tunneled chain. @item 3 bits of zero that the tunnel uses to go back to idle state. @end enumerate - @end deffn @deffn {Command} {riscv set_bscan_tunnel_ir} value diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index 2b458bc..bb89377 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -124,7 +124,7 @@ FLASH_BANK_COMMAND_HANDLER(ambiqmicro_flash_bank_command) if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - ambiqmicro_info = calloc(sizeof(struct ambiqmicro_flash_bank), 1); + ambiqmicro_info = calloc(1, sizeof(struct ambiqmicro_flash_bank)); bank->driver_priv = ambiqmicro_info; diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 6879a1b..86c8076 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -560,7 +560,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank) if (bnk > 0) { if (!t_bank->next) { /* create a new flash bank element */ - struct flash_bank *fb = calloc(sizeof(struct flash_bank), 1); + struct flash_bank *fb = calloc(1, sizeof(struct flash_bank)); if (!fb) { LOG_ERROR("No memory for flash bank"); return ERROR_FAIL; @@ -748,7 +748,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) if (bnk > 0) { if (!t_bank->next) { /* create a new bank element */ - struct flash_bank *fb = calloc(sizeof(struct flash_bank), 1); + struct flash_bank *fb = calloc(1, sizeof(struct flash_bank)); if (!fb) { LOG_ERROR("No memory for flash bank"); return ERROR_FAIL; diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 80911f7..ff175a1 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -32,18 +32,18 @@ struct flash_sector { uint32_t size; /** * Indication of erasure status: 0 = not erased, 1 = erased, - * other = unknown. Set by @c flash_driver_s::erase_check only. + * other = unknown. Set by @c flash_driver::erase_check only. * * This information must be considered stale immediately. - * Don't set it in flash_driver_s::erase or a device mass_erase - * Don't clear it in flash_driver_s::write + * Don't set it in flash_driver::erase or a device mass_erase + * Don't clear it in flash_driver::write * The flag is not used in a protection block */ int is_erased; /** * Indication of protection status: 0 = unprotected/unlocked, * 1 = protected/locked, other = unknown. Set by - * @c flash_driver_s::protect_check. + * @c flash_driver::protect_check. * * This information must be considered stale immediately. * A million things could make it stale: power cycle, @@ -67,7 +67,7 @@ struct flash_sector { * a major interface. * * This structure will be passed as a parameter to the callbacks in the - * flash_driver_s structure, some of which may modify the contents of + * flash_driver structure, some of which may modify the contents of * this structure of the area of flash that it defines. Driver writers * may use the @c driver_priv member to store additional data on a * per-bank basis, if required. diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 7d6f8c5..211661e 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -29,7 +29,7 @@ struct flash_bank; * flash bank DRIVERNAME ...parameters... * @endcode * - * OpenOCD will search for the driver with a @c flash_driver_s::name + * OpenOCD will search for the driver with a @c flash_driver::name * that matches @c DRIVERNAME. * * The flash subsystem calls some of the other drivers routines a using @@ -170,7 +170,7 @@ struct flash_driver { /** * Check the erasure status of a flash bank. * When called, the driver routine must perform the required - * checks and then set the @c flash_sector_s::is_erased field + * checks and then set the @c flash_sector::is_erased field * for each of the flash banks's sectors. * * @param bank The bank to check @@ -182,7 +182,7 @@ struct flash_driver { * Determine if the specific bank is "protected" or not. * When called, the driver routine must must perform the * required protection check(s) and then set the @c - * flash_sector_s::is_protected field for each of the flash + * flash_sector::is_protected field for each of the flash * bank's sectors. * * If protection is not implemented, set method to NULL @@ -204,7 +204,7 @@ struct flash_driver { int (*info)(struct flash_bank *bank, struct command_invocation *cmd); /** - * A more gentle flavor of flash_driver_s::probe, performing + * A more gentle flavor of flash_driver::probe, performing * setup with less noise. Generally, driver routines should test * to see if the bank has already been probed; if it has, the * driver probably should not perform its probe a second time. diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index e8074e3..fee3644 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -930,7 +930,7 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) k_chip = kinetis_get_chip(target); if (!k_chip) { - k_chip = calloc(sizeof(struct kinetis_chip), 1); + k_chip = calloc(1, sizeof(struct kinetis_chip)); if (!k_chip) { LOG_ERROR("No memory"); return ERROR_FAIL; @@ -1031,7 +1031,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) bank_idx - k_chip->num_pflash_blocks); } - bank = calloc(sizeof(struct flash_bank), 1); + bank = calloc(1, sizeof(struct flash_bank)); if (!bank) return ERROR_FAIL; diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c index 51d6ae2..59a14af 100644 --- a/src/flash/nor/max32xxx.c +++ b/src/flash/nor/max32xxx.c @@ -87,7 +87,7 @@ FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command) return ERROR_FLASH_BANK_INVALID; } - info = calloc(sizeof(struct max32xxx_flash_bank), 1); + info = calloc(1, sizeof(struct max32xxx_flash_bank)); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], info->flash_size); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], info->flc_base); COMMAND_PARSE_NUMBER(uint, CMD_ARGV[7], info->sector_size); diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index 5e2935d..b5e2b0b 100644 --- a/src/flash/nor/msp432.c +++ b/src/flash/nor/msp432.c @@ -937,7 +937,7 @@ static int msp432_probe(struct flash_bank *bank) if (is_main && MSP432P4 == msp432_bank->family_type) { /* Create the info flash bank needed by MSP432P4 variants */ - struct flash_bank *info = calloc(sizeof(struct flash_bank), 1); + struct flash_bank *info = calloc(1, sizeof(struct flash_bank)); if (!info) return ERROR_FAIL; diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index bf8c9da..f07433e 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -19,8 +19,7 @@ #include <helper/time_support.h> #include <helper/bits.h> -/* Both those values are constant across the current spectrum ofr nRF5 devices */ -#define WATCHDOG_REFRESH_REGISTER 0x40010600 +/* The refresh code is constant across the current spectrum of nRF5 devices */ #define WATCHDOG_REFRESH_VALUE 0x6e524635 enum { @@ -28,12 +27,9 @@ enum { }; enum nrf5_ficr_registers { - NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ + NRF51_52_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ -#define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset) - - NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010), - NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014), +#define NRF5_FICR_REG(offset) (NRF51_52_FICR_BASE + (offset)) NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028), NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C), @@ -42,39 +38,23 @@ enum nrf5_ficr_registers { NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), - - /* CONFIGID is documented on nRF51 series only. - * On nRF52 is present but not documented */ - NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), - - /* Following registers are available on nRF52 and on nRF51 since rev 3 */ - NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100), - NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104), - NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108), - NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C), - NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110), }; enum nrf5_uicr_registers { - NRF5_UICR_BASE = 0x10001000, /* User Information + NRF51_52_UICR_BASE = 0x10001000, /* User Information * Configuration Registers */ -#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) +#define NRF5_UICR_REG(offset) (NRF51_52_UICR_BASE + (offset)) NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000), }; enum nrf5_nvmc_registers { - NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory - * Controller Registers */ - -#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) - - NRF5_NVMC_READY = NRF5_NVMC_REG(0x400), - NRF5_NVMC_CONFIG = NRF5_NVMC_REG(0x504), - NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), - NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), - NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), + NRF5_NVMC_READY = 0x400, + NRF5_NVMC_CONFIG = 0x504, + NRF5_NVMC_ERASEPAGE = 0x508, + NRF5_NVMC_ERASEALL = 0x50C, + NRF5_NVMC_ERASEUICR = 0x514, NRF5_BPROT_BASE = 0x40000000, }; @@ -99,6 +79,9 @@ enum nrf5_features { NRF5_FEATURE_SERIES_52 = BIT(1), NRF5_FEATURE_BPROT = BIT(2), NRF5_FEATURE_ACL_PROT = BIT(3), + NRF5_FEATURE_SERIES_53 = BIT(4), + NRF5_FEATURE_SERIES_91 = BIT(5), + NRF5_FEATURE_ERASE_BY_FLASH_WR = BIT(6), }; struct nrf5_device_spec { @@ -110,6 +93,28 @@ struct nrf5_device_spec { enum nrf5_features features; }; +/* FICR registers offsets */ +struct nrf5_ficr_map { + uint32_t codepagesize; + uint32_t codesize; + uint32_t configid; + uint32_t info_part; + uint32_t info_variant; + uint32_t info_package; + uint32_t info_ram; + uint32_t info_flash; +}; + +/* Map of device */ +struct nrf5_map { + uint32_t flash_base; + uint32_t ficr_base; + uint32_t uicr_base; + uint32_t nvmc_base; + + uint32_t watchdog_refresh_addr; +}; + struct nrf5_info { unsigned int refcount; @@ -127,6 +132,9 @@ struct nrf5_info { enum nrf5_features features; unsigned int flash_size_kb; unsigned int ram_size_kb; + + const struct nrf5_map *map; + const struct nrf5_ficr_map *ficr_offsets; }; #define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ @@ -238,6 +246,96 @@ static const struct nrf5_device_package nrf52_packages_table[] = { { 0x2009, "CF" }, }; +static const struct nrf5_ficr_map nrf51_52_ficr_offsets = { + .codepagesize = 0x10, + .codesize = 0x14, + + /* CONFIGID is documented on nRF51 series only. + * On nRF52 is present but not documented */ + .configid = 0x5c, + + /* Following registers are available on nRF52 and on nRF51 since rev 3 */ + .info_part = 0x100, + .info_variant = 0x104, + .info_package = 0x108, + .info_ram = 0x10c, + .info_flash = 0x110, +}; + +static const struct nrf5_map nrf51_52_map = { + .flash_base = NRF5_FLASH_BASE, + .ficr_base = NRF51_52_FICR_BASE, + .uicr_base = NRF51_52_UICR_BASE, + .nvmc_base = 0x4001E000, + + .watchdog_refresh_addr = 0x40010600, +}; + + +/* Third generation devices (nRF53, nRF91) */ + +static const struct nrf5_ficr_map nrf53_91_ficr_offsets = { + .codepagesize = 0x220, + .codesize = 0x224, + .configid = 0x200, + .info_part = 0x20c, + .info_variant = 0x210, + .info_package = 0x214, + .info_ram = 0x218, + .info_flash = 0x21c, +}; + +/* Since nRF9160 Product Specification v2.1 there is + * a new UICR field SIPINFO, which should be preferred. + * The original INFO fields describe just a part of the chip + * (PARTNO=9120 at nRF9161) + */ +static const struct nrf5_ficr_map nrf91new_ficr_offsets = { + .codepagesize = 0x220, + .codesize = 0x224, + .configid = 0x200, + .info_part = 0x140, /* SIPINFO.PARTNO */ + .info_variant = 0x148, /* SIPINFO.VARIANT */ + .info_package = 0x214, + .info_ram = 0x218, + .info_flash = 0x21c, +}; + +enum { + NRF53APP_91_FICR_BASE = 0x00FF0000, + NRF53APP_91_UICR_BASE = 0x00FF8000, + NRF53NET_FLASH_BASE = 0x01000000, + NRF53NET_FICR_BASE = 0x01FF0000, + NRF53NET_UICR_BASE = 0x01FF8000, +}; + +static const struct nrf5_map nrf53app_91_map = { + .flash_base = NRF5_FLASH_BASE, + .ficr_base = NRF53APP_91_FICR_BASE, + .uicr_base = NRF53APP_91_UICR_BASE, + .nvmc_base = 0x50039000, + + .watchdog_refresh_addr = 0x50018600, +}; + +/* nRF53 duality: + * SoC consists of two Cortex-M33 cores: + * - application core with security extensions + * - network core + * Each core has its own RAM, flash, FICR and UICR + * The flash driver probes and handles flash and UICR of one core + * independently of those dedicated to the other core. + */ +static const struct nrf5_map nrf53net_map = { + .flash_base = NRF53NET_FLASH_BASE, + .ficr_base = NRF53NET_FICR_BASE, + .uicr_base = NRF53NET_UICR_BASE, + .nvmc_base = 0x41080000, + + .watchdog_refresh_addr = 0x41080000, +}; + + const struct flash_driver nrf5_flash, nrf51_flash; static bool nrf5_bank_is_probed(const struct flash_bank *bank) @@ -248,6 +346,24 @@ static bool nrf5_bank_is_probed(const struct flash_bank *bank) return nbank->probed; } +static bool nrf5_bank_is_uicr(const struct nrf5_bank *nbank) +{ + struct nrf5_info *chip = nbank->chip; + assert(chip); + + return nbank == &chip->bank[1]; +} + +static int nrf5_nvmc_read_u32(struct nrf5_info *chip, uint32_t reg_offset, uint32_t *value) +{ + return target_read_u32(chip->target, chip->map->nvmc_base + reg_offset, value); +} + +static int nrf5_nvmc_write_u32(struct nrf5_info *chip, uint32_t reg_offset, uint32_t value) +{ + return target_write_u32(chip->target, chip->map->nvmc_base + reg_offset, value); +} + static int nrf5_wait_for_nvmc(struct nrf5_info *chip) { uint32_t ready; @@ -256,7 +372,13 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) int64_t ts_start = timeval_ms(); do { - res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); + res = nrf5_nvmc_read_u32(chip, NRF5_NVMC_READY, &ready); + if (res == ERROR_WAIT) { + /* The adapter does not handle SWD WAIT properly, + * add some delay to reduce number of error messages */ + alive_sleep(10); + continue; + } if (res != ERROR_OK) { LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)"); return res; @@ -276,7 +398,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) { int res; - res = target_write_u32(chip->target, + res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_CONFIG, NRF5_NVMC_CONFIG_EEN); @@ -299,7 +421,7 @@ static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) static int nrf5_nvmc_write_enable(struct nrf5_info *chip) { int res; - res = target_write_u32(chip->target, + res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_CONFIG, NRF5_NVMC_CONFIG_WEN); @@ -322,12 +444,12 @@ static int nrf5_nvmc_write_enable(struct nrf5_info *chip) static int nrf5_nvmc_read_only(struct nrf5_info *chip) { int res; - res = target_write_u32(chip->target, + res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_CONFIG, NRF5_NVMC_CONFIG_REN); if (res != ERROR_OK) { - LOG_ERROR("Failed to enable read-only operation"); + LOG_ERROR("Failed to disable write/erase operation"); return res; } /* @@ -341,36 +463,8 @@ static int nrf5_nvmc_read_only(struct nrf5_info *chip) return res; } -static int nrf5_nvmc_generic_erase(struct nrf5_info *chip, - uint32_t erase_register, uint32_t erase_value) -{ - int res; - - res = nrf5_nvmc_erase_enable(chip); - if (res != ERROR_OK) - goto error; - - res = target_write_u32(chip->target, - erase_register, - erase_value); - if (res != ERROR_OK) - goto set_read_only; - - res = nrf5_wait_for_nvmc(chip); - if (res != ERROR_OK) - goto set_read_only; - - return nrf5_nvmc_read_only(chip); - -set_read_only: - nrf5_nvmc_read_only(chip); -error: - LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32, - erase_register, erase_value); - return ERROR_FAIL; -} - -static int nrf5_protect_check_clenr0(struct flash_bank *bank) +/* nRF51 series only */ +static int nrf51_protect_check_clenr0(struct flash_bank *bank) { int res; uint32_t clenr0; @@ -403,7 +497,8 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank) return ERROR_OK; } -static int nrf5_protect_check_bprot(struct flash_bank *bank) +/* nRF52 series only */ +static int nrf52_protect_check_bprot(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; assert(nbank); @@ -432,26 +527,27 @@ static int nrf5_protect_check_bprot(struct flash_bank *bank) static int nrf5_protect_check(struct flash_bank *bank) { - /* UICR cannot be write protected so just return early */ - if (bank->base == NRF5_UICR_BASE) - return ERROR_OK; - 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)) + return ERROR_OK; + if (chip->features & NRF5_FEATURE_BPROT) - return nrf5_protect_check_bprot(bank); + return nrf52_protect_check_bprot(bank); if (chip->features & NRF5_FEATURE_SERIES_51) - return nrf5_protect_check_clenr0(bank); + return nrf51_protect_check_clenr0(bank); LOG_WARNING("Flash protection of this nRF device is not supported"); return ERROR_FLASH_OPER_UNSUPPORTED; } -static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, +/* nRF51 series only */ +static int nrf51_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; @@ -517,8 +613,13 @@ error: 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 (bank->base == NRF5_UICR_BASE) { + if (nrf5_bank_is_uicr(nbank)) { LOG_ERROR("UICR page does not support protection"); return ERROR_FLASH_OPER_UNSUPPORTED; } @@ -528,24 +629,24 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, 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) - return nrf5_protect_clenr0(bank, set, first, last); + return nrf51_protect_clenr0(bank, set, first, last); LOG_ERROR("Flash protection setting is not supported on this nRF5 device"); return ERROR_FLASH_OPER_UNSUPPORTED; } -static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) +static bool nrf5_info_variant_to_str(uint32_t variant, char *bf, bool swap) { uint8_t b[4]; - h_u32_to_be(b, variant); - if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && isalnum(b[3])) { + if (swap) + h_u32_to_le(b, variant); + else + h_u32_to_be(b, variant); + + if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && + (isalnum(b[3]) || b[3] == 0)) { memcpy(bf, b, 4); bf[4] = 0; return true; @@ -564,7 +665,7 @@ static const char *nrf5_decode_info_package(uint32_t package) return "xx"; } -static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size) +static int nrf5_get_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size) { int res; if (chip->spec) { @@ -572,11 +673,19 @@ static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsig chip->spec->part, chip->spec->variant, chip->spec->build_code); } else if (chip->ficr_info_valid) { char variant[5]; - nrf5_info_variant_to_str(chip->ficr_info.variant, variant); - res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)", - chip->ficr_info.part, - nrf5_decode_info_package(chip->ficr_info.package), - variant, &variant[2]); + + nrf5_info_variant_to_str(chip->ficr_info.variant, variant, + chip->features & NRF5_FEATURE_SERIES_91); + + if (chip->features & (NRF5_FEATURE_SERIES_53 | NRF5_FEATURE_SERIES_91)) { + res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s", + chip->ficr_info.part, variant); + } else { + res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)", + chip->ficr_info.part, + nrf5_decode_info_package(chip->ficr_info.package), + variant, &variant[2]); + } } else { res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid); } @@ -597,7 +706,7 @@ static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) assert(chip); char chip_type_str[256]; - if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) return ERROR_FAIL; command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM", @@ -605,24 +714,27 @@ static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd) return ERROR_OK; } -static int nrf5_read_ficr_info(struct nrf5_info *chip) +static int nrf5_read_ficr_info_part(struct nrf5_info *chip, const struct nrf5_map *map, + const struct nrf5_ficr_map *ficr_offsets) { - int res; struct target *target = chip->target; + uint32_t ficr_base = map->ficr_base; - chip->ficr_info_valid = false; - - res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part); - if (res != ERROR_OK) { + int res = target_read_u32(target, ficr_base + ficr_offsets->info_part, &chip->ficr_info.part); + if (res != ERROR_OK) LOG_DEBUG("Couldn't read FICR INFO.PART register"); - return res; - } + + return res; +} + +static int nrf51_52_partno_check(struct nrf5_info *chip) +{ uint32_t series = chip->ficr_info.part & 0xfffff000; switch (series) { case 0x51000: chip->features = NRF5_FEATURE_SERIES_51; - break; + return ERROR_OK; case 0x52000: chip->features = NRF5_FEATURE_SERIES_52; @@ -641,41 +753,59 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip) chip->features |= NRF5_FEATURE_ACL_PROT; break; } - break; + return ERROR_OK; default: LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08" - PRIx32, chip->ficr_info.part); + PRIx32, chip->ficr_info.part); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } +} - /* Now we know the device has FICR INFO filled by something relevant: - * Although it is not documented, the tested nRF51 rev 3 devices - * have FICR INFO.PART, RAM and FLASH of the same format as nRF52. - * VARIANT and PACKAGE coding is unknown for a nRF51 device. - * nRF52 devices have FICR INFO documented and always filled. */ +static int nrf53_91_partno_check(struct nrf5_info *chip) +{ + uint32_t series = chip->ficr_info.part & 0xffffff00; + switch (series) { + case 0x5300: + chip->features = NRF5_FEATURE_SERIES_53 | NRF5_FEATURE_ERASE_BY_FLASH_WR; + return ERROR_OK; - res = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant); - if (res != ERROR_OK) - return res; + case 0x9100: + chip->features = NRF5_FEATURE_SERIES_91 | NRF5_FEATURE_ERASE_BY_FLASH_WR; + return ERROR_OK; - res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package); + default: + LOG_DEBUG("Invalid FICR INFO PART value 0x%08" + PRIx32, chip->ficr_info.part); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } +} + +static int nrf5_read_ficr_more_info(struct nrf5_info *chip) +{ + int res; + struct target *target = chip->target; + const struct nrf5_ficr_map *ficr_offsets = chip->ficr_offsets; + uint32_t ficr_base = chip->map->ficr_base; + + res = target_read_u32(target, ficr_base + ficr_offsets->info_variant, &chip->ficr_info.variant); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram); + res = target_read_u32(target, ficr_base + ficr_offsets->info_package, &chip->ficr_info.package); if (res != ERROR_OK) return res; - res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash); + res = target_read_u32(target, ficr_base + ficr_offsets->info_ram, &chip->ficr_info.ram); if (res != ERROR_OK) return res; - chip->ficr_info_valid = true; - return ERROR_OK; + res = target_read_u32(target, ficr_base + ficr_offsets->info_flash, &chip->ficr_info.flash); + return res; } -static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) +/* nRF51 series only */ +static int nrf51_get_ram_size(struct target *target, uint32_t *ram_size) { int res; @@ -710,7 +840,7 @@ static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size) static int nrf5_probe(struct flash_bank *bank) { - int res; + int res = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; struct nrf5_bank *nbank = bank->driver_priv; assert(nbank); @@ -718,24 +848,100 @@ static int nrf5_probe(struct flash_bank *bank) assert(chip); struct target *target = chip->target; - uint32_t configid; - res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid); + chip->spec = NULL; + chip->ficr_info_valid = false; + + /* First try to detect nRF53/91 */ + switch (bank->base) { + case NRF5_FLASH_BASE: + case NRF53APP_91_UICR_BASE: + res = nrf5_read_ficr_info_part(chip, &nrf53app_91_map, &nrf91new_ficr_offsets); + if (res == ERROR_OK) { + res = nrf53_91_partno_check(chip); + if (res == ERROR_OK) { + chip->map = &nrf53app_91_map; + chip->ficr_offsets = &nrf91new_ficr_offsets; + break; + } + } + + res = nrf5_read_ficr_info_part(chip, &nrf53app_91_map, &nrf53_91_ficr_offsets); + if (res != ERROR_OK) + break; + + res = nrf53_91_partno_check(chip); + if (res != ERROR_OK) + break; + + chip->map = &nrf53app_91_map; + chip->ficr_offsets = &nrf53_91_ficr_offsets; + break; + + case NRF53NET_FLASH_BASE: + case NRF53NET_UICR_BASE: + res = nrf5_read_ficr_info_part(chip, &nrf53net_map, &nrf53_91_ficr_offsets); + if (res != ERROR_OK) + break; + + res = nrf53_91_partno_check(chip); + if (res != ERROR_OK) + break; + + chip->map = &nrf53net_map; + chip->ficr_offsets = &nrf53_91_ficr_offsets; + break; + + default: + break; + } + + /* If nRF53/91 is not detected, try nRF51/52 */ if (res != ERROR_OK) { - LOG_ERROR("Couldn't read CONFIGID register"); - return res; + /* Guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ + chip->features = NRF5_FEATURE_SERIES_51; + chip->map = &nrf51_52_map; + chip->ficr_offsets = &nrf51_52_ficr_offsets; + + /* Don't bail out on error for the case that some old engineering + * sample has FICR INFO registers unreadable. We can proceed anyway. */ + res = nrf5_read_ficr_info_part(chip, chip->map, chip->ficr_offsets); + if (res == ERROR_OK) + res = nrf51_52_partno_check(chip); } - /* HWID is stored in the lower two bytes of the CONFIGID register */ - chip->hwid = configid & 0xFFFF; + if (res == ERROR_OK) { + /* Now we know the device has FICR INFO filled by something relevant: + * Although it is not documented, the tested nRF51 rev 3 devices + * have FICR INFO.PART, RAM and FLASH of the same format as nRF52. + * VARIANT and PACKAGE coding is unknown for a nRF51 device. + * nRF52 devices have FICR INFO documented and always filled. */ + res = nrf5_read_ficr_more_info(chip); + if (res == ERROR_OK) { + chip->ficr_info_valid = true; + } else if (chip->features & NRF5_FEATURE_SERIES_51) { + LOG_DEBUG("Couldn't read some of FICR INFO registers"); + } else { + LOG_ERROR("Couldn't read some of FICR INFO registers"); + return res; + } + } - /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ - chip->features = NRF5_FEATURE_SERIES_51; + const struct nrf5_ficr_map *ficr_offsets = chip->ficr_offsets; + uint32_t ficr_base = chip->map->ficr_base; + uint32_t configid = 0; + res = target_read_u32(target, ficr_base + ficr_offsets->configid, &configid); + if (res != ERROR_OK) { + if (chip->features & NRF5_FEATURE_SERIES_51) { + LOG_ERROR("Couldn't read FICR CONFIGID register"); + return res; + } - /* Don't bail out on error for the case that some old engineering - * sample has FICR INFO registers unreadable. We can proceed anyway. */ - (void)nrf5_read_ficr_info(chip); + LOG_DEBUG("Couldn't read FICR CONFIGID register, using FICR INFO"); + } + + /* HWID is stored in the lower two bytes of the CONFIGID register */ + chip->hwid = configid & 0xFFFF; - chip->spec = NULL; for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { if (chip->hwid == nrf5_known_devices_table[i].hwid) { chip->spec = &nrf5_known_devices_table[i]; @@ -753,15 +959,17 @@ static int nrf5_probe(struct flash_bank *bank) if (chip->ficr_info_valid) { chip->ram_size_kb = chip->ficr_info.ram; - } else { + } else if (chip->features & NRF5_FEATURE_SERIES_51) { uint32_t ram_size; - nrf5_get_ram_size(target, &ram_size); + nrf51_get_ram_size(target, &ram_size); chip->ram_size_kb = ram_size / 1024; + } else { + chip->ram_size_kb = 0; } - /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + /* 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, NRF5_FICR_CODEPAGESIZE, + res = target_read_u32(chip->target, ficr_base + ficr_offsets->codepagesize, &flash_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); @@ -769,9 +977,10 @@ static int nrf5_probe(struct flash_bank *bank) } /* Note the register name is misleading, - * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ + * 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, NRF5_FICR_CODESIZE, &num_sectors); + res = target_read_u32(chip->target, ficr_base + ficr_offsets->codesize, + &num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; @@ -781,7 +990,7 @@ static int nrf5_probe(struct flash_bank *bank) if (!chip->bank[0].probed && !chip->bank[1].probed) { char chip_type_str[256]; - if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK) + 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", @@ -793,7 +1002,7 @@ static int nrf5_probe(struct flash_bank *bank) free(bank->sectors); - if (bank->base == NRF5_FLASH_BASE) { + if (bank->base == chip->map->flash_base) { /* Sanity check */ if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb) LOG_WARNING("Chip's reported Flash capacity does not match expected one"); @@ -810,6 +1019,7 @@ static int nrf5_probe(struct flash_bank *bank) chip->bank[0].probed = true; } else { + /* UICR bank */ bank->num_sectors = 1; bank->size = flash_page_size; @@ -833,13 +1043,6 @@ static int nrf5_auto_probe(struct flash_bank *bank) return nrf5_probe(bank); } -static int nrf5_erase_all(struct nrf5_info *chip) -{ - LOG_DEBUG("Erasing all non-volatile memory"); - return nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEALL, - 0x00000001); -} static int nrf5_erase_page(struct flash_bank *bank, struct nrf5_info *chip, @@ -849,7 +1052,7 @@ static int nrf5_erase_page(struct flash_bank *bank, LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset); - if (bank->base == NRF5_UICR_BASE) { + if (bank->base == chip->map->uicr_base) { if (chip->features & NRF5_FEATURE_SERIES_51) { uint32_t ppfc; res = target_read_u32(chip->target, NRF51_FICR_PPFC, @@ -871,17 +1074,37 @@ static int nrf5_erase_page(struct flash_bank *bank, } } - res = nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEUICR, - 0x00000001); - + res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEUICR, 0x00000001); + + } else if (chip->features & NRF5_FEATURE_ERASE_BY_FLASH_WR) { + res = target_write_u32(chip->target, bank->base + sector->offset, 0xffffffff); + /* nRF9160 errata [2] NVMC: CPU code execution from RAM halted during + * flash page erase operation + * https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF9160_Rev1%2FERR%2FnRF9160%2FRev1%2Flatest%2Fanomaly_160_2.html + * affects also erasing by debugger MEM-AP write: + * + * Write to a flash address stalls the bus for 87 ms until + * page erase finishes! This makes problems if the adapter does not + * handle SWD WAIT properly or does not wait long enough. + * Using a target algo would not help, AP gets unresponsive too. + * Neither sending AP ABORT helps, the next AP access stalls again. + * Simply wait long enough before accessing AP again... + * + * The same errata was observed in nRF9161 + */ + if (chip->features & NRF5_FEATURE_SERIES_91) + alive_sleep(90); } else { - res = nrf5_nvmc_generic_erase(chip, - NRF5_NVMC_ERASEPAGE, - sector->offset); + res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEPAGE, sector->offset); + } + + if (res != ERROR_OK) { + /* caller logs the error */ + return res; } + res = nrf5_wait_for_nvmc(chip); return res; } @@ -958,7 +1181,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[3].value, 0, 32, address); buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE); - buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER); + buf_set_u32(reg_params[5].value, 0, 32, chip->map->watchdog_refresh_addr); retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4, 0, NULL, @@ -1008,7 +1231,7 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, * is protected. */ if (chip->features & NRF5_FEATURE_SERIES_51) { - res = nrf5_protect_check_clenr0(bank); + res = nrf51_protect_check_clenr0(bank); if (res != ERROR_OK) return res; @@ -1065,18 +1288,23 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, * is protected. */ if (chip->features & NRF5_FEATURE_SERIES_51) { - res = nrf5_protect_check_clenr0(bank); + res = nrf51_protect_check_clenr0(bank); if (res != ERROR_OK) return res; } + res = nrf5_nvmc_erase_enable(chip); + if (res != ERROR_OK) + goto error; + /* For each sector to be erased */ for (unsigned int s = first; s <= last; s++) { if (chip->features & NRF5_FEATURE_SERIES_51 && bank->sectors[s].is_protected == 1) { LOG_ERROR("Flash sector %d is protected", s); - return ERROR_FLASH_PROTECTED; + res = ERROR_FLASH_PROTECTED; + break; } res = nrf5_erase_page(bank, chip, &bank->sectors[s]); @@ -1086,7 +1314,9 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, } } - return ERROR_OK; +error: + nrf5_nvmc_read_only(chip); + return res; } static void nrf5_free_driver_priv(struct flash_bank *bank) @@ -1136,7 +1366,10 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) switch (bank->base) { case NRF5_FLASH_BASE: - case NRF5_UICR_BASE: + case NRF53NET_FLASH_BASE: + case NRF51_52_UICR_BASE: + case NRF53APP_91_UICR_BASE: + case NRF53NET_UICR_BASE: break; default: LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base); @@ -1155,9 +1388,12 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) switch (bank->base) { case NRF5_FLASH_BASE: + case NRF53NET_FLASH_BASE: nbank = &chip->bank[0]; break; - case NRF5_UICR_BASE: + case NRF51_52_UICR_BASE: + case NRF53APP_91_UICR_BASE: + case NRF53NET_UICR_BASE: nbank = &chip->bank[1]; break; } @@ -1210,14 +1446,27 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) } } - res = nrf5_erase_all(chip); + res = nrf5_nvmc_erase_enable(chip); + if (res != ERROR_OK) + goto error; + + res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEALL, 0x00000001); + if (res != ERROR_OK) { + LOG_ERROR("Mass erase failed"); + goto error; + } + + res = nrf5_wait_for_nvmc(chip); + if (res != ERROR_OK) + LOG_ERROR("Mass erase did not complete"); + +error: + nrf5_nvmc_read_only(chip); + if (res == ERROR_OK) { LOG_INFO("Mass erase completed."); if (chip->features & NRF5_FEATURE_SERIES_51) LOG_INFO("A reset or power cycle is required if the flash was protected before."); - - } else { - LOG_ERROR("Failed to erase the chip"); } return res; diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c index 0f3937c..982c961 100644 --- a/src/flash/nor/pic32mx.c +++ b/src/flash/nor/pic32mx.c @@ -92,7 +92,7 @@ struct pic32mx_flash_bank { * DEVID values as per PIC32MX Flash Programming Specification Rev N */ -static const struct pic32mx_devs_s { +static const struct pic32mx_devs { uint32_t devid; const char *name; } pic32mx_devs[] = { diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 972686e..eab6244 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -453,7 +453,7 @@ FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command) if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; - stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1); + stellaris_info = calloc(1, sizeof(struct stellaris_flash_bank)); bank->base = 0x0; bank->driver_priv = stellaris_info; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 4e0f731..3bafde5 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1020,7 +1020,7 @@ static int stm32x_probe(struct flash_bank *bank) assert(num_sectors > 0); bank->num_sectors = num_sectors; - bank->sectors = calloc(sizeof(struct flash_sector), num_sectors); + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); if (stm32x_otp_is_f7(bank)) bank->size = STM32F7_OTP_SIZE; diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 1c4e154..15edd1a 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -1299,6 +1299,7 @@ COMMAND_HANDLER(handle_flash_bank_command) if (retval != ERROR_OK) { LOG_ERROR("'%s' driver rejected flash bank at " TARGET_ADDR_FMT "; usage: %s", driver_name, c->base, driver->usage); + free(c->name); free(c); return retval; } diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index 5a0d479..e6e76e6 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -11,10 +11,10 @@ proc find {filename} { if {[catch {ocd_find $filename} t]==0} { return $t } - if {[catch {ocd_find [string map {\ /} $filename} t]==0} { + if {[catch {ocd_find [string map {\\ /} $filename]} t]==0} { return $t } - if {[catch {ocd_find [string map {/ \\} $filename} t]==0} { + if {[catch {ocd_find [string map {/ \\} $filename]} t]==0} { return $t } # make sure error message matches original input string diff --git a/src/jtag/commands.h b/src/jtag/commands.h index a1096da..8259077 100644 --- a/src/jtag/commands.h +++ b/src/jtag/commands.h @@ -15,7 +15,7 @@ #define OPENOCD_JTAG_COMMANDS_H /** - * The inferred type of a scan_command_s structure, indicating whether + * The inferred type of a scan_command structure, indicating whether * the command has the host scan in from the device, the host scan out * to the device, or both. */ @@ -29,7 +29,7 @@ enum scan_type { }; /** - * The scan_command provide a means of encapsulating a set of scan_field_s + * The scan_command provide a means of encapsulating a set of scan_field * structures that should be scanned in/out to the device. */ struct scan_command { @@ -123,7 +123,7 @@ union jtag_command_container { /** * The type of the @c jtag_command_container contained by a - * @c jtag_command_s structure. + * @c jtag_command structure. */ enum jtag_command_type { JTAG_SCAN = 1, diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index c024667..81dd1af 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -1597,7 +1597,7 @@ static int angie_queue_scan(struct angie *device, struct jtag_command *cmd) /* Allocate TDO buffer if required */ if (type == SCAN_IN || type == SCAN_IO) { - tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); + tdo_buffer_start = calloc(scan_size_bytes, sizeof(uint8_t)); if (!tdo_buffer_start) return ERROR_FAIL; diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index a0b120b..1793cbf 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1228,7 +1228,7 @@ COMMAND_HANDLER(ftdi_handle_get_signal_command) uint16_t sig_data = 0; sig = find_signal_by_name(CMD_ARGV[0]); if (!sig) { - LOG_ERROR("interface configuration doesn't define signal '%s'", CMD_ARGV[0]); + command_print(CMD, "interface configuration doesn't define signal '%s'", CMD_ARGV[0]); return ERROR_FAIL; } @@ -1236,7 +1236,7 @@ COMMAND_HANDLER(ftdi_handle_get_signal_command) if (ret != ERROR_OK) return ret; - LOG_USER("Signal %s = %#06x", sig->name, sig_data); + command_print(CMD, "%#06x", sig_data); return ERROR_OK; } diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index 4fdb857..66cf25a 100644 --- a/src/jtag/drivers/nulink_usb.c +++ b/src/jtag/drivers/nulink_usb.c @@ -34,7 +34,7 @@ #define NULINK2_USB_PID1 (0x5200) #define NULINK2_USB_PID2 (0x5201) -struct nulink_usb_handle_s { +struct nulink_usb_handle { hid_device *dev_handle; uint16_t max_packet_size; uint8_t usbcmdidx; @@ -87,7 +87,7 @@ enum nulink_connect { static int nulink_usb_xfer_rw(void *handle, uint8_t *buf) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -107,7 +107,7 @@ static int nulink_usb_xfer_rw(void *handle, uint8_t *buf) static int nulink1_usb_xfer(void *handle, uint8_t *buf, int size) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -120,7 +120,7 @@ static int nulink1_usb_xfer(void *handle, uint8_t *buf, int size) static int nulink2_usb_xfer(void *handle, uint8_t *buf, int size) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -133,7 +133,7 @@ static int nulink2_usb_xfer(void *handle, uint8_t *buf, int size) static void nulink1_usb_init_buffer(void *handle, uint32_t size) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; h->cmdidx = 0; @@ -149,7 +149,7 @@ static void nulink1_usb_init_buffer(void *handle, uint32_t size) static void nulink2_usb_init_buffer(void *handle, uint32_t size) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; h->cmdidx = 0; @@ -165,7 +165,7 @@ static void nulink2_usb_init_buffer(void *handle, uint32_t size) static inline int nulink_usb_xfer(void *handle, uint8_t *buf, int size) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -174,7 +174,7 @@ static inline int nulink_usb_xfer(void *handle, uint8_t *buf, int size) static inline void nulink_usb_init_buffer(void *handle, uint32_t size) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -183,7 +183,7 @@ static inline void nulink_usb_init_buffer(void *handle, uint32_t size) static int nulink_usb_version(void *handle) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_version"); @@ -219,7 +219,7 @@ static int nulink_usb_version(void *handle) static int nulink_usb_idcode(void *handle, uint32_t *idcode) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_idcode"); @@ -243,7 +243,7 @@ static int nulink_usb_idcode(void *handle, uint32_t *idcode) static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 " 0x%08" PRIX32, addr, val); @@ -278,7 +278,7 @@ static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) static enum target_state nulink_usb_state(void *handle) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -299,7 +299,7 @@ static enum target_state nulink_usb_state(void *handle) static int nulink_usb_assert_srst(void *handle, int srst) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_assert_srst"); @@ -324,7 +324,7 @@ static int nulink_usb_assert_srst(void *handle, int srst) static int nulink_usb_reset(void *handle) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_reset"); @@ -349,7 +349,7 @@ static int nulink_usb_reset(void *handle) static int nulink_usb_run(void *handle) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_run"); @@ -365,7 +365,7 @@ static int nulink_usb_run(void *handle) static int nulink_usb_halt(void *handle) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_halt"); @@ -385,7 +385,7 @@ static int nulink_usb_halt(void *handle) static int nulink_usb_step(void *handle) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_step"); @@ -405,7 +405,7 @@ static int nulink_usb_step(void *handle) static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -444,7 +444,7 @@ static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) static int nulink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -483,7 +483,7 @@ static int nulink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, int res = ERROR_OK; uint32_t offset = 0; uint32_t bytes_remaining = 12; - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_read_mem8: addr 0x%08" PRIx32 ", len %" PRId16, addr, len); @@ -568,7 +568,7 @@ static int nulink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, int res = ERROR_OK; uint32_t offset = 0; uint32_t bytes_remaining = 12; - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_write_mem8: addr 0x%08" PRIx32 ", len %" PRIu16, addr, len); @@ -675,7 +675,7 @@ static int nulink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, { int res = ERROR_OK; uint32_t bytes_remaining = 12; - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -744,7 +744,7 @@ static int nulink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, { int res = ERROR_OK; uint32_t bytes_remaining = 12; - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; assert(handle); @@ -819,7 +819,7 @@ static int nulink_usb_read_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; /* calculate byte count */ count *= size; @@ -879,7 +879,7 @@ static int nulink_usb_write_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; if (addr < ARM_SRAM_BASE) { LOG_DEBUG("nulink_usb_write_mem: address below ARM_SRAM_BASE, not supported.\n"); @@ -950,7 +950,7 @@ static int nulink_usb_override_target(const char *targetname) static int nulink_speed(void *handle, int khz, bool query) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; unsigned long max_ice_clock = khz; LOG_DEBUG("nulink_speed: query %s", query ? "yes" : "no"); @@ -1004,7 +1004,7 @@ static int nulink_speed(void *handle, int khz, bool query) static int nulink_usb_close(void *handle) { - struct nulink_usb_handle_s *h = handle; + struct nulink_usb_handle *h = handle; LOG_DEBUG("nulink_usb_close"); @@ -1018,7 +1018,7 @@ static int nulink_usb_close(void *handle) return ERROR_OK; } -static int nulink_usb_open(struct hl_interface_param_s *param, void **fd) +static int nulink_usb_open(struct hl_interface_param *param, void **fd) { struct hid_device_info *devs, *cur_dev; uint16_t target_vid = 0; @@ -1040,7 +1040,7 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd) return ERROR_FAIL; } - struct nulink_usb_handle_s *h = calloc(1, sizeof(*h)); + struct nulink_usb_handle *h = calloc(1, sizeof(*h)); if (!h) { LOG_ERROR("Out of memory"); goto error_open; @@ -1154,7 +1154,7 @@ error_open: return ERROR_FAIL; } -struct hl_layout_api_s nulink_usb_layout_api = { +struct hl_layout_api nulink_usb_layout_api = { .open = nulink_usb_open, .close = nulink_usb_close, .idcode = nulink_usb_idcode, diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index 53d2151..edd36f2 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -114,12 +114,18 @@ static int remote_bitbang_fill_buf(enum block_bool block) contiguous_available_space); if (first && block == BLOCK) socket_nonblock(remote_bitbang_fd); - first = false; if (count > 0) { remote_bitbang_recv_buf_end += count; if (remote_bitbang_recv_buf_end == sizeof(remote_bitbang_recv_buf)) remote_bitbang_recv_buf_end = 0; } else if (count == 0) { + /* When read_socket returns 0, socket reached EOF and there is + * no data to read. But if request was blocking, the caller + * expected some data. Such situations should be treated as ERROR. */ + if (first && block == BLOCK) { + LOG_ERROR("remote_bitbang: socket closed by remote"); + return ERROR_FAIL; + } return ERROR_OK; } else if (count < 0) { #ifdef _WIN32 @@ -133,6 +139,7 @@ static int remote_bitbang_fill_buf(enum block_bool block) return ERROR_FAIL; } } + first = false; } return ERROR_OK; diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 1b1f2e4..afdf16e 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -286,13 +286,13 @@ static uint8_t dtc_entry_download; static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const uint8_t *buffer, size_t length) { - struct header_s { + struct header { uint8_t type; uint8_t length; }; int usb_err; - struct header_s *header; + struct header *header; uint8_t lut_start = 0xc0; dtc_entry_download = 0; @@ -311,7 +311,7 @@ static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const u exit(1); } - header = (struct header_s *)buffer; + header = (struct header *)buffer; buffer += sizeof(*header); length -= sizeof(*header); diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index b14fbf1..8cf3b0c 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -140,7 +140,7 @@ struct stlink_usb_version { uint32_t flags; }; -struct stlink_usb_priv_s { +struct stlink_usb_priv { /** */ struct libusb_device_handle *fd; /** */ @@ -154,7 +154,7 @@ struct stlink_tcp_version { uint32_t build; }; -struct stlink_tcp_priv_s { +struct stlink_tcp_priv { /** */ int fd; /** */ @@ -171,9 +171,9 @@ struct stlink_tcp_priv_s { struct stlink_tcp_version version; }; -struct stlink_backend_s { +struct stlink_backend { /** */ - int (*open)(void *handle, struct hl_interface_param_s *param); + int (*open)(void *handle, struct hl_interface_param *param); /** */ int (*close)(void *handle); /** */ @@ -245,13 +245,13 @@ struct dap_queue { }; /** */ -struct stlink_usb_handle_s { +struct stlink_usb_handle { /** */ - struct stlink_backend_s *backend; + struct stlink_backend *backend; /** */ union { - struct stlink_usb_priv_s usb_backend_priv; - struct stlink_tcp_priv_s tcp_backend_priv; + struct stlink_usb_priv usb_backend_priv; + struct stlink_tcp_priv tcp_backend_priv; }; /** */ uint8_t rx_ep; @@ -294,22 +294,22 @@ struct stlink_usb_handle_s { }; /** */ -static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param) +static inline int stlink_usb_open(void *handle, struct hl_interface_param *param) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; return h->backend->open(handle, param); } /** */ static inline int stlink_usb_close(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; return h->backend->close(handle); } /** */ static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; return h->backend->xfer_noerrcheck(handle, buf, size); } @@ -567,7 +567,7 @@ static int stlink_usb_open_ap(void *handle, unsigned short apsel); /** */ static unsigned int stlink_usb_block(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -727,7 +727,7 @@ static int jtag_libusb_bulk_transfer_n( /** */ static int stlink_usb_xfer_v1_get_status(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int tr, ret; assert(handle); @@ -762,7 +762,7 @@ static int stlink_usb_xfer_v1_get_status(void *handle) #ifdef USE_LIBUSB_ASYNCIO static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -800,7 +800,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int #else static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int tr, ret; assert(handle); @@ -834,7 +834,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int static int stlink_usb_xfer_v1_get_sense(void *handle) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -860,7 +860,7 @@ static int stlink_usb_xfer_v1_get_sense(void *handle) /** */ static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int tr, ret; ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size, @@ -882,7 +882,7 @@ static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size) static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { int err, cmdsize = STLINK_CMD_SIZE_V2; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -915,7 +915,7 @@ static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool check_tcp_status) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -980,7 +980,7 @@ static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool /** */ static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int send_size = STLINK_TCP_USB_CMD_SIZE; int recv_size = STLINK_TCP_SS_SIZE; @@ -1040,7 +1040,7 @@ static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size /** */ static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; stlink_usb_init_buffer(h, h->trace_ep, 0); return stlink_tcp_xfer_noerrcheck(handle, buf, size); @@ -1052,7 +1052,7 @@ static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size) */ static int stlink_usb_error_check(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1162,7 +1162,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) { int retries = 0; int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; while (1) { if ((h->st_mode != STLINK_MODE_DEBUG_SWIM) || !retries) { @@ -1191,7 +1191,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size) /** */ static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1206,14 +1206,14 @@ static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size) */ static void stlink_usb_set_cbw_transfer_datalength(void *handle, uint32_t size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; buf_set_u32(h->cmdbuf+8, 0, 32, size); } static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; /* fill the send buffer */ strcpy((char *)h->cmdbuf, "USBC"); @@ -1234,7 +1234,7 @@ static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint3 /** */ static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; h->direction = direction; @@ -1256,7 +1256,7 @@ static int stlink_usb_version(void *handle) uint8_t v, x, y, jtag, swim, msd, bridge = 0; char v_str[5 * (1 + 3) + 1]; /* VvJjMmBbSs */ char *p; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1479,7 +1479,7 @@ static int stlink_usb_version(void *handle) static int stlink_usb_check_voltage(void *handle, float *target_voltage) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; uint32_t adc_results[2]; /* no error message, simply quit with error */ @@ -1511,7 +1511,7 @@ static int stlink_usb_check_voltage(void *handle, float *target_voltage) static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1535,7 +1535,7 @@ static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor) static int stlink_usb_set_jtagclk(void *handle, uint16_t clk_divisor) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1561,7 +1561,7 @@ static int stlink_usb_set_jtagclk(void *handle, uint16_t clk_divisor) static int stlink_usb_current_mode(void *handle, uint8_t *mode) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1583,7 +1583,7 @@ static int stlink_usb_current_mode(void *handle, uint8_t *mode) static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) { int rx_size = 0; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1631,7 +1631,7 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1725,7 +1725,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init int res; uint8_t mode; enum stlink_mode emode; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -1829,7 +1829,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init /* request status from last swim request */ static int stlink_swim_status(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 4); @@ -1849,7 +1849,7 @@ static int stlink_swim_status(void *handle) __attribute__((unused)) static int stlink_swim_cap(void *handle, uint8_t *cap) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 8); @@ -1866,7 +1866,7 @@ static int stlink_swim_cap(void *handle, uint8_t *cap) /* debug dongle assert/deassert sreset line */ static int stlink_swim_assert_reset(void *handle, int reset) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); @@ -1887,7 +1887,7 @@ static int stlink_swim_assert_reset(void *handle, int reset) */ static int stlink_swim_enter(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); @@ -1902,7 +1902,7 @@ static int stlink_swim_enter(void *handle) /* switch high/low speed swim */ static int stlink_swim_speed(void *handle, int speed) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); @@ -1924,7 +1924,7 @@ static int stlink_swim_speed(void *handle, int speed) */ static int stlink_swim_generate_rst(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); @@ -1943,7 +1943,7 @@ static int stlink_swim_generate_rst(void *handle) */ static int stlink_swim_resync(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; stlink_usb_init_buffer(handle, h->rx_ep, 0); @@ -1957,7 +1957,7 @@ static int stlink_swim_resync(void *handle) static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, const uint8_t *data) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; unsigned int i; unsigned int datalen = 0; @@ -1993,7 +1993,7 @@ static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, con static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint8_t *data) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; if (len > STLINK_SWIM_DATA_SIZE) @@ -2024,7 +2024,7 @@ static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint static int stlink_usb_idcode(void *handle, uint32_t *idcode) { int res, offset; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2061,7 +2061,7 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode) static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *val) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int res; assert(handle); @@ -2083,7 +2083,7 @@ static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *v static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2105,7 +2105,7 @@ static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) /** */ static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2156,7 +2156,7 @@ static enum target_state stlink_usb_v2_get_status(void *handle) static enum target_state stlink_usb_state(void *handle) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2198,7 +2198,7 @@ static enum target_state stlink_usb_state(void *handle) static int stlink_usb_assert_srst(void *handle, int srst) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2221,7 +2221,7 @@ static int stlink_usb_assert_srst(void *handle, int srst) static void stlink_usb_trace_disable(void *handle) { int res = ERROR_OK; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2243,7 +2243,7 @@ static void stlink_usb_trace_disable(void *handle) static int stlink_usb_trace_enable(void *handle) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2274,7 +2274,7 @@ static int stlink_usb_trace_enable(void *handle) /** */ static int stlink_usb_reset(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int retval; assert(handle); @@ -2304,7 +2304,7 @@ static int stlink_usb_reset(void *handle) static int stlink_usb_run(void *handle) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2326,7 +2326,7 @@ static int stlink_usb_run(void *handle) static int stlink_usb_halt(void *handle) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2347,7 +2347,7 @@ static int stlink_usb_halt(void *handle) /** */ static int stlink_usb_step(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2371,7 +2371,7 @@ static int stlink_usb_step(void *handle) static int stlink_usb_read_regs(void *handle) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2396,7 +2396,7 @@ static int stlink_usb_read_regs(void *handle) static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2436,7 +2436,7 @@ static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) /** */ static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2465,7 +2465,7 @@ static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) static int stlink_usb_get_rw_status(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2490,7 +2490,7 @@ static int stlink_usb_read_mem8(void *handle, uint8_t ap_num, uint32_t csw, { int res; uint16_t read_len = len; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2534,7 +2534,7 @@ static int stlink_usb_write_mem8(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2572,7 +2572,7 @@ static int stlink_usb_read_mem16(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, uint8_t *buffer) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2620,7 +2620,7 @@ static int stlink_usb_write_mem16(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2666,7 +2666,7 @@ static int stlink_usb_read_mem32(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, uint8_t *buffer) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2711,7 +2711,7 @@ static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -2752,7 +2752,7 @@ static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw, static int stlink_usb_read_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, uint8_t *buffer) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle != NULL); @@ -2794,7 +2794,7 @@ static int stlink_usb_read_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_ static int stlink_usb_write_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw, uint32_t addr, uint16_t len, const uint8_t *buffer) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle != NULL); @@ -2845,7 +2845,7 @@ static int stlink_usb_read_ap_mem(void *handle, uint8_t ap_num, uint32_t csw, int retval = ERROR_OK; uint32_t bytes_remaining; int retries = 0; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; /* calculate byte count */ count *= size; @@ -2930,7 +2930,7 @@ static int stlink_usb_write_ap_mem(void *handle, uint8_t ap_num, uint32_t csw, int retval = ERROR_OK; uint32_t bytes_remaining; int retries = 0; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; /* calculate byte count */ count *= size; @@ -3080,7 +3080,7 @@ static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_ static int stlink_speed_swd(void *handle, int khz, bool query) { int speed_index; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; /* old firmware cannot change it */ if (!(h->version.flags & STLINK_F_HAS_SWD_SET_FREQ)) @@ -3103,7 +3103,7 @@ static int stlink_speed_swd(void *handle, int khz, bool query) static int stlink_speed_jtag(void *handle, int khz, bool query) { int speed_index; - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; /* old firmware cannot change it */ if (!(h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ)) @@ -3135,7 +3135,7 @@ static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_ static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int i; if (h->version.jtag_api != STLINK_JTAG_API_V3) { @@ -3170,7 +3170,7 @@ static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map static int stlink_set_com_freq(void *handle, bool is_jtag, unsigned int frequency) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; if (h->version.jtag_api != STLINK_JTAG_API_V3) { LOG_ERROR("Unknown command"); @@ -3191,7 +3191,7 @@ static int stlink_set_com_freq(void *handle, bool is_jtag, unsigned int frequenc static int stlink_speed_v3(void *handle, bool is_jtag, int khz, bool query) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int speed_index; struct speed_map map[STLINK_V3_MAX_FREQ_NB]; @@ -3211,7 +3211,7 @@ static int stlink_speed_v3(void *handle, bool is_jtag, int khz, bool query) static int stlink_speed(void *handle, int khz, bool query) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; if (!handle) return khz; @@ -3241,7 +3241,7 @@ static int stlink_speed(void *handle, int khz, bool query) /** */ static int stlink_usb_usb_close(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; if (!h) return ERROR_OK; @@ -3262,7 +3262,7 @@ static int stlink_usb_usb_close(void *handle) /** */ static int stlink_tcp_close(void *handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; if (!h) return ERROR_OK; @@ -3295,7 +3295,7 @@ static int stlink_tcp_close(void *handle) static int stlink_close(void *handle) { if (handle) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; stlink_usb_close(handle); @@ -3385,9 +3385,9 @@ static char *stlink_usb_get_alternate_serial(struct libusb_device_handle *device } /** */ -static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) +static int stlink_usb_usb_open(void *handle, struct hl_interface_param *param) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int err, retry_count = 1; h->cmdbuf = malloc(STLINK_SG_SIZE); @@ -3496,9 +3496,9 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) } /** */ -static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param) +static int stlink_tcp_open(void *handle, struct hl_interface_param *param) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int ret; /* SWIM is not supported using stlink-server */ @@ -3711,27 +3711,27 @@ static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param) return stlink_usb_version(h); } -static struct stlink_backend_s stlink_usb_backend = { +static struct stlink_backend stlink_usb_backend = { .open = stlink_usb_usb_open, .close = stlink_usb_usb_close, .xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck, .read_trace = stlink_usb_usb_read_trace, }; -static struct stlink_backend_s stlink_tcp_backend = { +static struct stlink_backend stlink_tcp_backend = { .open = stlink_tcp_open, .close = stlink_tcp_close, .xfer_noerrcheck = stlink_tcp_xfer_noerrcheck, .read_trace = stlink_tcp_read_trace, }; -static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) +static int stlink_open(struct hl_interface_param *param, enum stlink_mode mode, void **fd) { - struct stlink_usb_handle_s *h; + struct stlink_usb_handle *h; LOG_DEBUG("stlink_open"); - h = calloc(1, sizeof(struct stlink_usb_handle_s)); + h = calloc(1, sizeof(struct stlink_usb_handle)); if (!h) { LOG_DEBUG("malloc failed"); @@ -3829,7 +3829,7 @@ error_open: return ERROR_FAIL; } -static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd) +static int stlink_usb_hl_open(struct hl_interface_param *param, void **fd) { return stlink_open(param, stlink_get_mode(param->transport), fd); } @@ -3839,7 +3839,7 @@ static int stlink_config_trace(void *handle, bool enabled, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; if (!(h->version.flags & STLINK_F_HAS_TRACE)) { LOG_ERROR("The attached ST-LINK version doesn't support trace"); @@ -3900,7 +3900,7 @@ static int stlink_config_trace(void *handle, bool enabled, /** */ static int stlink_usb_init_access_port(void *handle, unsigned char ap_num) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -3919,7 +3919,7 @@ static int stlink_usb_init_access_port(void *handle, unsigned char ap_num) /** */ static int stlink_usb_close_access_port(void *handle, unsigned char ap_num) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -3942,7 +3942,7 @@ static int stlink_usb_close_access_port(void *handle, unsigned char ap_num) static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *buffer) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; unsigned int buflen = ALIGN_UP(items, 4) + 4 * items; LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items); @@ -3963,7 +3963,7 @@ static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *b static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; unsigned int buflen = 2 * 4 * items; LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items); @@ -3991,7 +3991,7 @@ static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer) static int stlink_read_dap_register(void *handle, unsigned short dap_port, unsigned short addr, uint32_t *val) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int retval; assert(handle); @@ -4015,7 +4015,7 @@ static int stlink_read_dap_register(void *handle, unsigned short dap_port, static int stlink_write_dap_register(void *handle, unsigned short dap_port, unsigned short addr, uint32_t val) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; assert(handle); @@ -4033,7 +4033,7 @@ static int stlink_write_dap_register(void *handle, unsigned short dap_port, } /** */ -struct hl_layout_api_s stlink_usb_layout_api = { +struct hl_layout_api stlink_usb_layout_api = { /** */ .open = stlink_usb_hl_open, /** */ @@ -4078,8 +4078,8 @@ struct hl_layout_api_s stlink_usb_layout_api = { * DAP direct interface */ -static struct stlink_usb_handle_s *stlink_dap_handle; -static struct hl_interface_param_s stlink_dap_param; +static struct stlink_usb_handle *stlink_dap_handle; +static struct hl_interface_param stlink_dap_param; static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1); static uint32_t last_csw_default[DP_APSEL_MAX + 1]; static int stlink_dap_error = ERROR_OK; @@ -4107,7 +4107,7 @@ static int stlink_dap_get_error(void) static int stlink_usb_open_ap(void *handle, unsigned short apsel) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; int retval; /* nothing to do on old versions */ @@ -4523,7 +4523,7 @@ static int stlink_usb_buf_rw_segment(void *handle, const struct dap_queue *q, un static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *q, unsigned int len, unsigned int *pkt_items) { - struct stlink_usb_handle_s *h = handle; + struct stlink_usb_handle *h = handle; unsigned int i, items = 0; uint32_t ap_num = DP_APSEL_INVALID; unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE; @@ -5039,7 +5039,7 @@ COMMAND_HANDLER(stlink_dap_backend_command) COMMAND_HANDLER(stlink_dap_cmd_command) { unsigned int rx_n, tx_n; - struct stlink_usb_handle_s *h = stlink_dap_handle; + struct stlink_usb_handle *h = stlink_dap_handle; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 4260e2d..0e01171 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -33,7 +33,7 @@ #define PACKET_START "$" #define PACKET_END "#" -struct icdi_usb_handle_s { +struct icdi_usb_handle { struct libusb_device_handle *usb_dev; char *read_buffer; @@ -108,7 +108,7 @@ static int remote_unescape_input(const char *buffer, int len, char *out_buf, int static int icdi_send_packet(void *handle, int len) { unsigned char cksum = 0; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; int result, retry = 0; int transferred = 0; @@ -220,7 +220,7 @@ static int icdi_send_packet(void *handle, int len) static int icdi_send_cmd(void *handle, const char *cmd) { - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd); return icdi_send_packet(handle, cmd_len); @@ -228,7 +228,7 @@ static int icdi_send_cmd(void *handle, const char *cmd) static int icdi_send_remote_cmd(void *handle, const char *data) { - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,"); cmd_len += hexify(h->write_buffer + cmd_len, (const uint8_t *)data, @@ -239,7 +239,7 @@ static int icdi_send_remote_cmd(void *handle, const char *data) static int icdi_get_cmd_result(void *handle) { - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; int offset = 0; char ch; @@ -284,7 +284,7 @@ static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) static enum target_state icdi_usb_state(void *handle) { int result; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; uint32_t dhcsr; uint8_t buf[4]; @@ -303,7 +303,7 @@ static enum target_state icdi_usb_state(void *handle) static int icdi_usb_version(void *handle) { - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; char version[20]; @@ -335,7 +335,7 @@ static int icdi_usb_query(void *handle) { int result; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; result = icdi_send_cmd(handle, "qSupported"); if (result != ERROR_OK) @@ -468,7 +468,7 @@ static int icdi_usb_read_regs(void *handle) static int icdi_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int result; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; char cmd[10]; snprintf(cmd, sizeof(cmd), "p%x", regsel); @@ -521,7 +521,7 @@ static int icdi_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer) { int result; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; char cmd[20]; snprintf(cmd, sizeof(cmd), "x%" PRIx32 ",%" PRIx32, addr, len); @@ -549,7 +549,7 @@ static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint static int icdi_usb_write_mem_int(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer) { int result; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%" PRIx32 ",%" PRIx32 ":", addr, len); @@ -581,7 +581,7 @@ static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { int retval = ERROR_OK; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; uint32_t bytes_remaining; /* calculate byte count */ @@ -609,7 +609,7 @@ static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval = ERROR_OK; - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; uint32_t bytes_remaining; /* calculate byte count */ @@ -640,7 +640,7 @@ static int icdi_usb_override_target(const char *targetname) static int icdi_usb_close(void *handle) { - struct icdi_usb_handle_s *h = handle; + struct icdi_usb_handle *h = handle; if (!h) return ERROR_OK; @@ -654,15 +654,15 @@ static int icdi_usb_close(void *handle) return ERROR_OK; } -static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) +static int icdi_usb_open(struct hl_interface_param *param, void **fd) { /* TODO: Convert remaining libusb_ calls to jtag_libusb_ */ int retval; - struct icdi_usb_handle_s *h; + struct icdi_usb_handle *h; LOG_DEBUG("icdi_usb_open"); - h = calloc(1, sizeof(struct icdi_usb_handle_s)); + h = calloc(1, sizeof(struct icdi_usb_handle)); if (!h) { LOG_ERROR("unable to allocate memory"); @@ -743,7 +743,7 @@ error_open: return ERROR_FAIL; } -struct hl_layout_api_s icdi_usb_layout_api = { +struct hl_layout_api icdi_usb_layout_api = { .open = icdi_usb_open, .close = icdi_usb_close, .idcode = icdi_usb_idcode, diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 4f23c6c..0fe8989 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -1473,7 +1473,7 @@ static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) /* Allocate TDO buffer if required */ if ((type == SCAN_IN) || (type == SCAN_IO)) { - tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); + tdo_buffer_start = calloc(scan_size_bytes, sizeof(uint8_t)); if (!tdo_buffer_start) return ERROR_FAIL; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 9c8d0fa..6ac6801 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -23,7 +23,7 @@ #include <target/target.h> -static struct hl_interface_s hl_if = { +static struct hl_interface hl_if = { .param = { .device_desc = NULL, .vid = { 0 }, diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index fa49658..c95638b 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -20,7 +20,7 @@ extern const char *hl_transports[]; #define HLA_MAX_USB_IDS 16 -struct hl_interface_param_s { +struct hl_interface_param { /** */ const char *device_desc; /** List of recognised VIDs */ @@ -39,9 +39,9 @@ struct hl_interface_param_s { uint16_t stlink_tcp_port; }; -struct hl_interface_s { +struct hl_interface { /** */ - struct hl_interface_param_s param; + struct hl_interface_param param; /** */ const struct hl_layout *layout; /** */ diff --git a/src/jtag/hla/hla_layout.c b/src/jtag/hla/hla_layout.c index 51671d6..04c963f 100644 --- a/src/jtag/hla/hla_layout.c +++ b/src/jtag/hla/hla_layout.c @@ -21,7 +21,7 @@ #include <jtag/hla/hla_transport.h> #include <jtag/hla/hla_interface.h> -static int hl_layout_open(struct hl_interface_s *adapter) +static int hl_layout_open(struct hl_interface *adapter) { int res; @@ -39,7 +39,7 @@ static int hl_layout_open(struct hl_interface_s *adapter) return ERROR_OK; } -static int hl_layout_close(struct hl_interface_s *adapter) +static int hl_layout_close(struct hl_interface *adapter) { return ERROR_OK; } @@ -78,7 +78,7 @@ const struct hl_layout *hl_layout_get_list(void) return hl_layouts; } -int hl_layout_init(struct hl_interface_s *adapter) +int hl_layout_init(struct hl_interface *adapter) { LOG_DEBUG("hl_layout_init"); diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index e13da65..71a7563 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -15,18 +15,18 @@ #include <target/arm_tpiu_swo.h> /** */ -struct hl_interface_s; -struct hl_interface_param_s; +struct hl_interface; +struct hl_interface_param; /** */ -extern struct hl_layout_api_s stlink_usb_layout_api; -extern struct hl_layout_api_s icdi_usb_layout_api; -extern struct hl_layout_api_s nulink_usb_layout_api; +extern struct hl_layout_api stlink_usb_layout_api; +extern struct hl_layout_api icdi_usb_layout_api; +extern struct hl_layout_api nulink_usb_layout_api; /** */ -struct hl_layout_api_s { +struct hl_layout_api { /** */ - int (*open)(struct hl_interface_param_s *param, void **handle); + int (*open)(struct hl_interface_param *param, void **handle); /** */ int (*close)(void *handle); /** */ @@ -121,16 +121,16 @@ struct hl_layout { /** */ char *name; /** */ - int (*open)(struct hl_interface_s *adapter); + int (*open)(struct hl_interface *adapter); /** */ - int (*close)(struct hl_interface_s *adapter); + int (*close)(struct hl_interface *adapter); /** */ - struct hl_layout_api_s *api; + struct hl_layout_api *api; }; /** */ const struct hl_layout *hl_layout_get_list(void); /** */ -int hl_layout_init(struct hl_interface_s *adapter); +int hl_layout_init(struct hl_interface *adapter); #endif /* OPENOCD_JTAG_HLA_HLA_LAYOUT_H */ diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 7995529..1a4c4b7 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -760,8 +760,9 @@ static const struct command_registration jtag_subcommand_handlers[] = { .mode = COMMAND_EXEC, .handler = handle_jtag_configure, .help = "Return any Tcl handler for the specified " - "TAP event.", - .usage = "tap_name '-event' event_name", + "TAP event or the value of the IDCODE found in hardware.", + .usage = "tap_name '-event' event_name | " + "tap_name '-idcode'", }, { .name = "names", diff --git a/src/pld/intel.c b/src/pld/intel.c index a39e16c..a4bdabe 100644 --- a/src/pld/intel.c +++ b/src/pld/intel.c @@ -37,142 +37,11 @@ struct intel_pld_device { enum intel_family_e family; }; -struct intel_device_parameters_elem { - uint32_t id; - unsigned int boundary_scan_length; - int checkpos; - enum intel_family_e family; -}; - -static const struct intel_device_parameters_elem intel_device_parameters[] = { - {0x020f10dd, 603, 226, INTEL_CYCLONEIII}, /* EP3C5 EP3C10 */ - {0x020f20dd, 1080, 409, INTEL_CYCLONEIII}, /* EP3C16 */ - {0x020f30dd, 732, 286, INTEL_CYCLONEIII}, /* EP3C25 */ - {0x020f40dd, 1632, 604, INTEL_CYCLONEIII}, /* EP3C40 */ - {0x020f50dd, 1164, 442, INTEL_CYCLONEIII}, /* EP3C55 */ - {0x020f60dd, 1314, 502, INTEL_CYCLONEIII}, /* EP3C80 */ - {0x020f70dd, 1620, 613, INTEL_CYCLONEIII}, /* EP3C120*/ - {0x027010dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS70 */ - {0x027000dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS100 */ - {0x027030dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS150 */ - {0x027020dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS200 */ - - {0x020f10dd, 603, 226, INTEL_CYCLONEIV}, /* EP4CE6 EP4CE10 */ - {0x020f20dd, 1080, 409, INTEL_CYCLONEIV}, /* EP4CE15 */ - {0x020f30dd, 732, 286, INTEL_CYCLONEIV}, /* EP4CE22 */ - {0x020f40dd, 1632, 604, INTEL_CYCLONEIV}, /* EP4CE30 EP4CE40 */ - {0x020f50dd, 1164, 442, INTEL_CYCLONEIV}, /* EP4CE55 */ - {0x020f60dd, 1314, 502, INTEL_CYCLONEIV}, /* EP4CE75 */ - {0x020f70dd, 1620, 613, INTEL_CYCLONEIV}, /* EP4CE115 */ - {0x028010dd, 260, 229, INTEL_CYCLONEIV}, /* EP4CGX15 */ - {0x028120dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX22 */ - {0x028020dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX30 */ - {0x028230dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX30 */ - {0x028130dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX50 */ - {0x028030dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX75 */ - {0x028140dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX110 */ - {0x028040dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX150 */ - - {0x02b150dd, 864, 163, INTEL_CYCLONEV}, /* 5CEBA2F23 5CEBA2F17 5CEFA2M13 5CEFA2F23 5CEBA2U15 5CEFA2U19 5CEBA2U19 */ - {0x02d020dd, 1485, 19, INTEL_CYCLONEV}, /* 5CSXFC6D6F31 5CSTFD6D5F31 5CSEBA6U23 5CSEMA6U23 5CSEBA6U19 5CSEBA6U23 - 5CSEBA6U19 5CSEMA6F31 5CSXFC6C6U23 */ - {0x02b040dd, 1728, -1, INTEL_CYCLONEV}, /* 5CGXFC9EF35 5CGXBC9AU19 5CGXBC9CF23 5CGTFD9CF23 5CGXFC9AU19 5CGXFC9CF23 - 5CGXFC9EF31 5CGXFC9DF27 5CGXBC9DF27 5CGXBC9EF31 5CGTFD9EF31 5CGTFD9EF35 - 5CGTFD9AU19 5CGXBC9EF35 5CGTFD9DF27 */ - {0x02b050dd, 864, 163, INTEL_CYCLONEV}, /* 5CEFA4U19 5CEFA4F23 5CEFA4M13 5CEBA4F17 5CEBA4U15 5CEBA4U19 5CEBA4F23 */ - {0x02b030dd, 1488, 19, INTEL_CYCLONEV}, /* 5CGXBC7CU19 5CGTFD7CU19 5CGTFD7DF27 5CGXFC7BM15 5CGXFC7DF27 5CGXFC7DF31 - 5CGTFD7CF23 5CGXBC7CF23 5CGXBC7DF31 5CGTFD7BM15 5CGXFC7CU19 5CGTFD7DF31 - 5CGXBC7BM15 5CGXFC7CF23 5CGXBC7DF27 */ - {0x02d120dd, 1485, -1, INTEL_CYCLONEV}, /* 5CSEBA5U23 5CSEBA5U23 5CSTFD5D5F31 5CSEBA5U19 5CSXFC5D6F31 5CSEMA5U23 - 5CSEMA5F31 5CSXFC5C6U23 5CSEBA5U19 */ - {0x02b220dd, 1104, 19, INTEL_CYCLONEV}, /* 5CEBA5U19 5CEFA5U19 5CEFA5M13 5CEBA5F23 5CEFA5F23 */ - {0x02b020dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXBC5CU19 5CGXFC5F6M11 5CGXFC5CM13 5CGTFD5CF23 5CGXBC5CF23 5CGTFD5CF27 - 5CGTFD5F5M11 5CGXFC5CF27 5CGXFC5CU19 5CGTFD5CM13 5CGXFC5CF23 5CGXBC5CF27 - 5CGTFD5CU19 */ - {0x02d010dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA4U23 5CSXFC4C6U23 5CSEMA4U23 5CSEBA4U23 5CSEBA4U19 5CSEBA4U19 - 5CSXFC2C6U23 */ - {0x02b120dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXFC4CM13 5CGXFC4CU19 5CGXFC4F6M11 5CGXBC4CU19 5CGXFC4CF27 5CGXBC4CF23 - 5CGXBC4CF27 5CGXFC4CF23 */ - {0x02b140dd, 1728, -1, INTEL_CYCLONEV}, /* 5CEFA9F31 5CEBA9F31 5CEFA9F27 5CEBA9U19 5CEBA9F27 5CEFA9U19 5CEBA9F23 - 5CEFA9F23 */ - {0x02b010dd, 720, 19, INTEL_CYCLONEV}, /* 5CGXFC3U15 5CGXBC3U15 5CGXFC3F23 5CGXFC3U19 5CGXBC3U19 5CGXBC3F23 */ - {0x02b130dd, 1488, 19, INTEL_CYCLONEV}, /* 5CEFA7F31 5CEBA7F27 5CEBA7M15 5CEFA7U19 5CEBA7F23 5CEFA7F23 5CEFA7F27 - 5CEFA7M15 5CEBA7U19 5CEBA7F31 */ - {0x02d110dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA2U23 5CSEMA2U23 5CSEBA2U23 5CSEBA2U19 5CSEBA2U19 */ - - {0x020f10dd, 603, 226, INTEL_CYCLONE10}, /* 10CL006E144 10CL006U256 10CL010M164 10CL010U256 10CL010E144 */ - {0x020f20dd, 1080, 409, INTEL_CYCLONE10}, /* 10CL016U256 10CL016E144 10CL016U484 10CL016F484 10CL016M164 */ - {0x020f30dd, 732, 286, INTEL_CYCLONE10}, /* 10CL025U256 10CL025E144 */ - {0x020f40dd, 1632, 604, INTEL_CYCLONE10}, /* 10CL040F484 10CL040U484 */ - {0x020f50dd, 1164, 442, INTEL_CYCLONE10}, /* 10CL055F484 10CL055U484 */ - {0x020f60dd, 1314, 502, INTEL_CYCLONE10}, /* 10CL080F484 10CL080F780 10CL080U484 */ - {0x020f70dd, 1620, 613, INTEL_CYCLONE10}, /* 10CL120F484 10CL120F780 */ - - {0x02e120dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX085U484 10CX085F672 */ - {0x02e320dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX105F780 10CX105U484 10CX105F672 */ - {0x02e720dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX150F672 10CX150F780 10CX150U484 */ - {0x02ef20dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX220F672 10CX220F780 10CX220U484 */ - - {0x025120dd, 1227, 1174, INTEL_ARRIAII}, /* EP2AGX45 */ - {0x025020dd, 1227, -1, INTEL_ARRIAII}, /* EP2AGX65 */ - {0x025130dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX95 */ - {0x025030dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX125 */ - {0x025140dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX190 */ - {0x025040dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX260 */ - {0x024810dd, 2274, -1, INTEL_ARRIAII}, /* EP2AGZ225 */ - {0x0240a0dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ300 */ - {0x024820dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ350 */ -}; - -static int intel_fill_device_parameters(struct intel_pld_device *intel_info) -{ - for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { - if (intel_device_parameters[i].id == intel_info->tap->idcode && - intel_info->family == intel_device_parameters[i].family) { - if (intel_info->boundary_scan_length == 0) - intel_info->boundary_scan_length = intel_device_parameters[i].boundary_scan_length; - - if (intel_info->checkpos == -1) - intel_info->checkpos = intel_device_parameters[i].checkpos; - - return ERROR_OK; - } - } - - return ERROR_FAIL; -} - -static int intel_check_for_unique_id(struct intel_pld_device *intel_info) -{ - int found = 0; - for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { - if (intel_device_parameters[i].id == intel_info->tap->idcode) { - ++found; - intel_info->family = intel_device_parameters[i].family; - } - } - - return (found == 1) ? ERROR_OK : ERROR_FAIL; -} - static int intel_check_config(struct intel_pld_device *intel_info) { - if (!intel_info->tap->has_idcode) { - LOG_ERROR("no IDCODE"); - return ERROR_FAIL; - } - - if (intel_info->family == INTEL_UNKNOWN) { - if (intel_check_for_unique_id(intel_info) != ERROR_OK) { - LOG_ERROR("id is ambiguous, please specify family"); + if (intel_info->boundary_scan_length == 0) { + LOG_ERROR("unknown boundary scan length. Please specify with 'intel set_bscan'."); return ERROR_FAIL; - } - } - - if (intel_info->boundary_scan_length == 0 || intel_info->checkpos == -1) { - int ret = intel_fill_device_parameters(intel_info); - if (ret != ERROR_OK) - return ret; } if (intel_info->checkpos >= 0 && (unsigned int)intel_info->checkpos >= intel_info->boundary_scan_length) { @@ -248,9 +117,6 @@ static int intel_load(struct pld_device *pld_device, const char *filename) if (retval != ERROR_OK) return retval; - if (retval != ERROR_OK) - return retval; - retval = intel_set_instr(tap, 0x002); if (retval != ERROR_OK) { free(bit_file.data); @@ -308,6 +174,8 @@ static int intel_load(struct pld_device *pld_device, const char *filename) LOG_ERROR("Check failed"); return ERROR_FAIL; } + } else { + LOG_INFO("unable to check. Please specify with position 'intel set_check_pos'."); } retval = intel_set_instr(tap, 0x003); @@ -420,7 +288,7 @@ COMMAND_HANDLER(intel_set_check_pos_command_handler) PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command) { - if (CMD_ARGC != 4 && CMD_ARGC != 6) + if (CMD_ARGC != 6) return ERROR_COMMAND_SYNTAX_ERROR; if (strcmp(CMD_ARGV[2], "-chain-position") != 0) @@ -433,24 +301,23 @@ PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command) } enum intel_family_e family = INTEL_UNKNOWN; - if (CMD_ARGC == 6) { - if (strcmp(CMD_ARGV[4], "-family") != 0) - return ERROR_COMMAND_SYNTAX_ERROR; - - if (strcmp(CMD_ARGV[5], "cycloneiii") == 0) { - family = INTEL_CYCLONEIII; - } else if (strcmp(CMD_ARGV[5], "cycloneiv") == 0) { - family = INTEL_CYCLONEIV; - } else if (strcmp(CMD_ARGV[5], "cyclonev") == 0) { - family = INTEL_CYCLONEV; - } else if (strcmp(CMD_ARGV[5], "cyclone10") == 0) { - family = INTEL_CYCLONE10; - } else if (strcmp(CMD_ARGV[5], "arriaii") == 0) { - family = INTEL_ARRIAII; - } else { - command_print(CMD, "unknown family"); - return ERROR_FAIL; - } + + if (strcmp(CMD_ARGV[4], "-family") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[5], "cycloneiii") == 0) { + family = INTEL_CYCLONEIII; + } else if (strcmp(CMD_ARGV[5], "cycloneiv") == 0) { + family = INTEL_CYCLONEIV; + } else if (strcmp(CMD_ARGV[5], "cyclonev") == 0) { + family = INTEL_CYCLONEV; + } else if (strcmp(CMD_ARGV[5], "cyclone10") == 0) { + family = INTEL_CYCLONE10; + } else if (strcmp(CMD_ARGV[5], "arriaii") == 0) { + family = INTEL_ARRIAII; + } else { + command_print(CMD, "unknown family"); + return ERROR_FAIL; } struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device)); diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index dbbf027..f4ce5df 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1113,15 +1113,15 @@ static int gdb_new_connection(struct connection *connection) target_state_name(target)); if (!target_was_examined(target)) { - LOG_ERROR("Target %s not examined yet, refuse gdb connection %d!", - target_name(target), gdb_connection->unique_index); + LOG_TARGET_ERROR(target, "Target not examined yet, refuse gdb connection %d!", + gdb_connection->unique_index); return ERROR_TARGET_NOT_EXAMINED; } gdb_actual_connections++; if (target->state != TARGET_HALTED) - LOG_WARNING("GDB connection %d on target %s not halted", - gdb_actual_connections, target_name(target)); + LOG_TARGET_WARNING(target, "GDB connection %d not halted", + gdb_actual_connections); /* DANGER! If we fail subsequently, we must remove this handler, * otherwise we occasionally see crashes as the timer can invoke the @@ -1148,9 +1148,8 @@ static int gdb_connection_closed(struct connection *connection) log_remove_callback(gdb_log_callback, connection); gdb_actual_connections--; - LOG_DEBUG("{%d} GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", + LOG_TARGET_DEBUG(target, "{%d} GDB Close, state: %s, gdb_actual_connections=%d", gdb_connection->unique_index, - target_name(target), target_state_name(target), gdb_actual_connections); @@ -1279,6 +1278,8 @@ static int gdb_get_reg_value_as_str(struct target *target, char *tstr, struct re tstr[len] = '\0'; return ERROR_OK; } + memset(tstr, '0', len); + tstr[len] = '\0'; return ERROR_FAIL; } @@ -1323,7 +1324,9 @@ static int gdb_get_registers_packet(struct connection *connection, for (i = 0; i < reg_list_size; i++) { if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden) continue; - if (gdb_get_reg_value_as_str(target, reg_packet_p, reg_list[i]) != ERROR_OK) { + retval = gdb_get_reg_value_as_str(target, reg_packet_p, reg_list[i]); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name); free(reg_packet); free(reg_list); return gdb_error(connection, retval); @@ -1446,7 +1449,9 @@ static int gdb_get_register_packet(struct connection *connection, reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */ - if (gdb_get_reg_value_as_str(target, reg_packet, reg_list[reg_num]) != ERROR_OK) { + retval = gdb_get_reg_value_as_str(target, reg_packet, reg_list[reg_num]); + if (retval != ERROR_OK && gdb_report_register_access_error) { + LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name); free(reg_packet); free(reg_list); return gdb_error(connection, retval); @@ -2401,7 +2406,7 @@ static int smp_reg_list_noread(struct target *target, } } if (!found) { - LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); + LOG_TARGET_DEBUG(target, "%s not found in combined list", a->name); if (local_list_size >= combined_allocated) { combined_allocated *= 2; local_list = realloc(local_list, combined_allocated * sizeof(struct reg *)); @@ -2449,9 +2454,8 @@ static int smp_reg_list_noread(struct target *target, } } if (!found) { - LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where " - "this register does exist.", - a->name, target_name(head->target)); + LOG_TARGET_WARNING(head->target, "Register %s does not exist, which is part of an SMP group where " + "this register does exist.", a->name); } } free(reg_list); @@ -3083,17 +3087,17 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p target = available_target; } - LOG_DEBUG("target %s continue", target_name(target)); + LOG_TARGET_DEBUG(target, "target continue"); gdb_connection->output_flag = GDB_OUTPUT_ALL; retval = target_resume(target, 1, 0, 0, 0); if (retval == ERROR_TARGET_NOT_HALTED) - LOG_INFO("target %s was not halted when resume was requested", target_name(target)); + LOG_TARGET_INFO(target, "target was not halted when resume was requested"); /* poll target in an attempt to make its internal state consistent */ if (retval != ERROR_OK) { retval = target_poll(target); if (retval != ERROR_OK) - LOG_DEBUG("error polling target %s after failed resume", target_name(target)); + LOG_TARGET_DEBUG(target, "error polling target after failed resume"); } /* @@ -3186,7 +3190,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p } } - LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); + LOG_TARGET_DEBUG(ct, "single-step thread %" PRIx64, thread_id); gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); @@ -3229,14 +3233,14 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p } else { retval = target_step(ct, current_pc, 0, 0); if (retval == ERROR_TARGET_NOT_HALTED) - LOG_INFO("target %s was not halted when step was requested", target_name(ct)); + LOG_TARGET_INFO(ct, "target was not halted when step was requested"); } /* if step was successful send a reply back to gdb */ if (retval == ERROR_OK) { retval = target_poll(ct); if (retval != ERROR_OK) - LOG_DEBUG("error polling target %s after successful step", target_name(ct)); + LOG_TARGET_DEBUG(ct, "error polling target after successful step"); /* send back signal information */ gdb_signal_reply(ct, connection); /* stop forwarding log packets! */ @@ -3929,7 +3933,7 @@ static int gdb_target_start(struct target *target, const char *port) if (!gdb_service) return -ENOMEM; - LOG_INFO("starting gdb server for %s on %s", target_name(target), port); + LOG_TARGET_INFO(target, "starting gdb server on %s", port); gdb_service->target = target; gdb_service->core[0] = -1; @@ -3957,20 +3961,20 @@ static int gdb_target_add_one(struct target *target) /* skip targets that cannot handle a gdb connections (e.g. mem_ap) */ if (!target_supports_gdb_connection(target)) { - LOG_DEBUG("skip gdb server for target %s", target_name(target)); + LOG_TARGET_DEBUG(target, "skip gdb server"); return ERROR_OK; } if (target->gdb_port_override) { if (strcmp(target->gdb_port_override, "disabled") == 0) { - LOG_INFO("gdb port disabled"); + LOG_TARGET_INFO(target, "gdb port disabled"); return ERROR_OK; } return gdb_target_start(target, target->gdb_port_override); } - if (strcmp(gdb_port, "disabled") == 0) { - LOG_INFO("gdb port disabled"); + if (strcmp(gdb_port_next, "disabled") == 0) { + LOG_TARGET_INFO(target, "gdb port disabled"); return ERROR_OK; } @@ -3998,6 +4002,8 @@ static int gdb_target_add_one(struct target *target) gdb_port_next = strdup("0"); } } + } else if (strcmp(gdb_port_next, "pipe") == 0) { + gdb_port_next = "disabled"; } } return retval; diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c index ddb4f62..a186709 100644 --- a/src/target/arc_jtag.c +++ b/src/target/arc_jtag.c @@ -298,7 +298,7 @@ static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type, ARC_JTAG_READ_FROM_CORE_REG : ARC_JTAG_READ_FROM_AUX_REG); arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE); - uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4); + uint8_t *data_buf = calloc(count * 4, sizeof(uint8_t)); arc_jtag_enque_register_rw(jtag_info, addr, data_buf, NULL, count); @@ -498,7 +498,7 @@ int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr, if (!count) return ERROR_OK; - data_buf = calloc(sizeof(uint8_t), count * 4); + data_buf = calloc(count * 4, sizeof(uint8_t)); arc_jtag_enque_reset_transaction(jtag_info); /* We are reading from memory. */ diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index b5a4882..55a9778 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -965,8 +965,7 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const obj->out_filename = strdup("external"); if (!obj->out_filename) { LOG_ERROR("Out of memory"); - free(obj); - return JIM_ERR; + goto err_exit; } Jim_Obj *n; @@ -974,8 +973,7 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const obj->name = strdup(Jim_GetString(n, NULL)); if (!obj->name) { LOG_ERROR("Out of memory"); - free(obj); - return JIM_ERR; + goto err_exit; } /* Do the rest as "configure" options */ diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 45117d2..556568d 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -92,11 +92,14 @@ COMMAND_HANDLER(handle_itm_port_command) else armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port); - if (CMD_CTX->mode == COMMAND_EXEC) - return armv7m_trace_itm_config(target); + /* + * In config mode ITM is not accessible yet. + * Keep the value and it will be programmed at target init. + */ + if (CMD_CTX->mode == COMMAND_CONFIG) + return ERROR_OK; - armv7m->trace_config.itm_deferred_config = true; - return ERROR_OK; + return armv7m_trace_itm_config(target); } COMMAND_HANDLER(handle_itm_ports_command) @@ -112,11 +115,14 @@ COMMAND_HANDLER(handle_itm_ports_command) memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0, sizeof(armv7m->trace_config.itm_ter)); - if (CMD_CTX->mode == COMMAND_EXEC) - return armv7m_trace_itm_config(target); + /* + * In config mode ITM is not accessible yet. + * Keep the value and it will be programmed at target init. + */ + if (CMD_CTX->mode == COMMAND_CONFIG) + return ERROR_OK; - armv7m->trace_config.itm_deferred_config = true; - return ERROR_OK; + return armv7m_trace_itm_config(target); } static const struct command_registration itm_command_handlers[] = { diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index 5abb0b9..02eca93 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -35,8 +35,6 @@ struct armv7m_trace_config { bool itm_async_timestamps; /** Enable synchronisation packet transmission (for sync port only) */ bool itm_synchro_packets; - /** Config ITM after target examine */ - bool itm_deferred_config; }; extern const struct command_registration armv7m_trace_command_handlers[]; diff --git a/src/target/armv8.c b/src/target/armv8.c index bf582ff..b54ef13 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -278,10 +278,14 @@ static int armv8_get_pauth_mask(struct armv8_common *armv8, uint64_t *mask) static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval) { struct arm_dpm *dpm = &armv8->dpm; + unsigned int curel = armv8_curel_from_core_mode(dpm->arm->core_mode); int retval; uint32_t value; uint64_t value_64; + if (!regval) + return ERROR_FAIL; + switch (regnum) { case 0 ... 30: retval = dpm->instr_read_data_dcc_64(dpm, @@ -311,46 +315,85 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv value_64 = value; break; case ARMV8_ELR_EL1: + if (curel < SYSTEM_CUREL_EL1) { + LOG_DEBUG("ELR_EL1 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL1, 0), &value_64); break; case ARMV8_ELR_EL2: + if (curel < SYSTEM_CUREL_EL2) { + LOG_DEBUG("ELR_EL2 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL2, 0), &value_64); break; case ARMV8_ELR_EL3: + if (curel < SYSTEM_CUREL_EL3) { + LOG_DEBUG("ELR_EL3 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL3, 0), &value_64); break; case ARMV8_ESR_EL1: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_ESR_EL1, 0), &value); - value_64 = value; + if (curel < SYSTEM_CUREL_EL1) { + LOG_DEBUG("ESR_EL1 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ESR_EL1, 0), &value_64); break; case ARMV8_ESR_EL2: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_ESR_EL2, 0), &value); - value_64 = value; + if (curel < SYSTEM_CUREL_EL2) { + LOG_DEBUG("ESR_EL2 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ESR_EL2, 0), &value_64); break; case ARMV8_ESR_EL3: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_ESR_EL3, 0), &value); - value_64 = value; + if (curel < SYSTEM_CUREL_EL3) { + LOG_DEBUG("ESR_EL3 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ESR_EL3, 0), &value_64); break; case ARMV8_SPSR_EL1: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_SPSR_EL1, 0), &value); - value_64 = value; + if (curel < SYSTEM_CUREL_EL1) { + LOG_DEBUG("SPSR_EL1 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL1, 0), &value_64); break; case ARMV8_SPSR_EL2: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_SPSR_EL2, 0), &value); - value_64 = value; + if (curel < SYSTEM_CUREL_EL2) { + LOG_DEBUG("SPSR_EL2 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL2, 0), &value_64); break; case ARMV8_SPSR_EL3: - retval = dpm->instr_read_data_r0(dpm, - ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value); - value_64 = value; + if (curel < SYSTEM_CUREL_EL3) { + LOG_DEBUG("SPSR_EL3 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value_64); break; case ARMV8_PAUTH_CMASK: case ARMV8_PAUTH_DMASK: @@ -361,10 +404,8 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv break; } - if (retval == ERROR_OK && regval) + if (retval == ERROR_OK) *regval = value_64; - else - retval = ERROR_FAIL; return retval; } @@ -395,6 +436,7 @@ static int armv8_read_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t value_64) { struct arm_dpm *dpm = &armv8->dpm; + unsigned int curel = armv8_curel_from_core_mode(dpm->arm->core_mode); int retval; uint32_t value; @@ -434,46 +476,85 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu break; /* registers clobbered by taking exception in debug state */ case ARMV8_ELR_EL1: + if (curel < SYSTEM_CUREL_EL1) { + LOG_DEBUG("ELR_EL1 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MSR_GP(SYSTEM_ELR_EL1, 0), value_64); break; case ARMV8_ELR_EL2: + if (curel < SYSTEM_CUREL_EL2) { + LOG_DEBUG("ELR_EL2 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MSR_GP(SYSTEM_ELR_EL2, 0), value_64); break; case ARMV8_ELR_EL3: + if (curel < SYSTEM_CUREL_EL3) { + LOG_DEBUG("ELR_EL3 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } retval = dpm->instr_write_data_r0_64(dpm, ARMV8_MSR_GP(SYSTEM_ELR_EL3, 0), value_64); break; case ARMV8_ESR_EL1: - value = value_64; - retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP(SYSTEM_ESR_EL1, 0), value); + if (curel < SYSTEM_CUREL_EL1) { + LOG_DEBUG("ESR_EL1 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL1, 0), value_64); break; case ARMV8_ESR_EL2: - value = value_64; - retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP(SYSTEM_ESR_EL2, 0), value); + if (curel < SYSTEM_CUREL_EL2) { + LOG_DEBUG("ESR_EL2 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL2, 0), value_64); break; case ARMV8_ESR_EL3: - value = value_64; - retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP(SYSTEM_ESR_EL3, 0), value); + if (curel < SYSTEM_CUREL_EL3) { + LOG_DEBUG("ESR_EL3 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL3, 0), value_64); break; case ARMV8_SPSR_EL1: - value = value_64; - retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP(SYSTEM_SPSR_EL1, 0), value); + if (curel < SYSTEM_CUREL_EL1) { + LOG_DEBUG("SPSR_EL1 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL1, 0), value_64); break; case ARMV8_SPSR_EL2: - value = value_64; - retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP(SYSTEM_SPSR_EL2, 0), value); + if (curel < SYSTEM_CUREL_EL2) { + LOG_DEBUG("SPSR_EL2 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL2, 0), value_64); break; case ARMV8_SPSR_EL3: - value = value_64; - retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP(SYSTEM_SPSR_EL3, 0), value); + if (curel < SYSTEM_CUREL_EL3) { + LOG_DEBUG("SPSR_EL3 not accessible in EL%u", curel); + retval = ERROR_FAIL; + break; + } + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL3, 0), value_64); break; default: retval = ERROR_FAIL; @@ -512,6 +593,9 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re uint32_t value = 0; int retval; + if (!regval) + return ERROR_FAIL; + switch (regnum) { case ARMV8_R0 ... ARMV8_R14: /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ @@ -559,7 +643,7 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re ARMV4_5_MRC(15, 4, 0, 5, 2, 0), &value); break; - case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ + case ARMV8_ESR_EL3: /* no equivalent in aarch32 */ retval = ERROR_FAIL; break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ @@ -587,7 +671,7 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re break; } - if (retval == ERROR_OK && regval) + if (retval == ERROR_OK) *regval = value; return retval; @@ -695,7 +779,7 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va ARMV4_5_MCR(15, 4, 0, 5, 2, 0), value); break; - case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ + case ARMV8_ESR_EL3: /* no equivalent in aarch32 */ retval = ERROR_FAIL; break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ @@ -1504,23 +1588,23 @@ static const struct { { ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", NULL}, - { ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + { ARMV8_ESR_EL1, "ESR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked", NULL}, - { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + { ARMV8_SPSR_EL1, "SPSR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", NULL}, - { ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + { ARMV8_ESR_EL2, "ESR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked", NULL}, - { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + { ARMV8_SPSR_EL2, "SPSR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked", NULL}, - { ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + { ARMV8_ESR_EL3, "ESR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked", NULL}, - { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + { ARMV8_SPSR_EL3, "SPSR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked", NULL}, { ARMV8_PAUTH_DMASK, "pauth_dmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL}, { ARMV8_PAUTH_CMASK, "pauth_cmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL}, diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 8bb24f2..271bd91 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -677,7 +677,7 @@ static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } if (retval != ERROR_OK) - LOG_ERROR("Failed to read %s register", r->name); + LOG_DEBUG("Failed to read %s register", r->name); return retval; } @@ -719,7 +719,7 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } if (retval != ERROR_OK) - LOG_ERROR("Failed to write %s register", r->name); + LOG_DEBUG("Failed to write %s register", r->name); return retval; } diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index c225b1a..34c7cd4 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -931,8 +931,12 @@ static int cortex_m_poll_one(struct target *target) if (target->state != TARGET_RESET) { target->state = TARGET_RESET; LOG_TARGET_INFO(target, "external reset detected"); + /* In case of an unexpected S_RESET_ST set TARGET_RESET state + * and keep it until the next poll to allow its detection */ + return ERROR_OK; } - return ERROR_OK; + /* S_RESET_ST was expected (in a reset command). Continue processing + * to quickly get out of TARGET_RESET state */ } if (target->state == TARGET_RESET) { @@ -2655,8 +2659,8 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - if (armv7m->trace_config.itm_deferred_config) - armv7m_trace_itm_config(target); + /* Configure ITM */ + armv7m_trace_itm_config(target); /* NOTE: FPB and DWT are both optional. */ diff --git a/src/target/hla_target.c b/src/target/hla_target.c index c1bda99..d6f2afb 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -36,7 +36,7 @@ #define ARMV7M_SCS_DCRSR DCB_DCRSR #define ARMV7M_SCS_DCRDR DCB_DCRDR -static inline struct hl_interface_s *target_to_adapter(struct target *target) +static inline struct hl_interface *target_to_adapter(struct target *target) { return target->tap->priv; } @@ -44,14 +44,14 @@ static inline struct hl_interface_s *target_to_adapter(struct target *target) static int adapter_load_core_reg_u32(struct target *target, uint32_t regsel, uint32_t *value) { - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); return adapter->layout->api->read_reg(adapter->handle, regsel, value); } static int adapter_store_core_reg_u32(struct target *target, uint32_t regsel, uint32_t value) { - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); return adapter->layout->api->write_reg(adapter->handle, regsel, value); } @@ -65,7 +65,7 @@ static int adapter_examine_debug_reason(struct target *target) return ERROR_OK; } -static int hl_dcc_read(struct hl_interface_s *hl_if, uint8_t *value, uint8_t *ctrl) +static int hl_dcc_read(struct hl_interface *hl_if, uint8_t *value, uint8_t *ctrl) { uint16_t dcrdr; int retval = hl_if->layout->api->read_mem(hl_if->handle, @@ -90,7 +90,7 @@ static int hl_dcc_read(struct hl_interface_s *hl_if, uint8_t *value, uint8_t *ct static int hl_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { - struct hl_interface_s *hl_if = target_to_adapter(target); + struct hl_interface *hl_if = target_to_adapter(target); uint8_t data; uint8_t ctrl; uint32_t i; @@ -113,7 +113,7 @@ static int hl_handle_target_request(void *priv) if (!target_was_examined(target)) return ERROR_OK; - struct hl_interface_s *hl_if = target_to_adapter(target); + struct hl_interface *hl_if = target_to_adapter(target); if (!target->dbg_msg_enabled) return ERROR_OK; @@ -227,7 +227,7 @@ static int adapter_load_context(struct target *target) static int adapter_debug_entry(struct target *target) { - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; struct reg *r; @@ -286,7 +286,7 @@ static int adapter_debug_entry(struct target *target) static int adapter_poll(struct target *target) { enum target_state state; - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); enum target_state prev_target_state = target->state; @@ -329,7 +329,7 @@ static int adapter_poll(struct target *target) static int hl_assert_reset(struct target *target) { int res = ERROR_OK; - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); bool use_srst_fallback = true; @@ -412,7 +412,7 @@ static int hl_deassert_reset(struct target *target) static int adapter_halt(struct target *target) { int res; - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); LOG_DEBUG("%s", __func__); @@ -439,7 +439,7 @@ static int adapter_resume(struct target *target, int current, int debug_execution) { int res; - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t resume_pc; struct breakpoint *breakpoint = NULL; @@ -529,7 +529,7 @@ static int adapter_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { int res; - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; struct reg *pc = armv7m->arm.pc; @@ -593,7 +593,7 @@ static int adapter_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; @@ -608,7 +608,7 @@ static int adapter_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - struct hl_interface_s *adapter = target_to_adapter(target); + struct hl_interface *adapter = target_to_adapter(target); if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am index 7f25eca..aa82f58 100644 --- a/src/target/riscv/Makefile.am +++ b/src/target/riscv/Makefile.am @@ -11,11 +11,18 @@ noinst_LTLIBRARIES += %D%/libriscv.la %D%/opcodes.h \ %D%/program.h \ %D%/riscv.h \ + %D%/riscv-011.h \ + %D%/riscv-011_reg.h \ + %D%/riscv-013.h \ + %D%/riscv-013_reg.h \ %D%/batch.c \ %D%/program.c \ %D%/riscv-011.c \ + %D%/riscv-011_reg.c \ %D%/riscv-013.c \ + %D%/riscv-013_reg.c \ %D%/riscv.c \ + %D%/riscv_reg.c \ %D%/riscv_semihosting.c \ %D%/debug_defines.c \ %D%/debug_reg_printer.c diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 4115a37..bb1070a 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -29,7 +29,7 @@ struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans) out->allocated_scans = scans; out->last_scan = RISCV_SCAN_TYPE_INVALID; out->was_run = false; - out->used_delay = 0; + out->last_scan_delay = 0; out->data_out = NULL; out->data_in = NULL; @@ -109,7 +109,7 @@ static bool riscv_batch_was_scan_busy(const struct riscv_batch *batch, } static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_idx, - struct riscv_scan_delays delays) + const struct riscv_scan_delays *delays) { if (!batch->was_run) return; @@ -121,9 +121,9 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_ ? batch->delay_classes[start_idx - 1] : RISCV_DELAY_BASE; const unsigned int new_delay = riscv_scan_get_delay(delays, delay_class); - if (new_delay <= batch->used_delay) + if (new_delay <= batch->last_scan_delay) return; - const unsigned int idle_change = new_delay - batch->used_delay; + const unsigned int idle_change = new_delay - batch->last_scan_delay; LOG_TARGET_DEBUG(batch->target, "Adding %u idle cycles before the batch.", idle_change); assert(idle_change <= INT_MAX); @@ -131,19 +131,19 @@ 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, - struct riscv_scan_delays delays) + const struct riscv_scan_delays *delays) { assert(batch); assert(scan_idx < batch->used_scans); const enum riscv_scan_delay_class delay_class = batch->delay_classes[scan_idx]; - const unsigned int delay = riscv_scan_get_delay(delays, delay_class); + const unsigned int delay = riscv_scan_get_delay(delays, delay_class); assert(delay <= INT_MAX); return delay; } int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, - struct riscv_scan_delays delays, bool resets_delays, + const struct riscv_scan_delays *delays, bool resets_delays, size_t reset_delays_after) { assert(batch->used_scans); @@ -195,7 +195,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, } batch->was_run = true; - batch->used_delay = get_delay(batch, batch->used_scans - 1, delays); + batch->last_scan_delay = get_delay(batch, batch->used_scans - 1, delays); return ERROR_OK; } diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 03947aa..327406c 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -25,40 +25,66 @@ enum riscv_scan_delay_class { /* Delay for System Bus read operation: */ RISCV_DELAY_SYSBUS_READ, /* Delay for System Bus write operation: */ - RISCV_DELAY_SYSBUS_WRITE, + RISCV_DELAY_SYSBUS_WRITE }; +static inline const char * +riscv_scan_delay_class_name(enum riscv_scan_delay_class delay_class) +{ + switch (delay_class) { + case RISCV_DELAY_BASE: + return "DM access"; + case RISCV_DELAY_ABSTRACT_COMMAND: + return "Abstract Command"; + case RISCV_DELAY_SYSBUS_READ: + return "System Bus read"; + case RISCV_DELAY_SYSBUS_WRITE: + return "System Bus write"; + } + assert(0); + return NULL; +} + +/* The scan delay values are passed to "jtag_add_runtest()", which accepts an + * "int". Therefore, the passed value should be no greater than "INT_MAX". + * + * Since the resulting delay value can be a sum of two individual delays, + * individual delays are limited to "INT_MAX / 2" to prevent overflow of the + * final sum. + */ +#define RISCV_SCAN_DELAY_MAX (INT_MAX / 2) + struct riscv_scan_delays { - /* The purpose of these delays is to be passed to "jtag_add_runtest()", - * which accepts an "int". - * Therefore, they should be no greater then "INT_MAX". - */ unsigned int base_delay; unsigned int ac_delay; unsigned int sb_read_delay; unsigned int sb_write_delay; }; -static inline unsigned int riscv_scan_get_delay(struct riscv_scan_delays delays, +static inline unsigned int +riscv_scan_get_delay(const struct riscv_scan_delays *delays, enum riscv_scan_delay_class delay_class) { switch (delay_class) { case RISCV_DELAY_BASE: - return delays.base_delay; + return delays->base_delay; case RISCV_DELAY_ABSTRACT_COMMAND: - return delays.ac_delay; + return delays->base_delay + delays->ac_delay; case RISCV_DELAY_SYSBUS_READ: - return delays.sb_read_delay; + return delays->base_delay + delays->sb_read_delay; case RISCV_DELAY_SYSBUS_WRITE: - return delays.sb_write_delay; + return delays->base_delay + delays->sb_write_delay; } + assert(0); return 0; } static inline void riscv_scan_set_delay(struct riscv_scan_delays *delays, enum riscv_scan_delay_class delay_class, unsigned int delay) { - assert(delay <= INT_MAX); + assert(delay <= RISCV_SCAN_DELAY_MAX); + LOG_DEBUG("%s delay is set to %u.", + riscv_scan_delay_class_name(delay_class), delay); switch (delay_class) { case RISCV_DELAY_BASE: delays->base_delay = delay; @@ -73,6 +99,25 @@ static inline void riscv_scan_set_delay(struct riscv_scan_delays *delays, delays->sb_write_delay = delay; return; } + assert(0); +} + +static inline int riscv_scan_increase_delay(struct riscv_scan_delays *delays, + enum riscv_scan_delay_class delay_class) +{ + const unsigned int delay = riscv_scan_get_delay(delays, delay_class); + const unsigned int delay_step = delay / 10 + 1; + if (delay > RISCV_SCAN_DELAY_MAX - delay_step) { + /* It's not clear if this issue actually occurs in real + * use-cases, so stick with a simple solution until the + * first bug report. + */ + LOG_ERROR("Delay for %s (%d) is not increased anymore (maximum was reached).", + riscv_scan_delay_class_name(delay_class), delay); + return ERROR_FAIL; + } + riscv_scan_set_delay(delays, delay_class, delay + delay_step); + return ERROR_OK; } /* A batch of multiple JTAG scans, which are grouped together to avoid the @@ -113,7 +158,7 @@ struct riscv_batch { /* Number of RTI cycles used by the last scan on the last run. * Only valid when `was_run` is set. */ - unsigned int used_delay; + unsigned int last_scan_delay; }; /* Allocates (or frees) a new scan set. "scans" is the maximum number of JTAG @@ -138,7 +183,7 @@ bool riscv_batch_full(struct riscv_batch *batch); * OpenOCD that are based on batches. */ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, - struct riscv_scan_delays delays, bool resets_delays, + const struct riscv_scan_delays *delays, bool resets_delays, size_t reset_delays_after); /* Get the number of scans successfully executed form this batch. */ diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index 92c8cc5..d606f73 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -3,6 +3,8 @@ #ifndef TARGET__RISCV__GDB_REGS_H #define TARGET__RISCV__GDB_REGS_H +#include "encoding.h" + /* gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in * its source tree. We must interpret the numbers the same here. */ enum gdb_regno { @@ -123,6 +125,4 @@ enum gdb_regno { GDB_REGNO_COUNT }; -const char *gdb_regno_name(const struct target *target, enum gdb_regno regno); - #endif diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 361191a..93dbdbf 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -41,7 +41,7 @@ int riscv_program_write(struct riscv_program *program); /* Executes a program, returning 0 if the program successfully executed. Note * that this may cause registers to be saved or restored, which could result to - * calls to things like riscv_save_register which itself could require a + * calls to things like riscv013_reg_save which itself could require a * program to execute. That's OK, just make sure this eventually terminates. * */ int riscv_program_exec(struct riscv_program *p, struct target *t); diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index df59a49..0715de5 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -13,6 +13,8 @@ #include "config.h" #endif +#include "riscv-011.h" + #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" @@ -22,6 +24,8 @@ #include "target/breakpoints.h" #include "helper/time_support.h" #include "riscv.h" +#include "riscv_reg.h" +#include "riscv-011_reg.h" #include "asm.h" #include "gdb_regs.h" #include "field_helpers.h" @@ -210,8 +214,6 @@ typedef struct { static int poll_target(struct target *target, bool announce); static int riscv011_poll(struct target *target); -static int get_register(struct target *target, riscv_reg_t *value, - enum gdb_regno regid); /*** Utility functions. ***/ @@ -739,7 +741,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; @@ -1023,7 +1025,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; @@ -1045,7 +1047,7 @@ static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when reading %s", exception, - gdb_regno_name(target, GDB_REGNO_CSR0 + csr)); + riscv_reg_gdb_regno_name(target, GDB_REGNO_CSR0 + csr)); *value = ~0; return ERROR_FAIL; } @@ -1111,7 +1113,7 @@ static int execute_resume(struct target *target, bool step) LOG_DEBUG("step=%d", step); - if (riscv_flush_registers(target) != ERROR_OK) + if (riscv_reg_flush_all(target) != ERROR_OK) return ERROR_FAIL; maybe_write_tselect(target); @@ -1184,7 +1186,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; @@ -1225,7 +1227,7 @@ static int update_mstatus_actual(struct target *target) /* Force reading the register. In that process mstatus_actual will be * updated. */ riscv_reg_t mstatus; - return get_register(target, &mstatus, GDB_REGNO_MSTATUS); + return riscv011_get_register(target, &mstatus, GDB_REGNO_MSTATUS); } /*** OpenOCD target functions. ***/ @@ -1247,7 +1249,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { - LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(target, regnum)); + LOG_WARNING("Got exception 0x%x when reading %s", exception, riscv_reg_gdb_regno_name(target, regnum)); *value = ~0; return ERROR_FAIL; } @@ -1322,14 +1324,14 @@ static int register_write(struct target *target, unsigned int number, uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when writing %s", exception, - gdb_regno_name(target, number)); + riscv_reg_gdb_regno_name(target, number)); return ERROR_FAIL; } return ERROR_OK; } -static int get_register(struct target *target, riscv_reg_t *value, +int riscv011_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno regid) { riscv011_info_t *info = get_info(target); @@ -1377,7 +1379,7 @@ static int get_register(struct target *target, riscv_reg_t *value, /* This function is intended to handle accesses to registers through register * cache. */ -static int set_register(struct target *target, enum gdb_regno regid, +int riscv011_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t value) { assert(target->reg_cache); @@ -1595,7 +1597,7 @@ static int examine(struct target *target) } /* Update register list to match discovered XLEN/supported extensions. */ - riscv_init_registers(target); + riscv011_reg_init_all(target); info->never_halted = true; @@ -2342,10 +2344,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; } @@ -2391,8 +2393,6 @@ static int init_target(struct command_context *cmd_ctx, { LOG_DEBUG("init"); RISCV_INFO(generic_info); - generic_info->get_register = get_register; - generic_info->set_register = set_register; generic_info->read_memory = read_memory; generic_info->authdata_read = &riscv011_authdata_read; generic_info->authdata_write = &riscv011_authdata_write; @@ -2404,7 +2404,7 @@ static int init_target(struct command_context *cmd_ctx, /* Assume 32-bit until we discover the real value in examine(). */ generic_info->xlen = 32; - riscv_init_registers(target); + riscv011_reg_init_all(target); return ERROR_OK; } diff --git a/src/target/riscv/riscv-011.h b/src/target/riscv/riscv-011.h new file mode 100644 index 0000000..8d1d06a --- /dev/null +++ b/src/target/riscv/riscv-011.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_RISCV_RISCV_011_H +#define OPENOCD_TARGET_RISCV_RISCV_011_H + +#include "riscv.h" +#include "gdb_regs.h" +#include "target/target.h" + +int riscv011_get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno regid); +int riscv011_set_register(struct target *target, enum gdb_regno regid, + riscv_reg_t value); + +#endif /*OPENOCD_TARGET_RISCV_RISCV_011_H*/ diff --git a/src/target/riscv/riscv-011_reg.c b/src/target/riscv/riscv-011_reg.c new file mode 100644 index 0000000..7f29064 --- /dev/null +++ b/src/target/riscv/riscv-011_reg.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "riscv-011_reg.h" + +#include "riscv_reg_impl.h" +#include "riscv-011.h" + +static int riscv011_reg_get(struct reg *reg) +{ + struct target * const target = riscv_reg_impl_get_target(reg); + riscv_reg_t value; + const int result = riscv011_get_register(target, &value, reg->number); + if (result != ERROR_OK) + return result; + buf_set_u64(reg->value, 0, reg->size, value); + return ERROR_OK; +} + +static int riscv011_reg_set(struct reg *reg, uint8_t *buf) +{ + const riscv_reg_t value = buf_get_u64(buf, 0, reg->size); + struct target * const target = riscv_reg_impl_get_target(reg); + return riscv011_set_register(target, reg->number, value); +} + +static const struct reg_arch_type *riscv011_gdb_regno_reg_type(uint32_t regno) +{ + static const struct reg_arch_type riscv011_reg_type = { + .get = riscv011_reg_get, + .set = riscv011_reg_set + }; + return &riscv011_reg_type; +} + +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)); +} + +int riscv011_reg_init_all(struct target *target) +{ + if (riscv_reg_impl_init_cache(target) != ERROR_OK) + return ERROR_FAIL; + + init_shared_reg_info(target); + + for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) + if (riscv011_init_reg(target, regno) != ERROR_OK) + return ERROR_FAIL; + + if (riscv_reg_impl_expose_csrs(target) != ERROR_OK) + return ERROR_FAIL; + + riscv_reg_impl_hide_csrs(target); + + return ERROR_OK; +} diff --git a/src/target/riscv/riscv-011_reg.h b/src/target/riscv/riscv-011_reg.h new file mode 100644 index 0000000..ee00c9b --- /dev/null +++ b/src/target/riscv/riscv-011_reg.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_011_H +#define OPENOCD_TARGET_RISCV_RISCV_REG_011_H + +#include "target/target.h" + +/** + * This file describes additional register cache interface available to the + * RISC-V Debug Specification v0.11 targets. + */ + +/** + * Initialize register cache. After this function all registers can be + * safely accessed via functions described here and in `riscv_reg.h`. + */ +int riscv011_reg_init_all(struct target *target); + +#endif /*OPENOCD_TARGET_RISCV_RISCV_REG_011_H*/ diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 83f03f1..7898cae 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -23,6 +23,9 @@ #include "helper/time_support.h" #include "helper/list.h" #include "riscv.h" +#include "riscv-013.h" +#include "riscv_reg.h" +#include "riscv-013_reg.h" #include "debug_defines.h" #include "rtos/rtos.h" #include "program.h" @@ -37,10 +40,6 @@ static int riscv013_step_or_resume_current_hart(struct target *target, static int riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in struct riscv_info. */ -static int riscv013_get_register(struct target *target, - riscv_reg_t *value, enum gdb_regno rid); -static int riscv013_set_register(struct target *target, enum gdb_regno regid, - riscv_reg_t value); static int dm013_select_hart(struct target *target, int hart_index); static int riscv013_halt_prep(struct target *target); static int riscv013_halt_go(struct target *target); @@ -170,21 +169,12 @@ typedef struct { * access. */ unsigned int dtmcs_idle; - /* This value is incremented every time a dbus access comes back as "busy". - * It's used to determine how many run-test/idle cycles to feed the target - * in between accesses. */ - unsigned int dmi_busy_delay; - - /* Number of run-test/idle cycles to add between consecutive bus master - * reads/writes respectively. */ - unsigned int bus_master_write_delay, bus_master_read_delay; - - /* This value is increased every time we tried to execute two commands - * consecutively, and the second one failed because the previous hadn't - * completed yet. It's used to add extra run-test/idle cycles after - * starting a command, so we don't have to waste time checking for busy to - * go low. */ - unsigned int ac_busy_delay; + /* This structure is used to determine how many run-test/idle to use after + * an access of corresponding "riscv_scan_delay_class". + * Values are incremented every time an access results in a busy + * response. + */ + struct riscv_scan_delays learned_delays; bool abstract_read_csr_supported; bool abstract_write_csr_supported; @@ -479,15 +469,25 @@ static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr return ERROR_OK; } -static void increase_dmi_busy_delay(struct target *target) +static int increase_dmi_busy_delay(struct target *target) { - riscv013_info_t *info = get_info(target); - info->dmi_busy_delay += info->dmi_busy_delay / 10 + 1; - LOG_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", - info->dtmcs_idle, info->dmi_busy_delay, - info->ac_busy_delay); + RISCV013_INFO(info); - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); + int res = dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, + NULL /* discard result */); + if (res != ERROR_OK) + return res; + + res = riscv_scan_increase_delay(&info->learned_delays, + RISCV_DELAY_BASE); + return res; +} + +static void reset_learned_delays(struct target *target) +{ + RISCV013_INFO(info); + assert(info); + memset(&info->learned_delays, 0, sizeof(info->learned_delays)); } static void decrement_reset_delays_counter(struct target *target, size_t finished_scans) @@ -504,9 +504,7 @@ static void decrement_reset_delays_counter(struct target *target, size_t finishe r->reset_delays_wait = -1; LOG_TARGET_DEBUG(target, "resetting learned delays (reset_delays_wait counter expired)"); - RISCV013_INFO(info); - info->dmi_busy_delay = 0; - info->ac_busy_delay = 0; + reset_learned_delays(target); } /** * exec: If this is set, assume the scan results in an execution, so more @@ -555,9 +553,9 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); } - int idle_count = info->dmi_busy_delay; - if (exec) - idle_count += info->ac_busy_delay; + 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); @@ -636,7 +634,9 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, status = dmi_scan(target, NULL, NULL, op, address, data_out, exec); if (status == DMI_STATUS_BUSY) { - increase_dmi_busy_delay(target); + 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) { @@ -662,7 +662,9 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in, status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0, false); if (status == DMI_STATUS_BUSY) { - increase_dmi_busy_delay(target); + 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) { @@ -693,12 +695,12 @@ static int dmi_op(struct target *target, uint32_t *data_in, 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); + address, data_out, riscv_get_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); + riscv_get_command_timeout_sec()); return ERROR_FAIL; } return result; @@ -729,17 +731,6 @@ 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 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) @@ -803,11 +794,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); @@ -825,26 +815,11 @@ 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 void increase_ac_busy_delay(struct target *target) +static int increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); - info->ac_busy_delay += info->ac_busy_delay / 10 + 1; - LOG_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", - info->dtmcs_idle, info->dmi_busy_delay, - info->ac_busy_delay); + return riscv_scan_increase_delay(&info->learned_delays, + RISCV_DELAY_ABSTRACT_COMMAND); } static uint32_t __attribute__((unused)) abstract_register_size(unsigned width) @@ -890,12 +865,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) @@ -912,13 +887,13 @@ static int dm013_select_target(struct target *target) return dm013_select_hart(target, info->index); } -#define EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE 2 +#define ABSTRACT_COMMAND_BATCH_SIZE 2 static size_t abstract_cmd_fill_batch(struct riscv_batch *batch, uint32_t command) { assert(riscv_batch_available_scans(batch) - >= EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE); + >= ABSTRACT_COMMAND_BATCH_SIZE); riscv_batch_add_dm_write(batch, DM_COMMAND, command, /* read_back */ true, RISCV_DELAY_ABSTRACT_COMMAND); return riscv_batch_add_dm_read(batch, DM_ABSTRACTCS, RISCV_DELAY_BASE); @@ -936,7 +911,9 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target, res = wait_for_idle(target, &abstractcs); if (res != ERROR_OK) goto clear_cmderr; - increase_ac_busy_delay(target); + res = increase_ac_busy_delay(target); + if (res != ERROR_OK) + goto clear_cmderr; } *cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR); if (*cmderr == CMDERR_NONE) @@ -976,7 +953,7 @@ static int execute_abstract_command(struct target *target, uint32_t command, return ERROR_FAIL; struct riscv_batch *batch = riscv_batch_alloc(target, - EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE); + ABSTRACT_COMMAND_BATCH_SIZE); const size_t abstractcs_read_key = abstract_cmd_fill_batch(batch, command); /* Abstract commands are executed while running the batch. */ @@ -1104,7 +1081,7 @@ static uint32_t access_register_command(struct target *target, uint32_t number, break; default: LOG_TARGET_ERROR(target, "%d-bit register %s not supported.", - size, gdb_regno_name(target, number)); + size, riscv_reg_gdb_regno_name(target, number)); assert(0); } @@ -1204,7 +1181,7 @@ static int register_write_abstract(struct target *target, enum gdb_regno number, assert(size_bits % 32 == 0); const unsigned int size_in_words = size_bits / 32; const unsigned int batch_size = size_in_words - + EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE; + + ABSTRACT_COMMAND_BATCH_SIZE; struct riscv_batch * const batch = riscv_batch_alloc(target, batch_size); abstract_data_write_fill_batch(batch, value, /*index*/ 0, size_bits); @@ -1290,7 +1267,7 @@ static int examine_progbuf(struct target *target) return ERROR_OK; } - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -1365,12 +1342,12 @@ static int prep_for_register_access(struct target *target, } LOG_TARGET_DEBUG(target, "Preparing mstatus to access %s", - gdb_regno_name(target, regno)); + riscv_reg_gdb_regno_name(target, regno)); assert(target->state == TARGET_HALTED && "The target must be halted to modify and then restore mstatus"); - if (riscv_get_register(target, orig_mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + if (riscv_reg_get(target, orig_mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) return ERROR_FAIL; riscv_reg_t new_mstatus = *orig_mstatus; @@ -1381,11 +1358,11 @@ static int prep_for_register_access(struct target *target, new_mstatus = set_field(new_mstatus, field_mask, 1); - if (riscv_write_register(target, GDB_REGNO_MSTATUS, new_mstatus) != ERROR_OK) + if (riscv_reg_write(target, GDB_REGNO_MSTATUS, new_mstatus) != ERROR_OK) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "Prepared to access %s (mstatus=0x%" PRIx64 ")", - gdb_regno_name(target, regno), new_mstatus); + riscv_reg_gdb_regno_name(target, regno), new_mstatus); return ERROR_OK; } @@ -1397,7 +1374,7 @@ static int cleanup_after_register_access(struct target *target, return ERROR_OK; LOG_TARGET_DEBUG(target, "Restoring mstatus to 0x%" PRIx64, mstatus); - return riscv_write_register(target, GDB_REGNO_MSTATUS, mstatus); + return riscv_reg_write(target, GDB_REGNO_MSTATUS, mstatus); } typedef enum { @@ -1616,7 +1593,7 @@ static int fpr_read_progbuf(struct target *target, uint64_t *value, const unsigned int freg = number - GDB_REGNO_FPR0; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -1646,7 +1623,7 @@ static int csr_read_progbuf(struct target *target, uint64_t *value, assert(target->state == TARGET_HALTED); assert(number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095); - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -1674,7 +1651,7 @@ static int register_read_progbuf(struct target *target, uint64_t *value, return csr_read_progbuf(target, value, number); LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.", - gdb_regno_name(target, number)); + riscv_reg_gdb_regno_name(target, number)); return ERROR_FAIL; } @@ -1714,7 +1691,7 @@ static int fpr_write_progbuf(struct target *target, enum gdb_regno number, assert(number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31); const unsigned int freg = number - GDB_REGNO_FPR0; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -1744,11 +1721,11 @@ static int vtype_write_progbuf(struct target *target, riscv_reg_t value) { assert(target->state == TARGET_HALTED); - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -1765,11 +1742,11 @@ static int vl_write_progbuf(struct target *target, riscv_reg_t value) { assert(target->state == TARGET_HALTED); - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -1788,7 +1765,7 @@ static int csr_write_progbuf(struct target *target, enum gdb_regno number, assert(target->state == TARGET_HALTED); assert(number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095); - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK) return ERROR_FAIL; @@ -1820,7 +1797,7 @@ static int register_write_progbuf(struct target *target, enum gdb_regno number, return csr_write_progbuf(target, number, value); LOG_TARGET_ERROR(target, "Unexpected write to %s via program buffer.", - gdb_regno_name(target, number)); + riscv_reg_gdb_regno_name(target, number)); return ERROR_FAIL; } @@ -1832,7 +1809,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number, riscv_reg_t value) { LOG_TARGET_DEBUG(target, "Writing 0x%" PRIx64 " to %s", value, - gdb_regno_name(target, number)); + riscv_reg_gdb_regno_name(target, number)); if (target->state != TARGET_HALTED) return register_write_abstract(target, number, value); @@ -1850,7 +1827,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number, return ERROR_FAIL; if (result == ERROR_OK) - LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(target, number), + LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, riscv_reg_gdb_regno_name(target, number), value); return result; @@ -1860,7 +1837,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number, static int register_read_direct(struct target *target, riscv_reg_t *value, enum gdb_regno number) { - LOG_TARGET_DEBUG(target, "Reading %s", gdb_regno_name(target, number)); + LOG_TARGET_DEBUG(target, "Reading %s", riscv_reg_gdb_regno_name(target, number)); if (target->state != TARGET_HALTED) return register_read_abstract(target, value, number); @@ -1879,7 +1856,7 @@ static int register_read_direct(struct target *target, riscv_reg_t *value, return ERROR_FAIL; if (result == ERROR_OK) - LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(target, number), + LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, riscv_reg_gdb_regno_name(target, number), *value); return result; @@ -1896,10 +1873,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; } @@ -1919,7 +1896,7 @@ static int set_dcsr_ebreak(struct target *target, bool step) RISCV013_INFO(info); riscv_reg_t original_dcsr, dcsr; /* We want to twiddle some bits in the debug CSR so debugging works. */ - if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) return ERROR_FAIL; original_dcsr = dcsr; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); @@ -1929,7 +1906,7 @@ static int set_dcsr_ebreak(struct target *target, bool step) dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); if (dcsr != original_dcsr && - riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) + riscv_reg_set(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) return ERROR_FAIL; info->dcsr_ebreak_is_set = true; return ERROR_OK; @@ -2089,11 +2066,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)); @@ -2112,11 +2088,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)); @@ -2404,7 +2379,7 @@ static int examine(struct target *target) } /* Now init registers based on what we discovered. */ - if (riscv_init_registers(target) != ERROR_OK) + if (riscv013_reg_init_all(target) != ERROR_OK) return ERROR_FAIL; if (set_dcsr_ebreak(target, false) != ERROR_OK) @@ -2564,14 +2539,14 @@ static int try_set_vsew(struct target *target, unsigned int *debug_vsew) /* Set standard element width to match XLEN, for vmv instruction to move * the least significant bits into a GPR. */ - if (riscv_write_register(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK) + if (riscv_reg_write(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK) return ERROR_FAIL; if (encoded_vsew == 3 && r->vsew64_supported == YNM_MAYBE) { /* Check that it's supported. */ riscv_reg_t vtype; - if (riscv_get_register(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK) + if (riscv_reg_get(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK) return ERROR_FAIL; if (vtype >> (riscv_xlen(target) - 1)) { r->vsew64_supported = YNM_NO; @@ -2604,9 +2579,9 @@ static int prep_for_vector_access(struct target *target, return ERROR_FAIL; /* Save vtype and vl. */ - if (riscv_get_register(target, orig_vtype, GDB_REGNO_VTYPE) != ERROR_OK) + if (riscv_reg_get(target, orig_vtype, GDB_REGNO_VTYPE) != ERROR_OK) return ERROR_FAIL; - if (riscv_get_register(target, orig_vl, GDB_REGNO_VL) != ERROR_OK) + if (riscv_reg_get(target, orig_vl, GDB_REGNO_VL) != ERROR_OK) return ERROR_FAIL; if (try_set_vsew(target, debug_vsew) != ERROR_OK) @@ -2615,22 +2590,22 @@ static int prep_for_vector_access(struct target *target, * instruction, for the vslide1down instruction. * Set it so the entire V register is updated. */ *debug_vl = DIV_ROUND_UP(r->vlenb * 8, *debug_vsew); - return riscv_write_register(target, GDB_REGNO_VL, *debug_vl); + return riscv_reg_write(target, GDB_REGNO_VL, *debug_vl); } static int cleanup_after_vector_access(struct target *target, riscv_reg_t mstatus, riscv_reg_t vtype, riscv_reg_t vl) { /* Restore vtype and vl. */ - if (riscv_write_register(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK) + if (riscv_reg_write(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK) return ERROR_FAIL; - if (riscv_write_register(target, GDB_REGNO_VL, vl) != ERROR_OK) + if (riscv_reg_write(target, GDB_REGNO_VL, vl) != ERROR_OK) return ERROR_FAIL; return cleanup_after_register_access(target, mstatus, GDB_REGNO_VL); } -static int riscv013_get_register_buf(struct target *target, - uint8_t *value, enum gdb_regno regno) +int riscv013_get_register_buf(struct target *target, uint8_t *value, + enum gdb_regno regno) { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); @@ -2644,7 +2619,7 @@ static int riscv013_get_register_buf(struct target *target, &debug_vl, &debug_vsew) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; unsigned int vnum = regno - GDB_REGNO_V0; @@ -2673,7 +2648,7 @@ static int riscv013_get_register_buf(struct target *target, } else { LOG_TARGET_ERROR(target, "Failed to execute vmv/vslide1down while reading %s", - gdb_regno_name(target, regno)); + riscv_reg_gdb_regno_name(target, regno)); break; } } @@ -2684,8 +2659,8 @@ static int riscv013_get_register_buf(struct target *target, return result; } -static int riscv013_set_register_buf(struct target *target, - enum gdb_regno regno, const uint8_t *value) +int riscv013_set_register_buf(struct target *target, enum gdb_regno regno, + const uint8_t *value) { assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31); @@ -2699,7 +2674,7 @@ static int riscv013_set_register_buf(struct target *target, &debug_vl, &debug_vsew) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; unsigned int vnum = regno - GDB_REGNO_V0; @@ -2758,36 +2733,25 @@ static int sb_write_address(struct target *target, target_addr_t address, (uint32_t)address, false, ensure_success); } -/* TODO: store delays in "struct riscv_scan_delays" and remove this function. */ -struct riscv_scan_delays get_scan_delays(struct target *target) -{ - RISCV013_INFO(info); - assert(info); - struct riscv_scan_delays delays; - riscv_scan_set_delay(&delays, RISCV_DELAY_BASE, info->dmi_busy_delay); - riscv_scan_set_delay(&delays, RISCV_DELAY_ABSTRACT_COMMAND, info->dmi_busy_delay + - info->ac_busy_delay); - riscv_scan_set_delay(&delays, RISCV_DELAY_SYSBUS_READ, info->dmi_busy_delay + - info->bus_master_read_delay); - riscv_scan_set_delay(&delays, RISCV_DELAY_SYSBUS_WRITE, info->dmi_busy_delay + - info->bus_master_write_delay); - return delays; -} - static int batch_run(struct target *target, struct riscv_batch *batch) { RISCV_INFO(r); + RISCV013_INFO(info); + select_dmi(target); riscv_batch_add_nop(batch); - const int result = riscv_batch_run_from(batch, 0, - get_scan_delays(target), + 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 @@ -2796,44 +2760,49 @@ static int batch_run(struct target *target, struct riscv_batch *batch) static int batch_run_timeout(struct target *target, struct riscv_batch *batch) { RISCV013_INFO(info); - + select_dmi(target); riscv_batch_add_nop(batch); size_t finished_scans = 0; const time_t start = time(NULL); - const unsigned int old_dmi_busy_delay = info->dmi_busy_delay; + const unsigned int old_base_delay = riscv_scan_get_delay(&info->learned_delays, + RISCV_DELAY_BASE); int result; do { RISCV_INFO(r); result = riscv_batch_run_from(batch, finished_scans, - get_scan_delays(target), + &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; } - increase_dmi_busy_delay(target); - } while (time(NULL) - start < riscv_command_timeout_sec); + result = increase_dmi_busy_delay(target); + if (result != ERROR_OK) + return result; + } while (time(NULL) - start < riscv_get_command_timeout_sec()); assert(result == ERROR_OK); assert(riscv_batch_was_batch_busy(batch)); /* Reset dmi_busy_delay, so the value doesn't get too big. */ - LOG_TARGET_DEBUG(target, "dmi_busy_delay is restored to %u.", - old_dmi_busy_delay); - info->dmi_busy_delay = old_dmi_busy_delay; + LOG_TARGET_DEBUG(target, "%s delay is restored to %u.", + riscv_scan_delay_class_name(RISCV_DELAY_BASE), + old_base_delay); + riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE, + old_base_delay); 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; } @@ -2967,7 +2936,11 @@ static int sample_memory_bus_v1(struct target *target, * with a larger DMI delay. */ unsigned int sbcs_read_op = riscv_batch_get_dmi_read_op(batch, sbcs_read_index); if (sbcs_read_op == DTM_DMI_OP_BUSY) { - increase_dmi_busy_delay(target); + result = increase_dmi_busy_delay(target); + if (result != ERROR_OK) { + riscv_batch_free(batch); + return result; + } continue; } @@ -2975,9 +2948,12 @@ static int sample_memory_bus_v1(struct target *target, if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) { /* Discard this batch when we encounter "busy error" state on the System Bus level. * We'll try next time with a larger System Bus read delay. */ - info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; dm_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR); + int res = riscv_scan_increase_delay(&info->learned_delays, + RISCV_DELAY_SYSBUS_READ); riscv_batch_free(batch); + if (res != ERROR_OK) + return res; continue; } if (get_field(sbcs_read, DM_SBCS_SBERROR)) { @@ -3096,10 +3072,6 @@ static int init_target(struct command_context *cmd_ctx, LOG_TARGET_DEBUG(target, "Init."); RISCV_INFO(generic_info); - generic_info->get_register = &riscv013_get_register; - generic_info->set_register = &riscv013_set_register; - generic_info->get_register_buf = &riscv013_get_register_buf; - generic_info->set_register_buf = &riscv013_set_register_buf; generic_info->select_target = &dm013_select_target; generic_info->get_hart_state = &riscv013_get_hart_state; generic_info->resume_go = &riscv013_resume_go; @@ -3138,11 +3110,7 @@ static int init_target(struct command_context *cmd_ctx, riscv013_info_t *info = get_info(target); info->progbufsize = -1; - - info->dmi_busy_delay = 0; - info->bus_master_read_delay = 0; - info->bus_master_write_delay = 0; - info->ac_busy_delay = 0; + reset_learned_delays(target); /* Assume all these abstract commands are supported until we learn * otherwise. @@ -3229,25 +3197,20 @@ static int deassert_reset(struct target *target) return result; uint32_t dmstatus; - const int orig_dmi_busy_delay = info->dmi_busy_delay; + const unsigned int orig_base_delay = riscv_scan_get_delay(&info->learned_delays, + RISCV_DELAY_BASE); 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; @@ -3262,7 +3225,8 @@ static int deassert_reset(struct target *target) } while (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) && !get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)); - info->dmi_busy_delay = orig_dmi_busy_delay; + riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE, + orig_base_delay); if (target->reset_halt) { target->state = TARGET_HALTED; @@ -3432,10 +3396,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; } } @@ -3577,6 +3541,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); @@ -3591,10 +3558,12 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, if (sb_write_address(target, next_address, true) != ERROR_OK) return ERROR_FAIL; - if (info->bus_master_read_delay) { + 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", - info->bus_master_read_delay); - jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE); + 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; @@ -3605,75 +3574,44 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, * 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. */ - if (j == 0 && info->bus_master_read_delay) { - LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", - info->bus_master_read_delay); - jtag_add_runtest(info->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, 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) @@ -3714,9 +3652,10 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; } - info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1; - LOG_TARGET_DEBUG(target, "Increasing bus_master_read_delay to %d.", - info->bus_master_read_delay); + int res = riscv_scan_increase_delay(&info->learned_delays, + RISCV_DELAY_SYSBUS_READ); + if (res != ERROR_OK) + return res; continue; } @@ -4132,8 +4071,12 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, uint32_t start_index, uint32_t *elements_read, struct memory_access_info access) { - increase_ac_busy_delay(target); - riscv013_clear_abstract_error(target); + int res = riscv013_clear_abstract_error(target); + if (res != ERROR_OK) + return res; + res = increase_ac_busy_delay(target); + if (res != ERROR_OK) + return res; if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK) return ERROR_FAIL; @@ -4437,11 +4380,11 @@ static int read_memory_progbuf_inner_fill_progbuf(struct target *target, { const bool is_repeated_read = increment == 0; - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; - if (is_repeated_read && riscv_save_register(target, GDB_REGNO_A0) != ERROR_OK) + if (is_repeated_read && riscv013_reg_save(target, GDB_REGNO_A0) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -4534,7 +4477,7 @@ static int read_memory_progbuf_inner(struct target *target, static int read_memory_progbuf_inner_one(struct target *target, struct memory_access_info access, bool mprven) { - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -4800,39 +4743,30 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, /* Execute the batch of writes */ result = batch_run(target, batch); - riscv_batch_free(batch); - if (result != ERROR_OK) + if (result != ERROR_OK) { + riscv_batch_free(batch); return result; + } - /* Read sbcs value. - * At the same time, detect if DMI busy has occurred during the batch write. */ - bool dmi_busy_encountered; - if (dm_op(target, &sbcs, &dmi_busy_encountered, DMI_OP_READ, - DM_SBCS, 0, false, true) != ERROR_OK) - return ERROR_FAIL; + bool dmi_busy_encountered = riscv_batch_was_batch_busy(batch); + riscv_batch_free(batch); if (dmi_busy_encountered) LOG_TARGET_DEBUG(target, "DMI busy encountered during system bus write."); - /* Wait until sbbusy goes low */ - time_t start = time(NULL); - while (get_field(sbcs, DM_SBCS_SBBUSY)) { - if (time(NULL) - start > riscv_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); - return ERROR_FAIL; - } - if (dm_read(target, &sbcs, DM_SBCS) != ERROR_OK) - return ERROR_FAIL; - } + result = read_sbcs_nonbusy(target, &sbcs); + if (result != ERROR_OK) + return result; if (get_field(sbcs, DM_SBCS_SBBUSYERROR)) { /* We wrote while the target was busy. */ LOG_TARGET_DEBUG(target, "Sbbusyerror encountered during system bus write."); /* Clear the sticky error flag. */ dm_write(target, DM_SBCS, sbcs | DM_SBCS_SBBUSYERROR); - /* Slow down before trying again. */ - info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1; + /* Slow down before trying again. + * FIXME: Possible overflow is ignored here. + */ + riscv_scan_increase_delay(&info->learned_delays, + RISCV_DELAY_SYSBUS_WRITE); } if (get_field(sbcs, DM_SBCS_SBBUSYERROR) || dmi_busy_encountered) { @@ -4943,8 +4877,12 @@ static int write_memory_progbuf_teardown(struct target *target) static int write_memory_progbuf_handle_busy(struct target *target, target_addr_t *address_p, uint32_t size, const uint8_t *buffer) { - riscv013_clear_abstract_error(target); - increase_ac_busy_delay(target); + int res = riscv013_clear_abstract_error(target); + if (res != ERROR_OK) + return res; + res = increase_ac_busy_delay(target); + if (res != ERROR_OK) + return res; if (write_memory_progbuf_teardown(target) != ERROR_OK) return ERROR_FAIL; @@ -5077,9 +5015,9 @@ static int riscv_program_store_mprv(struct riscv_program *p, enum gdb_regno d, static int write_memory_progbuf_fill_progbuf(struct target *target, uint32_t size, bool mprven) { - if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK) + if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; struct riscv_program program; @@ -5250,7 +5188,7 @@ struct target_type riscv013_target = { }; /*** 0.13-specific implementations of various RISC-V helper functions. ***/ -static int riscv013_get_register(struct target *target, +int riscv013_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno rid) { /* It would be beneficial to move this redirection to the @@ -5259,14 +5197,14 @@ static int riscv013_get_register(struct target *target, */ if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; - if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) return ERROR_FAIL; *value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V)); *value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV)); return ERROR_OK; } - LOG_TARGET_DEBUG(target, "reading register %s", gdb_regno_name(target, rid)); + LOG_TARGET_DEBUG(target, "reading register %s", riscv_reg_gdb_regno_name(target, rid)); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; @@ -5279,11 +5217,11 @@ static int riscv013_get_register(struct target *target, return ERROR_OK; } -static int riscv013_set_register(struct target *target, enum gdb_regno rid, +int riscv013_set_register(struct target *target, enum gdb_regno rid, riscv_reg_t value) { LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s", - value, gdb_regno_name(target, rid)); + value, riscv_reg_gdb_regno_name(target, rid)); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; @@ -5647,7 +5585,7 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) if (set_dcsr_ebreak(target, step) != ERROR_OK) return ERROR_FAIL; - if (riscv_flush_registers(target) != ERROR_OK) + if (riscv_reg_flush_all(target) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } @@ -5661,7 +5599,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target, } LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step); - if (riscv_flush_registers(target) != ERROR_OK) + if (riscv_reg_flush_all(target) != ERROR_OK) return ERROR_FAIL; dm013_info_t *dm = get_dm(target); diff --git a/src/target/riscv/riscv-013.h b/src/target/riscv/riscv-013.h new file mode 100644 index 0000000..be508f7 --- /dev/null +++ b/src/target/riscv/riscv-013.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_RISCV_RISCV_013_H +#define OPENOCD_TARGET_RISCV_RISCV_013_H + +#include "riscv.h" + +/* TODO: These functions should be replaced here by access methods that can be + * reused by other modules (e.g. a function writing an abstract commands, a + * function filling/executing program buffer, etc.), while the specifics on how + * to use these general-purpose version-specific methods to get a register's + * value will be in `riscv-013_reg.c`. + */ +int riscv013_get_register(struct target *target, + riscv_reg_t *value, enum gdb_regno rid); +int riscv013_get_register_buf(struct target *target, uint8_t *value, + enum gdb_regno regno); +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); + +#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 new file mode 100644 index 0000000..a71a01c --- /dev/null +++ b/src/target/riscv/riscv-013_reg.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "riscv-013_reg.h" + +#include "riscv_reg.h" +#include "riscv_reg_impl.h" +#include "riscv-013.h" +#include <helper/time_support.h> + +static int riscv013_reg_get(struct reg *reg) +{ + struct target *target = riscv_reg_impl_get_target(reg); + + /* TODO: Hack to deal with gdb that thinks these registers still exist. */ + if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && + riscv_supports_extension(target, 'E')) { + buf_set_u64(reg->value, 0, reg->size, 0); + return ERROR_OK; + } + + if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { + if (riscv013_get_register_buf(target, reg->value, reg->number) != ERROR_OK) + return ERROR_FAIL; + + reg->valid = riscv_reg_impl_gdb_regno_cacheable(reg->number, /* is write? */ false); + } else { + uint64_t value; + int result = riscv_reg_get(target, &value, reg->number); + if (result != ERROR_OK) + return result; + buf_set_u64(reg->value, 0, reg->size, value); + } + char *str = buf_to_hex_str(reg->value, reg->size); + LOG_TARGET_DEBUG(target, "Read 0x%s from %s (valid=%d).", str, reg->name, + reg->valid); + free(str); + return ERROR_OK; +} + +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, + reg->valid); + free(str); + + /* TODO: Hack to deal with gdb that thinks these registers still exist. */ + if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && + riscv_supports_extension(target, 'E') && + 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; + + memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8)); + reg->valid = riscv_reg_impl_gdb_regno_cacheable(reg->number, /* is write? */ true); + } else { + const riscv_reg_t value = buf_get_u64(buf, 0, reg->size); + if (riscv_reg_set(target, reg->number, value) != ERROR_OK) + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static const struct reg_arch_type *riscv013_gdb_regno_reg_type(uint32_t regno) +{ + static const struct reg_arch_type riscv011_reg_type = { + .get = riscv013_reg_get, + .set = riscv013_reg_set + }; + return &riscv011_reg_type; +} + +static int riscv013_init_reg(struct target *target, uint32_t regno) +{ + return riscv_reg_impl_init_one(target, regno, riscv013_gdb_regno_reg_type(regno)); +} + +int riscv013_reg_init_all(struct target *target) +{ + if (riscv_reg_impl_init_cache(target) != ERROR_OK) + return ERROR_FAIL; + + init_shared_reg_info(target); + + 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; + + if (riscv_reg_impl_expose_csrs(target) != ERROR_OK) + return ERROR_FAIL; + + riscv_reg_impl_hide_csrs(target); + + return ERROR_OK; +} + +/** + * This function is used to save the value of a register in cache. The register + * is marked as dirty, and writeback is delayed for as long as possible. + */ +int riscv013_reg_save(struct target *target, enum gdb_regno regid) +{ + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "Can't save register %s on a hart that is not halted.", + riscv_reg_gdb_regno_name(target, regid)); + return ERROR_FAIL; + } + assert(riscv_reg_impl_gdb_regno_cacheable(regid, /* is write? */ false) && + "Only cacheable registers can be saved."); + + RISCV_INFO(r); + riscv_reg_t value; + if (!target->reg_cache) { + assert(!target_was_examined(target)); + /* To create register cache it is needed to examine the target first, + * therefore during examine, any changed register needs to be saved + * and restored manually. + */ + return ERROR_OK; + } + + struct reg *reg = riscv_reg_impl_cache_entry(target, regid); + + LOG_TARGET_DEBUG(target, "Saving %s", reg->name); + if (riscv_reg_get(target, &value, regid) != ERROR_OK) + return ERROR_FAIL; + + assert(reg->valid && + "The register is cacheable, so the cache entry must be valid now."); + /* Mark the register dirty. We assume that this function is called + * because the caller is about to mess with the underlying value of the + * register. */ + reg->dirty = true; + + r->last_activity = timeval_ms(); + + return ERROR_OK; +} diff --git a/src/target/riscv/riscv-013_reg.h b/src/target/riscv/riscv-013_reg.h new file mode 100644 index 0000000..2bdaaa0 --- /dev/null +++ b/src/target/riscv/riscv-013_reg.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_013_H +#define OPENOCD_TARGET_RISCV_RISCV_REG_013_H + +#include "target/target.h" +#include "gdb_regs.h" +#include "riscv.h" + +/** + * This file describes additional register cache interface available to the + * RISC-V Debug Specification v0.13+ targets. + */ + +/** + * Init initialize register cache. 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); + +/** + * This function is used to save the value of a register in cache. The register + * is marked as dirty, and writeback is delayed for as long as possible. + * Generally used to save registers before program buffer execution. + * + * TODO: The interface should be restricted in such a way that only GPRs can be + * saved. + */ +int riscv013_reg_save(struct target *target, enum gdb_regno regid); + +#endif /*OPENOCD_TARGET_RISCV_RISCV_REG_013_H*/ diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index b2612c2..a57c709 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -20,6 +20,7 @@ #include "helper/base64.h" #include "helper/time_support.h" #include "riscv.h" +#include "riscv_reg.h" #include "program.h" #include "gdb_regs.h" #include "rtos/rtos.h" @@ -139,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; @@ -481,38 +487,6 @@ static int riscv_init_target(struct command_context *cmd_ctx, return ERROR_OK; } -static void free_reg_names(struct target *target); - -static void riscv_free_registers(struct target *target) -{ - free_reg_names(target); - /* Free the shared structure use for most registers. */ - if (!target->reg_cache) - return; - if (target->reg_cache->reg_list) { - for (unsigned int i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++) - free(target->reg_cache->reg_list[i].arch_info); - for (unsigned int i = 0; i < target->reg_cache->num_regs; i++) - free(target->reg_cache->reg_list[i].value); - free(target->reg_cache->reg_list); - } - free(target->reg_cache); - target->reg_cache = NULL; -} - -static void free_custom_register_names(struct target *target) -{ - RISCV_INFO(info); - - if (!info->custom_register_names.reg_names) - return; - - for (unsigned int i = 0; i < info->custom_register_names.num_entries; i++) - free(info->custom_register_names.reg_names[i]); - free(info->custom_register_names.reg_names); - info->custom_register_names.reg_names = NULL; -} - static void free_wp_triggers_cache(struct target *target) { RISCV_INFO(r); @@ -541,13 +515,13 @@ static void riscv_deinit_target(struct target *target) if (!tt) LOG_TARGET_ERROR(target, "Could not identify target type."); - if (riscv_flush_registers(target) != ERROR_OK) + if (riscv_reg_flush_all(target) != ERROR_OK) LOG_TARGET_ERROR(target, "Failed to flush registers. Ignoring this error."); if (tt && info && info->version_specific) tt->deinit_target(target); - riscv_free_registers(target); + riscv_reg_free_all(target); free_wp_triggers_cache(target); if (!info) @@ -648,25 +622,25 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat { riscv_reg_t tdata1_rb, tdata2_rb; // Select which trigger to use - if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, idx) != ERROR_OK) return ERROR_FAIL; // Disable the trigger by writing 0 to it - if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) return ERROR_FAIL; // Set trigger data for tdata2 (and tdata3 if it was supported) - if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK) return ERROR_FAIL; // Set trigger data for tdata1 - if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK) return ERROR_FAIL; // Read back tdata1, tdata2, (tdata3), and check if the configuration is supported - if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) + if (riscv_reg_get(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; - if (riscv_get_register(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK) + 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; @@ -682,7 +656,7 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat LOG_TARGET_DEBUG(target, "wrote 0x%" PRIx64 " to tdata2 but read back 0x%" PRIx64, tdata2, tdata2_rb); - if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -712,7 +686,7 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) if (ret != ERROR_OK) return ret; - if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) { /* Trigger is already in use, presumably by user code. */ @@ -1242,7 +1216,7 @@ static int add_trigger(struct target *target, struct trigger *trigger) if (ret != ERROR_OK) return ret; - ret = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); + ret = riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT); if (ret != ERROR_OK) return ret; @@ -1260,7 +1234,7 @@ static int add_trigger(struct target *target, struct trigger *trigger) break; } while (0); - if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK && + if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK && ret == ERROR_OK) return ERROR_FAIL; @@ -1444,15 +1418,15 @@ static int remove_trigger(struct target *target, int unique_id) return ERROR_FAIL; riscv_reg_t tselect; - int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT); + int result = riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT); if (result != ERROR_OK) return result; bool done = false; for (unsigned int i = 0; i < r->trigger_count; i++) { if (r->trigger_unique_id[i] == unique_id) { - riscv_set_register(target, GDB_REGNO_TSELECT, i); - riscv_set_register(target, GDB_REGNO_TDATA1, 0); + riscv_reg_set(target, GDB_REGNO_TSELECT, i); + riscv_reg_set(target, GDB_REGNO_TDATA1, 0); r->trigger_unique_id[i] = -1; LOG_TARGET_DEBUG(target, "Stop using resource %d for bp %d", i, unique_id); @@ -1465,7 +1439,7 @@ static int remove_trigger(struct target *target, int unique_id) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - riscv_set_register(target, GDB_REGNO_TSELECT, tselect); + riscv_reg_set(target, GDB_REGNO_TSELECT, tselect); return ERROR_OK; } @@ -1566,7 +1540,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_ RISCV_INFO(r); riscv_reg_t tselect; - if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) return ERROR_FAIL; *unique_id = RISCV_TRIGGER_HIT_NOT_FOUND; @@ -1574,11 +1548,11 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_ if (r->trigger_unique_id[i] == -1) continue; - if (riscv_set_register(target, GDB_REGNO_TSELECT, i) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, i) != ERROR_OK) return ERROR_FAIL; uint64_t tdata1; - if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); @@ -1612,7 +1586,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_ if (tdata1 & hit_mask) { LOG_TARGET_DEBUG(target, "Trigger %u (unique_id=%" PRIi64 ") has hit bit set.", i, r->trigger_unique_id[i]); - if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK) return ERROR_FAIL; *unique_id = r->trigger_unique_id[i]; @@ -1620,7 +1594,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_ } } - if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; @@ -2082,7 +2056,7 @@ static int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_w } riscv_reg_t dpc; - if (riscv_get_register(target, &dpc, GDB_REGNO_DPC) != ERROR_OK) + if (riscv_reg_get(target, &dpc, GDB_REGNO_DPC) != ERROR_OK) return ERROR_FAIL; const uint8_t length = 4; LOG_TARGET_DEBUG(target, "dpc is 0x%" PRIx64, dpc); @@ -2109,7 +2083,7 @@ static int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_w if (get_loadstore_membase_regno(target, instruction, &rs) != ERROR_OK) return ERROR_FAIL; - if (riscv_get_register(target, &mem_addr, rs) != ERROR_OK) + if (riscv_reg_get(target, &mem_addr, rs) != ERROR_OK) return ERROR_FAIL; if (get_loadstore_memoffset(target, instruction, &memoffset) != ERROR_OK) return ERROR_FAIL; @@ -2239,44 +2213,6 @@ static int old_or_new_riscv_poll(struct target *target) return riscv_openocd_poll(target); } -static struct reg *get_reg_cache_entry(const struct target *target, - uint32_t number) -{ - assert(target->reg_cache); - assert(target->reg_cache->reg_list); - assert(number < target->reg_cache->num_regs); - return &target->reg_cache->reg_list[number]; -} - -int riscv_flush_registers(struct target *target) -{ - RISCV_INFO(r); - - if (!target->reg_cache) - return ERROR_OK; - - LOG_TARGET_DEBUG(target, "Flushing register cache"); - - /* Writing non-GPR registers may require progbuf execution, and some GPRs - * may become dirty in the process (e.g. S0, S1). For that reason, flush - * registers in reverse order, so that GPRs are flushed last. - */ - for (unsigned int number = target->reg_cache->num_regs; number-- > 0; ) { - struct reg *reg = get_reg_cache_entry(target, number); - if (reg->valid && reg->dirty) { - riscv_reg_t value = buf_get_u64(reg->value, 0, reg->size); - - LOG_TARGET_DEBUG(target, "%s is dirty; write back 0x%" PRIx64, - reg->name, value); - if (r->set_register(target, number, value) != ERROR_OK) - return ERROR_FAIL; - reg->dirty = false; - } - } - LOG_TARGET_DEBUG(target, "Flush of register cache completed"); - return ERROR_OK; -} - static enum target_debug_reason derive_debug_reason_without_hitbit(const struct target *target, riscv_reg_t dpc) { @@ -2352,7 +2288,7 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r LOG_TARGET_DEBUG(target, "No trigger hit found, deriving debug reason without it."); riscv_reg_t dpc; - if (riscv_get_register(target, &dpc, GDB_REGNO_DPC) != ERROR_OK) + if (riscv_reg_get(target, &dpc, GDB_REGNO_DPC) != ERROR_OK) return ERROR_FAIL; /* Here we don't have the hit bit set (likely, HW does not support it). * We are trying to guess the state. But here comes the problem: @@ -2530,21 +2466,21 @@ static int disable_triggers(struct target *target, riscv_reg_t *state) if (r->manual_hwbp_set) { /* Look at every trigger that may have been set. */ riscv_reg_t tselect; - if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + 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_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK) return ERROR_FAIL; riscv_reg_t tdata1; - if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; if (tdata1 & CSR_TDATA1_DMODE(riscv_xlen(target))) { state[t] = tdata1; - if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) return ERROR_FAIL; } } - if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) return ERROR_FAIL; } else { @@ -2573,17 +2509,17 @@ static int enable_triggers(struct target *target, riscv_reg_t *state) if (r->manual_hwbp_set) { /* Look at every trigger that may have been set. */ riscv_reg_t tselect; - if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) + 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_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK) return ERROR_FAIL; - if (riscv_set_register(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK) return ERROR_FAIL; } } - if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) return ERROR_FAIL; } else { @@ -2612,7 +2548,7 @@ static int resume_prep(struct target *target, int current, assert(target->state == TARGET_HALTED); RISCV_INFO(r); - if (!current && riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK) + if (!current && riscv_reg_set(target, GDB_REGNO_PC, address) != ERROR_OK) return ERROR_FAIL; if (handle_breakpoints) { @@ -2753,14 +2689,14 @@ static int riscv_target_resume(struct target *target, int current, static int riscv_effective_privilege_mode(struct target *target, int *v_mode, int *effective_mode) { riscv_reg_t priv; - if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { + if (riscv_reg_get(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read priv register."); return ERROR_FAIL; } *v_mode = get_field(priv, VIRT_PRIV_V); riscv_reg_t mstatus; - if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) { + if (riscv_reg_get(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read mstatus register."); return ERROR_FAIL; } @@ -2784,7 +2720,7 @@ static int riscv_mmu(struct target *target, int *enabled) /* Don't use MMU in explicit or effective M (machine) mode */ riscv_reg_t priv; - if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { + if (riscv_reg_get(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read priv register."); return ERROR_FAIL; } @@ -2802,7 +2738,7 @@ static int riscv_mmu(struct target *target, int *enabled) * effective privilege mode is U and hstatus.HU=0. */ if (effective_mode == PRV_U) { riscv_reg_t hstatus; - if (riscv_get_register(target, &hstatus, GDB_REGNO_HSTATUS) != ERROR_OK) { + if (riscv_reg_get(target, &hstatus, GDB_REGNO_HSTATUS) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read hstatus register."); return ERROR_FAIL; } @@ -2815,7 +2751,7 @@ static int riscv_mmu(struct target *target, int *enabled) } riscv_reg_t vsatp; - if (riscv_get_register(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) { + if (riscv_reg_get(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read vsatp register; priv=0x%" PRIx64, priv); return ERROR_FAIL; @@ -2828,7 +2764,7 @@ static int riscv_mmu(struct target *target, int *enabled) } riscv_reg_t hgatp; - if (riscv_get_register(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) { + if (riscv_reg_get(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read hgatp register; priv=0x%" PRIx64, priv); return ERROR_FAIL; @@ -2850,7 +2786,7 @@ static int riscv_mmu(struct target *target, int *enabled) } riscv_reg_t satp; - if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) { + if (riscv_reg_get(target, &satp, GDB_REGNO_SATP) != ERROR_OK) { LOG_TARGET_DEBUG(target, "Couldn't read SATP."); /* If we can't read SATP, then there must not be an MMU. */ return ERROR_OK; @@ -2961,7 +2897,7 @@ static int riscv_address_translate(struct target *target, static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, target_addr_t *physical) { riscv_reg_t vsatp; - if (riscv_get_register(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) { + if (riscv_reg_get(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read vsatp register."); return ERROR_FAIL; } @@ -2970,7 +2906,7 @@ static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, targe int vsatp_mode = get_field(vsatp, RISCV_SATP_MODE(xlen)); LOG_TARGET_DEBUG(target, "VS-stage translation mode: %d", vsatp_mode); riscv_reg_t hgatp; - if (riscv_get_register(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) { + if (riscv_reg_get(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read hgatp register."); return ERROR_FAIL; } @@ -3080,7 +3016,7 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_ } riscv_reg_t priv; - if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { + if (riscv_reg_get(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read priv register."); return ERROR_FAIL; } @@ -3089,7 +3025,7 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_ return riscv_virt2phys_v(target, virtual, physical); riscv_reg_t satp_value; - if (riscv_get_register(target, &satp_value, GDB_REGNO_SATP) != ERROR_OK) { + if (riscv_reg_get(target, &satp_value, GDB_REGNO_SATP) != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to read SATP register."); return ERROR_FAIL; } @@ -3366,10 +3302,10 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) { enum gdb_regno regno = regnums[i]; riscv_reg_t reg_value; - if (riscv_get_register(target, ®_value, regno) != ERROR_OK) + if (riscv_reg_get(target, ®_value, regno) != ERROR_OK) break; - LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, gdb_regno_name(target, regno), reg_value); + LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, riscv_reg_gdb_regno_name(target, regno), reg_value); } return ERROR_TARGET_TIMEOUT; } @@ -3578,7 +3514,7 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a if (state == RISCV_STATE_HALTED && timeval_ms() - r->last_activity > 100) { /* If we've been idle for a while, flush the register cache. Just in case * OpenOCD is going to be disconnected without shutting down cleanly. */ - if (riscv_flush_registers(target) != ERROR_OK) + if (riscv_reg_flush_all(target) != ERROR_OK) return ERROR_FAIL; } @@ -3829,7 +3765,7 @@ static int riscv_openocd_step_impl(struct target *target, int current, LOG_TARGET_DEBUG(target, "stepping hart"); if (!current) { - if (riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_PC, address) != ERROR_OK) return ERROR_FAIL; } @@ -3837,7 +3773,7 @@ static int riscv_openocd_step_impl(struct target *target, int current, /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { if (current) { - if (riscv_get_register(target, &address, GDB_REGNO_PC) != ERROR_OK) + if (riscv_reg_get(target, &address, GDB_REGNO_PC) != ERROR_OK) return ERROR_FAIL; } breakpoint = breakpoint_find(target, address); @@ -3922,13 +3858,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; @@ -5036,7 +4973,7 @@ COMMAND_HANDLER(riscv_exec_progbuf) return ERROR_FAIL; } - if (riscv_flush_registers(target) != ERROR_OK) + if (riscv_reg_flush_all(target) != ERROR_OK) return ERROR_FAIL; int error = riscv_program_exec(&prog, target); riscv_invalidate_register_cache(target); @@ -5135,7 +5072,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", @@ -5608,253 +5545,6 @@ static void riscv_invalidate_register_cache(struct target *target) register_cache_invalidate(target->reg_cache); } - -/** - * If write is true: - * return true iff we are guaranteed that the register will contain exactly - * the value we just wrote when it's read. - * If write is false: - * return true iff we are guaranteed that the register will read the same - * value in the future as the value we just read. - */ -static bool gdb_regno_cacheable(enum gdb_regno regno, bool is_write) -{ - if (regno == GDB_REGNO_ZERO) - return !is_write; - - /* GPRs, FPRs, vector registers are just normal data stores. */ - if (regno <= GDB_REGNO_XPR31 || - (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || - (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)) - return true; - - /* Most CSRs won't change value on us, but we can't assume it about arbitrary - * CSRs. */ - switch (regno) { - case GDB_REGNO_DPC: - case GDB_REGNO_VSTART: - case GDB_REGNO_VXSAT: - case GDB_REGNO_VXRM: - case GDB_REGNO_VLENB: - case GDB_REGNO_VL: - case GDB_REGNO_VTYPE: - case GDB_REGNO_MISA: - case GDB_REGNO_DCSR: - case GDB_REGNO_DSCRATCH0: - case GDB_REGNO_MSTATUS: - case GDB_REGNO_MEPC: - case GDB_REGNO_MCAUSE: - case GDB_REGNO_SATP: - /* - * WARL registers might not contain the value we just wrote, but - * these ones won't spontaneously change their value either. * - */ - return !is_write; - - case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */ - case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */ - case GDB_REGNO_TDATA2: /* Changes value when tselect is changed. */ - default: - return false; - } -} - -/** - * This function is used internally by functions that change register values. - * If `write_through` is true, it is ensured that the value of the target's - * register is set to be equal to the `value` argument. The cached value is - * updated if the register is cacheable. - */ -static int riscv_set_or_write_register(struct target *target, - enum gdb_regno regid, riscv_reg_t value, bool write_through) -{ - RISCV_INFO(r); - assert(r); - assert(r->set_register); - if (r->dtm_version == DTM_DTMCS_VERSION_0_11) - return r->set_register(target, regid, value); - - keep_alive(); - - if (regid == GDB_REGNO_PC) { - return riscv_set_or_write_register(target, GDB_REGNO_DPC, value, write_through); - } else if (regid == GDB_REGNO_PRIV) { - riscv_reg_t dcsr; - - if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) - return ERROR_FAIL; - dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV)); - dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V)); - 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, - gdb_regno_name(target, regid), value); - return r->set_register(target, regid, value); - } - - struct reg *reg = get_reg_cache_entry(target, regid); - - if (!reg->exist) { - LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); - return ERROR_FAIL; - } - - if (target->state != TARGET_HALTED) { - LOG_TARGET_DEBUG(target, - "Target not halted, writing to target: %s <- 0x%" PRIx64, - reg->name, value); - return r->set_register(target, regid, value); - } - - const bool need_to_write = !reg->valid || reg->dirty || - value != buf_get_u64(reg->value, 0, reg->size); - const bool cacheable = gdb_regno_cacheable(regid, need_to_write); - - if (!cacheable || (write_through && need_to_write)) { - LOG_TARGET_DEBUG(target, - "Writing to target: %s <- 0x%" PRIx64 " (cacheable=%s, valid=%s, dirty=%s)", - reg->name, value, cacheable ? "true" : "false", - reg->valid ? "true" : "false", - reg->dirty ? "true" : "false"); - if (r->set_register(target, regid, value) != ERROR_OK) - return ERROR_FAIL; - - reg->dirty = false; - } else { - reg->dirty = need_to_write; - } - - buf_set_u64(reg->value, 0, reg->size, value); - reg->valid = cacheable; - - LOG_TARGET_DEBUG(target, - "Wrote 0x%" PRIx64 " to %s (cacheable=%s, valid=%s, dirty=%s)", - value, reg->name, cacheable ? "true" : "false", - reg->valid ? "true" : "false", - reg->dirty ? "true" : "false"); - return ERROR_OK; -} - -/** - * This function is used to change the value of a register. The new value may - * be cached, and may not be written until the hart is resumed. - */ -int riscv_set_register(struct target *target, enum gdb_regno regid, - riscv_reg_t value) -{ - return riscv_set_or_write_register(target, regid, value, - /* write_through */ false); -} - -/** - * This function is used to change the value of a register. The new value may - * be cached, but it will be written to hart immediately. - */ -int riscv_write_register(struct target *target, enum gdb_regno regid, - riscv_reg_t value) -{ - return riscv_set_or_write_register(target, regid, value, - /* write_through */ true); -} - -/** - * This function is used to get the value of a register. If possible, the value - * in cache will be updated. - */ -int riscv_get_register(struct target *target, riscv_reg_t *value, - enum gdb_regno regid) -{ - RISCV_INFO(r); - assert(r); - assert(r->get_register); - if (r->dtm_version == DTM_DTMCS_VERSION_0_11) - return r->get_register(target, value, regid); - - keep_alive(); - - if (regid == GDB_REGNO_PC) - return riscv_get_register(target, value, GDB_REGNO_DPC); - - if (!target->reg_cache) { - assert(!target_was_examined(target)); - LOG_TARGET_DEBUG(target, "No cache, reading %s from target", - gdb_regno_name(target, regid)); - return r->get_register(target, value, regid); - } - - struct reg *reg = get_reg_cache_entry(target, regid); - if (!reg->exist) { - LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); - return ERROR_FAIL; - } - - if (reg->valid) { - *value = buf_get_u64(reg->value, 0, reg->size); - LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64 " (cached)", reg->name, - *value); - return ERROR_OK; - } - - LOG_TARGET_DEBUG(target, "Reading %s from target", reg->name); - if (r->get_register(target, value, regid) != ERROR_OK) - return ERROR_FAIL; - - buf_set_u64(reg->value, 0, reg->size, *value); - reg->valid = gdb_regno_cacheable(regid, /* is write? */ false) && - target->state == TARGET_HALTED; - reg->dirty = false; - - LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64, reg->name, *value); - return ERROR_OK; -} - -/** - * This function is used to save the value of a register in cache. The register - * is marked as dirty, and writeback is delayed for as long as possible. - */ -int riscv_save_register(struct target *target, enum gdb_regno regid) -{ - if (target->state != TARGET_HALTED) { - LOG_TARGET_ERROR(target, "Can't save register %s on a hart that is not halted.", - gdb_regno_name(target, regid)); - return ERROR_FAIL; - } - assert(gdb_regno_cacheable(regid, /* is write? */ false) && - "Only cacheable registers can be saved."); - - RISCV_INFO(r); - riscv_reg_t value; - if (!target->reg_cache) { - assert(!target_was_examined(target)); - /* To create register cache it is needed to examine the target first, - * therefore during examine, any changed register needs to be saved - * and restored manually. - */ - return ERROR_OK; - } - - struct reg *reg = get_reg_cache_entry(target, regid); - - LOG_TARGET_DEBUG(target, "Saving %s", reg->name); - if (riscv_get_register(target, &value, regid) != ERROR_OK) - return ERROR_FAIL; - - assert(reg->valid && - "The register is cacheable, so the cache entry must be valid now."); - /* Mark the register dirty. We assume that this function is called - * because the caller is about to mess with the underlying value of the - * register. */ - reg->dirty = true; - - r->last_activity = timeval_ms(); - - return ERROR_OK; -} - int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state) { RISCV_INFO(r); @@ -5924,10 +5614,10 @@ int riscv_get_dmi_scan_length(struct target *target) static int check_if_trigger_exists(struct target *target, unsigned int index) { /* If we can't write tselect, then this hart does not support triggers. */ - if (riscv_set_register(target, GDB_REGNO_TSELECT, index) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, index) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; riscv_reg_t tselect_rb; - if (riscv_get_register(target, &tselect_rb, GDB_REGNO_TSELECT) != ERROR_OK) + if (riscv_reg_get(target, &tselect_rb, GDB_REGNO_TSELECT) != ERROR_OK) return ERROR_FAIL; /* Mask off the top bit, which is used as tdrmode in legacy RISC-V Debug Spec * (old revisions of v0.11 spec). */ @@ -5947,7 +5637,7 @@ static int get_trigger_types(struct target *target, unsigned int *trigger_tinfo, { assert(trigger_tinfo); riscv_reg_t tinfo; - if (riscv_get_register(target, &tinfo, GDB_REGNO_TINFO) == ERROR_OK) { + if (riscv_reg_get(target, &tinfo, GDB_REGNO_TINFO) == ERROR_OK) { /* tinfo.INFO == 1: trigger doesn’t exist * tinfo == 0 or tinfo.INFO != 1 and tinfo LSB is set: invalid tinfo */ if (tinfo == 0 || tinfo & 0x1) @@ -5990,7 +5680,7 @@ static int disable_trigger_if_dmode(struct target *target, riscv_reg_t tdata1) if (!dmode_is_set) /* Nothing to do */ return ERROR_OK; - return riscv_set_register(target, GDB_REGNO_TDATA1, 0); + return riscv_reg_set(target, GDB_REGNO_TDATA1, 0); } /** @@ -6013,7 +5703,7 @@ int riscv_enumerate_triggers(struct target *target) } riscv_reg_t orig_tselect; - int result = riscv_get_register(target, &orig_tselect, GDB_REGNO_TSELECT); + int result = riscv_reg_get(target, &orig_tselect, GDB_REGNO_TSELECT); /* If tselect is not readable, the trigger module is likely not * implemented. */ if (result != ERROR_OK) { @@ -6033,7 +5723,7 @@ int riscv_enumerate_triggers(struct target *target) break; riscv_reg_t tdata1; - if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) return ERROR_FAIL; result = get_trigger_types(target, &r->trigger_tinfo[t], tdata1); @@ -6049,7 +5739,7 @@ int riscv_enumerate_triggers(struct target *target) return ERROR_FAIL; } - if (riscv_set_register(target, GDB_REGNO_TSELECT, orig_tselect) != ERROR_OK) + if (riscv_reg_set(target, GDB_REGNO_TSELECT, orig_tselect) != ERROR_OK) return ERROR_FAIL; r->triggers_enumerated = true; @@ -6059,1006 +5749,6 @@ int riscv_enumerate_triggers(struct target *target) return ERROR_OK; } -static char *init_reg_name(const char *name) -{ - const int size_buf = strlen(name) + 1; - - char * const buf = calloc(size_buf, sizeof(char)); - if (!buf) { - LOG_ERROR("Failed to allocate memory for a register name."); - return NULL; - } - strcpy(buf, name); - return buf; -} - -static char *init_reg_name_with_prefix(const char *name_prefix, - unsigned int num) -{ - const int size_buf = snprintf(NULL, 0, "%s%d", name_prefix, num) + 1; - - char * const buf = calloc(size_buf, sizeof(char)); - if (!buf) { - LOG_ERROR("Failed to allocate memory for a register name."); - return NULL; - } - int result = snprintf(buf, size_buf, "%s%d", name_prefix, num); - assert(result > 0 && result <= (size_buf - 1)); - return buf; -} - -static const char * const default_reg_names[GDB_REGNO_COUNT] = { - [GDB_REGNO_ZERO] = "zero", - [GDB_REGNO_RA] = "ra", - [GDB_REGNO_SP] = "sp", - [GDB_REGNO_GP] = "gp", - [GDB_REGNO_TP] = "tp", - [GDB_REGNO_T0] = "t0", - [GDB_REGNO_T1] = "t1", - [GDB_REGNO_T2] = "t2", - [GDB_REGNO_FP] = "fp", - [GDB_REGNO_S1] = "s1", - [GDB_REGNO_A0] = "a0", - [GDB_REGNO_A1] = "a1", - [GDB_REGNO_A2] = "a2", - [GDB_REGNO_A3] = "a3", - [GDB_REGNO_A4] = "a4", - [GDB_REGNO_A5] = "a5", - [GDB_REGNO_A6] = "a6", - [GDB_REGNO_A7] = "a7", - [GDB_REGNO_S2] = "s2", - [GDB_REGNO_S3] = "s3", - [GDB_REGNO_S4] = "s4", - [GDB_REGNO_S5] = "s5", - [GDB_REGNO_S6] = "s6", - [GDB_REGNO_S7] = "s7", - [GDB_REGNO_S8] = "s8", - [GDB_REGNO_S9] = "s9", - [GDB_REGNO_S10] = "s10", - [GDB_REGNO_S11] = "s11", - [GDB_REGNO_T3] = "t3", - [GDB_REGNO_T4] = "t4", - [GDB_REGNO_T5] = "t5", - [GDB_REGNO_T6] = "t6", - [GDB_REGNO_PC] = "pc", - [GDB_REGNO_CSR0] = "csr0", - [GDB_REGNO_PRIV] = "priv", - [GDB_REGNO_FT0] = "ft0", - [GDB_REGNO_FT1] = "ft1", - [GDB_REGNO_FT2] = "ft2", - [GDB_REGNO_FT3] = "ft3", - [GDB_REGNO_FT4] = "ft4", - [GDB_REGNO_FT5] = "ft5", - [GDB_REGNO_FT6] = "ft6", - [GDB_REGNO_FT7] = "ft7", - [GDB_REGNO_FS0] = "fs0", - [GDB_REGNO_FS1] = "fs1", - [GDB_REGNO_FA0] = "fa0", - [GDB_REGNO_FA1] = "fa1", - [GDB_REGNO_FA2] = "fa2", - [GDB_REGNO_FA3] = "fa3", - [GDB_REGNO_FA4] = "fa4", - [GDB_REGNO_FA5] = "fa5", - [GDB_REGNO_FA6] = "fa6", - [GDB_REGNO_FA7] = "fa7", - [GDB_REGNO_FS2] = "fs2", - [GDB_REGNO_FS3] = "fs3", - [GDB_REGNO_FS4] = "fs4", - [GDB_REGNO_FS5] = "fs5", - [GDB_REGNO_FS6] = "fs6", - [GDB_REGNO_FS7] = "fs7", - [GDB_REGNO_FS8] = "fs8", - [GDB_REGNO_FS9] = "fs9", - [GDB_REGNO_FS10] = "fs10", - [GDB_REGNO_FS11] = "fs11", - [GDB_REGNO_FT8] = "ft8", - [GDB_REGNO_FT9] = "ft9", - [GDB_REGNO_FT10] = "ft10", - [GDB_REGNO_FT11] = "ft11", - - #define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = #csr_name, - #include "encoding.h" - #undef DECLARE_CSR -}; - -static void free_reg_names(struct target *target) -{ - RISCV_INFO(info); - - if (!info->reg_names) - return; - - for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i) - free(info->reg_names[i]); - free(info->reg_names); - info->reg_names = NULL; - - free_custom_register_names(target); -} - -static void init_custom_csr_names(const struct target *target) -{ - RISCV_INFO(info); - range_list_t *entry; - - list_for_each_entry(entry, &info->expose_csr, list) { - if (!entry->name) - continue; - assert(entry->low == entry->high); - const unsigned int regno = entry->low + GDB_REGNO_CSR0; - assert(regno <= GDB_REGNO_CSR4095); - if (info->reg_names[regno]) - return; - info->reg_names[regno] = init_reg_name(entry->name); - } -} - -const char *gdb_regno_name(const struct target *target, enum gdb_regno regno) -{ - RISCV_INFO(info); - - if (regno >= GDB_REGNO_COUNT) { - assert(info->custom_register_names.reg_names); - assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.num_entries); - return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT]; - } - - if (!info->reg_names) - info->reg_names = calloc(GDB_REGNO_COUNT, sizeof(char *)); - - if (info->reg_names[regno]) - return info->reg_names[regno]; - if (default_reg_names[regno]) - return default_reg_names[regno]; - if (regno <= GDB_REGNO_XPR31) { - info->reg_names[regno] = init_reg_name_with_prefix("x", regno - GDB_REGNO_ZERO); - return info->reg_names[regno]; - } - if (regno <= GDB_REGNO_V31 && regno >= GDB_REGNO_V0) { - info->reg_names[regno] = init_reg_name_with_prefix("v", regno - GDB_REGNO_V0); - return info->reg_names[regno]; - } - if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { - init_custom_csr_names(target); - info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0); - return info->reg_names[regno]; - } - assert(!"Encountered uninitialized entry in reg_names table"); - - return NULL; -} - -static struct target *get_target_from_reg(const struct reg *reg); - -/** - * This function is the handler of user's request to read a register. - */ -static int riscv013_reg_get(struct reg *reg) -{ - struct target *target = get_target_from_reg(reg); - RISCV_INFO(r); - assert(r); - assert(r->dtm_version == DTM_DTMCS_VERSION_1_0); - - /* TODO: Hack to deal with gdb that thinks these registers still exist. */ - if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && - riscv_supports_extension(target, 'E')) { - buf_set_u64(reg->value, 0, reg->size, 0); - return ERROR_OK; - } - - if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { - if (!r->get_register_buf) { - LOG_TARGET_ERROR(target, - "Reading register %s not supported on this target.", - reg->name); - return ERROR_FAIL; - } - - if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK) - return ERROR_FAIL; - - reg->valid = gdb_regno_cacheable(reg->number, /* is write? */ false); - } else { - uint64_t value; - int result = riscv_get_register(target, &value, reg->number); - if (result != ERROR_OK) - return result; - buf_set_u64(reg->value, 0, reg->size, value); - } - char *str = buf_to_hex_str(reg->value, reg->size); - LOG_TARGET_DEBUG(target, "Read 0x%s from %s (valid=%d).", str, reg->name, - reg->valid); - free(str); - return ERROR_OK; -} - -/** - * This function is the handler of user's request to write a register. - */ -static int riscv013_reg_set(struct reg *reg, uint8_t *buf) -{ - struct target *target = get_target_from_reg(reg); - RISCV_INFO(r); - assert(r); - assert(r->dtm_version == DTM_DTMCS_VERSION_1_0); - - char *str = buf_to_hex_str(buf, reg->size); - LOG_TARGET_DEBUG(target, "Write 0x%s to %s (valid=%d).", str, reg->name, - reg->valid); - free(str); - - /* TODO: Hack to deal with gdb that thinks these registers still exist. */ - if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && - riscv_supports_extension(target, 'E') && - 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 (!r->set_register_buf) { - LOG_TARGET_ERROR(target, - "Writing register %s not supported on this target.", - reg->name); - return ERROR_FAIL; - } - - if (r->set_register_buf(target, reg->number, buf) != ERROR_OK) - return ERROR_FAIL; - - memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8)); - reg->valid = gdb_regno_cacheable(reg->number, /* is write? */ true); - } else { - const riscv_reg_t value = buf_get_u64(buf, 0, reg->size); - if (riscv_set_register(target, reg->number, value) != ERROR_OK) - return ERROR_FAIL; - } - - return ERROR_OK; -} - -static int init_custom_register_names(struct list_head *expose_custom, - struct reg_name_table *custom_register_names) -{ - unsigned int custom_regs_num = 0; - if (!list_empty(expose_custom)) { - range_list_t *entry; - list_for_each_entry(entry, expose_custom, list) - custom_regs_num += entry->high - entry->low + 1; - } - - if (!custom_regs_num) - return ERROR_OK; - - custom_register_names->reg_names = calloc(custom_regs_num, sizeof(char *)); - if (!custom_register_names->reg_names) { - LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names"); - return ERROR_FAIL; - } - custom_register_names->num_entries = custom_regs_num; - char **reg_names = custom_register_names->reg_names; - range_list_t *range; - unsigned int next_custom_reg_index = 0; - list_for_each_entry(range, expose_custom, list) { - for (unsigned int custom_number = range->low; custom_number <= range->high; ++custom_number) { - if (range->name) - reg_names[next_custom_reg_index] = init_reg_name(range->name); - else - reg_names[next_custom_reg_index] = - init_reg_name_with_prefix("custom", custom_number); - - if (!reg_names[next_custom_reg_index]) - return ERROR_FAIL; - ++next_custom_reg_index; - } - } - return ERROR_OK; -} - -static bool is_known_standard_csr(unsigned int csr_num) -{ - static const bool is_csr_in_buf[GDB_REGNO_CSR4095 - GDB_REGNO_CSR0 + 1] = { - #define DECLARE_CSR(csr_name, number)[number] = true, - #include "encoding.h" - #undef DECLARE_CSR - }; - assert(csr_num < ARRAY_SIZE(is_csr_in_buf)); - - return is_csr_in_buf[csr_num]; -} - -static bool reg_is_initialized(const struct reg *reg) -{ - assert(reg); - if (!reg->feature) { - const struct reg default_reg = {0}; - assert(!memcmp(&default_reg, reg, sizeof(*reg))); - return false; - } - assert(reg->arch_info); - assert(((riscv_reg_info_t *)reg->arch_info)->target); - assert((!reg->exist && !reg->value) || (reg->exist && reg->value)); - assert(reg->valid || !reg->dirty); - return true; -} - -static struct target *get_target_from_reg(const struct reg *reg) -{ - assert(reg_is_initialized(reg)); - return ((const riscv_reg_info_t *)reg->arch_info)->target; -} - -static int riscv011_reg_get(struct reg *reg) -{ - struct target * const target = get_target_from_reg(reg); - RISCV_INFO(r); - assert(r); - assert(r->dtm_version == DTM_DTMCS_VERSION_0_11); - riscv_reg_t value; - const int result = r->get_register(target, &value, reg->number); - if (result != ERROR_OK) - return result; - buf_set_u64(reg->value, 0, reg->size, value); - return ERROR_OK; -} - -static int riscv011_reg_set(struct reg *reg, uint8_t *buf) -{ - const riscv_reg_t value = buf_get_u64(buf, 0, reg->size); - struct target * const target = get_target_from_reg(reg); - RISCV_INFO(r); - assert(r); - assert(r->dtm_version == DTM_DTMCS_VERSION_0_11); - 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; - } - return r->set_register(target, reg->number, value); -} - -static struct reg_arch_type *gdb_regno_reg_type(const struct target *target, - uint32_t regno) -{ - RISCV_INFO(info); - assert(info); - if (info->dtm_version == DTM_DTMCS_VERSION_0_11) { - static struct reg_arch_type riscv011_reg_type = { - .get = riscv011_reg_get, - .set = riscv011_reg_set - }; - return &riscv011_reg_type; - } - - static struct reg_arch_type riscv013_reg_type = { - .get = riscv013_reg_get, - .set = riscv013_reg_set - }; - return &riscv013_reg_type; -} - -static struct reg_feature *gdb_regno_feature(uint32_t regno) -{ - if (regno <= GDB_REGNO_XPR31 || regno == GDB_REGNO_PC) { - static struct reg_feature feature_cpu = { - .name = "org.gnu.gdb.riscv.cpu" - }; - return &feature_cpu; - } - if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || - regno == GDB_REGNO_FFLAGS || - regno == GDB_REGNO_FRM || - regno == GDB_REGNO_FCSR) { - static struct reg_feature feature_fpu = { - .name = "org.gnu.gdb.riscv.fpu" - }; - return &feature_fpu; - } - if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) { - static struct reg_feature feature_vector = { - .name = "org.gnu.gdb.riscv.vector" - }; - return &feature_vector; - } - if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { - static struct reg_feature feature_csr = { - .name = "org.gnu.gdb.riscv.csr" - }; - return &feature_csr; - } - if (regno == GDB_REGNO_PRIV) { - static struct reg_feature feature_virtual = { - .name = "org.gnu.gdb.riscv.virtual" - }; - return &feature_virtual; - } - assert(regno >= GDB_REGNO_COUNT); - static struct reg_feature feature_custom = { - .name = "org.gnu.gdb.riscv.custom" - }; - return &feature_custom; -} - -static bool gdb_regno_caller_save(uint32_t regno) -{ - return regno <= GDB_REGNO_XPR31 || - regno == GDB_REGNO_PC || - (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31); -} - -static struct reg_data_type *gdb_regno_reg_data_type(const struct target *target, - uint32_t regno) -{ - if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) { - static struct reg_data_type type_ieee_single = { - .type = REG_TYPE_IEEE_SINGLE, - .id = "ieee_single" - }; - static struct reg_data_type type_ieee_double = { - .type = REG_TYPE_IEEE_DOUBLE, - .id = "ieee_double" - }; - static struct reg_data_type_union_field single_double_fields[] = { - {"float", &type_ieee_single, single_double_fields + 1}, - {"double", &type_ieee_double, NULL}, - }; - static struct reg_data_type_union single_double_union = { - .fields = single_double_fields - }; - static struct reg_data_type type_ieee_single_double = { - .type = REG_TYPE_ARCH_DEFINED, - .id = "FPU_FD", - .type_class = REG_TYPE_CLASS_UNION, - {.reg_type_union = &single_double_union} - }; - return riscv_supports_extension(target, 'D') ? - &type_ieee_single_double : - &type_ieee_single; - } - if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) { - RISCV_INFO(info); - return &info->type_vector; - } - return NULL; -} - -static const char *gdb_regno_group(uint32_t regno) -{ - if (regno <= GDB_REGNO_XPR31 || - regno == GDB_REGNO_PC || - regno == GDB_REGNO_PRIV) - return "general"; - if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || - regno == GDB_REGNO_FFLAGS || - regno == GDB_REGNO_FRM || - regno == GDB_REGNO_FCSR) - return "float"; - if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) - return "csr"; - if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) - return "vector"; - assert(regno >= GDB_REGNO_COUNT); - return "custom"; -} - -uint32_t gdb_regno_size(const struct target *target, uint32_t regno) -{ - if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) - return riscv_supports_extension(target, 'D') ? 64 : 32; - if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) - return riscv_vlenb(target) * 8; - if (regno == GDB_REGNO_PRIV) - return 8; - if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { - const unsigned int csr_number = regno - GDB_REGNO_CSR0; - switch (csr_number) { - case CSR_DCSR: - case CSR_MVENDORID: - case CSR_MCOUNTINHIBIT: - - case CSR_FFLAGS: - case CSR_FRM: - case CSR_FCSR: - - case CSR_SCOUNTEREN: - case CSR_MCOUNTEREN: - return 32; - } - } - return riscv_xlen(target); -} - -static bool vlenb_exists(const struct target *target) -{ - return riscv_vlenb(target) != 0; -} - -static bool mtopi_exists(const struct target *target) -{ - RISCV_INFO(info) - /* TODO: The naming is quite unfortunate here. `mtopi_readable` refers - * to how the fact that `mtopi` exists was deduced during examine. - */ - return info->mtopi_readable; -} - -static bool mtopei_exists(const struct target *target) -{ - RISCV_INFO(info) - /* TODO: The naming is quite unfortunate here. `mtopei_readable` refers - * to how the fact that `mtopei` exists was deduced during examine. - */ - return info->mtopei_readable; -} - -static bool gdb_regno_exist(const struct target *target, uint32_t regno) -{ - if (regno <= GDB_REGNO_XPR15 || - regno == GDB_REGNO_PC || - regno == GDB_REGNO_PRIV) - return true; - if (regno > GDB_REGNO_XPR15 && regno <= GDB_REGNO_XPR31) - return !riscv_supports_extension(target, 'E'); - if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) - return riscv_supports_extension(target, 'F'); - if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) - return vlenb_exists(target); - if (regno >= GDB_REGNO_COUNT) - return true; - assert(regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095); - const unsigned int csr_number = regno - GDB_REGNO_CSR0; - switch (csr_number) { - case CSR_FFLAGS: - case CSR_FRM: - case CSR_FCSR: - return riscv_supports_extension(target, 'F'); - case CSR_SCOUNTEREN: - case CSR_SSTATUS: - case CSR_STVEC: - case CSR_SIP: - case CSR_SIE: - case CSR_SSCRATCH: - case CSR_SEPC: - case CSR_SCAUSE: - case CSR_STVAL: - case CSR_SATP: - return riscv_supports_extension(target, 'S'); - case CSR_MEDELEG: - case CSR_MIDELEG: - /* "In systems with only M-mode, or with both M-mode and - * U-mode but without U-mode trap support, the medeleg and - * mideleg registers should not exist." */ - return riscv_supports_extension(target, 'S') || - riscv_supports_extension(target, 'N'); - - case CSR_PMPCFG1: - case CSR_PMPCFG3: - case CSR_CYCLEH: - case CSR_TIMEH: - case CSR_INSTRETH: - case CSR_HPMCOUNTER3H: - case CSR_HPMCOUNTER4H: - case CSR_HPMCOUNTER5H: - case CSR_HPMCOUNTER6H: - case CSR_HPMCOUNTER7H: - case CSR_HPMCOUNTER8H: - case CSR_HPMCOUNTER9H: - case CSR_HPMCOUNTER10H: - case CSR_HPMCOUNTER11H: - case CSR_HPMCOUNTER12H: - case CSR_HPMCOUNTER13H: - case CSR_HPMCOUNTER14H: - case CSR_HPMCOUNTER15H: - case CSR_HPMCOUNTER16H: - case CSR_HPMCOUNTER17H: - case CSR_HPMCOUNTER18H: - case CSR_HPMCOUNTER19H: - case CSR_HPMCOUNTER20H: - case CSR_HPMCOUNTER21H: - case CSR_HPMCOUNTER22H: - case CSR_HPMCOUNTER23H: - case CSR_HPMCOUNTER24H: - case CSR_HPMCOUNTER25H: - case CSR_HPMCOUNTER26H: - case CSR_HPMCOUNTER27H: - case CSR_HPMCOUNTER28H: - case CSR_HPMCOUNTER29H: - case CSR_HPMCOUNTER30H: - case CSR_HPMCOUNTER31H: - case CSR_MCYCLEH: - case CSR_MINSTRETH: - case CSR_MHPMCOUNTER4H: - case CSR_MHPMCOUNTER5H: - case CSR_MHPMCOUNTER6H: - case CSR_MHPMCOUNTER7H: - case CSR_MHPMCOUNTER8H: - case CSR_MHPMCOUNTER9H: - case CSR_MHPMCOUNTER10H: - case CSR_MHPMCOUNTER11H: - case CSR_MHPMCOUNTER12H: - case CSR_MHPMCOUNTER13H: - case CSR_MHPMCOUNTER14H: - case CSR_MHPMCOUNTER15H: - case CSR_MHPMCOUNTER16H: - case CSR_MHPMCOUNTER17H: - case CSR_MHPMCOUNTER18H: - case CSR_MHPMCOUNTER19H: - case CSR_MHPMCOUNTER20H: - case CSR_MHPMCOUNTER21H: - case CSR_MHPMCOUNTER22H: - case CSR_MHPMCOUNTER23H: - case CSR_MHPMCOUNTER24H: - case CSR_MHPMCOUNTER25H: - case CSR_MHPMCOUNTER26H: - case CSR_MHPMCOUNTER27H: - case CSR_MHPMCOUNTER28H: - case CSR_MHPMCOUNTER29H: - case CSR_MHPMCOUNTER30H: - case CSR_MHPMCOUNTER31H: - return riscv_xlen(target) == 32; - case CSR_MCOUNTEREN: - return riscv_supports_extension(target, 'U'); - /* Interrupts M-Mode CSRs. */ - case CSR_MISELECT: - case CSR_MIREG: - case CSR_MVIEN: - case CSR_MVIP: - case CSR_MIEH: - case CSR_MIPH: - return mtopi_exists(target); - case CSR_MIDELEGH: - case CSR_MVIENH: - case CSR_MVIPH: - return mtopi_exists(target) && - riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'S'); - /* Interrupts S-Mode CSRs. */ - case CSR_SISELECT: - case CSR_SIREG: - case CSR_STOPI: - return mtopi_exists(target) && - riscv_supports_extension(target, 'S'); - case CSR_STOPEI: - return mtopei_exists(target) && - riscv_supports_extension(target, 'S'); - case CSR_SIEH: - case CSR_SIPH: - return mtopi_exists(target) && - riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'S'); - /* Interrupts Hypervisor and VS CSRs. */ - case CSR_HVIEN: - case CSR_HVICTL: - case CSR_HVIPRIO1: - case CSR_HVIPRIO2: - case CSR_VSISELECT: - case CSR_VSIREG: - case CSR_VSTOPI: - return mtopi_exists(target) && - riscv_supports_extension(target, 'H'); - case CSR_VSTOPEI: - return mtopei_exists(target) && - riscv_supports_extension(target, 'H'); - case CSR_HIDELEGH: - case CSR_HVIENH: - case CSR_HVIPH: - case CSR_HVIPRIO1H: - case CSR_HVIPRIO2H: - case CSR_VSIEH: - case CSR_VSIPH: - return mtopi_exists(target) && - riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'H'); - } - return is_known_standard_csr(csr_number); -} - -static unsigned int gdb_regno_custom_number(const struct target *target, uint32_t regno) -{ - if (regno < GDB_REGNO_COUNT) - return 0; - - RISCV_INFO(info); - assert(!list_empty(&info->expose_custom)); - range_list_t *range; - unsigned int regno_start = GDB_REGNO_COUNT; - unsigned int start = 0; - unsigned int offset = 0; - list_for_each_entry(range, &info->expose_custom, list) { - start = range->low; - assert(regno >= regno_start); - offset = regno - regno_start; - const unsigned int regs_in_range = range->high - range->low + 1; - if (offset < regs_in_range) - break; - regno_start += regs_in_range; - } - return start + offset; -} - -static int resize_reg(const struct target *target, uint32_t regno, bool exist, - uint32_t size) -{ - struct reg *reg = get_reg_cache_entry(target, regno); - assert(reg_is_initialized(reg)); - free(reg->value); - reg->size = size; - reg->exist = exist; - if (reg->exist) { - reg->value = malloc(DIV_ROUND_UP(reg->size, 8)); - if (!reg->value) { - LOG_ERROR("Failed to allocate memory."); - return ERROR_FAIL; - } - } else { - reg->value = NULL; - } - assert(reg_is_initialized(reg)); - return ERROR_OK; -} - -static int set_reg_exist(const struct target *target, uint32_t regno, bool exist) -{ - const struct reg *reg = get_reg_cache_entry(target, regno); - assert(reg_is_initialized(reg)); - return resize_reg(target, regno, exist, reg->size); -} - -static int init_reg(struct target *target, uint32_t regno) -{ - struct reg * const reg = get_reg_cache_entry(target, regno); - if (reg_is_initialized(reg)) - return ERROR_OK; - reg->number = regno; - reg->type = gdb_regno_reg_type(target, regno); - reg->dirty = false; - reg->valid = false; - reg->hidden = false; - reg->name = gdb_regno_name(target, regno); - reg->feature = gdb_regno_feature(regno); - reg->caller_save = gdb_regno_caller_save(regno); - reg->reg_data_type = gdb_regno_reg_data_type(target, regno); - reg->group = gdb_regno_group(regno); - if (regno < GDB_REGNO_COUNT) { - RISCV_INFO(info); - reg->arch_info = &info->shared_reg_info; - } else { - reg->arch_info = calloc(1, sizeof(riscv_reg_info_t)); - if (!reg->arch_info) { - LOG_ERROR("Out of memory."); - return ERROR_FAIL; - } - riscv_reg_info_t * const reg_arch_info = reg->arch_info; - 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)); -} - -static int riscv_init_reg_cache(struct target *target) -{ - RISCV_INFO(info); - - riscv_free_registers(target); - - target->reg_cache = calloc(1, sizeof(*target->reg_cache)); - if (!target->reg_cache) { - LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache"); - return ERROR_FAIL; - } - target->reg_cache->name = "RISC-V Registers"; - - if (init_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) { - LOG_TARGET_ERROR(target, "init_custom_register_names failed"); - return ERROR_FAIL; - } - - target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.num_entries; - LOG_TARGET_DEBUG(target, "create register cache for %d registers", - target->reg_cache->num_regs); - - target->reg_cache->reg_list = - calloc(target->reg_cache->num_regs, sizeof(struct reg)); - if (!target->reg_cache->reg_list) { - LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache->reg_list"); - return ERROR_FAIL; - } - return ERROR_OK; -} - -static void init_shared_reg_info(struct target *target) -{ - RISCV_INFO(info); - info->shared_reg_info.target = target; - info->shared_reg_info.custom_number = 0; -} - -static void init_vector_reg_type(const struct target *target) -{ - RISCV_INFO(info); - static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" }; - static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" }; - static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" }; - static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" }; - static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" }; - - /* This is roughly the XML we want: - * <vector id="bytes" type="uint8" count="16"/> - * <vector id="shorts" type="uint16" count="8"/> - * <vector id="words" type="uint32" count="4"/> - * <vector id="longs" type="uint64" count="2"/> - * <vector id="quads" type="uint128" count="1"/> - * <union id="riscv_vector_type"> - * <field name="b" type="bytes"/> - * <field name="s" type="shorts"/> - * <field name="w" type="words"/> - * <field name="l" type="longs"/> - * <field name="q" type="quads"/> - * </union> - */ - - info->vector_uint8.type = &type_uint8; - info->vector_uint8.count = riscv_vlenb(target); - info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED; - info->type_uint8_vector.id = "bytes"; - info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR; - info->type_uint8_vector.reg_type_vector = &info->vector_uint8; - - info->vector_uint16.type = &type_uint16; - info->vector_uint16.count = riscv_vlenb(target) / 2; - info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED; - info->type_uint16_vector.id = "shorts"; - info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR; - info->type_uint16_vector.reg_type_vector = &info->vector_uint16; - - info->vector_uint32.type = &type_uint32; - info->vector_uint32.count = riscv_vlenb(target) / 4; - info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED; - info->type_uint32_vector.id = "words"; - info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR; - info->type_uint32_vector.reg_type_vector = &info->vector_uint32; - - info->vector_uint64.type = &type_uint64; - info->vector_uint64.count = riscv_vlenb(target) / 8; - info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED; - info->type_uint64_vector.id = "longs"; - info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR; - info->type_uint64_vector.reg_type_vector = &info->vector_uint64; - - info->vector_uint128.type = &type_uint128; - info->vector_uint128.count = riscv_vlenb(target) / 16; - info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED; - info->type_uint128_vector.id = "quads"; - info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR; - info->type_uint128_vector.reg_type_vector = &info->vector_uint128; - - info->vector_fields[0].name = "b"; - info->vector_fields[0].type = &info->type_uint8_vector; - if (riscv_vlenb(target) >= 2) { - info->vector_fields[0].next = info->vector_fields + 1; - info->vector_fields[1].name = "s"; - info->vector_fields[1].type = &info->type_uint16_vector; - } else { - info->vector_fields[0].next = NULL; - } - if (riscv_vlenb(target) >= 4) { - info->vector_fields[1].next = info->vector_fields + 2; - info->vector_fields[2].name = "w"; - info->vector_fields[2].type = &info->type_uint32_vector; - } else { - info->vector_fields[1].next = NULL; - } - if (riscv_vlenb(target) >= 8) { - info->vector_fields[2].next = info->vector_fields + 3; - info->vector_fields[3].name = "l"; - info->vector_fields[3].type = &info->type_uint64_vector; - } else { - info->vector_fields[2].next = NULL; - } - if (riscv_vlenb(target) >= 16) { - info->vector_fields[3].next = info->vector_fields + 4; - info->vector_fields[4].name = "q"; - info->vector_fields[4].type = &info->type_uint128_vector; - } else { - info->vector_fields[3].next = NULL; - } - info->vector_fields[4].next = NULL; - - info->vector_union.fields = info->vector_fields; - - info->type_vector.type = REG_TYPE_ARCH_DEFINED; - info->type_vector.id = "riscv_vector"; - info->type_vector.type_class = REG_TYPE_CLASS_UNION; - info->type_vector.reg_type_union = &info->vector_union; -} - -static int expose_csrs(const struct target *target) -{ - RISCV_INFO(info); - range_list_t *entry; - list_for_each_entry(entry, &info->expose_csr, list) { - assert(entry->low <= entry->high); - assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0); - const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high; - for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low; - regno <= last_regno; ++regno) { - struct reg * const reg = get_reg_cache_entry(target, regno); - const unsigned int csr_number = regno - GDB_REGNO_CSR0; - if (reg->exist) { - LOG_TARGET_WARNING(target, - "Not exposing CSR %d: register already exists.", - csr_number); - continue; - } - if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK) - return ERROR_FAIL; - LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", - csr_number, reg->name); - } - } - return ERROR_OK; -} - -static void hide_csrs(const struct target *target) -{ - RISCV_INFO(info); - range_list_t *entry; - list_for_each_entry(entry, &info->hide_csr, list) { - assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0); - const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high; - for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low; - regno <= last_regno; ++regno) { - struct reg * const reg = get_reg_cache_entry(target, regno); - const unsigned int csr_number = regno - GDB_REGNO_CSR0; - if (!reg->exist) { - LOG_TARGET_DEBUG(target, - "Not hiding CSR %d: register does not exist.", - csr_number); - continue; - } - LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_number, reg->name); - reg->hidden = true; - } - } -} - -int riscv_init_registers(struct target *target) -{ - if (riscv_init_reg_cache(target) != ERROR_OK) - return ERROR_FAIL; - - init_shared_reg_info(target); - - init_vector_reg_type(target); - - for (uint32_t reg_num = 0; reg_num < target->reg_cache->num_regs; reg_num++) - if (init_reg(target, reg_num) != ERROR_OK) - return ERROR_FAIL; - - - if (expose_csrs(target) != ERROR_OK) - return ERROR_FAIL; - - hide_csrs(target); - - return ERROR_OK; -} - void riscv_add_bscan_tunneled_scan(struct target *target, const struct scan_field *field, riscv_bscan_tunneled_scan_context_t *ctxt) { diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index d3703d1..5b75bf6 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -9,8 +9,9 @@ struct riscv_program; #include "opcodes.h" #include "gdb_regs.h" #include "jtag/jtag.h" -#include "target/register.h" #include "target/semihosting_common.h" +#include "target/target.h" +#include "target/register.h" #include <helper/command.h> #include <helper/bits.h> @@ -21,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) @@ -83,9 +83,11 @@ enum riscv_hart_state { RISCV_STATE_UNAVAILABLE }; +/* RISC-V-specific data assigned to a register. */ typedef struct { struct target *target; - unsigned custom_number; + /* Abstract command's regno for a custom register. */ + unsigned int custom_number; } riscv_reg_info_t; #define RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE 0x80 @@ -190,14 +192,6 @@ struct riscv_info { /* Helper functions that target the various RISC-V debug spec * implementations. */ - int (*get_register)(struct target *target, riscv_reg_t *value, - enum gdb_regno regno); - int (*set_register)(struct target *target, enum gdb_regno regno, - riscv_reg_t value); - int (*get_register_buf)(struct target *target, uint8_t *buf, - enum gdb_regno regno); - int (*set_register_buf)(struct target *target, enum gdb_regno regno, - const uint8_t *buf); int (*select_target)(struct target *target); int (*get_hart_state)(struct target *target, enum riscv_hart_state *state); /* Resume this target, as well as every other prepped target that can be @@ -345,10 +339,7 @@ typedef struct { } 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; @@ -404,25 +395,6 @@ unsigned int riscv_vlenb(const struct target *target); /*** Support functions for the RISC-V 'RTOS', which provides multihart support * without requiring multiple targets. */ -/** - * Set the register value. For cacheable registers, only the cache is updated - * (write-back mode). - */ -int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); -/** - * Set the register value and immediately write it to the target - * (write-through mode). - */ -int riscv_write_register(struct target *target, enum gdb_regno i, riscv_reg_t v); -/** Get register, from the cache if it's in there. */ -int riscv_get_register(struct target *target, riscv_reg_t *value, - enum gdb_regno r); -/** Read the register into the cache, and mark it dirty so it will be restored - * before resuming. */ -int riscv_save_register(struct target *target, enum gdb_regno regid); -/** Write all dirty registers to the target. */ -int riscv_flush_registers(struct target *target); - /* Checks the state of the current hart -- "is_halted" checks the actual * on-device register. */ int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state); @@ -448,8 +420,6 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int riscv_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); -int riscv_init_registers(struct target *target); - void riscv_semihosting_init(struct target *target); enum semihosting_result riscv_semihosting(struct target *target, int *retval); diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c new file mode 100644 index 0000000..6cf67dd --- /dev/null +++ b/src/target/riscv/riscv_reg.c @@ -0,0 +1,976 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gdb_regs.h" +#include "riscv.h" +#include "riscv_reg.h" +#include "riscv_reg_impl.h" +/** + * TODO: Currently `reg->get/set` is implemented in terms of + * `riscv_get/set_register`. However, the intention behind + * `riscv_get/set_register` is to work with the cache, therefore it accesses + * and modifyes register cache directly. The idea is to implement + * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and + * `reg->get/set`. + * Once this is done, the following includes should be removed. + */ +#include "debug_defines.h" +#include "riscv-011.h" +#include "riscv-013.h" +#include "field_helpers.h" + +static const char * const default_reg_names[GDB_REGNO_COUNT] = { + [GDB_REGNO_ZERO] = "zero", + [GDB_REGNO_RA] = "ra", + [GDB_REGNO_SP] = "sp", + [GDB_REGNO_GP] = "gp", + [GDB_REGNO_TP] = "tp", + [GDB_REGNO_T0] = "t0", + [GDB_REGNO_T1] = "t1", + [GDB_REGNO_T2] = "t2", + [GDB_REGNO_FP] = "fp", + [GDB_REGNO_S1] = "s1", + [GDB_REGNO_A0] = "a0", + [GDB_REGNO_A1] = "a1", + [GDB_REGNO_A2] = "a2", + [GDB_REGNO_A3] = "a3", + [GDB_REGNO_A4] = "a4", + [GDB_REGNO_A5] = "a5", + [GDB_REGNO_A6] = "a6", + [GDB_REGNO_A7] = "a7", + [GDB_REGNO_S2] = "s2", + [GDB_REGNO_S3] = "s3", + [GDB_REGNO_S4] = "s4", + [GDB_REGNO_S5] = "s5", + [GDB_REGNO_S6] = "s6", + [GDB_REGNO_S7] = "s7", + [GDB_REGNO_S8] = "s8", + [GDB_REGNO_S9] = "s9", + [GDB_REGNO_S10] = "s10", + [GDB_REGNO_S11] = "s11", + [GDB_REGNO_T3] = "t3", + [GDB_REGNO_T4] = "t4", + [GDB_REGNO_T5] = "t5", + [GDB_REGNO_T6] = "t6", + [GDB_REGNO_PC] = "pc", + [GDB_REGNO_CSR0] = "csr0", + [GDB_REGNO_PRIV] = "priv", + [GDB_REGNO_FT0] = "ft0", + [GDB_REGNO_FT1] = "ft1", + [GDB_REGNO_FT2] = "ft2", + [GDB_REGNO_FT3] = "ft3", + [GDB_REGNO_FT4] = "ft4", + [GDB_REGNO_FT5] = "ft5", + [GDB_REGNO_FT6] = "ft6", + [GDB_REGNO_FT7] = "ft7", + [GDB_REGNO_FS0] = "fs0", + [GDB_REGNO_FS1] = "fs1", + [GDB_REGNO_FA0] = "fa0", + [GDB_REGNO_FA1] = "fa1", + [GDB_REGNO_FA2] = "fa2", + [GDB_REGNO_FA3] = "fa3", + [GDB_REGNO_FA4] = "fa4", + [GDB_REGNO_FA5] = "fa5", + [GDB_REGNO_FA6] = "fa6", + [GDB_REGNO_FA7] = "fa7", + [GDB_REGNO_FS2] = "fs2", + [GDB_REGNO_FS3] = "fs3", + [GDB_REGNO_FS4] = "fs4", + [GDB_REGNO_FS5] = "fs5", + [GDB_REGNO_FS6] = "fs6", + [GDB_REGNO_FS7] = "fs7", + [GDB_REGNO_FS8] = "fs8", + [GDB_REGNO_FS9] = "fs9", + [GDB_REGNO_FS10] = "fs10", + [GDB_REGNO_FS11] = "fs11", + [GDB_REGNO_FT8] = "ft8", + [GDB_REGNO_FT9] = "ft9", + [GDB_REGNO_FT10] = "ft10", + [GDB_REGNO_FT11] = "ft11", + + #define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = #csr_name, + #include "encoding.h" + #undef DECLARE_CSR +}; + +static void free_custom_register_names(struct target *target) +{ + RISCV_INFO(info); + + if (!info->custom_register_names.reg_names) + return; + + for (unsigned int i = 0; i < info->custom_register_names.num_entries; i++) + free(info->custom_register_names.reg_names[i]); + free(info->custom_register_names.reg_names); + info->custom_register_names.reg_names = NULL; +} + +static void free_reg_names(struct target *target) +{ + RISCV_INFO(info); + + if (!info->reg_names) + return; + + for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i) + free(info->reg_names[i]); + free(info->reg_names); + info->reg_names = NULL; + + free_custom_register_names(target); +} + +static char *init_reg_name(const char *name) +{ + const int size_buf = strlen(name) + 1; + + char * const buf = calloc(size_buf, sizeof(char)); + if (!buf) { + LOG_ERROR("Failed to allocate memory for a register name."); + return NULL; + } + strcpy(buf, name); + return buf; +} + +static void init_custom_csr_names(const struct target *target) +{ + RISCV_INFO(info); + range_list_t *entry; + + list_for_each_entry(entry, &info->expose_csr, list) { + if (!entry->name) + continue; + assert(entry->low == entry->high); + const unsigned int regno = entry->low + GDB_REGNO_CSR0; + assert(regno <= GDB_REGNO_CSR4095); + if (info->reg_names[regno]) + return; + info->reg_names[regno] = init_reg_name(entry->name); + } +} + +static char *init_reg_name_with_prefix(const char *name_prefix, + unsigned int num) +{ + const int size_buf = snprintf(NULL, 0, "%s%d", name_prefix, num) + 1; + + char * const buf = calloc(size_buf, sizeof(char)); + if (!buf) { + LOG_ERROR("Failed to allocate memory for a register name."); + return NULL; + } + int result = snprintf(buf, size_buf, "%s%d", name_prefix, num); + assert(result > 0 && result <= (size_buf - 1)); + return buf; +} + +const char *riscv_reg_gdb_regno_name(const struct target *target, enum gdb_regno regno) +{ + RISCV_INFO(info); + + if (regno >= GDB_REGNO_COUNT) { + assert(info->custom_register_names.reg_names); + assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.num_entries); + return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT]; + } + + if (!info->reg_names) + info->reg_names = calloc(GDB_REGNO_COUNT, sizeof(char *)); + + if (info->reg_names[regno]) + return info->reg_names[regno]; + if (default_reg_names[regno]) + return default_reg_names[regno]; + if (regno <= GDB_REGNO_XPR31) { + info->reg_names[regno] = init_reg_name_with_prefix("x", regno - GDB_REGNO_ZERO); + return info->reg_names[regno]; + } + if (regno <= GDB_REGNO_V31 && regno >= GDB_REGNO_V0) { + info->reg_names[regno] = init_reg_name_with_prefix("v", regno - GDB_REGNO_V0); + return info->reg_names[regno]; + } + if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { + init_custom_csr_names(target); + info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0); + return info->reg_names[regno]; + } + assert(!"Encountered uninitialized entry in reg_names table"); + + return NULL; +} + +struct target *riscv_reg_impl_get_target(const struct reg *reg) +{ + assert(riscv_reg_impl_is_initialized(reg)); + return ((const riscv_reg_info_t *)reg->arch_info)->target; +} + +static struct reg_feature *gdb_regno_feature(uint32_t regno) +{ + if (regno <= GDB_REGNO_XPR31 || regno == GDB_REGNO_PC) { + static struct reg_feature feature_cpu = { + .name = "org.gnu.gdb.riscv.cpu" + }; + return &feature_cpu; + } + if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || + regno == GDB_REGNO_FFLAGS || + regno == GDB_REGNO_FRM || + regno == GDB_REGNO_FCSR) { + static struct reg_feature feature_fpu = { + .name = "org.gnu.gdb.riscv.fpu" + }; + return &feature_fpu; + } + if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) { + static struct reg_feature feature_vector = { + .name = "org.gnu.gdb.riscv.vector" + }; + return &feature_vector; + } + if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { + static struct reg_feature feature_csr = { + .name = "org.gnu.gdb.riscv.csr" + }; + return &feature_csr; + } + if (regno == GDB_REGNO_PRIV) { + static struct reg_feature feature_virtual = { + .name = "org.gnu.gdb.riscv.virtual" + }; + return &feature_virtual; + } + assert(regno >= GDB_REGNO_COUNT); + static struct reg_feature feature_custom = { + .name = "org.gnu.gdb.riscv.custom" + }; + return &feature_custom; +} + +static bool gdb_regno_caller_save(uint32_t regno) +{ + return regno <= GDB_REGNO_XPR31 || + regno == GDB_REGNO_PC || + (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31); +} + +static struct reg_data_type *gdb_regno_reg_data_type(const struct target *target, + uint32_t regno) +{ + if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) { + static struct reg_data_type type_ieee_single = { + .type = REG_TYPE_IEEE_SINGLE, + .id = "ieee_single" + }; + static struct reg_data_type type_ieee_double = { + .type = REG_TYPE_IEEE_DOUBLE, + .id = "ieee_double" + }; + static struct reg_data_type_union_field single_double_fields[] = { + {"float", &type_ieee_single, single_double_fields + 1}, + {"double", &type_ieee_double, NULL}, + }; + static struct reg_data_type_union single_double_union = { + .fields = single_double_fields + }; + static struct reg_data_type type_ieee_single_double = { + .type = REG_TYPE_ARCH_DEFINED, + .id = "FPU_FD", + .type_class = REG_TYPE_CLASS_UNION, + {.reg_type_union = &single_double_union} + }; + return riscv_supports_extension(target, 'D') ? + &type_ieee_single_double : + &type_ieee_single; + } + if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) { + RISCV_INFO(info); + return &info->type_vector; + } + return NULL; +} + +static const char *gdb_regno_group(uint32_t regno) +{ + if (regno <= GDB_REGNO_XPR31 || + regno == GDB_REGNO_PC || + regno == GDB_REGNO_PRIV) + return "general"; + if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || + regno == GDB_REGNO_FFLAGS || + regno == GDB_REGNO_FRM || + regno == GDB_REGNO_FCSR) + return "float"; + if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) + return "csr"; + if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) + return "vector"; + assert(regno >= GDB_REGNO_COUNT); + return "custom"; +} + +uint32_t gdb_regno_size(const struct target *target, uint32_t regno) +{ + if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) + return riscv_supports_extension(target, 'D') ? 64 : 32; + if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) + return riscv_vlenb(target) * 8; + if (regno == GDB_REGNO_PRIV) + return 8; + if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { + const unsigned int csr_number = regno - GDB_REGNO_CSR0; + switch (csr_number) { + case CSR_DCSR: + case CSR_MVENDORID: + case CSR_MCOUNTINHIBIT: + + case CSR_FFLAGS: + case CSR_FRM: + case CSR_FCSR: + + case CSR_SCOUNTEREN: + case CSR_MCOUNTEREN: + return 32; + } + } + return riscv_xlen(target); +} + +static bool vlenb_exists(const struct target *target) +{ + return riscv_vlenb(target) != 0; +} + +static bool mtopi_exists(const struct target *target) +{ + RISCV_INFO(info) + /* TODO: The naming is quite unfortunate here. `mtopi_readable` refers + * to how the fact that `mtopi` exists was deduced during examine. + */ + return info->mtopi_readable; +} + +static bool mtopei_exists(const struct target *target) +{ + RISCV_INFO(info) + /* TODO: The naming is quite unfortunate here. `mtopei_readable` refers + * to how the fact that `mtopei` exists was deduced during examine. + */ + return info->mtopei_readable; +} + +static bool is_known_standard_csr(unsigned int csr_num) +{ + static const bool is_csr_in_buf[GDB_REGNO_CSR4095 - GDB_REGNO_CSR0 + 1] = { + #define DECLARE_CSR(csr_name, number)[number] = true, + #include "encoding.h" + #undef DECLARE_CSR + }; + assert(csr_num < ARRAY_SIZE(is_csr_in_buf)); + + return is_csr_in_buf[csr_num]; +} + +static bool gdb_regno_exist(const struct target *target, uint32_t regno) +{ + if (regno <= GDB_REGNO_XPR15 || + regno == GDB_REGNO_PC || + regno == GDB_REGNO_PRIV) + return true; + if (regno > GDB_REGNO_XPR15 && regno <= GDB_REGNO_XPR31) + return !riscv_supports_extension(target, 'E'); + if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) + return riscv_supports_extension(target, 'F'); + if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) + return vlenb_exists(target); + if (regno >= GDB_REGNO_COUNT) + return true; + assert(regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095); + const unsigned int csr_number = regno - GDB_REGNO_CSR0; + switch (csr_number) { + case CSR_FFLAGS: + 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: + case CSR_VLENB: + return vlenb_exists(target); + case CSR_SCOUNTEREN: + case CSR_SSTATUS: + case CSR_STVEC: + case CSR_SIP: + case CSR_SIE: + case CSR_SSCRATCH: + case CSR_SEPC: + case CSR_SCAUSE: + case CSR_STVAL: + case CSR_SATP: + return riscv_supports_extension(target, 'S'); + case CSR_MEDELEG: + case CSR_MIDELEG: + /* "In systems with only M-mode, or with both M-mode and + * U-mode but without U-mode trap support, the medeleg and + * mideleg registers should not exist." */ + return riscv_supports_extension(target, 'S') || + riscv_supports_extension(target, 'N'); + + case CSR_PMPCFG1: + case CSR_PMPCFG3: + case CSR_CYCLEH: + case CSR_TIMEH: + case CSR_INSTRETH: + case CSR_HPMCOUNTER3H: + case CSR_HPMCOUNTER4H: + case CSR_HPMCOUNTER5H: + case CSR_HPMCOUNTER6H: + case CSR_HPMCOUNTER7H: + case CSR_HPMCOUNTER8H: + case CSR_HPMCOUNTER9H: + case CSR_HPMCOUNTER10H: + case CSR_HPMCOUNTER11H: + case CSR_HPMCOUNTER12H: + case CSR_HPMCOUNTER13H: + case CSR_HPMCOUNTER14H: + case CSR_HPMCOUNTER15H: + case CSR_HPMCOUNTER16H: + case CSR_HPMCOUNTER17H: + case CSR_HPMCOUNTER18H: + case CSR_HPMCOUNTER19H: + case CSR_HPMCOUNTER20H: + case CSR_HPMCOUNTER21H: + case CSR_HPMCOUNTER22H: + case CSR_HPMCOUNTER23H: + case CSR_HPMCOUNTER24H: + case CSR_HPMCOUNTER25H: + case CSR_HPMCOUNTER26H: + case CSR_HPMCOUNTER27H: + case CSR_HPMCOUNTER28H: + case CSR_HPMCOUNTER29H: + case CSR_HPMCOUNTER30H: + case CSR_HPMCOUNTER31H: + case CSR_MCYCLEH: + case CSR_MINSTRETH: + case CSR_MHPMCOUNTER4H: + case CSR_MHPMCOUNTER5H: + case CSR_MHPMCOUNTER6H: + case CSR_MHPMCOUNTER7H: + case CSR_MHPMCOUNTER8H: + case CSR_MHPMCOUNTER9H: + case CSR_MHPMCOUNTER10H: + case CSR_MHPMCOUNTER11H: + case CSR_MHPMCOUNTER12H: + case CSR_MHPMCOUNTER13H: + case CSR_MHPMCOUNTER14H: + case CSR_MHPMCOUNTER15H: + case CSR_MHPMCOUNTER16H: + case CSR_MHPMCOUNTER17H: + case CSR_MHPMCOUNTER18H: + case CSR_MHPMCOUNTER19H: + case CSR_MHPMCOUNTER20H: + case CSR_MHPMCOUNTER21H: + case CSR_MHPMCOUNTER22H: + case CSR_MHPMCOUNTER23H: + case CSR_MHPMCOUNTER24H: + case CSR_MHPMCOUNTER25H: + case CSR_MHPMCOUNTER26H: + case CSR_MHPMCOUNTER27H: + case CSR_MHPMCOUNTER28H: + case CSR_MHPMCOUNTER29H: + case CSR_MHPMCOUNTER30H: + case CSR_MHPMCOUNTER31H: + return riscv_xlen(target) == 32; + case CSR_MCOUNTEREN: + return riscv_supports_extension(target, 'U'); + /* Interrupts M-Mode CSRs. */ + case CSR_MISELECT: + case CSR_MIREG: + case CSR_MVIEN: + case CSR_MVIP: + case CSR_MIEH: + case CSR_MIPH: + return mtopi_exists(target); + case CSR_MIDELEGH: + case CSR_MVIENH: + case CSR_MVIPH: + return mtopi_exists(target) && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'S'); + /* Interrupts S-Mode CSRs. */ + case CSR_SISELECT: + case CSR_SIREG: + case CSR_STOPI: + return mtopi_exists(target) && + riscv_supports_extension(target, 'S'); + case CSR_STOPEI: + return mtopei_exists(target) && + riscv_supports_extension(target, 'S'); + case CSR_SIEH: + case CSR_SIPH: + return mtopi_exists(target) && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'S'); + /* Interrupts Hypervisor and VS CSRs. */ + case CSR_HVIEN: + case CSR_HVICTL: + case CSR_HVIPRIO1: + case CSR_HVIPRIO2: + case CSR_VSISELECT: + case CSR_VSIREG: + case CSR_VSTOPI: + return mtopi_exists(target) && + riscv_supports_extension(target, 'H'); + case CSR_VSTOPEI: + return mtopei_exists(target) && + riscv_supports_extension(target, 'H'); + case CSR_HIDELEGH: + case CSR_HVIENH: + case CSR_HVIPH: + case CSR_HVIPRIO1H: + case CSR_HVIPRIO2H: + case CSR_VSIEH: + case CSR_VSIPH: + return mtopi_exists(target) && + riscv_xlen(target) == 32 && + riscv_supports_extension(target, 'H'); + } + return is_known_standard_csr(csr_number); +} + +static unsigned int gdb_regno_custom_number(const struct target *target, uint32_t regno) +{ + if (regno < GDB_REGNO_COUNT) + return 0; + + RISCV_INFO(info); + assert(!list_empty(&info->expose_custom)); + range_list_t *range; + unsigned int regno_start = GDB_REGNO_COUNT; + unsigned int start = 0; + unsigned int offset = 0; + list_for_each_entry(range, &info->expose_custom, list) { + start = range->low; + assert(regno >= regno_start); + offset = regno - regno_start; + const unsigned int regs_in_range = range->high - range->low + 1; + if (offset < regs_in_range) + break; + regno_start += regs_in_range; + } + return start + offset; +} + +struct reg *riscv_reg_impl_cache_entry(const struct target *target, + uint32_t number) +{ + assert(target->reg_cache); + assert(target->reg_cache->reg_list); + assert(number < target->reg_cache->num_regs); + return &target->reg_cache->reg_list[number]; +} + +static int resize_reg(const struct target *target, uint32_t regno, bool exist, + uint32_t size) +{ + struct reg *reg = riscv_reg_impl_cache_entry(target, regno); + assert(riscv_reg_impl_is_initialized(reg)); + free(reg->value); + reg->size = size; + reg->exist = exist; + if (reg->exist) { + reg->value = malloc(DIV_ROUND_UP(reg->size, 8)); + if (!reg->value) { + LOG_ERROR("Failed to allocate memory."); + return ERROR_FAIL; + } + } else { + reg->value = NULL; + } + assert(riscv_reg_impl_is_initialized(reg)); + return ERROR_OK; +} + +static int set_reg_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) +{ + struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); + if (riscv_reg_impl_is_initialized(reg)) + return ERROR_OK; + reg->number = regno; + reg->type = reg_type; + reg->dirty = false; + reg->valid = false; + reg->hidden = false; + reg->name = riscv_reg_gdb_regno_name(target, regno); + reg->feature = gdb_regno_feature(regno); + reg->caller_save = gdb_regno_caller_save(regno); + reg->reg_data_type = gdb_regno_reg_data_type(target, regno); + reg->group = gdb_regno_group(regno); + if (regno < GDB_REGNO_COUNT) { + RISCV_INFO(info); + reg->arch_info = &info->shared_reg_info; + } else { + reg->arch_info = calloc(1, sizeof(riscv_reg_info_t)); + if (!reg->arch_info) { + LOG_ERROR("Out of memory."); + return ERROR_FAIL; + } + riscv_reg_info_t * const reg_arch_info = reg->arch_info; + 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)); +} + +static int init_custom_register_names(struct list_head *expose_custom, + struct reg_name_table *custom_register_names) +{ + unsigned int custom_regs_num = 0; + if (!list_empty(expose_custom)) { + range_list_t *entry; + list_for_each_entry(entry, expose_custom, list) + custom_regs_num += entry->high - entry->low + 1; + } + + if (!custom_regs_num) + return ERROR_OK; + + custom_register_names->reg_names = calloc(custom_regs_num, sizeof(char *)); + if (!custom_register_names->reg_names) { + LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names"); + return ERROR_FAIL; + } + custom_register_names->num_entries = custom_regs_num; + char **reg_names = custom_register_names->reg_names; + range_list_t *range; + unsigned int next_custom_reg_index = 0; + list_for_each_entry(range, expose_custom, list) { + for (unsigned int custom_number = range->low; custom_number <= range->high; ++custom_number) { + if (range->name) + reg_names[next_custom_reg_index] = init_reg_name(range->name); + else + reg_names[next_custom_reg_index] = + init_reg_name_with_prefix("custom", custom_number); + + if (!reg_names[next_custom_reg_index]) + return ERROR_FAIL; + ++next_custom_reg_index; + } + } + return ERROR_OK; +} + +int riscv_reg_impl_init_cache(struct target *target) +{ + RISCV_INFO(info); + + riscv_reg_free_all(target); + + target->reg_cache = calloc(1, sizeof(*target->reg_cache)); + if (!target->reg_cache) { + LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache"); + return ERROR_FAIL; + } + target->reg_cache->name = "RISC-V Registers"; + + if (init_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) { + LOG_TARGET_ERROR(target, "init_custom_register_names failed"); + return ERROR_FAIL; + } + + target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.num_entries; + LOG_TARGET_DEBUG(target, "create register cache for %d registers", + target->reg_cache->num_regs); + + target->reg_cache->reg_list = + calloc(target->reg_cache->num_regs, sizeof(struct reg)); + if (!target->reg_cache->reg_list) { + LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache->reg_list"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +int riscv_reg_impl_expose_csrs(const struct target *target) +{ + RISCV_INFO(info); + range_list_t *entry; + list_for_each_entry(entry, &info->expose_csr, list) { + assert(entry->low <= entry->high); + assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0); + const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high; + for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low; + regno <= last_regno; ++regno) { + 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, + "Not exposing CSR %d: register already exists.", + csr_number); + continue; + } + if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK) + return ERROR_FAIL; + LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", + csr_number, reg->name); + } + } + return ERROR_OK; +} + +void riscv_reg_impl_hide_csrs(const struct target *target) +{ + RISCV_INFO(info); + range_list_t *entry; + list_for_each_entry(entry, &info->hide_csr, list) { + assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0); + const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high; + for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low; + regno <= last_regno; ++regno) { + 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, + "Not hiding CSR %d: register does not exist.", + csr_number); + continue; + } + LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_number, reg->name); + reg->hidden = true; + } + } +} + +void riscv_reg_free_all(struct target *target) +{ + free_reg_names(target); + /* Free the shared structure use for most registers. */ + if (!target->reg_cache) + return; + if (target->reg_cache->reg_list) { + for (unsigned int i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++) + free(target->reg_cache->reg_list[i].arch_info); + for (unsigned int i = 0; i < target->reg_cache->num_regs; i++) + free(target->reg_cache->reg_list[i].value); + free(target->reg_cache->reg_list); + } + free(target->reg_cache); + target->reg_cache = NULL; +} + +int riscv_reg_flush_all(struct target *target) +{ + if (!target->reg_cache) + return ERROR_OK; + + LOG_TARGET_DEBUG(target, "Flushing register cache"); + + /* Writing non-GPR registers may require progbuf execution, and some GPRs + * may become dirty in the process (e.g. S0, S1). For that reason, flush + * registers in reverse order, so that GPRs are flushed last. + */ + for (unsigned int number = target->reg_cache->num_regs; number-- > 0; ) { + struct reg *reg = riscv_reg_impl_cache_entry(target, number); + if (reg->valid && reg->dirty) { + riscv_reg_t value = buf_get_u64(reg->value, 0, reg->size); + + LOG_TARGET_DEBUG(target, "%s is dirty; write back 0x%" PRIx64, + reg->name, value); + if (riscv_reg_write(target, number, value) != ERROR_OK) + return ERROR_FAIL; + } + } + LOG_TARGET_DEBUG(target, "Flush of register cache completed"); + return ERROR_OK; +} + +/** + * This function is used internally by functions that change register values. + * If `write_through` is true, it is ensured that the value of the target's + * register is set to be equal to the `value` argument. The cached value is + * updated if the register is cacheable. + * TODO: Currently `reg->get/set` is implemented in terms of + * `riscv_get/set_register`. However, the intention behind + * `riscv_get/set_register` is to work with the cache, therefore it accesses + * and modifyes register cache directly. The idea is to implement + * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and + * `reg->get/set`. + */ +static int riscv_set_or_write_register(struct target *target, + enum gdb_regno regid, riscv_reg_t value, bool write_through) +{ + RISCV_INFO(r); + assert(r); + if (r->dtm_version == DTM_DTMCS_VERSION_0_11) + return riscv011_set_register(target, regid, value); + + keep_alive(); + + if (regid == GDB_REGNO_PC) { + return riscv_set_or_write_register(target, GDB_REGNO_DPC, value, write_through); + } else if (regid == GDB_REGNO_PRIV) { + riscv_reg_t dcsr; + + if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV)); + dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V)); + 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); + + if (!reg->exist) { + LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) { + LOG_TARGET_DEBUG(target, + "Target not halted, writing to target: %s <- 0x%" PRIx64, + reg->name, value); + return riscv013_set_register(target, regid, value); + } + + const bool need_to_write = !reg->valid || reg->dirty || + value != buf_get_u64(reg->value, 0, reg->size); + const bool cacheable = riscv_reg_impl_gdb_regno_cacheable(regid, need_to_write); + + if (!cacheable || (write_through && need_to_write)) { + LOG_TARGET_DEBUG(target, + "Writing to target: %s <- 0x%" PRIx64 " (cacheable=%s, valid=%s, dirty=%s)", + reg->name, value, cacheable ? "true" : "false", + reg->valid ? "true" : "false", + reg->dirty ? "true" : "false"); + if (riscv013_set_register(target, regid, value) != ERROR_OK) + return ERROR_FAIL; + + reg->dirty = false; + } else { + reg->dirty = need_to_write; + } + + buf_set_u64(reg->value, 0, reg->size, value); + reg->valid = cacheable; + + LOG_TARGET_DEBUG(target, + "Wrote 0x%" PRIx64 " to %s (cacheable=%s, valid=%s, dirty=%s)", + value, reg->name, cacheable ? "true" : "false", + reg->valid ? "true" : "false", + reg->dirty ? "true" : "false"); + return ERROR_OK; +} + +/** + * This function is used to change the value of a register. The new value may + * be cached, and may not be written until the hart is resumed. + * TODO: Currently `reg->get/set` is implemented in terms of + * `riscv_get/set_register`. However, the intention behind + * `riscv_get/set_register` is to work with the cache, therefore it accesses + * and modifyes register cache directly. The idea is to implement + * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and + * `reg->get/set`. + */ +int riscv_reg_set(struct target *target, enum gdb_regno regid, + riscv_reg_t value) +{ + return riscv_set_or_write_register(target, regid, value, + /* write_through */ false); +} + +/** + * This function is used to change the value of a register. The new value may + * be cached, but it will be written to hart immediately. + * TODO: Currently `reg->get/set` is implemented in terms of + * `riscv_get/set_register`. However, the intention behind + * `riscv_get/set_register` is to work with the cache, therefore it accesses + * and modifyes register cache directly. The idea is to implement + * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and + * `reg->get/set`. + */ +int riscv_reg_write(struct target *target, enum gdb_regno regid, + riscv_reg_t value) +{ + return riscv_set_or_write_register(target, regid, value, + /* write_through */ true); +} + +/** + * This function is used to get the value of a register. If possible, the value + * in cache will be updated. + * TODO: Currently `reg->get/set` is implemented in terms of + * `riscv_get/set_register`. However, the intention behind + * `riscv_get/set_register` is to work with the cache, therefore it accesses + * and modifyes register cache directly. The idea is to implement + * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and + * `reg->get/set`. + */ +int riscv_reg_get(struct target *target, riscv_reg_t *value, + enum gdb_regno regid) +{ + RISCV_INFO(r); + assert(r); + if (r->dtm_version == DTM_DTMCS_VERSION_0_11) + return riscv013_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); + if (!reg->exist) { + LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); + return ERROR_FAIL; + } + + if (reg->valid) { + *value = buf_get_u64(reg->value, 0, reg->size); + LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64 " (cached)", reg->name, + *value); + return ERROR_OK; + } + + LOG_TARGET_DEBUG(target, "Reading %s from target", reg->name); + if (riscv013_get_register(target, value, regid) != ERROR_OK) + return ERROR_FAIL; + + buf_set_u64(reg->value, 0, reg->size, *value); + reg->valid = riscv_reg_impl_gdb_regno_cacheable(regid, /* is write? */ false) && + target->state == TARGET_HALTED; + reg->dirty = false; + + LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64, reg->name, *value); + return ERROR_OK; +} diff --git a/src/target/riscv/riscv_reg.h b/src/target/riscv/riscv_reg.h new file mode 100644 index 0000000..264addd --- /dev/null +++ b/src/target/riscv/riscv_reg.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_H +#define OPENOCD_TARGET_RISCV_RISCV_REG_H + +#include "target/target.h" +#include "target/register.h" + +/** + * This file describes the register cache interface available to the RISC-V + * target. Functions declared here should be safe to use once register cache is + * completely initialized and may be used with caution during register cache + * initialization. + */ + +/** Return the name of the register by it's number in register cache. */ +const char *riscv_reg_gdb_regno_name(const struct target *target, enum gdb_regno regno); + +/** Free register cache and associated structures. */ +void riscv_reg_free_all(struct target *target); + +/** Write all dirty registers to the target. */ +int riscv_reg_flush_all(struct target *target); +/** + * Set the register value. For cacheable registers, only the cache is updated + * (write-back mode). + */ +int riscv_reg_set(struct target *target, enum gdb_regno i, riscv_reg_t v); +/** + * Set the register value and immediately write it to the target + * (write-through mode). + */ +int riscv_reg_write(struct target *target, enum gdb_regno i, riscv_reg_t v); +/** Get register, from the cache if it's in there. */ +int riscv_reg_get(struct target *target, riscv_reg_t *value, + enum gdb_regno r); + +#endif /* OPENOCD_TARGET_RISCV_RISCV_REG_H */ diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h new file mode 100644 index 0000000..906a5b6 --- /dev/null +++ b/src/target/riscv/riscv_reg_impl.h @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_IMPL_H +#define OPENOCD_TARGET_RISCV_RISCV_REG_IMPL_H + +#include "gdb_regs.h" +#include "riscv.h" +#include "target/target.h" +#include "target/register.h" +#include <assert.h> + +/** + * 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. + * - initialized until `riscv_reg_free_all()` is called. + */ +static inline bool riscv_reg_impl_is_initialized(const struct reg *reg) +{ + assert(reg); + if (!reg->feature) { + const struct reg default_reg = {0}; + assert(!memcmp(&default_reg, reg, sizeof(*reg))); + return false; + } + assert(reg->arch_info); + assert(((riscv_reg_info_t *)reg->arch_info)->target); + assert((!reg->exist && !reg->value) || (reg->exist && reg->value)); + assert(reg->valid || !reg->dirty); + return true; +} +/** + * Initialize register cache. Note, that each specific register cache entry is + * not initialized by this function. + */ +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); + +/** Return the entry in the register cache of the target. */ +struct reg *riscv_reg_impl_cache_entry(const struct target *target, + uint32_t number); + +/** Return the target that owns the cache entry. */ +struct target *riscv_reg_impl_get_target(const struct reg *reg); + +static inline void init_shared_reg_info(struct target *target) +{ + RISCV_INFO(info); + info->shared_reg_info.target = target; + info->shared_reg_info.custom_number = 0; +} + +/** TODO: vector register type description can be moved into `riscv013_info_t`, + * since 0.11 targets do not support access to vector registers. */ +static inline void riscv_reg_impl_init_vector_reg_type(const struct target *target) +{ + RISCV_INFO(info); + static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" }; + static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" }; + static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" }; + static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" }; + static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" }; + + /* This is roughly the XML we want: + * <vector id="bytes" type="uint8" count="16"/> + * <vector id="shorts" type="uint16" count="8"/> + * <vector id="words" type="uint32" count="4"/> + * <vector id="longs" type="uint64" count="2"/> + * <vector id="quads" type="uint128" count="1"/> + * <union id="riscv_vector_type"> + * <field name="b" type="bytes"/> + * <field name="s" type="shorts"/> + * <field name="w" type="words"/> + * <field name="l" type="longs"/> + * <field name="q" type="quads"/> + * </union> + */ + + info->vector_uint8.type = &type_uint8; + info->vector_uint8.count = riscv_vlenb(target); + info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint8_vector.id = "bytes"; + info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint8_vector.reg_type_vector = &info->vector_uint8; + + info->vector_uint16.type = &type_uint16; + info->vector_uint16.count = riscv_vlenb(target) / 2; + info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint16_vector.id = "shorts"; + info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint16_vector.reg_type_vector = &info->vector_uint16; + + info->vector_uint32.type = &type_uint32; + info->vector_uint32.count = riscv_vlenb(target) / 4; + info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint32_vector.id = "words"; + info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint32_vector.reg_type_vector = &info->vector_uint32; + + info->vector_uint64.type = &type_uint64; + info->vector_uint64.count = riscv_vlenb(target) / 8; + info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint64_vector.id = "longs"; + info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint64_vector.reg_type_vector = &info->vector_uint64; + + info->vector_uint128.type = &type_uint128; + info->vector_uint128.count = riscv_vlenb(target) / 16; + info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_uint128_vector.id = "quads"; + info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR; + info->type_uint128_vector.reg_type_vector = &info->vector_uint128; + + info->vector_fields[0].name = "b"; + info->vector_fields[0].type = &info->type_uint8_vector; + if (riscv_vlenb(target) >= 2) { + info->vector_fields[0].next = info->vector_fields + 1; + info->vector_fields[1].name = "s"; + info->vector_fields[1].type = &info->type_uint16_vector; + } else { + info->vector_fields[0].next = NULL; + } + if (riscv_vlenb(target) >= 4) { + info->vector_fields[1].next = info->vector_fields + 2; + info->vector_fields[2].name = "w"; + info->vector_fields[2].type = &info->type_uint32_vector; + } else { + info->vector_fields[1].next = NULL; + } + if (riscv_vlenb(target) >= 8) { + info->vector_fields[2].next = info->vector_fields + 3; + info->vector_fields[3].name = "l"; + info->vector_fields[3].type = &info->type_uint64_vector; + } else { + info->vector_fields[2].next = NULL; + } + if (riscv_vlenb(target) >= 16) { + info->vector_fields[3].next = info->vector_fields + 4; + info->vector_fields[4].name = "q"; + info->vector_fields[4].type = &info->type_uint128_vector; + } else { + info->vector_fields[3].next = NULL; + } + info->vector_fields[4].next = NULL; + + info->vector_union.fields = info->vector_fields; + + info->type_vector.type = REG_TYPE_ARCH_DEFINED; + info->type_vector.id = "riscv_vector"; + info->type_vector.type_class = REG_TYPE_CLASS_UNION; + info->type_vector.reg_type_union = &info->vector_union; +} + +/** Expose additional CSRs, as specified by `riscv_info_t::expose_csr` list. */ +int riscv_reg_impl_expose_csrs(const struct target *target); + +/** Hide additional CSRs, as specified by `riscv_info_t::hide_csr` list. */ +void riscv_reg_impl_hide_csrs(const struct target *target); + +/** + * If write is true: + * return true iff we are guaranteed that the register will contain exactly + * the value we just wrote when it's read. + * If write is false: + * return true iff we are guaranteed that the register will read the same + * value in the future as the value we just read. + */ +static inline bool riscv_reg_impl_gdb_regno_cacheable(enum gdb_regno regno, + bool is_write) +{ + if (regno == GDB_REGNO_ZERO) + return !is_write; + + /* GPRs, FPRs, vector registers are just normal data stores. */ + if (regno <= GDB_REGNO_XPR31 || + (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) || + (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)) + return true; + + /* Most CSRs won't change value on us, but we can't assume it about arbitrary + * CSRs. */ + switch (regno) { + case GDB_REGNO_DPC: + case GDB_REGNO_VSTART: + case GDB_REGNO_VXSAT: + case GDB_REGNO_VXRM: + case GDB_REGNO_VLENB: + case GDB_REGNO_VL: + case GDB_REGNO_VTYPE: + case GDB_REGNO_MISA: + case GDB_REGNO_DCSR: + case GDB_REGNO_DSCRATCH0: + case GDB_REGNO_MSTATUS: + case GDB_REGNO_MEPC: + case GDB_REGNO_MCAUSE: + case GDB_REGNO_SATP: + /* + * WARL registers might not contain the value we just wrote, but + * these ones won't spontaneously change their value either. * + */ + return !is_write; + + case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */ + case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */ + case GDB_REGNO_TDATA2: /* Changes value when tselect is changed. */ + default: + return false; + } +} +#endif /* OPENOCD_TARGET_RISCV_RISCV_REG_IMPL_H */ diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index 9c708c8..0f4f6b5 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -32,6 +32,7 @@ #include "target/target.h" #include "riscv.h" +#include "riscv_reg.h" static int riscv_semihosting_setup(struct target *target, int enable); static int riscv_semihosting_post_result(struct target *target); @@ -67,7 +68,7 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval) } riscv_reg_t pc; - int result = riscv_get_register(target, &pc, GDB_REGNO_PC); + int result = riscv_reg_get(target, &pc, GDB_REGNO_PC); if (result != ERROR_OK) return SEMIHOSTING_ERROR; @@ -107,13 +108,13 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval) riscv_reg_t r0; riscv_reg_t r1; - result = riscv_get_register(target, &r0, GDB_REGNO_A0); + result = riscv_reg_get(target, &r0, GDB_REGNO_A0); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a0)"); return SEMIHOSTING_ERROR; } - result = riscv_get_register(target, &r1, GDB_REGNO_A1); + result = riscv_reg_get(target, &r1, GDB_REGNO_A1); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a1)"); return SEMIHOSTING_ERROR; @@ -140,7 +141,7 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval) } /* Resume right after the EBREAK 4 bytes instruction. */ - *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4); + *retval = riscv_reg_set(target, GDB_REGNO_PC, pc + 4); if (*retval != ERROR_OK) return SEMIHOSTING_ERROR; @@ -184,6 +185,6 @@ static int riscv_semihosting_post_result(struct target *target) } LOG_TARGET_DEBUG(target, "Result: 0x%" PRIx64, semihosting->result); - riscv_set_register(target, GDB_REGNO_A0, semihosting->result); + riscv_reg_set(target, GDB_REGNO_A0, semihosting->result); return 0; } diff --git a/src/target/target.c b/src/target/target.c index 5187006..fd9c34f 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4675,9 +4675,8 @@ void target_handle_event(struct target *target, enum target_event e) if (retval != JIM_OK) { Jim_MakeErrorMessage(teap->interp); - LOG_USER("Error executing event %s on target %s:\n%s", + LOG_TARGET_ERROR(target, "Execution of event %s failed:\n%s", target_event_name(e), - target_name(target), Jim_GetString(Jim_GetResult(teap->interp), NULL)); /* clean both error code and stacktrace before return */ Jim_Eval(teap->interp, "error \"\" \"\""); @@ -5349,17 +5348,19 @@ COMMAND_HANDLER(handle_target_reset) return ERROR_FAIL; } - if (target->defer_examine) - target_reset_examined(target); - /* determine if we should halt or not. */ target->reset_halt = (a != 0); /* When this happens - all workareas are invalid. */ target_free_all_working_areas_restore(target, 0); /* do the assert */ - if (n->value == NVP_ASSERT) - return target->type->assert_reset(target); + if (n->value == NVP_ASSERT) { + int retval = target->type->assert_reset(target); + if (target->defer_examine) + target_reset_examined(target); + return retval; + } + return target->type->deassert_reset(target); } diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index f7c82ef..702b8fc 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -331,7 +331,7 @@ union xtensa_reg_val_u { uint8_t buf[4]; }; -static const struct xtensa_keyval_info_s xt_qerr[XT_QERR_NUM] = { +static const struct xtensa_keyval_info xt_qerr[XT_QERR_NUM] = { { .chrval = "E00", .intval = ERROR_FAIL }, { .chrval = "E01", .intval = ERROR_FAIL }, { .chrval = "E02", .intval = ERROR_COMMAND_ARGUMENT_INVALID }, diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h index a220021..1d56f83 100644 --- a/src/target/xtensa/xtensa.h +++ b/src/target/xtensa/xtensa.h @@ -97,7 +97,7 @@ enum xtensa_ar_scratch_set_e { XT_AR_SCRATCH_NUM }; -struct xtensa_keyval_info_s { +struct xtensa_keyval_info { char *chrval; int intval; }; @@ -283,7 +283,7 @@ struct xtensa { bool halt_request; uint32_t nx_stop_cause; uint32_t nx_reg_idx[XT_NX_REG_IDX_NUM]; - struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM]; + struct xtensa_keyval_info scratch_ars[XT_AR_SCRATCH_NUM]; bool regs_fetched; /* true after first register fetch completed successfully */ }; diff --git a/tcl/board/digilent_nexys2.cfg b/tcl/board/digilent_nexys2.cfg new file mode 100644 index 0000000..c1c5b2a --- /dev/null +++ b/tcl/board/digilent_nexys2.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# https://digilent.com/reference/programmable-logic/nexys-2/start +# +# The Digilent Nexy2 normally requires proprietary tools to program and will +# enumerate as: +# ID 1443:0005 1443 ONBOARD USB +# +# However, the ixo-usb-jtag project provides an alternative open firmware for +# the on board programmer. When using this firmware the board will then +# enumerate as: +# ID 16c0:06ad ixo.de USB-JTAG-IF (With SerialNumber == hw_nexys) +# +# See the interface/usb-jtag.cfg for more information. + +source [find interface/usb-jtag.cfg] +source [find cpld/xilinx-xcf-s.cfg] +source [find fpga/xilinx-xc3s.cfg] + +# Usage: +# +# Load Bitstream into FPGA: +# openocd -f board/digilent_nexys2.cfg -c "init;\ +# pld load 0 bitstream.bit;\ +# shutdown" + +# Read Unique Device Identifier (DNA): +# openocd -f board/digilent_nexys2.cfg -c "init;\ +# xilinx_print_dna [xc3s_get_dna xc3s.tap];\ +# shutdown" diff --git a/tcl/board/nxp/frdm-kv11z-jlink.cfg b/tcl/board/nxp/frdm-kv11z-jlink.cfg new file mode 100644 index 0000000..725a37b --- /dev/null +++ b/tcl/board/nxp/frdm-kv11z-jlink.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Configuration file for NXP FRDM-KV11Z development boards. +# +# This configuration file is only for FRDM-KV11Z development boards with the +# SEGGER J-Link OpenSDA firmware, see: +# https://www.segger.com/products/debug-probes/j-link/models/other-j-links/opensda-sda-v2/ + +source [find interface/jlink.cfg] + +# Set working area size to 16 KiB. +set WORKAREASIZE 0x4000 + +# Set the chip name. +set CHIPNAME kv11z + +transport select swd + +source [find target/kx.cfg] + +reset_config srst_only diff --git a/tcl/board/nxp/frdm-kv31f-jlink.cfg b/tcl/board/nxp/frdm-kv31f-jlink.cfg new file mode 100644 index 0000000..e55a01c --- /dev/null +++ b/tcl/board/nxp/frdm-kv31f-jlink.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Configuration file for NXP FRDM-KV31F development boards. +# +# This configuration file is only for FRDM-KV31F development boards with the +# SEGGER J-Link OpenSDA firmware, see: +# https://www.segger.com/products/debug-probes/j-link/models/other-j-links/opensda-sda-v2/ + +source [find interface/jlink.cfg] + +# Set working area size to 32 KiB. +set WORKAREASIZE 0x8000 + +# Set the chip name. +set CHIPNAME kv31f + +transport select swd + +source [find target/kx.cfg] + +reset_config srst_only diff --git a/tcl/chip/st/spear/spear3xx_ddr.tcl b/tcl/chip/st/spear/spear3xx_ddr.tcl index 5992567..0696221 100644 --- a/tcl/chip/st/spear/spear3xx_ddr.tcl +++ b/tcl/chip/st/spear/spear3xx_ddr.tcl @@ -10,7 +10,7 @@ proc sp3xx_ddr_init {ddr_type {ddr_chips 1}} { if { $ddr_chips != 1 && $ddr_chips != 2 } { - error "Only 1 or 2 DDR chips permitted. Wrong value "$ddr_chips + error "Only 1 or 2 DDR chips permitted. Wrong value $ddr_chips" } if { $ddr_type == "mt47h64m16_3_333_cl5_async" } { @@ -21,7 +21,7 @@ proc sp3xx_ddr_init {ddr_type {ddr_chips 1}} { # ????? $ddr_chips # set ddr_size 0x????? } else { - error "sp3xx_ddr_init: unrecognized DDR type "$ddr_type + error "sp3xx_ddr_init: unrecognized DDR type $ddr_type" } # MPMC START diff --git a/tcl/fpga/altera-arriaii.cfg b/tcl/fpga/altera-arriaii.cfg index d59c182..9cf680d 100644 --- a/tcl/fpga/altera-arriaii.cfg +++ b/tcl/fpga/altera-arriaii.cfg @@ -21,11 +21,26 @@ if { [info exists CHIPNAME] } { set _CHIPNAME arriaii } -jtag newtap $_CHIPNAME tap -irlen 10 \ - -expected-id 0x025120dd -expected-id 0x025040dd \ - -expected-id 0x025020dd -expected-id 0x024810dd \ - -expected-id 0x025130dd -expected-id 0x0240a0dd \ - -expected-id 0x025030dd -expected-id 0x024820dd \ - -expected-id 0x025140dd +array set _ARRIA_2_DATA { + 0x025120dd {1227 1174 EP2AGX45} + 0x025020dd {1227 -1 EP2AGX65} + 0x025130dd {1467 -1 EP2AGX95} + 0x025030dd {1467 -1 EP2AGX125} + 0x025140dd {1971 -1 EP2AGX190} + 0x025040dd {1971 -1 EP2AGX260} + 0x024810dd {2274 -1 EP2AGZ225} + 0x0240a0dd {2682 -1 EP2AGZ300} + 0x024820dd {2682 -1 EP2AGZ350} +} + +set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version} +foreach id [array names _ARRIA_2_DATA] { + set cmd [concat "-expected-id" id] +} +eval $jtag_newtap_cmd + +source [find fpga/altera_common_init.cfg] pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family arriaii +jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_ARRIA_2_DATA}" + diff --git a/tcl/fpga/altera-cyclone10.cfg b/tcl/fpga/altera-cyclone10.cfg index 3a1bc1f..0898c74 100644 --- a/tcl/fpga/altera-cyclone10.cfg +++ b/tcl/fpga/altera-cyclone10.cfg @@ -4,31 +4,33 @@ # see: https://www.intel.com/content/www/us/en/docs/programmable/683777/current/bst-operation-control.html # and: https://www.intel.cn/content/dam/support/us/en/programmable/kdb/pdfs/literature/hb/cyclone-10/c10gx-51003.pdf -# GX085: 0x02e120dd -# GX105: 0x02e320dd -# GX150: 0x02e720dd -# GX220: 0x02ef20dd -# 10cl006: 0x020f10dd -# 10cl010: 0x020f10dd -# 10cl016: 0x020f20dd -# 10cl025: 0x020f30dd -# 10cl040: 0x020f40dd -# 10cl055: 0x020f50dd -# 10cl080: 0x020f60dd -# 10cl120: 0x020f70dd - if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cyclone10 } -jtag newtap $_CHIPNAME tap -irlen 10 \ - -expected-id 0x02e720dd -expected-id 0x02e120dd \ - -expected-id 0x02ef20dd -expected-id 0x02e320dd \ - -expected-id 0x020f10dd -expected-id 0x020f20dd \ - -expected-id 0x020f30dd -expected-id 0x020f40dd \ - -expected-id 0x020f50dd -expected-id 0x020f60dd \ - -expected-id 0x020f70dd +array set _CYCLONE_10_DATA { + 0x020f10dd { 603 226 10cl006_10cl010} + 0x020f20dd {1080 409 10cl016} + 0x020f30dd { 732 286 10cl025} + 0x020f40dd {1632 604 10cl040} + 0x020f50dd {1164 442 10cl055} + 0x020f60dd {1314 502 10cl080} + 0x020f70dd {1620 613 10cl120} + 0x02e120dd {1339 -1 GX085} + 0x02e320dd {1339 -1 GX105} + 0x02e720dd {1339 -1 GX150} + 0x02ef20dd {1339 -1 GX220} +} + +set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version} +foreach id [array names _CYCLONE_10_DATA] { + set cmd [concat "-expected-id" id] +} +eval $jtag_newtap_cmd + +source [find fpga/altera_common_init.cfg] -pld device intel $_CHIPNAME.tap cyclone10 +pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cyclone10 +jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_10_DATA}" diff --git a/tcl/fpga/altera-cycloneiii.cfg b/tcl/fpga/altera-cycloneiii.cfg index d9be645..b0da418 100644 --- a/tcl/fpga/altera-cycloneiii.cfg +++ b/tcl/fpga/altera-cycloneiii.cfg @@ -4,32 +4,33 @@ # see Cyclone III Device Handbook # Table 12-2: Device IDCODE for Cyclone III Device Family -#EP3C5 0x020f10dd -#EP3C10 0x020f10dd -#EP3C16 0x020f20dd -#EP3C25 0x020f30dd -#EP3C40 0x020f40dd -#EP3C55 0x020f50dd -#EP3C80 0x020f60dd -#EP3C120 0x020f70dd -#Cyclone III LS -#EP3CLS70 0x027010dd -#EP3CLS100 0x027000dd -#EP3CLS150 0x027030dd -#EP3CLS200 0x027020dd - if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cycloneiii } -jtag newtap $_CHIPNAME tap -irlen 10 \ - -expected-id 0x020f10dd -expected-id 0x020f20dd \ - -expected-id 0x020f30dd -expected-id 0x020f40dd \ - -expected-id 0x020f50dd -expected-id 0x020f60dd \ - -expected-id 0x020f70dd -expected-id 0x027010dd \ - -expected-id 0x027000dd -expected-id 0x027030dd \ - -expected-id 0x027020dd +array set _CYCLONE_3_DATA { + 0x020f10dd { 603 226 EP3C5_EP3C10} + 0x020f20dd {1080 409 EP3C16} + 0x020f30dd { 732 286 EP3C25} + 0x020f40dd {1632 604 EP3C40} + 0x020f50dd {1164 442 EP3C55} + 0x020f60dd {1314 502 EP3C80} + 0x020f70dd {1620 613 EP3C120} + 0x027010dd {1314 226 EP3CLS70} + 0x027000dd {1314 226 EP3CLS100} + 0x027030dd {1314 409 EP3CLS150} + 0x027020dd {1314 409 EP3CLS200} +} + +set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version} +foreach id [array names _CYCLONE_3_DATA] { + set cmd [concat "-expected-id" id] +} +eval $jtag_newtap_cmd + +source [find fpga/altera_common_init.cfg] pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiii +jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_3_DATA}" diff --git a/tcl/fpga/altera-cycloneiv.cfg b/tcl/fpga/altera-cycloneiv.cfg index 6a908e8..44eb89d 100644 --- a/tcl/fpga/altera-cycloneiv.cfg +++ b/tcl/fpga/altera-cycloneiv.cfg @@ -4,38 +4,37 @@ # see Cyclone IV Device Handbook # Table 10-2: IDCODE Information for 32-Bit Cyclone IV Devices -#EP4CE6 0x020f10dd -#EP4CE10 0x020f10dd -#EP4CE15 0x020f20dd -#EP4CE22 0x020f30dd -#EP4CE30 0x020f40dd -#EP4CE40 0x020f40dd -#EP4CE55 0x020f50dd -#EP4CE75 0x020f60dd -#EP4CE115 0x020f70dd -#EP4CGX15 0x028010dd -#EP4CGX22 0x028120dd -#EP4CGX30 (3) 0x028020dd -#EP4CGX30 (4) 0x028230dd -#EP4CGX50 0x028130dd -#EP4CGX75 0x028030dd -#EP4CGX110 0x028140dd -#EP4CGX150 0x028040dd - if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cycloneiv } -jtag newtap $_CHIPNAME tap -irlen 10 \ - -expected-id 0x020f10dd -expected-id 0x020f20dd \ - -expected-id 0x020f30dd -expected-id 0x020f40dd \ - -expected-id 0x020f50dd -expected-id 0x020f60dd \ - -expected-id 0x020f70dd -expected-id 0x028010dd \ - -expected-id 0x028120dd -expected-id 0x028020dd \ - -expected-id 0x028230dd -expected-id 0x028130dd \ - -expected-id 0x028030dd -expected-id 0x028140dd \ - -expected-id 0x028040dd +array set _CYCLON_4_DATA { + 0x020f10dd { 603 226 EP4CE6_EP4CE10} + 0x020f20dd {1080 409 EP4CE15} + 0x020f30dd { 732 286 EP4CE22} + 0x020f40dd {1632 604 EP4CE30_EP4CE40} + 0x020f50dd {1164 442 EP4CE55} + 0x020f60dd {1314 502 EP4CE75} + 0x020f70dd {1620 613 EP4CE115} + 0x028010dd { 260 229 EP4CGX15} + 0x028120dd { 494 463 EP4CGX22} + 0x028020dd { 494 463 EP4CGX30} + 0x028230dd {1006 943 EP4CGX30} + 0x028130dd {1006 943 EP4CGX50} + 0x028030dd {1006 943 EP4CGX75} + 0x028140dd {1495 1438 EP4CGX110} + 0x028040dd {1495 1438 EP4CGX150} +} + +set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version} +foreach id [array names _CYCLON_4_DATA] { + set cmd [concat "-expected-id" id] +} +eval $jtag_newtap_cmd + +source [find fpga/altera_common_init.cfg] pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiv +jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_4_DATA}" diff --git a/tcl/fpga/altera-cyclonev.cfg b/tcl/fpga/altera-cyclonev.cfg index 46532a5..8d19cd8 100644 --- a/tcl/fpga/altera-cyclonev.cfg +++ b/tcl/fpga/altera-cyclonev.cfg @@ -4,44 +4,36 @@ # see Cyclone V Device Handbook # Table 9-1: IDCODE Information for Cyclone V Devices -#5CEA2 0x02b150dd -#5CEA4 0x02b050dd -#5CEA5 0x02b220dd -#5CEA7 0x02b130dd -#5CEA9 0x02b140dd -#5CGXC3 0x02b010dd -#5CGXC4 0x02b120dd -#5CGXC5 0x02b020dd -#5CGXC7 0x02b030dd -#5CGXC9 0x02b040dd -#5CGTD5 0x02b020dd -#5CGTD7 0x02b030dd -#5CGTD9 0x02b040dd -#5CSEA2 0x02d110dd -#5CSEA4 0x02d010dd -#5CSEA5 0x02d120dd -#5CSEA6 0x02d020dd -#5CSXC2 0x02d110dd -#5CSXC4 0x02d010dd -#5CSXC5 0x02d120dd -#5CSXC6 0x02d020dd -#5CSTD5 0x02d120dd -#5CSTD6 0x02d020dd - - if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME cyclonev } -jtag newtap $_CHIPNAME tap -irlen 10 \ - -expected-id 0x02b150dd -expected-id 0x02b050dd \ - -expected-id 0x02b220dd -expected-id 0x02b130dd \ - -expected-id 0x02b140dd -expected-id 0x02b010dd \ - -expected-id 0x02b120dd -expected-id 0x02b020dd \ - -expected-id 0x02b030dd -expected-id 0x02b040dd \ - -expected-id 0x02d110dd -expected-id 0x02d010dd \ - -expected-id 0x02d120dd -expected-id 0x02d020dd +array set _CYCLONE_5_DATA { + 0x02b150dd { 864 163 5CEA2} + 0x02d020dd {1485 19 5CSEA6_5CSXC6_5CSTD6} + 0x02b040dd {1728 -1 5CGXC9_5CGTD9} + 0x02b050dd { 864 163 5CEA4} + 0x02b030dd {1488 19 5CGXC7_5CGTD7} + 0x02d120dd {1485 -1 5CSEA5_5CSXC5_5CSTD5} + 0x02b220dd {1104 19 5CEA5} + 0x02b020dd {1104 19 5CGXC5_5CGTD5} + 0x02d010dd {1197 -1 5CSEA4_5CSXC4} + 0x02b120dd {1104 19 5CGXC4} + 0x02b140dd {1728 -1 5CEA9} + 0x02b010dd { 720 19 5CGXC3} + 0x02b130dd {1488 19 5CEA7} + 0x02d110dd {1197 -1 5CSEA2_5CSXC2} +} + +set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version} +foreach id [array names _CYCLONE_5_DATA] { + set cmd [concat "-expected-id" id] +} +eval $jtag_newtap_cmd + +source [find fpga/altera_common_init.cfg] pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cyclonev +jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_5_DATA}" diff --git a/tcl/fpga/altera_common_init.cfg b/tcl/fpga/altera_common_init.cfg new file mode 100644 index 0000000..683a844 --- /dev/null +++ b/tcl/fpga/altera_common_init.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +proc set_bscan_checkpos_on_setup {chipname data} { + set tapid_w_version [jtag cget $chipname.tap -idcode] + set version_mask 0x0fffffff + set tapid [format 0x%08x [expr {$tapid_w_version & $version_mask}]] + intel set_bscan $chipname.pld [lindex $data($tapid) 0] + intel set_check_pos $chipname.pld [lindex $data($tapid) 1] +} diff --git a/tcl/fpga/xilinx-dna.cfg b/tcl/fpga/xilinx-dna.cfg index 56f8c14..6b16b78 100644 --- a/tcl/fpga/xilinx-dna.cfg +++ b/tcl/fpga/xilinx-dna.cfg @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later +# Spartan3: Table 9-5 in https://www.xilinx.com/support/documentation/user_guides/ug332.pdf proc xilinx_dna_addr {chip} { array set addrs { + Spartan3 0x31 Spartan6 0x30 Series7 0x17 } @@ -43,3 +45,7 @@ proc xc7_get_dna {tap} { proc xc6s_get_dna {tap} { return [xilinx_get_dna $tap Spartan6] } + +proc xc3s_get_dna {tap} { + return [xilinx_get_dna $tap Spartan3] +} diff --git a/tcl/fpga/xilinx-xc3s.cfg b/tcl/fpga/xilinx-xc3s.cfg new file mode 100644 index 0000000..7c17206 --- /dev/null +++ b/tcl/fpga/xilinx-xc3s.cfg @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Xilinx Spartan3 generation +# https://www.xilinx.com/support/documentation/user_guides/ug331.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xc3s +} + +# Table 12-4 in https://www.xilinx.com/support/documentation/user_guides/ug332.pdf +# the 4 top bits (28:31) are the die stepping, ignore them. +jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x02210093 \ + -expected-id 0x02218093 \ + -expected-id 0x02220093 \ + -expected-id 0x02228093 \ + -expected-id 0x02230093 \ + -expected-id 0x02610093 \ + -expected-id 0x02618093 \ + -expected-id 0x02620093 \ + -expected-id 0x02628093 \ + -expected-id 0x02630093 \ + -expected-id 0x03840093 \ + -expected-id 0x0384E093 \ + -expected-id 0x01C10093 \ + -expected-id 0x01C1A093 \ + -expected-id 0x01C22093 \ + -expected-id 0x01C2E093 \ + -expected-id 0x01C3A093 \ + -expected-id 0x0140C093 \ + -expected-id 0x01414093 \ + -expected-id 0x0141C093 \ + -expected-id 0x01428093 \ + -expected-id 0x01434093 \ + -expected-id 0x01440093 \ + -expected-id 0x01448093 \ + -expected-id 0x01450093 + +pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap + +source [find fpga/xilinx-dna.cfg] diff --git a/tcl/interface/raspberrypi-gpio-connector.cfg b/tcl/interface/raspberrypi-gpio-connector.cfg index eff73fc..af7266b 100644 --- a/tcl/interface/raspberrypi-gpio-connector.cfg +++ b/tcl/interface/raspberrypi-gpio-connector.cfg @@ -10,6 +10,12 @@ # Do not forget the GND connection, e.g. pin 20 of the GPIO header. # +if { [info exists GPIO_CHIP] } { + set _GPIO_CHIP $GPIO_CHIP +} else { + set _GPIO_CHIP 0 +} + # GPIO 25 (pin 22) previously used for TMS/SWDIO is pulled-down by default. # The JTAG/SWD specification requires pull-up at the target board # for either signal. Connecting the signal pulled-up on the target @@ -19,23 +25,23 @@ echo "Warn : TMS/SWDIO moved to GPIO 8 (pin 24). Check the wiring please!" # Each of the JTAG lines need a gpio number set: tck tms tdi tdo # Header pin numbers: 23 24 19 21 -adapter gpio tck -chip 0 11 -adapter gpio tms -chip 0 8 -adapter gpio tdi -chip 0 10 -adapter gpio tdo -chip 0 9 +adapter gpio tck -chip $_GPIO_CHIP 11 +adapter gpio tms -chip $_GPIO_CHIP 8 +adapter gpio tdi -chip $_GPIO_CHIP 10 +adapter gpio tdo -chip $_GPIO_CHIP 9 # Each of the SWD lines need a gpio number set: swclk swdio # Header pin numbers: 23 24 -adapter gpio swclk -chip 0 11 -adapter gpio swdio -chip 0 8 +adapter gpio swclk -chip $_GPIO_CHIP 11 +adapter gpio swdio -chip $_GPIO_CHIP 8 # If you define trst or srst, use appropriate reset_config # Header pin numbers: TRST - 26, SRST - 18 -# adapter gpio trst -chip 0 7 +# adapter gpio trst -chip $_GPIO_CHIP 7 # reset_config trst_only -# adapter gpio srst -chip 0 24 +# adapter gpio srst -chip $_GPIO_CHIP 24 # reset_config srst_only srst_push_pull # or if you have both connected, diff --git a/tcl/interface/raspberrypi-native.cfg b/tcl/interface/raspberrypi-native.cfg index 7224723..c80f90a 100644 --- a/tcl/interface/raspberrypi-native.cfg +++ b/tcl/interface/raspberrypi-native.cfg @@ -37,9 +37,9 @@ proc get_max_cpu_clock { default } { return $clock } - echo "WARNING: Host CPU clock unknown." - echo "WARNING: Using the highest possible value $default kHz as a safe default." - echo "WARNING: Expect JTAG/SWD clock significantly slower than requested." + echo "Warn : Host CPU clock unknown." + echo "Warn : Using the highest possible value $default kHz as a safe default." + echo "Warn : Expect JTAG/SWD clock significantly slower than requested." return $default } @@ -56,9 +56,13 @@ if {[string match *bcm2711* $compat]} { } elseif {[string match *bcm2835* $compat] || [string match *bcm2708* $compat]} { set clocks_per_timing_loop 6 set speed_offset 32 +} elseif {[string match *bcm2712* $compat]} { + echo "Error: Raspberrypi Pi 5 has moved GPIOs to PCIe connected RP1 chip." + echo "Error: Native GPIO handling is not supported, use 'raspberrypi5-gpiod.cfg'" + shutdown } else { set speed_offset 32 - echo "WARNING: Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested." + echo "Warn : Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested." } set clock [get_max_cpu_clock 2000000] diff --git a/tcl/interface/raspberrypi5-gpiod.cfg b/tcl/interface/raspberrypi5-gpiod.cfg new file mode 100644 index 0000000..f3fdde0 --- /dev/null +++ b/tcl/interface/raspberrypi5-gpiod.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Config for Raspberry Pi 5 used as a bitbang adapter. +# https://www.raspberrypi.com/documentation/computers/raspberry-pi.html + +# Raspberry Pi 5 is not compatible with bcm2835gpio native GPIO driver. +# The linuxgpiod driver without configurable adapter speed runs at approximately +# 800 kHz (SWD writes) and 360 kHz (SWD reads) + +adapter driver linuxgpiod + +proc read_file { name } { + if {[catch {open $name r} fd]} { + return "" + } + set result [read $fd] + close $fd + return $result +} + +set pcie_aspm [read_file /sys/module/pcie_aspm/parameters/policy] +# escaping [ ] characters in string match pattern does not work in Jim-Tcl +if {![string match "*<performance>*" [string map { "\[" < "\]" > } $pcie_aspm]]} { + echo "Warn : Switch PCIe power saving off or the first couple of pulses gets clocked as fast as 20 MHz" + echo "Warn : Issue 'echo performance | sudo tee /sys/module/pcie_aspm/parameters/policy'" +} + +set GPIO_CHIP 4 +source [find interface/raspberrypi-gpio-connector.cfg] diff --git a/tcl/memory.tcl b/tcl/memory.tcl index b111749..8b93b51 100644 --- a/tcl/memory.tcl +++ b/tcl/memory.tcl @@ -66,10 +66,10 @@ proc iswithin { ADDRESS BASE LEN } { proc address_info { ADDRESS } { foreach WHERE { FLASH RAM MMREGS XMEM UNKNOWN } { - if { info exists $WHERE } { + if { [info exists $WHERE] } { set lmt [set N_[set WHERE]] for { set region 0 } { $region < $lmt } { incr region } { - if { iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN) } { + if { [iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN)] } { return "$WHERE $region"; } } diff --git a/tcl/target/c100helper.tcl b/tcl/target/c100helper.tcl index d1d3f25..ba0e4fe 100644 --- a/tcl/target/c100helper.tcl +++ b/tcl/target/c100helper.tcl @@ -176,7 +176,7 @@ proc setupAmbaClk {} { mmw $CLKCORE_AHB_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" - while {[expr {[mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK]} == 0} { sleep 1 } + while {[mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $AHB_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX @@ -250,7 +250,7 @@ proc setupArmClk {} { mmw $CLKCORE_ARM_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0 # wait for PLL to lock echo "Waiting for Amba PLL to lock" - while {[expr {[mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK]} == 0} { sleep 1 } + while {[mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK == 0} { sleep 1 } # remove the internal PLL bypass mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $ARM_PLL_BY_CTRL # remove PLL from BYPASS mode using MUX diff --git a/tcl/target/nrf53.cfg b/tcl/target/nrf53.cfg new file mode 100644 index 0000000..307df90 --- /dev/null +++ b/tcl/target/nrf53.cfg @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic nRF53 series: dual ARM Cortex-M33, multidrop SWD +# + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME nrf53 +} + +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x6ba02477 +} + +# Configurable instance ID resides in application UICR TINSTANCE +if { [info exists SWD_INSTANCE_ID] } { + set _SWD_INSTANCE_ID $SWD_INSTANCE_ID +} else { + set _SWD_INSTANCE_ID 0 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID + +if { [info exists SWD_MULTIDROP] } { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -dp-id 0x0070289 -instance-id $_SWD_INSTANCE_ID +} else { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +} + +set _TARGETNAME_APP $_CHIPNAME.cpuapp +target create $_TARGETNAME_APP cortex_m -dap $_CHIPNAME.dap + +$_TARGETNAME_APP configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# The network core is not accessible over HLA +if { ![using_hla] } { + set _TARGETNAME_NET $_CHIPNAME.cpunet + target create $_TARGETNAME_NET cortex_m -dap $_CHIPNAME.dap -ap-num 1 -defer-examine + + targets $_TARGETNAME_APP + + $_TARGETNAME_NET configure -work-area-phys 0x21000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 +} + +# Keep adapter speed less or equal 2000 kHz or flash programming fails! +adapter speed 1000 + +source [find target/nrf_common.cfg] + +flash bank $_CHIPNAME.app.flash nrf5 0x00000000 0 0 0 $_TARGETNAME_APP +flash bank $_CHIPNAME.app.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME_APP + +if { ![using_hla] } { + + flash bank $_CHIPNAME.net.flash nrf5 0x01000000 0 0 0 $_TARGETNAME_NET + flash bank $_CHIPNAME.net.uicr nrf5 0x01FF8000 0 0 0 $_TARGETNAME_NET + + # System reset sets NETWORK.FORCEOFF which keeps the network core in reset + # Don't touch network core during reset + $_TARGETNAME_NET configure -event reset-assert {} + # and start it after application core reset is finished to make all flash accessible + $_TARGETNAME_APP configure -event reset-init "nrf53_cpunet_release $_CHIPNAME" + + $_TARGETNAME_APP cortex_m reset_config sysresetreq + $_TARGETNAME_NET cortex_m reset_config sysresetreq + + $_TARGETNAME_APP configure -event examine-fail { _nrf_check_ap_lock 2 3 } + $_TARGETNAME_NET configure -event examine-fail { _nrf_check_ap_lock 3 3 } + + $_TARGETNAME_NET configure -event gdb-attach "_nrf53_cpunet_gdb_attach $_CHIPNAME" + + proc _nrf53_cpunet_gdb_attach { _CHIPNAME } { + set _TARGETNAME_APP $_CHIPNAME.cpuapp + set _TARGETNAME_NET $_CHIPNAME.cpunet + set RESET_NETWORK_FORCEOFF 0x50005614 + + set is_off [$_TARGETNAME_APP read_memory $RESET_NETWORK_FORCEOFF 32 1] + if { $is_off } { + nrf53_cpunet_release $_CHIPNAME + $_TARGETNAME_NET arp_poll + $_TARGETNAME_NET arp_waitstate halted 100 + } else { + if { ![$_TARGETNAME_NET was_examined] } { + $_TARGETNAME_NET arp_examine + $_TARGETNAME_NET arp_poll + } + set s [$_TARGETNAME_NET curstate] + if { ![string compare $s "halted"] } { + halt + } + } + } + lappend _telnet_autocomplete_skip _nrf53_cpunet_gdb_attach + + # Release the network core + proc nrf53_cpunet_release { {_CHIPNAME nrf53} } { + set _TARGETNAME_APP $_CHIPNAME.cpuapp + set _TARGETNAME_NET $_CHIPNAME.cpunet + set RESET_NETWORK_FORCEOFF 0x50005614 + set RESET_NETWORK_WORKAROUND 0x50005618 + set CORTEX_M_DCB_DEMCR 0xE000EDFC + + $_TARGETNAME_APP mww $RESET_NETWORK_WORKAROUND 1 + $_TARGETNAME_APP mww $RESET_NETWORK_FORCEOFF 0 + $_TARGETNAME_APP mww $RESET_NETWORK_FORCEOFF 1 + set err [catch {$_TARGETNAME_NET arp_examine}] + if { $err } { + if { ![_nrf_check_ap_lock 3 3] } { + echo "Error: \[$_TARGETNAME_NET\] examination failed" + } + return + } + # set TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET + $_TARGETNAME_NET mww $CORTEX_M_DCB_DEMCR 0x01000501 + # Write DEMCR directly intead of permanetly setting by cortex_m vector_catch reset + # following cortex_m_endreset_event() restores the original DEMCR value + $_TARGETNAME_APP mww $RESET_NETWORK_FORCEOFF 0 + $_TARGETNAME_APP mww $RESET_NETWORK_WORKAROUND 0 + } + + # Mass erase and unlock the device using proprietary nRF CTRL-AP (AP #2 or #3) + proc nrf53_cpuapp_recover {} { + _nrf_ctrl_ap_recover 2 + } + add_help_text nrf53_cpuapp_recover "Mass erase flash and unlock nRF53 application CPU" + + proc nrf53_recover {} { + _nrf_ctrl_ap_recover 3 1 + } + add_help_text nrf53_recover "Mass erase all device flash and unlock nRF53" +} diff --git a/tcl/target/nrf91.cfg b/tcl/target/nrf91.cfg new file mode 100644 index 0000000..e0ff4e5 --- /dev/null +++ b/tcl/target/nrf91.cfg @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic nRF91 series: ARM Cortex-M33, SWD only +# + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME nrf91 +} + +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x6ba02477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID + +# Contrary to the product specification at least nRF9161 supports multidrop SWD. +# The instance ID is fixed, no more than one nRF91 can be connected to one SWD bus. +if { [info exists SWD_MULTIDROP] } { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -dp-id 0x0090289 -instance-id 0 +} else { + dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap + +# Keep adapter speed less or equal 2000 kHz or flash programming fails! +adapter speed 1000 + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +source [find target/nrf_common.cfg] + +flash bank $_CHIPNAME.flash nrf5 0x00000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME + +if { ![using_hla] } { + $_TARGETNAME cortex_m reset_config sysresetreq + + $_TARGETNAME configure -event examine-fail { _nrf_check_ap_lock 4 3 } +} + +# Mass erase and unlock the device using proprietary nRF CTRL-AP (AP #4) +proc nrf91_recover {} { + _nrf_ctrl_ap_recover 4 +} +add_help_text nrf91_recover "Mass erase and unlock nRF91 device" diff --git a/tcl/target/nrf_common.cfg b/tcl/target/nrf_common.cfg new file mode 100644 index 0000000..2ae5011 --- /dev/null +++ b/tcl/target/nrf_common.cfg @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic nRF52, nRF53 and nRF91 CTRL-AP handling +# + +if { [using_hla] } { + echo "" + echo "nRF device has a CTRL-AP dedicated to recover the device from AP lock." + echo "A high level adapter (like a ST-Link) you are currently using cannot access" + echo "the CTRL-AP so 'nrfxx_recover' command will not work." + echo "Do not enable UICR APPROTECT." + echo "" +} else { + + # Test if debug/MEM-AP is locked by UICR APPROTECT + proc _nrf_check_ap_lock { ctrl_ap_num unlocked_value } { + set target [target current] + set dap [$target cget -dap] + set err [catch {set APPROTECTSTATUS [$dap apreg $ctrl_ap_num 0xc]}] + if {$err == 0 && $APPROTECTSTATUS < $unlocked_value} { + echo "" + echo "****** WARNING ******" + echo "\[$target\] device has AP lock engaged (see UICR APPROTECT register)." + echo "Debug access is denied." + echo "Use 'nrfxx_recover' to erase and unlock the device." + echo "" + poll off + return 1 + } + return 0 + } + + # Mass erase and unlock the device using proprietary nRF CTRL-AP + proc _nrf_ctrl_ap_recover { ctrl_ap_num {is_cpunet 0} } { + set target [target current] + set dap [$target cget -dap] + + set IDR [$dap apreg $ctrl_ap_num 0xfc] + if {$IDR != 0x12880000} { + echo "Error: Cannot access nRF CTRL-AP!" + return + } + + poll off + + # Reset and trigger ERASEALL task + $dap apreg $ctrl_ap_num 4 0 + $dap apreg $ctrl_ap_num 4 1 + + for {set i 0} {1} {incr i} { + set ERASEALLSTATUS [$dap apreg $ctrl_ap_num 8] + if {$ERASEALLSTATUS == 0} { + echo "\[$target\] device has been successfully erased and unlocked." + break + } + if {$i == 0} { + echo "Waiting for chip erase..." + } + if {$i >= 150} { + echo "Error: \[$target\] recovery failed." + break + } + sleep 100 + } + + # Assert reset + $dap apreg $ctrl_ap_num 0 1 + + # Deassert reset + $dap apreg $ctrl_ap_num 0 0 + + # Reset ERASEALL task + $dap apreg $ctrl_ap_num 4 0 + + if { $is_cpunet } { + reset init + } else { + sleep 100 + $target arp_examine + poll on + } + } + + lappend _telnet_autocomplete_skip _nrf_check_ap_lock _nrf_ctrl_ap_recover +} |