diff options
Diffstat (limited to 'src')
63 files changed, 2911 insertions, 2689 deletions
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/asm.h b/src/target/riscv/asm.h index 6ceb8c9..828cd86 100644 --- a/src/target/riscv/asm.h +++ b/src/target/riscv/asm.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET__RISCV__ASM_H -#define TARGET__RISCV__ASM_H +#ifndef OPENOCD_TARGET_RISCV_ASM_H +#define OPENOCD_TARGET_RISCV_ASM_H #include "riscv.h" @@ -37,4 +37,4 @@ static uint32_t store(const struct target *target, unsigned int src, return 0; /* Silence -Werror=return-type */ } -#endif +#endif /* OPENOCD_TARGET_RISCV_ASM_H */ diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 4115a37..afea316 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); @@ -190,23 +190,22 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, for (size_t i = start_idx; i < batch->used_scans; ++i) { const int delay = get_delay(batch, i, delays); - riscv_log_dmi_scan(batch->target, delay, batch->fields + i, - /*discard_in*/ false); + riscv_log_dmi_scan(batch->target, delay, batch->fields + i); } 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; } -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_write(batch->target, (char *)field->out_value, address, data); + riscv_fill_dmi_write(batch->target, (char *)field->out_value, address, data); if (read_back) { field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); riscv_fill_dm_nop(batch->target, (char *)field->in_value); @@ -218,7 +217,7 @@ void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint3 batch->used_scans++; } -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address, enum riscv_scan_delay_class delay_class) { assert(batch->used_scans < batch->allocated_scans); @@ -226,7 +225,7 @@ size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, field->num_bits = riscv_get_dmi_scan_length(batch->target); field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_read(batch->target, (char *)field->out_value, address); + riscv_fill_dmi_read(batch->target, (char *)field->out_value, address); riscv_fill_dm_nop(batch->target, (char *)field->in_value); batch->delay_classes[batch->used_scans] = delay_class; batch->last_scan = RISCV_SCAN_TYPE_READ; diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 03947aa..660a63f 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET__RISCV__SCANS_H -#define TARGET__RISCV__SCANS_H +#ifndef OPENOCD_TARGET_RISCV_BATCH_H +#define OPENOCD_TARGET_RISCV_BATCH_H #include "target/target.h" #include "jtag/jtag.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,21 +183,39 @@ 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. */ size_t riscv_batch_finished_scans(const struct riscv_batch *batch); /* Adds a DM register write to this batch. */ -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint64_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class); +static inline void +riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, + bool read_back, enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_write(batch, + riscv_get_dmi_address(batch->target, address), data, + read_back, delay_type); +} + /* DM register reads must be handled in two parts: the first one schedules a read and * provides a key, the second one actually obtains the result of the read - * status (op) and the actual data. */ -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint64_t address, enum riscv_scan_delay_class delay_class); + +static inline size_t +riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, + enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_read(batch, + riscv_get_dmi_address(batch->target, address), delay_type); +} + unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key); uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key); @@ -168,7 +231,7 @@ bool riscv_batch_was_batch_busy(const struct riscv_batch *batch); /* TODO: The function is defined in `riscv-013.c`. This is done to reduce the * diff of the commit. The intention is to move the function definition to * a separate module (e.g. `riscv013-jtag-dtm.c/h`) in another commit. */ -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, - bool discard_in); +void riscv_log_dmi_scan(const struct target *target, int idle, + const struct scan_field *field); -#endif +#endif /* OPENOCD_TARGET_RISCV_BATCH_H */ diff --git a/src/target/riscv/debug_reg_printer.h b/src/target/riscv/debug_reg_printer.h index 98226b7..5089ff8 100644 --- a/src/target/riscv/debug_reg_printer.h +++ b/src/target/riscv/debug_reg_printer.h @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef OPENOCD_TARGET_RISCV_DEBUG_REG_PRINTER_H +#define OPENOCD_TARGET_RISCV_DEBUG_REG_PRINTER_H + #include "debug_defines.h" enum riscv_debug_reg_show { @@ -33,3 +36,5 @@ enum riscv_debug_reg_show { unsigned int riscv_debug_reg_to_s(char *buf, enum riscv_debug_reg_ordinal reg_ordinal, riscv_debug_reg_ctx_t context, uint64_t value, enum riscv_debug_reg_show show); + +#endif /* OPENOCD_TARGET_RISCV_DEBUG_REG_PRINTER_H */ diff --git a/src/target/riscv/field_helpers.h b/src/target/riscv/field_helpers.h index 16578f1..abf19f6 100644 --- a/src/target/riscv/field_helpers.h +++ b/src/target/riscv/field_helpers.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef FIELD_HELPERS_H -#define FIELD_HELPERS_H +#ifndef OPENOCD_TARGET_RISCV_FIELD_HELPERS_H +#define OPENOCD_TARGET_RISCV_FIELD_HELPERS_H #include <stdint.h> #include <assert.h> @@ -44,4 +44,4 @@ static inline uint32_t field_value32(uint32_t mask, uint32_t val) return set_field32(0, mask, val); } -#endif +#endif /* OPENOCD_TARGET_RISCV_FIELD_HELPERS_H */ diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index 92c8cc5..0d03929 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET__RISCV__GDB_REGS_H -#define TARGET__RISCV__GDB_REGS_H +#ifndef OPENOCD_TARGET_RISCV_GDB_REGS_H +#define OPENOCD_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. */ @@ -123,6 +125,4 @@ enum gdb_regno { GDB_REGNO_COUNT }; -const char *gdb_regno_name(const struct target *target, enum gdb_regno regno); - -#endif +#endif /* OPENOCD_TARGET_RISCV_GDB_REGS_H */ diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index 59c3413..99ae90f 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef OPENOCD_TARGET_RISCV_OPCODES_H +#define OPENOCD_TARGET_RISCV_OPCODES_H + #include "encoding.h" #define ZERO 0 @@ -339,3 +342,4 @@ static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2, return ((vm & 1) << 25) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX; } +#endif /* OPENOCD_TARGET_RISCV_OPCODES_H */ diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 361191a..91f0dab 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET__RISCV__PROGRAM_H -#define TARGET__RISCV__PROGRAM_H +#ifndef OPENOCD_TARGET_RISCV_PROGRAM_H +#define OPENOCD_TARGET_RISCV_PROGRAM_H #include "riscv.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); @@ -77,4 +77,4 @@ int riscv_program_ebreak(struct riscv_program *p); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); -#endif +#endif /* OPENOCD_TARGET_RISCV_PROGRAM_H */ 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..bbbc194 --- /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..4f7911a --- /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_011_REG_H +#define OPENOCD_TARGET_RISCV_RISCV_011_REG_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_011_REG_H */ diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 83f03f1..ae36a06 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); @@ -57,10 +56,7 @@ static int riscv013_invalidate_cached_progbuf(struct target *target); static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr); static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a); -static void riscv013_fill_dmi_nop(struct target *target, char *buf); static int riscv013_get_dmi_scan_length(struct target *target); -static void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -static void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a); static void riscv013_fill_dm_nop(struct target *target, char *buf); static unsigned int register_size(struct target *target, enum gdb_regno number); static int register_read_direct(struct target *target, riscv_reg_t *value, @@ -170,21 +166,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; @@ -386,7 +373,9 @@ static unsigned int decode_dmi(const struct target *target, char *text, uint32_t return 0; } -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, bool discard_in) +/* TODO: Move this function to "batch.c" and make it static. */ +void riscv_log_dmi_scan(const struct target *target, int idle, + const struct scan_field *field) { static const char * const op_string[] = {"-", "r", "w", "?"}; static const char * const status_string[] = {"+", "?", "F", "b"}; @@ -410,7 +399,7 @@ void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan field->num_bits, op_string[out_op], out_data, out_address, status_string[in_op], in_data, in_address, idle); - if (!discard_in && in_op == DTM_DMI_OP_SUCCESS) { + if (in_op == DTM_DMI_OP_SUCCESS) { char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1]; decode_dmi(target, in_decoded, in_address, in_data); /* FIXME: The current code assumes that the hardware @@ -479,15 +468,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); + + int res = dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, + NULL /* discard result */); + if (res != ERROR_OK) + return res; - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); + 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,219 +503,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; -} -/** - * exec: If this is set, assume the scan results in an execution, so more - * run-test/idle cycles may be required. - */ -static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in, - uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out, - bool exec) -{ - riscv013_info_t *info = get_info(target); - unsigned num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH; - size_t num_bytes = (num_bits + 7) / 8; - uint8_t in[num_bytes]; - uint8_t out[num_bytes]; - struct scan_field field = { - .num_bits = num_bits, - .out_value = out, - .in_value = in - }; - riscv_bscan_tunneled_scan_context_t bscan_ctxt; - - decrement_reset_delays_counter(target, 1); - - memset(in, 0, num_bytes); - memset(out, 0, num_bytes); - - if (info->abits == 0) { - LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0."); - return DMI_STATUS_FAILED; - } - - buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); - buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); - buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); - - /* I wanted to place this code in a different function, but the way JTAG command - queueing works in the jtag handling functions, the scan fields either have to be - heap allocated, global/static, or else they need to stay on the stack until - the jtag_execute_queue() call. Heap or static fields in this case doesn't seem - the best fit. Declaring stack based field values in a subsidiary function call wouldn't - work. */ - if (bscan_tunnel_ir_width != 0) { - riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt); - } else { - /* Assume dbus is already selected. */ - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); - } - - int idle_count = info->dmi_busy_delay; - if (exec) - idle_count += info->ac_busy_delay; - - if (idle_count) - jtag_add_runtest(idle_count, TAP_IDLE); - - int retval = jtag_execute_queue(); - if (retval != ERROR_OK) { - LOG_ERROR("dmi_scan failed jtag scan"); - if (data_in) - *data_in = ~0; - return DMI_STATUS_FAILED; - } - - if (bscan_tunnel_ir_width != 0) { - /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ - buffer_shr(in, num_bytes, 1); - } - - if (data_in) - *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); - - if (address_in) - *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); - riscv_log_dmi_scan(target, idle_count, &field, /*discard_in*/ !data_in); - return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); -} - -/** - * @param target - * @param data_in The data we received from the target. - * @param dmi_busy_encountered - * If non-NULL, will be updated to reflect whether DMI busy was - * encountered while executing this operation or not. - * @param op The operation to perform (read/write/nop). - * @param address The address argument to that operation. - * @param data_out The data to send to the target. - * @param timeout_sec - * @param exec When true, this scan will execute something, so extra RTI - * cycles may be added. - * @param ensure_success - * Scan a nop after the requested operation, ensuring the - * DMI operation succeeded. - */ -static int dmi_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) -{ - select_dmi(target); - - dmi_status_t status; - - if (dmi_busy_encountered) - *dmi_busy_encountered = false; - - const char *op_name; - switch (op) { - case DMI_OP_NOP: - op_name = "nop"; - break; - case DMI_OP_READ: - op_name = "read"; - break; - case DMI_OP_WRITE: - op_name = "write"; - break; - default: - LOG_ERROR("Invalid DMI operation: %d", op); - return ERROR_FAIL; - } - - keep_alive(); - - time_t start = time(NULL); - /* This first loop performs the request. Note that if for some reason this - * stays busy, it is actually due to the previous access. */ - while (1) { - status = dmi_scan(target, NULL, NULL, op, address, data_out, - exec); - if (status == DMI_STATUS_BUSY) { - increase_dmi_busy_delay(target); - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - break; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - - if (status != DMI_STATUS_SUCCESS) { - LOG_TARGET_ERROR(target, "Failed DMI %s at 0x%x; status=%d", op_name, address, status); - return ERROR_FAIL; - } - - if (ensure_success) { - /* This second loop ensures the request succeeded, and gets back data. - * Note that NOP can result in a 'busy' result as well, but that would be - * noticed on the next DMI access we do. */ - while (1) { - status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0, - false); - if (status == DMI_STATUS_BUSY) { - increase_dmi_busy_delay(target); - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - if (data_in) { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; value=0x%x, status=%d", - op_name, address, *data_in, status); - } else { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; status=%d", op_name, address, - status); - } - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - return ERROR_FAIL; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - } - - return ERROR_OK; -} - -static int dmi_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) -{ - int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, op, - address, data_out, riscv_command_timeout_sec, exec, ensure_success); - if (result == ERROR_TIMEOUT_REACHED) { - LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. The target is " - "either really slow or broken. You could increase the " - "timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec); - return ERROR_FAIL; - } - return result; -} - -static int dmi_read(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true); -} - -static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true); -} - -static int dmi_write(struct target *target, uint32_t address, uint32_t value) -{ - return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true); + reset_learned_delays(target); } static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t address) @@ -729,34 +516,22 @@ static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t a return address + base; } -static int dm_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_op_timeout(target, data_in, dmi_busy_encountered, op, address + dm->base, - data_out, timeout_sec, exec, ensure_success); -} +static int batch_run_timeout(struct target *target, struct riscv_batch *batch); -static int dm_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_op(target, data_in, dmi_busy_encountered, op, address + dm->base, - data_out, exec, ensure_success); + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_read(batch, address, RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; } static int dm_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_read(target, value, address + dm->base); + return dmi_read(target, value, riscv013_get_dmi_address(target, address)); } static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address) @@ -764,16 +539,29 @@ static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dm_read(batch, address, RISCV_DELAY_ABSTRACT_COMMAND); dm->abstract_cmd_maybe_busy = true; - return dmi_read_exec(target, value, address + dm->base); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; +} + +static int dmi_write(struct target *target, uint32_t address, uint32_t value) +{ + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_write(batch, address, value, /*read_back*/ true, + RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int dm_write(struct target *target, uint32_t address, uint32_t value) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_write(target, address + dm->base, value); + return dmi_write(target, riscv013_get_dmi_address(target, address), value); } static bool check_dbgbase_exists(struct target *target) @@ -803,11 +591,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 +612,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 +662,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 +684,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 +708,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) @@ -953,8 +727,6 @@ clear_cmderr: return res; } -static int batch_run_timeout(struct target *target, struct riscv_batch *batch); - static int execute_abstract_command(struct target *target, uint32_t command, uint32_t *cmderr) { @@ -976,7 +748,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 +876,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 +976,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 +1062,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 +1137,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 +1153,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 +1169,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 +1388,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 +1418,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 +1446,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 +1486,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 +1516,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 +1537,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 +1560,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 +1592,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 +1604,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 +1622,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 +1632,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 +1651,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 +1668,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 +1691,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 +1701,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 +1861,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 +1883,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 +2174,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 +2334,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 +2374,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 +2385,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 +2414,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 +2443,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 +2454,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 +2469,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; @@ -2741,53 +2511,63 @@ static uint32_t sb_sbaccess(unsigned int size_bytes) return 0; } -static int sb_write_address(struct target *target, target_addr_t address, - bool ensure_success) +static unsigned int get_sbaadress_reg_count(const struct target *target) { RISCV013_INFO(info); - unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + const unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + return DIV_ROUND_UP(sbasize, 32); +} + +static void batch_fill_sb_write_address(const struct target *target, + struct riscv_batch *batch, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) +{ /* There currently is no support for >64-bit addresses in OpenOCD. */ - if (sbasize > 96) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); - if (sbasize > 64) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); - if (sbasize > 32) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, - (uint32_t)(address >> 32), false, false); - return dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, - (uint32_t)address, false, ensure_success); + assert(sizeof(target_addr_t) == sizeof(uint64_t)); + const uint32_t addresses[] = {DM_SBADDRESS0, DM_SBADDRESS1, DM_SBADDRESS2, DM_SBADDRESS3}; + const uint32_t values[] = {(uint32_t)address, (uint32_t)(address >> 32), 0, 0}; + const unsigned int reg_count = get_sbaadress_reg_count(target); + assert(reg_count > 0); + assert(reg_count <= ARRAY_SIZE(addresses)); + assert(ARRAY_SIZE(addresses) == ARRAY_SIZE(values)); + + for (unsigned int i = reg_count - 1; i > 0; --i) + riscv_batch_add_dm_write(batch, addresses[i], values[i], /* read back */ true, + RISCV_DELAY_BASE); + riscv_batch_add_dm_write(batch, addresses[0], values[0], /* read back */ true, + sbaddr0_delay); } -/* TODO: store delays in "struct riscv_scan_delays" and remove this function. */ -struct riscv_scan_delays get_scan_delays(struct target *target) +static int sb_write_address(struct target *target, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) { - 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; + struct riscv_batch *batch = riscv_batch_alloc(target, + get_sbaadress_reg_count(target)); + batch_fill_sb_write_address(target, batch, address, sbaddr0_delay); + const int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int batch_run(struct target *target, struct riscv_batch *batch) { 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 +2576,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 +2752,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 +2764,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 +2888,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; @@ -3113,8 +2901,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->write_progbuf = &riscv013_write_progbuf; generic_info->execute_progbuf = &riscv013_execute_progbuf; generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf; - generic_info->fill_dm_write = &riscv013_fill_dm_write; - generic_info->fill_dm_read = &riscv013_fill_dm_read; + generic_info->fill_dmi_write = &riscv013_fill_dmi_write; + generic_info->fill_dmi_read = &riscv013_fill_dmi_read; generic_info->fill_dm_nop = &riscv013_fill_dm_nop; generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length; generic_info->authdata_read = &riscv013_authdata_read; @@ -3138,11 +2926,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 +3013,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 +3041,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 +3212,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 +3357,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); @@ -3588,92 +3371,51 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; /* This address write will trigger the first read. */ - if (sb_write_address(target, next_address, true) != ERROR_OK) + if (sb_write_address(target, next_address, RISCV_DELAY_SYSBUS_READ) != ERROR_OK) return ERROR_FAIL; - if (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; - } - } - /* First read has been started. Optimistically assume that it has * completed. */ static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3}; + /* TODO: The only purpose of "sbvalue" is to be passed to + * "log_memory_access()". If "log_memory_access()" were to + * accept "uint8_t *" instead of "uint32_t *", "sbvalue" would + * be unnecessary. + */ uint32_t sbvalue[4] = {0}; assert(size <= 16); - target_addr_t next_read = address - 1; - uint32_t buffer_offset = 0; - int next_read_j = 0; for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { - for (int j = (size - 1) / 4; j >= 0; j--) { - unsigned attempt = 0; - while (1) { - if (attempt++ > 100) { - LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory" - " just past " TARGET_ADDR_FMT, next_read); - return ERROR_FAIL; - } - keep_alive(); - dmi_status_t status = dmi_scan(target, NULL, &sbvalue[next_read_j], - DMI_OP_READ, sbdata[j] + dm->base, 0, false); - /* By reading from sbdata0, we have just initiated another system bus read. - * If necessary add a delay so the read can finish. */ - 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 +3456,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 +3875,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 +4184,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 +4281,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; @@ -4738,9 +4485,10 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, target_addr_t next_address = address; target_addr_t end_address = address + count * size; - int result; + int result = sb_write_address(target, next_address, RISCV_DELAY_BASE); + if (result != ERROR_OK) + return result; - sb_write_address(target, next_address, true); while (next_address < end_address) { LOG_TARGET_DEBUG(target, "Transferring burst starting at address 0x%" TARGET_PRIxADDR, next_address); @@ -4800,39 +4548,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 +4682,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 +4820,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 +4993,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 +5002,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 +5022,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; @@ -5596,7 +5339,7 @@ static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a) buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } -static void riscv013_fill_dmi_nop(struct target *target, char *buf) +static void riscv013_fill_dm_nop(struct target *target, char *buf) { RISCV013_INFO(info); buf_set_u64((unsigned char *)buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); @@ -5610,27 +5353,6 @@ static int riscv013_get_dmi_scan_length(struct target *target) return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } -void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_write(target, buf, a + dm->base, d); -} - -void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_read(target, buf, a + dm->base); -} - -void riscv013_fill_dm_nop(struct target *target, char *buf) -{ - riscv013_fill_dmi_nop(target, buf); -} - static int maybe_execute_fence_i(struct target *target) { if (has_sufficient_progbuf(target, 2)) @@ -5647,7 +5369,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 +5383,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..f39393c --- /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..e7a9447 --- /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_013_REG_H +#define OPENOCD_TARGET_RISCV_RISCV_013_REG_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_013_REG_H */ diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index b2612c2..267d20d 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); @@ -5897,16 +5587,16 @@ int riscv_execute_progbuf(struct target *target, uint32_t *cmderr) return r->execute_progbuf(target, cmderr); } -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) +void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d) { RISCV_INFO(r); - r->fill_dm_write(target, buf, a, d); + r->fill_dmi_write(target, buf, a, d); } -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a) +void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a) { RISCV_INFO(r); - r->fill_dm_read(target, buf, a); + r->fill_dmi_read(target, buf, a); } void riscv_fill_dm_nop(struct target *target, char *buf) @@ -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..a25aac8 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef RISCV_H -#define RISCV_H +#ifndef OPENOCD_TARGET_RISCV_RISCV_H +#define OPENOCD_TARGET_RISCV_RISCV_H struct riscv_program; @@ -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 @@ -232,8 +226,8 @@ struct riscv_info { int (*execute_progbuf)(struct target *target, uint32_t *cmderr); int (*invalidate_cached_progbuf)(struct target *target); int (*get_dmi_scan_length)(struct target *target); - void (*fill_dm_write)(struct target *target, char *buf, uint64_t a, uint32_t d); - void (*fill_dm_read)(struct target *target, char *buf, uint64_t a); + void (*fill_dmi_write)(struct target *target, char *buf, uint64_t a, uint32_t d); + void (*fill_dmi_read)(struct target *target, char *buf, uint64_t a); void (*fill_dm_nop)(struct target *target, char *buf); int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index); @@ -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); @@ -436,8 +408,8 @@ int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn); int riscv_execute_progbuf(struct target *target, uint32_t *cmderr); void riscv_fill_dm_nop(struct target *target, char *buf); -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a); +void riscv_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); +void riscv_fill_dmi_read(struct target *target, char *buf, uint64_t a); int riscv_get_dmi_scan_length(struct target *target); uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address); @@ -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); @@ -463,4 +433,4 @@ int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32 int riscv_interrupts_disable(struct target *target, uint64_t ie_mask, uint64_t *old_mstatus); int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus); -#endif +#endif /* OPENOCD_TARGET_RISCV_RISCV_H */ 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 */ }; |