From f2b228f5d1728b9972624c1a7ae681fc6df2cddc Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sat, 20 Jan 2018 21:05:46 +0300 Subject: [PATCH 01/91] jtag: drivers: stlink: ignore write verify error This looks like some inappropriate stlink (mis-)feature and it messes operations for writing to certain memory-mapped registers. Discussed at https://forum.sparkfun.com/viewtopic.php?f=18&t=44949 . Also known to be problematic for working with Kinetis parts. Reported by robertfoss_ on IRC. Change-Id: I8633aed13346c596000ba6c377758e1bb96db73f Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4368 Tested-by: jenkins Reviewed-by: Robert Foss Reviewed-by: Andreas Bolsch Reviewed-by: Freddie Chopin --- src/jtag/drivers/stlink_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 6f720b86b..99f96b9c9 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -457,8 +457,8 @@ static int stlink_usb_error_check(void *handle) LOG_DEBUG("Write error"); return ERROR_FAIL; case STLINK_JTAG_WRITE_VERIF_ERROR: - LOG_DEBUG("Verify error"); - return ERROR_FAIL; + LOG_DEBUG("Write verify error, ignoring"); + return ERROR_OK; case STLINK_SWD_AP_FAULT: /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 * returns ERROR_OK with the comment: From 0056037d68d29c566ce9f527a60828af51c68329 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 21 Jan 2018 10:47:32 +0100 Subject: [PATCH 02/91] flash/nor/kinetis_ke: fix warning retval set but not used I see no reason for not returning error from target_run_algorithm() to higher level. Reported by Clang static analyzer. Change-Id: Iaaa8b66e487ecae88c0cf4ae2addba63341c032c Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4391 Tested-by: jenkins Reviewed-by: Ivan Meleca --- src/flash/nor/kinetis_ke.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 636fcc2e9..b7a6a1ece 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -478,14 +478,13 @@ int kinetis_ke_stop_watchdog(struct target *target) watchdog_algorithm->address, 0, 100000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing Kinetis KE watchdog algorithm"); - retval = ERROR_FAIL; } else { LOG_INFO("Watchdog stopped"); } target_free_working_area(target, watchdog_algorithm); - return ERROR_OK; + return retval; } COMMAND_HANDLER(kinetis_ke_disable_wdog_handler) From 78a4b6607ef29b901bffaf506da024bf4d0823a6 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 6 Apr 2017 08:47:03 +0200 Subject: [PATCH 03/91] cortex_a: faster debug init Don't use atomic dap operations when not necessary Change-Id: Idc6dcd2bda95f7994852df4ae2a588976f4c9010 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4142 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 5d90e3416..672a300ec 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -206,23 +206,27 @@ static int cortex_a_init_debug_access(struct target *target) /* lock memory-mapped access to debug registers to prevent * software interference */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_LOCKACCESS, 0); if (retval != ERROR_OK) return retval; /* Disable cacheline fills and force cache write-through in debug state */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCCR, 0); if (retval != ERROR_OK) return retval; /* Disable TLB lookup and refill/eviction in debug state */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSMCR, 0); if (retval != ERROR_OK) return retval; + retval = dap_run(armv7a->debug_ap->dap); + if (retval != ERROR_OK) + return retval; + /* Enabling of instruction execution in debug mode is done in debug_entry code */ /* Resync breakpoint registers */ From 5830bf09a73f38cc96c49ff792bd5a85687a795b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 30 Oct 2017 17:59:06 +0100 Subject: [PATCH 04/91] flash/nor/at91samd: add SAM R30 family Microchip SAM R30 consist of a MCU SAM L21 and a radio. Similarly SAM R21 = SAM D21 + radio. Therefore SAM R devices was incorporated into SAM D21 and L21 device groups. Change-Id: I3448d784cae888070b57c2f504583760ddffc97f Suggested-by: Martin Deicke Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4282 Tested-by: jenkins --- src/flash/nor/at91samd.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index ad88c5143..449a283ca 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -159,23 +159,22 @@ static const struct samd_part samd21_parts[] = { { 0xC, "SAMD21E16A", 64, 8 }, { 0xD, "SAMD21E15A", 32, 4 }, { 0xE, "SAMD21E14A", 16, 2 }, - /* Below are B Variants (Table 3-7 from rev I of datasheet) */ - { 0x20, "SAMD21J16B", 64, 8 }, - { 0x21, "SAMD21J15B", 32, 4 }, - { 0x23, "SAMD21G16B", 64, 8 }, - { 0x24, "SAMD21G15B", 32, 4 }, - { 0x26, "SAMD21E16B", 64, 8 }, - { 0x27, "SAMD21E15B", 32, 4 }, -}; -/* Known SAMR21 parts. */ -static const struct samd_part samr21_parts[] = { + /* SAMR21 parts have integrated SAMD21 with a radio */ { 0x19, "SAMR21G18A", 256, 32 }, { 0x1A, "SAMR21G17A", 128, 32 }, { 0x1B, "SAMR21G16A", 64, 32 }, { 0x1C, "SAMR21E18A", 256, 32 }, { 0x1D, "SAMR21E17A", 128, 32 }, { 0x1E, "SAMR21E16A", 64, 32 }, + + /* SAMD21 B Variants (Table 3-7 from rev I of datasheet) */ + { 0x20, "SAMD21J16B", 64, 8 }, + { 0x21, "SAMD21J15B", 32, 4 }, + { 0x23, "SAMD21G16B", 64, 8 }, + { 0x24, "SAMD21G15B", 32, 4 }, + { 0x26, "SAMD21E16B", 64, 8 }, + { 0x27, "SAMD21E15B", 32, 4 }, }; /* Known SAML21 parts. */ @@ -200,6 +199,10 @@ static const struct samd_part saml21_parts[] = { { 0x1A, "SAML21E17B", 128, 16 }, { 0x1B, "SAML21E16B", 64, 8 }, { 0x1C, "SAML21E15B", 32, 4 }, + + /* SAMR30 parts have integrated SAML21 with a radio */ + { 0x1E, "SAMR30G18A", 256, 32 }, + { 0x1F, "SAMR30E18A", 256, 32 }, }; /* Known SAML22 parts. */ @@ -264,8 +267,6 @@ static const struct samd_family samd_families[] = { samd20_parts, ARRAY_SIZE(samd20_parts) }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, samd21_parts, ARRAY_SIZE(samd21_parts) }, - { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, - samr21_parts, ARRAY_SIZE(samr21_parts) }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09, samd09_parts, ARRAY_SIZE(samd09_parts) }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10, From 38030e011542a894237b517c065d22db97525954 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 26 Aug 2016 21:03:27 +0200 Subject: [PATCH 05/91] psoc4: update for 4x00BLE, L, M, S and PRoC BLE devices Flash ROM API command PSOC4_CMD_SET_IMO48 is now optional on new devices. Also code tidy up: - improved system ROM call error detection - probe does not require the target to be halted - default_padded_value and erased_value set to 0 - fixed endianess problem in flash write and protection setting - removed fancy chip detection table as it would be updated too often - psoc4 flash_autoerase is now on by default to ease programming psoc4.cfg distinguishes chip family and uses either proprietary acquire function of a KitProg adapter or TEST_MODE workaround to "reset halt" Change-Id: I2c75ec46ed0a95e09274fad70b62d6eed7b9ecdf Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/3807 Tested-by: jenkins Reviewed-by: David Girault --- src/flash/nor/psoc4.c | 631 +++++++++++++++++++++++++----------------- tcl/target/psoc4.cfg | 91 +++++- 2 files changed, 455 insertions(+), 267 deletions(-) diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index c7c85737c..1d861edc9 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -41,24 +41,65 @@ Document Number: 001-87197 Rev. *B Revised August 29, 2013 PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM - Document No. 001-85634 Rev. *C March 25, 2014 + Document No. 001-85634 Rev. *E June 28, 2016 PSoC(R) 4 Registers TRM Spec. Document No. 001-85847 Rev. *A June 25, 2013 + PSoC 4000 Family PSoC(R) 4 Technical Reference Manual + Document No. 001-89309 Rev. *B May 9, 2016 + + PSoC 41XX_BLE/42XX_BLE Family PSoC 4 BLE Architecture TRM + Document No. 001-92738 Rev. *C February 12, 2016 + + PSoC 4200L Family PSoC 4 Architecture TRM + Document No. 001-97952 Rev. *A December 15, 2015 + + PSoC 4200L Family PSoC 4 Registers TRM + Document No. 001-98126 Rev. *A December 16, 2015 + + PSoC 4100M/4200M Family PSoC 4 Architecture TRM + Document No. 001-95223 Rev. *B July 29, 2015 + + PSoC 4100S Family PSoC 4 Architecture TRM + Document No. 002-10621 Rev. *A July 29, 2016 + + PSoC 4100S Family PSoC 4 Registers TRM + Document No. 002-10523 Rev. *A July 20, 2016 + + PSoC Analog Coprocessor Architecture TRM + Document No. 002-10404 Rev. ** December 18, 2015 + + CY8C4Axx PSoC Analog Coprocessor Registers TRM + Document No. 002-10405 Rev. ** December 18, 2015 + CY8C41xx, CY8C42xx Programming Specifications Document No. 001-81799 Rev. *C March 4, 2014 + + CYBL10x6x, CY8C4127_BL, CY8C4247_BL Programming Specifications + Document No. 001-91508 Rev. *B September 22, 2014 */ /* register locations */ -#define PSOC4_CPUSS_SYSREQ 0x40000004 -#define PSOC4_CPUSS_SYSARG 0x40000008 -#define PSOC4_TEST_MODE 0x40030014 -#define PSOC4_SPCIF_GEOMETRY 0x400E0000 +#define PSOC4_SFLASH_MACRO0 0x0FFFF000 + +#define PSOC4_CPUSS_SYSREQ_LEGACY 0x40000004 +#define PSOC4_CPUSS_SYSARG_LEGACY 0x40000008 +#define PSOC4_SPCIF_GEOMETRY_LEGACY 0x400E0000 + +#define PSOC4_CPUSS_SYSREQ_NEW 0x40100004 +#define PSOC4_CPUSS_SYSARG_NEW 0x40100008 +#define PSOC4_SPCIF_GEOMETRY_NEW 0x40110000 + +#define PSOC4_TEST_MODE 0x40030014 + +#define PSOC4_ROMTABLE_PID0 0xF0000FE0 -#define PSOC4_SFLASH_MACRO 0x0ffff000 /* constants */ +#define PSOC4_SFLASH_MACRO_SIZE 0x400 +#define PSOC4_ROWS_PER_MACRO 512 + #define PSOC4_SROM_KEY1 0xb6 #define PSOC4_SROM_KEY2 0xd3 #define PSOC4_SROM_SYSREQ_BIT (1<<31) @@ -66,6 +107,10 @@ #define PSOC4_SROM_PRIVILEGED_BIT (1<<28) #define PSOC4_SROM_STATUS_SUCCEEDED 0xa0000000 #define PSOC4_SROM_STATUS_FAILED 0xf0000000 +#define PSOC4_SROM_STATUS_MASK 0xf0000000 + +/* not documented in any TRM */ +#define PSOC4_SROM_ERR_IMO_NOT_IMPLEM 0xf0000013 #define PSOC4_CMD_GET_SILICON_ID 0 #define PSOC4_CMD_LOAD_LATCH 4 @@ -74,76 +119,60 @@ #define PSOC4_CMD_ERASE_ALL 0xa #define PSOC4_CMD_CHECKSUM 0xb #define PSOC4_CMD_WRITE_PROTECTION 0xd +#define PSOC4_CMD_SET_IMO48 0x15 +#define PSOC4_CMD_WRITE_SFLASH_ROW 0x18 #define PSOC4_CHIP_PROT_VIRGIN 0x0 #define PSOC4_CHIP_PROT_OPEN 0x1 #define PSOC4_CHIP_PROT_PROTECTED 0x2 #define PSOC4_CHIP_PROT_KILL 0x4 +#define PSOC4_ROMTABLE_DESIGNER_CHECK 0xb4 -struct psoc4_chip_details { +#define PSOC4_FAMILY_FLAG_LEGACY 1 + +struct psoc4_chip_family { uint16_t id; - const char *type; - const char *package; - uint32_t flash_size_in_kb; + const char *name; + uint32_t flags; }; -/* list of PSoC 4 chips - * flash_size_in_kb is not necessary as it can be decoded from SPCIF_GEOMETRY - */ -const struct psoc4_chip_details psoc4_devices[] = { - /* 4200 series */ - { 0x04A6, "CY8C4245PVI-482", "SSOP-28", .flash_size_in_kb = 32 }, - { 0x04B6, "CY8C4245LQI-483", "QFN-40", .flash_size_in_kb = 32 }, - { 0x04C8, "CY8C4245AXI-483", "TQFP-44", .flash_size_in_kb = 32 }, - { 0x04FB, "CY8C4245AXI-473", "TQFP-44", .flash_size_in_kb = 32 }, - { 0x04F0, "CY8C4244PVI-432", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x04F1, "CY8C4244PVI-442", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x04F6, "CY8C4244LQI-443", "QFN-40", .flash_size_in_kb = 16 }, - { 0x04FA, "CY8C4244AXI-443", "TQFP-44", .flash_size_in_kb = 16 }, - - /* 4100 series */ - { 0x0410, "CY8C4124PVI-432", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x0411, "CY8C4124PVI-442", "SSOP-28", .flash_size_in_kb = 16 }, - { 0x041C, "CY8C4124LQI-443", "QFN-40", .flash_size_in_kb = 16 }, - { 0x041A, "CY8C4124AXI-443", "TQFP-44", .flash_size_in_kb = 16 }, - { 0x041B, "CY8C4125AXI-473", "TQFP-44", .flash_size_in_kb = 32 }, - { 0x0412, "CY8C4125PVI-482", "SSOP-28", .flash_size_in_kb = 32 }, - { 0x0417, "CY8C4125LQI-483", "QFN-40", .flash_size_in_kb = 32 }, - { 0x0416, "CY8C4125AXI-483", "TQFP-44", .flash_size_in_kb = 32 }, - - /* CCG1 series */ - { 0x0490, "CYPD1103-35FNXI", "CSP-35", .flash_size_in_kb = 32 }, - { 0x0489, "CYPD1121-40LQXI", "QFN-40", .flash_size_in_kb = 32 }, - { 0x048A, "CYPD1122-40LQXI", "QFN-40", .flash_size_in_kb = 32 }, - { 0x0491, "CYPD1131-35FNXI", "CSP-35", .flash_size_in_kb = 32 }, - { 0x0498, "CYPD1132-16SXI", "SOIC-16", .flash_size_in_kb = 32 }, - { 0x0481, "CYPD1134-28PVXI", "SSOP-28", .flash_size_in_kb = 32 }, - { 0x048B, "CYPD1134-40LQXI", "QFN-40", .flash_size_in_kb = 32 }, +const struct psoc4_chip_family psoc4_families[] = { + { 0x93, "PSoC4100/4200", .flags = PSOC4_FAMILY_FLAG_LEGACY }, + { 0x9A, "PSoC4000", .flags = 0 }, + { 0x9E, "PSoC/PRoC BLE (119E)", .flags = 0 }, + { 0xA0, "PSoC4200L", .flags = 0 }, + { 0xA1, "PSoC4100M/4200M", .flags = 0 }, + { 0xA3, "PSoC/PRoC BLE (11A3)", .flags = 0 }, + { 0xA9, "PSoC4000S", .flags = 0 }, + { 0xAA, "PSoC/PRoC BLE (11AA)", .flags = 0 }, + { 0xAB, "PSoC4100S", .flags = 0 }, + { 0xAC, "PSoC Analog Coprocessor", .flags = 0 }, + { 0, "Unknown", .flags = 0 } }; struct psoc4_flash_bank { uint32_t row_size; uint32_t user_bank_size; - int probed; - uint32_t silicon_id; - uint8_t chip_protection; + int num_macros; + bool probed; uint8_t cmd_program_row; + uint16_t family_id; + bool legacy_family; + uint32_t cpuss_sysreq_addr; + uint32_t cpuss_sysarg_addr; + uint32_t spcif_geometry_addr; }; -static const struct psoc4_chip_details *psoc4_details_by_id(uint32_t silicon_id) +static const struct psoc4_chip_family *psoc4_family_by_id(uint16_t family_id) { - const struct psoc4_chip_details *p = psoc4_devices; - unsigned int i; - uint16_t id = silicon_id >> 16; /* ignore die revision */ - for (i = 0; i < sizeof(psoc4_devices)/sizeof(psoc4_devices[0]); i++, p++) { - if (p->id == id) - return p; - } - LOG_DEBUG("Unknown PSoC 4 device silicon id 0x%08" PRIx32 ".", silicon_id); - return NULL; + const struct psoc4_chip_family *p = psoc4_families; + while (p->id && p->id != family_id) + p++; + + return p; } static const char *psoc4_decode_chip_protection(uint8_t protection) @@ -176,7 +205,9 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command) psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank)); bank->driver_priv = psoc4_info; + bank->default_padded_value = bank->erased_value = 0x00; psoc4_info->user_bank_size = bank->size; + psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW; return ERROR_OK; } @@ -189,9 +220,14 @@ FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command) * Otherwise address of memory parameter block is set in CPUSS_SYSARG * and the first parameter is written to the first word of parameter block */ -static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, - uint32_t *sysreq_params, uint32_t sysreq_params_size) +static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd, + uint16_t cmd_param, + uint32_t *sysreq_params, uint32_t sysreq_params_size, + uint32_t *sysarg_out) { + struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; + struct working_area *sysreq_wait_algorithm; struct working_area *sysreq_mem; @@ -212,8 +248,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4; /* stack must be aligned */ - const int stack_size = 196; - /* tested stack sizes on PSoC 4: + const int stack_size = 256; + /* tested stack sizes on PSoC4200: ERASE_ALL 144 PROGRAM_ROW 112 other sysreq 68 @@ -238,6 +274,8 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, } if (sysreq_params_size) { + LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " %08" PRIx32 " size %" PRIu32, + cmd, cmd_param, param1, sysreq_params[0], sysreq_params_size); /* Allocate memory for sysreq_params */ retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem); if (retval != ERROR_OK) { @@ -250,21 +288,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, } /* Write sysreq_params */ - sysreq_params[0] = param1; + target_buffer_set_u32(target, (uint8_t *)sysreq_params, param1); retval = target_write_buffer(target, sysreq_mem->address, sysreq_params_size, (uint8_t *)sysreq_params); if (retval != ERROR_OK) goto cleanup_mem; /* Set address of sysreq parameters block */ - retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, sysreq_mem->address); + retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, sysreq_mem->address); if (retval != ERROR_OK) goto cleanup_mem; } else { /* Sysreq without memory block of parameters */ + LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32, + cmd, cmd_param, param1); /* Set register parameter */ - retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, param1); + retval = target_write_u32(target, psoc4_info->cpuss_sysarg_addr, param1); if (retval != ERROR_OK) goto cleanup_mem; } @@ -279,14 +319,13 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m == NULL) { - /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); goto cleanup; } /* Set SROM request */ - retval = target_write_u32(target, PSOC4_CPUSS_SYSREQ, + retval = target_write_u32(target, psoc4_info->cpuss_sysreq_addr, PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd); if (retval != ERROR_OK) goto cleanup; @@ -295,9 +334,23 @@ static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param, retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params) / sizeof(*reg_params), reg_params, sysreq_wait_algorithm->address, 0, 1000, &armv7m_info); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { LOG_ERROR("sysreq wait code execution failed"); + goto cleanup; + } + uint32_t sysarg_out_tmp; + retval = target_read_u32(target, psoc4_info->cpuss_sysarg_addr, &sysarg_out_tmp); + if (retval != ERROR_OK) + goto cleanup; + + if (sysarg_out) { + *sysarg_out = sysarg_out_tmp; + /* If result is an error, do not show now, let caller to decide */ + } else if ((sysarg_out_tmp & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { + LOG_ERROR("sysreq error 0x%" PRIx32, sysarg_out_tmp); + retval = ERROR_FAIL; + } cleanup: destroy_reg_param(®_params[0]); @@ -313,42 +366,123 @@ cleanup_algo: /* helper routine to get silicon ID from a PSoC 4 chip */ -static int psoc4_get_silicon_id(struct target *target, uint32_t *silicon_id, uint8_t *protection) +static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, uint16_t *family_id, uint8_t *protection) { - uint32_t params = PSOC4_SROM_KEY1 - | ((PSOC4_SROM_KEY2 + PSOC4_CMD_GET_SILICON_ID) << 8); + struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; + uint32_t part0, part1; - int retval = psoc4_sysreq(target, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0); + int retval = psoc4_sysreq(bank, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0, &part0); if (retval != ERROR_OK) return retval; - retval = target_read_u32(target, PSOC4_CPUSS_SYSARG, &part0); - if (retval != ERROR_OK) - return retval; - - if (part0 == params) { - LOG_ERROR("sysreq silicon id request not served"); + if ((part0 & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { + LOG_ERROR("sysreq error 0x%" PRIx32, part0); return ERROR_FAIL; } - retval = target_read_u32(target, PSOC4_CPUSS_SYSREQ, &part1); + retval = target_read_u32(target, psoc4_info->cpuss_sysreq_addr, &part1); if (retval != ERROR_OK) return retval; - uint32_t silicon = ((part0 & 0xffff) << 16) - | (((part0 >> 16) & 0xff) << 8) - | (part1 & 0xff); - uint8_t prot = (part1 >> 12) & 0xff; - + /* build ID as Cypress sw does: + * bit 31..16 silicon ID + * bit 15..8 revision ID (so far 0x11 for all devices) + * bit 7..0 family ID (lowes 8 bits) + */ if (silicon_id) - *silicon_id = silicon; - if (protection) - *protection = prot; + *silicon_id = ((part0 & 0x0000ffff) << 16) + | ((part0 & 0x00ff0000) >> 8) + | (part1 & 0x000000ff); - LOG_DEBUG("silicon id: 0x%08" PRIx32 "", silicon); - LOG_DEBUG("protection: 0x%02" PRIx8 "", prot); - return retval; + if (family_id) + *family_id = part1 & 0x0fff; + + if (protection) + *protection = (part1 >> 12) & 0x0f; + + return ERROR_OK; +} + + +static int psoc4_get_family(struct target *target, uint16_t *family_id) +{ + int retval, i; + uint32_t pidbf[3]; + uint8_t pid[3]; + + retval = target_read_memory(target, PSOC4_ROMTABLE_PID0, 4, 3, (uint8_t *)pidbf); + if (retval != ERROR_OK) + return retval; + + for (i = 0; i < 3; i++) { + uint32_t tmp = target_buffer_get_u32(target, (uint8_t *)(pidbf + i)); + if (tmp & 0xffffff00) { + LOG_ERROR("Unexpected data in ROMTABLE"); + return ERROR_FAIL; + } + pid[i] = tmp & 0xff; + } + + uint16_t family = pid[0] | ((pid[1] & 0xf) << 8); + uint32_t designer = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0xf) << 4); + + if (designer != PSOC4_ROMTABLE_DESIGNER_CHECK) { + LOG_ERROR("ROMTABLE designer is not Cypress"); + return ERROR_FAIL; + } + + *family_id = family; + return ERROR_OK; +} + + +static int psoc4_flash_prepare(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + uint16_t family_id; + int retval; + + /* get family ID from SROM call */ + retval = psoc4_get_silicon_id(bank, NULL, &family_id, NULL); + if (retval != ERROR_OK) + return retval; + + /* and check with family ID from ROMTABLE */ + if (family_id != psoc4_info->family_id) { + LOG_ERROR("Family mismatch"); + return ERROR_FAIL; + } + + if (!psoc4_info->legacy_family) { + uint32_t sysreq_status; + retval = psoc4_sysreq(bank, PSOC4_CMD_SET_IMO48, 0, NULL, 0, &sysreq_status); + if (retval != ERROR_OK) + return retval; + + if ((sysreq_status & PSOC4_SROM_STATUS_MASK) != PSOC4_SROM_STATUS_SUCCEEDED) { + /* This undocumented error code is returned probably when + * PSOC4_CMD_SET_IMO48 command is not implemented. + * Can be safely ignored, programming works. + */ + if (sysreq_status == PSOC4_SROM_ERR_IMO_NOT_IMPLEM) + LOG_INFO("PSOC4_CMD_SET_IMO48 is not implemented on this device."); + else { + LOG_ERROR("sysreq error 0x%" PRIx32, sysreq_status); + return ERROR_FAIL; + } + } + } + + return ERROR_OK; } @@ -357,48 +491,37 @@ static int psoc4_protect_check(struct flash_bank *bank) struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; - uint32_t prot_addr = PSOC4_SFLASH_MACRO; - uint32_t protection; - int i, s; - int num_bits; - int retval = ERROR_OK; + uint32_t prot_addr = PSOC4_SFLASH_MACRO0; + int retval; + int s = 0; + int m, i; + uint8_t bf[PSOC4_ROWS_PER_MACRO/8]; - num_bits = bank->num_sectors; - - for (i = 0; i < num_bits; i += 32) { - retval = target_read_u32(target, prot_addr, &protection); + for (m = 0; m < psoc4_info->num_macros; m++, prot_addr += PSOC4_SFLASH_MACRO_SIZE) { + retval = target_read_memory(target, prot_addr, 4, PSOC4_ROWS_PER_MACRO/32, bf); if (retval != ERROR_OK) return retval; - prot_addr += 4; - - for (s = 0; s < 32; s++) { - if (i + s >= num_bits) - break; - bank->sectors[i + s].is_protected = (protection & (1 << s)) ? 1 : 0; - } + for (i = 0; i < PSOC4_ROWS_PER_MACRO && s < bank->num_sectors; i++, s++) + bank->sectors[s].is_protected = bf[i/8] & (1 << (i%8)) ? 1 : 0; } - retval = psoc4_get_silicon_id(target, NULL, &(psoc4_info->chip_protection)); - return retval; + return ERROR_OK; } static int psoc4_mass_erase(struct flash_bank *bank) { - struct target *target = bank->target; int i; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + int retval = psoc4_flash_prepare(bank); + if (retval != ERROR_OK) + return retval; /* Call "Erase All" system ROM API */ - uint32_t param; - int retval = psoc4_sysreq(target, PSOC4_CMD_ERASE_ALL, + uint32_t param = 0; + retval = psoc4_sysreq(bank, PSOC4_CMD_ERASE_ALL, 0, - ¶m, sizeof(param)); + ¶m, sizeof(param), NULL); if (retval == ERROR_OK) /* set all sectors as erased */ @@ -420,7 +543,7 @@ static int psoc4_erase(struct flash_bank *bank, int first, int last) if ((first == 0) && (last == (bank->num_sectors - 1))) return psoc4_mass_erase(bank); - LOG_ERROR("Only mass erase available"); + LOG_ERROR("Only mass erase available! Consider using 'psoc4 flash_autoerase 0 on'"); return ERROR_FAIL; } @@ -431,22 +554,23 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last) struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; - if (psoc4_info->probed == 0) + if (!psoc4_info->probed) return ERROR_FAIL; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + int retval = psoc4_flash_prepare(bank); + if (retval != ERROR_OK) + return retval; uint32_t *sysrq_buffer = NULL; - int retval; - int num_bits = bank->num_sectors; const int param_sz = 8; - int prot_sz = num_bits / 8; int chip_prot = PSOC4_CHIP_PROT_OPEN; - int flash_macro = 0; /* PSoC 42xx has only macro 0 */ - int i; + int i, m; + int num_bits = bank->num_sectors; + + if (num_bits > PSOC4_ROWS_PER_MACRO) + num_bits = PSOC4_ROWS_PER_MACRO; + + int prot_sz = num_bits / 8; sysrq_buffer = calloc(1, param_sz + prot_sz); if (sysrq_buffer == NULL) { @@ -454,33 +578,38 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - for (i = first; i < num_bits && i <= last; i++) + for (i = first; i <= last && i < bank->num_sectors; i++) bank->sectors[i].is_protected = set; - uint32_t *p = sysrq_buffer + 2; - for (i = 0; i < num_bits; i++) { - if (bank->sectors[i].is_protected) - p[i / 32] |= 1 << (i % 32); + for (m = 0; m < psoc4_info->num_macros; m++) { + uint8_t *p = (uint8_t *)(sysrq_buffer + 2); + for (i = 0; i < num_bits && i < bank->num_sectors; i++) { + if (bank->sectors[i].is_protected) + p[i/8] |= 1 << (i%8); + } + + /* Call "Load Latch" system ROM API */ + target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1), + prot_sz - 1); + retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH, + 0 /* Byte number in latch from what to write */ + | (m << 8), /* flash macro index */ + sysrq_buffer, param_sz + psoc4_info->row_size, + NULL); + if (retval != ERROR_OK) + break; + + /* Call "Write Protection" system ROM API */ + retval = psoc4_sysreq(bank, PSOC4_CMD_WRITE_PROTECTION, + chip_prot | (m << 8), NULL, 0, NULL); + if (retval != ERROR_OK) + break; } - /* Call "Load Latch" system ROM API */ - sysrq_buffer[1] = prot_sz - 1; - retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH, - 0, /* Byte number in latch from what to write */ - sysrq_buffer, param_sz + psoc4_info->row_size); - if (retval != ERROR_OK) - goto cleanup; - - /* Call "Write Protection" system ROM API */ - retval = psoc4_sysreq(target, PSOC4_CMD_WRITE_PROTECTION, - chip_prot | (flash_macro << 8), NULL, 0); -cleanup: - if (retval != ERROR_OK) - psoc4_protect_check(bank); - if (sysrq_buffer) free(sysrq_buffer); + psoc4_protect_check(bank); return retval; } @@ -516,21 +645,14 @@ COMMAND_HANDLER(psoc4_handle_flash_autoerase_command) static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - struct psoc4_flash_bank *psoc4_info = bank->driver_priv; struct target *target = bank->target; + struct psoc4_flash_bank *psoc4_info = bank->driver_priv; uint32_t *sysrq_buffer = NULL; - int retval = ERROR_OK; const int param_sz = 8; - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (offset & 0x1) { - LOG_ERROR("offset 0x%08" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } + int retval = psoc4_flash_prepare(bank); + if (retval != ERROR_OK) + return retval; sysrq_buffer = malloc(param_sz + psoc4_info->row_size); if (sysrq_buffer == NULL) { @@ -542,7 +664,7 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t row_num = offset / psoc4_info->row_size; uint32_t row_offset = offset - row_num * psoc4_info->row_size; if (row_offset) - memset(row_buffer, 0, row_offset); + memset(row_buffer, bank->default_padded_value, row_offset); bool save_poll = jtag_poll_get_enabled(); jtag_poll_set_enabled(false); @@ -551,25 +673,31 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t chunk_size = psoc4_info->row_size - row_offset; if (chunk_size > count) { chunk_size = count; - memset(row_buffer + chunk_size, 0, psoc4_info->row_size - chunk_size); + memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size); } memcpy(row_buffer + row_offset, buffer, chunk_size); LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "", offset, row_offset, chunk_size); + uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO; + /* Call "Load Latch" system ROM API */ - sysrq_buffer[1] = psoc4_info->row_size - 1; - retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH, - 0, /* Byte number in latch from what to write */ - sysrq_buffer, param_sz + psoc4_info->row_size); + target_buffer_set_u32(target, (uint8_t *)(sysrq_buffer + 1), + psoc4_info->row_size - 1); + retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH, + 0 /* Byte number in latch from what to write */ + | (macro_idx << 8), + sysrq_buffer, param_sz + psoc4_info->row_size, + NULL); if (retval != ERROR_OK) goto cleanup; /* Call "Program Row" or "Write Row" system ROM API */ uint32_t sysrq_param; - retval = psoc4_sysreq(target, psoc4_info->cmd_program_row, + retval = psoc4_sysreq(bank, psoc4_info->cmd_program_row, row_num & 0xffff, - &sysrq_param, sizeof(sysrq_param)); + &sysrq_param, sizeof(sysrq_param), + NULL); if (retval != ERROR_OK) goto cleanup; @@ -593,80 +721,62 @@ static int psoc4_probe(struct flash_bank *bank) { struct psoc4_flash_bank *psoc4_info = bank->driver_priv; struct target *target = bank->target; - uint32_t flash_size_in_kb = 0; - uint32_t max_flash_size_in_kb; - uint32_t cpu_id; - uint32_t silicon_id; - uint32_t row_size; - uint32_t base_address = 0x00000000; - uint8_t protection; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } + int retval; + uint16_t family_id; - psoc4_info->probed = 0; - psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW; + psoc4_info->probed = false; - /* Get the CPUID from the ARM Core - * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */ - int retval = target_read_u32(target, 0xE000ED00, &cpu_id); + retval = psoc4_get_family(target, &family_id); if (retval != ERROR_OK) return retval; - LOG_DEBUG("cpu id = 0x%08" PRIx32 "", cpu_id); + const struct psoc4_chip_family *family = psoc4_family_by_id(family_id); - /* set page size, protection granularity and max flash size depending on family */ - switch ((cpu_id >> 4) & 0xFFF) { - case 0xc20: /* M0 -> PSoC4 */ - row_size = 128; - max_flash_size_in_kb = 32; - break; - default: - LOG_WARNING("Cannot identify target as a PSoC 4 family."); + if (family->id == 0) { + LOG_ERROR("Cannot identify PSoC 4 family."); return ERROR_FAIL; } - uint32_t spcif_geometry; - retval = target_read_u32(target, PSOC4_SPCIF_GEOMETRY, &spcif_geometry); - if (retval == ERROR_OK) { - row_size = 128 * ((spcif_geometry >> 22) & 3); - flash_size_in_kb = (spcif_geometry & 0xffff) * 256 / 1024; - LOG_INFO("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.", - flash_size_in_kb, row_size); + if (family->flags & PSOC4_FAMILY_FLAG_LEGACY) { + LOG_INFO("%s legacy family detected.", family->name); + psoc4_info->legacy_family = true; + psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_LEGACY; + psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_LEGACY; + psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_LEGACY; + } else { + LOG_INFO("%s family detected.", family->name); + psoc4_info->legacy_family = false; + psoc4_info->cpuss_sysreq_addr = PSOC4_CPUSS_SYSREQ_NEW; + psoc4_info->cpuss_sysarg_addr = PSOC4_CPUSS_SYSARG_NEW; + psoc4_info->spcif_geometry_addr = PSOC4_SPCIF_GEOMETRY_NEW; } - /* Early revisions of ST-Link v2 have some problem reading PSOC4_SPCIF_GEOMETRY - and an error is reported late. Dummy read gets this error. */ - uint32_t dummy; - target_read_u32(target, PSOC4_CPUSS_SYSREQ, &dummy); - - /* get silicon ID from target. */ - retval = psoc4_get_silicon_id(target, &silicon_id, &protection); + uint32_t spcif_geometry; + retval = target_read_u32(target, psoc4_info->spcif_geometry_addr, &spcif_geometry); if (retval != ERROR_OK) return retval; - const struct psoc4_chip_details *details = psoc4_details_by_id(silicon_id); - if (details) { - LOG_INFO("%s device detected.", details->type); - if (flash_size_in_kb == 0) - flash_size_in_kb = details->flash_size_in_kb; - else if (flash_size_in_kb != details->flash_size_in_kb) - LOG_ERROR("Flash size mismatch"); + uint32_t flash_size_in_kb = spcif_geometry & 0x3fff; + /* TRM of legacy, M and L version describes FLASH field as 16-bit. + * S-series and PSoC Analog Coprocessor changes spec to 14-bit only. + * Impose PSoC Analog Coprocessor limit to all devices as it + * does not make any harm: flash size is safely below 4 MByte limit + */ + uint32_t row_size = (spcif_geometry >> 22) & 3; + uint32_t num_macros = (spcif_geometry >> 20) & 3; + + if (psoc4_info->legacy_family) { + flash_size_in_kb = flash_size_in_kb * 256 / 1024; + row_size *= 128; + } else { + flash_size_in_kb = (flash_size_in_kb + 1) * 256 / 1024; + row_size = 64 * (row_size + 1); + num_macros++; } - psoc4_info->row_size = row_size; - psoc4_info->silicon_id = silicon_id; - psoc4_info->chip_protection = protection; - - /* failed reading flash size or flash size invalid (early silicon), - * default to max target family */ - if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { - LOG_WARNING("PSoC 4 flash size failed, probe inaccurate - assuming %" PRIu32 " k flash", - max_flash_size_in_kb); - flash_size_in_kb = max_flash_size_in_kb; - } + LOG_DEBUG("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.", + flash_size_in_kb, row_size); /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ @@ -675,37 +785,35 @@ static int psoc4_probe(struct flash_bank *bank) flash_size_in_kb = psoc4_info->user_bank_size / 1024; } - LOG_INFO("flash size = %" PRIu32 " kbytes", flash_size_in_kb); + char macros_txt[20] = ""; + if (num_macros > 1) + snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros); - /* did we assign flash size? */ - assert(flash_size_in_kb != 0xffff); + LOG_INFO("flash size = %" PRIu32 " kbytes%s", flash_size_in_kb, macros_txt); - /* calculate numbers of pages */ + /* calculate number of pages */ uint32_t num_rows = flash_size_in_kb * 1024 / row_size; - /* check that calculation result makes sense */ - assert(num_rows > 0); + /* check number of flash macros */ + if (num_macros != (num_rows + PSOC4_ROWS_PER_MACRO - 1) / PSOC4_ROWS_PER_MACRO) + LOG_WARNING("Number of macros does not correspond with flash size!"); if (bank->sectors) { free(bank->sectors); - bank->sectors = NULL; } - bank->base = base_address; + psoc4_info->family_id = family_id; + psoc4_info->num_macros = num_macros; + psoc4_info->row_size = row_size; + bank->base = 0x00000000; bank->size = num_rows * row_size; bank->num_sectors = num_rows; - bank->sectors = malloc(sizeof(struct flash_sector) * num_rows); + bank->sectors = alloc_block_array(0, row_size, num_rows); + if (bank->sectors == NULL) + return ERROR_FAIL; - uint32_t i; - for (i = 0; i < num_rows; i++) { - bank->sectors[i].offset = i * row_size; - bank->sectors[i].size = row_size; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 1; - } - - LOG_INFO("flash bank set %" PRIu32 " rows", num_rows); - psoc4_info->probed = 1; + LOG_DEBUG("flash bank set %" PRIu32 " rows", num_rows); + psoc4_info->probed = true; return ERROR_OK; } @@ -721,28 +829,45 @@ static int psoc4_auto_probe(struct flash_bank *bank) static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size) { + struct target *target = bank->target; struct psoc4_flash_bank *psoc4_info = bank->driver_priv; - int printed = 0; - if (psoc4_info->probed == 0) + if (!psoc4_info->probed) return ERROR_FAIL; - const struct psoc4_chip_details *details = psoc4_details_by_id(psoc4_info->silicon_id); + const struct psoc4_chip_family *family = psoc4_family_by_id(psoc4_info->family_id); + uint32_t size_in_kb = bank->size / 1024; - if (details) { - uint32_t chip_revision = psoc4_info->silicon_id & 0xffff; - printed = snprintf(buf, buf_size, "PSoC 4 %s rev 0x%04" PRIx32 " package %s", - details->type, chip_revision, details->package); - } else - printed = snprintf(buf, buf_size, "PSoC 4 silicon id 0x%08" PRIx32 "", - psoc4_info->silicon_id); + if (target->state != TARGET_HALTED) { + snprintf(buf, buf_size, "%s, flash %" PRIu32 " kb" + " (halt target to see details)", family->name, size_in_kb); + return ERROR_OK; + } + + int retval; + int printed = 0; + uint32_t silicon_id; + uint16_t family_id; + uint8_t protection; + + retval = psoc4_get_silicon_id(bank, &silicon_id, &family_id, &protection); + if (retval != ERROR_OK) + return retval; + + if (family_id != psoc4_info->family_id) + printed = snprintf(buf, buf_size, "Family id mismatch 0x%02" PRIx16 + "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32, + psoc4_info->family_id, family_id, silicon_id); + else { + printed = snprintf(buf, buf_size, "%s silicon id 0x%08" PRIx32 "", + family->name, silicon_id); + } buf += printed; buf_size -= printed; - const char *prot_txt = psoc4_decode_chip_protection(psoc4_info->chip_protection); - uint32_t size_in_kb = bank->size / 1024; - snprintf(buf, buf_size, " flash %" PRIu32 " kb %s", size_in_kb, prot_txt); + const char *prot_txt = psoc4_decode_chip_protection(protection); + snprintf(buf, buf_size, ", flash %" PRIu32 " kb %s", size_in_kb, prot_txt); return ERROR_OK; } diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index d443b0144..5d6dcede3 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -1,4 +1,4 @@ -# script for Cypress PSoC 41xx/42xx family +# script for Cypress PSoC 4 devices # # PSoC 4 devices support SWD transports only. @@ -53,8 +53,14 @@ adapter_khz 1500 # set in time frame 400 usec delayed about 1 msec from reset. # # OpenOCD have no standard way how to set TEST_MODE in specified time frame. -# TEST_MODE flag is set before reset instead. It worked for tested chips -# despite it is not guaranteed by specification. +# As a workaround the TEST_MODE flag is set before reset instead. +# It worked for the oldest family PSoC4100/4200 even though it is not guaranteed +# by specification. +# +# Newer families like PSoC 4000, 4100M, 4200M, 4100L, 4200L and PSoC 4 BLE +# clear TEST_MODE flag during device reset so workaround is not possible. +# Use a KitProg adapter for theese devices or "reset halt" will not stop +# before executing user code. # # 3) SWD cannot be connected during system initialization after reset. # This might be a reason for unconnecting ST-Link v2 when deasserting reset. @@ -66,11 +72,34 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } -proc ocd_process_reset_inner { MODE } { - if { 0 != [string compare psoc4.cpu [target names]] } { - return -code error "PSoC 4 reset can handle only one psoc4.cpu target"; +proc psoc4_get_family_id {} { + set err [catch "mem2array romtable_pid 32 0xF0000FE0 3"] + if { $err } { + return 0 } - set t psoc4.cpu + if { [expr $romtable_pid(0) & 0xffffff00 ] + || [expr $romtable_pid(1) & 0xffffff00 ] + || [expr $romtable_pid(2) & 0xffffff00 ] } { + echo "Unexpected data in ROMTABLE" + return 0 + } + set designer_id [expr (( $romtable_pid(1) & 0xf0 ) >> 4) | (( $romtable_pid(2) & 0xf ) << 4 ) ] + if { $designer_id != 0xb4 } { + echo [format "ROMTABLE Designer ID 0x%02x is not Cypress" $designer_id] + return 0 + } + set family_id [expr ( $romtable_pid(0) & 0xff ) | (( $romtable_pid(1) & 0xf ) << 8 ) ] + return $family_id +} + +proc ocd_process_reset_inner { MODE } { + global PSOC4_USE_ACQUIRE PSOC4_TEST_MODE_WORKAROUND + global _TARGETNAME + + if { 0 != [string compare $_TARGETNAME [target names]] } { + return -code error "PSoC 4 reset can handle only one $_TARGETNAME target"; + } + set t $_TARGETNAME # If this target must be halted... set halt -1 @@ -87,17 +116,42 @@ proc ocd_process_reset_inner { MODE } { return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; } + if { ! [info exists PSOC4_USE_ACQUIRE] } { + if { 0 == [string compare [adapter_name] kitprog ] } { + set PSOC4_USE_ACQUIRE 1 + } else { + set PSOC4_USE_ACQUIRE 0 + } + } + if { $PSOC4_USE_ACQUIRE } { + set PSOC4_TEST_MODE_WORKAROUND 0 + } elseif { ! [info exists PSOC4_TEST_MODE_WORKAROUND] } { + if { [psoc4_get_family_id] == 0x93 } { + set PSOC4_TEST_MODE_WORKAROUND 1 + } else { + set PSOC4_TEST_MODE_WORKAROUND 0 + } + } + #$t invoke-event reset-start $t invoke-event reset-assert-pre - set TEST_MODE 0x40030014 - if { $halt == 1 } { - mww $TEST_MODE 0x80000000 + if { $halt && $PSOC4_USE_ACQUIRE } { + catch { [adapter_name] acquire_psoc } + $t arp_examine } else { - mww $TEST_MODE 0 + if { $PSOC4_TEST_MODE_WORKAROUND } { + set TEST_MODE 0x40030014 + if { $halt == 1 } { + catch { mww $TEST_MODE 0x80000000 } + } else { + catch { mww $TEST_MODE 0 } + } + } + + $t arp_reset assert 0 } - $t arp_reset assert 0 $t invoke-event reset-assert-post $t invoke-event reset-deassert-pre if {![using_hla]} { # workaround ST-Link v2 fails and forcing reconnect @@ -127,7 +181,14 @@ proc ocd_process_reset_inner { MODE } { set pc [ocd_reg pc] regsub {pc[^:]*: } $pc "" pc if { $pc < 0x10000000 || $pc > 0x1000ffff } { - return -code error [format "TARGET: %s - Not halted in system ROM, use 'reset_config none'" $t] + set hint "" + set family_id [psoc4_get_family_id] + if { $family_id == 0x93 } { + set hint ", use 'reset_config none'" + } elseif { $family_id > 0x93 } { + set hint ", use a KitProg adapter" + } + return -code error [format "TARGET: %s - Not halted in system ROM%s" $t $hint] } # Set registers to reset vector values @@ -135,7 +196,9 @@ proc ocd_process_reset_inner { MODE } { reg pc [expr $value(1) & 0xfffffffe ] reg msp $value(0) - mww $TEST_MODE 0 + if { $PSOC4_TEST_MODE_WORKAROUND } { + catch { mww $TEST_MODE 0 } + } } #Pass 2 - if needed "init" From 445dc23eb51bc2d7f4466392d36d40fcecf54f65 Mon Sep 17 00:00:00 2001 From: Andreas Bolsch Date: Sat, 28 Oct 2017 19:39:35 +0200 Subject: [PATCH 06/91] Handle improperly build image files gracefully Images build improperly (by simply concatenating separate images) were accepted, but anything after the first end-of-file record *silently* ignored. Now emit warning for intel and motorola images upon non-whitespace after first end-of-file record but continue reading anyway. ST ships some images broken that way in their CubeMX packages ... Change-Id: I0c5d08fa90070fed11fb805c5f0dc39817048176 Signed-off-by: Andreas Bolsch Reviewed-on: http://openocd.zylin.com/4281 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Tomas Vanek --- src/helper/fileio.c | 5 + src/helper/fileio.h | 1 + src/target/image.c | 559 +++++++++++++++++++++++--------------------- 3 files changed, 303 insertions(+), 262 deletions(-) diff --git a/src/helper/fileio.c b/src/helper/fileio.c index 47494dfcd..9dd57e72a 100644 --- a/src/helper/fileio.c +++ b/src/helper/fileio.c @@ -153,6 +153,11 @@ int fileio_close(struct fileio *fileio) return retval; } +int fileio_feof(struct fileio *fileio) +{ + return feof(fileio->file); +} + int fileio_seek(struct fileio *fileio, size_t position) { int retval; diff --git a/src/helper/fileio.h b/src/helper/fileio.h index ae4a3ecfc..02592e28d 100644 --- a/src/helper/fileio.h +++ b/src/helper/fileio.h @@ -46,6 +46,7 @@ struct fileio; int fileio_open(struct fileio **fileio, const char *url, enum fileio_access access_type, enum fileio_type type); int fileio_close(struct fileio *fileio); +int fileio_feof(struct fileio *fileio); int fileio_seek(struct fileio *fileio, size_t position); int fileio_fgets(struct fileio *fileio, size_t size, void *buffer); diff --git a/src/target/image.c b/src/target/image.c index f97d90403..9f56bea04 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -121,8 +121,9 @@ static int image_ihex_buffer_complete_inner(struct image *image, { struct image_ihex *ihex = image->type_private; struct fileio *fileio = ihex->fileio; - uint32_t full_address = 0x0; + uint32_t full_address; uint32_t cooked_bytes; + bool end_rec = false; int i; /* we can't determine the number of sections that we'll have to create ahead of time, @@ -137,175 +138,190 @@ static int image_ihex_buffer_complete_inner(struct image *image, ihex->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; - section[image->num_sections].private = &ihex->buffer[cooked_bytes]; - section[image->num_sections].base_address = 0x0; - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { - uint32_t count; - uint32_t address; - uint32_t record_type; - uint32_t checksum; - uint8_t cal_checksum = 0; - size_t bytes_read = 0; + while (!fileio_feof(fileio)) { + full_address = 0x0; + section[image->num_sections].private = &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = 0x0; + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; - if (lpszLine[0] == '#') - continue; + while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { + uint32_t count; + uint32_t address; + uint32_t record_type; + uint32_t checksum; + uint8_t cal_checksum = 0; + size_t bytes_read = 0; - if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, - &address, &record_type) != 3) - return ERROR_IMAGE_FORMAT_ERROR; - bytes_read += 9; + /* skip comments and blank lines */ + if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0)) + continue; - cal_checksum += (uint8_t)count; - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - cal_checksum += (uint8_t)record_type; + if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, + &address, &record_type) != 3) + return ERROR_IMAGE_FORMAT_ERROR; + bytes_read += 9; - if (record_type == 0) { /* Data Record */ - if ((full_address & 0xffff) != address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - if (image->num_sections >= IMAGE_MAX_SECTIONS) { - /* too many sections */ - LOG_ERROR("Too many sections found in IHEX file"); - return ERROR_IMAGE_FORMAT_ERROR; + cal_checksum += (uint8_t)count; + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + cal_checksum += (uint8_t)record_type; + + if (record_type == 0) { /* Data Record */ + if ((full_address & 0xffff) != address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + if (image->num_sections >= IMAGE_MAX_SECTIONS) { + /* too many sections */ + LOG_ERROR("Too many sections found in IHEX file"); + return ERROR_IMAGE_FORMAT_ERROR; + } + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &ihex->buffer[cooked_bytes]; } - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = + (full_address & 0xffff0000) | address; + full_address = (full_address & 0xffff0000) | address; } - section[image->num_sections].base_address = - (full_address & 0xffff0000) | address; - full_address = (full_address & 0xffff0000) | address; - } - while (count-- > 0) { - unsigned value; - sscanf(&lpszLine[bytes_read], "%2x", &value); - ihex->buffer[cooked_bytes] = (uint8_t)value; - cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; - bytes_read += 2; - cooked_bytes += 1; - section[image->num_sections].size += 1; - full_address++; - } - } else if (record_type == 1) { /* End of File Record */ - /* finish the current section */ - image->num_sections++; + while (count-- > 0) { + unsigned value; + sscanf(&lpszLine[bytes_read], "%2x", &value); + ihex->buffer[cooked_bytes] = (uint8_t)value; + cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; + bytes_read += 2; + cooked_bytes += 1; + section[image->num_sections].size += 1; + full_address++; + } + } else if (record_type == 1) { /* End of File Record */ + /* finish the current section */ + image->num_sections++; - /* copy section information */ - image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { - image->sections[i].private = section[i].private; - image->sections[i].base_address = section[i].base_address; - image->sections[i].size = section[i].size; - image->sections[i].flags = section[i].flags; - } + /* copy section information */ + image->sections = malloc(sizeof(struct imagesection) * image->num_sections); + for (i = 0; i < image->num_sections; i++) { + image->sections[i].private = section[i].private; + image->sections[i].base_address = section[i].base_address; + image->sections[i].size = section[i].size; + image->sections[i].flags = section[i].flags; + } - return ERROR_OK; - } else if (record_type == 2) { /* Linear Address Record */ - uint16_t upper_address; + end_rec = true; + break; + } else if (record_type == 2) { /* Linear Address Record */ + uint16_t upper_address; - sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); - cal_checksum += (uint8_t)(upper_address >> 8); - cal_checksum += (uint8_t)upper_address; - bytes_read += 4; + sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); + cal_checksum += (uint8_t)(upper_address >> 8); + cal_checksum += (uint8_t)upper_address; + bytes_read += 4; - if ((full_address >> 4) != upper_address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - if (image->num_sections >= IMAGE_MAX_SECTIONS) { - /* too many sections */ - LOG_ERROR("Too many sections found in IHEX file"); - return ERROR_IMAGE_FORMAT_ERROR; + if ((full_address >> 4) != upper_address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + if (image->num_sections >= IMAGE_MAX_SECTIONS) { + /* too many sections */ + LOG_ERROR("Too many sections found in IHEX file"); + return ERROR_IMAGE_FORMAT_ERROR; + } + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &ihex->buffer[cooked_bytes]; } - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = + (full_address & 0xffff) | (upper_address << 4); + full_address = (full_address & 0xffff) | (upper_address << 4); } - section[image->num_sections].base_address = - (full_address & 0xffff) | (upper_address << 4); - full_address = (full_address & 0xffff) | (upper_address << 4); - } - } else if (record_type == 3) { /* Start Segment Address Record */ - uint32_t dummy; + } else if (record_type == 3) { /* Start Segment Address Record */ + uint32_t dummy; - /* "Start Segment Address Record" will not be supported - * but we must consume it, and do not create an error. */ - while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); - cal_checksum += (uint8_t)dummy; - bytes_read += 2; - } - } else if (record_type == 4) { /* Extended Linear Address Record */ - uint16_t upper_address; + /* "Start Segment Address Record" will not be supported + * but we must consume it, and do not create an error. */ + while (count-- > 0) { + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); + cal_checksum += (uint8_t)dummy; + bytes_read += 2; + } + } else if (record_type == 4) { /* Extended Linear Address Record */ + uint16_t upper_address; - sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); - cal_checksum += (uint8_t)(upper_address >> 8); - cal_checksum += (uint8_t)upper_address; - bytes_read += 4; + sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); + cal_checksum += (uint8_t)(upper_address >> 8); + cal_checksum += (uint8_t)upper_address; + bytes_read += 4; - if ((full_address >> 16) != upper_address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - if (image->num_sections >= IMAGE_MAX_SECTIONS) { - /* too many sections */ - LOG_ERROR("Too many sections found in IHEX file"); - return ERROR_IMAGE_FORMAT_ERROR; + if ((full_address >> 16) != upper_address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + if (image->num_sections >= IMAGE_MAX_SECTIONS) { + /* too many sections */ + LOG_ERROR("Too many sections found in IHEX file"); + return ERROR_IMAGE_FORMAT_ERROR; + } + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &ihex->buffer[cooked_bytes]; } - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &ihex->buffer[cooked_bytes]; + section[image->num_sections].base_address = + (full_address & 0xffff) | (upper_address << 16); + full_address = (full_address & 0xffff) | (upper_address << 16); } - section[image->num_sections].base_address = - (full_address & 0xffff) | (upper_address << 16); - full_address = (full_address & 0xffff) | (upper_address << 16); + } else if (record_type == 5) { /* Start Linear Address Record */ + uint32_t start_address; + + sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address); + cal_checksum += (uint8_t)(start_address >> 24); + cal_checksum += (uint8_t)(start_address >> 16); + cal_checksum += (uint8_t)(start_address >> 8); + cal_checksum += (uint8_t)start_address; + bytes_read += 8; + + image->start_address_set = 1; + image->start_address = be_to_h_u32((uint8_t *)&start_address); + } else { + LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); + return ERROR_IMAGE_FORMAT_ERROR; } - } else if (record_type == 5) { /* Start Linear Address Record */ - uint32_t start_address; - sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address); - cal_checksum += (uint8_t)(start_address >> 24); - cal_checksum += (uint8_t)(start_address >> 16); - cal_checksum += (uint8_t)(start_address >> 8); - cal_checksum += (uint8_t)start_address; - bytes_read += 8; + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); - image->start_address_set = 1; - image->start_address = be_to_h_u32((uint8_t *)&start_address); - } else { - LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); - return ERROR_IMAGE_FORMAT_ERROR; - } + if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) { + /* checksum failed */ + LOG_ERROR("incorrect record checksum found in IHEX file"); + return ERROR_IMAGE_CHECKSUM; + } - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); - - if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) { - /* checksum failed */ - LOG_ERROR("incorrect record checksum found in IHEX file"); - return ERROR_IMAGE_CHECKSUM; + if (end_rec) { + end_rec = false; + LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine); + } } } - LOG_ERROR("premature end of IHEX file, no end-of-file record found"); - return ERROR_IMAGE_FORMAT_ERROR; + if (end_rec) + return ERROR_OK; + else { + LOG_ERROR("premature end of IHEX file, no matching end-of-file record found"); + return ERROR_IMAGE_FORMAT_ERROR; + } } /** @@ -510,8 +526,9 @@ static int image_mot_buffer_complete_inner(struct image *image, { struct image_mot *mot = image->type_private; struct fileio *fileio = mot->fileio; - uint32_t full_address = 0x0; + uint32_t full_address; uint32_t cooked_bytes; + bool end_rec = false; int i; /* we can't determine the number of sections that we'll have to create ahead of time, @@ -526,140 +543,158 @@ static int image_mot_buffer_complete_inner(struct image *image, mot->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; - section[image->num_sections].private = &mot->buffer[cooked_bytes]; - section[image->num_sections].base_address = 0x0; - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { - uint32_t count; - uint32_t address; - uint32_t record_type; - uint32_t checksum; - uint8_t cal_checksum = 0; - uint32_t bytes_read = 0; + while (!fileio_feof(fileio)) { + full_address = 0x0; + section[image->num_sections].private = &mot->buffer[cooked_bytes]; + section[image->num_sections].base_address = 0x0; + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; - /* get record type and record length */ - if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, - &count) != 2) - return ERROR_IMAGE_FORMAT_ERROR; + while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { + uint32_t count; + uint32_t address; + uint32_t record_type; + uint32_t checksum; + uint8_t cal_checksum = 0; + uint32_t bytes_read = 0; - bytes_read += 4; - cal_checksum += (uint8_t)count; + /* skip comments and blank lines */ + if ((lpszLine[0] == '#') || (strlen(lpszLine + strspn(lpszLine, "\n\t\r ")) == 0)) + continue; - /* skip checksum byte */ - count -= 1; + /* get record type and record length */ + if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, + &count) != 2) + return ERROR_IMAGE_FORMAT_ERROR; - if (record_type == 0) { - /* S0 - starting record (optional) */ - int iValue; + bytes_read += 4; + cal_checksum += (uint8_t)count; - while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2x", &iValue); - cal_checksum += (uint8_t)iValue; - bytes_read += 2; - } - } else if (record_type >= 1 && record_type <= 3) { - switch (record_type) { - case 1: - /* S1 - 16 bit address data record */ - sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 4; - count -= 2; - break; + /* skip checksum byte */ + count -= 1; - case 2: - /* S2 - 24 bit address data record */ - sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 16); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 6; - count -= 3; - break; + if (record_type == 0) { + /* S0 - starting record (optional) */ + int iValue; - case 3: - /* S3 - 32 bit address data record */ - sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 24); - cal_checksum += (uint8_t)(address >> 16); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 8; - count -= 4; - break; - - } - - if (full_address != address) { - /* we encountered a nonconsecutive location, create a new section, - * unless the current section has zero size, in which case this specifies - * the current section's base address - */ - if (section[image->num_sections].size != 0) { - image->num_sections++; - section[image->num_sections].size = 0x0; - section[image->num_sections].flags = 0; - section[image->num_sections].private = - &mot->buffer[cooked_bytes]; + while (count-- > 0) { + sscanf(&lpszLine[bytes_read], "%2x", &iValue); + cal_checksum += (uint8_t)iValue; + bytes_read += 2; } - section[image->num_sections].base_address = address; - full_address = address; + } else if (record_type >= 1 && record_type <= 3) { + switch (record_type) { + case 1: + /* S1 - 16 bit address data record */ + sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 4; + count -= 2; + break; + + case 2: + /* S2 - 24 bit address data record */ + sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 16); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 6; + count -= 3; + break; + + case 3: + /* S3 - 32 bit address data record */ + sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 24); + cal_checksum += (uint8_t)(address >> 16); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 8; + count -= 4; + break; + + } + + if (full_address != address) { + /* we encountered a nonconsecutive location, create a new section, + * unless the current section has zero size, in which case this specifies + * the current section's base address + */ + if (section[image->num_sections].size != 0) { + image->num_sections++; + section[image->num_sections].size = 0x0; + section[image->num_sections].flags = 0; + section[image->num_sections].private = + &mot->buffer[cooked_bytes]; + } + section[image->num_sections].base_address = address; + full_address = address; + } + + while (count-- > 0) { + unsigned value; + sscanf(&lpszLine[bytes_read], "%2x", &value); + mot->buffer[cooked_bytes] = (uint8_t)value; + cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; + bytes_read += 2; + cooked_bytes += 1; + section[image->num_sections].size += 1; + full_address++; + } + } else if (record_type == 5) { + /* S5 is the data count record, we ignore it */ + uint32_t dummy; + + while (count-- > 0) { + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); + cal_checksum += (uint8_t)dummy; + bytes_read += 2; + } + } else if (record_type >= 7 && record_type <= 9) { + /* S7, S8, S9 - ending records for 32, 24 and 16bit */ + image->num_sections++; + + /* copy section information */ + image->sections = malloc(sizeof(struct imagesection) * image->num_sections); + for (i = 0; i < image->num_sections; i++) { + image->sections[i].private = section[i].private; + image->sections[i].base_address = section[i].base_address; + image->sections[i].size = section[i].size; + image->sections[i].flags = section[i].flags; + } + + end_rec = true; + break; + } else { + LOG_ERROR("unhandled S19 record type: %i", (int)(record_type)); + return ERROR_IMAGE_FORMAT_ERROR; } - while (count-- > 0) { - unsigned value; - sscanf(&lpszLine[bytes_read], "%2x", &value); - mot->buffer[cooked_bytes] = (uint8_t)value; - cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; - bytes_read += 2; - cooked_bytes += 1; - section[image->num_sections].size += 1; - full_address++; - } - } else if (record_type == 5) { - /* S5 is the data count record, we ignore it */ - uint32_t dummy; + /* account for checksum, will always be 0xFF */ + sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); + cal_checksum += (uint8_t)checksum; - while (count-- > 0) { - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); - cal_checksum += (uint8_t)dummy; - bytes_read += 2; - } - } else if (record_type >= 7 && record_type <= 9) { - /* S7, S8, S9 - ending records for 32, 24 and 16bit */ - image->num_sections++; - - /* copy section information */ - image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { - image->sections[i].private = section[i].private; - image->sections[i].base_address = section[i].base_address; - image->sections[i].size = section[i].size; - image->sections[i].flags = section[i].flags; + if (cal_checksum != 0xFF) { + /* checksum failed */ + LOG_ERROR("incorrect record checksum found in S19 file"); + return ERROR_IMAGE_CHECKSUM; } - return ERROR_OK; - } else { - LOG_ERROR("unhandled S19 record type: %i", (int)(record_type)); - return ERROR_IMAGE_FORMAT_ERROR; - } - - /* account for checksum, will always be 0xFF */ - sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); - cal_checksum += (uint8_t)checksum; - - if (cal_checksum != 0xFF) { - /* checksum failed */ - LOG_ERROR("incorrect record checksum found in S19 file"); - return ERROR_IMAGE_CHECKSUM; + if (end_rec) { + end_rec = false; + LOG_WARNING("continuing after end-of-file record: %.40s", lpszLine); + } } } - LOG_ERROR("premature end of S19 file, no end-of-file record found"); - return ERROR_IMAGE_FORMAT_ERROR; + if (end_rec) + return ERROR_OK; + else { + LOG_ERROR("premature end of S19 file, no matching end-of-file record found"); + return ERROR_IMAGE_FORMAT_ERROR; + } } /** From e9f54db0033ad1f98a5a8e8168113e74a2d21ee8 Mon Sep 17 00:00:00 2001 From: Bohdan Tymkiv Date: Mon, 25 Sep 2017 14:25:22 +0300 Subject: [PATCH 07/91] Add support for Cypress PSoC6 family of devices * Tested on CY8CKIT-001 kit with PSoC6 daughter board. * Tested with several J-Link adapters (Ultra+, Basic) Change-Id: I0a818c231e5f0b270c7774037b38d23221d59417 Signed-off-by: Bohdan Tymkiv Reviewed-on: http://openocd.zylin.com/4233 Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 56 +++ src/flash/nor/Makefile.am | 1 + src/flash/nor/drivers.c | 2 + src/flash/nor/psoc6.c | 985 ++++++++++++++++++++++++++++++++++++++ tcl/target/psoc6.cfg | 134 ++++++ 5 files changed, 1178 insertions(+) create mode 100644 src/flash/nor/psoc6.c create mode 100644 tcl/target/psoc6.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 898ffb948..a6f220f46 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5891,6 +5891,62 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn +@deffn {Flash Driver} psoc6 +Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers. +PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share +the same Flash/RAM/MMIO address space. + +Flash in PSoC6 is split into three regions: +@itemize @bullet +@item Main Flash - this is the main storage for user application. +Total size varies among devices, sector size: 256 kBytes, row size: +512 bytes. Supports erase operation on individual rows. +@item Work Flash - intended to be used as storage for user data +(e.g. EEPROM emulation). Total size: 32 KBytes, sector size: 32 KBytes, +row size: 512 bytes. +@item Supervisory Flash - special region which contains device-specific +service data. This region does not support erase operation. Only few rows can +be programmed by the user, most of the rows are read only. Programming +operation will erase row automatically. +@end itemize + +All three flash regions are supported by the driver. Flash geometry is detected +automatically by parsing data in SPCIF_GEOMETRY register. + +PSoC6 is equipped with NOR Flash so erased Flash reads as 0x00. + +@example +flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 $@{TARGET@}.cm0 +flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 $@{TARGET@}.cm0 +flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 $@{TARGET@}.cm0 + +flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 $@{TARGET@}.cm4 +flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 $@{TARGET@}.cm4 +flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 $@{TARGET@}.cm4 +@end example + +psoc6-specific commands +@deffn Command {psoc6 reset_halt} +Command can be used to simulate broken Vector Catch from gdbinit or tcl scripts. +When invoked for CM0+ target, it will set break point at application entry point +and issue SYSRESETREQ. This will reset both cores and all peripherals. CM0+ will +reset CM4 during boot anyway so this is safe. On CM4 target, VECTRESET is used +instead of SYSRESETREQ to avoid unwanted reset of CM0+; +@end deffn + +@deffn Command {psoc6 mass_erase} num +Erases the contents given flash bank. The @var{num} parameter is a value shown +by @command{flash banks}. +Note: only Main and Work flash regions support Erase operation. +@end deffn +@end deffn + @deffn {Flash Driver} sim3x All members of the SiM3 microcontroller family from Silicon Laboratories include internal flash and use ARM Cortex-M3 cores. It supports both JTAG diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 6dc61e62f..4b74a4682 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -41,6 +41,7 @@ NOR_DRIVERS = \ %D%/ocl.c \ %D%/pic32mx.c \ %D%/psoc4.c \ + %D%/psoc6.c \ %D%/sim3x.c \ %D%/spi.c \ %D%/stmsmi.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3b055d19a..0e6a7382e 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -54,6 +54,7 @@ extern struct flash_driver numicro_flash; extern struct flash_driver ocl_flash; extern struct flash_driver pic32mx_flash; extern struct flash_driver psoc4_flash; +extern struct flash_driver psoc6_flash; extern struct flash_driver sim3x_flash; extern struct flash_driver stellaris_flash; extern struct flash_driver stm32f1x_flash; @@ -110,6 +111,7 @@ static struct flash_driver *flash_drivers[] = { &ocl_flash, &pic32mx_flash, &psoc4_flash, + &psoc6_flash, &sim3x_flash, &stellaris_flash, &stm32f1x_flash, diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c new file mode 100644 index 000000000..259d6679d --- /dev/null +++ b/src/flash/nor/psoc6.c @@ -0,0 +1,985 @@ +/*************************************************************************** + * * + * Copyright (C) 2017 by Bohdan Tymkiv * + * bohdan.tymkiv@cypress.com bohdan200@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "imp.h" +#include "target/target.h" +#include "target/cortex_m.h" +#include "target/breakpoints.h" +#include "target/target_type.h" +#include "time_support.h" +#include "target/algorithm.h" + +/************************************************************************************************** + * PSoC6 device definitions + *************************************************************************************************/ +#define MFLASH_SECTOR_SIZE (256u * 1024u) +#define WFLASH_SECTOR_SIZE (32u * 1024u) + +#define MEM_BASE_MFLASH 0x10000000u +#define MEM_BASE_WFLASH 0x14000000u +#define MEM_WFLASH_SIZE 32768u +#define MEM_BASE_SFLASH 0x16000000u +#define RAM_STACK_WA_SIZE 2048u +#define PSOC6_SPCIF_GEOMETRY 0x4025F00Cu + +#define PROTECTION_UNKNOWN 0x00u +#define PROTECTION_VIRGIN 0x01u +#define PROTECTION_NORMAL 0x02u +#define PROTECTION_SECURE 0x03u +#define PROTECTION_DEAD 0x04u + +#define MEM_BASE_IPC 0x40230000u +#define IPC_STRUCT_SIZE 0x20u +#define MEM_IPC(n) (MEM_BASE_IPC + (n) * IPC_STRUCT_SIZE) +#define MEM_IPC_ACQUIRE(n) (MEM_IPC(n) + 0x00u) +#define MEM_IPC_NOTIFY(n) (MEM_IPC(n) + 0x08u) +#define MEM_IPC_DATA(n) (MEM_IPC(n) + 0x0Cu) +#define MEM_IPC_LOCK_STATUS(n) (MEM_IPC(n) + 0x10u) + +#define MEM_BASE_IPC_INTR 0x40231000u +#define IPC_INTR_STRUCT_SIZE 0x20u +#define MEM_IPC_INTR(n) (MEM_BASE_IPC_INTR + (n) * IPC_INTR_STRUCT_SIZE) +#define MEM_IPC_INTR_MASK(n) (MEM_IPC_INTR(n) + 0x08u) +#define IPC_ACQUIRE_SUCCESS_MSK 0x80000000u +#define IPC_LOCK_ACQUIRED_MSK 0x80000000u + +#define IPC_ID 2u +#define IPC_INTR_ID 0u +#define IPC_TIMEOUT_MS 1000 + +#define SROMAPI_SIID_REQ 0x00000001u +#define SROMAPI_SIID_REQ_FAMILY_REVISION (SROMAPI_SIID_REQ | 0x000u) +#define SROMAPI_SIID_REQ_SIID_PROTECTION (SROMAPI_SIID_REQ | 0x100u) +#define SROMAPI_WRITEROW_REQ 0x05000100u +#define SROMAPI_PROGRAMROW_REQ 0x06000100u +#define SROMAPI_ERASESECTOR_REQ 0x14000100u +#define SROMAPI_ERASEALL_REQ 0x0A000100u +#define SROMAPI_ERASEROW_REQ 0x1C000100u + +#define SROMAPI_STATUS_MSK 0xF0000000u +#define SROMAPI_STAT_SUCCESS 0xA0000000u +#define SROMAPI_DATA_LOCATION_MSK 0x00000001u +#define SROMAPI_CALL_TIMEOUT_MS 1500 + +struct psoc6_target_info { + uint32_t silicon_id; + uint8_t protection; + uint32_t main_flash_sz; + uint32_t row_sz; + bool is_probed; +}; + +struct timeout { + int64_t start_time; + long timeout_ms; +}; + +struct row_region { + uint32_t addr; + size_t size; +}; + +static struct row_region safe_sflash_regions[] = { + {0x16000800, 0x800}, /* SFLASH: User Data */ + {0x16001A00, 0x200}, /* SFLASH: NAR */ + {0x16005A00, 0xC00}, /* SFLASH: Public Key */ + {0x16007C00, 0x400}, /* SFLASH: TOC2 */ +}; + +#define SFLASH_NUM_REGIONS (sizeof(safe_sflash_regions) / sizeof(safe_sflash_regions[0])) + +static struct working_area *g_stack_area; +/************************************************************************************************** + * Initializes timeout_s structure with given timeout in milliseconds + *************************************************************************************************/ +static void timeout_init(struct timeout *to, long timeout_ms) +{ + to->start_time = timeval_ms(); + to->timeout_ms = timeout_ms; +} + +/************************************************************************************************** + * Returns true if given timeout_s object has expired + *************************************************************************************************/ +static bool timeout_expired(struct timeout *to) +{ + return (timeval_ms() - to->start_time) > to->timeout_ms; +} + +/************************************************************************************************** + * Prepares PSoC6 for running pseudo flash algorithm. This function allocates Working Area for + * the algorithm and for CPU Stack. + *************************************************************************************************/ +static int sromalgo_prepare(struct target *target) +{ + int hr; + + /* Initialize Vector Table Offset register (in case FW modified it) */ + hr = target_write_u32(target, 0xE000ED08, 0x00000000); + if (hr != ERROR_OK) + return hr; + + /* Allocate Working Area for Stack and Flash algorithm */ + hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area); + if (hr != ERROR_OK) + return hr; + + /* Restore THUMB bit in xPSR register */ + const struct armv7m_common *cm = target_to_armv7m(target); + hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000); + if (hr != ERROR_OK) + goto exit_free_wa; + + return ERROR_OK; + +exit_free_wa: + /* Something went wrong, free allocated area */ + if (g_stack_area) { + target_free_working_area(target, g_stack_area); + g_stack_area = NULL; + } + + return hr; +} + +/************************************************************************************************** + * Releases working area + *************************************************************************************************/ +static int sromalgo_release(struct target *target) +{ + int hr = ERROR_OK; + + /* Free Stack/Flash algorithm working area */ + if (g_stack_area) { + hr = target_free_working_area(target, g_stack_area); + g_stack_area = NULL; + } + + return hr; +} + +/************************************************************************************************** + * Runs pseudo flash algorithm. Algorithm itself consist of couple of NOPs followed by BKPT + * instruction. The trick here is that NMI has already been posted to CM0 via IPC structure + * prior to calling this function. CM0 will immediately jump to NMI handler and execute + * SROM API code. + * This approach is borrowed from PSoC4 Flash Driver. + *************************************************************************************************/ +static int sromalgo_run(struct target *target) +{ + int hr; + + struct armv7m_algorithm armv7m_info; + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + struct reg_param reg_params; + init_reg_param(®_params, "sp", 32, PARAM_OUT); + buf_set_u32(reg_params.value, 0, 32, g_stack_area->address + g_stack_area->size); + + /* mov r8, r8; mov r8, r8 */ + hr = target_write_u32(target, g_stack_area->address + 0, 0x46C046C0); + if (hr != ERROR_OK) + return hr; + + /* mov r8, r8; bkpt #0 */ + hr = target_write_u32(target, g_stack_area->address + 4, 0xBE0046C0); + if (hr != ERROR_OK) + return hr; + + hr = target_run_algorithm(target, 0, NULL, 1, ®_params, g_stack_area->address, + 0, SROMAPI_CALL_TIMEOUT_MS, &armv7m_info); + + destroy_reg_param(®_params); + + return hr; +} + +/************************************************************************************************** + * Waits for expected IPC lock status. + * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API. + * IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the + * system will use same IPC thus corrupting our data. Locking is performed by ipc_acquire(), this + * function ensures that IPC is actually in expected state + *************************************************************************************************/ +static int ipc_poll_lock_stat(struct target *target, uint32_t ipc_id, bool lock_expected) +{ + int hr; + uint32_t reg_val; + + struct timeout to; + timeout_init(&to, IPC_TIMEOUT_MS); + + while (!timeout_expired(&to)) { + /* Process any server requests */ + keep_alive(); + + /* Read IPC Lock status */ + hr = target_read_u32(target, MEM_IPC_LOCK_STATUS(ipc_id), ®_val); + if (hr != ERROR_OK) { + LOG_ERROR("Unable to read IPC Lock Status register"); + return hr; + } + + bool is_locked = (reg_val & IPC_LOCK_ACQUIRED_MSK) != 0; + + if (lock_expected == is_locked) + return ERROR_OK; + } + + if (target->coreid) { + LOG_WARNING("SROM API calls via CM4 target are supported on single-core PSoC6 devices only. " + "Please perform all Flash-related operations via CM0+ target on dual-core devices."); + } + + LOG_ERROR("Timeout polling IPC Lock Status"); + return ERROR_TARGET_TIMEOUT; +} + +/************************************************************************************************** + * Acquires IPC structure + * PSoC6 uses IPC structures for inter-core communication. Same IPCs are used to invoke SROM API. + * IPC structure must be locked prior to invoking any SROM API. This ensures nothing else in the + * system will use same IPC thus corrupting our data. This function locks the IPC. + *************************************************************************************************/ +static int ipc_acquire(struct target *target, char ipc_id) +{ + int hr = ERROR_OK; + bool is_acquired = false; + uint32_t reg_val; + + struct timeout to; + timeout_init(&to, IPC_TIMEOUT_MS); + + while (!timeout_expired(&to)) { + keep_alive(); + + hr = target_write_u32(target, MEM_IPC_ACQUIRE(ipc_id), IPC_ACQUIRE_SUCCESS_MSK); + if (hr != ERROR_OK) { + LOG_ERROR("Unable to write to IPC Acquire register"); + return hr; + } + + /* Check if data is written on first step */ + hr = target_read_u32(target, MEM_IPC_ACQUIRE(ipc_id), ®_val); + if (hr != ERROR_OK) { + LOG_ERROR("Unable to read IPC Acquire register"); + return hr; + } + + is_acquired = (reg_val & IPC_ACQUIRE_SUCCESS_MSK) != 0; + if (is_acquired) { + /* If IPC structure is acquired, the lock status should be set */ + hr = ipc_poll_lock_stat(target, ipc_id, true); + break; + } + } + + if (!is_acquired) + LOG_ERROR("Timeout acquiring IPC structure"); + + return hr; +} + +/************************************************************************************************** + * Invokes SROM API functions which are responsible for Flash operations + *************************************************************************************************/ +static int call_sromapi(struct target *target, + uint32_t req_and_params, + uint32_t working_area, + uint32_t *data_out) +{ + int hr; + + bool is_data_in_ram = (req_and_params & SROMAPI_DATA_LOCATION_MSK) == 0; + + hr = ipc_acquire(target, IPC_ID); + if (hr != ERROR_OK) + return hr; + + if (is_data_in_ram) + hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), working_area); + else + hr = target_write_u32(target, MEM_IPC_DATA(IPC_ID), req_and_params); + + if (hr != ERROR_OK) + return hr; + + /* Enable notification interrupt of IPC_INTR_STRUCT0(CM0+) for IPC_STRUCT2 */ + hr = target_write_u32(target, MEM_IPC_INTR_MASK(IPC_INTR_ID), 1u << (16 + IPC_ID)); + if (hr != ERROR_OK) + return hr; + + hr = target_write_u32(target, MEM_IPC_NOTIFY(IPC_ID), 1); + if (hr != ERROR_OK) + return hr; + + hr = sromalgo_run(target); + if (hr != ERROR_OK) + return hr; + + /* Poll lock status */ + hr = ipc_poll_lock_stat(target, IPC_ID, false); + if (hr != ERROR_OK) + return hr; + + /* Poll Data byte */ + if (is_data_in_ram) + hr = target_read_u32(target, working_area, data_out); + else + hr = target_read_u32(target, MEM_IPC_DATA(IPC_ID), data_out); + + if (hr != ERROR_OK) { + LOG_ERROR("Error reading SROM API Status location"); + return hr; + } + + bool is_success = (*data_out & SROMAPI_STATUS_MSK) == SROMAPI_STAT_SUCCESS; + if (!is_success) { + LOG_ERROR("SROM API execution failed. Status: 0x%08X", (uint32_t)*data_out); + return ERROR_TARGET_FAILURE; + } + + return ERROR_OK; +} + +/************************************************************************************************** + * Retrieves SiliconID and Protection status of the target device + *************************************************************************************************/ +static int get_silicon_id(struct target *target, uint32_t *si_id, uint8_t *protection) +{ + int hr; + uint32_t family_rev, siid_prot; + + hr = sromalgo_prepare(target); + if (hr != ERROR_OK) + return hr; + + /* Read FamilyID and Revision */ + hr = call_sromapi(target, SROMAPI_SIID_REQ_FAMILY_REVISION, 0, &family_rev); + if (hr != ERROR_OK) + return hr; + + /* Read SiliconID and Protection */ + hr = call_sromapi(target, SROMAPI_SIID_REQ_SIID_PROTECTION, 0, &siid_prot); + if (hr != ERROR_OK) + return hr; + + *si_id = (siid_prot & 0x0000FFFF) << 16; + *si_id |= (family_rev & 0x00FF0000) >> 8; + *si_id |= (family_rev & 0x000000FF) >> 0; + + *protection = (siid_prot & 0x000F0000) >> 0x10; + + hr = sromalgo_release(target); + return hr; +} + +/************************************************************************************************** + * Translates Protection status to openocd-friendly boolean value + *************************************************************************************************/ +static int psoc6_protect_check(struct flash_bank *bank) +{ + int is_protected; + + struct psoc6_target_info *psoc6_info = bank->driver_priv; + int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection); + if (hr != ERROR_OK) + return hr; + + switch (psoc6_info->protection) { + case PROTECTION_VIRGIN: + case PROTECTION_NORMAL: + is_protected = 0; + break; + + case PROTECTION_UNKNOWN: + case PROTECTION_SECURE: + case PROTECTION_DEAD: + default: + is_protected = 1; + break; + } + + for (int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = is_protected; + + return ERROR_OK; +} + +/************************************************************************************************** + * Life Cycle transition is not currently supported + *************************************************************************************************/ +static int psoc6_protect(struct flash_bank *bank, int set, int first, int last) +{ + (void)bank; + (void)set; + (void)first; + (void)last; + + LOG_WARNING("Life Cycle transition for PSoC6 is not supported"); + return ERROR_OK; +} + +/************************************************************************************************** + * Translates Protection status to string + *************************************************************************************************/ +static const char *protection_to_str(uint8_t protection) +{ + switch (protection) { + case PROTECTION_VIRGIN: + return "VIRGIN"; + break; + case PROTECTION_NORMAL: + return "NORMAL"; + break; + case PROTECTION_SECURE: + return "SECURE"; + break; + case PROTECTION_DEAD: + return "DEAD"; + break; + case PROTECTION_UNKNOWN: + default: + return "UNKNOWN"; + break; + } +} + +/************************************************************************************************** + * Displays human-readable information about acquired device + *************************************************************************************************/ +static int psoc6_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct psoc6_target_info *psoc6_info = bank->driver_priv; + + if (psoc6_info->is_probed == false) + return ERROR_FAIL; + + int hr = get_silicon_id(bank->target, &psoc6_info->silicon_id, &psoc6_info->protection); + if (hr != ERROR_OK) + return hr; + + snprintf(buf, buf_size, + "PSoC6 Silicon ID: 0x%08X\n" + "Protection: %s\n" + "Main Flash size: %d kB\n" + "Work Flash size: 32 kB\n", + psoc6_info->silicon_id, + protection_to_str(psoc6_info->protection), + psoc6_info->main_flash_sz / 1024); + + return ERROR_OK; +} + +/************************************************************************************************** + * Returns true if flash bank name represents Supervisory Flash + *************************************************************************************************/ +static bool is_sflash_bank(struct flash_bank *bank) +{ + for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) { + if (bank->base == safe_sflash_regions[i].addr) + return true; + } + + return false; +} + +/************************************************************************************************** + * Returns true if flash bank name represents Work Flash + *************************************************************************************************/ +static inline bool is_wflash_bank(struct flash_bank *bank) +{ + return (bank->base == MEM_BASE_WFLASH); +} + +/************************************************************************************************** + * Returns true if flash bank name represents Main Flash + *************************************************************************************************/ +static inline bool is_mflash_bank(struct flash_bank *bank) +{ + return (bank->base == MEM_BASE_MFLASH); +} + +/************************************************************************************************** + * Probes the device and populates related data structures with target flash geometry data. + * This is done in non-intrusive way, no SROM API calls are involved so GDB can safely attach to a + * running target. + * Function assumes that size of Work Flash is 32kB (true for all current part numbers) + *************************************************************************************************/ +static int psoc6_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + + int hr = ERROR_OK; + + /* Retrieve data from SPCIF_GEOMATRY */ + uint32_t geom; + target_read_u32(target, PSOC6_SPCIF_GEOMETRY, &geom); + uint32_t row_sz_lg2 = (geom & 0xF0) >> 4; + uint32_t row_sz = (0x01 << row_sz_lg2); + uint32_t row_cnt = 1 + ((geom & 0x00FFFF00) >> 8); + uint32_t bank_cnt = 1 + ((geom & 0xFF000000) >> 24); + + /* Calculate size of Main Flash*/ + uint32_t flash_sz_bytes = bank_cnt * row_cnt * row_sz; + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + size_t bank_size = 0; + + if (is_mflash_bank(bank)) + bank_size = flash_sz_bytes; + else if (is_wflash_bank(bank)) + bank_size = MEM_WFLASH_SIZE; + else if (is_sflash_bank(bank)) { + for (size_t i = 0; i < SFLASH_NUM_REGIONS; i++) { + if (safe_sflash_regions[i].addr == bank->base) { + bank_size = safe_sflash_regions[i].size; + break; + } + } + } + + if (bank_size == 0) { + LOG_ERROR("Invalid Flash Bank base address in config file"); + return ERROR_FLASH_BANK_INVALID; + } + + size_t num_sectors = bank_size / row_sz; + bank->size = bank_size; + bank->chip_width = 4; + bank->bus_width = 4; + bank->erased_value = 0; + bank->default_padded_value = 0; + + bank->num_sectors = num_sectors; + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); + for (size_t i = 0; i < num_sectors; i++) { + bank->sectors[i].size = row_sz; + bank->sectors[i].offset = i * row_sz; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = -1; + } + + psoc6_info->is_probed = true; + psoc6_info->main_flash_sz = flash_sz_bytes; + psoc6_info->row_sz = row_sz; + + return hr; +} + +/************************************************************************************************** + * Probes target device only if it hasn't been probed yet + *************************************************************************************************/ +static int psoc6_auto_probe(struct flash_bank *bank) +{ + struct psoc6_target_info *psoc6_info = bank->driver_priv; + int hr; + + if (psoc6_info->is_probed) + hr = ERROR_OK; + else + hr = psoc6_probe(bank); + + return hr; +} + +/************************************************************************************************** + * Erases single sector (256k) on target device + *************************************************************************************************/ +static int psoc6_erase_sector(struct flash_bank *bank, struct working_area *wa, uint32_t addr) +{ + struct target *target = bank->target; + + LOG_DEBUG("Erasing SECTOR @%08X", addr); + + int hr = target_write_u32(target, wa->address, SROMAPI_ERASESECTOR_REQ); + if (hr != ERROR_OK) + return hr; + + hr = target_write_u32(target, wa->address + 0x04, addr); + if (hr != ERROR_OK) + return hr; + + uint32_t data_out; + hr = call_sromapi(target, SROMAPI_ERASESECTOR_REQ, wa->address, &data_out); + if (hr != ERROR_OK) + LOG_ERROR("SECTOR @%08X not erased!", addr); + + return hr; +} + +/************************************************************************************************** + * Erases single row (512b) on target device + *************************************************************************************************/ +static int psoc6_erase_row(struct flash_bank *bank, struct working_area *wa, uint32_t addr) +{ + struct target *target = bank->target; + + LOG_DEBUG("Erasing ROW @%08X", addr); + + int hr = target_write_u32(target, wa->address, SROMAPI_ERASEROW_REQ); + if (hr != ERROR_OK) + return hr; + + hr = target_write_u32(target, wa->address + 0x04, addr); + if (hr != ERROR_OK) + return hr; + + uint32_t data_out; + hr = call_sromapi(target, SROMAPI_ERASEROW_REQ, wa->address, &data_out); + if (hr != ERROR_OK) + LOG_ERROR("ROW @%08X not erased!", addr); + + return hr; +} + +/************************************************************************************************** + * Performs Erase operation. + * Function will try to use biggest erase block possible to speedup the operation + *************************************************************************************************/ +static int psoc6_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + const uint32_t sector_size = is_wflash_bank(bank) ? WFLASH_SECTOR_SIZE : MFLASH_SECTOR_SIZE; + + int hr; + struct working_area *wa; + + if (is_sflash_bank(bank)) { + LOG_INFO("Erase operation on Supervisory Flash is not required, skipping"); + return ERROR_OK; + } + + hr = sromalgo_prepare(target); + if (hr != ERROR_OK) + return hr; + + hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa); + if (hr != ERROR_OK) + goto exit; + + /* Number of rows in single sector */ + const int rows_in_sector = sector_size / psoc6_info->row_sz; + + while (last >= first) { + /* Erase Sector if we are on sector boundary and erase size covers whole sector */ + if ((first % rows_in_sector) == 0 && + (last - first + 1) >= rows_in_sector) { + hr = psoc6_erase_sector(bank, wa, bank->base + first * psoc6_info->row_sz); + if (hr != ERROR_OK) + goto exit_free_wa; + + for (int i = first; i < first + rows_in_sector; i++) + bank->sectors[i].is_erased = 1; + + first += rows_in_sector; + } else { + /* Perform Row Erase otherwise */ + hr = psoc6_erase_row(bank, wa, bank->base + first * psoc6_info->row_sz); + if (hr != ERROR_OK) + goto exit_free_wa; + + bank->sectors[first].is_erased = 1; + first += 1; + } + } + +exit_free_wa: + target_free_working_area(target, wa); +exit: + sromalgo_release(target); + return hr; +} + + +/************************************************************************************************** + * Programs single Flash Row + *************************************************************************************************/ +static int psoc6_program_row(struct flash_bank *bank, + uint32_t addr, + const uint8_t *buffer, + bool is_sflash) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + struct working_area *wa; + const uint32_t sromapi_req = is_sflash ? SROMAPI_WRITEROW_REQ : SROMAPI_PROGRAMROW_REQ; + uint32_t data_out; + int hr = ERROR_OK; + + LOG_DEBUG("Programming ROW @%08X", addr); + + hr = target_alloc_working_area(target, psoc6_info->row_sz + 32, &wa); + if (hr != ERROR_OK) + goto exit; + + hr = target_write_u32(target, wa->address, sromapi_req); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_u32(target, + wa->address + 0x04, + 0x106); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_u32(target, wa->address + 0x08, addr); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_u32(target, wa->address + 0x0C, wa->address + 0x10); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = target_write_buffer(target, wa->address + 0x10, psoc6_info->row_sz, buffer); + if (hr != ERROR_OK) + goto exit_free_wa; + + hr = call_sromapi(target, sromapi_req, wa->address, &data_out); + +exit_free_wa: + target_free_working_area(target, wa); + +exit: + return hr; +} + + +/************************************************************************************************** + * Programs set of Rows + *************************************************************************************************/ +static int psoc6_program(struct flash_bank *bank, + const uint8_t *buffer, + uint32_t offset, + uint32_t count) +{ + struct target *target = bank->target; + struct psoc6_target_info *psoc6_info = bank->driver_priv; + const bool is_sflash = is_sflash_bank(bank); + int hr; + + hr = sromalgo_prepare(target); + if (hr != ERROR_OK) + return hr; + + uint8_t page_buf[psoc6_info->row_sz]; + + while (count) { + uint32_t row_offset = offset % psoc6_info->row_sz; + uint32_t aligned_addr = bank->base + offset - row_offset; + uint32_t row_bytes = MIN(psoc6_info->row_sz - row_offset, count); + + memset(page_buf, 0, sizeof(page_buf)); + memcpy(&page_buf[row_offset], buffer, row_bytes); + + hr = psoc6_program_row(bank, aligned_addr, page_buf, is_sflash); + if (hr != ERROR_OK) { + LOG_ERROR("Failed to program Flash at address 0x%08X", aligned_addr); + break; + } + + buffer += row_bytes; + offset += row_bytes; + count -= row_bytes; + } + + hr = sromalgo_release(target); + return hr; +} + +/************************************************************************************************** + * Performs Mass Erase of given flash bank + * Syntax: psoc6 mass_erase bank_id + *************************************************************************************************/ +COMMAND_HANDLER(psoc6_handle_mass_erase_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int hr = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (hr != ERROR_OK) + return hr; + + hr = psoc6_erase(bank, 0, bank->num_sectors - 1); + + return hr; +} + +/************************************************************************************************** + * Simulates broken Vector Catch + * Function will try to determine entry point of user application. If it succeeds it will set HW + * breakpoint at that address, issue SW Reset and remove the breakpoint afterwards. + * In case of CM0, SYSRESETREQ is used. This allows to reset all peripherals. Boot code will + * reset CM4 anyway, so using SYSRESETREQ is safe here. + * In case of CM4, VECTRESET is used instead of SYSRESETREQ to not disturb CM0 core. + *************************************************************************************************/ +int handle_reset_halt(struct target *target) +{ + int hr; + uint32_t reset_addr; + bool is_cm0 = (target->coreid == 0); + + /* Halt target device */ + if (target->state != TARGET_HALTED) { + hr = target_halt(target); + if (hr != ERROR_OK) + return hr; + + target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS); + if (hr != ERROR_OK) + return hr; + } + + /* Read Vector Offset register */ + uint32_t vt_base; + const uint32_t vt_offset_reg = is_cm0 ? 0x402102B0 : 0x402102C0; + hr = target_read_u32(target, vt_offset_reg, &vt_base); + if (hr != ERROR_OK) + return ERROR_OK; + + /* Invalid value means flash is empty */ + vt_base &= 0xFFFFFF00; + if ((vt_base == 0) || (vt_base == 0xFFFFFF00)) + return ERROR_OK; + + /* Read Reset Vector value*/ + hr = target_read_u32(target, vt_base + 4, &reset_addr); + if (hr != ERROR_OK) + return hr; + + /* Invalid value means flash is empty */ + if ((reset_addr == 0) || (reset_addr == 0xFFFFFF00)) + return ERROR_OK; + + + /* Set breakpoint at User Application entry point */ + hr = breakpoint_add(target, reset_addr, 2, BKPT_HARD); + if (hr != ERROR_OK) + return hr; + + const struct armv7m_common *cm = target_to_armv7m(target); + + if (is_cm0) { + /* Reset the CM0 by asserting SYSRESETREQ. This will also reset CM4 */ + LOG_INFO("psoc6.cm0: bkpt @0x%08X, issuing SYSRESETREQ", reset_addr); + hr = mem_ap_write_atomic_u32(cm->debug_ap, + NVIC_AIRCR, + AIRCR_VECTKEY | AIRCR_SYSRESETREQ); + + /* Wait for bootcode and initialize DAP */ + usleep(3000); + dap_dp_init(cm->debug_ap->dap); + } else { + LOG_INFO("psoc6.cm4: bkpt @0x%08X, issuing VECTRESET", reset_addr); + hr = mem_ap_write_atomic_u32(cm->debug_ap, + NVIC_AIRCR, + AIRCR_VECTKEY | AIRCR_VECTRESET); + if (hr != ERROR_OK) + return hr; + } + + target_wait_state(target, TARGET_HALTED, IPC_TIMEOUT_MS); + + /* Remove the break point */ + breakpoint_remove(target, reset_addr); + + return hr; +} + +COMMAND_HANDLER(psoc6_handle_reset_halt) +{ + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + return handle_reset_halt(target); +} + +FLASH_BANK_COMMAND_HANDLER(psoc6_flash_bank_command) +{ + struct psoc6_target_info *psoc6_info; + int hr = ERROR_OK; + + if (CMD_ARGC < 6) + hr = ERROR_COMMAND_SYNTAX_ERROR; + else { + psoc6_info = calloc(1, sizeof(struct psoc6_target_info)); + psoc6_info->is_probed = false; + bank->driver_priv = psoc6_info; + } + return hr; +} + +static const struct command_registration psoc6_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = psoc6_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = NULL, + .help = "Erases entire Main Flash", + }, + { + .name = "reset_halt", + .handler = psoc6_handle_reset_halt, + .mode = COMMAND_EXEC, + .usage = NULL, + .help = "Tries to simulate broken Vector Catch", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration psoc6_command_handlers[] = { + { + .name = "psoc6", + .mode = COMMAND_ANY, + .help = "PSoC 6 flash command group", + .usage = "", + .chain = psoc6_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver psoc6_flash = { + .name = "psoc6", + .commands = psoc6_command_handlers, + .flash_bank_command = psoc6_flash_bank_command, + .erase = psoc6_erase, + .protect = psoc6_protect, + .write = psoc6_program, + .read = default_flash_read, + .probe = psoc6_probe, + .auto_probe = psoc6_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = psoc6_protect_check, + .info = psoc6_get_info, +}; diff --git a/tcl/target/psoc6.cfg b/tcl/target/psoc6.cfg new file mode 100644 index 000000000..d6c5a04ad --- /dev/null +++ b/tcl/target/psoc6.cfg @@ -0,0 +1,134 @@ +# +# Configuration script for Cypress PSoC6 family of microcontrollers (CY8C6xxx) +# PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share +# the same Flash/RAM/MMIO address space. +# + +source [find target/swj-dp.tcl] + +adapter_khz 1000 + +global _CHIPNAME +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME psoc6 +} + +global TARGET +set TARGET $_CHIPNAME.cpu + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf + +# Is CM0 Debugging enabled ? +global _ENABLE_CM0 +if { [info exists ENABLE_CM0] } { + set _ENABLE_CM0 $ENABLE_CM0 +} else { + set _ENABLE_CM0 1 +} + +# Is CM4 Debugging enabled ? +global _ENABLE_CM4 +if { [info exists ENABLE_CM4] } { + set _ENABLE_CM4 $ENABLE_CM4 +} else { + set _ENABLE_CM4 1 +} + +global _WORKAREASIZE_CM0 +if { [info exists WORKAREASIZE_CM0] } { + set _WORKAREASIZE_CM0 $WORKAREASIZE_CM0 +} else { + set _WORKAREASIZE_CM0 0x4000 +} + +global _WORKAREASIZE_CM4 +if { [info exists WORKAREASIZE_CM4] } { + set _WORKAREASIZE_CM4 $WORKAREASIZE_CM4 +} else { + set _WORKAREASIZE_CM4 0x4000 +} + +global _WORKAREAADDR_CM0 +if { [info exists WORKAREAADDR_CM0] } { + set _WORKAREAADDR_CM0 $WORKAREAADDR_CM0 +} else { + set _WORKAREAADDR_CM0 0x08000000 +} + +global _WORKAREAADDR_CM4 +if { [info exists WORKAREAADDR_CM4] } { + set _WORKAREAADDR_CM4 $WORKAREAADDR_CM4 +} else { + set _WORKAREAADDR_CM4 0x08000000 +} + +proc init_reset { mode } { + global RESET_MODE + set RESET_MODE $mode + + if {[using_jtag]} { + jtag arp_init-reset + } +} + +# Utility to make 'reset halt' work as reset;halt on a target +# It does not prevent running code after reset +proc psoc6_deassert_post { target } { + # PSoC6 cleared AP registers including TAR during reset + # Force examine to synchronize OpenOCD target status + $target arp_examine + + global RESET_MODE + if { $RESET_MODE ne "run" } { + $target arp_poll + $target arp_poll + set st [$target curstate] + if { $st eq "reset" } { + # we assume running state follows + # if reset accidentally halts, waiting is useless + catch { $target arp_waitstate running 100 } + set st [$target curstate] + } + if { $st eq "running" } { + echo "$target: Ran after reset and before halt..." + $target arp_halt + } + } +} + +if { $_ENABLE_CM0 } { + target create ${TARGET}.cm0 cortex_m -chain-position $TARGET -ap-num 1 -coreid 0 + ${TARGET}.cm0 configure -work-area-phys $_WORKAREAADDR_CM0 -work-area-size $_WORKAREASIZE_CM0 -work-area-backup 0 + + flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 ${TARGET}.cm0 + flash bank work_flash_cm0 psoc6 0x14000000 0 0 0 ${TARGET}.cm0 + flash bank super_flash_user_cm0 psoc6 0x16000800 0 0 0 ${TARGET}.cm0 + flash bank super_flash_nar_cm0 psoc6 0x16001A00 0 0 0 ${TARGET}.cm0 + flash bank super_flash_key_cm0 psoc6 0x16005A00 0 0 0 ${TARGET}.cm0 + flash bank super_flash_toc2_cm0 psoc6 0x16007C00 0 0 0 ${TARGET}.cm0 + + ${TARGET}.cm0 cortex_m reset_config sysresetreq + ${TARGET}.cm0 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm0" +} + +if { $_ENABLE_CM4 } { + target create ${TARGET}.cm4 cortex_m -chain-position $TARGET -ap-num 2 -coreid 1 + ${TARGET}.cm4 configure -work-area-phys $_WORKAREAADDR_CM4 -work-area-size $_WORKAREASIZE_CM4 -work-area-backup 0 + + flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 ${TARGET}.cm4 + flash bank work_flash_cm4 psoc6 0x14000000 0 0 0 ${TARGET}.cm4 + flash bank super_flash_user_cm4 psoc6 0x16000800 0 0 0 ${TARGET}.cm4 + flash bank super_flash_nar_cm4 psoc6 0x16001A00 0 0 0 ${TARGET}.cm4 + flash bank super_flash_key_cm4 psoc6 0x16005A00 0 0 0 ${TARGET}.cm4 + flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 ${TARGET}.cm4 + + ${TARGET}.cm4 cortex_m reset_config vectreset + ${TARGET}.cm4 configure -event reset-deassert-post "psoc6_deassert_post ${TARGET}.cm4" +} + +if { $_ENABLE_CM0 } { + # Use CM0+ by default on dual-core devices + targets ${TARGET}.cm0 +} From 6d390e1b2a393505b38e1d0fcd741cd0b1cf92aa Mon Sep 17 00:00:00 2001 From: Jonas Norling Date: Tue, 17 Oct 2017 08:57:06 +0200 Subject: [PATCH 08/91] efm32: Refactor EFM32 chip family data, add more chips Add support for more EFM32/EFR32 Series 1 families. The family IDs come from the DEVICE_FAMILY list in the EFM32GG11 reference manual, which is the most up to date source I could find. Register locations have been checked against SiLab's header files. No datasheets or headers were available for EFR32MG2, EFR32xG14 and EFM32TG11B, so they are just assumed to follow the pattern. EFM32GG11B has the MSC registers on a different address compared to other chips. This commit attempts not to change current behavior when detecting chips. One detail that has changed is that PAGE_SIZE is read before applying the workaround for old Giant and Leopard Gecko revisions, but this is believed to be OK because the register exists but just has an invalid value in it. The manuals disagree on which of 120 and 121 is WG, so this commit leaves it as is. Change-Id: Ia152b0b9e323defc5158cb02d9a6b04a27008f2a Signed-off-by: Jonas Norling Reviewed-on: http://openocd.zylin.com/4263 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Fredrik Hederstierna --- src/flash/nor/efm32.c | 270 +++++++++++++++++++++++------------------- 1 file changed, 145 insertions(+), 125 deletions(-) diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index b8453e1dd..282b6bddd 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -38,19 +38,8 @@ #include #include -/* keep family IDs in decimal */ -#define EFM_FAMILY_ID_GECKO 71 #define EFM_FAMILY_ID_GIANT_GECKO 72 -#define EFM_FAMILY_ID_TINY_GECKO 73 #define EFM_FAMILY_ID_LEOPARD_GECKO 74 -#define EFM_FAMILY_ID_WONDER_GECKO 75 -#define EFM_FAMILY_ID_ZERO_GECKO 76 -#define EFM_FAMILY_ID_HAPPY_GECKO 77 -#define EZR_FAMILY_ID_WONDER_GECKO 120 -#define EZR_FAMILY_ID_LEOPARD_GECKO 121 -#define EZR_FAMILY_ID_HAPPY_GECKO 122 -#define EFR_FAMILY_ID_MIGHTY_GECKO 16 -#define EFR_FAMILY_ID_BLUE_GECKO 20 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 @@ -65,7 +54,7 @@ #define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000) #define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000) -/* PAGE_SIZE is only present in Leopard, Giant and Wonder Gecko MCUs */ +/* PAGE_SIZE is not present in Zero, Happy and the original Gecko MCU */ #define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7) #define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8) #define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa) @@ -74,7 +63,7 @@ #define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) #define EFM32_MSC_REGBASE 0x400c0000 -#define EFR32_MSC_REGBASE 0x400e0000 +#define EFM32_MSC_REGBASE_SERIES1 0x400e0000 #define EFM32_MSC_REG_WRITECTRL 0x008 #define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 #define EFM32_MSC_REG_WRITECMD 0x00c @@ -91,9 +80,24 @@ #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 #define EFM32_MSC_REG_LOCK 0x03c -#define EFR32_MSC_REG_LOCK 0x040 +#define EFM32_MSC_REG_LOCK_SERIES1 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 +struct efm32_family_data { + int family_id; + const char *name; + + /* EFM32 series (EFM32LG995F is the "old" series 0, while EFR32MG12P132 + is the "new" series 1). Determines location of MSC registers. */ + int series; + + /* Page size in bytes, or 0 to read from EFM32_MSC_DI_PAGE_SIZE */ + int page_size; + + /* MSC register base address, or 0 to use default */ + uint32_t msc_regbase; +}; + struct efm32x_flash_bank { int probed; uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; @@ -102,6 +106,7 @@ struct efm32x_flash_bank { }; struct efm32_info { + const struct efm32_family_data *family_data; uint16_t flash_sz_kib; uint16_t ram_sz_kib; uint16_t part_num; @@ -110,6 +115,64 @@ struct efm32_info { uint16_t page_size; }; +static const struct efm32_family_data efm32_families[] = { + { 16, "EFR32MG1P Mighty", .series = 1 }, + { 17, "EFR32MG1B Mighty", .series = 1 }, + { 18, "EFR32MG1V Mighty", .series = 1 }, + { 19, "EFR32MG1P Blue", .series = 1 }, + { 20, "EFR32MG1B Blue", .series = 1 }, + { 21, "EFR32MG1V Blue", .series = 1 }, + { 25, "EFR32FG1P Flex", .series = 1 }, + { 26, "EFR32FG1B Flex", .series = 1 }, + { 27, "EFR32FG1V Flex", .series = 1 }, + { 28, "EFR32MG2P Mighty", .series = 1 }, + { 29, "EFR32MG2B Mighty", .series = 1 }, + { 30, "EFR32MG2V Mighty", .series = 1 }, + { 31, "EFR32BG12P Blue", .series = 1 }, + { 32, "EFR32BG12B Blue", .series = 1 }, + { 33, "EFR32BG12V Blue", .series = 1 }, + { 37, "EFR32FG12P Flex", .series = 1 }, + { 38, "EFR32FG12B Flex", .series = 1 }, + { 39, "EFR32FG12V Flex", .series = 1 }, + { 40, "EFR32MG13P Mighty", .series = 1 }, + { 41, "EFR32MG13B Mighty", .series = 1 }, + { 42, "EFR32MG13V Mighty", .series = 1 }, + { 43, "EFR32BG13P Blue", .series = 1 }, + { 44, "EFR32BG13B Blue", .series = 1 }, + { 45, "EFR32BG13V Blue", .series = 1 }, + { 49, "EFR32FG13P Flex", .series = 1 }, + { 50, "EFR32FG13B Flex", .series = 1 }, + { 51, "EFR32FG13V Flex", .series = 1 }, + { 52, "EFR32MG14P Mighty", .series = 1 }, + { 53, "EFR32MG14B Mighty", .series = 1 }, + { 54, "EFR32MG14V Mighty", .series = 1 }, + { 55, "EFR32BG14P Blue", .series = 1 }, + { 56, "EFR32BG14B Blue", .series = 1 }, + { 57, "EFR32BG14V Blue", .series = 1 }, + { 61, "EFR32FG14P Flex", .series = 1 }, + { 62, "EFR32FG14B Flex", .series = 1 }, + { 63, "EFR32FG14V Flex", .series = 1 }, + { 71, "EFM32G", .series = 0, .page_size = 512 }, + { 72, "EFM32GG Giant", .series = 0 }, + { 73, "EFM32TG Tiny", .series = 0, .page_size = 512 }, + { 74, "EFM32LG Leopard", .series = 0 }, + { 75, "EFM32WG Wonder", .series = 0 }, + { 76, "EFM32ZG Zero", .series = 0, .page_size = 1024 }, + { 77, "EFM32HG Happy", .series = 0, .page_size = 1024 }, + { 81, "EFM32PG1B Pearl", .series = 1 }, + { 83, "EFM32JG1B Jade", .series = 1 }, + { 85, "EFM32PG12B Pearl", .series = 1 }, + { 87, "EFM32JG12B Jade", .series = 1 }, + { 89, "EFM32PG13B Pearl", .series = 1 }, + { 91, "EFM32JG13B Jade", .series = 1 }, + { 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 }, + { 103, "EFM32TG11B Tiny", .series = 1 }, + { 120, "EZR32WG Wonder", .series = 0 }, + { 121, "EZR32LG Leopard", .series = 0 }, + { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 }, +}; + + static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); @@ -200,51 +263,33 @@ static int efm32x_read_info(struct flash_bank *bank, if (ERROR_OK != ret) return ret; - if (EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || - EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { - efm32x_info->reg_base = EFR32_MSC_REGBASE; - efm32x_info->reg_lock = EFR32_MSC_REG_LOCK; - } else { - efm32x_info->reg_base = EFM32_MSC_REGBASE; - efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) { + if (efm32_families[i].family_id == efm32_info->part_family) + efm32_info->family_data = &efm32_families[i]; } - if (EFM_FAMILY_ID_GECKO == efm32_info->part_family || - EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family) - efm32_info->page_size = 512; - else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family || - EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family) - efm32_info->page_size = 1024; - else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family || - EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) { - if (efm32_info->prod_rev >= 18) { - uint8_t pg_size = 0; - ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, - &pg_size); - if (ERROR_OK != ret) - return ret; + if (efm32_info->family_data == NULL) { + LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); + return ERROR_FAIL; + } - efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); - } else { - /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid - for MCUs with PROD_REV < 18 */ - if (efm32_info->flash_sz_kib < 512) - efm32_info->page_size = 2048; - else - efm32_info->page_size = 4096; - } + switch (efm32_info->family_data->series) { + case 0: + efm32x_info->reg_base = EFM32_MSC_REGBASE; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + break; + case 1: + efm32x_info->reg_base = EFM32_MSC_REGBASE_SERIES1; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK_SERIES1; + break; + } - if ((2048 != efm32_info->page_size) && - (4096 != efm32_info->page_size)) { - LOG_ERROR("Invalid page size %u", efm32_info->page_size); - return ERROR_FAIL; - } - } else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family || - EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || - EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { + if (efm32_info->family_data->msc_regbase != 0) + efm32x_info->reg_base = efm32_info->family_data->msc_regbase; + + if (efm32_info->family_data->page_size != 0) { + efm32_info->page_size = efm32_info->family_data->page_size; + } else { uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); @@ -252,13 +297,25 @@ static int efm32x_read_info(struct flash_bank *bank, return ret; efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); - if (2048 != efm32_info->page_size) { + + if (efm32_info->part_family == EFM_FAMILY_ID_GIANT_GECKO || + efm32_info->part_family == EFM_FAMILY_ID_LEOPARD_GECKO) { + /* Giant or Leopard Gecko */ + if (efm32_info->prod_rev < 18) { + /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid + for MCUs with PROD_REV < 18 */ + if (efm32_info->flash_sz_kib < 512) + efm32_info->page_size = 2048; + else + efm32_info->page_size = 4096; + } + } + + if ((efm32_info->page_size != 2048) && + (efm32_info->page_size != 4096)) { LOG_ERROR("Invalid page size %u", efm32_info->page_size); return ERROR_FAIL; } - } else { - LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); - return ERROR_FAIL; } return ERROR_OK; @@ -270,71 +327,10 @@ static int efm32x_read_info(struct flash_bank *bank, static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) { int printed = 0; + printed = snprintf(buf, buf_size, "%s Gecko, rev %d", + info->family_data->name, info->prod_rev); - switch (info->part_family) { - case EZR_FAMILY_ID_WONDER_GECKO: - case EZR_FAMILY_ID_LEOPARD_GECKO: - case EZR_FAMILY_ID_HAPPY_GECKO: - printed = snprintf(buf, buf_size, "EZR32 "); - break; - case EFR_FAMILY_ID_MIGHTY_GECKO: - case EFR_FAMILY_ID_BLUE_GECKO: - printed = snprintf(buf, buf_size, "EFR32 "); - break; - default: - printed = snprintf(buf, buf_size, "EFM32 "); - } - - buf += printed; - buf_size -= printed; - - if (0 >= buf_size) - return ERROR_BUF_TOO_SMALL; - - switch (info->part_family) { - case EFM_FAMILY_ID_GECKO: - printed = snprintf(buf, buf_size, "Gecko"); - break; - case EFM_FAMILY_ID_GIANT_GECKO: - printed = snprintf(buf, buf_size, "Giant Gecko"); - break; - case EFM_FAMILY_ID_TINY_GECKO: - printed = snprintf(buf, buf_size, "Tiny Gecko"); - break; - case EFM_FAMILY_ID_LEOPARD_GECKO: - case EZR_FAMILY_ID_LEOPARD_GECKO: - printed = snprintf(buf, buf_size, "Leopard Gecko"); - break; - case EFM_FAMILY_ID_WONDER_GECKO: - case EZR_FAMILY_ID_WONDER_GECKO: - printed = snprintf(buf, buf_size, "Wonder Gecko"); - break; - case EFM_FAMILY_ID_ZERO_GECKO: - printed = snprintf(buf, buf_size, "Zero Gecko"); - break; - case EFM_FAMILY_ID_HAPPY_GECKO: - case EZR_FAMILY_ID_HAPPY_GECKO: - printed = snprintf(buf, buf_size, "Happy Gecko"); - break; - case EFR_FAMILY_ID_BLUE_GECKO: - printed = snprintf(buf, buf_size, "Blue Gecko"); - break; - case EFR_FAMILY_ID_MIGHTY_GECKO: - printed = snprintf(buf, buf_size, "Mighty Gecko"); - break; - } - - buf += printed; - buf_size -= printed; - - if (0 >= buf_size) - return ERROR_BUF_TOO_SMALL; - - printed = snprintf(buf, buf_size, " - Rev: %d", info->prod_rev); - buf += printed; - buf_size -= printed; - - if (0 >= buf_size) + if (printed >= buf_size) return ERROR_BUF_TOO_SMALL; return ERROR_OK; @@ -522,7 +518,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) } } - /* also, read ULW, DLW and MLW */ + /* also, read ULW, DLW, MLW, ALW and CLW words */ /* ULW, word 126 */ ptr = efm32x_info->lb_page + 126; @@ -540,7 +536,7 @@ static int efm32x_read_lock_data(struct flash_bank *bank) return ret; } - /* MLW, word 125, present in GG and LG */ + /* MLW, word 125, present in GG, LG, PG, JG, EFR32 */ ptr = efm32x_info->lb_page + 125; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr); if (ERROR_OK != ret) { @@ -548,6 +544,30 @@ static int efm32x_read_lock_data(struct flash_bank *bank) return ret; } + /* ALW, word 124, present in GG, LG, PG, JG, EFR32 */ + ptr = efm32x_info->lb_page + 124; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+124*4, ptr); + if (ERROR_OK != ret) { + LOG_ERROR("Failed to read ALW"); + return ret; + } + + /* CLW1, word 123, present in EFR32 */ + ptr = efm32x_info->lb_page + 123; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+123*4, ptr); + if (ERROR_OK != ret) { + LOG_ERROR("Failed to read CLW1"); + return ret; + } + + /* CLW0, word 122, present in GG, LG, PG, JG, EFR32 */ + ptr = efm32x_info->lb_page + 122; + ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+122*4, ptr); + if (ERROR_OK != ret) { + LOG_ERROR("Failed to read CLW0"); + return ret; + } + return ERROR_OK; } From e195b0bc812deaad4d770cb1044c5a1b905d8671 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 30 Jan 2018 10:37:51 +0100 Subject: [PATCH 09/91] armv7a: forward error value in armv7a_cache_auto_flush_all_data if armv7a_l1_d_cache_clean_inval_all will fail, error value is never forwarded. So make sure we do it from now. Change-Id: I02acfaa938ec09f58df77191d13d8f4bb3308720 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4384 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv7a_cache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 7af3e6d4e..3e5f8d6de 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -148,10 +148,11 @@ int armv7a_cache_auto_flush_all_data(struct target *target) } else retval = armv7a_l1_d_cache_clean_inval_all(target); - /* do outer cache flushing after inner caches have been flushed */ - retval = arm7a_l2x_flush_all_data(target); + if (retval != ERROR_OK) + return retval; - return retval; + /* do outer cache flushing after inner caches have been flushed */ + return arm7a_l2x_flush_all_data(target); } From dd60dd84f28deb9dd485384466c4417b527ac3b2 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Sun, 26 Mar 2017 10:24:59 +0200 Subject: [PATCH 10/91] icepick-d: extend access to core control register The ICEPick-D jtag router has core control registers that provide the same (or similar) functionality as the tap control register, for individual cores accessible through the same tap (e.g. through a DAP). Core control registers are located at address "0x60 + core-id" of the ROUTER address space (IR=ROUTER). It is sometimes helpful or even necessary to modify the core control register. This patch renames the "icepick_d_coreid" function to the more appropriate "icepick_d_core_control" and adds a "value" argument that allows writing of arbitrary value. "icepick_d_tapenable" is extended by an optional value argument so that core control can be written as the tap is enabled. Change-Id: I0e7f91b596cb5075364c6c233348508f58e0a901 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4141 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/target/icepick.cfg | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tcl/target/icepick.cfg b/tcl/target/icepick.cfg index abd7b6a08..0f160bb10 100644 --- a/tcl/target/icepick.cfg +++ b/tcl/target/icepick.cfg @@ -63,7 +63,8 @@ proc icepick_c_router {jrc rw block register payload} { irscan $jrc [CONST IR_ROUTER] -endstate IRPAUSE # ROUTER instructions are 32 bits wide - set old_dr_value [drscan $jrc 32 $new_dr_value -endstate DRPAUSE] + set old_dr_value 0x[drscan $jrc 32 $new_dr_value -endstate DRPAUSE] +# echo "\tOld router value:\t0x[format %x $old_dr_value]" } # Configure the icepick control register @@ -109,15 +110,15 @@ proc icepick_c_tapenable {jrc port} { # jrc == TAP name for the ICEpick # coreid== core id number 0..15 (not same as port number!) -proc icepick_d_set_coreid {jrc coreid } { - icepick_c_router $jrc 1 0x6 $coreid 0x2008 +proc icepick_d_set_core_control {jrc coreid value } { + icepick_c_router $jrc 1 0x6 $coreid $value } # jrc == TAP name for the ICEpick # port == a port number, 0..15 # Follow the sequence described in # http://processors.wiki.ti.com/images/f/f6/Router_Scan_Sequence-ICEpick-D.pdf -proc icepick_d_tapenable {jrc port coreid} { +proc icepick_d_tapenable {jrc port coreid { value 0x2008 } } { # First CONNECT to the ICEPick icepick_c_connect $jrc icepick_c_setup $jrc @@ -125,8 +126,8 @@ proc icepick_d_tapenable {jrc port coreid} { # Select the port icepick_c_router $jrc 1 0x2 $port 0x2108 - # Set 4 bit core ID to the Cortex-A - icepick_d_set_coreid $jrc $coreid + # Set icepick core control for $coreid + icepick_d_set_core_control $jrc $coreid $value # Enter the bypass state irscan $jrc [CONST IF_BYPASS] -endstate RUN/IDLE From b551c62a7ff4e97a947486904f09a2356f27ced5 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 5 Oct 2017 14:50:16 +0200 Subject: [PATCH 11/91] cortex_a: fix handling of Thumb-2 32bit breakpoints When debugging Thumb-2 code, Gdb will at times send a breakpoint packet 'Z0,,3', the number 3 denoting that the instruction to break on is 32 bits long. Handle this by replacing it with two consecutive 16bit Thumb BKPTs and make sure to save and restore the full, original 32bit instruction. Note that this fix is only applicable if you debug a bare-metal program (like the linux kernel) with the 'wrong' gdb, e.g. use an "arm-linux" gdb instead of an "arm-eabi" gdb. But since most people may not know about the subtle differences between gdb configurations regarding thumb2 breakpoints it's still valid. Change-Id: Ib93025faf35b11f0dba747a8c1fc36fd09a4c0f8 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4241 Reviewed-by: Matthias Welwarsky Tested-by: jenkins --- src/target/cortex_a.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 672a300ec..9f7e38efc 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1500,10 +1500,22 @@ static int cortex_a_set_breakpoint(struct target *target, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; + /* length == 2: Thumb breakpoint */ if (breakpoint->length == 2) buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); else + /* length == 3: Thumb-2 breakpoint, actual encoding is + * a regular Thumb BKPT instruction but we replace a + * 32bit Thumb-2 instruction, so fix-up the breakpoint + * length + */ + if (breakpoint->length == 3) { + buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); + breakpoint->length = 4; + } else + /* length == 4, normal ARM breakpoint */ buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); + retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, From d301d8b42f0bfe67d76d6f340db6570cc71c876e Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Wed, 20 Sep 2017 12:02:08 +0200 Subject: [PATCH 12/91] gdb_server: add support for vCont Make gdb use target support for single-stepping if available. Change-Id: Ie72345a1e749aefba7cd175ccbf5cf51d4f1a632 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3833 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/gdb_server.c | 103 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f90f12bb5..d866fc6e2 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include "server.h" #include #include "gdb_server.h" @@ -110,6 +112,8 @@ static char *gdb_port_next; static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string); +static void gdb_sig_halted(struct connection *connection); + /* number of gdb connections, mainly to suppress gdb related debugging spam * in helper/log.c when no gdb connections are actually active */ int gdb_actual_connections; @@ -2470,7 +2474,7 @@ static int gdb_query_packet(struct connection *connection, &buffer, &pos, &size, - "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+", + "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read%c;qXfer:threads:read+;QStartNoAckMode+;vContSupported+", (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-', (gdb_target_desc_supported == 1) ? '+' : '-'); @@ -2559,6 +2563,90 @@ static int gdb_query_packet(struct connection *connection, return ERROR_OK; } +static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size) +{ + struct gdb_connection *gdb_connection = connection->priv; + struct target *target = get_target_from_connection(connection); + const char *parse = packet; + int retval; + + /* query for vCont supported */ + if (parse[0] == '?') { + if (target->type->step != NULL) { + /* gdb doesn't accept c without C and s without S */ + gdb_put_packet(connection, "vCont;c;C;s;S", 13); + return true; + } + return false; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + } + + /* simple case, a continue packet */ + if (parse[0] == 'c') { + LOG_DEBUG("target %s continue", target_name(target)); + log_add_callback(gdb_log_callback, connection); + retval = target_resume(target, 1, 0, 0, 0); + if (retval == ERROR_OK) { + gdb_connection->frontend_state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_GDB_START); + } + return true; + } + + /* single-step or step-over-breakpoint */ + if (parse[0] == 's') { + if (strncmp(parse, "s:", 2) == 0) { + int handle_breakpoint = 1; + struct target *ct = target; + int64_t thread_id; + char *endp; + + parse += 2; + packet_size -= 2; + + thread_id = strtoll(parse, &endp, 16); + if (endp != NULL) { + packet_size -= endp - parse; + parse = endp; + } + + if (parse[0] == ';') { + ++parse; + --packet_size; + + if (parse[0] == 'c') { + parse += 1; + packet_size -= 1; + + handle_breakpoint = 0; + } + } + + LOG_DEBUG("target %s single-step thread %"PRId64, target_name(ct), thread_id); + retval = target_step(ct, 1, 0, handle_breakpoint); + if (retval == ERROR_OK) { + gdb_signal_reply(target, connection); + /* stop forwarding log packets! */ + log_remove_callback(gdb_log_callback, connection); + } else + if (retval == ERROR_TARGET_TIMEOUT) { + gdb_connection->frontend_state = TARGET_RUNNING; + target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); + } + } else { + LOG_ERROR("Unknown vCont packet"); + return false; + } + return true; + } + + return false; +} + static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { @@ -2568,6 +2656,19 @@ static int gdb_v_packet(struct connection *connection, target = get_target_from_connection(connection); + if (strncmp(packet, "vCont", 5) == 0) { + bool handled; + + packet += 5; + packet_size -= 5; + + handled = gdb_handle_vcont_packet(connection, packet, packet_size); + if (!handled) + gdb_put_packet(connection, "", 0); + + return ERROR_OK; + } + /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { From 293fb9b25faf8c89a9d06d73b83526b86d4c14d8 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Fri, 17 Feb 2017 14:45:00 +0100 Subject: [PATCH 13/91] rtos: facilitate RTOS SMP handling The RTOS handlers present OS threads to gdb but the openocd target layer only knows about CPU cores (hardware threads). This patch allows closing this gap inside the RTOS handler. The default implementation just returns the current core, but a RTOS handler can provide its own function that associates a an OS thread with a core. Change-Id: I12cafe50b38a38b28057bc5d3a708aa20bf60515 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3997 Reviewed-by: Matthias Welwarsky Tested-by: jenkins --- src/rtos/rtos.c | 10 ++++++++++ src/rtos/rtos.h | 1 + src/server/gdb_server.c | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 84ee498be..4552a87d1 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -57,6 +57,15 @@ int rtos_smp_init(struct target *target) return ERROR_TARGET_INIT_FAILED; } +static int rtos_target_for_threadid(struct connection *connection, int64_t threadid, struct target **t) +{ + struct target *curr = get_target_from_connection(connection); + if (t) + *t = curr; + + return ERROR_OK; +} + static int os_alloc(struct target *target, struct rtos_type *ostype) { struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); @@ -72,6 +81,7 @@ static int os_alloc(struct target *target, struct rtos_type *ostype) /* RTOS drivers can override the packet handler in _create(). */ os->gdb_thread_packet = rtos_thread_packet; + os->gdb_target_for_threadid = rtos_target_for_threadid; return JIM_OK; } diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 87aa5027d..9978b34ff 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -54,6 +54,7 @@ struct rtos { struct thread_detail *thread_details; int thread_count; int (*gdb_thread_packet)(struct connection *connection, char const *packet, int packet_size); + int (*gdb_target_for_threadid)(struct connection *connection, int64_t thread_id, struct target **p_target); void *rtos_specific_params; }; diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index d866fc6e2..42ac8a5e2 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -764,8 +764,12 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio current_thread[0] = '\0'; if (target->rtos != NULL) { - snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", target->rtos->current_thread); + struct target *ct; + snprintf(current_thread, sizeof(current_thread), "thread:%016" PRIx64 ";", + target->rtos->current_thread); target->rtos->current_threadid = target->rtos->current_thread; + target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); + signal_var = gdb_last_signal(ct); } sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", @@ -2614,6 +2618,9 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p parse = endp; } + if (target->rtos != NULL) + target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); + if (parse[0] == ';') { ++parse; --packet_size; @@ -3108,7 +3115,10 @@ static int gdb_input_inner(struct connection *connection) if (gdb_con->ctrl_c) { if (target->state == TARGET_RUNNING) { - retval = target_halt(target); + struct target *t = target; + if (target->rtos) + target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); + retval = target_halt(t); if (retval != ERROR_OK) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = 0; From 3aa8bd2d1704118ad9bbee2f21cbc15a848c8c5b Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Fri, 17 Feb 2017 16:12:07 +0100 Subject: [PATCH 14/91] rtos: run rtos create hook only once on autodetect Whenever a "qSymbol" from gdb is received, the rtos "create" function was called. Make sure this happens only once and only if rtos autodetection is used. Change-Id: Ie5f8632cfce2d64a38dbdb63468302c4e8a784f4 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3998 Tested-by: jenkins Reviewed-by: Sergey A. Borshch Reviewed-by: Matthias Welwarsky --- src/rtos/rtos.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 4552a87d1..497ea8b49 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -346,9 +346,11 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa return ERROR_OK; } else if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { - target->rtos_auto_detect = false; - target->rtos->type->create(target); - target->rtos->type->update_threads(target->rtos); + if (target->rtos_auto_detect == true) { + target->rtos_auto_detect = false; + target->rtos->type->create(target); + target->rtos->type->update_threads(target->rtos); + } } return ERROR_OK; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { From 6168a806946d16e1862fa35d287d46e3cae34078 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Fri, 17 Feb 2017 16:18:09 +0100 Subject: [PATCH 15/91] gdb_server: update rtos threads on new connection make sure the RTOS thread database is updated early on a new gdb connection. Change-Id: I4da9ef30f8634263d697116cefc47976cd1970ad Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4000 Reviewed-by: Matthias Welwarsky Tested-by: jenkins --- src/server/gdb_server.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 42ac8a5e2..cbf1ca9f4 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -961,9 +961,14 @@ static int gdb_new_connection(struct connection *connection) breakpoint_clear_target(target); watchpoint_clear_target(target); - /* clean previous rtos session if supported*/ - if ((target->rtos) && (target->rtos->type->clean)) - target->rtos->type->clean(target); + if (target->rtos) { + /* clean previous rtos session if supported*/ + if (target->rtos->type->clean) + target->rtos->type->clean(target); + + /* update threads */ + rtos_update_threads(target); + } /* remove the initial ACK from the incoming buffer */ retval = gdb_get_char(connection, &initial_ack); From efe6991e804b0ad807b926c51108c92c3c627f83 Mon Sep 17 00:00:00 2001 From: Peter Mamonov Date: Wed, 15 Feb 2017 13:03:15 +0300 Subject: [PATCH 16/91] target: fix target.working_area type Change-Id: I15cfbe6984656fb0b48d2af5a7e1afa10d47b6ab Signed-off-by: Peter Mamonov Reviewed-on: http://openocd.zylin.com/3977 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/target.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/target.h b/src/target/target.h index 0096cae10..6020400f3 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -153,7 +153,7 @@ struct target { struct target_event_action *event_action; int reset_halt; /* attempt resetting the CPU into the halted mode? */ - uint32_t working_area; /* working area (initialised RAM). Evaluated + target_addr_t working_area; /* working area (initialised RAM). Evaluated * upon first allocation from virtual/physical address. */ bool working_area_virt_spec; /* virtual address specified? */ target_addr_t working_area_virt; /* virtual address */ From cb75947a0974fa7449f65c195197cb785ac5f06d Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 8 Feb 2018 14:44:10 +0100 Subject: [PATCH 17/91] flash/nor/core: fix Segmentation fault during flash write of bad formed img flash_write_unlock() sorts sections by base address but does not check if they overlap. In case of overlapped sections an item of padding[] array can get negative and padding loop writes out of allocated buffer. How to replicate: cat two copies of an ihex file to one file and try to flash it. Check for overlapped sections and abort write in such case. Change-Id: I43eee7dc290a8d18faa59567b2118b88ad4bedca Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4397 Tested-by: jenkins Reviewed-by: Andreas Bolsch --- src/flash/nor/core.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index ab69a328b..7b91e57b2 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -601,7 +601,7 @@ int flash_write_unlock(struct target *target, struct image *image, uint32_t buffer_size; uint8_t *buffer; int section_last; - uint32_t run_address = sections[section]->base_address + section_offset; + target_addr_t run_address = sections[section]->base_address + section_offset; uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; @@ -617,7 +617,7 @@ int flash_write_unlock(struct target *target, struct image *image, if (retval != ERROR_OK) goto done; if (c == NULL) { - LOG_WARNING("no flash bank found for address %" PRIx32, run_address); + LOG_WARNING("no flash bank found for address " TARGET_ADDR_FMT, run_address); section++; /* and skip it */ section_offset = 0; continue; @@ -652,7 +652,18 @@ int flash_write_unlock(struct target *target, struct image *image, /* if we have multiple sections within our image, * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ - pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size); + target_addr_t run_next_addr = run_address + run_size; + if (sections[section_last + 1]->base_address < run_next_addr) { + LOG_ERROR("Section at " TARGET_ADDR_FMT + " overlaps section ending at " TARGET_ADDR_FMT, + sections[section_last + 1]->base_address, + run_next_addr); + LOG_ERROR("Flash write aborted."); + retval = ERROR_FAIL; + goto done; + } + + pad_bytes = sections[section_last + 1]->base_address - run_next_addr; padding[section_last] = pad_bytes; run_size += sections[++section_last]->size; run_size += pad_bytes; From 9d7db2dc86ea59115a0979bd654d9b2b273a6d6c Mon Sep 17 00:00:00 2001 From: Ake Rehnman Date: Tue, 23 Jan 2018 11:10:19 +0100 Subject: [PATCH 18/91] stm8: fix compilation warning Change-Id: Iedad040384316356442ec87769855fa2960893c5 Signed-off-by: Ake Rehnman Reviewed-on: http://openocd.zylin.com/4377 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/target/stm8.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/target/stm8.c b/src/target/stm8.c index 262497b0d..4556fd987 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -477,7 +477,8 @@ static int stm8_examine_debug_reason(struct target *target) uint8_t csr1, csr2; retval = stm8_read_dm_csrx(target, &csr1, &csr2); - LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); + if (retval == ERROR_OK) + LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { From 30f334e3ae0a9008d274ae76093c1eb3470ff08a Mon Sep 17 00:00:00 2001 From: Jonas Norling Date: Tue, 17 Oct 2017 11:38:16 +0200 Subject: [PATCH 19/91] efm32: Add JTAG definitions to EFM32 target file This makes it possible to program newer EFM32 and EFR32 chips with JTAG, as opposed to SWD. Change-Id: Ia3e8c1bbc66fc1f33e8cf2087ccf0d1b4dfd74e1 Signed-off-by: Jonas Norling Reviewed-on: http://openocd.zylin.com/4262 Tested-by: jenkins Reviewed-by: Fredrik Hederstierna Reviewed-by: Tomas Vanek --- tcl/target/efm32.cfg | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tcl/target/efm32.cfg b/tcl/target/efm32.cfg index 33610d5a8..e0c553fd2 100644 --- a/tcl/target/efm32.cfg +++ b/tcl/target/efm32.cfg @@ -1,5 +1,8 @@ # -# efm32 target +# Silicon Labs (formerly Energy Micro) EFM32 target +# +# Note: All EFM32 chips have SWD support, but only newer series 1 +# chips have JTAG support. # source [find target/swj-dp.tcl] @@ -21,10 +24,14 @@ if { [info exists WORKAREASIZE] } { if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { - set _CPUTAPID 0x2ba01477 + if { [using_jtag] } { + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x2ba01477 + } } -swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID adapter_khz 1000 From e84592d17d11bb1b3bbae24e1aed725913787285 Mon Sep 17 00:00:00 2001 From: Girts Folkmanis Date: Mon, 8 May 2017 15:31:31 -0700 Subject: [PATCH 20/91] Expand target_run_flash_async_algorithm() doc comment. Change-Id: I5d1e8401cbcf0e116a233a2839a06d2c9dbc85ce Signed-off-by: Girts Folkmanis Reviewed-on: http://openocd.zylin.com/4127 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Andreas Bolsch Reviewed-by: Tomas Vanek --- src/target/target.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 58d6d8268..055658ea6 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -882,12 +882,45 @@ done: } /** - * Executes a target-specific native code algorithm in the target. - * It differs from target_run_algorithm in that the algorithm is asynchronous. - * Because of this it requires an compliant algorithm: - * see contrib/loaders/flash/stm32f1x.S for example. + * Streams data to a circular buffer on target intended for consumption by code + * running asynchronously on target. + * + * This is intended for applications where target-specific native code runs + * on the target, receives data from the circular buffer, does something with + * it (most likely writing it to a flash memory), and advances the circular + * buffer pointer. + * + * This assumes that the helper algorithm has already been loaded to the target, + * but has not been started yet. Given memory and register parameters are passed + * to the algorithm. + * + * The buffer is defined by (buffer_start, buffer_size) arguments and has the + * following format: + * + * [buffer_start + 0, buffer_start + 4): + * Write Pointer address (aka head). Written and updated by this + * routine when new data is written to the circular buffer. + * [buffer_start + 4, buffer_start + 8): + * Read Pointer address (aka tail). Updated by code running on the + * target after it consumes data. + * [buffer_start + 8, buffer_start + buffer_size): + * Circular buffer contents. + * + * See contrib/loaders/flash/stm32f1x.S for an example. * * @param target used to run the algorithm + * @param buffer address on the host where data to be sent is located + * @param count number of blocks to send + * @param block_size size in bytes of each block + * @param num_mem_params count of memory-based params to pass to algorithm + * @param mem_params memory-based params to pass to algorithm + * @param num_reg_params count of register-based params to pass to algorithm + * @param reg_params memory-based params to pass to algorithm + * @param buffer_start address on the target of the circular buffer structure + * @param buffer_size size of the circular buffer structure + * @param entry_point address on the target to execute to start the algorithm + * @param exit_point address at which to set a breakpoint to catch the + * end of the algorithm; can be 0 if target triggers a breakpoint itself */ int target_run_flash_async_algorithm(struct target *target, From 1a3cbbf3a5e3432aeab52d7e5f1ff83f71dca929 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Mon, 26 Feb 2018 14:51:35 -0800 Subject: [PATCH 21/91] Fix incorrect comment target_start_algorithm does not download the algorithm. It only starts it. It expects someone else to have already written the algorithm code into the proper location before calling it. Change-Id: I5e04406eed0ebb1c23e550dbf8d9f1204c432603 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4435 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/target.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 055658ea6..523761015 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -808,8 +808,7 @@ done: } /** - * Downloads a target-specific native code algorithm to the target, - * executes and leaves it running. + * Executes a target-specific native code algorithm and leaves it running. * * @param target used to run the algorithm * @param arch_info target-specific description of the algorithm. From bae76053dc515252dc5c8235b9a848e461080c66 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 23 Feb 2018 19:27:28 +0100 Subject: [PATCH 22/91] gdb_server: run control fixes for vCont this patch contains several changes to run control and state handling together with gdb: - graceful handling of target/gdb desync on resume, step and halt - a default gdb-attach event executing the "halt" command, to meet gdb expectation of target state when it attaches - call target_poll() after Ctrl-C command from gdb - call target_poll() after resume and step through a vCont packet - fix log message forwarding on vCont stepping, also move an aarch64 log message from INFO to DEBUG level to prevent messing up the gdb console during source-line stepping - fix oversight in vCont support that messes up breakpoint handling during stepping Change-Id: Ic79db7c2b798a35283ff752e9b12475486a1f31a Fixes: d301d8b42f0bfe67d76d6f340db6570cc71c876e Signed-off-by: Tomas Vanek Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4432 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 78 +++++++++++++++++++++++++++++++++++------ src/target/aarch64.c | 4 +-- src/target/startup.tcl | 1 + 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index cbf1ca9f4..a15c5bb81 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2599,18 +2599,32 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p LOG_DEBUG("target %s continue", target_name(target)); log_add_callback(gdb_log_callback, connection); retval = target_resume(target, 1, 0, 0, 0); - if (retval == ERROR_OK) { - gdb_connection->frontend_state = TARGET_RUNNING; - target_call_event_callbacks(target, TARGET_EVENT_GDB_START); + if (retval == ERROR_TARGET_NOT_HALTED) + LOG_INFO("target %s was not halted when resume was requested", target_name(target)); + + /* 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)); } + + /* + * We don't report errors to gdb here, move frontend_state to + * TARGET_RUNNING to stay in sync with gdb's expectation of the + * target state + */ + gdb_connection->frontend_state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_GDB_START); + return true; } /* single-step or step-over-breakpoint */ if (parse[0] == 's') { if (strncmp(parse, "s:", 2) == 0) { - int handle_breakpoint = 1; struct target *ct = target; + int current_pc = 1; int64_t thread_id; char *endp; @@ -2634,21 +2648,63 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p parse += 1; packet_size -= 1; - handle_breakpoint = 0; + /* check if thread-id follows */ + if (parse[0] == ':') { + int64_t tid; + parse += 1; + packet_size -= 1; + + tid = strtoll(parse, &endp, 16); + if (tid == thread_id) { + /* + * Special case: only step a single thread (core), + * keep the other threads halted. Currently, only + * aarch64 target understands it. Other target types don't + * care (nobody checks the actual value of 'current') + * and it doesn't really matter. This deserves + * a symbolic constant and a formal interface documentation + * at a later time. + */ + LOG_DEBUG("request to step current core only"); + /* uncomment after checking that indeed other targets are safe */ + /*current_pc = 2;*/ + } + } } } LOG_DEBUG("target %s single-step thread %"PRId64, target_name(ct), thread_id); - retval = target_step(ct, 1, 0, handle_breakpoint); + log_add_callback(gdb_log_callback, connection); + target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); + + /* support for gdb_sync command */ + if (gdb_connection->sync) { + gdb_connection->sync = false; + if (ct->state == TARGET_HALTED) { + LOG_WARNING("stepi ignored. GDB will now fetch the register state " \ + "from the target."); + gdb_sig_halted(connection); + log_remove_callback(gdb_log_callback, connection); + } else + gdb_connection->frontend_state = TARGET_RUNNING; + return true; + } + + 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)); + + /* if step was successful send a reply back to gdb */ if (retval == ERROR_OK) { - gdb_signal_reply(target, connection); + retval = target_poll(ct); + if (retval != ERROR_OK) + LOG_DEBUG("error polling target %s after successful step", target_name(ct)); + /* send back signal information */ + gdb_signal_reply(ct, connection); /* stop forwarding log packets! */ log_remove_callback(gdb_log_callback, connection); } else - if (retval == ERROR_TARGET_TIMEOUT) { gdb_connection->frontend_state = TARGET_RUNNING; - target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); - } } else { LOG_ERROR("Unknown vCont packet"); return false; @@ -3124,6 +3180,8 @@ static int gdb_input_inner(struct connection *connection) if (target->rtos) target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &t); retval = target_halt(t); + if (retval == ERROR_OK) + retval = target_poll(t); if (retval != ERROR_OK) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = 0; diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 14a2da6c1..0630ffb9b 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -452,7 +452,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug struct target *curr; if (debug_reason == DBG_REASON_NOTHALTED) { - LOG_INFO("Halting remaining targets in SMP group"); + LOG_DEBUG("Halting remaining targets in SMP group"); aarch64_halt_smp(target, true); } @@ -1086,7 +1086,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (retval != ERROR_OK) return retval; - if (target->smp && !handle_breakpoints) { + if (target->smp && (current == 1)) { /* * isolate current target so that it doesn't get resumed * together with the others diff --git a/src/target/startup.tcl b/src/target/startup.tcl index 9bbc6e32c..cf844e1f6 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -203,6 +203,7 @@ proc init_target_events {} { foreach t $targets { set_default_target_event $t gdb-flash-erase-start "reset init" set_default_target_event $t gdb-flash-write-end "reset halt" + set_default_target_event $t gdb-attach "halt" } } From eaeb4191e55c3a23582ecb40b852f95c2e0ea917 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 1 Mar 2018 17:43:25 +0100 Subject: [PATCH 23/91] rtos: fix rtos no-auto configuration A previous fix avoiding multiple calls to the rtos_create function had a side effect if rtos support was configured explicitly. It affected all rtos' that rely on symbol resolution from gdb. Change-Id: Id7f17c6ec5ce2450322d2748a4b2369aaa524a7b Fixes: 3aa8bd2d1704118ad9bbee2f21cbc15a848c8c5b Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4438 Tested-by: jenkins Reviewed-by: Richard Braun Reviewed-by: Matthias Welwarsky --- src/rtos/rtos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 497ea8b49..1fee5b084 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -349,8 +349,8 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa if (target->rtos_auto_detect == true) { target->rtos_auto_detect = false; target->rtos->type->create(target); - target->rtos->type->update_threads(target->rtos); } + target->rtos->type->update_threads(target->rtos); } return ERROR_OK; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { From bb9d9c60264a905926e0d15f84842858d0de80b7 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 21 Nov 2017 22:57:39 +0100 Subject: [PATCH 24/91] target: use correct target in target-prefixed commands and event handlers This change contains an alternative to Matthias Welwarsky's #4130 (target-prefixed commands) and to #4293 (event handlers). get_current_target() must retrieve the target associated to the current command. If no target associated, the current target of the command context is used as a fallback. Many Tcl event handlers work with the current target as if it were the target issuing the event. current_target in command_context is a number and has to be converted to a pointer in every get_current_target() call. The solution: - Replace current_target in command_context by a target pointer - Add another target pointer current_target_override - get_current_target() returns current_target_override if set, otherwise current_target - Save, set and restore current_target_override to the current prefix in run_command() - Save, set and restore current_target_override to the event invoking target in target_handle_event() While on it use calloc when allocating a new command_context. Change-Id: I9a82102e94dcac063743834a1d28da861b2e74ea Signed-off-by: Tomas Vanek Suggested-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4295 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 3 +++ src/helper/command.c | 24 +++++++++++++++++++----- src/helper/command.h | 15 ++++++++++++++- src/server/tcl_server.c | 2 +- src/target/target.c | 26 +++++++++++++++++++++----- 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index a6f220f46..9126003b8 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4217,6 +4217,9 @@ Calling this twice with two different event names assigns two different handlers, but calling it twice with the same event name assigns only one handler. +Current target is temporarily overridden to the event issuing target +before handler code starts and switched back after handler is done. + @item @code{-work-area-backup} (@option{0}|@option{1}) -- says whether the work area gets backed up; by default, @emph{it is not backed up.} diff --git a/src/helper/command.c b/src/helper/command.c index cbd52fbf1..f8b731e4a 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -608,7 +608,23 @@ static int run_command(struct command_context *context, .argc = num_words - 1, .argv = words + 1, }; + /* Black magic of overridden current target: + * If the command we are going to handle has a target prefix, + * override the current target temporarily for the time + * of processing the command. + * current_target_override is used also for event handlers + * therefore we prevent touching it if command has no prefix. + * Previous override is saved and restored back to ensure + * correct work when run_command() is re-entered. */ + struct target *saved_target_override = context->current_target_override; + if (c->jim_handler_data) + context->current_target_override = c->jim_handler_data; + int retval = c->handler(&cmd); + + if (c->jim_handler_data) + context->current_target_override = saved_target_override; + if (retval == ERROR_COMMAND_SYNTAX_ERROR) { /* Print help for command */ char *full_name = command_name(c, ' '); @@ -643,6 +659,8 @@ int command_run_line(struct command_context *context, char *line) * happen when the Jim Tcl interpreter is provided by eCos for * instance. */ + context->current_target_override = NULL; + Jim_Interp *interp = context->interp; Jim_DeleteAssocData(interp, "context"); retcode = Jim_SetAssocData(interp, "context", NULL, context); @@ -1269,14 +1287,10 @@ static const struct command_registration command_builtin_handlers[] = { struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp) { - struct command_context *context = malloc(sizeof(struct command_context)); + struct command_context *context = calloc(1, sizeof(struct command_context)); const char *HostOs; context->mode = COMMAND_EXEC; - context->commands = NULL; - context->current_target = 0; - context->output_handler = NULL; - context->output_handler_priv = NULL; /* Create a jim interpreter if we were not handed one */ if (interp == NULL) { diff --git a/src/helper/command.h b/src/helper/command.h index f696ab823..1a26c0699 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -49,7 +49,15 @@ struct command_context { Jim_Interp *interp; enum command_mode mode; struct command *commands; - int current_target; + struct target *current_target; + /* The target set by 'targets xx' command or the latest created */ + struct target *current_target_override; + /* If set overrides current_target + * It happens during processing of + * 1) a target prefixed command + * 2) an event handler + * Pay attention to reentrancy when setting override. + */ command_output_handler_t output_handler; void *output_handler_priv; }; @@ -168,6 +176,11 @@ struct command { command_handler_t handler; Jim_CmdProc *jim_handler; void *jim_handler_data; + /* Currently used only for target of target-prefixed cmd. + * Native OpenOCD commands use jim_handler_data exclusively + * as a target override. + * Jim handlers outside of target cmd tree can use + * jim_handler_data for any handler specific data */ enum command_mode mode; struct command *next; }; diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 0077339f2..7c40f7dce 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -157,7 +157,7 @@ static int tcl_new_connection(struct connection *connection) connection->priv = tclc; - struct target *target = get_target_by_num(connection->cmd_ctx->current_target); + struct target *target = get_current_target(connection->cmd_ctx); if (target != NULL) tclc->tc_laststate = target->state; diff --git a/src/target/target.c b/src/target/target.c index 523761015..32000c047 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -510,7 +510,9 @@ struct target *get_target_by_num(int num) struct target *get_current_target(struct command_context *cmd_ctx) { - struct target *target = get_target_by_num(cmd_ctx->current_target); + struct target *target = cmd_ctx->current_target_override + ? cmd_ctx->current_target_override + : cmd_ctx->current_target; if (target == NULL) { LOG_ERROR("BUG: current_target out of bounds"); @@ -2505,7 +2507,10 @@ static int find_target(struct command_context *cmd_ctx, const char *name) return ERROR_FAIL; } - cmd_ctx->current_target = target->target_number; + cmd_ctx->current_target = target; + if (cmd_ctx->current_target_override) + cmd_ctx->current_target_override = target; + return ERROR_OK; } @@ -2533,7 +2538,7 @@ COMMAND_HANDLER(handle_targets_command) else state = "tap-disabled"; - if (CMD_CTX->current_target == target->target_number) + if (CMD_CTX->current_target == target) marker = '*'; /* keep columns lined up to match the headers above */ @@ -4441,17 +4446,28 @@ void target_handle_event(struct target *target, enum target_event e) for (teap = target->event_action; teap != NULL; teap = teap->next) { if (teap->event == e) { - LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s", + LOG_DEBUG("target(%d): %s (%s) event: %d (%s) action: %s", target->target_number, target_name(target), target_type_name(target), e, Jim_Nvp_value2name_simple(nvp_target_event, e)->name, Jim_GetString(teap->body, NULL)); + + /* Override current target by the target an event + * is issued from (lot of scripts need it). + * Return back to previous override as soon + * as the handler processing is done */ + struct command_context *cmd_ctx = current_command_context(teap->interp); + struct target *saved_target_override = cmd_ctx->current_target_override; + cmd_ctx->current_target_override = target; + if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) { Jim_MakeErrorMessage(teap->interp); command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(teap->interp), NULL)); } + + cmd_ctx->current_target_override = saved_target_override; } } } @@ -5529,7 +5545,7 @@ static int target_create(Jim_GetOptInfo *goi) target = calloc(1, sizeof(struct target)); /* set target number */ target->target_number = new_target_number(); - cmd_ctx->current_target = target->target_number; + cmd_ctx->current_target = target; /* allocate memory for each unique target type */ target->type = calloc(1, sizeof(struct target_type)); From e8b2e62d45a7e62bc0d982f6d778d86accfee060 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 6 Jan 2018 12:10:12 +0100 Subject: [PATCH 25/91] flash/nor/psoc4: adjust flash size limited by wounding All credit goes to Dmitry Grinberg http://dmitry.gr/index.php?r=05.Projects&proj=24.%20PSoC4%20confidential Change-Id: Iae8fd6f11a7f62e8ffe970473688f6fac5a0a261 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4324 Tested-by: jenkins --- src/flash/nor/psoc4.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index 1d861edc9..d4ce1fb02 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -78,6 +78,8 @@ CYBL10x6x, CY8C4127_BL, CY8C4247_BL Programming Specifications Document No. 001-91508 Rev. *B September 22, 2014 + + http://dmitry.gr/index.php?r=05.Projects&proj=24.%20PSoC4%20confidential */ /* register locations */ @@ -717,6 +719,22 @@ cleanup: } +/* Due to Cypress's method of market segmentation some devices + * have accessible only 1/2, 1/4 or 1/8 of SPCIF described flash */ +static int psoc4_test_flash_wounding(struct target *target, uint32_t flash_size) +{ + int retval, i; + for (i = 3; i >= 1; i--) { + uint32_t addr = flash_size >> i; + uint32_t dummy; + retval = target_read_u32(target, addr, &dummy); + if (retval != ERROR_OK) + return i; + } + return 0; +} + + static int psoc4_probe(struct flash_bank *bank) { struct psoc4_flash_bank *psoc4_info = bank->driver_priv; @@ -798,6 +816,15 @@ static int psoc4_probe(struct flash_bank *bank) if (num_macros != (num_rows + PSOC4_ROWS_PER_MACRO - 1) / PSOC4_ROWS_PER_MACRO) LOG_WARNING("Number of macros does not correspond with flash size!"); + if (!psoc4_info->legacy_family) { + int wounding = psoc4_test_flash_wounding(target, num_rows * row_size); + if (wounding > 0) { + flash_size_in_kb = flash_size_in_kb >> wounding; + num_rows = num_rows >> wounding; + LOG_INFO("WOUNDING detected: accessible flash size %" PRIu32 " kbytes", flash_size_in_kb); + } + } + if (bank->sectors) { free(bank->sectors); } From a088e3942300a02a7a170aa26d780dd156baf0b4 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 18 Jan 2018 09:42:41 +0100 Subject: [PATCH 26/91] flash/nor/core: fix warning in flash_iterate_address_range_inner Refactor the code to improve readability. Reported by Clang static analyzer. Change-Id: I671447050e93c6f067917c4456b36ac11abb4663 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4355 Tested-by: jenkins --- src/flash/nor/core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 7b91e57b2..6eb7052ef 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -399,18 +399,21 @@ static int flash_iterate_address_range_inner(struct target *target, return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - addr -= c->base; - last_addr -= c->base; + if (c->prot_blocks == NULL || c->num_prot_blocks == 0) { + /* flash driver does not define protect blocks, use sectors instead */ + iterate_protect_blocks = false; + } - if (iterate_protect_blocks && c->prot_blocks && c->num_prot_blocks) { + if (iterate_protect_blocks) { block_array = c->prot_blocks; num_blocks = c->num_prot_blocks; } else { block_array = c->sectors; num_blocks = c->num_sectors; - iterate_protect_blocks = false; } + addr -= c->base; + last_addr -= c->base; for (i = 0; i < num_blocks; i++) { struct flash_sector *f = &block_array[i]; From 66686284311961cab48172b948180d2958eb6ae7 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Feb 2018 19:47:06 +0100 Subject: [PATCH 27/91] flash/nor/psoc4: fix warnings Reported by Clang static analyzer. Change-Id: I1118f303f468b6a78ec6cba692762aee565bdf9e Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4407 Tested-by: jenkins --- src/flash/nor/psoc4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index d4ce1fb02..62b904ed1 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -276,8 +276,8 @@ static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd, } if (sysreq_params_size) { - LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " %08" PRIx32 " size %" PRIu32, - cmd, cmd_param, param1, sysreq_params[0], sysreq_params_size); + LOG_DEBUG("SYSREQ %02" PRIx8 " %04" PRIx16 " %08" PRIx32 " size %" PRIu32, + cmd, cmd_param, param1, sysreq_params_size); /* Allocate memory for sysreq_params */ retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem); if (retval != ERROR_OK) { @@ -323,6 +323,7 @@ static int psoc4_sysreq(struct flash_bank *bank, uint8_t cmd, if (armv7m == NULL) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); + retval = ERROR_FAIL; goto cleanup; } From 8f1f912a7d2cb5777116056fc9d67aa2ea0c9467 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 21 Feb 2018 13:54:44 +0100 Subject: [PATCH 28/91] flash/nor/psoc4: fix protection on devices with 256k flash Protection read and setting of the second flash macro did not work. Tested on CY8CKIT-046 Change-Id: I67789399ad1e89bbfc23a95547ecca7753130701 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4425 Tested-by: jenkins --- src/flash/nor/psoc4.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index 62b904ed1..a0240091d 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -99,7 +99,7 @@ /* constants */ -#define PSOC4_SFLASH_MACRO_SIZE 0x400 +#define PSOC4_SFLASH_MACRO_SIZE 0x800 #define PSOC4_ROWS_PER_MACRO 512 #define PSOC4_SROM_KEY1 0xb6 @@ -567,7 +567,7 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last) uint32_t *sysrq_buffer = NULL; const int param_sz = 8; int chip_prot = PSOC4_CHIP_PROT_OPEN; - int i, m; + int i, m, sect; int num_bits = bank->num_sectors; if (num_bits > PSOC4_ROWS_PER_MACRO) @@ -575,7 +575,7 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last) int prot_sz = num_bits / 8; - sysrq_buffer = calloc(1, param_sz + prot_sz); + sysrq_buffer = malloc(param_sz + prot_sz); if (sysrq_buffer == NULL) { LOG_ERROR("no memory for row buffer"); return ERROR_FAIL; @@ -584,10 +584,11 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last) for (i = first; i <= last && i < bank->num_sectors; i++) bank->sectors[i].is_protected = set; - for (m = 0; m < psoc4_info->num_macros; m++) { + for (m = 0, sect = 0; m < psoc4_info->num_macros; m++) { uint8_t *p = (uint8_t *)(sysrq_buffer + 2); - for (i = 0; i < num_bits && i < bank->num_sectors; i++) { - if (bank->sectors[i].is_protected) + memset(p, 0, prot_sz); + for (i = 0; i < num_bits && sect < bank->num_sectors; i++, sect++) { + if (bank->sectors[sect].is_protected) p[i/8] |= 1 << (i%8); } @@ -597,7 +598,7 @@ static int psoc4_protect(struct flash_bank *bank, int set, int first, int last) retval = psoc4_sysreq(bank, PSOC4_CMD_LOAD_LATCH, 0 /* Byte number in latch from what to write */ | (m << 8), /* flash macro index */ - sysrq_buffer, param_sz + psoc4_info->row_size, + sysrq_buffer, param_sz + prot_sz, NULL); if (retval != ERROR_OK) break; From cb2f21bf3608f24de5c2e4219626cc464269e830 Mon Sep 17 00:00:00 2001 From: Michele Sardo Date: Tue, 12 Sep 2017 08:51:29 +0200 Subject: [PATCH 29/91] Added support for STMicroelectronics BlueNRG-1 and BlueNRG-2 SoC Added configuration files and flash loaders. Change-Id: I768eb3626f4e0eadb206bef90a867cc146fe8c75 Signed-off-by: Michele Sardo Reviewed-on: http://openocd.zylin.com/4226 Tested-by: jenkins Reviewed-by: Tomas Vanek --- contrib/loaders/flash/bluenrg-x/Makefile | 27 + .../loaders/flash/bluenrg-x/bluenrg-x_write.c | 132 +++++ .../flash/bluenrg-x/bluenrg-x_write.inc | 18 + doc/openocd.texi | 24 + src/flash/nor/Makefile.am | 1 + src/flash/nor/bluenrg-x.c | 549 ++++++++++++++++++ src/flash/nor/drivers.c | 2 + tcl/board/steval-idb007v1.cfg | 4 + tcl/board/steval-idb008v1.cfg | 4 + tcl/target/bluenrg-x.cfg | 73 +++ 10 files changed, 834 insertions(+) create mode 100644 contrib/loaders/flash/bluenrg-x/Makefile create mode 100644 contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c create mode 100644 contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc create mode 100644 src/flash/nor/bluenrg-x.c create mode 100644 tcl/board/steval-idb007v1.cfg create mode 100644 tcl/board/steval-idb008v1.cfg create mode 100644 tcl/target/bluenrg-x.cfg diff --git a/contrib/loaders/flash/bluenrg-x/Makefile b/contrib/loaders/flash/bluenrg-x/Makefile new file mode 100644 index 000000000..1a5cfc013 --- /dev/null +++ b/contrib/loaders/flash/bluenrg-x/Makefile @@ -0,0 +1,27 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= arm-none-eabi- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump + +CFLAGS = -c -mthumb -mcpu=cortex-m0 -O3 -g + +all: bluenrg-x_write.inc + +.PHONY: clean + +.INTERMEDIATE: bluenrg-x_write.o + +%.o: %.c + $(CC) $(CFLAGS) -Wall -Wextra -Wa,-adhln=$*.lst $< -o $@ + +%.bin: %.o + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.o *.lst *.bin *.inc diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c new file mode 100644 index 000000000..3dd17b2fc --- /dev/null +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c @@ -0,0 +1,132 @@ +/* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */ +/* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */ + +#include + +/* Status Values ----------------------------------------------------------*/ +#define SUCCESS 0 +#define ERR_UNALIGNED 1 +#define ERR_INVALID_ADDRESS 2 +#define ERR_INVALID_TYPE 3 +#define ERR_WRITE_PROTECTED 4 +#define ERR_WRITE_FAILED 5 +#define ERR_ERASE_REQUIRED 6 +#define ERR_VERIFY_FAILED 7 + +/* Flash Controller defines ---------------------------------------------------*/ +#define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000) +#define FLASH_REG_CONFIG ((volatile uint32_t *)0x40100004) +#define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008) +#define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4010000C) +#define FLASH_REG_IRQRAW ((volatile uint32_t *)0x40100010) +#define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018) +#define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C) +#define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020) +#define FLASH_REG_DATA0 ((volatile uint32_t *)0x40100040) +#define FLASH_REG_DATA1 ((volatile uint32_t *)0x40100044) +#define FLASH_REG_DATA2 ((volatile uint32_t *)0x40100048) +#define FLASH_REG_DATA3 ((volatile uint32_t *)0x4010004C) +#define FLASH_SIZE_REG 0x40100014 + +#define MFB_MASS_ERASE 0x01 +#define MFB_PAGE_ERASE 0x02 + +#define DO_ERASE 0x0100 +#define DO_VERIFY 0x0200 +#define FLASH_CMD_ERASE_PAGE 0x11 +#define FLASH_CMD_MASSERASE 0x22 +#define FLASH_CMD_WRITE 0x33 +#define FLASH_CMD_BURSTWRITE 0xCC +#define FLASH_INT_CMDDONE 0x01 +#define MFB_BOTTOM (0x10040000) +#define MFB_SIZE_B ((16 * (((*(uint32_t *) FLASH_SIZE_REG) + 1) >> 12)) * 1024) +#define MFB_SIZE_W (MFB_SIZE_B/4) +#define MFB_TOP (MFB_BOTTOM+MFB_SIZE_B-1) +#define MFB_PAGE_SIZE_B (2048) +#define MFB_PAGE_SIZE_W (MFB_PAGE_SIZE_B/4) + +#define AREA_ERROR 0x01 +#define AREA_MFB 0x04 + +#define FLASH_WORD_LEN 4 + +typedef struct { + volatile uint8_t *wp; + uint8_t *rp; +} work_area_t; + +/* Flash Commands --------------------------------------------------------*/ +static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data, + uint32_t writeLength) +{ + uint32_t index, flash_word[4]; + uint8_t i; + + *FLASH_REG_IRQMASK = 0; + for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) { + for (i = 0; i < 4; i++) + flash_word[i] = (*(uint32_t *) (*data + i*4)); + + /* Clear the IRQ flags */ + *FLASH_REG_IRQRAW = 0x0000003F; + /* Load the flash address to write */ + *FLASH_REG_ADDRESS = (uint16_t)((address + index) >> 2); + /* Prepare and load the data to flash */ + *FLASH_REG_DATA0 = flash_word[0]; + *FLASH_REG_DATA1 = flash_word[1]; + *FLASH_REG_DATA2 = flash_word[2]; + *FLASH_REG_DATA3 = flash_word[3]; + /* Flash write command */ + *FLASH_REG_COMMAND = FLASH_CMD_BURSTWRITE; + /* Wait the end of the flash write command */ + while ((*FLASH_REG_IRQRAW & FLASH_INT_CMDDONE) == 0) + ; + *data += (FLASH_WORD_LEN * 4); + } + + return SUCCESS; +} + +__attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p, + uint8_t *fifo_end, + uint8_t *target_address, + uint32_t count) +{ + uint32_t retval; + volatile work_area_t *work_area = (work_area_t *) work_area_p; + uint8_t *fifo_start = (uint8_t *) work_area->rp; + + while (count) { + volatile int32_t fifo_linear_size; + + /* Wait for some data in the FIFO */ + while (work_area->rp == work_area->wp) + ; + if (work_area->wp == 0) { + /* Aborted by other party */ + break; + } + if (work_area->rp > work_area->wp) { + fifo_linear_size = fifo_end-work_area->rp; + } else { + fifo_linear_size = (work_area->wp - work_area->rp); + if (fifo_linear_size < 0) + fifo_linear_size = 0; + } + if (fifo_linear_size < 16) { + /* We should never get here */ + continue; + } + + retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size); + if (retval != SUCCESS) { + work_area->rp = (uint8_t *)retval; + break; + } + target_address += fifo_linear_size; + if (work_area->rp >= fifo_end) + work_area->rp = fifo_start; + count -= fifo_linear_size; + } + __asm("bkpt 0"); +} diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc new file mode 100644 index 000000000..47f331228 --- /dev/null +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc @@ -0,0 +1,18 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x05,0x93,0x43,0x68,0x05,0x00,0x07,0x93,0x05,0x9b,0x06,0x91,0x03,0x92,0x35,0x4c, +0x00,0x2b,0x5c,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0,0x2b,0x68,0x00,0x2b, +0x55,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x52,0xd9,0x6b,0x68,0x06,0x9a,0xd3,0x1a, +0x09,0x93,0x09,0x9b,0x0f,0x2b,0xed,0xdd,0x00,0x21,0x09,0x9b,0x04,0x93,0x1a,0x1e, +0x29,0x4b,0x19,0x60,0x32,0xd0,0x29,0x4b,0x00,0x20,0x98,0x46,0x28,0x4b,0x6a,0x68, +0x9c,0x46,0x28,0x4b,0x28,0x4e,0x9b,0x46,0x28,0x4b,0x9a,0x46,0x28,0x4b,0x99,0x46, +0x01,0x23,0x51,0x68,0x17,0x68,0x00,0x91,0x91,0x68,0x01,0x91,0xd1,0x68,0x02,0x91, +0x3f,0x21,0x21,0x60,0x03,0x99,0x09,0x18,0x89,0x03,0x09,0x0c,0x31,0x60,0x41,0x46, +0x0f,0x60,0x67,0x46,0x00,0x99,0x39,0x60,0x5f,0x46,0x01,0x99,0x39,0x60,0x57,0x46, +0x02,0x99,0x39,0x60,0x49,0x46,0xcc,0x27,0x0f,0x60,0x21,0x68,0x0b,0x42,0xfc,0xd0, +0x04,0x99,0x10,0x32,0x10,0x30,0x6a,0x60,0x81,0x42,0xda,0xd8,0x03,0x9a,0x09,0x9b, +0x94,0x46,0x9c,0x44,0x63,0x46,0x06,0x9a,0x03,0x93,0x6b,0x68,0x9a,0x42,0x01,0xd8, +0x07,0x9b,0x6b,0x60,0x05,0x9a,0x09,0x9b,0xd3,0x1a,0x05,0x93,0xa2,0xd1,0x00,0xbe, +0x2b,0x68,0x6a,0x68,0x9b,0x1a,0x09,0x93,0x09,0x9b,0x00,0x2b,0xa9,0xda,0x00,0x23, +0x09,0x93,0xa6,0xe7,0x10,0x00,0x10,0x40,0x0c,0x00,0x10,0x40,0x40,0x00,0x10,0x40, +0x44,0x00,0x10,0x40,0x48,0x00,0x10,0x40,0x18,0x00,0x10,0x40,0x4c,0x00,0x10,0x40, +0x00,0x00,0x10,0x40, diff --git a/doc/openocd.texi b/doc/openocd.texi index 9126003b8..2f01153f8 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5344,6 +5344,30 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory. @comment - defines mass_erase ... pointless given flash_erase_address @end deffn +@deffn {Flash Driver} bluenrg-x +STMicroelectronics BlueNRG-1 and BlueNRG-2 Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0 core and internal flash memory. +The driver automatically recognizes these chips using +the chip identification registers, and autoconfigures itself. + +@example +flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME +@end example + +Note that when users ask to erase all the sectors of the flash, a mass erase command is used which is faster than erasing +each single sector one by one. + +@example +flash erase_sector 0 0 79 # It will perform a mass erase on BlueNRG-1 +@end example + +@example +flash erase_sector 0 0 127 # It will perform a mass erase on BlueNRG-2 +@end example + +Triggering a mass erase is also useful when users want to disable readout protection. + +@end deffn + @deffn {Flash Driver} efm32 All members of the EFM32 microcontroller family from Energy Micro include internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 4b74a4682..b9353642f 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -18,6 +18,7 @@ NOR_DRIVERS = \ %D%/ath79.c \ %D%/atsamv.c \ %D%/avrf.c \ + %D%/bluenrg-x.c \ %D%/cfi.c \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c new file mode 100644 index 000000000..c4a808047 --- /dev/null +++ b/src/flash/nor/bluenrg-x.c @@ -0,0 +1,549 @@ +/*************************************************************************** + * Copyright (C) 2017 by Michele Sardo * + * msmttchr@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "imp.h" + +#define FLASH_SIZE_REG (0x40100014) +#define DIE_ID_REG (0x4090001C) +#define JTAG_IDCODE_REG (0x40900028) +#define BLUENRG2_IDCODE (0x0200A041) +#define FLASH_BASE (0x10040000) +#define FLASH_PAGE_SIZE (2048) +#define FLASH_REG_COMMAND (0x40100000) +#define FLASH_REG_IRQRAW (0x40100010) +#define FLASH_REG_ADDRESS (0x40100018) +#define FLASH_REG_DATA (0x40100040) +#define FLASH_CMD_ERASE_PAGE 0x11 +#define FLASH_CMD_MASSERASE 0x22 +#define FLASH_CMD_WRITE 0x33 +#define FLASH_CMD_BURSTWRITE 0xCC +#define FLASH_INT_CMDDONE 0x01 +#define FLASH_WORD_LEN 4 + +struct bluenrgx_flash_bank { + int probed; + uint32_t idcode; + uint32_t die_id; +}; + +static int bluenrgx_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +/* flash_bank bluenrg-x 0 0 0 0 */ +FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) +{ + struct bluenrgx_flash_bank *bluenrgx_info; + /* Create the bank structure */ + bluenrgx_info = calloc(1, sizeof(*bluenrgx_info)); + + /* Check allocation */ + if (bluenrgx_info == NULL) { + LOG_ERROR("failed to allocate bank structure"); + return ERROR_FAIL; + } + + bank->driver_priv = bluenrgx_info; + + bluenrgx_info->probed = 0; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + return ERROR_OK; +} + +static int bluenrgx_erase(struct flash_bank *bank, int first, int last) +{ + int retval = ERROR_OK; + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + int num_sectors = (last - first + 1); + int mass_erase = (num_sectors == bank->num_sectors); + struct target *target = bank->target; + uint32_t address, command; + + /* check preconditions */ + if (bluenrgx_info->probed == 0) + return ERROR_FLASH_BANK_NOT_PROBED; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + /* Disable blue module */ + if (target_write_u32(target, 0x200000c0, 0) != ERROR_OK) { + LOG_ERROR("Blue disable failed"); + return ERROR_FAIL; + } + + if (mass_erase) { + command = FLASH_CMD_MASSERASE; + address = bank->base; + if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + for (int i = 0; i < 100; i++) { + uint32_t value; + if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + if (value & FLASH_INT_CMDDONE) + break; + if (i == 99) { + LOG_ERROR("Mass erase command failed (timeout)"); + retval = ERROR_FAIL; + } + } + + } else { + command = FLASH_CMD_ERASE_PAGE; + for (int i = first; i <= last; i++) { + address = bank->base+i*FLASH_PAGE_SIZE; + + if (target_write_u32(target, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_ADDRESS, address >> 2) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_u32(target, FLASH_REG_COMMAND, command) != ERROR_OK) { + LOG_ERROR("Failed"); + return ERROR_FAIL; + } + + for (int j = 0; j < 100; j++) { + uint32_t value; + if (target_read_u32(target, FLASH_REG_IRQRAW, &value)) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + if (value & FLASH_INT_CMDDONE) + break; + if (j == 99) { + LOG_ERROR("Erase command failed (timeout)"); + retval = ERROR_FAIL; + } + } + } + } + + return retval; + +} + +static int bluenrgx_protect(struct flash_bank *bank, int set, int first, int last) +{ + /* Protection is only handled in software: no hardware write protection + available in BlueNRG-x devices */ + int sector; + + for (sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + return ERROR_OK; +} +static int bluenrgx_write_word(struct target *target, uint32_t address_base, uint8_t *values, uint32_t count) +{ + int retval = ERROR_OK; + + retval = target_write_u32(target, FLASH_REG_IRQRAW, 0x3f); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + for (uint32_t i = 0; i < count; i++) { + uint32_t address = address_base + i * FLASH_WORD_LEN; + + retval = target_write_u32(target, FLASH_REG_ADDRESS, address >> 2); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + retval = target_write_buffer(target, FLASH_REG_DATA, FLASH_WORD_LEN, values + i * FLASH_WORD_LEN); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + retval = target_write_u32(target, FLASH_REG_COMMAND, FLASH_CMD_WRITE); + if (retval != ERROR_OK) { + LOG_ERROR("Register write failed, error code: %d", retval); + return retval; + } + + for (int j = 0; j < 100; j++) { + uint32_t reg_value; + retval = target_read_u32(target, FLASH_REG_IRQRAW, ®_value); + + if (retval != ERROR_OK) { + LOG_ERROR("Register read failed, error code: %d", retval); + return retval; + } + + if (reg_value & FLASH_INT_CMDDONE) + break; + + if (j == 99) { + LOG_ERROR("Write command failed (timeout)"); + return ERROR_FAIL; + } + } + } + return retval; +} + +static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, uint8_t *buffer, uint32_t count) +{ + int retval = ERROR_OK; + uint8_t *new_buffer = NULL; + uint32_t pre_bytes = 0, post_bytes = 0, pre_word, post_word, pre_address, post_address; + + if (count == 0) { + /* Just return if there are no bytes to write */ + return retval; + } + + if (address_base & 3) { + pre_bytes = address_base & 3; + pre_address = address_base - pre_bytes; + } + + if ((count + pre_bytes) & 3) { + post_bytes = ((count + pre_bytes + 3) & ~3) - (count + pre_bytes); + post_address = (address_base + count) & ~3; + } + + if (pre_bytes || post_bytes) { + uint32_t old_count = count; + + count = old_count + pre_bytes + post_bytes; + + new_buffer = malloc(count); + + if (new_buffer == NULL) { + LOG_ERROR("odd number of bytes to write and no memory " + "for padding buffer"); + return ERROR_FAIL; + } + + LOG_INFO("Requested number of bytes to write and/or address not word aligned (%" PRIu32 "), extending to %" + PRIu32 " ", old_count, count); + + if (pre_bytes) { + if (target_read_u32(target, pre_address, &pre_word)) { + LOG_ERROR("Memory read failed"); + return ERROR_FAIL; + } + + } + + if (post_bytes) { + if (target_read_u32(target, post_address, &post_word)) { + LOG_ERROR("Memory read failed"); + return ERROR_FAIL; + } + + } + + memcpy(new_buffer, &pre_word, pre_bytes); + memcpy((new_buffer+((pre_bytes+old_count) & ~3)), &post_word, 4); + memcpy(new_buffer+pre_bytes, buffer, old_count); + buffer = new_buffer; + } + + retval = bluenrgx_write_word(target, address_base - pre_bytes, buffer, count/4); + + if (new_buffer) + free(new_buffer); + + return retval; +} + +static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + uint32_t buffer_size = 16384 + 8; + struct working_area *write_algorithm; + struct working_area *write_algorithm_sp; + struct working_area *source; + uint32_t address = bank->base + offset; + struct reg_param reg_params[5]; + struct armv7m_algorithm armv7m_info; + int retval = ERROR_OK; + uint32_t pre_size = 0, fast_size = 0, post_size = 0; + uint32_t pre_offset = 0, fast_offset = 0, post_offset = 0; + + /* See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c for source and + * hints how to generate the data! + */ + static const uint8_t bluenrgx_flash_write_code[] = { +#include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" + }; + + if ((offset + count) > bank->size) { + LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %d, size=%d", + (offset + count), + bank->size); + return ERROR_FLASH_DST_OUT_OF_BANK; + } + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* We are good here and we need to compute pre_size, fast_size, post_size */ + pre_size = MIN(count, ((offset+0xF) & ~0xF) - offset); + pre_offset = offset; + fast_size = 16*((count - pre_size) / 16); + fast_offset = offset + pre_size; + post_size = (count-pre_size-fast_size) % 16; + post_offset = fast_offset + fast_size; + + LOG_DEBUG("pre_size = %08x, pre_offset=%08x", pre_size, pre_offset); + LOG_DEBUG("fast_size = %08x, fast_offset=%08x", fast_size, fast_offset); + LOG_DEBUG("post_size = %08x, post_offset=%08x", post_size, post_offset); + + /* Program initial chunk not 16 bytes aligned */ + retval = bluenrgx_write_bytes(target, bank->base+pre_offset, (uint8_t *) buffer, pre_size); + if (retval) { + LOG_ERROR("bluenrgx_write_bytes failed %d", retval); + return ERROR_FAIL; + } + + /* Program chunk 16 bytes aligned in fast mode */ + if (fast_size) { + + if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = target_write_buffer(target, write_algorithm->address, + sizeof(bluenrgx_flash_write_code), + bluenrgx_flash_write_code); + if (retval != ERROR_OK) + return retval; + + /* memory buffer */ + if (target_alloc_working_area(target, buffer_size, &source)) { + LOG_WARNING("no large enough working area available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Stack pointer area */ + if (target_alloc_working_area(target, 64, + &write_algorithm_sp) != ERROR_OK) { + LOG_DEBUG("no working area for write code stack pointer"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); + + /* FIFO start address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[0].value, 0, 32, source->address); + /* FIFO end address (first two words used for write and read pointers) */ + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + /* Flash memory address */ + buf_set_u32(reg_params[2].value, 0, 32, address+pre_size); + /* Number of bytes */ + buf_set_u32(reg_params[3].value, 0, 32, fast_size); + /* Stack pointer for program working area */ + buf_set_u32(reg_params[4].value, 0, 32, write_algorithm_sp->address); + + LOG_DEBUG("source->address = %08" TARGET_PRIxADDR, source->address); + LOG_DEBUG("source->address+ source->size = %08" TARGET_PRIxADDR, source->address+source->size); + LOG_DEBUG("write_algorithm_sp->address = %08" TARGET_PRIxADDR, write_algorithm_sp->address); + LOG_DEBUG("address = %08x", address+pre_size); + LOG_DEBUG("count = %08x", count); + + retval = target_run_flash_async_algorithm(target, + buffer+pre_size, + fast_size/16, + 16, /* Block size: we write in block of 16 bytes to enjoy burstwrite speed */ + 0, + NULL, + 5, + reg_params, + source->address, + source->size, + write_algorithm->address, + 0, + &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_ERROR("error executing bluenrg-x flash write algorithm"); + + uint32_t error = buf_get_u32(reg_params[0].value, 0, 32); + + if (error != 0) + LOG_ERROR("flash write failed = %08" PRIx32, error); + } + if (retval == ERROR_OK) { + uint32_t rp; + /* Read back rp and check that is valid */ + retval = target_read_u32(target, source->address+4, &rp); + if (retval == ERROR_OK) { + if ((rp < source->address+8) || (rp > (source->address + source->size))) { + LOG_ERROR("flash write failed = %08" PRIx32, rp); + retval = ERROR_FLASH_OPERATION_FAILED; + } + } + } + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + target_free_working_area(target, write_algorithm_sp); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + } + + /* Program chunk at end, not addressable by fast burst write algorithm */ + retval = bluenrgx_write_bytes(target, bank->base+post_offset, (uint8_t *) (buffer+pre_size+fast_size), post_size); + if (retval) { + LOG_ERROR("bluenrgx_write_bytes failed %d", retval); + return ERROR_FAIL; + } + return retval; +} + +static int bluenrgx_probe(struct flash_bank *bank) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + uint32_t idcode, size_info, die_id; + int i; + int retval = target_read_u32(bank->target, JTAG_IDCODE_REG, &idcode); + if (retval != ERROR_OK) + return retval; + retval = target_read_u32(bank->target, FLASH_SIZE_REG, &size_info); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(bank->target, DIE_ID_REG, &die_id); + if (retval != ERROR_OK) + return retval; + + bank->size = (size_info + 1) * 4; + bank->base = FLASH_BASE; + bank->num_sectors = bank->size/FLASH_PAGE_SIZE; + bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); + + for (i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * FLASH_PAGE_SIZE; + bank->sectors[i].size = FLASH_PAGE_SIZE; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + bluenrgx_info->probed = 1; + bluenrgx_info->die_id = die_id; + bluenrgx_info->idcode = idcode; + return ERROR_OK; +} + +static int bluenrgx_auto_probe(struct flash_bank *bank) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + + if (bluenrgx_info->probed) + return ERROR_OK; + + return bluenrgx_probe(bank); +} + +/* This method must return a string displaying information about the bank */ +static int bluenrgx_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + int mask_number, cut_number; + char *part_name; + + if (!bluenrgx_info->probed) { + int retval = bluenrgx_probe(bank); + if (retval != ERROR_OK) { + snprintf(buf, buf_size, + "Unable to find bank information."); + return retval; + } + } + + if (bluenrgx_info->idcode == BLUENRG2_IDCODE) + part_name = "BLUENRG-2"; + else + part_name = "BLUENRG-1"; + + mask_number = (bluenrgx_info->die_id >> 4) & 0xF; + cut_number = bluenrgx_info->die_id & 0xF; + + snprintf(buf, buf_size, + "%s - Rev: %d.%d", part_name, mask_number, cut_number); + return ERROR_OK; +} + +struct flash_driver bluenrgx_flash = { + .name = "bluenrg-x", + .flash_bank_command = bluenrgx_flash_bank_command, + .erase = bluenrgx_erase, + .protect = bluenrgx_protect, + .write = bluenrgx_write, + .read = default_flash_read, + .probe = bluenrgx_probe, + .erase_check = default_flash_blank_check, + .protect_check = bluenrgx_protect_check, + .auto_probe = bluenrgx_auto_probe, + .info = bluenrgx_get_info, +}; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 0e6a7382e..a4640a5e7 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -31,6 +31,7 @@ extern struct flash_driver at91samd_flash; extern struct flash_driver ath79_flash; extern struct flash_driver atsamv_flash; extern struct flash_driver avr_flash; +extern struct flash_driver bluenrgx_flash; extern struct flash_driver cfi_flash; extern struct flash_driver dsp5680xx_flash; extern struct flash_driver efm32_flash; @@ -88,6 +89,7 @@ static struct flash_driver *flash_drivers[] = { &ath79_flash, &atsamv_flash, &avr_flash, + &bluenrgx_flash, &cfi_flash, &dsp5680xx_flash, &efm32_flash, diff --git a/tcl/board/steval-idb007v1.cfg b/tcl/board/steval-idb007v1.cfg new file mode 100644 index 000000000..24dbd1e9c --- /dev/null +++ b/tcl/board/steval-idb007v1.cfg @@ -0,0 +1,4 @@ +# This is an evaluation board with a single BlueNRG-1 chip. +# http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb008v1.html +set CHIPNAME bluenrg-1 +source [find target/bluenrg-x.cfg] diff --git a/tcl/board/steval-idb008v1.cfg b/tcl/board/steval-idb008v1.cfg new file mode 100644 index 000000000..3e9d0e5ee --- /dev/null +++ b/tcl/board/steval-idb008v1.cfg @@ -0,0 +1,4 @@ +# This is an evaluation board with a single BlueNRG-2 chip. +# http://www.st.com/content/st_com/en/products/evaluation-tools/solution-evaluation-tools/communication-and-connectivity-solution-eval-boards/steval-idb007v1.html +set CHIPNAME bluenrg-2 +source [find target/bluenrg-x.cfg] diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg new file mode 100644 index 000000000..3ae5108cf --- /dev/null +++ b/tcl/target/bluenrg-x.cfg @@ -0,0 +1,73 @@ +# +# bluenrg-1/2 devices support only SWD transports. +# + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bluenrg-1 +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 24kB-256bytes +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x5F00 +} + +adapter_khz 4000 + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x0bb11477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +set WDOG_VALUE 0 +set WDOG_VALUE_SET 0 + +target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME + +$_TARGETNAME configure -work-area-phys 0x20000100 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# flash size will be probed +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME bluenrg-x 0 0 0 0 $_TARGETNAME + +# In BlueNRG-X reset pin is actually a shutdown (power-off), so define reset as none +reset_config none + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event halted { + global WDOG_VALUE + global WDOG_VALUE_SET + # Stop watchdog during halt, if enabled + mem2array value 32 0x40700008 1 + set WDOG_VALUE [expr ($value(0))] + if [expr ($value(0) & (1 << 1))] { + set WDOG_VALUE_SET 1 + mww 0x40700008 [expr ($value(0) & 0xFFFFFFFD)] + } +} +$_TARGETNAME configure -event resumed { + global WDOG_VALUE + global WDOG_VALUE_SET + if [expr $WDOG_VALUE_SET] { + # Restore watchdog enable value after resume + mww 0x40700008 $WDOG_VALUE + set WDOG_VALUE_SET 0 + } +} From 06e13d6ff56175317ae39ee0e86efbf55d2b27fd Mon Sep 17 00:00:00 2001 From: Luca Dariz Date: Fri, 9 Feb 2018 16:58:25 +0100 Subject: [PATCH 30/91] Fix ChibiOS FPU detection. This is needed for Cortex-M7 devices, which have newer FPU. This issue caused the registry integrity check to fail if FPU was enabled. Currently the code must use FPUv4_SP anyway, since other configurations are not supported by ChibiOS. Change-Id: Ie8a2cb8282ccff6c2a3eb0ffeaddaf149d55d685 Signed-off-by: Luca Dariz Reviewed-on: http://openocd.zylin.com/4398 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Tomas Vanek --- src/rtos/ChibiOS.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c index ef0bb16cf..a46f7a492 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/ChibiOS.c @@ -247,7 +247,7 @@ static int ChibiOS_update_stacking(struct rtos *rtos) /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { - if (armv7m_target->fp_feature == FPv4_SP) { + if (armv7m_target->fp_feature != FP_NONE) { /* Found ARM v7m target which includes a FPU */ uint32_t cpacr; From fd6986168a5e9f33b8dba628b9d9e42196c02923 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 5 Oct 2017 15:44:58 +0200 Subject: [PATCH 31/91] pipistrello: decrease jtag speed to 10 MHz 30 MHz is not working reliably here Change-Id: I38f5f8c7153fc64e313ee911b1629fb5f1114c39 Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4242 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/interface/ftdi/pipistrello.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/interface/ftdi/pipistrello.cfg b/tcl/interface/ftdi/pipistrello.cfg index b51405a2d..5ee5be5bb 100644 --- a/tcl/interface/ftdi/pipistrello.cfg +++ b/tcl/interface/ftdi/pipistrello.cfg @@ -10,4 +10,4 @@ ftdi_layout_init 0x0008 0x000b reset_config none # this generally works fast: the fpga can handle 30MHz, the spi flash can handle # 54MHz with simple read, no dummy cycles, and wait-for-write-completion -adapter_khz 30000 +adapter_khz 10000 From c1c450e0f75a5ed11b2163a1e21dd9516dc07618 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 7 Jan 2017 17:43:49 +0100 Subject: [PATCH 32/91] server/server: Remove all connections on shutdown This patch fixes a memory leak in the internal server. Steps for reproduction: * valgrind --leak-check=full --show-reachable=yes ./build/src/openocd * Establish more than one connection to OpenOCD (e.g. telnet) * Shutdown OpenOCD * Check for memory leaks in add_connection() Change-Id: I0ae6fcf2918fd9bdec350446d3e26742d08ff698 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4053 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/server.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/server/server.c b/src/server/server.c index 46c860f4f..6fa864bbc 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -345,6 +345,21 @@ int add_service(char *name, return ERROR_OK; } +static void remove_connections(struct service *service) +{ + struct connection *connection; + + connection = service->connections; + + while (connection) { + struct connection *tmp; + + tmp = connection->next; + remove_connection(service, connection); + connection = tmp; + } +} + static int remove_services(void) { struct service *c = services; @@ -353,6 +368,8 @@ static int remove_services(void) while (c) { struct service *next = c->next; + remove_connections(c); + if (c->name) free(c->name); From 703ce2e9414246b15fced07889c58f0acd691053 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Wed, 8 Mar 2017 00:06:35 +0100 Subject: [PATCH 33/91] helper/replacements.h: Add missing #include Change-Id: Ic6c47f7fbc999d00ef3211c1fa44867e3aabc321 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4057 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/helper/replacements.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helper/replacements.h b/src/helper/replacements.h index f43b7e0f3..ac5009549 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -25,6 +25,8 @@ #ifndef OPENOCD_HELPER_REPLACEMENTS_H #define OPENOCD_HELPER_REPLACEMENTS_H +#include + /* MIN,MAX macros */ #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) From 83f313542f35b4551ba493930946c4813b39ee89 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 15 Dec 2016 09:40:49 +0100 Subject: [PATCH 34/91] helper/command.h: Add missing #includes Change-Id: I84650a51cdb015f5e8ae933a3288f6e87f9fb80b Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4049 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/helper/command.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helper/command.h b/src/helper/command.h index 1a26c0699..fc017326b 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -22,6 +22,8 @@ #ifndef OPENOCD_HELPER_COMMAND_H #define OPENOCD_HELPER_COMMAND_H +#include +#include #include /* To achieve C99 printf compatibility in MinGW, gnu_printf should be From 7417feab29d987a2a68e376913b7c7f0999c0769 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 15 Dec 2016 10:44:21 +0100 Subject: [PATCH 35/91] helper/types.h: Add missing #includes Change-Id: I02ae0fb9527c4b87308da9c2cab66c80d84579eb Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4050 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/helper/types.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/helper/types.h b/src/helper/types.h index 58c9e7245..a7dd2a816 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -22,7 +22,12 @@ #ifndef OPENOCD_HELPER_TYPES_H #define OPENOCD_HELPER_TYPES_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include +#include #ifdef HAVE_SYS_TYPES_H #include #endif From a4df0e02b2853be00ebcbcca81f39c99ae2b854c Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 16 Dec 2016 16:37:19 +0100 Subject: [PATCH 36/91] server/server.h: Add missing #include Change-Id: I9d0615f9218470d190223f7f6b5b406e5c7f2b11 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4051 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/server.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/server/server.h b/src/server/server.h index 68ad16d55..8c8062675 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -25,6 +25,10 @@ #ifndef OPENOCD_SERVER_SERVER_H #define OPENOCD_SERVER_SERVER_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #ifdef HAVE_NETINET_IN_H From 6c0590cb4d3e7701658279ee76d96e5c077fb256 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 12 Feb 2017 22:46:20 +0100 Subject: [PATCH 37/91] helper/command.h: Add missing #include for target_addr_t Change-Id: Ic406257c0da6e1889d4434cc98cf59c2b97aa30c Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4052 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/helper/command.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helper/command.h b/src/helper/command.h index fc017326b..f9c02e573 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -26,6 +26,8 @@ #include #include +#include + /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later */ From 35da3e1d948bdd8c86862c36fe83ada2c73c6e34 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Feb 2018 22:38:13 +0100 Subject: [PATCH 38/91] helper/configuration: free script_search_dirs and config_file_names Although the leak is negligible, the clean heap on exit will ease valgrind testing. Change-Id: If43f02fe594c30ceb1bea3259ea3e098d4b2d239 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4408 Tested-by: jenkins Reviewed-by: Marc Schink --- src/helper/configuration.c | 15 +++++++++++++++ src/helper/configuration.h | 2 ++ src/openocd.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/helper/configuration.c b/src/helper/configuration.c index 2a278838d..114ad2c6c 100644 --- a/src/helper/configuration.c +++ b/src/helper/configuration.c @@ -51,6 +51,21 @@ void add_config_command(const char *cfg) config_file_names[num_config_files] = NULL; } +void free_config(void) +{ + while (num_config_files) + free(config_file_names[--num_config_files]); + + free(config_file_names); + config_file_names = NULL; + + while (num_script_dirs) + free(script_search_dirs[--num_script_dirs]); + + free(script_search_dirs); + script_search_dirs = NULL; +} + /* return full path or NULL according to search rules */ char *find_file(const char *file) { diff --git a/src/helper/configuration.h b/src/helper/configuration.h index 3cbcd41f6..cc28efcdb 100644 --- a/src/helper/configuration.h +++ b/src/helper/configuration.h @@ -32,6 +32,8 @@ void add_config_command(const char *cfg); void add_script_search_dir(const char *dir); +void free_config(void); + int configuration_output_handler(struct command_context *cmd_ctx, const char *line); diff --git a/src/openocd.c b/src/openocd.c index 831bd17f2..05533aae3 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -349,6 +349,8 @@ int openocd_main(int argc, char *argv[]) adapter_quit(); + free_config(); + if (ERROR_FAIL == ret) return EXIT_FAILURE; else if (ERROR_OK != ret) From db268a3115b28c3c50c76a67d34113d619a54f89 Mon Sep 17 00:00:00 2001 From: Evan Hunter Date: Fri, 17 Jul 2015 12:44:11 +0100 Subject: [PATCH 39/91] Cortex-R : Remove commands which are not relevant to Cortex-R Change-Id: I8dec85150386c149ffdb7bf4e7e533f16bb63b84 Signed-off-by: Evan Hunter Reviewed-on: http://openocd.zylin.com/2877 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/cortex_a.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 9f7e38efc..8ed85ac88 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3493,13 +3493,6 @@ struct target_type cortexa_target = { }; static const struct command_registration cortex_r4_exec_command_handlers[] = { - { - .name = "cache_info", - .handler = cortex_a_handle_cache_info_command, - .mode = COMMAND_EXEC, - .help = "display information about target caches", - .usage = "", - }, { .name = "dbginit", .handler = cortex_a_handle_dbginit_command, @@ -3522,7 +3515,7 @@ static const struct command_registration cortex_r4_command_handlers[] = { .chain = arm_command_handlers, }, { - .chain = armv7a_command_handlers, + .chain = dap_command_handlers, }, { .name = "cortex_r4", From b4a01f8cdc943fe03a827513aad2f4df2d2a7399 Mon Sep 17 00:00:00 2001 From: Omair Javaid Date: Mon, 22 Jan 2018 02:57:19 +0500 Subject: [PATCH 40/91] Allow generation of nested target defined types in gdb target xml This patch adds support to generate multiple nested architecture defined data types in gdb target xml generated by openOCD. Architecture defined structs, unions, vectors nested in one or more architecture defined types can be generated now. Example: Change-Id: I0f3c5c6daf3d22cde7e4b7b4165d2e97e25872f7 Signed-off-by: Omair Javaid Reviewed-on: http://openocd.zylin.com/4372 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 75 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index a15c5bb81..5319106a3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1946,12 +1946,45 @@ static const char *gdb_get_reg_type_name(enum reg_type type) return "int"; /* "int" as default value */ } +static int lookup_add_arch_defined_types(char const **arch_defined_types_list[], const char *type_id, + int *num_arch_defined_types) +{ + int tbl_sz = *num_arch_defined_types; + + if (type_id != NULL && (strcmp(type_id, ""))) { + for (int j = 0; j < (tbl_sz + 1); j++) { + if (!((*arch_defined_types_list)[j])) { + (*arch_defined_types_list)[tbl_sz++] = type_id; + *arch_defined_types_list = realloc(*arch_defined_types_list, + sizeof(char *) * (tbl_sz + 1)); + (*arch_defined_types_list)[tbl_sz] = NULL; + *num_arch_defined_types = tbl_sz; + return 1; + } else { + if (!strcmp((*arch_defined_types_list)[j], type_id)) + return 0; + } + } + } + + return -1; +} + static int gdb_generate_reg_type_description(struct target *target, - char **tdesc, int *pos, int *size, struct reg_data_type *type) + char **tdesc, int *pos, int *size, struct reg_data_type *type, + char const **arch_defined_types_list[], int * num_arch_defined_types) { int retval = ERROR_OK; if (type->type_class == REG_TYPE_CLASS_VECTOR) { + struct reg_data_type *data_type = type->reg_type_vector->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } /* */ xml_printf(&retval, tdesc, pos, size, "\n", @@ -1959,6 +1992,20 @@ static int gdb_generate_reg_type_description(struct target *target, type->reg_type_vector->count); } else if (type->type_class == REG_TYPE_CLASS_UNION) { + struct reg_data_type_union_field *field; + field = type->reg_type_union->fields; + while (field != NULL) { + struct reg_data_type *data_type = field->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } + + field = field->next; + } /* * ... * */ @@ -1966,7 +2013,6 @@ static int gdb_generate_reg_type_description(struct target *target, "\n", type->id); - struct reg_data_type_union_field *field; field = type->reg_type_union->fields; while (field != NULL) { xml_printf(&retval, tdesc, pos, size, @@ -1999,6 +2045,17 @@ static int gdb_generate_reg_type_description(struct target *target, field = field->next; } } else { + while (field != NULL) { + struct reg_data_type *data_type = field->type; + if (data_type->type == REG_TYPE_ARCH_DEFINED) { + if (lookup_add_arch_defined_types(arch_defined_types_list, data_type->id, + num_arch_defined_types)) + gdb_generate_reg_type_description(target, tdesc, pos, size, data_type, + arch_defined_types_list, + num_arch_defined_types); + } + } + /* * ... * */ @@ -2091,11 +2148,15 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o struct reg **reg_list = NULL; int reg_list_size; char const **features = NULL; + char const **arch_defined_types = NULL; int feature_list_size = 0; + int num_arch_defined_types = 0; char *tdesc = NULL; int pos = 0; int size = 0; + arch_defined_types = calloc(1, sizeof(char *)); + retval = target_get_gdb_reg_list(target, ®_list, ®_list_size, REG_CLASS_ALL); @@ -2148,8 +2209,13 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o if (reg_list[i]->reg_data_type != NULL) { if (reg_list[i]->reg_data_type->type == REG_TYPE_ARCH_DEFINED) { /* generate reg_data_type); + if (lookup_add_arch_defined_types(&arch_defined_types, + reg_list[i]->reg_data_type->id, + &num_arch_defined_types)) + gdb_generate_reg_type_description(target, &tdesc, &pos, &size, + reg_list[i]->reg_data_type, + &arch_defined_types, + &num_arch_defined_types); type_str = reg_list[i]->reg_data_type->id; } else { @@ -2199,6 +2265,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o error: free(features); free(reg_list); + free(arch_defined_types); if (retval == ERROR_OK) *tdesc_out = tdesc; From a48264414e53d99ffe69df0687abf1effb13be22 Mon Sep 17 00:00:00 2001 From: Omair Javaid Date: Mon, 22 Jan 2018 03:26:01 +0500 Subject: [PATCH 41/91] Support AArch64 SIMD/FP registers read/write This patch adds support in openOCD to read/write AArch64 SIMD/FP registers. This patch depends on a previous patch which adds support to generation of target xml by openOCD with nested architecture defined types. AArch64 SIMD/FP registers assumes various types and to support all types we implement them as architecture defined type aarch64v which in turn consists of various architecture defined types. This is compatible with AArch64-FPU target xml in GDB. Please refer to binutils-gdb/gdb/features/aarch64-fpu.xml Change-Id: I7ffb0c21b3c2e08f13720b765408b30aab2a9808 Signed-off-by: Omair Javaid Reviewed-on: http://openocd.zylin.com/4373 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/arm.h | 2 +- src/target/armv8.c | 340 +++++++++++++++++++++++++++++++------ src/target/armv8.h | 59 ++++++- src/target/armv8_dpm.c | 80 ++++++--- src/target/armv8_opcodes.h | 8 + 5 files changed, 404 insertions(+), 85 deletions(-) diff --git a/src/target/arm.h b/src/target/arm.h index eb4a51f98..c7963dd65 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -225,7 +225,7 @@ struct arm_reg { enum arm_mode mode; struct target *target; struct arm *arm; - uint8_t value[8]; + uint8_t value[16]; }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm); diff --git a/src/target/armv8.c b/src/target/armv8.c index 1b8e45016..93644aabc 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -135,6 +135,16 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv ARMV8_MRS_DSPSR(0), &value); value_64 = value; break; + case ARMV8_FPSR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_FPSR(0), &value); + value_64 = value; + break; + case ARMV8_FPCR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_FPCR(0), &value); + value_64 = value; + break; case ARMV8_ELR_EL1: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_ELR_EL1, 0), &value_64); @@ -184,6 +194,31 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv if (retval == ERROR_OK && regval != NULL) *regval = value_64; + else + retval = ERROR_FAIL; + + return retval; +} + +static int armv8_read_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V31: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 1), hvalue); + if (retval != ERROR_OK) + return retval; + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MOV_GPR_VFP(0, (regnum - ARMV8_V0), 0), lvalue); + break; + + default: + retval = ERROR_FAIL; + break; + } return retval; } @@ -216,6 +251,18 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu ARMV8_MSR_DSPSR(0), value); break; + case ARMV8_FPSR: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_FPSR(0), + value); + break; + case ARMV8_FPCR: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_FPCR(0), + value); + break; /* registers clobbered by taking exception in debug state */ case ARMV8_ELR_EL1: retval = dpm->instr_write_data_r0_64(dpm, @@ -267,6 +314,29 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu return retval; } +static int armv8_write_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V31: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 1), hvalue); + if (retval != ERROR_OK) + return retval; + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MOV_VFP_GPR((regnum - ARMV8_V0), 0, 0), lvalue); + break; + + default: + retval = ERROR_FAIL; + break; + } + + return retval; +} + static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *regval) { struct arm_dpm *dpm = &armv8->dpm; @@ -431,6 +501,9 @@ void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) if (is_aarch64) { armv8->read_reg_u64 = armv8_read_reg; armv8->write_reg_u64 = armv8_write_reg; + armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch64; + armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch64; + } else { armv8->read_reg_u64 = armv8_read_reg32; armv8->write_reg_u64 = armv8_write_reg32; @@ -897,6 +970,110 @@ int armv8_arch_state(struct target *target) return ERROR_OK; } +static struct reg_data_type aarch64_vector_base_types[] = { + {REG_TYPE_IEEE_DOUBLE, "ieee_double", 0, {NULL} }, + {REG_TYPE_UINT64, "uint64", 0, {NULL} }, + {REG_TYPE_INT64, "int64", 0, {NULL} }, + {REG_TYPE_IEEE_SINGLE, "ieee_single", 0, {NULL} }, + {REG_TYPE_UINT32, "uint32", 0, {NULL} }, + {REG_TYPE_INT32, "int32", 0, {NULL} }, + {REG_TYPE_UINT16, "uint16", 0, {NULL} }, + {REG_TYPE_INT16, "int16", 0, {NULL} }, + {REG_TYPE_UINT8, "uint8", 0, {NULL} }, + {REG_TYPE_INT8, "int8", 0, {NULL} }, + {REG_TYPE_UINT128, "uint128", 0, {NULL} }, + {REG_TYPE_INT128, "int128", 0, {NULL} } +}; + +static struct reg_data_type_vector aarch64_vector_types[] = { + {aarch64_vector_base_types + 0, 2}, + {aarch64_vector_base_types + 1, 2}, + {aarch64_vector_base_types + 2, 2}, + {aarch64_vector_base_types + 3, 4}, + {aarch64_vector_base_types + 4, 4}, + {aarch64_vector_base_types + 5, 4}, + {aarch64_vector_base_types + 6, 8}, + {aarch64_vector_base_types + 7, 8}, + {aarch64_vector_base_types + 8, 16}, + {aarch64_vector_base_types + 9, 16}, + {aarch64_vector_base_types + 10, 01}, + {aarch64_vector_base_types + 11, 01}, +}; + +static struct reg_data_type aarch64_fpu_vector[] = { + {REG_TYPE_ARCH_DEFINED, "v2d", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 0} }, + {REG_TYPE_ARCH_DEFINED, "v2u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 1} }, + {REG_TYPE_ARCH_DEFINED, "v2i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 2} }, + {REG_TYPE_ARCH_DEFINED, "v4f", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 3} }, + {REG_TYPE_ARCH_DEFINED, "v4u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 4} }, + {REG_TYPE_ARCH_DEFINED, "v4i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 5} }, + {REG_TYPE_ARCH_DEFINED, "v8u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 6} }, + {REG_TYPE_ARCH_DEFINED, "v8i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 7} }, + {REG_TYPE_ARCH_DEFINED, "v16u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 8} }, + {REG_TYPE_ARCH_DEFINED, "v16i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 9} }, + {REG_TYPE_ARCH_DEFINED, "v1u", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 10} }, + {REG_TYPE_ARCH_DEFINED, "v1i", REG_TYPE_CLASS_VECTOR, {aarch64_vector_types + 11} }, +}; + +static struct reg_data_type_union_field aarch64_union_fields_vnd[] = { + {"f", aarch64_fpu_vector + 0, aarch64_union_fields_vnd + 1}, + {"u", aarch64_fpu_vector + 1, aarch64_union_fields_vnd + 2}, + {"s", aarch64_fpu_vector + 2, NULL}, +}; + +static struct reg_data_type_union_field aarch64_union_fields_vns[] = { + {"f", aarch64_fpu_vector + 3, aarch64_union_fields_vns + 1}, + {"u", aarch64_fpu_vector + 4, aarch64_union_fields_vns + 2}, + {"s", aarch64_fpu_vector + 5, NULL}, +}; + +static struct reg_data_type_union_field aarch64_union_fields_vnh[] = { + {"u", aarch64_fpu_vector + 6, aarch64_union_fields_vnh + 1}, + {"s", aarch64_fpu_vector + 7, NULL}, +}; + +static struct reg_data_type_union_field aarch64_union_fields_vnb[] = { + {"u", aarch64_fpu_vector + 8, aarch64_union_fields_vnb + 1}, + {"s", aarch64_fpu_vector + 9, NULL}, +}; + +static struct reg_data_type_union_field aarch64_union_fields_vnq[] = { + {"u", aarch64_fpu_vector + 10, aarch64_union_fields_vnq + 1}, + {"s", aarch64_fpu_vector + 11, NULL}, +}; + +static struct reg_data_type_union aarch64_union_types[] = { + {aarch64_union_fields_vnd}, + {aarch64_union_fields_vns}, + {aarch64_union_fields_vnh}, + {aarch64_union_fields_vnb}, + {aarch64_union_fields_vnq}, +}; + +static struct reg_data_type aarch64_fpu_union[] = { + {REG_TYPE_ARCH_DEFINED, "vnd", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 0} }, + {REG_TYPE_ARCH_DEFINED, "vns", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 1} }, + {REG_TYPE_ARCH_DEFINED, "vnh", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 2} }, + {REG_TYPE_ARCH_DEFINED, "vnb", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 3} }, + {REG_TYPE_ARCH_DEFINED, "vnq", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64_union_types + 4} }, +}; + +static struct reg_data_type_union_field aarch64v_union_fields[] = { + {"d", aarch64_fpu_union + 0, aarch64v_union_fields + 1}, + {"s", aarch64_fpu_union + 1, aarch64v_union_fields + 2}, + {"h", aarch64_fpu_union + 2, aarch64v_union_fields + 3}, + {"b", aarch64_fpu_union + 3, aarch64v_union_fields + 4}, + {"q", aarch64_fpu_union + 4, NULL}, +}; + +static struct reg_data_type_union aarch64v_union[] = { + {aarch64v_union_fields} +}; + +static struct reg_data_type aarch64v[] = { + {REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64v_union} }, +}; + static const struct { unsigned id; const char *name; @@ -905,55 +1082,100 @@ static const struct { enum reg_type type; const char *group; const char *feature; + struct reg_data_type *data_type; } armv8_regs[] = { - { ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core", NULL}, - { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, + { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, - { ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core", NULL}, - { ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + { ARMV8_V0, "v0", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V1, "v1", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V2, "v2", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V3, "v3", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V4, "v4", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V5, "v5", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V6, "v6", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V7, "v7", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V8, "v8", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V9, "v9", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V10, "v10", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V11, "v11", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V12, "v12", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V13, "v13", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V14, "v14", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V15, "v15", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V16, "v16", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V17, "v17", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V18, "v18", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V19, "v19", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V20, "v20", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V21, "v21", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V22, "v22", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V23, "v23", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V24, "v24", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V25, "v25", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V26, "v26", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V27, "v27", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V28, "v28", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V29, "v29", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V30, "v30", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_V31, "v31", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, + { ARMV8_FPSR, "fpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL}, + { ARMV8_FPCR, "fpcr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "simdfp", "org.gnu.gdb.aarch64.fpu", NULL}, - { ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + { 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", + NULL}, + { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, - { ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, - { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + { 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", + NULL}, + { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "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", + NULL}, + { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked", + NULL}, }; static const struct { @@ -1004,15 +1226,23 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf) struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); - uint64_t value = buf_get_u64(buf, 0, 64); + uint64_t value = buf_get_u64(buf, 0, reg->size); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - if (reg == arm->cpsr) { - armv8_set_cpsr(arm, (uint32_t)value); - } else { + if (reg->size <= 64) { + if (reg == arm->cpsr) + armv8_set_cpsr(arm, (uint32_t)value); + else { + buf_set_u64(reg->value, 0, reg->size, value); + reg->valid = 1; + } + } else if (reg->size <= 128) { + uint64_t hvalue = buf_get_u64(buf + 8, 0, reg->size - 64); + buf_set_u64(reg->value, 0, 64, value); + buf_set_u64(reg->value + 8, 0, reg->size - 64, hvalue); reg->valid = 1; } @@ -1122,11 +1352,15 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) } else LOG_ERROR("unable to allocate feature list"); - reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); - if (reg_list[i].reg_data_type) - reg_list[i].reg_data_type->type = armv8_regs[i].type; - else - LOG_ERROR("unable to allocate reg type list"); + if (armv8_regs[i].data_type == NULL) { + reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list[i].reg_data_type) + reg_list[i].reg_data_type->type = armv8_regs[i].type; + else + LOG_ERROR("unable to allocate reg type list"); + } else + reg_list[i].reg_data_type = armv8_regs[i].data_type; + } arm->cpsr = reg_list + ARMV8_xPSR; @@ -1200,7 +1434,7 @@ int armv8_get_gdb_reg_list(struct target *target, switch (reg_class) { case REG_CLASS_GENERAL: - *reg_list_size = ARMV8_ELR_EL1; + *reg_list_size = ARMV8_V0; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) diff --git a/src/target/armv8.h b/src/target/armv8.h index 0f3e66f65..6525d2601 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -63,17 +63,52 @@ enum { ARMV8_PC = 32, ARMV8_xPSR = 33, - ARMV8_ELR_EL1 = 34, - ARMV8_ESR_EL1 = 35, - ARMV8_SPSR_EL1 = 36, + ARMV8_V0 = 34, + ARMV8_V1, + ARMV8_V2, + ARMV8_V3, + ARMV8_V4, + ARMV8_V5, + ARMV8_V6, + ARMV8_V7, + ARMV8_V8, + ARMV8_V9, + ARMV8_V10, + ARMV8_V11, + ARMV8_V12, + ARMV8_V13, + ARMV8_V14, + ARMV8_V15, + ARMV8_V16, + ARMV8_V17, + ARMV8_V18, + ARMV8_V19, + ARMV8_V20, + ARMV8_V21, + ARMV8_V22, + ARMV8_V23, + ARMV8_V24, + ARMV8_V25, + ARMV8_V26, + ARMV8_V27, + ARMV8_V28, + ARMV8_V29, + ARMV8_V30, + ARMV8_V31, + ARMV8_FPSR, + ARMV8_FPCR, - ARMV8_ELR_EL2 = 37, - ARMV8_ESR_EL2 = 38, - ARMV8_SPSR_EL2 = 39, + ARMV8_ELR_EL1 = 68, + ARMV8_ESR_EL1 = 69, + ARMV8_SPSR_EL1 = 70, - ARMV8_ELR_EL3 = 40, - ARMV8_ESR_EL3 = 41, - ARMV8_SPSR_EL3 = 42, + ARMV8_ELR_EL2 = 71, + ARMV8_ESR_EL2 = 72, + ARMV8_SPSR_EL2 = 73, + + ARMV8_ELR_EL3 = 74, + ARMV8_ESR_EL3 = 75, + ARMV8_SPSR_EL3 = 76, ARMV8_LAST_REG, }; @@ -179,6 +214,12 @@ struct armv8_common { int (*read_reg_u64)(struct armv8_common *armv8, int num, uint64_t *value); int (*write_reg_u64)(struct armv8_common *armv8, int num, uint64_t value); + /* SIMD/FPU registers read/write interface */ + int (*read_reg_u128)(struct armv8_common *armv8, int num, + uint64_t *lvalue, uint64_t *hvalue); + int (*write_reg_u128)(struct armv8_common *armv8, int num, + uint64_t lvalue, uint64_t hvalue); + int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index c79b1a0ff..91b2f5171 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -650,21 +650,37 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; - uint64_t value_64; - int retval; + int retval = ERROR_FAIL; - retval = armv8->read_reg_u64(armv8, regnum, &value_64); + if (r->size <= 64) { + uint64_t value_64; + retval = armv8->read_reg_u64(armv8, regnum, &value_64); - if (retval == ERROR_OK) { - r->valid = true; - r->dirty = false; - buf_set_u64(r->value, 0, r->size, value_64); - if (r->size == 64) - LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64); - else - LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64); + if (retval == ERROR_OK) { + r->valid = true; + r->dirty = false; + buf_set_u64(r->value, 0, r->size, value_64); + if (r->size == 64) + LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64); + else + LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64); + } + } else if (r->size <= 128) { + uint64_t lvalue = 0, hvalue = 0; + retval = armv8->read_reg_u128(armv8, regnum, &lvalue, &hvalue); + + if (retval == ERROR_OK) { + r->valid = true; + r->dirty = false; + + buf_set_u64(r->value, 0, 64, lvalue); + buf_set_u64(r->value + 8, 0, r->size - 64, hvalue); + + LOG_DEBUG("READ: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue); + LOG_DEBUG("READ: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); + } } - return ERROR_OK; + return retval; } /* @@ -674,20 +690,36 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval = ERROR_FAIL; - uint64_t value_64; - value_64 = buf_get_u64(r->value, 0, r->size); + if (r->size <= 64) { + uint64_t value_64; - retval = armv8->write_reg_u64(armv8, regnum, value_64); - if (retval == ERROR_OK) { - r->dirty = false; - if (r->size == 64) - LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64); - else - LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64); + value_64 = buf_get_u64(r->value, 0, r->size); + retval = armv8->write_reg_u64(armv8, regnum, value_64); + + if (retval == ERROR_OK) { + r->dirty = false; + if (r->size == 64) + LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64); + else + LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64); + } + } else if (r->size <= 128) { + uint64_t lvalue, hvalue; + + lvalue = buf_get_u64(r->value, 0, 64); + hvalue = buf_get_u64(r->value + 8, 0, r->size - 64); + retval = armv8->write_reg_u128(armv8, regnum, lvalue, hvalue); + + if (retval == ERROR_OK) { + r->dirty = false; + + LOG_DEBUG("WRITE: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue); + LOG_DEBUG("WRITE: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue); + } } - return ERROR_OK; + return retval; } /** @@ -745,6 +777,10 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) if (r->valid) continue; + /* Skip reading FP-SIMD registers */ + if (r->number >= ARMV8_V0 && r->number <= ARMV8_FPCR) + continue; + /* * Only read registers that are available from the * current EL (or core mode). diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h index 987198a87..3fda29668 100644 --- a/src/target/armv8_opcodes.h +++ b/src/target/armv8_opcodes.h @@ -167,6 +167,14 @@ #define ARMV8_STRH_IP(Rd, Rn) (0x78002400 | (Rn << 5) | Rd) #define ARMV8_STRW_IP(Rd, Rn) (0xb8004400 | (Rn << 5) | Rd) +#define ARMV8_MOV_GPR_VFP(Rd, Rn, Index) (0x4e083c00 | (Index << 20) | (Rn << 5) | Rd) +#define ARMV8_MOV_VFP_GPR(Rd, Rn, Index) (0x4e081c00 | (Index << 20) | (Rn << 5) | Rd) + +#define ARMV8_MRS_FPCR(Rt) (0xd53b4400 | (Rt)) +#define ARMV8_MRS_FPSR(Rt) (0xd53b4420 | (Rt)) +#define ARMV8_MSR_FPCR(Rt) (0xd51b4400 | (Rt)) +#define ARMV8_MSR_FPSR(Rt) (0xd51b4420 | (Rt)) + #define ARMV8_SYS(System, Rt) (0xD5080000 | ((System) << 5) | Rt) enum armv8_opcode { From 2830008be0f782f22e09f6ecd1764e168560de40 Mon Sep 17 00:00:00 2001 From: Omair Javaid Date: Mon, 5 Mar 2018 16:25:21 +0500 Subject: [PATCH 42/91] Support for AArch32 SIMD/Floating-point registers This patch adds support for read/write of SIMD and floating-point register in AArch32 mode. This patch is tested using Raspberry Pi3 halted in AArch32 mode with FP/SIMD enabled. Software need to make sure floating-point and SIMD unit is enabled. Change-Id: I2b3b8af02257c6420e5a70c6f4c91f839c1f5ee5 Signed-off-by: Omair Javaid Reviewed-on: http://openocd.zylin.com/4446 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv8.c | 190 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 171 insertions(+), 19 deletions(-) diff --git a/src/target/armv8.c b/src/target/armv8.c index 93644aabc..86bb8707e 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -408,6 +408,11 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re ARMV8_MRS_xPSR_T1(1, 0), &value); break; + case ARMV8_FPSR: + /* "VMRS r0, FPSCR"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMRS(0), &value); + break; default: retval = ERROR_FAIL; break; @@ -419,6 +424,56 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re return retval; } +static int armv8_read_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t *lvalue, uint64_t *hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; + uint32_t value_r0 = 0, value_r1 = 0; + unsigned num = (regnum - ARMV8_V0) << 1; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V15: + /* we are going to write R1, mark it dirty */ + reg_r1->dirty = true; + /* move from double word register to r0:r1: "vmov r0, r1, vm" + * then read r0 via dcc + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), + &value_r0); + /* read r1 via dcc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + if (retval == ERROR_OK) { + *lvalue = value_r1; + *lvalue = ((*lvalue) << 32) | value_r0; + } else + return retval; + + num++; + /* repeat above steps for high 64 bits of V register */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, (num >> 4), (num & 0xf)), + &value_r0); + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + if (retval == ERROR_OK) { + *hvalue = value_r1; + *hvalue = ((*hvalue) << 32) | value_r0; + } else + return retval; + break; + default: + retval = ERROR_FAIL; + break; + } + + return retval; +} + static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value) { struct arm_dpm *dpm = &armv8->dpm; @@ -487,6 +542,11 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va ARMV8_MSR_GP_xPSR_T1(1, 0, 15), value); break; + case ARMV8_FPSR: + /* move to r0 from DCC, then "VMSR FPSCR, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMSR(0), value); + break; default: retval = ERROR_FAIL; break; @@ -496,6 +556,50 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va } +static int armv8_write_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, uint64_t lvalue, uint64_t hvalue) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = &armv8->dpm; + struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; + uint32_t value_r0 = 0, value_r1 = 0; + unsigned num = (regnum - ARMV8_V0) << 1; + + switch (regnum) { + case ARMV8_V0 ... ARMV8_V15: + /* we are going to write R1, mark it dirty */ + reg_r1->dirty = true; + value_r1 = lvalue >> 32; + value_r0 = lvalue & 0xFFFFFFFF; + /* write value_r1 to r1 via dcc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + /* write value_r0 to r0 via dcc then, + * move to double word register from r0:r1: "vmov vm, r0, r1" + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), + value_r0); + + num++; + /* repeat above steps for high 64 bits of V register */ + value_r1 = hvalue >> 32; + value_r0 = hvalue & 0xFFFFFFFF; + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMOV(0, 1, 0, (num >> 4), (num & 0xf)), + value_r0); + break; + default: + retval = ERROR_FAIL; + break; + } + + return retval; +} + void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) { if (is_aarch64) { @@ -507,6 +611,8 @@ void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) } else { armv8->read_reg_u64 = armv8_read_reg32; armv8->write_reg_u64 = armv8_write_reg32; + armv8->read_reg_u128 = armv8_read_reg_simdfp_aarch32; + armv8->write_reg_u128 = armv8_write_reg_simdfp_aarch32; } } @@ -1180,6 +1286,7 @@ static const struct { static const struct { unsigned id; + unsigned mapping; const char *name; unsigned bits; enum arm_mode mode; @@ -1187,23 +1294,56 @@ static const struct { const char *group; const char *feature; } armv8_regs32[] = { - { ARMV8_R0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R1, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R2, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R3, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R4, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R5, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R6, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R7, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R8, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R9, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R10, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R11, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R12, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R13, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_R14, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_PC, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, - { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R0, 0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R1, 0, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R2, 0, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R3, 0, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R4, 0, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R5, 0, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R6, 0, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R7, 0, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R8, 0, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R9, 0, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R10, 0, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R11, 0, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R12, 0, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R13, 0, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R14, 0, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_PC, 0, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_xPSR, 0, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_V0, 0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V0, 8, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V1, 0, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V1, 8, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V2, 0, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V2, 8, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V3, 0, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V3, 8, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V4, 0, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V4, 8, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V5, 0, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V5, 8, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V6, 0, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V6, 8, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V7, 0, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V7, 8, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V8, 0, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V8, 8, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V9, 0, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V9, 8, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V10, 0, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V10, 8, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V11, 0, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V11, 8, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V12, 0, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V12, 8, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V13, 0, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V13, 8, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V14, 0, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V14, 8, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V15, 0, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_V15, 8, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARMV8_FPSR, 0, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "float", "org.gnu.gdb.arm.vfp"}, }; #define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs) @@ -1291,7 +1431,12 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf) if (reg64 == arm->cpsr) { armv8_set_cpsr(arm, value); } else { - buf_set_u32(reg->value, 0, 32, value); + if (reg->size <= 32) + buf_set_u32(reg->value, 0, 32, value); + else if (reg->size <= 64) { + uint64_t value64 = buf_get_u64(buf, 0, 64); + buf_set_u64(reg->value, 0, 64, value64); + } reg->valid = 1; reg64->valid = 1; } @@ -1376,7 +1521,7 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) for (i = 0; i < num_regs32; i++) { reg_list32[i].name = armv8_regs32[i].name; reg_list32[i].size = armv8_regs32[i].bits; - reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[0]; + reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[armv8_regs32[i].mapping]; reg_list32[i].type = &armv8_reg32_type; reg_list32[i].arch_info = &arch_info[armv8_regs32[i].id]; reg_list32[i].group = armv8_regs32[i].group; @@ -1461,6 +1606,13 @@ int armv8_get_gdb_reg_list(struct target *target, switch (reg_class) { case REG_CLASS_GENERAL: + *reg_list_size = ARMV8_R14 + 3; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < *reg_list_size; i++) + (*reg_list)[i] = cache32->reg_list + i; + + return ERROR_OK; case REG_CLASS_ALL: *reg_list_size = cache32->num_regs; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); From f18ca510b3430a515f28f19ea6c6731a40022fb6 Mon Sep 17 00:00:00 2001 From: Omair Javaid Date: Fri, 16 Feb 2018 03:08:51 +0500 Subject: [PATCH 43/91] Support for Arm VFP v3 registers read/write This patch adds support in openOCD to read/write Arm vector/floating point registers. This is compatible with Arm vfp v3 target xml in GDB. Please refer to binutils-gdb/gdb/features/arm/arm-vfpv3.xml Change-Id: Id4dd1bddef51c558f1a86300c1a876d159463f18 Signed-off-by: Omair Javaid Reviewed-on: http://openocd.zylin.com/4421 Reviewed-by: Matthias Welwarsky Tested-by: jenkins --- src/target/arm.h | 48 ++++++++++++++++ src/target/arm_dpm.c | 115 +++++++++++++++++++++++++++++++++++---- src/target/arm_opcodes.h | 24 ++++++++ src/target/armv4_5.c | 93 ++++++++++++++++++++++++++++++- src/target/cortex_a.c | 2 + 5 files changed, 269 insertions(+), 13 deletions(-) diff --git a/src/target/arm.h b/src/target/arm.h index c7963dd65..62fbb7368 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -77,6 +77,43 @@ enum arm_mode { ARM_MODE_ANY = -1 }; +/* VFPv3 internal register numbers mapping to d0:31 */ +enum { + ARM_VFP_V3_D0 = 51, + ARM_VFP_V3_D1, + ARM_VFP_V3_D2, + ARM_VFP_V3_D3, + ARM_VFP_V3_D4, + ARM_VFP_V3_D5, + ARM_VFP_V3_D6, + ARM_VFP_V3_D7, + ARM_VFP_V3_D8, + ARM_VFP_V3_D9, + ARM_VFP_V3_D10, + ARM_VFP_V3_D11, + ARM_VFP_V3_D12, + ARM_VFP_V3_D13, + ARM_VFP_V3_D14, + ARM_VFP_V3_D15, + ARM_VFP_V3_D16, + ARM_VFP_V3_D17, + ARM_VFP_V3_D18, + ARM_VFP_V3_D19, + ARM_VFP_V3_D20, + ARM_VFP_V3_D21, + ARM_VFP_V3_D22, + ARM_VFP_V3_D23, + ARM_VFP_V3_D24, + ARM_VFP_V3_D25, + ARM_VFP_V3_D26, + ARM_VFP_V3_D27, + ARM_VFP_V3_D28, + ARM_VFP_V3_D29, + ARM_VFP_V3_D30, + ARM_VFP_V3_D31, + ARM_VFP_V3_FPSCR, +}; + const char *arm_mode_name(unsigned psr_mode); bool is_arm_mode(unsigned psr_mode); @@ -89,6 +126,14 @@ enum arm_state { ARM_STATE_AARCH64, }; +/** ARM vector floating point enabled, if yes which version. */ +enum arm_vfp_version { + ARM_VFP_DISABLED, + ARM_VFP_V1, + ARM_VFP_V2, + ARM_VFP_V3, +}; + #define ARM_COMMON_MAGIC 0x0A450A45 /** @@ -145,6 +190,9 @@ struct arm { /** Flag reporting whether semihosting fileio operation is active. */ bool semihosting_hit_fileio; + /** Floating point or VFP version, 0 if disabled. */ + int arm_vfp_version; + /** Current semihosting operation. */ int semihosting_op; diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 3e8180c36..65790995a 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -131,6 +131,42 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) return retval; } +/* Read 64bit VFP registers */ +static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +{ + int retval = ERROR_FAIL; + uint32_t value_r0, value_r1; + + switch (regnum) { + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* move from double word register to r0:r1: "vmov r0, r1, vm" + * then read r0 via dcc + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); + /* read r1 via dcc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + break; + default: + + break; + } + + if (retval == ERROR_OK) { + buf_set_u32(r->value, 0, 32, value_r0); + buf_set_u32(r->value + 4, 0, 32, value_r1); + r->valid = true; + r->dirty = false; + LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name, + (unsigned) value_r0, (unsigned) value_r1); + } + + return retval; +} + /* just read the register -- rely on the core mode being right */ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { @@ -171,6 +207,14 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) break; } break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_read_reg_u64(dpm, r, regnum); + break; + case ARM_VFP_V3_FPSCR: + /* "VMRS r0, FPSCR"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMRS(0), &value); + break; default: /* 16: "MRS r0, CPSR"; then return via DCC * 17: "MRS r0, SPSR"; then return via DCC @@ -191,6 +235,40 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) return retval; } +/* Write 64bit VFP registers */ +static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +{ + int retval = ERROR_FAIL; + uint32_t value_r0 = buf_get_u32(r->value, 0, 32); + uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32); + + switch (regnum) { + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* write value_r1 to r1 via dcc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + /* write value_r0 to r0 via dcc then, + * move to double word register from r0:r1: "vmov vm, r0, r1" + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0); + break; + default: + + break; + } + + if (retval == ERROR_OK) { + r->dirty = false; + LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name, + (unsigned) value_r0, (unsigned) value_r1); + } + + return retval; +} + /* just write the register -- rely on the core mode being right */ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { @@ -208,6 +286,14 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) * read r0 from DCC; then "MOV pc, r0" */ retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_write_reg_u64(dpm, r, regnum); + break; + case ARM_VFP_V3_FPSCR: + /* move to r0 from DCC, then "VMSR FPSCR, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMSR(0), value); + break; default: /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" @@ -262,14 +348,16 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) if (retval != ERROR_OK) return retval; - /* read R0 first (it's used for scratch), then CPSR */ - r = arm->core_cache->reg_list + 0; - if (!r->valid) { - retval = dpm_read_reg(dpm, r, 0); - if (retval != ERROR_OK) - goto fail; + /* read R0 and R1 first (it's used for scratch), then CPSR */ + for (unsigned i = 0; i < 2; i++) { + r = arm->core_cache->reg_list + i; + if (!r->valid) { + retval = dpm_read_reg(dpm, r, i); + if (retval != ERROR_OK) + goto fail; + } + r->dirty = true; } - r->dirty = true; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr); if (retval != ERROR_OK) @@ -279,7 +367,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) arm_set_cpsr(arm, cpsr); /* REVISIT we can probably avoid reading R1..R14, saving time... */ - for (unsigned i = 1; i < 16; i++) { + for (unsigned i = 2; i < 16; i++) { r = arm_reg_current(arm, i); if (r->valid) continue; @@ -412,8 +500,8 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) did_write = false; - /* check everything except our scratch register R0 */ - for (unsigned i = 1; i < cache->num_regs; i++) { + /* check everything except our scratch registers R0 and R1 */ + for (unsigned i = 2; i < cache->num_regs; i++) { struct arm_reg *r; unsigned regnum; @@ -540,6 +628,7 @@ static enum arm_mode dpm_mapmode(struct arm *arm, /* r13/sp, and r14/lr are always shadowed */ case 13: case 14: + case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR: return mode; default: LOG_WARNING("invalid register #%u", num); @@ -561,7 +650,8 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; - if (regnum < 0 || regnum > 16) + if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) || + (regnum > ARM_VFP_V3_FPSCR)) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { @@ -604,7 +694,8 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r, int retval; - if (regnum < 0 || regnum > 16) + if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) || + (regnum > ARM_VFP_V3_FPSCR)) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { diff --git a/src/target/arm_opcodes.h b/src/target/arm_opcodes.h index a53fee71e..482abe630 100644 --- a/src/target/arm_opcodes.h +++ b/src/target/arm_opcodes.h @@ -132,6 +132,30 @@ */ #define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm)) +/* Copies two words from two ARM core registers + * into a doubleword extension register, or + * from a doubleword extension register to two ARM core registers. + * See Armv7-A arch reference manual section A8.8.345 + * Rt: Arm core register 1 + * Rt2: Arm core register 2 + * Vm: The doubleword extension register + * M: m = UInt(M:Vm); + * op: to_arm_registers = (op == ‘1’); + */ +#define ARMV4_5_VMOV(op, Rt2, Rt, M, Vm) \ + (0xec400b10 | ((op) << 20) | ((Rt2) << 16) | \ + ((Rt) << 12) | ((M) << 5) | (Vm)) + +/* Moves the value of the FPSCR to an ARM core register + * Rt: Arm core register + */ +#define ARMV4_5_VMRS(Rt) (0xeef10a10 | ((Rt) << 12)) + +/* Moves the value of an ARM core register to the FPSCR. + * Rt: Arm core register + */ +#define ARMV4_5_VMSR(Rt) (0xeee10a10 | ((Rt) << 12)) + /* Store data from coprocessor to consecutive memory * See Armv7-A arch doc section A8.6.187 * P: 1=index mode (offset from Rn) diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 48050b078..a6fadaa0b 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -340,6 +340,50 @@ static const struct { }; +static const struct { + unsigned int id; + const char *name; + uint32_t bits; + enum arm_mode mode; + enum reg_type type; + const char *group; + const char *feature; +} arm_vfp_v3_regs[] = { + { ARM_VFP_V3_D0, "d0", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D1, "d1", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D2, "d2", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D3, "d3", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D4, "d4", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D5, "d5", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D6, "d6", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D7, "d7", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D8, "d8", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D9, "d9", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D10, "d10", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D11, "d11", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D12, "d12", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D13, "d13", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D14, "d14", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D15, "d15", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D16, "d16", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D17, "d17", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D18, "d18", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D19, "d19", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D20, "d20", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D21, "d21", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D22, "d22", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D23, "d23", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D24, "d24", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D25, "d25", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D26, "d26", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D27, "d27", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D28, "d28", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D29, "d29", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D30, "d30", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_D31, "d31", 64, ARM_MODE_ANY, REG_TYPE_IEEE_DOUBLE, NULL, "org.gnu.gdb.arm.vfp"}, + { ARM_VFP_V3_FPSCR, "fpscr", 32, ARM_MODE_ANY, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp"}, +}; + /* map core mode (USR, FIQ, ...) and register number to * indices into the register cache */ @@ -567,6 +611,10 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) } } else { buf_set_u32(reg->value, 0, 32, value); + if (reg->size == 64) { + value = buf_get_u32(buf + 4, 0, 32); + buf_set_u32(reg->value + 4, 0, 32, value); + } reg->valid = 1; } reg->dirty = 1; @@ -582,6 +630,10 @@ static const struct reg_arch_type arm_reg_type = { struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) { int num_regs = ARRAY_SIZE(arm_core_regs); + int num_core_regs = num_regs; + if (arm->arm_vfp_version == ARM_VFP_V3) + num_regs += ARRAY_SIZE(arm_vfp_v3_regs); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg)); @@ -599,7 +651,7 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) cache->reg_list = reg_list; cache->num_regs = 0; - for (i = 0; i < num_regs; i++) { + for (i = 0; i < num_core_regs; i++) { /* Skip registers this core doesn't expose */ if (arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_MODE_MON) @@ -651,9 +703,38 @@ struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) cache->num_regs++; } + int j; + for (i = num_core_regs, j = 0; i < num_regs; i++, j++) { + reg_arch_info[i].num = arm_vfp_v3_regs[j].id; + reg_arch_info[i].mode = arm_vfp_v3_regs[j].mode; + reg_arch_info[i].target = target; + reg_arch_info[i].arm = arm; + + reg_list[i].name = arm_vfp_v3_regs[j].name; + reg_list[i].number = arm_vfp_v3_regs[j].id; + reg_list[i].size = arm_vfp_v3_regs[j].bits; + reg_list[i].value = reg_arch_info[i].value; + reg_list[i].type = &arm_reg_type; + reg_list[i].arch_info = ®_arch_info[i]; + reg_list[i].exist = true; + + reg_list[i].caller_save = false; + + reg_list[i].reg_data_type = malloc(sizeof(struct reg_data_type)); + reg_list[i].reg_data_type->type = arm_vfp_v3_regs[j].type; + + reg_list[i].feature = malloc(sizeof(struct reg_feature)); + reg_list[i].feature->name = arm_vfp_v3_regs[j].feature; + + reg_list[i].group = arm_vfp_v3_regs[j].group; + + cache->num_regs++; + } + arm->pc = reg_list + 15; arm->cpsr = reg_list + ARMV4_5_CPSR; arm->core_cache = cache; + return cache; } @@ -1229,6 +1310,10 @@ int arm_get_gdb_reg_list(struct target *target, case REG_CLASS_ALL: *reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51); + unsigned int list_size_core = *reg_list_size; + if (arm->arm_vfp_version == ARM_VFP_V3) + *reg_list_size += 33; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) @@ -1249,6 +1334,12 @@ int arm_get_gdb_reg_list(struct target *target, (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[24]->size = 0; + if (arm->arm_vfp_version == ARM_VFP_V3) { + unsigned int num_core_regs = ARRAY_SIZE(arm_core_regs); + for (i = 0; i < 33; i++) + (*reg_list)[list_size_core + i] = &(arm->core_cache->reg_list[num_core_regs + i]); + } + return ERROR_OK; break; diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 8ed85ac88..37098afd1 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3178,6 +3178,8 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp) cortex_a->armv7a_common.is_armv7r = false; + cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3; + return cortex_a_init_arch_info(target, cortex_a, target->tap); } From bfc5c764df145f68835543119865eabe462e19c2 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Sun, 15 Nov 2015 09:18:57 +0100 Subject: [PATCH 44/91] armv7a: cache ttbcr and ttb0/1 on debug state entry Instead of re-reading ttbcr and ttb0/1 whenever a virt2phys translation is done, cache the values once when entering debug state. Use the cached values in armv7a_mmu_translate_va(). Change-Id: I1bc5349ad2f19b2dd75bdd48468a2c1f1e028699 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3112 Tested-by: jenkins --- src/target/armv7a.c | 47 ++++++++++++++++++--------------------------- src/target/armv7a.h | 1 + 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/target/armv7a.c b/src/target/armv7a.c index db72afd21..183fde1bf 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -129,9 +129,13 @@ static int armv7a_read_ttbcr(struct target *target) struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttbcr, ttbcr_n; - int retval = dpm->prepare(dpm); + int ttbidx; + int retval; + + retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; + /* MRC p15,0,,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 2, 0, 2), @@ -145,6 +149,15 @@ static int armv7a_read_ttbcr(struct target *target) armv7a->armv7a_mmu.ttbcr = ttbcr; armv7a->armv7a_mmu.cached = 1; + for (ttbidx = 0; ttbidx < 2; ttbidx++) { + /* MRC p15,0,,c2,c0,ttbidx */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx), + &armv7a->armv7a_mmu.ttbr[ttbidx]); + if (retval != ERROR_OK) + goto done; + } + /* * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition), * document # ARM DDI 0406C @@ -182,42 +195,21 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) uint32_t second_lvl_descriptor = 0x0; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttbidx = 0; /* default to ttbr0 */ uint32_t ttb_mask; uint32_t va_mask; - uint32_t ttbcr; uint32_t ttb; - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - - /* MRC p15,0,,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(15, 0, 0, 2, 0, 2), - &ttbcr); - if (retval != ERROR_OK) - goto done; - - /* if ttbcr has changed or was not read before, re-read the information */ - if ((armv7a->armv7a_mmu.cached == 0) || - (armv7a->armv7a_mmu.ttbcr != ttbcr)) { - armv7a_read_ttbcr(target); - } + if (target->state != TARGET_HALTED) + LOG_INFO("target not halted, using cached values for translation table!"); /* if va is above the range handled by ttbr0, select ttbr1 */ if (va > armv7a->armv7a_mmu.ttbr_range[0]) { /* select ttb 1 */ ttbidx = 1; } - /* MRC p15,0,,c2,c0,ttbidx */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx), - &ttb); - if (retval != ERROR_OK) - return retval; + ttb = armv7a->armv7a_mmu.ttbr[ttbidx]; ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx]; va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx]; @@ -279,9 +271,6 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) } return ERROR_OK; - -done: - return retval; } /* V7 method VA TO PA */ @@ -740,6 +729,8 @@ int armv7a_arch_state(struct target *target) arm_arch_state(target); + armv7a_read_ttbcr(target); + if (armv7a->is_armv7r) { LOG_USER("D-Cache: %s, I-Cache: %s", state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 14112e4ed..33f6f5dbe 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -87,6 +87,7 @@ struct armv7a_mmu_common { /* following field mmu working way */ int32_t cached; /* 0: not initialized, 1: initialized */ uint32_t ttbcr; /* cache for ttbcr register */ + uint32_t ttbr[2]; uint32_t ttbr_mask[2]; uint32_t ttbr_range[2]; From 6c6b42664a460da505a55c9062708fe314a9fcd8 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sat, 13 Jan 2018 17:24:37 +0300 Subject: [PATCH 45/91] jtag: hla: tcl: fix inconsistent expected_id handling Copy from 20fcd0729e7187e8fe6a38ce53b0a1b95ea647fb. Should fix http://build.openocd.org/job/openocd-clang/doclinks/1/report-1e9b08.html Change-Id: I1a83387b4d745134acc38eeba08aa869d9895573 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4333 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/hla/hla_tcl.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/jtag/hla/hla_tcl.c b/src/jtag/hla/hla_tcl.c index 9378427b0..73f78fc8a 100644 --- a/src/jtag/hla/hla_tcl.c +++ b/src/jtag/hla/hla_tcl.c @@ -39,20 +39,15 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, return e; } - unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt; - uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t)); - if (new_expected_ids == NULL) { + uint32_t *p = realloc(pTap->expected_ids, + (pTap->expected_ids_cnt + 1) * sizeof(uint32_t)); + if (!p) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } - memcpy(new_expected_ids, pTap->expected_ids, expected_len); - - new_expected_ids[pTap->expected_ids_cnt] = w; - - free(pTap->expected_ids); - pTap->expected_ids = new_expected_ids; - pTap->expected_ids_cnt++; + pTap->expected_ids = p; + pTap->expected_ids[pTap->expected_ids_cnt++] = w; return JIM_OK; } From d4ef54c6098b9ddeca60489644922825f3cf3d0d Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Wed, 7 Mar 2018 11:27:02 -0500 Subject: [PATCH 46/91] helper/types: cast to uint32_t,uint16_t to avoid UB by shifting int too far Without this, we have some types promoted to `int` when they need to be `unsigned int`. Here's some ubsan output hitting this: Unfortunately, what happens is that things get promoted to `int`, but need to be `unsigned int`. Here's the ubsan output: src/helper/types.h:126:65: runtime error: left shift of 255 by 24 places cannot be represented in type 'int' #0 0x55978a612060 in le_to_h_u32 src/helper/types.h:126 #1 0x55978a61ff9e in stlink_usb_read_reg src/jtag/drivers/stlink_usb.c:1539 #2 0x55978a8cfd45 in adapter_load_core_reg_u32 src/target/hla_target.c:67 #3 0x55978a9f48e3 in armv7m_read_core_reg src/target/armv7m.c:236 #4 0x55978a8d24fc in adapter_load_context src/target/hla_target.c:372 #5 0x55978a8d261b in adapter_debug_entry src/target/hla_target.c:396 #6 0x55978a8d3123 in adapter_poll src/target/hla_target.c:457 #7 0x55978a528357 in target_poll src/target/target.c:535 #8 0x55978a539fd4 in target_wait_state src/target/target.c:2914 #9 0x55978a556e20 in jim_target_wait_state src/target/target.c:5256 #10 0x55978a5cca62 in command_unknown src/helper/command.c:1030 #11 0x55978aaed894 in JimInvokeCommand /home/cody/d/openocd-code/jimtcl/jim.c:10364 Change-Id: I24f6abfd26b6980100657397d69c84f2b80a005a Signed-off-by: Cody P Schafer Reviewed-on: http://openocd.zylin.com/4455 Reviewed-by: Tomas Vanek Tested-by: jenkins Reviewed-by: Christopher Head --- src/helper/types.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/helper/types.h b/src/helper/types.h index a7dd2a816..5e35c13b7 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -128,17 +128,17 @@ static inline uint64_t le_to_h_u64(const uint8_t *buf) static inline uint32_t le_to_h_u32(const uint8_t* buf) { - return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24); + return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24); } static inline uint32_t le_to_h_u24(const uint8_t* buf) { - return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16); + return (uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16); } static inline uint16_t le_to_h_u16(const uint8_t* buf) { - return (uint16_t)(buf[0] | buf[1] << 8); + return (uint16_t)((uint16_t)buf[0] | (uint16_t)buf[1] << 8); } static inline uint64_t be_to_h_u64(const uint8_t *buf) @@ -155,17 +155,17 @@ static inline uint64_t be_to_h_u64(const uint8_t *buf) static inline uint32_t be_to_h_u32(const uint8_t* buf) { - return (uint32_t)(buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24); + return (uint32_t)((uint32_t)buf[3] | (uint32_t)buf[2] << 8 | (uint32_t)buf[1] << 16 | (uint32_t)buf[0] << 24); } static inline uint32_t be_to_h_u24(const uint8_t* buf) { - return (uint32_t)(buf[2] | buf[1] << 8 | buf[0] << 16); + return (uint32_t)((uint32_t)buf[2] | (uint32_t)buf[1] << 8 | (uint32_t)buf[0] << 16); } static inline uint16_t be_to_h_u16(const uint8_t* buf) { - return (uint16_t)(buf[1] | buf[0] << 8); + return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8); } static inline void h_u64_to_le(uint8_t *buf, int64_t val) From 396ea7c8dd448482789122799b5dbc60b77223ad Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 4 Mar 2018 12:05:15 +0100 Subject: [PATCH 47/91] doc: update openocd.texi after change of gdb-attach default value While on it - change some occurrences of gdb to GDB if it refers GDB software (as oposed to a gdb command) - add some xrefs - give more meaningful example of target event definition - remove obsoleted example of GDB hook-step Change-Id: Ia2e26021d57f675acfa1de704f6c3e81c22bb8bf Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4444 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 113 +++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 37 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 2f01153f8..3a38a9680 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -1595,8 +1595,11 @@ proc enable_fast_clock @{@} @{ proc init_board @{@} @{ reset_config trst_and_srst trst_pulls_srst + $_TARGETNAME configure -event reset-start @{ + adapter_khz 100 + @} + $_TARGETNAME configure -event reset-init @{ - adapter_khz 1 enable_fast_clock adapter_khz 10000 @} @@ -4430,16 +4433,14 @@ buttons and events. The two examples below act the same, but one creates and invokes a small procedure while the other inlines it. @example -proc my_attach_proc @{ @} @{ - echo "Reset..." - reset halt +proc my_init_proc @{ @} @{ + echo "Disabling watchdog..." + mww 0xfffffd44 0x00008000 @} -mychip.cpu configure -event gdb-attach my_attach_proc -mychip.cpu configure -event gdb-attach @{ - echo "Reset..." - # To make flash probe and gdb load to flash work - # we need a reset init. - reset init +mychip.cpu configure -event reset-init my_init_proc +mychip.cpu configure -event reset-init @{ + echo "Disabling watchdog..." + mww 0xfffffd44 0x00008000 @} @end example @@ -4449,7 +4450,7 @@ The following target events are defined: @item @b{debug-halted} @* The target has halted for debug reasons (i.e.: breakpoint) @item @b{debug-resumed} -@* The target has resumed (i.e.: gdb said run) +@* The target has resumed (i.e.: GDB said run) @item @b{early-halted} @* Occurs early in the halt process @item @b{examine-start} @@ -4457,11 +4458,16 @@ The following target events are defined: @item @b{examine-end} @* After target examine is called with no errors. @item @b{gdb-attach} -@* When GDB connects. This is before any communication with the target, so this -can be used to set up the target so it is possible to probe flash. Probing flash -is necessary during gdb connect if gdb load is to write the image to flash. Another -use of the flash memory map is for GDB to automatically hardware/software breakpoints -depending on whether the breakpoint is in RAM or read only memory. +@* When GDB connects. This is before any communication with the target and GDB +expects the target is halted during attachment. +@xref{gdbmeminspect,,GDB as a non-intrusive memory inspector} for exclusion. +The event can be also used to set up the target so it is possible to probe flash. +Probing flash is necessary during GDB connect if you want to use +@pxref{programmingusinggdb,,programming using GDB}. +Another use of the flash memory map is for GDB to automatically choose +hardware or software breakpoints depending on whether the breakpoint +is in RAM or read only memory. +Default is @code{halt} @item @b{gdb-detach} @* When GDB disconnects @item @b{gdb-end} @@ -4476,13 +4482,13 @@ depending on whether the breakpoint is in RAM or read only memory. @item @b{gdb-flash-write-end} @* After GDB writes to the flash (default is @code{reset halt}) @item @b{gdb-start} -@* Before the target steps, gdb is trying to start/resume the target +@* Before the target steps, GDB is trying to start/resume the target @item @b{halted} @* The target has halted @item @b{reset-assert-pre} @* Issued as part of @command{reset} processing -after @command{reset_init} was triggered -but before either SRST alone is re-asserted on the scan chain, +after @command{reset-start} was triggered +but before either SRST alone is asserted on the scan chain, or @code{reset-assert} is triggered. @item @b{reset-assert} @* Issued as part of @command{reset} processing @@ -4516,8 +4522,8 @@ multiplexing, and so on. (You may be able to switch to a fast JTAG clock rate here, after the target clocks are fully set up.) @item @b{reset-start} -@* Issued as part of @command{reset} processing -before @command{reset_init} is called. +@* Issued as the first step in @command{reset} processing +before @command{reset-assert-pre} is called. This is the most robust place to use @command{jtag_rclk} or @command{adapter_khz} to switch to a low JTAG clock rate, @@ -9178,19 +9184,6 @@ With that particular hardware (Cortex-M3) the hardware breakpoints only work for code running from flash memory. Most other ARM systems do not have such restrictions. -Another example of useful GDB configuration came from a user who -found that single stepping his Cortex-M3 didn't work well with IRQs -and an RTOS until he told GDB to disable the IRQs while stepping: - -@example -define hook-step -mon cortex_m maskisr on -end -define hookpost-step -mon cortex_m maskisr off -end -@end example - Rather than typing such commands interactively, you may prefer to save them in a file and have GDB execute them as it starts, perhaps using a @file{.gdbinit} in your project directory or starting GDB @@ -9230,14 +9223,60 @@ GDB will look at the target memory map when a load command is given, if any areas to be programmed lie within the target flash area the vFlash packets will be used. -If the target needs configuring before GDB programming, an event -script can be executed: +If the target needs configuring before GDB programming, set target +event gdb-flash-erase-start: @example -$_TARGETNAME configure -event EVENTNAME BODY +$_TARGETNAME configure -event gdb-flash-erase-start BODY @end example +@xref{targetevents,,Target Events} for other GDB programming related events. To verify any flash programming the GDB command @option{compare-sections} can be used. + +@section Using GDB as a non-intrusive memory inspector +@cindex Using GDB as a non-intrusive memory inspector +@anchor{gdbmeminspect} + +If your project controls more than a blinking LED, let's say a heavy industrial +robot or an experimental nuclear reactor, stopping the controlling process +just because you want to attach GDB is not a good option. + +OpenOCD does not support GDB non-stop mode (might be implemented in the future). +Though there is a possible setup where the target does not get stopped +and GDB treats it as it were running. +If the target supports background access to memory while it is running, +you can use GDB in this mode to inspect memory (mainly global variables) +without any intrusion of the target process. + +Remove default setting of gdb-attach event. @xref{targetevents,,Target Events}. +Place following command after target configuration: +@example +$_TARGETNAME configure -event gdb-attach @{@} +@end example + +If any of installed flash banks does not support probe on running target, +switch off gdb_memory_map: +@example +gdb_memory_map disable +@end example + +Ensure GDB is configured without interrupt-on-connect. +Some GDB versions set it by default, some does not. +@example +set remote interrupt-on-connect off +@end example + +If you switched gdb_memory_map off, you may want to setup GDB memory map +manually or issue @command{set mem inaccessible-by-default off} + +Now you can issue GDB command @command{target remote ...} and inspect memory +of a running target. Do not use GDB commands @command{continue}, +@command{step} or @command{next} as they synchronize GDB with your target +and GDB would require stopping the target to get the prompt back. + +Do not use this mode under an IDE like Eclipse as it caches values of +previously shown varibles. + @anchor{usingopenocdsmpwithgdb} @section Using OpenOCD SMP with GDB @cindex SMP From 69325f6970f445f43b8cac05824a68a8f906735a Mon Sep 17 00:00:00 2001 From: Hellosun Wu Date: Fri, 12 May 2017 14:37:21 +0800 Subject: [PATCH 48/91] nds32: Add jtag scan_chain command Create new command to refresh idcode list during runtime and update Tap idcode. Change-Id: Ie889a39a6f57cea207b2b9c9e42c51c97cfe4d8e Signed-off-by: Hellosun Wu Reviewed-on: http://openocd.zylin.com/4133 Tested-by: jenkins Reviewed-by: Hsiangkai Wang Reviewed-by: penny chen Reviewed-by: Tomas Vanek --- src/jtag/aice/aice_interface.c | 24 ++++++++++++++ src/jtag/aice/aice_interface.h | 1 + src/jtag/aice/aice_transport.c | 60 ++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/src/jtag/aice/aice_interface.c b/src/jtag/aice/aice_interface.c index 20f1f07f9..c758bb43b 100644 --- a/src/jtag/aice/aice_interface.c +++ b/src/jtag/aice/aice_interface.c @@ -239,6 +239,30 @@ static int aice_khz(int khz, int *jtag_speed) return ERROR_OK; } +int aice_scan_jtag_chain(void) +{ + LOG_DEBUG("=== %s ===", __func__); + uint8_t num_of_idcode = 0; + struct target *target; + + int res = aice_port->api->idcode(aice_target_id_codes, &num_of_idcode); + if (res != ERROR_OK) { + LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore " + "JTAG Manufacture ID in the JTAG scan chain. " + "Failed to access EDM registers. -->"); + return res; + } + + for (uint32_t i = 0; i < num_of_idcode; i++) + LOG_DEBUG("id_codes[%d] = 0x%x", i, aice_target_id_codes[i]); + + /* Update tap idcode */ + for (target = all_targets; target; target = target->next) + target->tap->idcode = aice_target_id_codes[target->tap->abs_chain_position]; + + return ERROR_OK; +} + /***************************************************************************/ /* Command handlers */ COMMAND_HANDLER(aice_handle_aice_info_command) diff --git a/src/jtag/aice/aice_interface.h b/src/jtag/aice/aice_interface.h index 0e3f10836..220b0b04d 100644 --- a/src/jtag/aice/aice_interface.h +++ b/src/jtag/aice/aice_interface.h @@ -31,5 +31,6 @@ struct aice_interface_param_s { }; int aice_init_targets(void); +int aice_scan_jtag_chain(void); #endif /* OPENOCD_JTAG_AICE_AICE_INTERFACE_H */ diff --git a/src/jtag/aice/aice_transport.c b/src/jtag/aice/aice_transport.c index 9f079468c..57c93f2a1 100644 --- a/src/jtag/aice/aice_transport.c +++ b/src/jtag/aice/aice_transport.c @@ -158,6 +158,59 @@ COMMAND_HANDLER(handle_aice_init_command) return jtag_init(CMD_CTX); } +COMMAND_HANDLER(handle_scan_chain_command) +{ + struct jtag_tap *tap; + char expected_id[12]; + + aice_scan_jtag_chain(); + tap = jtag_all_taps(); + command_print(CMD_CTX, + " TapName Enabled IdCode Expected IrLen IrCap IrMask"); + command_print(CMD_CTX, + "-- ------------------- -------- ---------- ---------- ----- ----- ------"); + + while (tap) { + uint32_t expected, expected_mask, ii; + + snprintf(expected_id, sizeof expected_id, "0x%08x", + (unsigned)((tap->expected_ids_cnt > 0) + ? tap->expected_ids[0] + : 0)); + if (tap->ignore_version) + expected_id[2] = '*'; + + expected = buf_get_u32(tap->expected, 0, tap->ir_length); + expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length); + + command_print(CMD_CTX, + "%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x", + tap->abs_chain_position, + tap->dotted_name, + tap->enabled ? 'Y' : 'n', + (unsigned int)(tap->idcode), + expected_id, + (unsigned int)(tap->ir_length), + (unsigned int)(expected), + (unsigned int)(expected_mask)); + + for (ii = 1; ii < tap->expected_ids_cnt; ii++) { + snprintf(expected_id, sizeof expected_id, "0x%08x", + (unsigned) tap->expected_ids[ii]); + if (tap->ignore_version) + expected_id[2] = '*'; + + command_print(CMD_CTX, + " %s", + expected_id); + } + + tap = tap->next_tap; + } + + return ERROR_OK; +} + static int jim_aice_arp_init(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { LOG_DEBUG("No implement: jim_aice_arp_init"); @@ -307,6 +360,13 @@ aice_transport_jtag_subcommand_handlers[] = { .jim_handler = jim_aice_names, .help = "Returns list of all JTAG tap names.", }, + { + .name = "scan_chain", + .handler = handle_scan_chain_command, + .mode = COMMAND_ANY, + .help = "print current scan chain configuration", + .usage = "" + }, COMMAND_REGISTRATION_DONE }; From 6a4f5a4a6707520b7e12ec4199cd77129ee6436e Mon Sep 17 00:00:00 2001 From: Mateusz Manowiecki Date: Thu, 26 Jan 2017 01:12:18 +0100 Subject: [PATCH 49/91] Add SWD protocol support to buspirate (2nd try) This is a second try for this patch. I removed the queues from the previous version. I made it compatible with SRST reset and added support for those features that could be supported in raw binary mode. Change-Id: I96fc06abbea9873e98b414f34afd9043fd9c2a41 Signed-off-by: Mateusz Manowiecki Reviewed-on: http://openocd.zylin.com/3960 Tested-by: jenkins Reviewed-by: Eric Work Reviewed-by: Thomas Jarosch Reviewed-by: Jacob Alexander Reviewed-by: Tomas Vanek --- src/jtag/drivers/buspirate.c | 463 +++++++++++++++++++++++++++++++++-- tcl/interface/buspirate.cfg | 2 +- 2 files changed, 437 insertions(+), 28 deletions(-) diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index aa0d8cc3f..76be103e6 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -48,9 +49,21 @@ static void buspirate_stableclocks(int num_cycles); #define CMD_READ_ADCS 0x03 /*#define CMD_TAP_SHIFT 0x04 // old protocol */ #define CMD_TAP_SHIFT 0x05 +#define CMD_ENTER_RWIRE 0x05 #define CMD_ENTER_OOCD 0x06 #define CMD_UART_SPEED 0x07 #define CMD_JTAG_SPEED 0x08 +#define CMD_RAW_PERIPH 0x40 +#define CMD_RAW_SPEED 0x60 +#define CMD_RAW_MODE 0x80 + +/* raw-wire mode configuration */ +#define CMD_RAW_CONFIG_HIZ 0x00 +#define CMD_RAW_CONFIG_3V3 0x08 +#define CMD_RAW_CONFIG_2W 0x00 +#define CMD_RAW_CONFIG_3W 0x04 +#define CMD_RAW_CONFIG_MSB 0x00 +#define CMD_RAW_CONFIG_LSB 0x02 /* Not all OSes have this speed defined */ #if !defined(B1000000) @@ -81,6 +94,18 @@ enum { SERIAL_FAST = 1 }; +enum { + SPEED_RAW_5_KHZ = 0x0, + SPEED_RAW_50_KHZ = 0x1, + SPEED_RAW_100_KHZ = 0x2, + SPEED_RAW_400_KHZ = 0x3 +}; + +/* SWD mode specific */ +static bool swd_mode; +static int queued_retval; +static char swd_features; + static const cc_t SHORT_TIMEOUT = 1; /* Must be at least 1. */ static const cc_t NORMAL_TIMEOUT = 10; @@ -93,6 +118,12 @@ static char *buspirate_port; static enum tap_state last_tap_state = TAP_RESET; +/* SWD interface */ +static int buspirate_swd_init(void); +static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk); +static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk); +static int buspirate_swd_switch_seq(enum swd_special_seq seq); +static int buspirate_swd_run_queue(void); /* TAP interface */ static void buspirate_tap_init(void); @@ -103,16 +134,24 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer, static void buspirate_tap_make_space(int scan, int bits); static void buspirate_reset(int trst, int srst); +static void buspirate_set_feature(int, char, char); +static void buspirate_set_mode(int, char); +static void buspirate_set_speed(int, char); /* low level interface */ +static void buspirate_bbio_enable(int); static void buspirate_jtag_reset(int); -static void buspirate_jtag_enable(int); static unsigned char buspirate_jtag_command(int, char *, int); static void buspirate_jtag_set_speed(int, char); static void buspirate_jtag_set_mode(int, char); static void buspirate_jtag_set_feature(int, char, char); static void buspirate_jtag_get_adcs(int); +/* low level two-wire interface */ +static void buspirate_swd_set_speed(int, char); +static void buspirate_swd_set_feature(int, char, char); +static void buspirate_swd_set_mode(int, char); + /* low level HW communication interface */ static int buspirate_serial_open(char *port); static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout); @@ -295,18 +334,20 @@ static int buspirate_init(void) return ERROR_JTAG_INIT_FAILED; } - buspirate_jtag_enable(buspirate_fd); + buspirate_bbio_enable(buspirate_fd); - if (buspirate_baudrate != SERIAL_NORMAL) - buspirate_jtag_set_speed(buspirate_fd, SERIAL_FAST); + if (swd_mode || buspirate_baudrate != SERIAL_NORMAL) + buspirate_set_speed(buspirate_fd, SERIAL_FAST); - LOG_INFO("Buspirate Interface ready!"); + LOG_INFO("Buspirate %s Interface ready!", swd_mode ? "SWD" : "JTAG"); - buspirate_tap_init(); - buspirate_jtag_set_mode(buspirate_fd, buspirate_pinmode); - buspirate_jtag_set_feature(buspirate_fd, FEATURE_VREG, + if (!swd_mode) + buspirate_tap_init(); + + buspirate_set_mode(buspirate_fd, buspirate_pinmode); + buspirate_set_feature(buspirate_fd, FEATURE_VREG, (buspirate_vreg == 1) ? ACTION_ENABLE : ACTION_DISABLE); - buspirate_jtag_set_feature(buspirate_fd, FEATURE_PULLUP, + buspirate_set_feature(buspirate_fd, FEATURE_PULLUP, (buspirate_pullup == 1) ? ACTION_ENABLE : ACTION_DISABLE); buspirate_reset(0, 0); @@ -316,9 +357,9 @@ static int buspirate_init(void) static int buspirate_quit(void) { LOG_INFO("Shutting down buspirate."); - buspirate_jtag_set_mode(buspirate_fd, MODE_HIZ); + buspirate_set_mode(buspirate_fd, MODE_HIZ); + buspirate_set_speed(buspirate_fd, SERIAL_NORMAL); - buspirate_jtag_set_speed(buspirate_fd, SERIAL_NORMAL); buspirate_jtag_reset(buspirate_fd); buspirate_serial_close(buspirate_fd); @@ -336,6 +377,10 @@ COMMAND_HANDLER(buspirate_handle_adc_command) if (buspirate_fd == -1) return ERROR_OK; + /* unavailable in SWD mode */ + if (swd_mode) + return ERROR_OK; + /* send the command */ buspirate_jtag_get_adcs(buspirate_fd); @@ -382,11 +427,11 @@ COMMAND_HANDLER(buspirate_handle_led_command) if (atoi(CMD_ARGV[0]) == 1) { /* enable led */ - buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, + buspirate_set_feature(buspirate_fd, FEATURE_LED, ACTION_ENABLE); } else if (atoi(CMD_ARGV[0]) == 0) { /* disable led */ - buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, + buspirate_set_feature(buspirate_fd, FEATURE_LED, ACTION_DISABLE); } else { LOG_ERROR("usage: buspirate_led <1|0>"); @@ -492,10 +537,22 @@ static const struct command_registration buspirate_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct swd_driver buspirate_swd = { + .init = buspirate_swd_init, + .switch_seq = buspirate_swd_switch_seq, + .read_reg = buspirate_swd_read_reg, + .write_reg = buspirate_swd_write_reg, + .run = buspirate_swd_run_queue, +}; + +static const char * const buspirate_transports[] = { "jtag", "swd", NULL }; + struct jtag_interface buspirate_interface = { .name = "buspirate", .execute_queue = buspirate_execute_queue, .commands = buspirate_command_handlers, + .transports = buspirate_transports, + .swd = &buspirate_swd, .init = buspirate_init, .quit = buspirate_quit }; @@ -799,7 +856,7 @@ static void buspirate_tap_append_scan(int length, uint8_t *buffer, tap_pending_scans_num++; } -/*************** jtag wrapper functions *********************/ +/*************** wrapper functions *********************/ /* (1) assert or (0) deassert reset lines */ static void buspirate_reset(int trst, int srst) @@ -807,33 +864,148 @@ static void buspirate_reset(int trst, int srst) LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst) - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_TRST, ACTION_DISABLE); + buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_DISABLE); else - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_TRST, ACTION_ENABLE); + buspirate_set_feature(buspirate_fd, FEATURE_TRST, ACTION_ENABLE); if (srst) - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_SRST, ACTION_DISABLE); + buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE); else - buspirate_jtag_set_feature(buspirate_fd, - FEATURE_SRST, ACTION_ENABLE); + buspirate_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE); +} + +static void buspirate_set_feature(int fd, char feat, char action) +{ + if (swd_mode) + buspirate_swd_set_feature(fd, feat, action); + else + buspirate_jtag_set_feature(fd, feat, action); +} + +static void buspirate_set_mode(int fd, char mode) +{ + if (swd_mode) + buspirate_swd_set_mode(fd, mode); + else + buspirate_jtag_set_mode(fd, mode); +} + +static void buspirate_set_speed(int fd, char speed) +{ + if (swd_mode) + buspirate_swd_set_speed(fd, speed); + else + buspirate_jtag_set_speed(fd, speed); +} + + +/*************** swd lowlevel functions ********************/ + +static void buspirate_swd_set_speed(int fd, char speed) +{ + int ret; + char tmp[1]; + + LOG_DEBUG("Buspirate speed setting in SWD mode defaults to 400 kHz"); + + /* speed settings */ + tmp[0] = CMD_RAW_SPEED | SPEED_RAW_400_KHZ; + buspirate_serial_write(fd, tmp, 1); + ret = buspirate_serial_read(fd, tmp, 1); + if (ret != 1) { + LOG_ERROR("Buspirate did not answer correctly"); + exit(-1); + } + if (tmp[0] != 1) { + LOG_ERROR("Buspirate did not reply as expected to the speed change command"); + exit(-1); + } +} + +static void buspirate_swd_set_mode(int fd, char mode) +{ + int ret; + char tmp[1]; + + /* raw-wire mode configuration */ + if (mode == MODE_HIZ) + tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB; + else + tmp[0] = CMD_RAW_MODE | CMD_RAW_CONFIG_LSB | CMD_RAW_CONFIG_3V3; + + buspirate_serial_write(fd, tmp, 1); + ret = buspirate_serial_read(fd, tmp, 1); + if (ret != 1) { + LOG_ERROR("Buspirate did not answer correctly"); + exit(-1); + } + if (tmp[0] != 1) { + LOG_ERROR("Buspirate did not reply as expected to the configure command"); + exit(-1); + } +} + +static void buspirate_swd_set_feature(int fd, char feat, char action) +{ + int ret; + char tmp[1]; + + switch (feat) { + case FEATURE_TRST: + LOG_DEBUG("Buspirate TRST feature not available in SWD mode"); + return; + case FEATURE_LED: + LOG_ERROR("Buspirate LED feature not available in SWD mode"); + return; + case FEATURE_SRST: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D; + break; + case FEATURE_PULLUP: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B; + break; + case FEATURE_VREG: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07; + break; + default: + LOG_DEBUG("Buspirate unknown feature %d", feat); + return; + } + + tmp[0] = CMD_RAW_PERIPH | swd_features; + buspirate_serial_write(fd, tmp, 1); + ret = buspirate_serial_read(fd, tmp, 1); + if (ret != 1) { + LOG_DEBUG("Buspirate feature %d not supported in SWD mode", feat); + } else if (tmp[0] != 1) { + LOG_ERROR("Buspirate did not reply as expected to the configure command"); + exit(-1); + } } /*************** jtag lowlevel functions ********************/ -static void buspirate_jtag_enable(int fd) +static void buspirate_bbio_enable(int fd) { int ret; + char command; + const char *mode_answers[2] = { "OCD1", "RAW1" }; + const char *correct_ans = NULL; char tmp[21] = { [0 ... 20] = 0x00 }; int done = 0; int cmd_sent = 0; - LOG_DEBUG("Entering binary mode"); + if (swd_mode) { + command = CMD_ENTER_RWIRE; + correct_ans = mode_answers[1]; + } else { + command = CMD_ENTER_OOCD; + correct_ans = mode_answers[0]; + } + + LOG_DEBUG("Entering binary mode, that is %s", correct_ans); buspirate_serial_write(fd, tmp, 20); usleep(10000); - /* reads 1 to n "BBIO1"s and one "OCD1" */ + /* reads 1 to n "BBIO1"s and one "OCD1" or "RAW1" */ while (!done) { ret = buspirate_serial_read(fd, tmp, 4); if (ret != 4) { @@ -854,14 +1026,14 @@ static void buspirate_jtag_enable(int fd) } if (cmd_sent == 0) { cmd_sent = 1; - tmp[0] = CMD_ENTER_OOCD; + tmp[0] = command; ret = buspirate_serial_write(fd, tmp, 1); if (ret != 1) { LOG_ERROR("error reading"); exit(-1); } } - } else if (strncmp(tmp, "OCD1", 4) == 0) + } else if (strncmp(tmp, correct_ans, 4) == 0) done = 1; else { LOG_ERROR("Buspirate did not answer correctly! " @@ -1124,3 +1296,240 @@ static void buspirate_print_buffer(char *buf, int size) if (line[0] != 0) LOG_DEBUG("%s", line); } + +/************************* SWD related stuff **********/ + +static int buspirate_swd_init(void) +{ + LOG_INFO("Buspirate SWD mode enabled"); + swd_mode = true; + + return ERROR_OK; +} + +static int buspirate_swd_switch_seq(enum swd_special_seq seq) +{ + const uint8_t *sequence; + int sequence_len; + char tmp[64]; + + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + sequence = swd_seq_line_reset; + sequence_len = DIV_ROUND_UP(swd_seq_line_reset_len, 8); + break; + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + sequence = swd_seq_jtag_to_swd; + sequence_len = DIV_ROUND_UP(swd_seq_jtag_to_swd_len, 8); + break; + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + sequence = swd_seq_swd_to_jtag; + sequence_len = DIV_ROUND_UP(swd_seq_swd_to_jtag_len, 8); + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } + + /* FIXME: all above sequences fit into one pirate command for now + * but it may cause trouble later + */ + + tmp[0] = 0x10 + ((sequence_len - 1) & 0x0F); + memcpy(tmp + 1, sequence, sequence_len); + + buspirate_serial_write(buspirate_fd, tmp, sequence_len + 1); + buspirate_serial_read(buspirate_fd, tmp, sequence_len + 1); + + return ERROR_OK; +} + +static uint8_t buspirate_swd_write_header(uint8_t cmd) +{ + char tmp[8]; + int to_send; + + tmp[0] = 0x10; /* bus pirate: send 1 byte */ + tmp[1] = cmd; /* swd cmd */ + tmp[2] = 0x07; /* ack __x */ + tmp[3] = 0x07; /* ack _x_ */ + tmp[4] = 0x07; /* ack x__ */ + tmp[5] = 0x07; /* write mode trn_1 */ + tmp[6] = 0x07; /* write mode trn_2 */ + + to_send = ((cmd & SWD_CMD_RnW) == 0) ? 7 : 5; + buspirate_serial_write(buspirate_fd, tmp, to_send); + + /* read ack */ + buspirate_serial_read(buspirate_fd, tmp, 2); /* drop pirate command ret vals */ + buspirate_serial_read(buspirate_fd, tmp, to_send - 2); /* ack bits */ + + return tmp[2] << 2 | tmp[1] << 1 | tmp[0]; +} + +static void buspirate_swd_idle_clocks(uint32_t no_bits) +{ + uint32_t no_bytes; + char tmp[20]; + + no_bytes = (no_bits + 7) / 8; + memset(tmp + 1, 0x00, sizeof(tmp) - 1); + + /* unfortunately bus pirate misbehaves when clocks are sent in parts + * so we need to limit at 128 clock cycles + */ + if (no_bytes > 16) + no_bytes = 16; + + while (no_bytes) { + uint8_t to_send = no_bytes > 16 ? 16 : no_bytes; + tmp[0] = 0x10 + ((to_send - 1) & 0x0F); + + buspirate_serial_write(buspirate_fd, tmp, to_send + 1); + buspirate_serial_read(buspirate_fd, tmp, to_send + 1); + + no_bytes -= to_send; + } +} + +static void buspirate_swd_clear_sticky_errors(void) +{ + buspirate_swd_write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); +} + +static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + char tmp[16]; + + LOG_DEBUG("buspirate_swd_read_reg"); + assert(cmd & SWD_CMD_RnW); + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skip buspirate_swd_read_reg because queued_retval=%d", queued_retval); + return; + } + + cmd |= SWD_CMD_START | SWD_CMD_PARK; + uint8_t ack = buspirate_swd_write_header(cmd); + + /* do a read transaction */ + tmp[0] = 0x06; /* 4 data bytes */ + tmp[1] = 0x06; + tmp[2] = 0x06; + tmp[3] = 0x06; + tmp[4] = 0x07; /* parity bit */ + tmp[5] = 0x21; /* 2 turnaround clocks */ + + buspirate_serial_write(buspirate_fd, tmp, 6); + buspirate_serial_read(buspirate_fd, tmp, 6); + + /* store the data and parity */ + uint32_t data = (uint8_t) tmp[0]; + data |= (uint8_t) tmp[1] << 8; + data |= (uint8_t) tmp[2] << 16; + data |= (uint8_t) tmp[3] << 24; + int parity = tmp[4] ? 0x01 : 0x00; + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + data); + + switch (ack) { + case SWD_ACK_OK: + if (parity != parity_u32(data)) { + LOG_DEBUG("Read data parity mismatch %x %x", parity, parity_u32(data)); + queued_retval = ERROR_FAIL; + return; + } + if (value) + *value = data; + if (cmd & SWD_CMD_APnDP) + buspirate_swd_idle_clocks(ap_delay_clk); + return; + case SWD_ACK_WAIT: + LOG_DEBUG("SWD_ACK_WAIT"); + buspirate_swd_clear_sticky_errors(); + return; + case SWD_ACK_FAULT: + LOG_DEBUG("SWD_ACK_FAULT"); + queued_retval = ack; + return; + default: + LOG_DEBUG("No valid acknowledge: ack=%d", ack); + queued_retval = ack; + return; + } +} + +static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) +{ + char tmp[16]; + + LOG_DEBUG("buspirate_swd_write_reg"); + assert(!(cmd & SWD_CMD_RnW)); + + if (queued_retval != ERROR_OK) { + LOG_DEBUG("Skip buspirate_swd_write_reg because queued_retval=%d", queued_retval); + return; + } + + cmd |= SWD_CMD_START | SWD_CMD_PARK; + uint8_t ack = buspirate_swd_write_header(cmd); + + /* do a write transaction */ + tmp[0] = 0x10 + ((4 + 1 - 1) & 0xF); /* bus pirate: send 4+1 bytes */ + buf_set_u32((uint8_t *) tmp + 1, 0, 32, value); + /* write sequence ends with parity bit and 7 idle ticks */ + tmp[5] = parity_u32(value) ? 0x01 : 0x00; + + buspirate_serial_write(buspirate_fd, tmp, 6); + buspirate_serial_read(buspirate_fd, tmp, 6); + + LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APnDP ? "AP" : "DP", + cmd & SWD_CMD_RnW ? "read" : "write", + (cmd & SWD_CMD_A32) >> 1, + value); + + switch (ack) { + case SWD_ACK_OK: + if (cmd & SWD_CMD_APnDP) + buspirate_swd_idle_clocks(ap_delay_clk); + return; + case SWD_ACK_WAIT: + LOG_DEBUG("SWD_ACK_WAIT"); + buspirate_swd_clear_sticky_errors(); + return; + case SWD_ACK_FAULT: + LOG_DEBUG("SWD_ACK_FAULT"); + queued_retval = ack; + return; + default: + LOG_DEBUG("No valid acknowledge: ack=%d", ack); + queued_retval = ack; + return; + } +} + +static int buspirate_swd_run_queue(void) +{ + LOG_DEBUG("buspirate_swd_run_queue"); + /* A transaction must be followed by another transaction or at least 8 idle cycles to + * ensure that data is clocked through the AP. */ + buspirate_swd_idle_clocks(8); + + int retval = queued_retval; + queued_retval = ERROR_OK; + LOG_DEBUG("SWD queue return value: %02x", retval); + return retval; +} + + diff --git a/tcl/interface/buspirate.cfg b/tcl/interface/buspirate.cfg index 2b68538bf..c2f3a83c4 100644 --- a/tcl/interface/buspirate.cfg +++ b/tcl/interface/buspirate.cfg @@ -15,7 +15,7 @@ buspirate_speed normal ;# or fast # voltage regulator Enabled = 1 Disabled = 0 #buspirate_vreg 0 -# pin mode normal or open-drain +# pin mode normal or open-drain (jtag only) #buspirate_mode normal # pullup state Enabled = 1 Disabled = 0 From b8c7232b6694a60970176f8854d6b4a2f1860d6e Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Mon, 12 Mar 2018 20:09:50 +0300 Subject: [PATCH 50/91] jtag: drivers: buspirate: fix abuse of "char" type Change occurrences of char to uint8_t where appropriate as a binary protocol is used to talk to this adapter. This fixes a build issue with modern clang. Change-Id: I21cc82c8cad148bd0977533c12c74a9d6ba2faff Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4462 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/jtag/drivers/buspirate.c | 64 ++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 76be103e6..35649c280 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -141,7 +141,7 @@ static void buspirate_set_speed(int, char); /* low level interface */ static void buspirate_bbio_enable(int); static void buspirate_jtag_reset(int); -static unsigned char buspirate_jtag_command(int, char *, int); +static unsigned char buspirate_jtag_command(int, uint8_t *, int); static void buspirate_jtag_set_speed(int, char); static void buspirate_jtag_set_mode(int, char); static void buspirate_jtag_set_feature(int, char, char); @@ -155,10 +155,10 @@ static void buspirate_swd_set_mode(int, char); /* low level HW communication interface */ static int buspirate_serial_open(char *port); static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout); -static int buspirate_serial_write(int fd, char *buf, int size); -static int buspirate_serial_read(int fd, char *buf, int size); +static int buspirate_serial_write(int fd, uint8_t *buf, int size); +static int buspirate_serial_read(int fd, uint8_t *buf, int size); static void buspirate_serial_close(int fd); -static void buspirate_print_buffer(char *buf, int size); +static void buspirate_print_buffer(uint8_t *buf, int size); static int buspirate_execute_queue(void) { @@ -255,7 +255,7 @@ static bool read_and_discard_all_data(const int fd) bool was_msg_already_printed = false; for ( ; ; ) { - char buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */ + uint8_t buffer[1024]; /* Any size will do, it's a trade-off between stack size and performance. */ const ssize_t read_count = read(fd, buffer, sizeof(buffer)); @@ -690,8 +690,8 @@ static void buspirate_stableclocks(int num_cycles) make it incompatible with the Bus Pirate firmware. */ #define BUSPIRATE_MAX_PENDING_SCANS 128 -static char tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ -static char tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ +static uint8_t tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ +static uint8_t tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ static int tap_chain_index; struct pending_scan_result /* this was stolen from arm-jtag-ew */ @@ -716,7 +716,7 @@ static int buspirate_tap_execute(void) { static const int CMD_TAP_SHIFT_HEADER_LEN = 3; - char tmp[4096]; + uint8_t tmp[4096]; uint8_t *in_buf; int i; int fill_index = 0; @@ -732,8 +732,8 @@ static int buspirate_tap_execute(void) bytes_to_send = DIV_ROUND_UP(tap_chain_index, 8); tmp[0] = CMD_TAP_SHIFT; /* this command expects number of bits */ - tmp[1] = (char)(tap_chain_index >> 8); /* high */ - tmp[2] = (char)(tap_chain_index); /* low */ + tmp[1] = tap_chain_index >> 8; /* high */ + tmp[2] = tap_chain_index; /* low */ fill_index = CMD_TAP_SHIFT_HEADER_LEN; for (i = 0; i < bytes_to_send; i++) { @@ -904,7 +904,7 @@ static void buspirate_set_speed(int fd, char speed) static void buspirate_swd_set_speed(int fd, char speed) { int ret; - char tmp[1]; + uint8_t tmp[1]; LOG_DEBUG("Buspirate speed setting in SWD mode defaults to 400 kHz"); @@ -925,7 +925,7 @@ static void buspirate_swd_set_speed(int fd, char speed) static void buspirate_swd_set_mode(int fd, char mode) { int ret; - char tmp[1]; + uint8_t tmp[1]; /* raw-wire mode configuration */ if (mode == MODE_HIZ) @@ -948,7 +948,7 @@ static void buspirate_swd_set_mode(int fd, char mode) static void buspirate_swd_set_feature(int fd, char feat, char action) { int ret; - char tmp[1]; + uint8_t tmp[1]; switch (feat) { case FEATURE_TRST: @@ -989,7 +989,7 @@ static void buspirate_bbio_enable(int fd) char command; const char *mode_answers[2] = { "OCD1", "RAW1" }; const char *correct_ans = NULL; - char tmp[21] = { [0 ... 20] = 0x00 }; + uint8_t tmp[21] = { [0 ... 20] = 0x00 }; int done = 0; int cmd_sent = 0; @@ -1013,7 +1013,7 @@ static void buspirate_bbio_enable(int fd) "/OpenOCD support enabled?"); exit(-1); } - if (strncmp(tmp, "BBIO", 4) == 0) { + if (strncmp((char *)tmp, "BBIO", 4) == 0) { ret = buspirate_serial_read(fd, tmp, 1); if (ret != 1) { LOG_ERROR("Buspirate did not answer correctly! " @@ -1033,7 +1033,7 @@ static void buspirate_bbio_enable(int fd) exit(-1); } } - } else if (strncmp(tmp, correct_ans, 4) == 0) + } else if (strncmp((char *)tmp, correct_ans, 4) == 0) done = 1; else { LOG_ERROR("Buspirate did not answer correctly! " @@ -1046,14 +1046,14 @@ static void buspirate_bbio_enable(int fd) static void buspirate_jtag_reset(int fd) { - char tmp[5]; + uint8_t tmp[5]; tmp[0] = 0x00; /* exit OCD1 mode */ buspirate_serial_write(fd, tmp, 1); usleep(10000); /* We ignore the return value here purposly, nothing we can do */ buspirate_serial_read(fd, tmp, 5); - if (strncmp(tmp, "BBIO1", 5) == 0) { + if (strncmp((char *)tmp, "BBIO1", 5) == 0) { tmp[0] = 0x0F; /* reset BP */ buspirate_serial_write(fd, tmp, 1); } else @@ -1063,8 +1063,8 @@ static void buspirate_jtag_reset(int fd) static void buspirate_jtag_set_speed(int fd, char speed) { int ret; - char tmp[2]; - char ack[2]; + uint8_t tmp[2]; + uint8_t ack[2]; ack[0] = 0xAA; ack[1] = 0x55; @@ -1096,7 +1096,7 @@ static void buspirate_jtag_set_speed(int fd, char speed) static void buspirate_jtag_set_mode(int fd, char mode) { - char tmp[2]; + uint8_t tmp[2]; tmp[0] = CMD_PORT_MODE; tmp[1] = mode; buspirate_jtag_command(fd, tmp, 2); @@ -1104,7 +1104,7 @@ static void buspirate_jtag_set_mode(int fd, char mode) static void buspirate_jtag_set_feature(int fd, char feat, char action) { - char tmp[3]; + uint8_t tmp[3]; tmp[0] = CMD_FEATURE; tmp[1] = feat; /* what */ tmp[2] = action; /* action */ @@ -1116,7 +1116,7 @@ static void buspirate_jtag_get_adcs(int fd) uint8_t tmp[10]; uint16_t a, b, c, d; tmp[0] = CMD_READ_ADCS; - buspirate_jtag_command(fd, (char *)tmp, 1); + buspirate_jtag_command(fd, tmp, 1); a = tmp[2] << 8 | tmp[3]; b = tmp[4] << 8 | tmp[5]; c = tmp[6] << 8 | tmp[7]; @@ -1129,7 +1129,7 @@ static void buspirate_jtag_get_adcs(int fd) } static unsigned char buspirate_jtag_command(int fd, - char *cmd, int cmdlen) + uint8_t *cmd, int cmdlen) { int res; int len = 0; @@ -1220,7 +1220,7 @@ static int buspirate_serial_setspeed(int fd, char speed, cc_t timeout) return 0; } -static int buspirate_serial_write(int fd, char *buf, int size) +static int buspirate_serial_write(int fd, uint8_t *buf, int size) { int ret = 0; @@ -1235,7 +1235,7 @@ static int buspirate_serial_write(int fd, char *buf, int size) return ret; } -static int buspirate_serial_read(int fd, char *buf, int size) +static int buspirate_serial_read(int fd, uint8_t *buf, int size) { int len = 0; int ret = 0; @@ -1274,7 +1274,7 @@ static void buspirate_serial_close(int fd) #define LINE_SIZE 81 #define BYTES_PER_LINE 16 -static void buspirate_print_buffer(char *buf, int size) +static void buspirate_print_buffer(uint8_t *buf, int size) { char line[LINE_SIZE]; char tmp[10]; @@ -1311,7 +1311,7 @@ static int buspirate_swd_switch_seq(enum swd_special_seq seq) { const uint8_t *sequence; int sequence_len; - char tmp[64]; + uint8_t tmp[64]; switch (seq) { case LINE_RESET: @@ -1349,7 +1349,7 @@ static int buspirate_swd_switch_seq(enum swd_special_seq seq) static uint8_t buspirate_swd_write_header(uint8_t cmd) { - char tmp[8]; + uint8_t tmp[8]; int to_send; tmp[0] = 0x10; /* bus pirate: send 1 byte */ @@ -1373,7 +1373,7 @@ static uint8_t buspirate_swd_write_header(uint8_t cmd) static void buspirate_swd_idle_clocks(uint32_t no_bits) { uint32_t no_bytes; - char tmp[20]; + uint8_t tmp[20]; no_bytes = (no_bits + 7) / 8; memset(tmp + 1, 0x00, sizeof(tmp) - 1); @@ -1403,7 +1403,7 @@ static void buspirate_swd_clear_sticky_errors(void) static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) { - char tmp[16]; + uint8_t tmp[16]; LOG_DEBUG("buspirate_swd_read_reg"); assert(cmd & SWD_CMD_RnW); @@ -1470,7 +1470,7 @@ static void buspirate_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_del static void buspirate_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) { - char tmp[16]; + uint8_t tmp[16]; LOG_DEBUG("buspirate_swd_write_reg"); assert(!(cmd & SWD_CMD_RnW)); From 3a32902987fd1ebf256f4f2aea79c7c87ed86070 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Thu, 18 Jan 2018 11:39:52 +0300 Subject: [PATCH 51/91] HACKING: clarify linking identities procedure Change-Id: I89e93002181926eec5fc5a339765b773559a8ff1 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4354 Tested-by: jenkins Reviewed-by: Tomas Vanek --- HACKING | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/HACKING b/HACKING index 162da8698..0bea65a75 100644 --- a/HACKING +++ b/HACKING @@ -1,13 +1,20 @@ // This file is part of the Doxygen Developer Manual /** @page patchguide Patch Guidelines -\attention If you're behind a corporate wall with http only access to the -world, you can still use these instructions! - \attention You can't send patches to the mailing list anymore at all. Nowadays you are expected to send patches to the OpenOCD Gerrit GIT server for a review. +\attention If you already have a Gerrit account and want to try a +different sign in method, please first sign in as usually, press your +name in the upper-right corner, go to @a Settings, select @a +Identities pane, press Link Another Identity button. In case +you already have duplicated accounts, ask administrators for manual +merging. + +\attention If you're behind a corporate wall with http only access to the +world, you can still use these instructions! + @section gerrit Submitting patches to the OpenOCD Gerrit server OpenOCD is to some extent a "self service" open source project, so to From 8b192df59a10df105af3cff1551f5181deea83d6 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Thu, 18 Jan 2018 11:59:10 +0300 Subject: [PATCH 52/91] svf: improve robustness when processing invalid SVF files Uninitialized argument value warnings reported by clang static analizer. Change-Id: I30af4900f517ffc0a7282689b58c7a224cdc080a Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4356 Tested-by: jenkins --- src/svf/svf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/svf/svf.c b/src/svf/svf.c index 1d686ba61..223af7e18 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -741,6 +741,9 @@ parse_char: pos++; } + if (num == 0) + return ERROR_FAIL; + *num_of_argu = num; return ERROR_OK; @@ -1313,7 +1316,7 @@ XXR_common: * SEC]] [ENDSTATE end_state] */ /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE * end_state] */ - if ((num_of_argu < 3) && (num_of_argu > 11)) { + if ((num_of_argu < 3) || (num_of_argu > 11)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } From 7ac798016fe1de11b20c4450a861ee477e7ed6c9 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sat, 27 Jan 2018 20:23:24 +0300 Subject: [PATCH 53/91] tcl: interface: usb blaster I: specify driver explicitly When a user asks for blaster I, he or she should either get it, or get an error, not blaster II driver. Change-Id: Ibc7683676ce42773e2b14ea5ccb3d119d1e6acea Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4381 Tested-by: jenkins --- tcl/interface/altera-usb-blaster.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/tcl/interface/altera-usb-blaster.cfg b/tcl/interface/altera-usb-blaster.cfg index f19abfebe..1bfef9dc4 100644 --- a/tcl/interface/altera-usb-blaster.cfg +++ b/tcl/interface/altera-usb-blaster.cfg @@ -5,6 +5,7 @@ # interface usb_blaster +usb_blaster_lowlevel_driver ftdi # These are already the defaults. # usb_blaster_vid_pid 0x09FB 0x6001 # usb_blaster_device_desc "USB-Blaster" From a957a1c8433f45452902de3060364122602e6e1c Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sun, 28 Jan 2018 15:48:46 +0300 Subject: [PATCH 54/91] target: arm: disassembler: fix Thumb2 BLX decoding address Since BLX in Thumb2 always switches mode to ARM, the PC needs to be 4-bytes aligned. Change-Id: I4f4c194fe21093cecfd9872e1d30588f4adc7257 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4382 Reviewed-by: Philipp Guehring Tested-by: jenkins Reviewed-by: Paul Sokolovsky --- src/target/arm_disassembler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index ef69a203c..8e783d342 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -2978,6 +2978,7 @@ static int t2ev_b_bl(uint32_t opcode, uint32_t address, case 0x4: inst = "BLX"; instruction->type = ARM_BLX; + address &= 0xfffffffc; break; case 0x5: inst = "BL"; From 6e76e56e2e34b78e4f0fad4238c2de85b1983305 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sat, 13 Jan 2018 17:15:29 +0300 Subject: [PATCH 55/91] target: hla: check return value of hl_dcc_read This should fix "Assigned value is garbage or undefined" warning reported by clang: http://build.openocd.org/job/openocd-clang/doclinks/1/report-391318.html Change-Id: Ib9488fadca871814328501e415f88822291e0c96 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4332 Tested-by: jenkins --- src/target/hla_target.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/target/hla_target.c b/src/target/hla_target.c index a3e683597..ba88248e3 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -271,7 +271,10 @@ static int hl_target_request_data(struct target *target, uint32_t i; for (i = 0; i < (size * 4); i++) { - hl_dcc_read(hl_if, &data, &ctrl); + int err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + buffer[i] = data; } @@ -281,6 +284,8 @@ static int hl_target_request_data(struct target *target, static int hl_handle_target_request(void *priv) { struct target *target = priv; + int err; + if (!target_was_examined(target)) return ERROR_OK; struct hl_interface_s *hl_if = target_to_adapter(target); @@ -292,7 +297,9 @@ static int hl_handle_target_request(void *priv) uint8_t data; uint8_t ctrl; - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; /* check if we have data */ if (ctrl & (1 << 0)) { @@ -300,11 +307,20 @@ static int hl_handle_target_request(void *priv) /* we assume target is quick enough */ request = data; - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + request |= (data << 8); - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + request |= (data << 16); - hl_dcc_read(hl_if, &data, &ctrl); + err = hl_dcc_read(hl_if, &data, &ctrl); + if (err != ERROR_OK) + return err; + request |= (data << 24); target_request(target, request); } From ffb93ef37134afcbed2ac958918c95d66f86b7a3 Mon Sep 17 00:00:00 2001 From: Matej Kogovsek Date: Sun, 3 Sep 2017 12:19:41 +0200 Subject: [PATCH 56/91] jtag: drivers: add support for FT232R sync bitbang JTAG interfaces Change-Id: Ib88a9e270f5c2a50902a137bcc97fdefd5aad1c6 Signed-off-by: Matej Kogovsek Reviewed-on: http://openocd.zylin.com/4215 Tested-by: jenkins Reviewed-by: Paul Fertser --- configure.ac | 1 + doc/openocd.texi | 30 ++ src/jtag/drivers/Makefile.am | 3 + src/jtag/drivers/ft232r.c | 669 +++++++++++++++++++++++++++++++++++ src/jtag/interfaces.c | 6 + tcl/interface/ft232r.cfg | 2 + 6 files changed, 711 insertions(+) create mode 100644 src/jtag/drivers/ft232r.c create mode 100644 tcl/interface/ft232r.cfg diff --git a/configure.ac b/configure.ac index 562ec5a7c..f4f66ab43 100644 --- a/configure.ac +++ b/configure.ac @@ -114,6 +114,7 @@ m4_define([USB1_ADAPTERS], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]], + [[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]]]) m4_define([USB_ADAPTERS], diff --git a/doc/openocd.texi b/doc/openocd.texi index 3a38a9680..ce9cd3b96 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2559,6 +2559,36 @@ For example adapter definitions, see the configuration files shipped in the @end deffn +@deffn {Interface Driver} {ft232r} +This driver is implementing synchronous bitbang mode of an FTDI FT232R +USB UART bridge IC. + +List of connections (pin numbers for SSOP): +@itemize @minus +@item RXD(5) - TDI +@item TXD(1) - TCK +@item RTS(3) - TDO +@item CTS(11) - TMS +@item DTR(2) - TRST +@item DCD(10) - SRST +@end itemize + +These interfaces have several commands, used to configure the driver +before initializing the JTAG scan chain: + +@deffn {Config Command} {ft232r_vid_pid} @var{vid} @var{pid} +The vendor ID and product ID of the adapter. If not specified, default +0x0403:0x6001 is used. +@end deffn + +@deffn {Config Command} {ft232r_serial_desc} @var{serial} +Specifies the @var{serial} of the adapter to use, in case the +vendor provides unique IDs and more than one adapter is connected to +the host. If not specified, serial numbers are not considered. +@end deffn + +@end deffn + @deffn {Interface Driver} {remote_bitbang} Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection with a remote process and sends ASCII encoded bitbang requests to that process diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 3e5974da4..b3b4d2198 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -80,6 +80,9 @@ if USB_BLASTER_DRIVER %C%_libocdjtagdrivers_la_LIBADD += %D%/usb_blaster/libocdusbblaster.la include %D%/usb_blaster/Makefile.am endif +if FT232R +DRIVERFILES += %D%/ft232r.c +endif if AMTJTAGACCEL DRIVERFILES += %D%/amt_jtagaccel.c endif diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c new file mode 100644 index 000000000..fc3d75f43 --- /dev/null +++ b/src/jtag/drivers/ft232r.c @@ -0,0 +1,669 @@ +/*************************************************************************** + * Copyright (C) 2010 Serge Vakulenko * + * serge@vak.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +/* project specific includes */ +#include +#include +#include +#include "libusb1_common.h" + +/* system includes */ +#include +#include +#include +#include +#include + +/* + * Bit 7 (0x80, pin 6, RI ): unused. + * Bit 6 (0x40, pin 10,DCD): /SYSRST output. + * Bit 5 (0x20, pin 9, DSR): unused. + * Bit 4 (0x10, pin 2, DTR): /TRST output. + * Bit 3 (0x08, pin 11,CTS): TMS output. + * Bit 2 (0x04, pin 3, RTS): TDO input. + * Bit 1 (0x02, pin 5, RXD): TDI output. + * Bit 0 (0x01, pin 1, TXD): TCK output. + * + * Sync bit bang mode is implemented as described in FTDI Application + * Note AN232R-01: "Bit Bang Modes for the FT232R and FT245R". + */ +#define TCK (1 << 0) +#define TDI (1 << 1) +#define READ_TDO (1 << 2) +#define TMS (1 << 3) +#define NTRST (1 << 4) +#define NSYSRST (1 << 6) + +/* + * USB endpoints. + */ +#define IN_EP 0x02 +#define OUT_EP 0x81 + +/* Requests */ +#define SIO_RESET 0 /* Reset the port */ +#define SIO_MODEM_CTRL 1 /* Set the modem control register */ +#define SIO_SET_FLOW_CTRL 2 /* Set flow control register */ +#define SIO_SET_BAUD_RATE 3 /* Set baud rate */ +#define SIO_SET_DATA 4 /* Set the data characteristics of the port */ +#define SIO_POLL_MODEM_STATUS 5 +#define SIO_SET_EVENT_CHAR 6 +#define SIO_SET_ERROR_CHAR 7 +#define SIO_SET_LATENCY_TIMER 9 +#define SIO_GET_LATENCY_TIMER 10 +#define SIO_SET_BITMODE 11 +#define SIO_READ_PINS 12 +#define SIO_READ_EEPROM 0x90 +#define SIO_WRITE_EEPROM 0x91 +#define SIO_ERASE_EEPROM 0x92 + +#define FT232R_BUF_SIZE 4000 + +static char *ft232r_serial_desc; +static uint16_t ft232r_vid = 0x0403; /* FTDI */ +static uint16_t ft232r_pid = 0x6001; /* FT232R */ +static jtag_libusb_device_handle *adapter; + +static uint8_t *ft232r_output; +static size_t ft232r_output_len; + +/** + * Perform sync bitbang output/input transaction. + * Before call, an array ft232r_output[] should be filled with data to send. + * Counter ft232r_output_len contains the number of bytes to send. + * On return, received data is put back to array ft232r_output[]. + */ +static int ft232r_send_recv(void) +{ + /* FIFO TX buffer has 128 bytes. + * FIFO RX buffer has 256 bytes. + * First two bytes of received packet contain contain modem + * and line status and are ignored. + * Unfortunately, transfer sizes bigger than 64 bytes + * frequently cause hang ups. */ + assert(ft232r_output_len > 0); + + size_t total_written = 0; + size_t total_read = 0; + int rxfifo_free = 128; + + while (total_read < ft232r_output_len) { + /* Write */ + int bytes_to_write = ft232r_output_len - total_written; + if (bytes_to_write > 64) + bytes_to_write = 64; + if (bytes_to_write > rxfifo_free) + bytes_to_write = rxfifo_free; + + if (bytes_to_write) { + int n = jtag_libusb_bulk_write(adapter, IN_EP, + (char *) ft232r_output + total_written, + bytes_to_write, 1000); + + if (n == 0) { + LOG_ERROR("usb bulk write failed"); + return ERROR_JTAG_DEVICE_ERROR; + } + + total_written += n; + rxfifo_free -= n; + } + + /* Read */ + uint8_t reply[64]; + + int n = jtag_libusb_bulk_read(adapter, OUT_EP, + (char *) reply, + sizeof(reply), 1000); + + if (n == 0) { + LOG_ERROR("usb bulk read failed"); + return ERROR_JTAG_DEVICE_ERROR; + } + if (n > 2) { + /* Copy data, ignoring first 2 bytes. */ + memcpy(ft232r_output + total_read, reply + 2, n - 2); + int bytes_read = n - 2; + total_read += bytes_read; + rxfifo_free += bytes_read; + if (total_read > total_written) { + LOG_ERROR("read more bytes than wrote"); + return ERROR_JTAG_DEVICE_ERROR; + } + } + } + ft232r_output_len = 0; + return ERROR_OK; +} + +/** + * Add one TCK/TMS/TDI sample to send buffer. + */ +static void ft232r_write(int tck, int tms, int tdi) +{ + unsigned out_value = NTRST | NSYSRST; + if (tck) + out_value |= TCK; + if (tms) + out_value |= TMS; + if (tdi) + out_value |= TDI; + + if (ft232r_output_len >= FT232R_BUF_SIZE) { + /* FIXME: should we just execute queue here? */ + LOG_ERROR("ft232r_write: buffer overflow"); + return; + } + ft232r_output[ft232r_output_len++] = out_value; +} + +/** + * Control /TRST and /SYSRST pins. + * Perform immediate bitbang transaction. + */ +static void ft232r_reset(int trst, int srst) +{ + unsigned out_value = NTRST | NSYSRST; + LOG_DEBUG("ft232r_reset(%d,%d)", trst, srst); + + if (trst == 1) + out_value &= ~NTRST; /* switch /TRST low */ + else if (trst == 0) + out_value |= NTRST; /* switch /TRST high */ + + if (srst == 1) + out_value &= ~NSYSRST; /* switch /SYSRST low */ + else if (srst == 0) + out_value |= NSYSRST; /* switch /SYSRST high */ + + if (ft232r_output_len >= FT232R_BUF_SIZE) { + /* FIXME: should we just execute queue here? */ + LOG_ERROR("ft232r_write: buffer overflow"); + return; + } + + ft232r_output[ft232r_output_len++] = out_value; + ft232r_send_recv(); +} + +static int ft232r_speed(int divisor) +{ + int baud = (divisor == 0) ? 3000000 : + (divisor == 1) ? 2000000 : + 3000000 / divisor; + LOG_DEBUG("ft232r_speed(%d) rate %d bits/sec", divisor, baud); + + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_BAUD_RATE, divisor, 0, 0, 0, 1000) != 0) { + LOG_ERROR("cannot set baud rate"); + return ERROR_JTAG_DEVICE_ERROR; + } + return ERROR_OK; +} + +static int ft232r_init(void) +{ + uint16_t avids[] = {ft232r_vid, 0}; + uint16_t apids[] = {ft232r_pid, 0}; + if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter)) { + LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", + ft232r_vid, ft232r_pid, (ft232r_serial_desc == NULL) ? "[any]" : ft232r_serial_desc); + return ERROR_JTAG_INIT_FAILED; + } + + libusb_detach_kernel_driver(adapter, 0); + + if (jtag_libusb_claim_interface(adapter, 0)) { + LOG_ERROR("unable to claim interface"); + return ERROR_JTAG_INIT_FAILED; + } + + /* Reset the device. */ + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_RESET, 0, 0, 0, 0, 1000) != 0) { + LOG_ERROR("unable to reset device"); + return ERROR_JTAG_INIT_FAILED; + } + + /* Sync bit bang mode. */ + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_BITMODE, TCK | TDI | TMS | NTRST | NSYSRST | 0x400, + 0, 0, 0, 1000) != 0) { + LOG_ERROR("cannot set sync bitbang mode"); + return ERROR_JTAG_INIT_FAILED; + } + + /* Exactly 500 nsec between updates. */ + unsigned divisor = 1; + unsigned char latency_timer = 1; + + /* Frequency divisor is 14-bit non-zero value. */ + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_BAUD_RATE, divisor, + 0, 0, 0, 1000) != 0) { + LOG_ERROR("cannot set baud rate"); + return ERROR_JTAG_INIT_FAILED; + } + if (jtag_libusb_control_transfer(adapter, + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, + SIO_SET_LATENCY_TIMER, latency_timer, 0, 0, 0, 1000) != 0) { + LOG_ERROR("unable to set latency timer"); + return ERROR_JTAG_INIT_FAILED; + } + + ft232r_output = malloc(FT232R_BUF_SIZE); + if (ft232r_output == NULL) { + LOG_ERROR("Unable to allocate memory for the buffer"); + return ERROR_JTAG_INIT_FAILED; + } + + return ERROR_OK; +} + +static int ft232r_quit(void) +{ + if (jtag_libusb_release_interface(adapter, 0) != 0) + LOG_ERROR("usb release interface failed"); + + jtag_libusb_close(adapter); + free(ft232r_output); + + return ERROR_OK; +} + +static int ft232r_speed_div(int divisor, int *khz) +{ + /* Maximum 3 Mbaud for bit bang mode. */ + if (divisor == 0) + *khz = 3000; + else if (divisor == 1) + *khz = 2000; + else + *khz = 3000 / divisor; + return ERROR_OK; +} + +static int ft232r_khz(int khz, int *divisor) +{ + if (khz == 0) { + LOG_DEBUG("RCLK not supported"); + return ERROR_FAIL; + } + + /* Calculate frequency divisor. */ + if (khz > 2500) + *divisor = 0; /* Special case: 3 MHz */ + else if (khz > 1700) + *divisor = 1; /* Special case: 2 MHz */ + else { + *divisor = (2*3000 / khz + 1) / 2; + if (*divisor > 0x3FFF) + *divisor = 0x3FFF; + } + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_serial_desc_command) +{ + if (CMD_ARGC == 1) + ft232r_serial_desc = strdup(CMD_ARGV[0]); + else + LOG_ERROR("require exactly one argument to " + "ft232r_serial_desc "); + return ERROR_OK; +} + +COMMAND_HANDLER(ft232r_handle_vid_pid_command) +{ + if (CMD_ARGC > 2) { + LOG_WARNING("ignoring extra IDs in ft232r_vid_pid " + "(maximum is 1 pair)"); + CMD_ARGC = 2; + } + if (CMD_ARGC == 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_vid); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], ft232r_pid); + } else + LOG_WARNING("incomplete ft232r_vid_pid configuration"); + + return ERROR_OK; +} + +static const struct command_registration ft232r_command_handlers[] = { + { + .name = "ft232r_serial_desc", + .handler = ft232r_handle_serial_desc_command, + .mode = COMMAND_CONFIG, + .help = "USB serial descriptor of the adapter", + .usage = "serial string", + }, + { + .name = "ft232r_vid_pid", + .handler = ft232r_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "USB VID and PID of the adapter", + .usage = "vid pid", + }, + COMMAND_REGISTRATION_DONE +}; + +/* + * Synchronous bitbang protocol implementation. + */ + +static void syncbb_end_state(tap_state_t state) +{ + if (tap_is_state_stable(state)) + tap_set_end_state(state); + else { + LOG_ERROR("BUG: %i is not a valid end state", state); + exit(-1); + } +} + +static void syncbb_state_move(int skip) +{ + int i = 0, tms = 0; + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + for (i = skip; i < tms_count; i++) { + tms = (tms_scan >> i) & 1; + ft232r_write(0, tms, 0); + ft232r_write(1, tms, 0); + } + ft232r_write(0, tms, 0); + + tap_set_state(tap_get_end_state()); +} + +/** + * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG + * (or SWD) state machine. + */ +static int syncbb_execute_tms(struct jtag_command *cmd) +{ + unsigned num_bits = cmd->cmd.tms->num_bits; + const uint8_t *bits = cmd->cmd.tms->bits; + + DEBUG_JTAG_IO("TMS: %d bits", num_bits); + + int tms = 0; + for (unsigned i = 0; i < num_bits; i++) { + tms = ((bits[i/8] >> (i % 8)) & 1); + ft232r_write(0, tms, 0); + ft232r_write(1, tms, 0); + } + ft232r_write(0, tms, 0); + + return ERROR_OK; +} + +static void syncbb_path_move(struct pathmove_command *cmd) +{ + int num_states = cmd->num_states; + int state_count; + int tms = 0; + + state_count = 0; + while (num_states) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { + tms = 0; + } else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) { + tms = 1; + } else { + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", + tap_state_name(tap_get_state()), + tap_state_name(cmd->path[state_count])); + exit(-1); + } + + ft232r_write(0, tms, 0); + ft232r_write(1, tms, 0); + + tap_set_state(cmd->path[state_count]); + state_count++; + num_states--; + } + + ft232r_write(0, tms, 0); + + tap_set_end_state(tap_get_state()); +} + +static void syncbb_runtest(int num_cycles) +{ + int i; + + tap_state_t saved_end_state = tap_get_end_state(); + + /* only do a state_move when we're not already in IDLE */ + if (tap_get_state() != TAP_IDLE) { + syncbb_end_state(TAP_IDLE); + syncbb_state_move(0); + } + + /* execute num_cycles */ + for (i = 0; i < num_cycles; i++) { + ft232r_write(0, 0, 0); + ft232r_write(1, 0, 0); + } + ft232r_write(0, 0, 0); + + /* finish in end_state */ + syncbb_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) + syncbb_state_move(0); +} + +/** + * Function syncbb_stableclocks + * issues a number of clock cycles while staying in a stable state. + * Because the TMS value required to stay in the RESET state is a 1, whereas + * the TMS value required to stay in any of the other stable states is a 0, + * this function checks the current stable state to decide on the value of TMS + * to use. + */ +static void syncbb_stableclocks(int num_cycles) +{ + int tms = (tap_get_state() == TAP_RESET ? 1 : 0); + int i; + + /* send num_cycles clocks onto the cable */ + for (i = 0; i < num_cycles; i++) { + ft232r_write(1, tms, 0); + ft232r_write(0, tms, 0); + } +} + +static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) +{ + tap_state_t saved_end_state = tap_get_end_state(); + int bit_cnt, bit0_index; + + if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { + if (ir_scan) + syncbb_end_state(TAP_IRSHIFT); + else + syncbb_end_state(TAP_DRSHIFT); + + syncbb_state_move(0); + syncbb_end_state(saved_end_state); + } + + bit0_index = ft232r_output_len; + for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { + int tms = (bit_cnt == scan_size-1) ? 1 : 0; + int tdi; + int bytec = bit_cnt/8; + int bcval = 1 << (bit_cnt % 8); + + /* if we're just reading the scan, but don't care about the output + * default to outputting 'low', this also makes valgrind traces more readable, + * as it removes the dependency on an uninitialised value + */ + tdi = 0; + if ((type != SCAN_IN) && (buffer[bytec] & bcval)) + tdi = 1; + + ft232r_write(0, tms, tdi); + ft232r_write(1, tms, tdi); + } + + if (tap_get_state() != tap_get_end_state()) { + /* we *KNOW* the above loop transitioned out of + * the shift state, so we skip the first state + * and move directly to the end state. + */ + syncbb_state_move(1); + } + ft232r_send_recv(); + + if (type != SCAN_OUT) + for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { + int bytec = bit_cnt/8; + int bcval = 1 << (bit_cnt % 8); + int val = ft232r_output[bit0_index + bit_cnt*2 + 1]; + + if (val & READ_TDO) + buffer[bytec] |= bcval; + else + buffer[bytec] &= ~bcval; + } +} + +static int syncbb_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ + int scan_size; + enum scan_type type; + uint8_t *buffer; + int retval; + + /* return ERROR_OK, unless a jtag_read_buffer returns a failed check + * that wasn't handled by a caller-provided error handler + */ + retval = ERROR_OK; + +/* ft232r_blink(1);*/ + + while (cmd) { + switch (cmd->type) { + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + + if ((cmd->cmd.reset->trst == 1) || + (cmd->cmd.reset->srst && + (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { + tap_set_state(TAP_RESET); + } + ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + + syncbb_end_state(cmd->cmd.runtest->end_state); + syncbb_runtest(cmd->cmd.runtest->num_cycles); + break; + + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + + case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */ + LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); + + syncbb_end_state(cmd->cmd.statemove->end_state); + syncbb_state_move(0); + break; + + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + + syncbb_path_move(cmd->cmd.pathmove); + break; + + case JTAG_SCAN: + LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + + syncbb_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + if (buffer) + free(buffer); + break; + + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); + + jtag_sleep(cmd->cmd.sleep->us); + break; + + case JTAG_TMS: + retval = syncbb_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); + } + if (ft232r_output_len > 0) + ft232r_send_recv(); + cmd = cmd->next; + } +/* ft232r_blink(0);*/ + + return retval; +} + +struct jtag_interface ft232r_interface = { + .name = "ft232r", + .commands = ft232r_command_handlers, + .transports = jtag_only, + .supported = DEBUG_CAP_TMS_SEQ, + + .execute_queue = syncbb_execute_queue, + + .speed = ft232r_speed, + .init = ft232r_init, + .quit = ft232r_quit, + .speed_div = ft232r_speed_div, + .khz = ft232r_khz, +}; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 174c63a3c..ddeadb466 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -60,6 +60,9 @@ extern struct jtag_interface usb_blaster_interface; #if BUILD_JTAG_VPI == 1 extern struct jtag_interface jtag_vpi_interface; #endif +#if BUILD_FT232R == 1 +extern struct jtag_interface ft232r_interface; +#endif #if BUILD_AMTJTAGACCEL == 1 extern struct jtag_interface amt_jtagaccel_interface; #endif @@ -159,6 +162,9 @@ struct jtag_interface *jtag_interfaces[] = { #if BUILD_JTAG_VPI == 1 &jtag_vpi_interface, #endif +#if BUILD_FT232R == 1 + &ft232r_interface, +#endif #if BUILD_AMTJTAGACCEL == 1 &amt_jtagaccel_interface, #endif diff --git a/tcl/interface/ft232r.cfg b/tcl/interface/ft232r.cfg new file mode 100644 index 000000000..b4f71c8d4 --- /dev/null +++ b/tcl/interface/ft232r.cfg @@ -0,0 +1,2 @@ +interface ft232r +adapter_khz 1000 From 6f700d2b1c57d40c6ce4e9972427334f89bbc96c Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 13 Mar 2018 10:30:59 +0100 Subject: [PATCH 57/91] doc: make gdb-attach description understandable Change-Id: I31babf4e3bbe7c94f26818d938699562a4a26d48 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4465 Tested-by: jenkins Reviewed-by: Paul Fertser --- doc/openocd.texi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index ce9cd3b96..4cc051ee4 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4488,9 +4488,10 @@ The following target events are defined: @item @b{examine-end} @* After target examine is called with no errors. @item @b{gdb-attach} -@* When GDB connects. This is before any communication with the target and GDB -expects the target is halted during attachment. -@xref{gdbmeminspect,,GDB as a non-intrusive memory inspector} for exclusion. +@* When GDB connects. Issued before any GDB communication with the target +starts. GDB expects the target is halted during attachment. +@xref{gdbmeminspect,,GDB as a non-intrusive memory inspector}, how to +connect GDB to running target. The event can be also used to set up the target so it is possible to probe flash. Probing flash is necessary during GDB connect if you want to use @pxref{programmingusinggdb,,programming using GDB}. From 437925c1415ac1f7d5b1b1bb4dcfb4898849d499 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Tue, 13 Mar 2018 13:48:25 +0300 Subject: [PATCH 58/91] doc: fix xref texinfo warning Change-Id: Iff1ba5836e3a4f352903c3a5ae73c7d992306d42 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4466 Reviewed-by: Tomas Vanek Tested-by: jenkins --- doc/openocd.texi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 4cc051ee4..6362b41f2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9259,7 +9259,7 @@ event gdb-flash-erase-start: @example $_TARGETNAME configure -event gdb-flash-erase-start BODY @end example -@xref{targetevents,,Target Events} for other GDB programming related events. +@xref{targetevents,,Target Events}, for other GDB programming related events. To verify any flash programming the GDB command @option{compare-sections} can be used. From a0b76360b874607f2aa075e764891f129b5ff0f9 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 10 Feb 2018 18:51:40 +0100 Subject: [PATCH 59/91] tcl/target: warn if a Kinetis MCU is connected to a high level adapter Make sure the user is aware he can lock the device though unlock is not possible without access to MDM-AP. Change-Id: I92676530e95d19489c6739748a99c2895849f90f Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4403 Tested-by: jenkins --- tcl/target/klx.cfg | 14 +++++++++++++- tcl/target/kx.cfg | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index 1a2ee6798..b41dbf78e 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -43,7 +43,19 @@ adapter_khz 1000 reset_config srst_nogate -if {![using_hla]} { +if {[using_hla]} { + echo "" + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." + echo " A high level adapter (like a ST-Link) you are currently using cannot access" + echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" + echo " configuration. Also security locked state of the device will not be reported." + echo "" + echo " Be very careful as you can lock the device though there is no way to unlock" + echo " it without mass erase. Don't set write protection on the first block." + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo "" +} { # Detect secured MCU or boot lock-up in RESET/WDOG loop $_CHIPNAME.cpu configure -event examine-start { kinetis mdm check_security diff --git a/tcl/target/kx.cfg b/tcl/target/kx.cfg index 7b0351706..51703e69d 100644 --- a/tcl/target/kx.cfg +++ b/tcl/target/kx.cfg @@ -44,7 +44,20 @@ adapter_khz 1000 reset_config srst_nogate -if {![using_hla]} { +if {[using_hla]} { + echo "" + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo " Kinetis MCUs have a MDM-AP dedicated mainly to MCU security related functions." + echo " A high level adapter (like a ST-Link) you are currently using cannot access" + echo " the MDM-AP, so commands like 'mdm mass_erase' are not available in your" + echo " configuration. Also security locked state of the device will not be reported." + echo " Expect problems connecting to a blank device without boot ROM." + echo "" + echo " Be very careful as you can lock the device though there is no way to unlock" + echo " it without mass erase. Don't set write protection on the first block." + echo "!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!" + echo "" +} { # Detect secured MCU or boot lock-up in RESET/WDOG loop $_CHIPNAME.cpu configure -event examine-start { kinetis mdm check_security From ae5b30ae960b35187751e9d837d5dc42745d2376 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Feb 2018 22:53:14 +0100 Subject: [PATCH 60/91] openocd.c: call server_quit() for cmd line with -c shutdown If OpenOCD command line contains -c shutdown, server_quit() is not called. Though if -c init is also on command line, gdb_server is already initialized. Call server_quit() on both successful and failure exit from command line. Change-Id: I6df41c5df045b61d84a5515d1abaa5dc96bc30ac Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4409 Tested-by: jenkins --- src/openocd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/openocd.c b/src/openocd.c index 05533aae3..739442163 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -286,10 +286,13 @@ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ct return ERROR_FAIL; ret = parse_config_file(cmd_ctx); - if (ret == ERROR_COMMAND_CLOSE_CONNECTION) + if (ret == ERROR_COMMAND_CLOSE_CONNECTION) { + server_quit(); /* gdb server may be initialized by -c init */ return ERROR_OK; - else if (ret != ERROR_OK) + } else if (ret != ERROR_OK) { + server_quit(); /* gdb server may be initialized by -c init */ return ERROR_FAIL; + } ret = server_init(cmd_ctx); if (ERROR_OK != ret) From 33a33553046bc720800f410adbc81bc2fb175e74 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 00:22:42 +0100 Subject: [PATCH 61/91] server: free strduped port numbers Although the leak is negligible, the clean heap on exit will ease valgrind testing. Change-Id: I3a7a9c8e8dc7557aa51d0b9caa244537e5e7007d Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4410 Tested-by: jenkins --- src/openocd.c | 3 +++ src/server/gdb_server.c | 6 ++++++ src/server/gdb_server.h | 1 + src/server/server.c | 7 +++++++ src/server/server.h | 1 + src/server/tcl_server.c | 5 +++++ src/server/tcl_server.h | 1 + src/server/telnet_server.c | 5 +++++ src/server/telnet_server.h | 1 + src/target/openrisc/jsp_server.c | 4 ++++ src/target/openrisc/jsp_server.h | 1 + 11 files changed, 35 insertions(+) diff --git a/src/openocd.c b/src/openocd.c index 739442163..54fc83a17 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -345,6 +345,9 @@ int openocd_main(int argc, char *argv[]) /* Start the executable meat that can evolve into thread in future. */ ret = openocd_thread(argc, argv, cmd_ctx); + gdb_service_free(); + server_free(); + unregister_all_commands(cmd_ctx, NULL); /* Shutdown commandline interface */ diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 5319106a3..c52176911 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3572,3 +3572,9 @@ int gdb_register_commands(struct command_context *cmd_ctx) gdb_port_next = strdup("3333"); return register_commands(cmd_ctx, NULL, gdb_command_handlers); } + +void gdb_service_free(void) +{ + free(gdb_port); + free(gdb_port_next); +} diff --git a/src/server/gdb_server.h b/src/server/gdb_server.h index 2b4ac4eaf..993984bc3 100644 --- a/src/server/gdb_server.h +++ b/src/server/gdb_server.h @@ -36,6 +36,7 @@ struct reg; int gdb_target_add_all(struct target *target); int gdb_register_commands(struct command_context *command_context); +void gdb_service_free(void); int gdb_put_packet(struct connection *connection, char *buffer, int len); diff --git a/src/server/server.c b/src/server/server.c index 6fa864bbc..8fd2d71d4 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -641,6 +641,13 @@ int server_quit(void) return last_signal; } +void server_free(void) +{ + tcl_service_free(); + telnet_service_free(); + jsp_service_free(); +} + void exit_on_signal(int sig) { #ifndef _WIN32 diff --git a/src/server/server.h b/src/server/server.h index 8c8062675..d4eae9424 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -82,6 +82,7 @@ int add_service(char *name, const char *port, int server_preinit(void); int server_init(struct command_context *cmd_ctx); int server_quit(void); +void server_free(void); void exit_on_signal(int); int server_loop(struct command_context *command_context); diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 7c40f7dce..3cb63a275 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -359,3 +359,8 @@ int tcl_register_commands(struct command_context *cmd_ctx) tcl_port = strdup("6666"); return register_commands(cmd_ctx, NULL, tcl_command_handlers); } + +void tcl_service_free(void) +{ + free(tcl_port); +} diff --git a/src/server/tcl_server.h b/src/server/tcl_server.h index 422c794ee..6ce3ab95f 100644 --- a/src/server/tcl_server.h +++ b/src/server/tcl_server.h @@ -22,5 +22,6 @@ int tcl_init(void); int tcl_register_commands(struct command_context *cmd_ctx); +void tcl_service_free(void); #endif /* OPENOCD_SERVER_TCL_SERVER_H */ diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 9077b6c46..a864f5fd2 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -719,3 +719,8 @@ int telnet_register_commands(struct command_context *cmd_ctx) telnet_port = strdup("4444"); return register_commands(cmd_ctx, NULL, telnet_command_handlers); } + +void telnet_service_free(void) +{ + free(telnet_port); +} diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index 5e238f441..27148d7ce 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -64,5 +64,6 @@ struct telnet_service { int telnet_init(char *banner); int telnet_register_commands(struct command_context *command_context); +void telnet_service_free(void); #endif /* OPENOCD_SERVER_TELNET_SERVER_H */ diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index 2d90114fa..6cd53f43c 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -242,3 +242,7 @@ int jsp_register_commands(struct command_context *cmd_ctx) return register_commands(cmd_ctx, NULL, jsp_command_handlers); } +void jsp_service_free(void) +{ + free(jsp_port); +} diff --git a/src/target/openrisc/jsp_server.h b/src/target/openrisc/jsp_server.h index f8e71215a..e5cfaa8b4 100644 --- a/src/target/openrisc/jsp_server.h +++ b/src/target/openrisc/jsp_server.h @@ -13,5 +13,6 @@ struct jsp_service { int jsp_init(struct or1k_jtag *jtag_info, char *banner); int jsp_register_commands(struct command_context *cmd_ctx); +void jsp_service_free(void); #endif /* OPENOCD_TARGET_OPENRISC_JSP_SERVER_H */ From 63d768824550a9607daef9449eed422bd941ad32 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 00:56:44 +0100 Subject: [PATCH 62/91] jtag/core: free all taps and daps in adapter_quit() Change-Id: I74496f6ddfb0a72b2933e8d682a73a694b8d107b Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4411 Tested-by: jenkins --- src/jtag/core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index 8c79eb230..df4afeb9d 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1315,6 +1315,7 @@ void jtag_tap_free(struct jtag_tap *tap) free(tap->chip); free(tap->tapname); free(tap->dotted_name); + free(tap->dap); free(tap); } @@ -1472,13 +1473,19 @@ int jtag_init_inner(struct command_context *cmd_ctx) int adapter_quit(void) { - if (!jtag || !jtag->quit) - return ERROR_OK; + if (jtag && jtag->quit) { + /* close the JTAG interface */ + int result = jtag->quit(); + if (ERROR_OK != result) + LOG_ERROR("failed: %d", result); + } - /* close the JTAG interface */ - int result = jtag->quit(); - if (ERROR_OK != result) - LOG_ERROR("failed: %d", result); + struct jtag_tap *t = jtag_all_taps(); + while (t) { + struct jtag_tap *n = t->next_tap; + jtag_tap_free(t); + t = n; + } return ERROR_OK; } From 7ad11de2fa37b504fc84f608ee355cf02221429a Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 01:24:50 +0100 Subject: [PATCH 63/91] target/target: free what leaked in target_destroy() Free event_action, fileio_info and working area. Change-Id: Iac81230423e92304b8e2c971d0ec71a96b693fc4 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4412 Tested-by: jenkins --- src/target/target.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/target/target.c b/src/target/target.c index 32000c047..bd9d56b04 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1892,8 +1892,24 @@ static void target_destroy(struct target *target) if (target->type->deinit_target) target->type->deinit_target(target); + struct target_event_action *teap = target->event_action; + while (teap) { + struct target_event_action *next = teap->next; + Jim_DecrRefCount(teap->interp, teap->body); + free(teap); + teap = next; + } + + target_free_all_working_areas(target); + /* Now we have none or only one working area marked as free */ + if (target->working_areas) { + free(target->working_areas->backup); + free(target->working_areas); + } + free(target->type); free(target->trace_info); + free(target->fileio_info); free(target->cmd_name); free(target); } From 71f5f6eb14a1161875122d6b015b2f6fe2415b33 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 10:24:15 +0100 Subject: [PATCH 64/91] src/jtag/hla: free allocated memory in hl_interface_quit() Change-Id: If6ead00e47021c88e4c106b4aeaf038db87ff50b Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4413 Tested-by: jenkins --- src/jtag/hla/hla_interface.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 62a8f5947..cb9ef3969 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -119,6 +119,11 @@ static int hl_interface_quit(void) if (hl_if.layout->api->close) hl_if.layout->api->close(hl_if.handle); + jtag_command_queue_reset(); + + free((void *)hl_if.param.device_desc); + free((void *)hl_if.param.serial); + return ERROR_OK; } From ff23980434b3be523853034c71e61662303aa742 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 16 Feb 2018 09:13:36 +0100 Subject: [PATCH 65/91] drivers/ftdi: free allocated memory Also uses calloc() for mpsse_ctx->write_buffer to prevent a false positive valgrind report "Syscall param ioctl(USBDEVFS_SUBMITURB).buffer points to uninitialised bytes(s)" Change-Id: I91963371d15c21ea0fee4c40c1da86174db44520 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4418 Tested-by: jenkins --- src/jtag/drivers/ftdi.c | 12 ++++++++++++ src/jtag/drivers/mpsse.c | 8 +++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index e69707e5a..7c6709cd5 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -694,6 +694,18 @@ static int ftdi_quit(void) { mpsse_close(mpsse_ctx); + struct signal *sig = signals; + while (sig) { + struct signal *next = sig->next; + free((void *)sig->name); + free(sig); + sig = next; + } + + free(ftdi_device_desc); + free(ftdi_serial); + free(ftdi_location); + free(swd_cmd_queue); return ERROR_OK; diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index 924c97450..06d008b47 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -335,7 +335,13 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha ctx->write_size = 16384; ctx->read_chunk = malloc(ctx->read_chunk_size); ctx->read_buffer = malloc(ctx->read_size); - ctx->write_buffer = malloc(ctx->write_size); + + /* Use calloc to make valgrind happy: buffer_write() sets payload + * on bit basis, so some bits can be left uninitialized in write_buffer. + * Although this is perfectly ok with MPSSE, valgrind reports + * Syscall param ioctl(USBDEVFS_SUBMITURB).buffer points to uninitialised byte(s) */ + ctx->write_buffer = calloc(1, ctx->write_size); + if (!ctx->read_chunk || !ctx->read_buffer || !ctx->write_buffer) goto error; From a4cdce0129a6b206a2081d77dd518ce2cae0b71f Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 16 Feb 2018 11:58:10 +0100 Subject: [PATCH 66/91] gdb_server: prevent false positive valgrind report Change-Id: Ia59fdf8a23043889840122859b0c5bdb5f757703 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4420 Tested-by: jenkins --- src/server/gdb_server.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index c52176911..2acebe839 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2442,7 +2442,11 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list, else transfer_type = 'l'; - *chunk = malloc(length + 2); + *chunk = malloc(length + 2 + 3); + /* Allocating extra 3 bytes prevents false positive valgrind report + * of strlen(chunk) word access: + * Invalid read of size 4 + * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */ if (*chunk == NULL) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; From cbf7889873c16e80109ee7d46995a0adf08af84c Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Sun, 4 Mar 2018 18:52:14 +0100 Subject: [PATCH 67/91] gdb_server: fix ignored interrupt request from gdb during stepping Normally, when a ctrl-c is received from gdb, a SIGINT is reported back unconditionally to tell gdb that the target has stopped in response. However when a rtos support was configured, the rtos awareness overwrote the signal with an actual thread state, which gdb then ignored and got stuck without the user able to interrupt. Change-Id: I40fd62333e020a8c4d9df0079270e84df9c77f88 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4445 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 2acebe839..712c39341 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -732,7 +732,6 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio } else { if (gdb_connection->ctrl_c) { signal_var = 0x2; - gdb_connection->ctrl_c = 0; } else signal_var = gdb_last_signal(target); @@ -769,11 +768,14 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio target->rtos->current_thread); target->rtos->current_threadid = target->rtos->current_thread; target->rtos->gdb_target_for_threadid(connection, target->rtos->current_threadid, &ct); - signal_var = gdb_last_signal(ct); + if (!gdb_connection->ctrl_c) + signal_var = gdb_last_signal(ct); } sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), "T%2.2x%s%s", signal_var, stop_reason, current_thread); + + gdb_connection->ctrl_c = 0; } gdb_put_packet(connection, sig_reply, sig_reply_len); From 935f0c5cc28a3a2cc627ff25b30d65d8d82ad8c4 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Mon, 5 Mar 2018 14:50:51 +0100 Subject: [PATCH 68/91] gdb_server: fake step if thread is not current rtos thread gdb assumes that a rtos can make any thread active at will in response to a 'Hg' packet. It further assumes that it needs to step-over after setting a breakpoint on frame #0 of any non-current thread. Both assumptions are not valid for an actual rtos. We fake the step-over to not trigger an internal error in gdb. See https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details. Change-Id: Ida60cd134033c1d58ada77b87fe664a58f61e2c0 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4448 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 712c39341..74074a1f1 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2695,6 +2695,8 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p /* single-step or step-over-breakpoint */ if (parse[0] == 's') { + bool fake_step = false; + if (strncmp(parse, "s:", 2) == 0) { struct target *ct = target; int current_pc = 1; @@ -2710,9 +2712,20 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p parse = endp; } - if (target->rtos != NULL) + if (target->rtos != NULL) { + /* FIXME: why is this necessary? rtos state should be up-to-date here already! */ + rtos_update_threads(target); + target->rtos->gdb_target_for_threadid(connection, thread_id, &ct); + /* + * check if the thread to be stepped is the current rtos thread + * if not, we must fake the step + */ + if (target->rtos->current_thread != thread_id) + fake_step = true; + } + if (parse[0] == ';') { ++parse; --packet_size; @@ -2746,10 +2759,33 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p } } - LOG_DEBUG("target %s single-step thread %"PRId64, target_name(ct), thread_id); + LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); log_add_callback(gdb_log_callback, connection); target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); + /* + * work around an annoying gdb behaviour: when the current thread + * is changed in gdb, it assumes that the target can follow and also + * make the thread current. This is an assumption that cannot hold + * for a real target running a multi-threading OS. We just fake + * the step to not trigger an internal error in gdb. See + * https://sourceware.org/bugzilla/show_bug.cgi?id=22925 for details + */ + if (fake_step) { + int sig_reply_len; + char sig_reply[128]; + + LOG_DEBUG("fake step thread %"PRIx64, thread_id); + + sig_reply_len = snprintf(sig_reply, sizeof(sig_reply), + "T05thread:%016"PRIx64";", thread_id); + + gdb_put_packet(connection, sig_reply, sig_reply_len); + log_remove_callback(gdb_log_callback, connection); + + return true; + } + /* support for gdb_sync command */ if (gdb_connection->sync) { gdb_connection->sync = false; From ffd6b78a2c47d1c15629dc72c71caea30ef8161a Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Mon, 12 Mar 2018 16:56:05 +0100 Subject: [PATCH 69/91] aarch64: fix debug entry from EL0 If we enter debug state from EL0, some registers are not accessible. Temporarily move to EL1H and back to gain access. Also, fix armv8_dpm_modeswitch() to not immediately restore the previous state on elevating the privilege level. Change-Id: Ic2a92109230ff4eb6834c00ef544397a5b7ad56a Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4461 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/aarch64.c | 4 ++-- src/target/armv8.c | 9 +++++++++ src/target/armv8_cache.c | 9 +++++++++ src/target/armv8_dpm.c | 9 +++++---- src/target/armv8_dpm.h | 2 +- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 0630ffb9b..b586e24eb 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1861,7 +1861,7 @@ static int aarch64_write_cpu_memory(struct target *target, if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, true); return ERROR_FAIL; } @@ -2080,7 +2080,7 @@ static int aarch64_read_cpu_memory(struct target *target, if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr); - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, true); return ERROR_FAIL; } diff --git a/src/target/armv8.c b/src/target/armv8.c index 86bb8707e..e8c700af3 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -620,6 +620,7 @@ void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) int armv8_read_mpidr(struct armv8_common *armv8) { int retval = ERROR_FAIL; + struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; uint32_t mpidr; @@ -627,6 +628,13 @@ int armv8_read_mpidr(struct armv8_common *armv8) if (retval != ERROR_OK) goto done; + /* check if we're in an unprivileged mode */ + if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { + retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); + if (retval != ERROR_OK) + return retval; + } + retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); if (retval != ERROR_OK) goto done; @@ -642,6 +650,7 @@ int armv8_read_mpidr(struct armv8_common *armv8) LOG_ERROR("mpidr not in multiprocessor format"); done: + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; } diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index 7f610c953..40965ebd8 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -310,6 +310,7 @@ int armv8_identify_cache(struct armv8_common *armv8) { /* read cache descriptor */ int retval = ERROR_FAIL; + struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; uint32_t csselr, clidr, ctr; uint32_t cache_reg; @@ -320,6 +321,13 @@ int armv8_identify_cache(struct armv8_common *armv8) if (retval != ERROR_OK) goto done; + /* check if we're in an unprivileged mode */ + if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { + retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); + if (retval != ERROR_OK) + return retval; + } + /* retrieve CTR */ retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CTR), &ctr); @@ -417,6 +425,7 @@ int armv8_identify_cache(struct armv8_common *armv8) } done: + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 91b2f5171..3c941fa2d 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -258,7 +258,7 @@ static int dpmv8_exec_opcode(struct arm_dpm *dpm, if (dscr & DSCR_ERR) { LOG_ERROR("Opcode 0x%08"PRIx32", DSCR.ERR=1, DSCR.EL=%i", opcode, dpm->last_el); - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, true); retval = ERROR_FAIL; } @@ -600,7 +600,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el); /* DCPS clobbers registers just like an exception taken */ - armv8_dpm_handle_exception(dpm); + armv8_dpm_handle_exception(dpm, false); } else { core_state = armv8_dpm_get_core_state(dpm); if (core_state != ARM_STATE_AARCH64) { @@ -1298,7 +1298,7 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t addr) * This function must not perform any actions that trigger another exception * or a recursion will happen. */ -void armv8_dpm_handle_exception(struct arm_dpm *dpm) +void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore) { struct armv8_common *armv8 = dpm->arm->arch_info; struct reg_cache *cache = dpm->arm->core_cache; @@ -1344,7 +1344,8 @@ void armv8_dpm_handle_exception(struct arm_dpm *dpm) armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64); armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64); - armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + if (do_restore) + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); } /*----------------------------------------------------------------------*/ diff --git a/src/target/armv8_dpm.h b/src/target/armv8_dpm.h index c03935928..f40440370 100644 --- a/src/target/armv8_dpm.h +++ b/src/target/armv8_dpm.h @@ -116,7 +116,7 @@ void armv8_dpm_report_wfar(struct arm_dpm *, uint64_t wfar); #define PRCR_COREPURQ (1 << 3) void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr); -void armv8_dpm_handle_exception(struct arm_dpm *dpm); +void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore); enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm); #endif /* OPENOCD_TARGET_ARM_DPM_H */ From 828ee07657914212f81152a768a8ec43bb73db03 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sat, 13 Jan 2018 16:22:10 +0300 Subject: [PATCH 70/91] server: bind to IPv4 localhost by default Since OpenOCD basically allows to perform arbitrary actions on behalf of the running user, it makes sense to restrict the exposure by default. If you need network connectivity and your environment is safe enough, use "bindto 0.0.0.0" to switch to the old behaviour. Change-Id: I4a4044b90d0ecb30118cea96fc92a7bcff0924e0 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4331 Reviewed-by: Jonathan McDowell Reviewed-by: Antonio Borneo Tested-by: jenkins --- doc/openocd.texi | 8 +++++--- src/server/server.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 6362b41f2..73d64b3dc 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7132,9 +7132,11 @@ the initial log output channel is stderr. Add @var{directory} to the file/script search path. @end deffn -@deffn Command bindto [name] -Specify address by name on which to listen for incoming TCP/IP connections. -By default, OpenOCD will listen on all available interfaces. +@deffn Command bindto [@var{name}] +Specify hostname or IPv4 address on which to listen for incoming +TCP/IP connections. By default, OpenOCD will listen on the loopback +interface only. If your network environment is safe, @code{bindto +0.0.0.0} can be used to cover all available interfaces. @end deffn @anchor{targetstatehandling} diff --git a/src/server/server.c b/src/server/server.c index 8fd2d71d4..4e806563c 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -259,7 +259,7 @@ int add_service(char *name, c->sin.sin_family = AF_INET; if (bindto_name == NULL) - c->sin.sin_addr.s_addr = INADDR_ANY; + c->sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else { hp = gethostbyname(bindto_name); if (hp == NULL) { From 78a44055c50f4ea10ebb14714c4b6563cd64f71b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Mar 2018 20:02:10 +0100 Subject: [PATCH 71/91] transport: add transport_is_hla() and move declaration of all transport_is_xxx() functions to transport.h Change-Id: Ib229115b5017507b49655bc43b517ab6fb32f7a6 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4469 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/jtag/hla/hla_transport.c | 8 ++++++++ src/jtag/jtag.h | 2 -- src/jtag/swd.h | 2 -- src/jtag/tcl.c | 1 + src/target/cortex_a.c | 2 +- src/transport/transport.h | 19 +++++++++++++++++++ 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index 5a5671db6..ddacea36a 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -233,3 +233,11 @@ static void hl_constructor(void) transport_register(&hl_jtag_transport); transport_register(&stlink_swim_transport); } + +bool transport_is_hla(void) +{ + struct transport *t; + t = get_current_transport(); + return t == &hl_swd_transport || t == &hl_jtag_transport + || t == &stlink_swim_transport; +} diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 7702d6ca8..751facb17 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -642,8 +642,6 @@ void jtag_poll_set_enabled(bool value); * level APIs that are used in inner loops. */ #include -bool transport_is_jtag(void); - int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv); #endif /* OPENOCD_JTAG_JTAG_H */ diff --git a/src/jtag/swd.h b/src/jtag/swd.h index c888cc07d..52f41d5d9 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -211,6 +211,4 @@ struct swd_driver { int swd_init_reset(struct command_context *cmd_ctx); void swd_add_reset(int req_srst); -bool transport_is_swd(void); - #endif /* OPENOCD_JTAG_SWD_H */ diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index bc6bbf204..e32f0ca07 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -42,6 +42,7 @@ #endif #include +#include "transport/transport.h" /** * @file diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 37098afd1..74f30cb47 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -54,7 +54,7 @@ #include "target_type.h" #include "arm_opcodes.h" #include "arm_semihosting.h" -#include "jtag/swd.h" +#include "transport/transport.h" #include static int cortex_a_poll(struct target *target); diff --git a/src/transport/transport.h b/src/transport/transport.h index 6c57067a3..d0a77ddfb 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -19,6 +19,10 @@ #ifndef OPENOCD_TRANSPORT_TRANSPORT_H #define OPENOCD_TRANSPORT_TRANSPORT_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "helper/command.h" /** @@ -90,4 +94,19 @@ int allow_transports(struct command_context *ctx, const char * const *vector); bool transports_are_declared(void); +bool transport_is_jtag(void); +bool transport_is_swd(void); + +/* FIXME: ZY1000 test build on jenkins is configured with enabled hla adapters + * but jtag/hla/hla_*.c files are not compiled. To workaround the problem we assume hla + * is broken if BUILD_ZY1000 is set */ +#if BUILD_HLADAPTER && !BUILD_ZY1000 +bool transport_is_hla(void); +#else +static inline bool transport_is_hla(void) +{ + return false; +} +#endif + #endif /* OPENOCD_TRANSPORT_TRANSPORT_H */ From 0808c6e8a3bd82316988d3d86bd6b212eefff6a2 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 8 Mar 2018 14:40:10 +0100 Subject: [PATCH 72/91] tdesc: bitfields may carry a type a bitfield may carry a type (bool or int), add support for that. Change-Id: Ic831a9b8eac8579e8fdd7d0f01b7f1c9259e6739 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4459 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/server/gdb_server.c | 15 ++++++++++----- src/target/register.h | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 74074a1f1..428547b46 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1909,6 +1909,8 @@ static int gdb_memory_map(struct connection *connection, static const char *gdb_get_reg_type_name(enum reg_type type) { switch (type) { + case REG_TYPE_BOOL: + return "bool"; case REG_TYPE_INT: return "int"; case REG_TYPE_INT8: @@ -1921,6 +1923,8 @@ static const char *gdb_get_reg_type_name(enum reg_type type) return "int64"; case REG_TYPE_INT128: return "int128"; + case REG_TYPE_UINT: + return "uint"; case REG_TYPE_UINT8: return "uint8"; case REG_TYPE_UINT16: @@ -2040,9 +2044,9 @@ static int gdb_generate_reg_type_description(struct target *target, type->id, type->reg_type_struct->size); while (field != NULL) { xml_printf(&retval, tdesc, pos, size, - "\n", - field->name, field->bitfield->start, - field->bitfield->end); + "\n", + field->name, field->bitfield->start, field->bitfield->end, + gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } @@ -2088,8 +2092,9 @@ static int gdb_generate_reg_type_description(struct target *target, field = type->reg_type_flags->fields; while (field != NULL) { xml_printf(&retval, tdesc, pos, size, - "\n", - field->name, field->bitfield->start, field->bitfield->end); + "\n", + field->name, field->bitfield->start, field->bitfield->end, + gdb_get_reg_type_name(field->bitfield->type)); field = field->next; } diff --git a/src/target/register.h b/src/target/register.h index dc18e9a89..32c1f39ac 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -25,12 +25,14 @@ struct target; enum reg_type { + REG_TYPE_BOOL, REG_TYPE_INT, REG_TYPE_INT8, REG_TYPE_INT16, REG_TYPE_INT32, REG_TYPE_INT64, REG_TYPE_INT128, + REG_TYPE_UINT, REG_TYPE_UINT8, REG_TYPE_UINT16, REG_TYPE_UINT32, @@ -66,6 +68,7 @@ struct reg_data_type_union { struct reg_data_type_bitfield { uint32_t start; uint32_t end; + enum reg_type type; }; struct reg_data_type_struct_field { From 1756f393e45c2a23dd29ff8bc85d188b547624f9 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Wed, 7 Mar 2018 21:14:24 +0100 Subject: [PATCH 73/91] aarch64: add cpsr bitfields to target description provide meta information for the cpsr so gdb can display the status flags and not only a hexadecimal number Change-Id: I9d3fb29153780adbea389d7e4175d5e19bddc256 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4460 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/target/armv8.c | 49 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/target/armv8.c b/src/target/armv8.c index e8c700af3..b88f37d6b 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1186,7 +1186,49 @@ static struct reg_data_type_union aarch64v_union[] = { }; static struct reg_data_type aarch64v[] = { - {REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION, {.reg_type_union = aarch64v_union} }, + {REG_TYPE_ARCH_DEFINED, "aarch64v", REG_TYPE_CLASS_UNION, + {.reg_type_union = aarch64v_union} }, +}; + +static struct reg_data_type_bitfield aarch64_cpsr_bits[] = { + { 0, 0 , REG_TYPE_UINT8 }, + { 2, 3, REG_TYPE_UINT8 }, + { 4, 4 , REG_TYPE_UINT8 }, + { 6, 6 , REG_TYPE_BOOL }, + { 7, 7 , REG_TYPE_BOOL }, + { 8, 8 , REG_TYPE_BOOL }, + { 9, 9 , REG_TYPE_BOOL }, + { 20, 20, REG_TYPE_BOOL }, + { 21, 21, REG_TYPE_BOOL }, + { 28, 28, REG_TYPE_BOOL }, + { 29, 29, REG_TYPE_BOOL }, + { 30, 30, REG_TYPE_BOOL }, + { 31, 31, REG_TYPE_BOOL }, +}; + +static struct reg_data_type_flags_field aarch64_cpsr_fields[] = { + { "SP", aarch64_cpsr_bits + 0, aarch64_cpsr_fields + 1 }, + { "EL", aarch64_cpsr_bits + 1, aarch64_cpsr_fields + 2 }, + { "nRW", aarch64_cpsr_bits + 2, aarch64_cpsr_fields + 3 }, + { "F" , aarch64_cpsr_bits + 3, aarch64_cpsr_fields + 4 }, + { "I" , aarch64_cpsr_bits + 4, aarch64_cpsr_fields + 5 }, + { "A" , aarch64_cpsr_bits + 5, aarch64_cpsr_fields + 6 }, + { "D" , aarch64_cpsr_bits + 6, aarch64_cpsr_fields + 7 }, + { "IL" , aarch64_cpsr_bits + 7, aarch64_cpsr_fields + 8 }, + { "SS" , aarch64_cpsr_bits + 8, aarch64_cpsr_fields + 9 }, + { "V" , aarch64_cpsr_bits + 9, aarch64_cpsr_fields + 10 }, + { "C" , aarch64_cpsr_bits + 10, aarch64_cpsr_fields + 11 }, + { "Z" , aarch64_cpsr_bits + 11, aarch64_cpsr_fields + 12 }, + { "N" , aarch64_cpsr_bits + 12, NULL } +}; + +static struct reg_data_type_flags aarch64_cpsr_flags[] = { + { 4, aarch64_cpsr_fields } +}; + +static struct reg_data_type aarch64_flags_cpsr[] = { + {REG_TYPE_ARCH_DEFINED, "cpsr_flags", REG_TYPE_CLASS_FLAGS, + {.reg_type_flags = aarch64_cpsr_flags} }, }; static const struct { @@ -1233,9 +1275,8 @@ static const struct { { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core", NULL}, - - { ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core", NULL}, - + { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, + "general", "org.gnu.gdb.aarch64.core", aarch64_flags_cpsr}, { ARMV8_V0, "v0", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V1, "v1", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, { ARMV8_V2, "v2", 128, ARM_MODE_ANY, REG_TYPE_ARCH_DEFINED, "simdfp", "org.gnu.gdb.aarch64.fpu", aarch64v}, From f444c57bf2d692171b7b50a6ce477265f951f77e Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Mon, 10 Apr 2017 22:53:27 +0200 Subject: [PATCH 74/91] arm_cti: add cti command group Extend the CTI abstraction to be accessible from TCL and change the 'target' command to accept a cti 'object' instead of a base address. This also allows accessing CTI instances that are not related to a configured target. Change-Id: Iac9ed0edca6f1be00fe93783a35c26077f6bc80a Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4031 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 52 +++- src/openocd.c | 2 + src/target/aarch64.c | 80 +++++- src/target/arm_cti.c | 445 ++++++++++++++++++++++++++++++++- src/target/arm_cti.h | 8 +- src/target/target.c | 17 +- src/target/target.h | 4 - tcl/target/hi3798.cfg | 2 + tcl/target/hi6220.cfg | 9 +- tcl/target/marvell/88f37x0.cfg | 4 +- 10 files changed, 578 insertions(+), 45 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 73d64b3dc..d12c28c4d 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4290,9 +4290,11 @@ access the target for debugging. Use this option with systems where multiple, independent cores are connected to separate access ports of the same DAP. -@item @code{-ctibase} @var{address} -- set base address of Cross-Trigger interface (CTI) connected -to the target. Currently, only the @code{aarch64} target makes use of this option, where it is -a mandatory configuration for the target run control. +@item @code{-cti} @var{cti_name} -- set Cross-Trigger Interface (CTI) connected +to the target. Currently, only the @code{aarch64} target makes use of this option, +where it is a mandatory configuration for the target run control. +@xref{armcrosstrigger,,ARM Cross-Trigger Interface}, +for instruction on how to declare and control a CTI instance. @end itemize @end deffn @@ -7781,6 +7783,50 @@ Reports whether the capture clock is locked or not. @end deffn @end deffn +@anchor{armcrosstrigger} +@section ARM Cross-Trigger Interface +@cindex CTI + +The ARM Cross-Trigger Interface (CTI) is a generic CoreSight component +that connects event sources like tracing components or CPU cores with each +other through a common trigger matrix (CTM). For ARMv8 architecture, a +CTI is mandatory for core run control and each core has an individual +CTI instance attached to it. OpenOCD has limited support for CTI using +the @emph{cti} group of commands. + +@deffn Command {cti create} @var{cti_name} -chain-position @var{tap_name} -ap-num @var{apn} -ctibase @var{base_address} +Creates a CTI object @var{cti_name} on the JTAG tap @var{tap_name} on MEM-AP +@var{apn} of the DAP reachable through @var{tap}. The @var{base_address} must match +the base address of the CTI on the respective MEM-AP. All arguments are +mandatory. This creates a new command (@command{@var{cti_name}}) which +is used for various purposes including additional configuration. +@end deffn + +@deffn Command {$cti_name enable} @option{on|off} +Enable (@option{on}) or disable (@option{off}) the CTI. +@end deffn + +@deffn Command {$cti_name dump} +Displays a register dump of the CTI. +@end deffn + +@deffn Command {$cti_name write } @var{reg_name} @var{value} +Write @var{value} to the CTI register with the symbolic name @var{reg_name}. +@end deffn + +@deffn Command {$cti_name read} @var{reg_name} +Print the value read from the CTI register with the symbolic name @var{reg_name}. +@end deffn + +@deffn Command {$cti_name testmode} @option{on|off} +Enable (@option{on}) or disable (@option{off}) the integration test mode +of the CTI. +@end deffn + +@deffn Command {cti names} +Prints a list of names of all CTI objects created. This command is mainly +useful in TCL scripting. +@end deffn @section Generic ARM @cindex ARM diff --git a/src/openocd.c b/src/openocd.c index 54fc83a17..b97df3784 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -252,6 +253,7 @@ struct command_context *setup_command_handler(Jim_Interp *interp) &nand_register_commands, &pld_register_commands, &mflash_register_commands, + &cti_register_commands, NULL }; for (unsigned i = 0; NULL != command_registrants[i]; i++) { diff --git a/src/target/aarch64.c b/src/target/aarch64.c index b586e24eb..e9c822d64 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -40,6 +40,10 @@ enum halt_mode { HALT_SYNC, }; +struct aarch64_private_config { + struct arm_cti *cti; +}; + static int aarch64_poll(struct target *target); static int aarch64_debug_entry(struct target *target); static int aarch64_restore_context(struct target *target, bool bpwp); @@ -2198,7 +2202,7 @@ static int aarch64_examine_first(struct target *target) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct adiv5_dap *swjdp = armv8->arm.dap; - uint32_t cti_base; + struct aarch64_private_config *pc; int i; int retval = ERROR_OK; uint64_t debug, ttypr; @@ -2289,17 +2293,15 @@ static int aarch64_examine_first(struct target *target) LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr); LOG_DEBUG("debug = 0x%08" PRIx64, debug); - if (target->ctibase == 0) { - /* assume a v8 rom table layout */ - cti_base = armv8->debug_base + 0x10000; - LOG_INFO("Target ctibase is not set, assuming 0x%0" PRIx32, cti_base); - } else - cti_base = target->ctibase; - - armv8->cti = arm_cti_create(armv8->debug_ap, cti_base); - if (armv8->cti == NULL) + if (target->private_config == NULL) return ERROR_FAIL; + pc = (struct aarch64_private_config *)target->private_config; + if (pc->cti == NULL) + return ERROR_FAIL; + + armv8->cti = pc->cti; + retval = aarch64_dpm_setup(aarch64, debug); if (retval != ERROR_OK) return retval; @@ -2405,6 +2407,63 @@ static int aarch64_virt2phys(struct target *target, target_addr_t virt, return armv8_mmu_translate_va_pa(target, virt, phys, 1); } +static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) +{ + struct aarch64_private_config *pc; + const char *arg; + int e; + + /* check if argv[0] is for us */ + arg = Jim_GetString(goi->argv[0], NULL); + if (strcmp(arg, "-cti")) + return JIM_CONTINUE; + + /* pop the argument from argv */ + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + /* check if we have another option */ + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-cti ?cti-name?"); + return JIM_ERR; + } + + pc = (struct aarch64_private_config *)target->private_config; + + if (goi->isconfigure) { + Jim_Obj *o_cti; + struct arm_cti *cti; + e = Jim_GetOpt_Obj(goi, &o_cti); + if (e != JIM_OK) + return e; + cti = cti_instance_by_jim_obj(goi->interp, o_cti); + if (cti == NULL) + return JIM_ERR; + + if (pc == NULL) { + pc = calloc(1, sizeof(struct aarch64_private_config)); + target->private_config = pc; + } + pc->cti = cti; + } else { + if (goi->argc != 0) { + Jim_WrongNumArgs(goi->interp, + goi->argc, goi->argv, + "NO PARAMS"); + return JIM_ERR; + } + + if (pc == NULL || pc->cti == NULL) { + Jim_SetResultString(goi->interp, "CTI not configured", -1); + return JIM_ERR; + } + Jim_SetResultString(goi->interp, arm_cti_name(pc->cti), -1); + } + + return JIM_OK; +} + COMMAND_HANDLER(aarch64_handle_cache_info_command) { struct target *target = get_current_target(CMD_CTX); @@ -2570,6 +2629,7 @@ struct target_type aarch64_target = { .commands = aarch64_command_handlers, .target_create = aarch64_target_create, + .target_jim_configure = aarch64_jim_configure, .init_target = aarch64_init_target, .examine = aarch64_examine, diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 75169b2ee..6834a34a0 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -27,21 +27,47 @@ #include "target/arm_cti.h" #include "target/target.h" #include "helper/time_support.h" +#include "helper/list.h" +#include "helper/command.h" struct arm_cti { - uint32_t base; + target_addr_t base; struct adiv5_ap *ap; }; -struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base) -{ - struct arm_cti *self = calloc(1, sizeof(struct arm_cti)); - if (!self) - return NULL; +struct arm_cti_object { + struct list_head lh; + struct arm_cti cti; + int ap_num; + char *name; +}; - self->base = base; - self->ap = ap; - return self; +static LIST_HEAD(all_cti); + +const char *arm_cti_name(struct arm_cti *self) +{ + struct arm_cti_object *obj = container_of(self, struct arm_cti_object, cti); + return obj->name; +} + +struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) +{ + struct arm_cti_object *obj = NULL; + const char *name; + bool found = false; + + name = Jim_GetString(o, NULL); + + list_for_each_entry(obj, &all_cti, lh) { + if (!strcmp(name, obj->name)) { + found = true; + break; + } + } + + if (found) + return &obj->cti; + return NULL; } static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value) @@ -146,3 +172,404 @@ int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel) return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel)); } + +static uint32_t cti_regs[26]; + +static const struct { + uint32_t offset; + const char *label; + uint32_t *p_val; +} cti_names[] = { + { CTI_CTR, "CTR", &cti_regs[0] }, + { CTI_GATE, "GATE", &cti_regs[1] }, + { CTI_INEN0, "INEN0", &cti_regs[2] }, + { CTI_INEN1, "INEN1", &cti_regs[3] }, + { CTI_INEN2, "INEN2", &cti_regs[4] }, + { CTI_INEN3, "INEN3", &cti_regs[5] }, + { CTI_INEN4, "INEN4", &cti_regs[6] }, + { CTI_INEN5, "INEN5", &cti_regs[7] }, + { CTI_INEN6, "INEN6", &cti_regs[8] }, + { CTI_INEN7, "INEN7", &cti_regs[9] }, + { CTI_INEN8, "INEN8", &cti_regs[10] }, + { CTI_OUTEN0, "OUTEN0", &cti_regs[11] }, + { CTI_OUTEN1, "OUTEN1", &cti_regs[12] }, + { CTI_OUTEN2, "OUTEN2", &cti_regs[13] }, + { CTI_OUTEN3, "OUTEN3", &cti_regs[14] }, + { CTI_OUTEN4, "OUTEN4", &cti_regs[15] }, + { CTI_OUTEN5, "OUTEN5", &cti_regs[16] }, + { CTI_OUTEN6, "OUTEN6", &cti_regs[17] }, + { CTI_OUTEN7, "OUTEN7", &cti_regs[18] }, + { CTI_OUTEN8, "OUTEN8", &cti_regs[19] }, + { CTI_TRIN_STATUS, "TRIN", &cti_regs[20] }, + { CTI_TROUT_STATUS, "TROUT", &cti_regs[21] }, + { CTI_CHIN_STATUS, "CHIN", &cti_regs[22] }, + { CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] }, + { CTI_APPSET, "APPSET", &cti_regs[24] }, + { CTI_APPCLEAR, "APPCLR", &cti_regs[25] }, +}; + +static int cti_find_reg_offset(const char *name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cti_names); i++) { + if (!strcmp(name, cti_names[i].label)) + return cti_names[i].offset; + } + return -1; +} + +COMMAND_HANDLER(handle_cti_dump) +{ + struct arm_cti_object *obj = CMD_DATA; + struct arm_cti *cti = &obj->cti; + int retval = ERROR_OK; + + for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) + retval = mem_ap_read_u32(cti->ap, + cti->base + cti_names[i].offset, cti_names[i].p_val); + + if (retval == ERROR_OK) + retval = dap_run(cti->ap->dap); + + if (retval != ERROR_OK) + return JIM_ERR; + + for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++) + command_print(CMD_CTX, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32, + cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val); + + return JIM_OK; +} + +COMMAND_HANDLER(handle_cti_enable) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + bool on_off; + + if (CMD_ARGC != 1) { + Jim_SetResultString(interp, "wrong number of args", -1); + return ERROR_FAIL; + } + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); + + return arm_cti_enable(cti, on_off); +} + +COMMAND_HANDLER(handle_cti_testmode) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + bool on_off; + + if (CMD_ARGC != 1) { + Jim_SetResultString(interp, "wrong number of args", -1); + return ERROR_FAIL; + } + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], on_off); + + return arm_cti_write_reg(cti, 0xf00, on_off ? 0x1 : 0x0); +} + +COMMAND_HANDLER(handle_cti_write) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + int offset; + uint32_t value; + + if (CMD_ARGC != 2) { + Jim_SetResultString(interp, "Wrong numer of args", -1); + return ERROR_FAIL; + } + + offset = cti_find_reg_offset(CMD_ARGV[0]); + if (offset < 0) + return ERROR_FAIL; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + return arm_cti_write_reg(cti, offset, value); +} + +COMMAND_HANDLER(handle_cti_read) +{ + struct arm_cti_object *obj = CMD_DATA; + Jim_Interp *interp = CMD_CTX->interp; + struct arm_cti *cti = &obj->cti; + int offset; + int retval; + uint32_t value; + + if (CMD_ARGC != 1) { + Jim_SetResultString(interp, "Wrong numer of args", -1); + return ERROR_FAIL; + } + + offset = cti_find_reg_offset(CMD_ARGV[0]); + if (offset < 0) + return ERROR_FAIL; + + retval = arm_cti_read_reg(cti, offset, &value); + if (retval != ERROR_OK) + return retval; + + command_print(CMD_CTX, "0x%08"PRIx32, value); + + return ERROR_OK; +} + +static const struct command_registration cti_instance_command_handlers[] = { + { + .name = "dump", + .mode = COMMAND_EXEC, + .handler = handle_cti_dump, + .help = "dump CTI registers", + .usage = "", + }, + { + .name = "enable", + .mode = COMMAND_EXEC, + .handler = handle_cti_enable, + .help = "enable or disable the CTI", + .usage = "'on'|'off'", + }, + { + .name = "testmode", + .mode = COMMAND_EXEC, + .handler = handle_cti_testmode, + .help = "enable or disable integration test mode", + .usage = "'on'|'off'", + }, + { + .name = "write", + .mode = COMMAND_EXEC, + .handler = handle_cti_write, + .help = "write to a CTI register", + .usage = "register_name value", + }, + { + .name = "read", + .mode = COMMAND_EXEC, + .handler = handle_cti_read, + .help = "read a CTI register", + .usage = "register_name", + }, + COMMAND_REGISTRATION_DONE +}; + +enum cti_cfg_param { + CFG_CHAIN_POSITION, + CFG_AP_NUM, + CFG_CTIBASE +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, + { .name = "-ctibase", .value = CFG_CTIBASE }, + { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = NULL, .value = -1 } +}; + +static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) +{ + struct jtag_tap *tap = NULL; + struct adiv5_dap *dap; + Jim_Nvp *n; + jim_wide w; + int e; + + /* parse config or cget options ... */ + while (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); + return e; + } + switch (n->value) { + case CFG_CHAIN_POSITION: { + Jim_Obj *o_t; + e = Jim_GetOpt_Obj(goi, &o_t); + if (e != JIM_OK) + return e; + tap = jtag_tap_by_jim_obj(goi->interp, o_t); + if (tap == NULL) { + Jim_SetResultString(goi->interp, "-chain-position is invalid", -1); + return JIM_ERR; + } + /* loop for more */ + break; + } + case CFG_CTIBASE: + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + cti->cti.base = (uint32_t)w; + /* loop for more */ + break; + + case CFG_AP_NUM: + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + cti->ap_num = (uint32_t)w; + } + } + + if (tap == NULL) { + Jim_SetResultString(goi->interp, "-chain-position required when creating CTI", -1); + return JIM_ERR; + } + + if (tap->dap == NULL) { + dap = dap_init(); + dap->tap = tap; + tap->dap = dap; + } else + dap = tap->dap; + + cti->cti.ap = dap_ap(dap, cti->ap_num); + + return JIM_OK; +} + +static int cti_create(Jim_GetOptInfo *goi) +{ + struct command_context *cmd_ctx; + static struct arm_cti_object *cti; + Jim_Obj *new_cmd; + Jim_Cmd *cmd; + const char *cp; + int e; + + cmd_ctx = current_command_context(goi->interp); + assert(cmd_ctx != NULL); + + if (goi->argc < 3) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); + return JIM_ERR; + } + /* COMMAND */ + Jim_GetOpt_Obj(goi, &new_cmd); + /* does this command exist? */ + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + if (cmd) { + cp = Jim_GetString(new_cmd, NULL); + Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); + return JIM_ERR; + } + + /* Create it */ + cti = calloc(1, sizeof(struct arm_cti_object)); + if (cti == NULL) + return JIM_ERR; + + e = cti_configure(goi, cti); + if (e != JIM_OK) { + free(cti); + return e; + } + + cp = Jim_GetString(new_cmd, NULL); + cti->name = strdup(cp); + + /* now - create the new cti name command */ + const struct command_registration cti_subcommands[] = { + { + .chain = cti_instance_command_handlers, + }, + COMMAND_REGISTRATION_DONE + }; + const struct command_registration cti_commands[] = { + { + .name = cp, + .mode = COMMAND_ANY, + .help = "cti instance command group", + .usage = "", + .chain = cti_subcommands, + }, + COMMAND_REGISTRATION_DONE + }; + e = register_commands(cmd_ctx, NULL, cti_commands); + if (ERROR_OK != e) + return JIM_ERR; + + struct command *c = command_find_in_context(cmd_ctx, cp); + assert(c); + command_set_handler_data(c, cti); + + list_add_tail(&cti->lh, &all_cti); + + return (ERROR_OK == e) ? JIM_OK : JIM_ERR; +} + +static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_GetOptInfo goi; + Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + if (goi.argc < 2) { + Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, + " [ ...]"); + return JIM_ERR; + } + return cti_create(&goi); +} + +static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct arm_cti_object *obj; + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); + list_for_each_entry(obj, &all_cti, lh) { + Jim_ListAppendElement(interp, Jim_GetResult(interp), + Jim_NewStringObj(interp, obj->name, -1)); + } + return JIM_OK; +} + + +static const struct command_registration cti_subcommand_handlers[] = { + { + .name = "create", + .mode = COMMAND_ANY, + .jim_handler = jim_cti_create, + .usage = "name '-chain-position' name [options ...]", + .help = "Creates a new CTI object", + }, + { + .name = "names", + .mode = COMMAND_ANY, + .jim_handler = jim_cti_names, + .usage = "", + .help = "Lists all registered CTI objects by name", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration cti_command_handlers[] = { + { + .name = "cti", + .mode = COMMAND_CONFIG, + .help = "CTI commands", + .chain = cti_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +int cti_register_commands(struct command_context *cmd_ctx) +{ + return register_commands(cmd_ctx, NULL, cti_command_handlers); +} + diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h index 99724c406..181f06447 100644 --- a/src/target/arm_cti.h +++ b/src/target/arm_cti.h @@ -34,6 +34,7 @@ #define CTI_INEN5 0x34 #define CTI_INEN6 0x38 #define CTI_INEN7 0x3C +#define CTI_INEN8 0x40 #define CTI_INEN(n) (0x20 + 4 * n) #define CTI_OUTEN0 0xA0 #define CTI_OUTEN1 0xA4 @@ -43,6 +44,7 @@ #define CTI_OUTEN5 0xB4 #define CTI_OUTEN6 0xB8 #define CTI_OUTEN7 0xBC +#define CTI_OUTEN8 0xC0 #define CTI_OUTEN(n) (0xA0 + 4 * n) #define CTI_TRIN_STATUS 0x130 #define CTI_TROUT_STATUS 0x134 @@ -58,8 +60,10 @@ /* forward-declare arm_cti struct */ struct arm_cti; +struct adiv5_ap; -extern struct arm_cti *arm_cti_create(struct adiv5_ap *ap, uint32_t base); +extern const char *arm_cti_name(struct arm_cti *self); +extern struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o); extern int arm_cti_enable(struct arm_cti *self, bool enable); extern int arm_cti_ack_events(struct arm_cti *self, uint32_t event); extern int arm_cti_gate_channel(struct arm_cti *self, uint32_t channel); @@ -70,4 +74,6 @@ extern int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_set_channel(struct arm_cti *self, uint32_t channel); extern int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel); +extern int cti_register_commands(struct command_context *cmd_ctx); + #endif /* OPENOCD_TARGET_ARM_CTI_H */ diff --git a/src/target/target.c b/src/target/target.c index bd9d56b04..9b6348a7d 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -54,6 +54,7 @@ #include "image.h" #include "rtos/rtos.h" #include "transport/transport.h" +#include "arm_cti.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -4513,7 +4514,6 @@ enum target_cfg_param { TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, - TCFG_CTIBASE, TCFG_RTOS, TCFG_DEFER_EXAMINE, }; @@ -4529,7 +4529,6 @@ static Jim_Nvp nvp_config_opts[] = { { .name = "-coreid", .value = TCFG_COREID }, { .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, { .name = "-dbgbase", .value = TCFG_DBGBASE }, - { .name = "-ctibase", .value = TCFG_CTIBASE }, { .name = "-rtos", .value = TCFG_RTOS }, { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE }, { .name = NULL, .value = -1 } @@ -4796,20 +4795,6 @@ no_params: Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ break; - case TCFG_CTIBASE: - if (goi->isconfigure) { - e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) - return e; - target->ctibase = (uint32_t)w; - target->ctibase_set = true; - } else { - if (goi->argc != 0) - goto no_params; - } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->ctibase)); - /* loop for more */ - break; case TCFG_RTOS: /* RTOS */ { diff --git a/src/target/target.h b/src/target/target.h index 6020400f3..49048bcf4 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -186,10 +186,6 @@ struct target { * system in place to support target specific options * currently. */ - bool ctibase_set; /* By default the debug base is not set */ - uint32_t ctibase; /* Really a Cortex-A specific option, but there is no - * system in place to support target specific options - * currently. */ struct rtos *rtos; /* Instance of Real Time Operating System support */ bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" * and must be detected when symbols are offered */ diff --git a/tcl/target/hi3798.cfg b/tcl/target/hi3798.cfg index 9eda15035..b6c3edabd 100644 --- a/tcl/target/hi3798.cfg +++ b/tcl/target/hi3798.cfg @@ -30,6 +30,8 @@ set $_TARGETNAME.cti(3) 0x80320000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + set _command "target create ${_TARGETNAME}$_core aarch64 \ -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_core)]" diff --git a/tcl/target/hi6220.cfg b/tcl/target/hi6220.cfg index 7daa3c118..13d8586dd 100644 --- a/tcl/target/hi6220.cfg +++ b/tcl/target/hi6220.cfg @@ -34,8 +34,10 @@ set $_TARGETNAME.cti(7) 0x801DB000 set _cores 8 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + cti create cti$_core -chain-position $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + set _command "target create ${_TARGETNAME}$_core aarch64 \ - -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_core)]" + -chain-position $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail @@ -52,5 +54,10 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { eval $_smp_command +cti create cti.sys -chain-position hi6220.dap -ap-num 0 -ctibase 0x80003000 + # declare the auxiliary Cortex-M3 core on AP #2 (runs mcuimage.bin) target create ${_TARGETNAME}.m3 cortex_m -chain-position $_CHIPNAME.dap -ap-num 2 -defer-examine + +# declare the auxiliary Cortex-A7 core +target create ${_TARGETNAME}.a7 cortex_a -chain-position $_CHIPNAME.dap -dbgbase 0x80210000 -defer-examine diff --git a/tcl/target/marvell/88f37x0.cfg b/tcl/target/marvell/88f37x0.cfg index dba7da21e..c7007dd48 100644 --- a/tcl/target/marvell/88f37x0.cfg +++ b/tcl/target/marvell/88f37x0.cfg @@ -43,9 +43,11 @@ set _smp_command "" for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + cti create cti$_core -chain-position $_CHIPNAME.dap -ctibase [lindex $_ctis $_core] -ap-num 0 + set _command "target create ${_TARGETNAME}$_core aarch64 \ -chain-position $_CHIPNAME.dap -coreid $_core \ - -ctibase [lindex $_ctis $_core]" + -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail From 72740904568414bb4a9192fe89034bae3b1a9e45 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Tue, 13 Mar 2018 17:03:38 +0100 Subject: [PATCH 75/91] tcl/board: add configuration for the avnet ultrazed-eg starter kit also contains target configuration for the Xilinx UltraScale+ platform Change-Id: I6300cbc85c1ed71df71d8aaca59500bbf18f0093 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4467 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/avnet_ultrazed-eg.cfg | 16 ++++++ tcl/target/xilinx_ultrascale.cfg | 90 ++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 tcl/board/avnet_ultrazed-eg.cfg create mode 100644 tcl/target/xilinx_ultrascale.cfg diff --git a/tcl/board/avnet_ultrazed-eg.cfg b/tcl/board/avnet_ultrazed-eg.cfg new file mode 100644 index 000000000..a0ac5c6a7 --- /dev/null +++ b/tcl/board/avnet_ultrazed-eg.cfg @@ -0,0 +1,16 @@ +# +# AVNET UltraZED EG StarterKit +# UlraScale-EG plus IO Carrier with on-board digilent smt2 +# +source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] +# jtag transport only +transport select jtag +# reset lines are not wired +reset_config none + +# slow default clock +adapter_khz 1000 + +set CHIPNAME uscale + +source [find target/xilinx_ultrascale.cfg] diff --git a/tcl/target/xilinx_ultrascale.cfg b/tcl/target/xilinx_ultrascale.cfg new file mode 100644 index 000000000..9be198dc1 --- /dev/null +++ b/tcl/target/xilinx_ultrascale.cfg @@ -0,0 +1,90 @@ +# +# target configuration for +# Xilinx UltraScale+ +# +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME uscale +} + +# +# DAP tap +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID + +# +# PS tap +# +if { [info exists PS_TAPID] } { + set _PS_TAPID $PS_TAPID +} else { + set _PS_TAPID 0x04710093 +} + +set jtag_configured 0 + +jtag newtap $_CHIPNAME ps -irlen 12 -ircapture 0x1 -irmask 0x03 -expected-id $_PS_TAPID + +jtag configure $_CHIPNAME.ps -event setup { + global _CHIPNAME + global jtag_configured + + if { $jtag_configured == 0 } { + # add the DAP tap to the chain + # See https://forums.xilinx.com/t5/UltraScale-Architecture/JTAG-Chain-Configuration-for-Zynq-UltraScale-MPSoC/td-p/758924 + irscan $_CHIPNAME.ps 0x824 + drscan $_CHIPNAME.ps 32 0x00000003 + runtest 100 + + # setup event will be re-entered through jtag arp_init + # break the recursion + set jtag_configured 1 + # re-initialized the jtag chain + jtag arp_init + } +} + +set _TARGETNAME $_CHIPNAME.a53 +set _CTINAME $_CHIPNAME.cti + +set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} +set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} +set _cores 4 + +for { set _core 0 } { $_core < $_cores } { incr _core } { + + cti create $_CTINAME.$_core -chain-position $_CHIPNAME.dap -ap-num 1 \ + -ctibase [lindex $CTIBASE $_core] + + set _command "target create $_TARGETNAME.$_core aarch64 -chain-position $_CHIPNAME.dap \ + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" + + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command $_TARGETNAME.$_core" + } else { + # uncomment when "hawt" rtos is merged + #set _command "$_command -rtos hawt" + set _smp_command "target smp $_TARGETNAME.$_core" + } + + eval $_command +} + +eval $_smp_command +targets $_TARGETNAME.0 + +proc core_up { args } { + global _TARGETNAME + foreach { core } [set args] { + $_TARGETNAME.$core arp_examine + } +} From 2231da8ec4e7d7ae9b652f3dd1a7104f5a110f3f Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Fri, 23 Mar 2018 21:17:29 +0100 Subject: [PATCH 76/91] target: restructure dap support - add 'dap create' command to create dap instances - move all dap subcmmand into the dap instance commands - keep 'dap info' for convenience - change all armv7 and armv8 targets to take a dap instance instead of a jtag chain position - restructure tap/dap/target relations, jtag tap no longer references the dap, daps are now independently created and initialized. - clean up swd connect - re-initialize DAP also on JTAG errors (e.g. after reset, power cycle) - update documentation - update target files Change-Id: I322cf3969b5407c25d1d3962f9d9b9bc1df067d9 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/4468 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- doc/openocd.texi | 155 ++++++++----- src/jtag/core.c | 3 +- src/jtag/jtag.h | 2 - src/openocd.c | 6 + src/target/Makefile.am | 1 + src/target/aarch64.c | 133 ++++++----- src/target/adi_v5_jtag.c | 28 ++- src/target/adi_v5_swd.c | 60 ++--- src/target/arm_adi_v5.c | 223 ++++++++++--------- src/target/arm_adi_v5.h | 19 +- src/target/arm_cti.c | 30 +-- src/target/arm_dap.c | 366 +++++++++++++++++++++++++++++++ src/target/armv7a.c | 3 - src/target/armv7m.c | 3 - src/target/armv8.c | 4 - src/target/cortex_a.c | 42 ++-- src/target/cortex_m.c | 34 +-- src/target/hla_target.c | 9 +- src/target/target.c | 40 +++- src/target/target.h | 5 + tcl/target/1986ве1т.cfg | 3 +- tcl/target/adsp-sc58x.cfg | 3 +- tcl/target/aducm360.cfg | 5 +- tcl/target/altera_fpgasoc.cfg | 7 +- tcl/target/am335x.cfg | 16 +- tcl/target/am437x.cfg | 4 +- tcl/target/amdm37x.cfg | 7 +- tcl/target/armada370.cfg | 5 +- tcl/target/at91sam3XXX.cfg | 3 +- tcl/target/at91sam3nXX.cfg | 3 +- tcl/target/at91sam4XXX.cfg | 3 +- tcl/target/at91samdXX.cfg | 3 +- tcl/target/atsamv.cfg | 3 +- tcl/target/bcm281xx.cfg | 8 +- tcl/target/bluenrg-x.cfg | 3 +- tcl/target/cc26xx.cfg | 9 +- tcl/target/cc32xx.cfg | 9 +- tcl/target/efm32.cfg | 3 +- tcl/target/em357.cfg | 3 +- tcl/target/exynos5250.cfg | 5 +- tcl/target/fm3.cfg | 3 +- tcl/target/fm4.cfg | 3 +- tcl/target/hi3798.cfg | 6 +- tcl/target/hi6220.cfg | 15 +- tcl/target/imx51.cfg | 11 +- tcl/target/imx53.cfg | 11 +- tcl/target/imx6.cfg | 5 +- tcl/target/imx7.cfg | 11 +- tcl/target/k1921vk01t.cfg | 3 +- tcl/target/ke0x.cfg | 3 +- tcl/target/klx.cfg | 3 +- tcl/target/kx.cfg | 3 +- tcl/target/lpc1850.cfg | 3 +- tcl/target/lpc1xxx.cfg | 3 +- tcl/target/lpc4350.cfg | 6 +- tcl/target/lpc4370.cfg | 10 +- tcl/target/marvell/88f37x0.cfg | 9 +- tcl/target/mdr32f9q2i.cfg | 3 +- tcl/target/nrf51.cfg | 3 +- tcl/target/nrf52.cfg | 3 +- tcl/target/numicro.cfg | 3 +- tcl/target/omap3530.cfg | 7 +- tcl/target/omap4430.cfg | 30 +-- tcl/target/omap4460.cfg | 27 ++- tcl/target/psoc4.cfg | 3 +- tcl/target/psoc5lp.cfg | 3 +- tcl/target/psoc6.cfg | 5 +- tcl/target/renesas_s7g2.cfg | 3 +- tcl/target/sim3x.cfg | 3 +- tcl/target/stellaris.cfg | 5 +- tcl/target/stm32f0x.cfg | 3 +- tcl/target/stm32f1x.cfg | 3 +- tcl/target/stm32f2x.cfg | 3 +- tcl/target/stm32f3x.cfg | 3 +- tcl/target/stm32f4x.cfg | 3 +- tcl/target/stm32f7x.cfg | 3 +- tcl/target/stm32h7x.cfg | 3 +- tcl/target/stm32l0.cfg | 3 +- tcl/target/stm32l1.cfg | 3 +- tcl/target/stm32l4x.cfg | 3 +- tcl/target/stm32w108xx.cfg | 3 +- tcl/target/ti_msp432p4xx.cfg | 3 +- tcl/target/u8500.cfg | 16 +- tcl/target/vybrid_vf6xx.cfg | 3 +- tcl/target/xilinx_ultrascale.cfg | 8 +- tcl/target/xmc1xxx.cfg | 3 +- tcl/target/xmc4xxx.cfg | 3 +- tcl/target/zynq_7000.cfg | 8 +- 88 files changed, 1056 insertions(+), 498 deletions(-) create mode 100644 src/target/arm_dap.c diff --git a/doc/openocd.texi b/doc/openocd.texi index d12c28c4d..f6795e15b 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4002,6 +4002,84 @@ with these TAPs, any targets associated with them, and any on-chip resources; then a @file{board.cfg} with off-chip resources, clocking, and so forth. +@anchor{dapdeclaration} +@section DAP declaration (ARMv7 and ARMv8 targets) +@cindex DAP declaration + +Since OpenOCD version 0.11.0, the Debug Access Port (DAP) is +no longer implicitly created together with the target. It must be +explicitly declared using the @command{dap create} command. For all +ARMv7 and ARMv8 targets, the option "@option{-dap} @var{dap_name}" has to be used +instead of "@option{-chain-position} @var{dotted.name}" when the target is created. + +The @command{dap} command group supports the following sub-commands: + +@deffn Command {dap create} dap_name @option{-chain-position} dotted.name +Declare a DAP instance named @var{dap_name} linked to the JTAG tap +@var{dotted.name}. This also creates a new command (@command{dap_name}) +which is used for various purposes including additional configuration. +There can only be one DAP for each JTAG tap in the system. +@end deffn + +@deffn Command {dap names} +This command returns a list of all registered DAP objects. It it useful mainly +for TCL scripting. +@end deffn + +@deffn Command {dap info} [num] +Displays the ROM table for MEM-AP @var{num}, +defaulting to the currently selected AP of the currently selected target. +@end deffn + +@deffn Command {dap init} +Initialize all registered DAPs. This command is used internally +during initialization. It can be issued at any time after the +initialization, too. +@end deffn + +The following commands exist as subcommands of DAP instances: + +@deffn Command {$dap_name info} [num] +Displays the ROM table for MEM-AP @var{num}, +defaulting to the currently selected AP. +@end deffn + +@deffn Command {$dap_name apid} [num] +Displays ID register from AP @var{num}, defaulting to the currently selected AP. +@end deffn + +@deffn Command {$dap_name apreg} ap_num reg [value] +Displays content of a register @var{reg} from AP @var{ap_num} +or set a new value @var{value}. +@var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc. +@end deffn + +@deffn Command {$dap_name apsel} [num] +Select AP @var{num}, defaulting to 0. +@end deffn + +@deffn Command {$dap_name baseaddr} [num] +Displays debug base address from MEM-AP @var{num}, +defaulting to the currently selected AP. +@end deffn + +@deffn Command {$dap_name memaccess} [value] +Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP +memory bus access [0-255], giving additional time to respond to reads. +If @var{value} is defined, first assigns that. +@end deffn + +@deffn Command {$dap_name apcsw} [0 / 1] +fix CSW_SPROT from register AP_REG_CSW on selected dap. +Defaulting to 0. +@end deffn + +@deffn Command {$dap_name ti_be_32_quirks} [@option{enable}] +Set/get quirks mode for TI TMS450/TMS570 processors +Disabled by default +@end deffn + + @node CPU Configuration @chapter CPU Configuration @cindex GDB target @@ -4168,10 +4246,11 @@ to be much more board-specific. The key steps you use might look something like this @example -target create MyTarget cortex_m -chain-position mychip.cpu -$MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 -$MyTarget configure -event reset-deassert-pre @{ jtag_rclk 5 @} -$MyTarget configure -event reset-init @{ myboard_reinit @} +dap create mychip.dap -chain-position mychip.cpu +target create MyTarget cortex_m -dap mychip.dap +MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 +MyTarget configure -event reset-deassert-pre @{ jtag_rclk 5 @} +MyTarget configure -event reset-init @{ myboard_reinit @} @end example You should specify a working area if you can; typically it uses some @@ -4221,7 +4300,8 @@ and in other places the target needs to be identified. @command{$target_name configure} are permitted. If the target is big-endian, set it here with @code{-endian big}. -You @emph{must} set the @code{-chain-position @var{dotted.name}} here. +You @emph{must} set the @code{-chain-position @var{dotted.name}} or +@code{-dap @var{dap_name}} here. @end itemize @end deffn @@ -4240,6 +4320,10 @@ and changing its endianness. @item @code{-chain-position} @var{dotted.name} -- names the TAP used to access this target. +@item @code{-dap} @var{dap_name} -- names the DAP used to access +this target. @xref{dapdeclaration,,DAP declaration}, on how to +create and manage DAP instances. + @item @code{-endian} (@option{big}|@option{little}) -- specifies whether the CPU uses big or little endian conventions @@ -7794,12 +7878,12 @@ CTI is mandatory for core run control and each core has an individual CTI instance attached to it. OpenOCD has limited support for CTI using the @emph{cti} group of commands. -@deffn Command {cti create} @var{cti_name} -chain-position @var{tap_name} -ap-num @var{apn} -ctibase @var{base_address} -Creates a CTI object @var{cti_name} on the JTAG tap @var{tap_name} on MEM-AP -@var{apn} of the DAP reachable through @var{tap}. The @var{base_address} must match -the base address of the CTI on the respective MEM-AP. All arguments are -mandatory. This creates a new command (@command{@var{cti_name}}) which -is used for various purposes including additional configuration. +@deffn Command {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-ctibase} base_address +Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP +@var{apn}. The @var{base_address} must match the base address of the CTI +on the respective MEM-AP. All arguments are mandatory. This creates a +new command @command{$cti_name} which is used for various purposes +including additional configuration. @end deffn @deffn Command {$cti_name enable} @option{on|off} @@ -8306,55 +8390,6 @@ cores @emph{except the ARM1176} use the same six bits. @cindex ARMv7 @cindex ARMv8 -@subsection ARMv7 and ARMv8 Debug Access Port (DAP) specific commands -@cindex Debug Access Port -@cindex DAP -These commands are specific to ARM architecture v7 and v8 Debug Access Port (DAP), -included on Cortex-M and Cortex-A systems. -They are available in addition to other core-specific commands that may be available. - -@deffn Command {dap apid} [num] -Displays ID register from AP @var{num}, -defaulting to the currently selected AP. -@end deffn - -@deffn Command {dap apreg} ap_num reg [value] -Displays content of a register @var{reg} from AP @var{ap_num} -or set a new value @var{value}. -@var{reg} is byte address of a word register, 0, 4, 8 ... 0xfc. -@end deffn - -@deffn Command {dap apsel} [num] -Select AP @var{num}, defaulting to 0. -@end deffn - -@deffn Command {dap baseaddr} [num] -Displays debug base address from MEM-AP @var{num}, -defaulting to the currently selected AP. -@end deffn - -@deffn Command {dap info} [num] -Displays the ROM table for MEM-AP @var{num}, -defaulting to the currently selected AP. -@end deffn - -@deffn Command {dap memaccess} [value] -Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP -memory bus access [0-255], giving additional time to respond to reads. -If @var{value} is defined, first assigns that. -@end deffn - -@deffn Command {dap apcsw} [0 / 1] -fix CSW_SPROT from register AP_REG_CSW on selected dap. -Defaulting to 0. -@end deffn - -@deffn Command {dap ti_be_32_quirks} [@option{enable}] -Set/get quirks mode for TI TMS450/TMS570 processors -Disabled by default -@end deffn - - @subsection ARMv7-A specific commands @cindex Cortex-A diff --git a/src/jtag/core.c b/src/jtag/core.c index df4afeb9d..0fbd327fe 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1315,7 +1315,6 @@ void jtag_tap_free(struct jtag_tap *tap) free(tap->chip); free(tap->tapname); free(tap->dotted_name); - free(tap->dap); free(tap); } @@ -1487,6 +1486,8 @@ int adapter_quit(void) t = n; } + dap_cleanup_all(); + return ERROR_OK; } diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 751facb17..a6891c03f 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -153,8 +153,6 @@ struct jtag_tap { struct jtag_tap_event_action *event_action; struct jtag_tap *next_tap; - /* dap instance if some null if no instance , initialized to 0 by calloc*/ - struct adiv5_dap *dap; /* private pointer to support none-jtag specific functions */ void *priv; }; diff --git a/src/openocd.c b/src/openocd.c index b97df3784..bd52f4acf 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -151,6 +152,10 @@ COMMAND_HANDLER(handle_init_command) if (ERROR_OK != retval) return ERROR_FAIL; + retval = command_run_line(CMD_CTX, "dap init"); + if (ERROR_OK != retval) + return ERROR_FAIL; + LOG_DEBUG("Examining targets..."); if (target_examine() != ERROR_OK) LOG_DEBUG("target examination failed"); @@ -254,6 +259,7 @@ struct command_context *setup_command_handler(Jim_Interp *interp) &pld_register_commands, &mflash_register_commands, &cti_register_commands, + &dap_register_commands, NULL }; for (unsigned i = 0; NULL != command_registrants[i]; i++) { diff --git a/src/target/Makefile.am b/src/target/Makefile.am index d2aab0a5e..206b28148 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -88,6 +88,7 @@ ARM_DEBUG_SRC = \ %D%/arm_simulator.c \ %D%/arm_semihosting.c \ %D%/arm_adi_v5.c \ + %D%/arm_dap.c \ %D%/armv7a_cache.c \ %D%/armv7a_cache_l2x.c \ %D%/adi_v5_jtag.c \ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index e9c822d64..4641a3fd5 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -41,6 +41,7 @@ enum halt_mode { }; struct aarch64_private_config { + struct adiv5_private_config adiv5_config; struct arm_cti *cti; }; @@ -2210,10 +2211,6 @@ static int aarch64_examine_first(struct target *target) uint32_t tmp0, tmp1, tmp2, tmp3; debug = ttypr = cpuid = 0; - retval = dap_dp_init(swjdp); - if (retval != ERROR_OK) - return retval; - /* Search for the APB-AB - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap); if (retval != ERROR_OK) { @@ -2358,18 +2355,13 @@ static int aarch64_init_target(struct command_context *cmd_ctx, } static int aarch64_init_arch_info(struct target *target, - struct aarch64_common *aarch64, struct jtag_tap *tap) + struct aarch64_common *aarch64, struct adiv5_dap *dap) { struct armv8_common *armv8 = &aarch64->armv8_common; /* Setup struct aarch64_common */ aarch64->common_magic = AARCH64_COMMON_MAGIC; - /* tap has no dap initialized */ - if (!tap->dap) { - tap->dap = dap_init(); - tap->dap->tap = tap; - } - armv8->arm.dap = tap->dap; + armv8->arm.dap = dap; /* register arch-specific functions */ armv8->examine_debug_reason = NULL; @@ -2385,9 +2377,13 @@ static int aarch64_init_arch_info(struct target *target, static int aarch64_target_create(struct target *target, Jim_Interp *interp) { + struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64 = calloc(1, sizeof(struct aarch64_common)); - return aarch64_init_arch_info(target, aarch64, target->tap); + if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) + return ERROR_FAIL; + + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } static int aarch64_mmu(struct target *target, int *enabled) @@ -2407,58 +2403,89 @@ static int aarch64_virt2phys(struct target *target, target_addr_t virt, return armv8_mmu_translate_va_pa(target, virt, phys, 1); } +/* + * private target configuration items + */ +enum aarch64_cfg_param { + CFG_CTI, +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-cti", .value = CFG_CTI }, + { .name = NULL, .value = -1 } +}; + static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) { struct aarch64_private_config *pc; - const char *arg; + Jim_Nvp *n; int e; - /* check if argv[0] is for us */ - arg = Jim_GetString(goi->argv[0], NULL); - if (strcmp(arg, "-cti")) - return JIM_CONTINUE; - - /* pop the argument from argv */ - e = Jim_GetOpt_String(goi, &arg, NULL); - if (e != JIM_OK) - return e; - - /* check if we have another option */ - if (goi->argc == 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-cti ?cti-name?"); - return JIM_ERR; - } - pc = (struct aarch64_private_config *)target->private_config; - - if (goi->isconfigure) { - Jim_Obj *o_cti; - struct arm_cti *cti; - e = Jim_GetOpt_Obj(goi, &o_cti); - if (e != JIM_OK) - return e; - cti = cti_instance_by_jim_obj(goi->interp, o_cti); - if (cti == NULL) - return JIM_ERR; - - if (pc == NULL) { + if (pc == NULL) { pc = calloc(1, sizeof(struct aarch64_private_config)); target->private_config = pc; - } - pc->cti = cti; - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; + } + + /* + * Call adiv5_jim_configure() to parse the common DAP options + * It will return JIM_CONTINUE if it didn't find any known + * options, JIM_OK if it correctly parsed the topmost option + * and JIM_ERR if an error occured during parameter evaluation. + * For JIM_CONTINUE, we check our own params. + */ + e = adiv5_jim_configure(target, goi); + if (e != JIM_CONTINUE) + return e; + + /* parse config or cget options ... */ + if (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + /* check first if topmost item is for us */ + e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, + goi->argv[0], &n); + if (e != JIM_OK) + return JIM_CONTINUE; + + e = Jim_GetOpt_Obj(goi, NULL); + if (e != JIM_OK) + return e; + + switch (n->value) { + case CFG_CTI: { + if (goi->isconfigure) { + Jim_Obj *o_cti; + struct arm_cti *cti; + e = Jim_GetOpt_Obj(goi, &o_cti); + if (e != JIM_OK) + return e; + cti = cti_instance_by_jim_obj(goi->interp, o_cti); + if (cti == NULL) { + Jim_SetResultString(goi->interp, "CTI name invalid!", -1); + return JIM_ERR; + } + pc->cti = cti; + } else { + if (goi->argc != 0) { + Jim_WrongNumArgs(goi->interp, + goi->argc, goi->argv, + "NO PARAMS"); + return JIM_ERR; + } + + if (pc == NULL || pc->cti == NULL) { + Jim_SetResultString(goi->interp, "CTI not configured", -1); + return JIM_ERR; + } + Jim_SetResultString(goi->interp, arm_cti_name(pc->cti), -1); + } + break; } - if (pc == NULL || pc->cti == NULL) { - Jim_SetResultString(goi->interp, "CTI not configured", -1); - return JIM_ERR; + default: + return JIM_CONTINUE; } - Jim_SetResultString(goi->interp, arm_cti_name(pc->cti), -1); } return JIM_OK; diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index c7dc4f7c9..dc0237900 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -574,6 +574,7 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) if ((ctrlstat & (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) != (CDBGPWRUPREQ | CDBGPWRUPACK | CSYSPWRUPREQ | CSYSPWRUPACK)) { LOG_ERROR("Debug regions are unpowered, an unexpected reset might have happened"); + dap->do_reconnect = true; } if (ctrlstat & SSTICKYERR) @@ -598,6 +599,20 @@ static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) /*--------------------------------------------------------------------------*/ +static int jtag_connect(struct adiv5_dap *dap) +{ + dap->do_reconnect = false; + return dap_dp_init(dap); +} + +static int jtag_check_reconnect(struct adiv5_dap *dap) +{ + if (dap->do_reconnect) + return jtag_connect(dap); + + return ERROR_OK; +} + static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { @@ -633,7 +648,11 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg) static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { - int retval = jtag_ap_q_bankselect(ap, reg); + int retval = jtag_check_reconnect(ap->dap); + if (retval != ERROR_OK) + return retval; + + retval = jtag_ap_q_bankselect(ap, reg); if (retval != ERROR_OK) return retval; @@ -647,7 +666,11 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { - int retval = jtag_ap_q_bankselect(ap, reg); + int retval = jtag_check_reconnect(ap->dap); + if (retval != ERROR_OK) + return retval; + + retval = jtag_ap_q_bankselect(ap, reg); if (retval != ERROR_OK) return retval; @@ -692,6 +715,7 @@ static int jtag_dp_sync(struct adiv5_dap *dap) * part of DAP setup */ const struct dap_ops jtag_dp_ops = { + .connect = jtag_connect, .queue_dp_read = jtag_dp_q_read, .queue_dp_write = jtag_dp_q_write, .queue_ap_read = jtag_ap_q_read, diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index c503f090b..0de272dd9 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -53,13 +53,11 @@ #include -/* YUK! - but this is currently a global.... */ -extern struct jtag_interface *jtag_interface; static bool do_sync; static void swd_finish_read(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); if (dap->last_read != NULL) { swd->read_reg(swd_cmd(true, false, DP_RDBUFF), dap->last_read, 0); dap->last_read = NULL; @@ -73,7 +71,7 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, static void swd_clear_sticky_errors(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); swd->write_reg(swd_cmd(false, false, DP_ABORT), @@ -82,7 +80,7 @@ static void swd_clear_sticky_errors(struct adiv5_dap *dap) static int swd_run_inner(struct adiv5_dap *dap) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); int retval; retval = swd->run(); @@ -97,6 +95,7 @@ static int swd_run_inner(struct adiv5_dap *dap) static int swd_connect(struct adiv5_dap *dap) { + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); uint32_t dpidr; int status; @@ -120,7 +119,7 @@ static int swd_connect(struct adiv5_dap *dap) } /* Note, debugport_init() does setup too */ - jtag_interface->swd->switch_seq(JTAG_TO_SWD); + swd->switch_seq(JTAG_TO_SWD); /* Clear link state, including the SELECT cache. */ dap->do_reconnect = false; @@ -136,6 +135,7 @@ static int swd_connect(struct adiv5_dap *dap) if (status == ERROR_OK) { LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr); dap->do_reconnect = false; + status = dap_dp_init(dap); } else dap->do_reconnect = true; @@ -157,7 +157,7 @@ static int swd_check_reconnect(struct adiv5_dap *dap) static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); swd->write_reg(swd_cmd(false, false, DP_ABORT), @@ -187,7 +187,7 @@ static void swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg) static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_check_reconnect(dap); @@ -203,7 +203,7 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { - const struct swd_driver *swd = jtag_interface->swd; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); int retval = swd_check_reconnect(dap); @@ -236,10 +236,9 @@ static void swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg) static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, uint32_t *data) { - const struct swd_driver *swd = jtag_interface->swd; - assert(swd); - struct adiv5_dap *dap = ap->dap; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) @@ -255,10 +254,9 @@ static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg, uint32_t data) { - const struct swd_driver *swd = jtag_interface->swd; - assert(swd); - struct adiv5_dap *dap = ap->dap; + const struct swd_driver *swd = adiv5_dap_swd_driver(dap); + assert(swd); int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) @@ -279,6 +277,7 @@ static int swd_run(struct adiv5_dap *dap) } const struct dap_ops swd_dap_ops = { + .connect = swd_connect, .queue_dp_read = swd_queue_dp_read, .queue_dp_write = swd_queue_dp_write, .queue_ap_read = swd_queue_ap_read, @@ -381,15 +380,15 @@ static const struct command_registration swd_handlers[] = { static int swd_select(struct command_context *ctx) { + /* FIXME: only place where global 'jtag_interface' is still needed */ + extern struct jtag_interface *jtag_interface; + const struct swd_driver *swd = jtag_interface->swd; int retval; retval = register_commands(ctx, NULL, swd_handlers); - if (retval != ERROR_OK) return retval; - const struct swd_driver *swd = jtag_interface->swd; - /* be sure driver is in SWD mode; start * with hardware default TRN (1), it can be changed later */ @@ -404,33 +403,14 @@ static int swd_select(struct command_context *ctx) return retval; } - /* force DAP into SWD mode (not JTAG) */ - /*retval = dap_to_swd(target);*/ - - if (ctx->current_target) { - /* force DAP into SWD mode (not JTAG) */ - struct target *target = get_current_target(ctx); - retval = dap_to_swd(target); - } - return retval; } static int swd_init(struct command_context *ctx) { - struct target *target = get_current_target(ctx); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - /* Force the DAP's ops vector for SWD mode. - * messy - is there a better way? */ - arm->dap->ops = &swd_dap_ops; - /* First connect after init is not reconnecting. */ - dap->do_reconnect = false; - - int retval = swd_connect(dap); - if (retval != ERROR_OK) - LOG_ERROR("SWD connect failed"); - return retval; + /* nothing done here, SWD is initialized + * together with the DAP */ + return ERROR_OK; } static struct transport swd_transport = { diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index dfbc5ade2..2b7d7b22d 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -76,6 +76,7 @@ #include #include #include +#include /* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */ @@ -614,33 +615,8 @@ int mem_ap_write_buf_noincr(struct adiv5_ap *ap, #define DAP_POWER_DOMAIN_TIMEOUT (10) -/* FIXME don't import ... just initialize as - * part of DAP transport setup -*/ -extern const struct dap_ops jtag_dp_ops; - /*--------------------------------------------------------------------------*/ -/** - * Create a new DAP - */ -struct adiv5_dap *dap_init(void) -{ - struct adiv5_dap *dap = calloc(1, sizeof(struct adiv5_dap)); - int i; - /* Set up with safe defaults */ - for (i = 0; i <= 255; i++) { - dap->ap[i].dap = dap; - dap->ap[i].ap_num = i; - /* memaccess_tck max is 255 */ - dap->ap[i].memaccess_tck = 255; - /* Number of bits for tar autoincrement, impl. dep. at least 10 */ - dap->ap[i].tar_autoincr_block = (1<<10); - } - INIT_LIST_HEAD(&dap->cmd_journal); - return dap; -} - /** * Invalidate cached DP select and cached TAR and CSW of all APs */ @@ -667,14 +643,7 @@ int dap_dp_init(struct adiv5_dap *dap) { int retval; - LOG_DEBUG(" "); - /* JTAG-DP or SWJ-DP, in JTAG mode - * ... for SWD mode this is patched as part - * of link switchover - * FIXME: This should already be setup by the respective transport specific DAP creation. - */ - if (!dap->ops) - dap->ops = &jtag_dp_ops; + LOG_DEBUG("%s", adiv5_dap_name(dap)); dap_invalidate_cache(dap); @@ -1376,7 +1345,7 @@ static int dap_rom_display(struct command_context *cmd_ctx, return ERROR_OK; } -static int dap_info_command(struct command_context *cmd_ctx, +int dap_info_command(struct command_context *cmd_ctx, struct adiv5_ap *ap) { int retval; @@ -1434,46 +1403,131 @@ static int dap_info_command(struct command_context *cmd_ctx, return ERROR_OK; } +enum adiv5_cfg_param { + CFG_DAP, + CFG_AP_NUM +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-dap", .value = CFG_DAP }, + { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = NULL, .value = -1 } +}; + int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) { struct adiv5_private_config *pc; - const char *arg; - jim_wide ap_num; int e; - /* check if argv[0] is for us */ - arg = Jim_GetString(goi->argv[0], NULL); - if (strcmp(arg, "-ap-num")) - return JIM_CONTINUE; - - e = Jim_GetOpt_String(goi, &arg, NULL); - if (e != JIM_OK) - return e; - - if (goi->argc == 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-ap-num ?ap-number? ..."); - return JIM_ERR; - } - - e = Jim_GetOpt_Wide(goi, &ap_num); - if (e != JIM_OK) - return e; - - if (target->private_config == NULL) { + pc = (struct adiv5_private_config *)target->private_config; + if (pc == NULL) { pc = calloc(1, sizeof(struct adiv5_private_config)); + pc->ap_num = -1; target->private_config = pc; - pc->ap_num = ap_num; } + target->has_dap = true; + + if (goi->argc > 0) { + Jim_Nvp *n; + + Jim_SetEmptyResult(goi->interp); + + /* check first if topmost item is for us */ + e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, + goi->argv[0], &n); + if (e != JIM_OK) + return JIM_CONTINUE; + + e = Jim_GetOpt_Obj(goi, NULL); + if (e != JIM_OK) + return e; + + switch (n->value) { + case CFG_DAP: + if (goi->isconfigure) { + Jim_Obj *o_t; + struct adiv5_dap *dap; + e = Jim_GetOpt_Obj(goi, &o_t); + if (e != JIM_OK) + return e; + dap = dap_instance_by_jim_obj(goi->interp, o_t); + if (dap == NULL) { + Jim_SetResultString(goi->interp, "DAP name invalid!", -1); + return JIM_ERR; + } + if (pc->dap != NULL && pc->dap != dap) { + Jim_SetResultString(goi->interp, + "DAP assignment cannot be changed after target was created!", -1); + return JIM_ERR; + } + if (target->tap_configured) { + Jim_SetResultString(goi->interp, + "-chain-position and -dap configparams are mutually exclusive!", -1); + return JIM_ERR; + } + pc->dap = dap; + target->tap = dap->tap; + target->dap_configured = true; + } else { + if (goi->argc != 0) { + Jim_WrongNumArgs(goi->interp, + goi->argc, goi->argv, + "NO PARAMS"); + return JIM_ERR; + } + + if (pc->dap == NULL) { + Jim_SetResultString(goi->interp, "DAP not configured", -1); + return JIM_ERR; + } + Jim_SetResultString(goi->interp, adiv5_dap_name(pc->dap), -1); + } + break; + + case CFG_AP_NUM: + if (goi->isconfigure) { + jim_wide ap_num; + e = Jim_GetOpt_Wide(goi, &ap_num); + if (e != JIM_OK) + return e; + pc->ap_num = ap_num; + } else { + if (goi->argc != 0) { + Jim_WrongNumArgs(goi->interp, + goi->argc, goi->argv, + "NO PARAMS"); + return JIM_ERR; + } + + if (pc->ap_num < 0) { + Jim_SetResultString(goi->interp, "AP number not configured", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, (int)pc->ap_num)); + } + break; + } + } return JIM_OK; } +int adiv5_verify_config(struct adiv5_private_config *pc) +{ + if (pc == NULL) + return ERROR_FAIL; + + if (pc->dap == NULL) + return ERROR_FAIL; + + return ERROR_OK; +} + + COMMAND_HANDLER(handle_dap_info_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel; switch (CMD_ARGC) { @@ -1494,10 +1548,7 @@ COMMAND_HANDLER(handle_dap_info_command) COMMAND_HANDLER(dap_baseaddr_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, baseaddr; int retval; @@ -1534,10 +1585,7 @@ COMMAND_HANDLER(dap_baseaddr_command) COMMAND_HANDLER(dap_memaccess_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t memaccess_tck; switch (CMD_ARGC) { @@ -1560,10 +1608,7 @@ COMMAND_HANDLER(dap_memaccess_command) COMMAND_HANDLER(dap_apsel_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, apid; int retval; @@ -1598,11 +1643,9 @@ COMMAND_HANDLER(dap_apsel_command) COMMAND_HANDLER(dap_apcsw_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - - uint32_t apcsw = dap->ap[dap->apsel].csw_default, sprot = 0; + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); + uint32_t apcsw = dap->ap[dap->apsel].csw_default; + uint32_t sprot = 0; switch (CMD_ARGC) { case 0: @@ -1631,10 +1674,7 @@ COMMAND_HANDLER(dap_apcsw_command) COMMAND_HANDLER(dap_apid_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, apid; int retval; @@ -1666,10 +1706,7 @@ COMMAND_HANDLER(dap_apid_command) COMMAND_HANDLER(dap_apreg_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t apsel, reg, value; int retval; @@ -1705,10 +1742,7 @@ COMMAND_HANDLER(dap_apreg_command) COMMAND_HANDLER(dap_ti_be_32_quirks_command) { - struct target *target = get_current_target(CMD_CTX); - struct arm *arm = target_to_arm(target); - struct adiv5_dap *dap = arm->dap; - + struct adiv5_dap *dap = adiv5_get_dap(CMD_DATA); uint32_t enable = dap->ti_be_32_quirks; switch (CMD_ARGC) { @@ -1729,7 +1763,7 @@ COMMAND_HANDLER(dap_ti_be_32_quirks_command) return 0; } -static const struct command_registration dap_commands[] = { +const struct command_registration dap_instance_commands[] = { { .name = "info", .handler = handle_dap_info_command, @@ -1795,14 +1829,3 @@ static const struct command_registration dap_commands[] = { }, COMMAND_REGISTRATION_DONE }; - -const struct command_registration dap_command_handlers[] = { - { - .name = "dap", - .mode = COMMAND_EXEC, - .help = "DAP command group", - .usage = "", - .chain = dap_commands, - }, - COMMAND_REGISTRATION_DONE -}; diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 657427b25..aa5fa42fe 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -254,6 +254,8 @@ struct adiv5_dap { * available until run(). */ struct dap_ops { + /** connect operation for SWD */ + int (*connect)(struct adiv5_dap *dap); /** DP register read. */ int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data); @@ -473,9 +475,6 @@ int mem_ap_read_buf_noincr(struct adiv5_ap *ap, int mem_ap_write_buf_noincr(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t address); -/* Create DAP struct */ -struct adiv5_dap *dap_init(void); - /* Initialisation of the debug system, power domains and registers */ int dap_dp_init(struct adiv5_dap *dap); int mem_ap_init(struct adiv5_ap *ap); @@ -509,12 +508,24 @@ int dap_to_swd(struct target *target); /* Put debug link into JTAG mode */ int dap_to_jtag(struct target *target); -extern const struct command_registration dap_command_handlers[]; +extern const struct command_registration dap_instance_commands[]; + +struct arm_dap_object; +extern struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o); +extern struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj); +extern int dap_info_command(struct command_context *cmd_ctx, + struct adiv5_ap *ap); +extern int dap_register_commands(struct command_context *cmd_ctx); +extern const char *adiv5_dap_name(struct adiv5_dap *self); +extern const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self); +extern int dap_cleanup_all(void); struct adiv5_private_config { int ap_num; + struct adiv5_dap *dap; }; +extern int adiv5_verify_config(struct adiv5_private_config *pc); extern int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi); #endif /* OPENOCD_TARGET_ARM_ADI_V5_H */ diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 6834a34a0..547b96158 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -365,22 +365,21 @@ static const struct command_registration cti_instance_command_handlers[] = { }; enum cti_cfg_param { - CFG_CHAIN_POSITION, + CFG_DAP, CFG_AP_NUM, CFG_CTIBASE }; static const Jim_Nvp nvp_config_opts[] = { - { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, - { .name = "-ctibase", .value = CFG_CTIBASE }, - { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = "-dap", .value = CFG_DAP }, + { .name = "-ctibase", .value = CFG_CTIBASE }, + { .name = "-ap-num", .value = CFG_AP_NUM }, { .name = NULL, .value = -1 } }; static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) { - struct jtag_tap *tap = NULL; - struct adiv5_dap *dap; + struct adiv5_dap *dap = NULL; Jim_Nvp *n; jim_wide w; int e; @@ -395,14 +394,14 @@ static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) return e; } switch (n->value) { - case CFG_CHAIN_POSITION: { + case CFG_DAP: { Jim_Obj *o_t; e = Jim_GetOpt_Obj(goi, &o_t); if (e != JIM_OK) return e; - tap = jtag_tap_by_jim_obj(goi->interp, o_t); - if (tap == NULL) { - Jim_SetResultString(goi->interp, "-chain-position is invalid", -1); + dap = dap_instance_by_jim_obj(goi->interp, o_t); + if (dap == NULL) { + Jim_SetResultString(goi->interp, "-dap is invalid", -1); return JIM_ERR; } /* loop for more */ @@ -424,18 +423,11 @@ static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) } } - if (tap == NULL) { - Jim_SetResultString(goi->interp, "-chain-position required when creating CTI", -1); + if (dap == NULL) { + Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1); return JIM_ERR; } - if (tap->dap == NULL) { - dap = dap_init(); - dap->tap = tap; - tap->dap = dap; - } else - dap = tap->dap; - cti->cti.ap = dap_ap(dap, cti->ap_num); return JIM_OK; diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c new file mode 100644 index 000000000..692feb322 --- /dev/null +++ b/src/target/arm_dap.c @@ -0,0 +1,366 @@ +/*************************************************************************** + * Copyright (C) 2016 by Matthias Welwarsky * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "target/arm_adi_v5.h" +#include "target/arm.h" +#include "helper/list.h" +#include "helper/command.h" +#include "transport/transport.h" +#include "jtag/interface.h" + +static LIST_HEAD(all_dap); + +extern const struct dap_ops swd_dap_ops; +extern const struct dap_ops jtag_dp_ops; +extern struct jtag_interface *jtag_interface; + +/* DAP command support */ +struct arm_dap_object { + struct list_head lh; + struct adiv5_dap dap; + char *name; + const struct swd_driver *swd; +}; + +static void dap_instance_init(struct adiv5_dap *dap) +{ + int i; + /* Set up with safe defaults */ + for (i = 0; i <= 255; i++) { + dap->ap[i].dap = dap; + dap->ap[i].ap_num = i; + /* memaccess_tck max is 255 */ + dap->ap[i].memaccess_tck = 255; + /* Number of bits for tar autoincrement, impl. dep. at least 10 */ + dap->ap[i].tar_autoincr_block = (1<<10); + } + INIT_LIST_HEAD(&dap->cmd_journal); +} + +const char *adiv5_dap_name(struct adiv5_dap *self) +{ + struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap); + return obj->name; +} + +const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self) +{ + struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap); + return obj->swd; +} + +struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj) +{ + return &obj->dap; +} +struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) +{ + struct arm_dap_object *obj = NULL; + const char *name; + bool found = false; + + name = Jim_GetString(o, NULL); + + list_for_each_entry(obj, &all_dap, lh) { + if (!strcmp(name, obj->name)) { + found = true; + break; + } + } + + if (found) + return &obj->dap; + return NULL; +} + +static int dap_init_all(void) +{ + struct arm_dap_object *obj; + int retval; + + LOG_DEBUG("Initializing all DAPs ..."); + + list_for_each_entry(obj, &all_dap, lh) { + struct adiv5_dap *dap = &obj->dap; + + /* with hla, dap is just a dummy */ + if (transport_is_hla()) + continue; + + /* skip taps that are disabled */ + if (!dap->tap->enabled) + continue; + + if (transport_is_swd()) { + dap->ops = &swd_dap_ops; + obj->swd = jtag_interface->swd; + } else + dap->ops = &jtag_dp_ops; + + retval = dap->ops->connect(dap); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +int dap_cleanup_all(void) +{ + struct arm_dap_object *obj, *tmp; + + list_for_each_entry_safe(obj, tmp, &all_dap, lh) { + free(obj->name); + free(obj); + } + + return ERROR_OK; +} + +enum dap_cfg_param { + CFG_CHAIN_POSITION, +}; + +static const Jim_Nvp nvp_config_opts[] = { + { .name = "-chain-position", .value = CFG_CHAIN_POSITION }, + { .name = NULL, .value = -1 } +}; + +static int dap_configure(Jim_GetOptInfo *goi, struct arm_dap_object *dap) +{ + struct jtag_tap *tap = NULL; + Jim_Nvp *n; + int e; + + /* parse config or cget options ... */ + while (goi->argc > 0) { + Jim_SetEmptyResult(goi->interp); + + e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); + if (e != JIM_OK) { + Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); + return e; + } + switch (n->value) { + case CFG_CHAIN_POSITION: { + Jim_Obj *o_t; + e = Jim_GetOpt_Obj(goi, &o_t); + if (e != JIM_OK) + return e; + tap = jtag_tap_by_jim_obj(goi->interp, o_t); + if (tap == NULL) { + Jim_SetResultString(goi->interp, "-chain-position is invalid", -1); + return JIM_ERR; + } + /* loop for more */ + break; + } + default: + break; + } + } + + if (tap == NULL) { + Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1); + return JIM_ERR; + } + + dap_instance_init(&dap->dap); + dap->dap.tap = tap; + + return JIM_OK; +} + +static int dap_create(Jim_GetOptInfo *goi) +{ + struct command_context *cmd_ctx; + static struct arm_dap_object *dap; + Jim_Obj *new_cmd; + Jim_Cmd *cmd; + const char *cp; + int e; + + cmd_ctx = current_command_context(goi->interp); + assert(cmd_ctx != NULL); + + if (goi->argc < 3) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); + return JIM_ERR; + } + /* COMMAND */ + Jim_GetOpt_Obj(goi, &new_cmd); + /* does this command exist? */ + cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); + if (cmd) { + cp = Jim_GetString(new_cmd, NULL); + Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); + return JIM_ERR; + } + + /* Create it */ + dap = calloc(1, sizeof(struct arm_dap_object)); + if (dap == NULL) + return JIM_ERR; + + e = dap_configure(goi, dap); + if (e != JIM_OK) { + free(dap); + return e; + } + + cp = Jim_GetString(new_cmd, NULL); + dap->name = strdup(cp); + + struct command_registration dap_commands[] = { + { + .name = cp, + .mode = COMMAND_ANY, + .help = "dap instance command group", + .usage = "", + .chain = dap_instance_commands, + }, + COMMAND_REGISTRATION_DONE + }; + + /* don't expose the instance commands when using hla */ + if (transport_is_hla()) + dap_commands[0].chain = NULL; + + e = register_commands(cmd_ctx, NULL, dap_commands); + if (ERROR_OK != e) + return JIM_ERR; + + struct command *c = command_find_in_context(cmd_ctx, cp); + assert(c); + command_set_handler_data(c, dap); + + list_add_tail(&dap->lh, &all_dap); + + return (ERROR_OK == e) ? JIM_OK : JIM_ERR; +} + +static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_GetOptInfo goi; + Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + if (goi.argc < 2) { + Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, + " [ ...]"); + return JIM_ERR; + } + return dap_create(&goi); +} + +static int jim_dap_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct arm_dap_object *obj; + + if (argc != 1) { + Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); + return JIM_ERR; + } + Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); + list_for_each_entry(obj, &all_dap, lh) { + Jim_ListAppendElement(interp, Jim_GetResult(interp), + Jim_NewStringObj(interp, obj->name, -1)); + } + return JIM_OK; +} + +COMMAND_HANDLER(handle_dap_init) +{ + return dap_init_all(); +} + +COMMAND_HANDLER(handle_dap_info_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct arm *arm = target_to_arm(target); + struct adiv5_dap *dap = arm->dap; + uint32_t apsel; + + switch (CMD_ARGC) { + case 0: + apsel = dap->apsel; + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); + if (apsel >= 256) + return ERROR_COMMAND_SYNTAX_ERROR; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return dap_info_command(CMD_CTX, &dap->ap[apsel]); +} + +static const struct command_registration dap_subcommand_handlers[] = { + { + .name = "create", + .mode = COMMAND_ANY, + .jim_handler = jim_dap_create, + .usage = "name '-chain-position' name", + .help = "Creates a new DAP instance", + }, + { + .name = "names", + .mode = COMMAND_ANY, + .jim_handler = jim_dap_names, + .usage = "", + .help = "Lists all registered DAP instances by name", + }, + { + .name = "init", + .mode = COMMAND_ANY, + .handler = handle_dap_init, + .usage = "", + .help = "Initialize all registered DAP instances" + }, + { + .name = "info", + .handler = handle_dap_info_command, + .mode = COMMAND_EXEC, + .help = "display ROM table for MEM-AP of current target " + "(default currently selected AP)", + .usage = "[ap_num]", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration dap_commands[] = { + { + .name = "dap", + .mode = COMMAND_CONFIG, + .help = "DAP commands", + .chain = dap_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +int dap_register_commands(struct command_context *cmd_ctx) +{ + return register_commands(cmd_ctx, NULL, dap_commands); +} diff --git a/src/target/armv7a.c b/src/target/armv7a.c index 183fde1bf..fab736310 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -776,9 +776,6 @@ const struct command_registration l2x_cache_command_handlers[] = { }; const struct command_registration armv7a_command_handlers[] = { - { - .chain = dap_command_handlers, - }, { .chain = l2x_cache_command_handlers, }, diff --git a/src/target/armv7m.c b/src/target/armv7m.c index e0911c30f..a8ddfe894 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -843,8 +843,5 @@ const struct command_registration armv7m_command_handlers[] = { { .chain = arm_command_handlers, }, - { - .chain = dap_command_handlers, - }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/armv8.c b/src/target/armv8.c index b88f37d6b..3321dd600 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1609,13 +1609,9 @@ struct reg *armv8_reg_current(struct arm *arm, unsigned regnum) } const struct command_registration armv8_command_handlers[] = { - { - .chain = dap_command_handlers, - }, COMMAND_REGISTRATION_DONE }; - int armv8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 74f30cb47..8985051ee 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -2947,12 +2947,6 @@ static int cortex_a_examine_first(struct target *target) int retval = ERROR_OK; uint32_t didr, cpuid, dbg_osreg; - retval = dap_dp_init(swjdp); - if (retval != ERROR_OK) { - LOG_ERROR("Could not initialize the debug port"); - return retval; - } - /* Search for the APB-AP - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); if (retval != ERROR_OK) { @@ -3134,22 +3128,13 @@ static int cortex_a_init_target(struct command_context *cmd_ctx, } static int cortex_a_init_arch_info(struct target *target, - struct cortex_a_common *cortex_a, struct jtag_tap *tap) + struct cortex_a_common *cortex_a, struct adiv5_dap *dap) { struct armv7a_common *armv7a = &cortex_a->armv7a_common; /* Setup struct cortex_a_common */ cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; - - /* tap has no dap initialized */ - if (!tap->dap) { - tap->dap = dap_init(); - - /* Leave (only) generic DAP stuff for debugport_init() */ - tap->dap->tap = tap; - } - - armv7a->arm.dap = tap->dap; + armv7a->arm.dap = dap; cortex_a->fast_reg_read = 0; @@ -3175,21 +3160,34 @@ static int cortex_a_init_arch_info(struct target *target, static int cortex_a_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common)); + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; + struct adiv5_private_config *pc; + + if (target->private_config == NULL) + return ERROR_FAIL; + + pc = (struct adiv5_private_config *)target->private_config; cortex_a->armv7a_common.is_armv7r = false; cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3; - return cortex_a_init_arch_info(target, cortex_a, target->tap); + return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common)); + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; + struct adiv5_private_config *pc; + + pc = (struct adiv5_private_config *)target->private_config; + if (adiv5_verify_config(pc) != ERROR_OK) + return ERROR_FAIL; cortex_a->armv7a_common.is_armv7r = true; - return cortex_a_init_arch_info(target, cortex_a, target->tap); + return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static void cortex_a_deinit_target(struct target *target) @@ -3200,6 +3198,7 @@ static void cortex_a_deinit_target(struct target *target) free(cortex_a->brp_list); free(dpm->dbp); free(dpm->dwp); + free(target->private_config); free(cortex_a); } @@ -3484,6 +3483,7 @@ struct target_type cortexa_target = { .commands = cortex_a_command_handlers, .target_create = cortex_a_target_create, + .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, @@ -3516,9 +3516,6 @@ static const struct command_registration cortex_r4_command_handlers[] = { { .chain = arm_command_handlers, }, - { - .chain = dap_command_handlers, - }, { .name = "cortex_r4", .mode = COMMAND_ANY, @@ -3562,6 +3559,7 @@ struct target_type cortexr4_target = { .commands = cortex_r4_command_handlers, .target_create = cortex_r4_target_create, + .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 79af632ac..14ebba318 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1992,12 +1992,6 @@ int cortex_m_examine(struct target *target) /* stlink shares the examine handler but does not support * all its calls */ if (!armv7m->stlink) { - retval = dap_dp_init(swjdp); - if (retval != ERROR_OK) { - LOG_ERROR("Could not initialize the debug port"); - return retval; - } - if (cortex_m->apsel < 0) { /* Search for the MEM-AP */ retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap); @@ -2228,25 +2222,17 @@ static int cortex_m_handle_target_request(void *priv) } static int cortex_m_init_arch_info(struct target *target, - struct cortex_m_common *cortex_m, struct jtag_tap *tap) + struct cortex_m_common *cortex_m, struct adiv5_dap *dap) { struct armv7m_common *armv7m = &cortex_m->armv7m; armv7m_init_arch_info(target, armv7m); - /* tap has no dap initialized */ - if (!tap->dap) { - tap->dap = dap_init(); - - /* Leave (only) generic DAP stuff for debugport_init() */ - tap->dap->tap = tap; - } - /* default reset mode is to use srst if fitted * if not it will use CORTEX_M3_RESET_VECTRESET */ cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; - armv7m->arm.dap = tap->dap; + armv7m->arm.dap = dap; /* register arch-specific functions */ armv7m->examine_debug_reason = cortex_m_examine_debug_reason; @@ -2266,16 +2252,16 @@ static int cortex_m_init_arch_info(struct target *target, static int cortex_m_target_create(struct target *target, Jim_Interp *interp) { struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); - cortex_m->common_magic = CORTEX_M_COMMON_MAGIC; - cortex_m_init_arch_info(target, cortex_m, target->tap); + struct adiv5_private_config *pc; - if (target->private_config != NULL) { - struct adiv5_private_config *pc = - (struct adiv5_private_config *)target->private_config; - cortex_m->apsel = pc->ap_num; - } else - cortex_m->apsel = -1; + pc = (struct adiv5_private_config *)target->private_config; + if (adiv5_verify_config(pc) != ERROR_OK) + return ERROR_FAIL; + + cortex_m->apsel = pc->ap_num; + + cortex_m_init_arch_info(target, cortex_m, pc->dap); return ERROR_OK; } diff --git a/src/target/hla_target.c b/src/target/hla_target.c index ba88248e3..9ebf24168 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -365,12 +365,16 @@ static int adapter_target_create(struct target *target, Jim_Interp *interp) { LOG_DEBUG("%s", __func__); - + struct adiv5_private_config *pc = target->private_config; struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common)); - if (!cortex_m) return ERROR_COMMAND_SYNTAX_ERROR; + if (pc != NULL && pc->ap_num > 0) { + LOG_ERROR("hla_target: invalid parameter -ap-num (> 0)"); + return ERROR_FAIL; + } + adapter_init_arch_info(target, cortex_m, target->tap); return ERROR_OK; @@ -801,6 +805,7 @@ struct target_type hla_target = { .init_target = adapter_init_target, .deinit_target = cortex_m_deinit_target, .target_create = adapter_target_create, + .target_jim_configure = adiv5_jim_configure, .examine = cortex_m_examine, .commands = adapter_command_handlers, diff --git a/src/target/target.c b/src/target/target.c index 9b6348a7d..4552034ec 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4765,6 +4765,13 @@ no_params: if (goi->isconfigure) { Jim_Obj *o_t; struct jtag_tap *tap; + + if (target->has_dap) { + Jim_SetResultString(goi->interp, + "target requires -dap parameter instead of -chain-position!", -1); + return JIM_ERR; + } + target_free_all_working_areas(target); e = Jim_GetOpt_Obj(goi, &o_t); if (e != JIM_OK) @@ -4772,8 +4779,8 @@ no_params: tap = jtag_tap_by_jim_obj(goi->interp, o_t); if (tap == NULL) return JIM_ERR; - /* make this exactly 1 or 0 */ target->tap = tap; + target->tap_configured = true; } else { if (goi->argc != 0) goto no_params; @@ -5591,9 +5598,21 @@ static int target_create(Jim_GetOptInfo *goi) goi->isconfigure = 1; e = target_configure(goi, target); - if (target->tap == NULL) { - Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1); - e = JIM_ERR; + if (e == JIM_OK) { + if (target->has_dap) { + if (!target->dap_configured) { + Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1); + e = JIM_ERR; + } + } else { + if (!target->tap_configured) { + Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1); + e = JIM_ERR; + } + } + /* tap must be set after target was configured */ + if (target->tap == NULL) + e = JIM_ERR; } if (e != JIM_OK) { @@ -5610,14 +5629,23 @@ static int target_create(Jim_GetOptInfo *goi) cp = Jim_GetString(new_cmd, NULL); target->cmd_name = strdup(cp); + if (target->type->target_create) { + e = (*(target->type->target_create))(target, goi->interp); + if (e != ERROR_OK) { + LOG_DEBUG("target_create failed"); + free(target->type); + free(target->cmd_name); + free(target); + return JIM_ERR; + } + } + /* create the target specific commands */ if (target->type->commands) { e = register_commands(cmd_ctx, NULL, target->type->commands); if (ERROR_OK != e) LOG_ERROR("unable to register '%s' commands", cp); } - if (target->type->target_create) - (*(target->type->target_create))(target, goi->interp); /* append to end of list */ { diff --git a/src/target/target.h b/src/target/target.h index 49048bcf4..0ce4a137a 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -181,10 +181,15 @@ struct target { bool halt_issued; /* did we transition to halted state? */ int64_t halt_issued_time; /* Note time when halt was issued */ + /* ARM v7/v8 targets with ADIv5 interface */ bool dbgbase_set; /* By default the debug base is not set */ uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no * system in place to support target specific options * currently. */ + bool has_dap; /* set to true if target has ADIv5 support */ + bool dap_configured; /* set to true if ADIv5 DAP is configured */ + bool tap_configured; /* set to true if JTAG tap has been configured + * through -chain-position */ struct rtos *rtos; /* Instance of Real Time Operating System support */ bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" diff --git a/tcl/target/1986ве1т.cfg b/tcl/target/1986ве1т.cfg index 7b0c35f08..ecb3f8ae1 100644 --- a/tcl/target/1986ве1т.cfg +++ b/tcl/target/1986ве1т.cfg @@ -34,9 +34,10 @@ if { [info exists CPUTAPID] } { } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # use AHB-Lite SRAM for work area $_TARGETNAME configure -work-area-phys 0x20100000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/adsp-sc58x.cfg b/tcl/target/adsp-sc58x.cfg index 369137ed9..e2b695215 100644 --- a/tcl/target/adsp-sc58x.cfg +++ b/tcl/target/adsp-sc58x.cfg @@ -27,9 +27,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_a -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -event examine-end { global _TARGETNAME diff --git a/tcl/target/aducm360.cfg b/tcl/target/aducm360.cfg index 785c18c59..ca4bc68de 100755 --- a/tcl/target/aducm360.cfg +++ b/tcl/target/aducm360.cfg @@ -32,7 +32,8 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x2ba01477 } -swd newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # SWD/JTAG speed adapter_khz 1000 @@ -41,7 +42,7 @@ adapter_khz 1000 ## Target configuration ## set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # allocate the working area $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/altera_fpgasoc.cfg b/tcl/target/altera_fpgasoc.cfg index 25fe1f493..1fbc5a375 100644 --- a/tcl/target/altera_fpgasoc.cfg +++ b/tcl/target/altera_fpgasoc.cfg @@ -14,7 +14,7 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # Subsidiary TAP: fpga @@ -42,7 +42,8 @@ set _TARGETNAME1 $_CHIPNAME.cpu.0 set _TARGETNAME2 $_CHIPNAME.cpu.1 # A9 core 0 -target create $_TARGETNAME1 cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80110000 $_TARGETNAME1 configure -event reset-start { adapter_khz 1000 } @@ -51,7 +52,7 @@ $_TARGETNAME1 configure -event gdb-attach { halt } # A9 core 1 -#target create $_TARGETNAME2 cortex_a -chain-position $_CHIPNAME.dap \ +#target create $_TARGETNAME2 cortex_a -dap $_CHIPNAME.dap \ # -coreid 1 -dbgbase 0x80112000 #$_TARGETNAME2 configure -event reset-start { adapter_khz 1000 } diff --git a/tcl/target/am335x.cfg b/tcl/target/am335x.cfg index 3ca196b11..02d8c7e82 100644 --- a/tcl/target/am335x.cfg +++ b/tcl/target/am335x.cfg @@ -12,7 +12,7 @@ if { [info exists CHIPNAME] } { if { [info exists DEFAULT_TAPS] } { set _DEFAULT_TAPS "$DEFAULT_TAPS" } else { - set _DEFAULT_TAPS "$_CHIPNAME.dap" + set _DEFAULT_TAPS "$_CHIPNAME.tap" } # @@ -23,8 +23,9 @@ if { [info exists DAP_TAPID] } { } else { set _DAP_TAPID 0x4b6b902f } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 12 0" +jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable +jtag configure $_CHIPNAME.tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 12 0" +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # # M3 DAP @@ -34,8 +35,9 @@ if { [info exists M3_DAP_TAPID] } { } else { set _M3_DAP_TAPID 0x4b6b902f } -jtag newtap $_CHIPNAME m3_dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m3_dap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 11 0" +jtag newtap $_CHIPNAME m3_tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable +jtag configure $_CHIPNAME.m3_tap -event tap-enable "icepick_d_tapenable $_CHIPNAME.jrc 11 0" +dap create $_CHIPNAME.m3_dap -chain-position $_CHIPNAME.m3_tap # # ICEpick-D (JTAG route controller) @@ -66,13 +68,13 @@ proc enable_default_taps { taps } { # Cortex-M3 target # set _TARGETNAME_2 $_CHIPNAME.m3 -target create $_TARGETNAME_2 cortex_m -chain-position $_CHIPNAME.m3_dap +target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.m3_dap # # Cortex-A8 target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap -dbgbase 0x80001000 +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80001000 # SRAM: 64K at 0x4030.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x4000 diff --git a/tcl/target/am437x.cfg b/tcl/target/am437x.cfg index fe0ffff29..8ce0941df 100644 --- a/tcl/target/am437x.cfg +++ b/tcl/target/am437x.cfg @@ -458,6 +458,7 @@ if { [info exists M3_DAP_TAPID] } { } jtag newtap $_CHIPNAME $M3_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_DAP_TAPID -disable jtag configure $M3_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 11 0" +dap create $M3_NAME.dap -chain-position $M3_NAME # # DebugSS DAP @@ -469,6 +470,7 @@ if { [info exists DAP_TAPID] } { } jtag newtap $_CHIPNAME $DEBUGSS_MODULE -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable jtag configure $DEBUGSS_NAME -event tap-enable "icepick_d_tapenable $JRC_NAME 12 0" +dap create $DEBUGSS_NAME.dap -chain-position $DEBUGSS_NAME # # ICEpick-D (JTAG route controller) @@ -486,7 +488,7 @@ jtag configure $JRC_NAME -event post-reset "runtest 100" # # Cortex-A9 target # -target create $_TARGETNAME cortex_a -chain-position $DEBUGSS_NAME -coreid 0 -dbgbase 0x80000000 +target create $_TARGETNAME cortex_a -dap $DEBUGSS_NAME.dap -coreid 0 -dbgbase 0x80000000 # SRAM: 256K at 0x4030.0000 diff --git a/tcl/target/amdm37x.cfg b/tcl/target/amdm37x.cfg index c00dae921..5c4e3151d 100644 --- a/tcl/target/amdm37x.cfg +++ b/tcl/target/amdm37x.cfg @@ -86,8 +86,8 @@ source [find target/icepick.cfg] # Secondary TAP: DAP is closest to the TDO output # The TAP enable event also needs to be described -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -disable +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # These taps are only present in the DM37x series. @@ -141,7 +141,8 @@ jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" # Create the CPU target to be used with GDB: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # The DM37x has 64K of SRAM starting at address 0x4020_0000. Allow the first # 16K to be used as a scratchpad for OpenOCD. diff --git a/tcl/target/armada370.cfg b/tcl/target/armada370.cfg index 40c779bdc..5b84637a2 100644 --- a/tcl/target/armada370.cfg +++ b/tcl/target/armada370.cfg @@ -16,10 +16,11 @@ if { [info exists CPUTAPID] } { set _CPUTAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap proc armada370_dbginit {target} { cortex_a dbginit diff --git a/tcl/target/at91sam3XXX.cfg b/tcl/target/at91sam3XXX.cfg index fca655d2c..e7dec4b3e 100644 --- a/tcl/target/at91sam3XXX.cfg +++ b/tcl/target/at91sam3XXX.cfg @@ -55,9 +55,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/at91sam3nXX.cfg b/tcl/target/at91sam3nXX.cfg index 19bd33a9e..3450c2626 100644 --- a/tcl/target/at91sam3nXX.cfg +++ b/tcl/target/at91sam3nXX.cfg @@ -18,9 +18,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap set _FLASHNAME $_CHIPNAME.flash flash bank flash0 at91sam3 0x00400000 0 0 0 $_TARGETNAME diff --git a/tcl/target/at91sam4XXX.cfg b/tcl/target/at91sam4XXX.cfg index ca801431a..ff7367040 100644 --- a/tcl/target/at91sam4XXX.cfg +++ b/tcl/target/at91sam4XXX.cfg @@ -35,9 +35,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # 16K is plenty, the smallest chip has this much $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/at91samdXX.cfg b/tcl/target/at91samdXX.cfg index 93a95c8eb..f0644d177 100644 --- a/tcl/target/at91samdXX.cfg +++ b/tcl/target/at91samdXX.cfg @@ -34,9 +34,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index b6c484237..d1f8454d5 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -32,9 +32,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20400000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/bcm281xx.cfg b/tcl/target/bcm281xx.cfg index 224af7933..6432a2092 100644 --- a/tcl/target/bcm281xx.cfg +++ b/tcl/target/bcm281xx.cfg @@ -14,15 +14,17 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -expected-id $_DAP_TAPID -irlen 4 +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 # Dual Cortex-A9 set _TARGETNAME0 $_CHIPNAME.cpu0 set _TARGETNAME1 $_CHIPNAME.cpu1 -target create $_TARGETNAME0 cortex_a -chain-position $_CHIPNAME.dap -coreid 0 -dbgbase 0x3fe10000 -target create $_TARGETNAME1 cortex_a -chain-position $_CHIPNAME.dap -coreid 1 -dbgbase 0x3fe12000 +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME0 cortex_a -dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x3fe10000 +target create $_TARGETNAME1 cortex_a -dap $_CHIPNAME.dap -coreid 1 -dbgbase 0x3fe12000 target smp $_TARGETNAME0 $_TARGETNAME1 $_TARGETNAME0 configure -event gdb-attach { diff --git a/tcl/target/bluenrg-x.cfg b/tcl/target/bluenrg-x.cfg index 3ae5108cf..b0dd61ae9 100644 --- a/tcl/target/bluenrg-x.cfg +++ b/tcl/target/bluenrg-x.cfg @@ -29,12 +29,13 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu set WDOG_VALUE 0 set WDOG_VALUE_SET 0 -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000100 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/cc26xx.cfg b/tcl/target/cc26xx.cfg index 1492e6a22..c3ac8470a 100755 --- a/tcl/target/cc26xx.cfg +++ b/tcl/target/cc26xx.cfg @@ -19,8 +19,8 @@ if { [info exists DAP_TAPID] } { } else { set _DAP_TAPID 0x4BA00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable +jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" # # ICEpick-C (JTAG route controller) @@ -33,11 +33,12 @@ if { [info exists JRC_TAPID] } { jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version # A start sequence is needed to change from cJTAG (Compact JTAG) to # 4-pin JTAG before talking via JTAG commands -jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap" +jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu" jtag configure $_CHIPNAME.jrc -event post-reset "ti_cjtag_to_4pin_jtag $_CHIPNAME.jrc" # # Cortex-M3 target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/cc32xx.cfg b/tcl/target/cc32xx.cfg index 154bf9106..dfc4c17a8 100755 --- a/tcl/target/cc32xx.cfg +++ b/tcl/target/cc32xx.cfg @@ -26,10 +26,10 @@ if { [info exists DAP_TAPID] } { } if {[using_jtag]} { - jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable - jtag configure $_CHIPNAME.dap -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" + jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable + jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0" } else { - swj_newdap $_CHIPNAME dap -expected-id $_DAP_TAPID + swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID } # @@ -50,4 +50,5 @@ if {[using_jtag]} { # Cortex-M3 target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/efm32.cfg b/tcl/target/efm32.cfg index e0c553fd2..e22ce5cba 100644 --- a/tcl/target/efm32.cfg +++ b/tcl/target/efm32.cfg @@ -32,11 +32,12 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu adapter_khz 1000 set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/em357.cfg b/tcl/target/em357.cfg index 24ffb04f9..572007134 100644 --- a/tcl/target/em357.cfg +++ b/tcl/target/em357.cfg @@ -50,12 +50,13 @@ if { [info exists FLASHSIZE] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [using_jtag] } { swj_newdap $_CHIPNAME bs -irlen 4 -expected-id $_BSTAPID -ircapture 0xe -irmask 0xf } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/exynos5250.cfg b/tcl/target/exynos5250.cfg index 36783410b..d3aaa986d 100644 --- a/tcl/target/exynos5250.cfg +++ b/tcl/target/exynos5250.cfg @@ -17,7 +17,8 @@ if { [info exists CPUTAPID] } { jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu -target create ${_TARGETNAME}0 cortex_a -chain-position $_TARGETNAME -target create ${_TARGETNAME}1 cortex_a -chain-position $_TARGETNAME +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap +target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap target smp ${_TARGETNAME}0 ${_TARGETNAME}1 diff --git a/tcl/target/fm3.cfg b/tcl/target/fm3.cfg index 78bbc945c..a0610ce17 100644 --- a/tcl/target/fm3.cfg +++ b/tcl/target/fm3.cfg @@ -31,9 +31,10 @@ if {[using_jtag]} { reset_config trst_only swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap # MB9BF506 has 64kB of SRAM on its main system bus $_TARGETNAME configure -work-area-phys 0x1FFF8000 -work-area-size 0x10000 -work-area-backup 0 diff --git a/tcl/target/fm4.cfg b/tcl/target/fm4.cfg index e5d0f8d60..b79634d96 100644 --- a/tcl/target/fm4.cfg +++ b/tcl/target/fm4.cfg @@ -19,9 +19,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap adapter_khz 500 diff --git a/tcl/target/hi3798.cfg b/tcl/target/hi3798.cfg index b6c3edabd..aa811d44d 100644 --- a/tcl/target/hi3798.cfg +++ b/tcl/target/hi3798.cfg @@ -16,8 +16,8 @@ if { [info exists DAP_TAPID] } { } # declare the one JTAG tap to access the DAP -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable - +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the 4 main application cores set _TARGETNAME $_CHIPNAME.cpu set _smp_command "" @@ -33,7 +33,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ - -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_core)]" + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail diff --git a/tcl/target/hi6220.cfg b/tcl/target/hi6220.cfg index 13d8586dd..c2feb0b36 100644 --- a/tcl/target/hi6220.cfg +++ b/tcl/target/hi6220.cfg @@ -16,7 +16,10 @@ if { [info exists DAP_TAPID] } { } # declare the one JTAG tap to access the DAP -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version + +# create the DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # declare the 8 main application cores set _TARGETNAME $_CHIPNAME.cpu @@ -34,10 +37,10 @@ set $_TARGETNAME.cti(7) 0x801DB000 set _cores 8 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -chain-position $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ - -chain-position $_CHIPNAME.dap -coreid $_core -cti cti$_core" + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" if { $_core != 0 } { # non-boot core examination may fail @@ -54,10 +57,10 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { eval $_smp_command -cti create cti.sys -chain-position hi6220.dap -ap-num 0 -ctibase 0x80003000 +cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -ctibase 0x80003000 # declare the auxiliary Cortex-M3 core on AP #2 (runs mcuimage.bin) -target create ${_TARGETNAME}.m3 cortex_m -chain-position $_CHIPNAME.dap -ap-num 2 -defer-examine +target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine # declare the auxiliary Cortex-A7 core -target create ${_TARGETNAME}.a7 cortex_a -chain-position $_CHIPNAME.dap -dbgbase 0x80210000 -defer-examine +target create ${_TARGETNAME}.a7 cortex_a -dap $_CHIPNAME.dap -dbgbase 0x80210000 -defer-examine diff --git a/tcl/target/imx51.cfg b/tcl/target/imx51.cfg index d10cf9f5d..22af2843e 100644 --- a/tcl/target/imx51.cfg +++ b/tcl/target/imx51.cfg @@ -13,11 +13,11 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x1ba00477 } -jtag newtap $_CHIPNAME DAP -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE -jtag newtap $_CHIPNAME SDMA -irlen 4 -ircapture 0x0 -irmask 0xf +jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { @@ -26,15 +26,16 @@ if { [info exists SJC_TAPID] } { set _SJC_TAPID 0x0190c01d } -jtag newtap $_CHIPNAME SJC -irlen 5 -ircapture 0x1 -irmask 0x1f \ +jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain -jtag configure $_CHIPNAME.SJC -event post-reset "runtest 100" +jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx51_dbginit {target} { # General Cortex-A8 debug initialisation diff --git a/tcl/target/imx53.cfg b/tcl/target/imx53.cfg index 5ad6473a8..84a85babb 100644 --- a/tcl/target/imx53.cfg +++ b/tcl/target/imx53.cfg @@ -13,11 +13,11 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x1ba00477 } -jtag newtap $_CHIPNAME DAP -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID # SDMA / no IDCODE -jtag newtap $_CHIPNAME SDMA -irlen 4 -ircapture 0x0 -irmask 0xf +jtag newtap $_CHIPNAME sdma -irlen 4 -ircapture 0x0 -irmask 0xf # SJC if { [info exists SJC_TAPID] } { @@ -26,15 +26,16 @@ if { [info exists SJC_TAPID] } { set _SJC_TAPID 0x0190d01d } -jtag newtap $_CHIPNAME SJC -irlen 5 -ircapture 0x1 -irmask 0x1f \ +jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x1 -irmask 0x1f \ -expected-id $_SJC_TAPID -ignore-version # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # some TCK tycles are required to activate the DEBUG power domain -jtag configure $_CHIPNAME.SJC -event post-reset "runtest 100" +jtag configure $_CHIPNAME.sjc -event post-reset "runtest 100" proc imx53_dbginit {target} { # General Cortex-A8 debug initialisation diff --git a/tcl/target/imx6.cfg b/tcl/target/imx6.cfg index 4f7e98afd..5b59ecf86 100644 --- a/tcl/target/imx6.cfg +++ b/tcl/target/imx6.cfg @@ -13,7 +13,7 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # SDMA / no IDCODE @@ -40,7 +40,8 @@ jtag newtap $_CHIPNAME sjc -irlen 5 -ircapture 0x01 -irmask 0x1f \ # core 2 - 0x82154000 # core 3 - 0x82156000 set _TARGETNAME $_CHIPNAME.cpu.0 -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x82150000 # some TCK cycles are required to activate the DEBUG power domain diff --git a/tcl/target/imx7.cfg b/tcl/target/imx7.cfg index d16e95a27..f47dd7d0f 100644 --- a/tcl/target/imx7.cfg +++ b/tcl/target/imx7.cfg @@ -11,7 +11,7 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x5ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f \ -expected-id $_DAP_TAPID # @@ -22,16 +22,19 @@ jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x0f \ # core 0 - 0x80070000 # core 1 - 0x80072000 set _TARGETNAME $_CHIPNAME.cpu_a7 -target create $_TARGETNAME.0 cortex_a -chain-position $_CHIPNAME.dap \ + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME.0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80070000 -target create $_TARGETNAME.1 cortex_a -chain-position $_CHIPNAME.dap \ +target create $_TARGETNAME.1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80072000 -defer-examine # # Cortex-M4 target # set _TARGETNAME_2 $_CHIPNAME.cpu_m4 -target create $_TARGETNAME_2 cortex_m -chain-position $_CHIPNAME.dap -ap-num 4 \ +target create $_TARGETNAME_2 cortex_m -dap $_CHIPNAME.dap -ap-num 4 \ -defer-examine targets $_TARGETNAME.0 diff --git a/tcl/target/k1921vk01t.cfg b/tcl/target/k1921vk01t.cfg index 61b193e39..1a8402106 100755 --- a/tcl/target/k1921vk01t.cfg +++ b/tcl/target/k1921vk01t.cfg @@ -31,9 +31,10 @@ if { [info exists CPUTAPID] } { } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/ke0x.cfg b/tcl/target/ke0x.cfg index 1f1b1321e..8239400d0 100644 --- a/tcl/target/ke0x.cfg +++ b/tcl/target/ke0x.cfg @@ -25,9 +25,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index b41dbf78e..5d9286a69 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -26,9 +26,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/kx.cfg b/tcl/target/kx.cfg index 51703e69d..73ee62a79 100644 --- a/tcl/target/kx.cfg +++ b/tcl/target/kx.cfg @@ -30,9 +30,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/lpc1850.cfg b/tcl/target/lpc1850.cfg index a78140374..925a0498d 100644 --- a/tcl/target/lpc1850.cfg +++ b/tcl/target/lpc1850.cfg @@ -23,9 +23,10 @@ if { [info exists M3_JTAG_TAPID] } { } swj_newdap $_CHIPNAME m3 -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_M3_JTAG_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.m3 set _TARGETNAME $_CHIPNAME.m3 -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap if {![using_hla]} { # if srst is not fitted use SYSRESETREQ to diff --git a/tcl/target/lpc1xxx.cfg b/tcl/target/lpc1xxx.cfg index 9c10e9f93..701adf278 100644 --- a/tcl/target/lpc1xxx.cfg +++ b/tcl/target/lpc1xxx.cfg @@ -75,9 +75,10 @@ if { [info exists WORKAREASIZE] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # The LPC11xx devices have 2/4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) # The LPC12xx devices have 4/8kB of SRAM in the ARMv7-M "Code" area (at 0x10000000) diff --git a/tcl/target/lpc4350.cfg b/tcl/target/lpc4350.cfg index 4e23ffb0d..2b728840e 100644 --- a/tcl/target/lpc4350.cfg +++ b/tcl/target/lpc4350.cfg @@ -43,12 +43,14 @@ if { [info exists M0_JTAG_TAPID] } { swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID -target create $_CHIPNAME.m4 cortex_m -chain-position $_CHIPNAME.m4 +dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 +target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap if { [using_jtag] } { swj_newdap $_CHIPNAME m0 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID - target create $_CHIPNAME.m0 cortex_m -chain-position $_CHIPNAME.m0 + dap create $_CHIPNAME.m0.dap -chain-position $_CHIPNAME.m0 + target create $_CHIPNAME.m0 cortex_m -dap $_CHIPNAME.m0.dap } # LPC4350 has 96+32 KB SRAM diff --git a/tcl/target/lpc4370.cfg b/tcl/target/lpc4370.cfg index 67bff0adc..1374ef275 100644 --- a/tcl/target/lpc4370.cfg +++ b/tcl/target/lpc4370.cfg @@ -47,8 +47,8 @@ if { [info exists M0_JTAG_TAPID] } { swj_newdap $_CHIPNAME m4 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M4_TAPID - -target create $_CHIPNAME.m4 cortex_m -chain-position $_CHIPNAME.m4 +dap create $_CHIPNAME.m4.dap -chain-position $_CHIPNAME.m4 +target create $_CHIPNAME.m4 cortex_m -dap $_CHIPNAME.m4.dap # LPC4370 has 96+32 KB contiguous SRAM if { [info exists WORKAREASIZE] } { @@ -65,8 +65,10 @@ if { [using_jtag] } { jtag newtap $_CHIPNAME m0sub -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M0_JTAG_TAPID - target create $_CHIPNAME.m0app cortex_m -chain-position $_CHIPNAME.m0app - target create $_CHIPNAME.m0sub cortex_m -chain-position $_CHIPNAME.m0sub + dap create $_CHIPNAME.m0app.dap -chain-position $_CHIPNAME.m0app + dap create $_CHIPNAME.m0sub.dap -chain-position $_CHIPNAME.m0sub + target create $_CHIPNAME.m0app cortex_m -dap $_CHIPNAME.m0app.dap + target create $_CHIPNAME.m0sub cortex_m -dap $_CHIPNAME.m0sub.dap # 32+8+32 KB SRAM $_CHIPNAME.m0app configure -work-area-phys 0x10080000 \ diff --git a/tcl/target/marvell/88f37x0.cfg b/tcl/target/marvell/88f37x0.cfg index c7007dd48..5e7513588 100644 --- a/tcl/target/marvell/88f37x0.cfg +++ b/tcl/target/marvell/88f37x0.cfg @@ -35,7 +35,8 @@ if { [info exists DAP_TAPID] } { } # declare the one JTAG tap to access the DAP -swj_newdap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # declare the main application cores set _TARGETNAME $_CHIPNAME.cpu @@ -43,10 +44,10 @@ set _smp_command "" for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -chain-position $_CHIPNAME.dap -ctibase [lindex $_ctis $_core] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -ctibase [lindex $_ctis $_core] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ - -chain-position $_CHIPNAME.dap -coreid $_core \ + -dap $_CHIPNAME.dap -coreid $_core \ -cti cti$_core" if { $_core != 0 } { @@ -65,6 +66,6 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { eval $_smp_command # declare the auxiliary Cortex-M3 core on AP #3 -target create ${_TARGETNAME}.m3 cortex_m -chain-position $_CHIPNAME.dap -ap-num 3 -defer-examine +target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine targets ${_TARGETNAME}0 diff --git a/tcl/target/mdr32f9q2i.cfg b/tcl/target/mdr32f9q2i.cfg index 804ac1aef..67481024c 100644 --- a/tcl/target/mdr32f9q2i.cfg +++ b/tcl/target/mdr32f9q2i.cfg @@ -34,9 +34,10 @@ if { [info exists CPUTAPID] } { } } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/nrf51.cfg b/tcl/target/nrf51.cfg index 280dd4ff3..4f2402033 100644 --- a/tcl/target/nrf51.cfg +++ b/tcl/target/nrf51.cfg @@ -31,9 +31,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index e73017503..c29adbdd6 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -25,9 +25,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap adapter_khz 1000 diff --git a/tcl/target/numicro.cfg b/tcl/target/numicro.cfg index 13d965432..c42dfbc2f 100644 --- a/tcl/target/numicro.cfg +++ b/tcl/target/numicro.cfg @@ -28,8 +28,9 @@ if { [info exists WORKAREASIZE] } { # Debug Adapter Target Settings swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUDAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/omap3530.cfg b/tcl/target/omap3530.cfg index c2929d1c4..078d7f24d 100644 --- a/tcl/target/omap3530.cfg +++ b/tcl/target/omap3530.cfg @@ -20,9 +20,9 @@ if { [info exists DAP_TAPID] } { } else { set _DAP_TAPID 0x0b6d602f } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 3" # Primary TAP: ICEpick-C (JTAG route controller) and boundary scan @@ -36,7 +36,8 @@ jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \ # GDB target: Cortex-A8, using DAP set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap # SRAM: 64K at 0x4020.0000; use the first 16K $_TARGETNAME configure -work-area-phys 0x40200000 -work-area-size 0x4000 diff --git a/tcl/target/omap4430.cfg b/tcl/target/omap4430.cfg index 6f3525aed..6e3e78d37 100644 --- a/tcl/target/omap4430.cfg +++ b/tcl/target/omap4430.cfg @@ -22,9 +22,9 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x3BA00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" @@ -37,14 +37,14 @@ if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID 0x4BA00477 } -jtag newtap $_CHIPNAME m31_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m31_dap -event tap-enable \ +jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" -jtag newtap $_CHIPNAME m30_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m30_dap -event tap-enable \ +jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" @@ -93,8 +93,9 @@ set _TARGETNAME $_CHIPNAME.cpu set _coreid 0 set _dbgbase [expr 0x80000000 | ($_coreid << 13)] echo "Using dbgbase = [format 0x%x $_dbgbase]" - -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap \ + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 @@ -104,15 +105,17 @@ $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # -target create $_CHIPNAME.m30 cortex_m -chain-position $_CHIPNAME.m30_dap -target create $_CHIPNAME.m31 cortex_m -chain-position $_CHIPNAME.m31_dap +dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 +dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 +target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap +target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " - jtag tapenable $_CHIPNAME.dap - jtag tapenable $_CHIPNAME.m30_dap - jtag tapenable $_CHIPNAME.m31_dap + jtag tapenable $_CHIPNAME.cpu + jtag tapenable $_CHIPNAME.m30 + jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset @@ -124,4 +127,3 @@ $_CHIPNAME.m31 configure -event reset-assert { } # Soft breakpoints don't currently work due to broken cache handling gdb_breakpoint_override hard - diff --git a/tcl/target/omap4460.cfg b/tcl/target/omap4460.cfg index 9c40e62d0..218eb64e9 100644 --- a/tcl/target/omap4460.cfg +++ b/tcl/target/omap4460.cfg @@ -22,9 +22,9 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x3BA00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_DAP_TAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ +jtag configure $_CHIPNAME.cpu -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 9" @@ -37,14 +37,14 @@ if { [info exists M3_DAP_TAPID] } { set _M3_DAP_TAPID 0x4BA00477 } -jtag newtap $_CHIPNAME m31_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m31 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m31_dap -event tap-enable \ +jtag configure $_CHIPNAME.m31 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 5" -jtag newtap $_CHIPNAME m30_dap -irlen 4 -ircapture 0x1 -irmask 0xf \ +jtag newtap $_CHIPNAME m30 -irlen 4 -ircapture 0x1 -irmask 0xf \ -expected-id $_M3_DAP_TAPID -disable -jtag configure $_CHIPNAME.m30_dap -event tap-enable \ +jtag configure $_CHIPNAME.m30 -event tap-enable \ "icepick_c_tapenable $_CHIPNAME.jrc 4" @@ -94,7 +94,8 @@ set _coreid 0 set _dbgbase [expr 0x80000000 | ($_coreid << 13)] echo "Using dbgbase = [format 0x%x $_dbgbase]" -target create $_TARGETNAME cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase $_dbgbase # SRAM: 56KiB at 0x4030.0000 @@ -104,15 +105,17 @@ $_TARGETNAME configure -work-area-phys 0x40300000 -work-area-size 0x1000 # # M3 targets, separate TAP/DAP for each core # -target create $_CHIPNAME.m30 cortex_m -chain-position $_CHIPNAME.m30_dap -target create $_CHIPNAME.m31 cortex_m -chain-position $_CHIPNAME.m31_dap +dap create $_CHIPNAME.m30_dap -chain-position $_CHIPNAME.m30 +dap create $_CHIPNAME.m31_dap -chain-position $_CHIPNAME.m31 +target create $_CHIPNAME.m30 cortex_m -dap $_CHIPNAME.m30_dap +target create $_CHIPNAME.m31 cortex_m -dap $_CHIPNAME.m31_dap # Once the JRC is up, enable our TAPs jtag configure $_CHIPNAME.jrc -event setup " - jtag tapenable $_CHIPNAME.dap - jtag tapenable $_CHIPNAME.m30_dap - jtag tapenable $_CHIPNAME.m31_dap + jtag tapenable $_CHIPNAME.cpu + jtag tapenable $_CHIPNAME.m30 + jtag tapenable $_CHIPNAME.m31 " # Assume SRST is unavailable (e.g. TI-14 JTAG), so we must assert reset diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index 5d6dcede3..eb51847ce 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -26,9 +26,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/psoc5lp.cfg b/tcl/target/psoc5lp.cfg index 1cdde4712..230ca0732 100644 --- a/tcl/target/psoc5lp.cfg +++ b/tcl/target/psoc5lp.cfg @@ -23,9 +23,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_DAP_ID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if {![using_hla]} { cortex_m reset_config sysresetreq diff --git a/tcl/target/psoc6.cfg b/tcl/target/psoc6.cfg index d6c5a04ad..ad9aba569 100644 --- a/tcl/target/psoc6.cfg +++ b/tcl/target/psoc6.cfg @@ -19,6 +19,7 @@ global TARGET set TARGET $_CHIPNAME.cpu swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu # Is CM0 Debugging enabled ? global _ENABLE_CM0 @@ -99,7 +100,7 @@ proc psoc6_deassert_post { target } { } if { $_ENABLE_CM0 } { - target create ${TARGET}.cm0 cortex_m -chain-position $TARGET -ap-num 1 -coreid 0 + target create ${TARGET}.cm0 cortex_m -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 ${TARGET}.cm0 configure -work-area-phys $_WORKAREAADDR_CM0 -work-area-size $_WORKAREASIZE_CM0 -work-area-backup 0 flash bank main_flash_cm0 psoc6 0x10000000 0 0 0 ${TARGET}.cm0 @@ -114,7 +115,7 @@ if { $_ENABLE_CM0 } { } if { $_ENABLE_CM4 } { - target create ${TARGET}.cm4 cortex_m -chain-position $TARGET -ap-num 2 -coreid 1 + target create ${TARGET}.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -coreid 1 ${TARGET}.cm4 configure -work-area-phys $_WORKAREAADDR_CM4 -work-area-size $_WORKAREASIZE_CM4 -work-area-backup 0 flash bank main_flash_cm4 psoc6 0x10000000 0 0 0 ${TARGET}.cm4 diff --git a/tcl/target/renesas_s7g2.cfg b/tcl/target/renesas_s7g2.cfg index a09377b2d..78fb3e82f 100644 --- a/tcl/target/renesas_s7g2.cfg +++ b/tcl/target/renesas_s7g2.cfg @@ -29,9 +29,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE diff --git a/tcl/target/sim3x.cfg b/tcl/target/sim3x.cfg index f721f36c8..ed46a3b34 100755 --- a/tcl/target/sim3x.cfg +++ b/tcl/target/sim3x.cfg @@ -38,9 +38,10 @@ if { [info exists WORKAREASIZE] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE diff --git a/tcl/target/stellaris.cfg b/tcl/target/stellaris.cfg index 4fe99394a..7fffd2a7c 100644 --- a/tcl/target/stellaris.cfg +++ b/tcl/target/stellaris.cfg @@ -42,7 +42,8 @@ if { [info exists CPUTAPID] } { # ... even though SWD ignores all except TAPID, and # JTAG shouldn't need anything more then irlen. (and TAPID). swj_newdap $_CHIPNAME cpu -irlen 4 -irmask 0xf \ - -expected-id $_CPUTAPID -ignore-version + -expected-id $_CPUTAPID -ignore-version +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE @@ -52,7 +53,7 @@ if { [info exists WORKAREASIZE] } { } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # 8K working area at base of ram, not backed up # diff --git a/tcl/target/stm32f0x.cfg b/tcl/target/stm32f0x.cfg index 2b48cfce3..b8c0de94c 100644 --- a/tcl/target/stm32f0x.cfg +++ b/tcl/target/stm32f0x.cfg @@ -32,9 +32,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f1x.cfg b/tcl/target/stm32f1x.cfg index 5a4c2fa70..e0f6ede95 100644 --- a/tcl/target/stm32f1x.cfg +++ b/tcl/target/stm32f1x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f2x.cfg b/tcl/target/stm32f2x.cfg index 44955d455..80f9274d5 100644 --- a/tcl/target/stm32f2x.cfg +++ b/tcl/target/stm32f2x.cfg @@ -49,13 +49,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f3x.cfg b/tcl/target/stm32f3x.cfg index 0c8919f1d..86e9f594e 100644 --- a/tcl/target/stm32f3x.cfg +++ b/tcl/target/stm32f3x.cfg @@ -49,13 +49,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 7a0af9fba..73b1dc8ed 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 4065e2a07..dc310da44 100755 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 02dbed4a8..10477a5a7 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -34,13 +34,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { swj_newdap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32l0.cfg b/tcl/target/stm32l0.cfg index 417b282d3..ec5d5463e 100644 --- a/tcl/target/stm32l0.cfg +++ b/tcl/target/stm32l0.cfg @@ -37,9 +37,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32l1.cfg b/tcl/target/stm32l1.cfg index a8d6fdf25..054fa9b74 100644 --- a/tcl/target/stm32l1.cfg +++ b/tcl/target/stm32l1.cfg @@ -45,13 +45,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index ccee48e97..496b47a72 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -36,13 +36,14 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/stm32w108xx.cfg b/tcl/target/stm32w108xx.cfg index d07afc414..3a83fd19e 100644 --- a/tcl/target/stm32w108xx.cfg +++ b/tcl/target/stm32w108xx.cfg @@ -37,6 +37,7 @@ if { [info exists CPUTAPID] } { set _ENDIAN little swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu if {[using_jtag]} { if { [info exists BSTAPID] } { @@ -53,7 +54,7 @@ if {[using_jtag]} { # Set Target # set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 diff --git a/tcl/target/ti_msp432p4xx.cfg b/tcl/target/ti_msp432p4xx.cfg index 860086707..461b59547 100644 --- a/tcl/target/ti_msp432p4xx.cfg +++ b/tcl/target/ti_msp432p4xx.cfg @@ -31,9 +31,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_DAP_ID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE diff --git a/tcl/target/u8500.cfg b/tcl/target/u8500.cfg index 66fc075c2..7d8bfe375 100644 --- a/tcl/target/u8500.cfg +++ b/tcl/target/u8500.cfg @@ -167,11 +167,11 @@ if { [info exists CPUTAPID] } { } else { set _CPUTAPID 0x4ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0xe -irmask 0xf -expected-id $_CPUTAPID -disable -jtag configure $_CHIPNAME.dap -event tap-enable \ - "u8500_dapenable $_CHIPNAME.dap" -jtag configure $_CHIPNAME.dap -event tap-disable \ - "u8500_tapdisable $_CHIPNAME.dap 0xc0" +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0xe -irmask 0xf -expected-id $_CPUTAPID -disable +jtag configure $_CHIPNAME.cpu -event tap-enable \ + "u8500_dapenable $_CHIPNAME.cpu" +jtag configure $_CHIPNAME.cpu -event tap-disable \ + "u8500_tapdisable $_CHIPNAME.cpu 0xc0" #CLTAPC TAP JRC equivalent @@ -202,7 +202,9 @@ if { [info exists DAP_DBG2] } { set _DAP_DBG2 0x801AA000 } -target create $_TARGETNAME_1 cortex_a -chain-position $_CHIPNAME.dap -dbgbase $_DAP_DBG1 -coreid 0 -rtos linux +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create $_TARGETNAME_1 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG1 -coreid 0 -rtos linux $_TARGETNAME_1 configure -event gdb-attach { halt @@ -217,7 +219,7 @@ global _TARGETNAME_2 set _TARGETNAME_2 $TARGETNAME_2 } -target create $_TARGETNAME_2 cortex_a -chain-position $_CHIPNAME.dap -dbgbase $_DAP_DBG2 -coreid 1 -rtos linux +target create $_TARGETNAME_2 cortex_a -dap $_CHIPNAME.dap -dbgbase $_DAP_DBG2 -coreid 1 -rtos linux $_TARGETNAME_2 configure -event gdb-attach { halt diff --git a/tcl/target/vybrid_vf6xx.cfg b/tcl/target/vybrid_vf6xx.cfg index 6ec4b35cd..a1202efb7 100644 --- a/tcl/target/vybrid_vf6xx.cfg +++ b/tcl/target/vybrid_vf6xx.cfg @@ -29,8 +29,9 @@ if { [using_jtag] } { source [find target/swj-dp.tcl] swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_A5_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create ${_TARGETNAME}0 cortex_a -chain-position $_CHIPNAME.cpu -dbgbase 0xc0088000 +target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap -dbgbase 0xc0088000 adapter_khz 1000 diff --git a/tcl/target/xilinx_ultrascale.cfg b/tcl/target/xilinx_ultrascale.cfg index 9be198dc1..9056c976e 100644 --- a/tcl/target/xilinx_ultrascale.cfg +++ b/tcl/target/xilinx_ultrascale.cfg @@ -17,7 +17,8 @@ if { [info exists DAP_TAPID] } { set _DAP_TAPID 0x5ba00477 } -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID +jtag newtap $_CHIPNAME tap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap # # PS tap @@ -53,6 +54,7 @@ jtag configure $_CHIPNAME.ps -event setup { set _TARGETNAME $_CHIPNAME.a53 set _CTINAME $_CHIPNAME.cti +set _smp_command "" set DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000} set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} @@ -60,10 +62,10 @@ set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core } { - cti create $_CTINAME.$_core -chain-position $_CHIPNAME.dap -ap-num 1 \ + cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -ctibase [lindex $CTIBASE $_core] - set _command "target create $_TARGETNAME.$_core aarch64 -chain-position $_CHIPNAME.dap \ + set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" if { $_core != 0 } { diff --git a/tcl/target/xmc1xxx.cfg b/tcl/target/xmc1xxx.cfg index d3123c437..e693b59db 100644 --- a/tcl/target/xmc1xxx.cfg +++ b/tcl/target/xmc1xxx.cfg @@ -20,9 +20,10 @@ if { [info exists CPUTAPID] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_SWD_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian little -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE diff --git a/tcl/target/xmc4xxx.cfg b/tcl/target/xmc4xxx.cfg index bc0077799..e106d34e3 100644 --- a/tcl/target/xmc4xxx.cfg +++ b/tcl/target/xmc4xxx.cfg @@ -35,9 +35,10 @@ if { [using_jtag] } { } swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap # Work-area is a space in RAM used for flash programming # By default use 16 kB diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index 70a861625..07a6c8352 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -13,11 +13,13 @@ jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \ -expected-id 0x03727093 \ -expected-id 0x03736093 -jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477 -target create ${_TARGETNAME}0 cortex_a -chain-position $_CHIPNAME.dap \ +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +target create ${_TARGETNAME}0 cortex_a -dap $_CHIPNAME.dap \ -coreid 0 -dbgbase 0x80090000 -target create ${_TARGETNAME}1 cortex_a -chain-position $_CHIPNAME.dap \ +target create ${_TARGETNAME}1 cortex_a -dap $_CHIPNAME.dap \ -coreid 1 -dbgbase 0x80092000 target smp ${_TARGETNAME}0 ${_TARGETNAME}1 From 7944ebb6945d01e2f603f80c5c70f349c8338950 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 3 Aug 2017 12:25:07 +0200 Subject: [PATCH 77/91] xilinx-xcu: add Xilinx Ultrascale tap data The Ultrascale series is a bit more complicated to handle since with the stacked and interconnected dies the IR gets longer. This adds support for all currently known chips from the Ultrascale family. Change-Id: Ibac325dd6fadc76f73cc682b1c62c1a5f39f0786 Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4188 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/cpld/xilinx-xcu.cfg | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tcl/cpld/xilinx-xcu.cfg diff --git a/tcl/cpld/xilinx-xcu.cfg b/tcl/cpld/xilinx-xcu.cfg new file mode 100644 index 000000000..327059711 --- /dev/null +++ b/tcl/cpld/xilinx-xcu.cfg @@ -0,0 +1,72 @@ +# Xilinx Ultrascale (Kintex, Virtex, Zynq) +# https://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xcu +} + +# The cvarious chips in the Ultrascale family have different IR length. +# Set $CHIP before including this file to determine the device. +array set _XCU_DATA { + XCKU025 {0x03824093 6} + XCKU035 {0x03823093 6} + XCKU040 {0x03822093 6} + XCKU060 {0x03919093 6} + XCKU095 {0x03844093 6} + XCKU3P {0x04A63093 6} + XCKU5P {0x04A62093 6} + XCKU9P {0x0484A093 6} + XCKU11P {0x04A4E093 6} + XCKU13P {0x04A52093 6} + XCKU15P {0x04A56093 6} + XCVU065 {0x03939093 6} + XCVU080 {0x03843093 6} + XCVU095 {0x03842093 6} + XCVU3P {0x04B39093 6} + XCKU085 {0x0380F093 12} + XCKU115 {0x0390D093 12} + XCVU125 {0x0392D093 12} + XCVU5P {0x04B2B093 12} + XCVU7P {0x04B29093 12} + XCVU160 {0x03933093 18} + XCVU190 {0x03931093 18} + XCVU440 {0x0396D093 18} + XCVU9P {0x04B31093 18} + XCVU11P {0x04B49093 18} + XCVU13P {0x04B51093 24} +} + +if { ![info exists CHIP] } { + error "set CHIP to one of "[concat [array names _XCU_DATA]] +} + +if { ![llength [array names _XCU_DATA $CHIP]] } { + error "unknown CHIP: "$CHIP +} + +set _EXPID [lindex $_XCU_DATA($CHIP) 0] +set _IRLEN [lindex $_XCU_DATA($CHIP) 1] + +# the 4 top bits (28:31) are the die stepping/revisions. ignore it. +jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID + +pld device virtex2 $_CHIPNAME.tap 1 + +set XCU_JSHUTDOWN 0x0d +set XCU_JPROGRAM 0x0b +set XCU_JSTART 0x0c +set XCU_BYPASS 0x3f + +proc xcu_program {tap} { + global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS + irscan $tap $XCU_JSHUTDOWN + irscan $tap $XCU_JPROGRAM + runtest 60000 + #JSTART prevents this from working... + #irscan $tap $XCU_JSTART + runtest 2000 + irscan $tap $XCU_BYPASS + runtest 2000 +} From ca3228dda610227fa7aee9efc33d2971841eb4c2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 3 Aug 2017 22:55:59 +0200 Subject: [PATCH 78/91] kcu105: add support for Xilinx KCU105 * Development board with Kintex Ultrascale XCKU040 * Dual SPI 256 MBit flash, supported through xilinx_bscan_spi Change-Id: I478ec7481beedd270bfba8af56a93301b0ee3028 Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4189 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/kcu105.cfg | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tcl/board/kcu105.cfg diff --git a/tcl/board/kcu105.cfg b/tcl/board/kcu105.cfg new file mode 100644 index 000000000..c8daea652 --- /dev/null +++ b/tcl/board/kcu105.cfg @@ -0,0 +1,11 @@ +# xilinx ultrascale +# http://www.xilinx.com/support/documentation/user_guides/ug570-ultrascale-configuration.pdf + +source [find interface/ftdi/digilent_jtag_smt2_nc.cfg] + +set CHIP XCKU040 +source [find cpld/xilinx-xcu.cfg] + +source [find cpld/jtagspi.cfg] + +adapter_khz 25000 From 33f70625d7a9f6392fa7d549d696e5955543fa69 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 28 Sep 2017 14:40:47 +0200 Subject: [PATCH 79/91] sayma_amc: add Sayma AMC board definition Change-Id: I4a3dc5fe2d81b6906099af8cc1a360b3cf4a6b80 Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4237 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/sayma_amc.cfg | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tcl/board/sayma_amc.cfg diff --git a/tcl/board/sayma_amc.cfg b/tcl/board/sayma_amc.cfg new file mode 100644 index 000000000..5d338ed8a --- /dev/null +++ b/tcl/board/sayma_amc.cfg @@ -0,0 +1,45 @@ +# Sayma AMC is an FPGA board for the µTCA AMC format +# The board is open hardware (CERN OHL) and the gateware and software +# running on it are open source (ARTIQ, LGPLv3+). +# +# https://github.com/m-labs/sinara/wiki/Sayma +# +# It contains a Xilinx Kintex Ultrascale 040 FPGA (xcku040). +# There is a SCANSTA112SM JTAG router on the board which is configured to +# automatically add devices to the JTAG svcan chain when they are added. +# Sayma AMC is usually combined with Sayma RTM (rear transition module) +# which features an Artix 7 FPGA. + +interface ftdi +ftdi_device_desc "Quad RS232-HS" +ftdi_vid_pid 0x0403 0x6011 +ftdi_channel 0 +# Use this to distinguish multiple boards by topology +#ftdi_location 5:1 +# sampling on falling edge generally seems to work and accelerates things but +# is not fully tested +#ftdi_tdo_sample_edge falling +# EN_USB_JTAG on ADBUS7: out, high +# USB_nTRST on ADBUS4: out, high, but R46 is DNP +ftdi_layout_init 0x0098 0x008b +#ftdi_layout_signal EN_USB -data 0x0080 +#ftdi_layout_signal nTRST -data 0x0010 +reset_config none + +adapter_khz 5000 + +transport select jtag + +# Add the RTM Artix to the chain. Note that this changes the PLD numbering. +# Unfortunately openocd TAPs can't be disabled after they have been added and +# before `init`. +#source [find cpld/xilinx-xc7.cfg] + +set CHIP XCKU040 +source [find cpld/xilinx-xcu.cfg] + +set XILINX_USER1 0x02 +set XILINX_USER2 0x03 +set JTAGSPI_IR $XILINX_USER1 +source [find cpld/jtagspi.cfg] +flash bank xcu.spi1 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER2 From 38607b2e560fc4d9a24e594fc0bdd66d574faea9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 10:53:48 +0000 Subject: [PATCH 80/91] tcl/board: add support for Kasli Kasli is an open hardware FPGA board. It is part of the Sinara family of devices designed to control quantum physics experiments (see Sayma_AMC for other boards already suppported by openocd). Kasli was developed as part of the opticlock project. It features a Xilinx Artix 7 100T FPGA, DDR3 RAM, a clock reconstruction and distribution network, four 6 Gb/s transceiver links (three SFP and one SATA) as well as interfaces to up to 12 Eurocard Extension Modules (EEMs). https://github.com/m-labs/sinara/wiki/Kasli http://www.opticlock.de/en/ Change-Id: I88b5e9f16b79e1e731056c45da6b5e1448d2c0e7 Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4341 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/kasli.cfg | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tcl/board/kasli.cfg diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg new file mode 100644 index 000000000..caa294f82 --- /dev/null +++ b/tcl/board/kasli.cfg @@ -0,0 +1,13 @@ +interface ftdi +ftdi_device_desc "Quad RS232-HS" +ftdi_vid_pid 0x0403 0x6011 +ftdi_channel 0 +ftdi_layout_init 0x0008 0x000b +# ftdi_location 1:8 + +reset_config none +transport select jtag +adapter_khz 25000 + +source [find cpld/xilinx-xc7.cfg] +source [find cpld/jtagspi.cfg] From f035b0851bbc6a9ccc2b20128ae2e4d3abd9ba38 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 02:29:56 +0100 Subject: [PATCH 81/91] flash/nor: implement flash bank deallocation on OpenOCD exit Change-Id: I8fcf09b2a85b3b68743f5fd68a31edea933b9b17 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4414 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/flash/nor/core.c | 25 +++++++++++++++++++++++++ src/flash/nor/core.h | 9 ++++++++- src/flash/nor/driver.h | 8 ++++++++ src/openocd.c | 1 + 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 6eb7052ef..636d50c51 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -171,6 +171,31 @@ int flash_get_bank_count(void) return i; } +void default_flash_free_driver_priv(struct flash_bank *bank) +{ + free(bank->driver_priv); + bank->driver_priv = NULL; +} + +void flash_free_all_banks(void) +{ + struct flash_bank *bank = flash_banks; + while (bank) { + struct flash_bank *next = bank->next; + if (bank->driver->free_driver_priv) + bank->driver->free_driver_priv(bank); + else + LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name); + + free(bank->name); + free(bank->sectors); + free(bank->prot_blocks); + free(bank); + bank = next; + } + flash_banks = NULL; +} + struct flash_bank *get_flash_bank_by_name_noprobe(const char *name) { unsigned requested = get_flash_name_index(name); diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 338363e2a..1bfe1ab97 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -76,7 +76,7 @@ struct flash_sector { * per-bank basis, if required. */ struct flash_bank { - const char *name; + char *name; struct target *target; /**< Target to which this bank belongs. */ @@ -153,8 +153,15 @@ int flash_write(struct target *target, * This routine must be called when the system may modify the status. */ void flash_set_dirty(void); + /** @returns The number of flash banks currently defined. */ int flash_get_bank_count(void); + +/** Deallocates bank->driver_priv */ +void default_flash_free_driver_priv(struct flash_bank *bank); + +/** Deallocates all flash banks */ +void flash_free_all_banks(void); /** * Provides default read implementation for flash memory. * @param bank The bank to read. diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 0ae4d8e20..e7b323443 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -209,6 +209,14 @@ struct flash_driver { * @returns ERROR_OK if successful; otherwise, an error code. */ int (*auto_probe)(struct flash_bank *bank); + + /** + * Deallocates private driver structures. + * Use default_flash_free_driver_priv() to simply free(bank->driver_priv) + * + * @param bank - the bank being destroyed + */ + void (*free_driver_priv)(struct flash_bank *bank); }; #define FLASH_BANK_COMMAND_HANDLER(name) \ diff --git a/src/openocd.c b/src/openocd.c index bd52f4acf..1874530cb 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -353,6 +353,7 @@ int openocd_main(int argc, char *argv[]) /* Start the executable meat that can evolve into thread in future. */ ret = openocd_thread(argc, argv, cmd_ctx); + flash_free_all_banks(); gdb_service_free(); server_free(); From 37deb37593c20c05a4bb29e1d88671a1f7ec6548 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 22 Mar 2018 11:53:40 +0100 Subject: [PATCH 82/91] target: fix display halt message logic If a target is run from gdb and then stopped from OpenOCD telnet interface, halt does not show message with status and PC registers. While on it rename 'display' to 'verbose_halt_msg' and use bool type instead of int. Change-Id: Ibe6589015b302e0be97258b06938c297745436a5 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4475 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/openocd.c | 6 +++--- src/target/target.c | 5 ++++- src/target/target.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/openocd.c b/src/openocd.c index 1874530cb..d5d7ebe87 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -87,13 +87,13 @@ static int log_target_callback_event_handler(struct target *target, { switch (event) { case TARGET_EVENT_GDB_START: - target->display = 0; + target->verbose_halt_msg = false; break; case TARGET_EVENT_GDB_END: - target->display = 1; + target->verbose_halt_msg = true; break; case TARGET_EVENT_HALTED: - if (target->display) { + if (target->verbose_halt_msg) { /* do not display information when debugger caused the halt */ target_arch_state(target); } diff --git a/src/target/target.c b/src/target/target.c index 4552034ec..10426023a 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -2959,6 +2959,9 @@ COMMAND_HANDLER(handle_halt_command) LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); + + target->verbose_halt_msg = true; + int retval = target_halt(target); if (ERROR_OK != retval) return retval; @@ -5579,7 +5582,7 @@ static int target_create(Jim_GetOptInfo *goi) target->next = NULL; target->arch_info = NULL; - target->display = 1; + target->verbose_halt_msg = true; target->halt_issued = false; diff --git a/src/target/target.h b/src/target/target.h index 0ce4a137a..7a8a80f30 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -176,7 +176,7 @@ struct target { void *private_config; /* pointer to target specific config data (for jim_configure hook) */ struct target *next; /* next target in list */ - int display; /* display async info in telnet session. Do not display + bool verbose_halt_msg; /* display async info in telnet session. Do not display * lots of halted/resumed info when stepping in debugger. */ bool halt_issued; /* did we transition to halted state? */ int64_t halt_issued_time; /* Note time when halt was issued */ From 6eba3777fca4a3e8c0d91dce9caedfeb9c08dc67 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 22 Mar 2018 00:20:15 +0100 Subject: [PATCH 83/91] jtag/core, target: unregister JTAG events Also call adapter_exit() before command_exit() as the latter releases Jim interpreter so JTAG events should be released before. Fixes memory leak reported by valgrind Change-Id: I493f3fcba34ea2b4234148e79a4e329c866e0f05 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4474 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- src/jtag/core.c | 8 ++++++++ src/openocd.c | 4 ++-- src/target/target.c | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index 0fbd327fe..4522321a7 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1308,6 +1308,14 @@ void jtag_tap_free(struct jtag_tap *tap) { jtag_unregister_event_callback(&jtag_reset_callback, tap); + struct jtag_tap_event_action *jteap = tap->event_action; + while (jteap) { + struct jtag_tap_event_action *next = jteap->next; + Jim_DecrRefCount(jteap->interp, jteap->body); + free(jteap); + jteap = next; + } + free(tap->expected); free(tap->expected_mask); free(tap->expected_ids); diff --git a/src/openocd.c b/src/openocd.c index d5d7ebe87..902528d08 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -359,11 +359,11 @@ int openocd_main(int argc, char *argv[]) unregister_all_commands(cmd_ctx, NULL); + adapter_quit(); + /* Shutdown commandline interface */ command_exit(cmd_ctx); - adapter_quit(); - free_config(); if (ERROR_FAIL == ret) diff --git a/src/target/target.c b/src/target/target.c index 10426023a..ac2e1d030 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1893,6 +1893,8 @@ static void target_destroy(struct target *target) if (target->type->deinit_target) target->type->deinit_target(target); + jtag_unregister_event_callback(jtag_enable_callback, target); + struct target_event_action *teap = target->event_action; while (teap) { struct target_event_action *next = teap->next; From 27473588a40604822dcbee1c1950d27fdf248fe9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 29 Jan 2018 21:12:37 +0100 Subject: [PATCH 84/91] tcl/fpga/xilinx-xadc.cfg: add support for XADC The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die temperature, internal power supply rail voltages as well as external voltages. The XADC is available both from fabric as well as through the JTAG TAP. This code implements access throught the JTAG TAP. https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf Change-Id: I6cef4d0244add71749fa28b58a736302151cc4dd Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4395 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/kasli.cfg | 1 + tcl/board/kc705.cfg | 1 + tcl/fpga/xilinx-xadc.cfg | 159 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 tcl/fpga/xilinx-xadc.cfg diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg index caa294f82..4d96a8f7c 100644 --- a/tcl/board/kasli.cfg +++ b/tcl/board/kasli.cfg @@ -11,3 +11,4 @@ adapter_khz 25000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] +source [find fpga/xilinx-xadc.cfg] diff --git a/tcl/board/kc705.cfg b/tcl/board/kc705.cfg index 39f7fa39c..d6b835a5f 100644 --- a/tcl/board/kc705.cfg +++ b/tcl/board/kc705.cfg @@ -3,6 +3,7 @@ source [find interface/ftdi/digilent-hs1.cfg] source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] +source [find fpga/xilinx-xadc.cfg] adapter_khz 25000 # example command to write bitstream, soft-cpu bios and runtime: diff --git a/tcl/fpga/xilinx-xadc.cfg b/tcl/fpga/xilinx-xadc.cfg new file mode 100644 index 000000000..38691045c --- /dev/null +++ b/tcl/fpga/xilinx-xadc.cfg @@ -0,0 +1,159 @@ +# Xilinx XADC support for 7 Series FPGAs +# +# The 7 Series FPGAs contain an on-chip 12 bit ADC that can probe die +# temperature, internal power supply rail voltages as well as external +# voltages. The XADC is available both from fabric as well as through the +# JTAG TAP. +# +# This code implements access throught the JTAG TAP. +# +# https://www.xilinx.com/support/documentation/user_guides/ug480_7Series_XADC.pdf + +# build a 32 bit DRP command for the XADC DR +proc xadc_cmd {cmd addr data} { + array set cmds { + NOP 0x00 + READ 0x01 + WRITE 0x02 + } + return [expr ($cmds($cmd) << 26) | ($addr << 16) | ($data << 0)] +} + +# XADC register addresses +# Some addresses (status registers 0-3) have special function when written to. +proc XADC {key} { + array set addrs { + TEMP 0x00 + LOCK 0x00 + VCCINT 0x01 + VCCAUX 0x02 + VAUXEN 0x02 + VPVN 0x03 + RESET 0x03 + VREFP 0x04 + VREFN 0x05 + VCCBRAM 0x06 + SUPAOFFS 0x08 + ADCAOFFS 0x09 + ADCAGAIN 0x0a + VCCPINT 0x0d + VCCPAUX 0x0e + VCCODDR 0x0f + VAUX0 0x10 + VAUX1 0x11 + VAUX2 0x12 + VAUX3 0x13 + VAUX4 0x14 + VAUX5 0x15 + VAUX6 0x16 + VAUX7 0x17 + VAUX8 0x18 + VAUX9 0x19 + VAUX10 0x1a + VAUX11 0x1b + VAUX12 0x1c + VAUX13 0x1d + VAUX14 0x1e + VAUX15 0x1f + SUPBOFFS 0x30 + ADCBOFFS 0x31 + ADCBGAIN 0x32 + FLAG 0x3f + CFG0 0x40 + CFG1 0x41 + CFG2 0x42 + SEQ0 0x48 + SEQ1 0x49 + SEQ2 0x4a + SEQ3 0x4b + SEQ4 0x4c + SEQ5 0x4d + SEQ6 0x4e + SEQ7 0x4f + ALARM0 0x50 + ALARM1 0x51 + ALARM2 0x52 + ALARM3 0x53 + ALARM4 0x54 + ALARM5 0x55 + ALARM6 0x56 + ALARM7 0x57 + ALARM8 0x58 + ALARM9 0x59 + ALARM10 0x5a + ALARM11 0x5b + ALARM12 0x5c + ALARM13 0x5d + ALARM14 0x5e + ALARM15 0x5f + } + return $addrs($key) +} + +# Select the XADC DR +proc xadc_select {tap} { + set XADC_IR 0x37 + irscan $tap $XADC_IR + runtest 10 +} + +# XADC transfer +proc xadc_xfer {tap cmd addr data} { + set ret [drscan $tap 32 [xadc_cmd $cmd $addr $data]] + runtest 10 + return [expr 0x$ret] +} + +# XADC register write +proc xadc_write {tap addr data} { + xadc_xfer $tap WRITE $addr $data +} + +# XADC register read, non-pipelined +proc xadc_read {tap addr} { + xadc_xfer $tap READ $addr 0 + return [xadc_xfer $tap NOP 0 0] +} + +# convert 16 bit register code from ADC measurement on +# external voltages (VAUX) to Volt +proc xadc_volt {code} { + return [expr $code * 1./(1 << 16)] +} + +# convert 16 bit temperature measurement to Celsius +proc xadc_temp {code} { + return [expr $code * 503.975/(1 << 16) - 273.15] +} + +# convert 16 bit suppply voltage measurement to Volt +proc xadc_sup {code} { + return [expr $code * 3./(1 << 16)] +} + +# perform a single channel measurement using default settings +proc xadc_single {tap ch} { + set cfg0 [xadc_read $tap [XADC CFG0]] + set cfg1 [xadc_read $tap [XADC CFG1]] + # set channel + xadc_write $tap [XADC CFG0] $cfg0 + # single channel, disable the sequencer + xadc_write $tap [XADC CFG1] 0x3000 + # leave some time for the conversion + runtest 100 + set ret [xadc_read $tap [XADC $ch]] + # restore CFG0/1 + xadc_write $tap [XADC CFG0] $cfg0 + xadc_write $tap [XADC CFG1] $cfg1 + return $ret +} + +# measure all internal voltages +proc xadc_report {tap} { + xadc_select $tap + echo "TEMP [format %.2f [xadc_temp [xadc_single $tap TEMP]]] C" + foreach ch [list VCCINT VCCAUX VCCBRAM VPVN VREFP VREFN \ + VCCPINT VCCPAUX VCCODDR] { + echo "$ch [format %.3f [xadc_sup [xadc_single $tap $ch]]] V" + } +} From 3d3b45af465f6dcfc85ea69cc10a719bc3b2851c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 5 Feb 2018 11:54:29 +0000 Subject: [PATCH 85/91] xilinx-dna.cfg: generic tools for reading Xilinx Device DNA Most Xilinx FPGA devices contain an embedded, unique device identifier. The identifier is nonvolatile, permanently programmed into the FPGA, and is unchangeable providing a great serial / tracking number. This commit adds generic support for reading the Xilinx Spartan 6 and 7 Series (Kintex, Artix, Ultrascale) Device DNA. The code is similar to the function in fpga/xilinx-xc6s.cfg for Spartan 6 but the register addresses are different and the logic has been simplified. The code was not placed in xilinx-xc7.cfg. The approach of defining taps in the same file as library code to use them is fundamentally broken on boards that have more than one FPGA or other chips. This commit (like the addition of support for Xilinx XADC) starts to remedy that by splitting library code from board-specific fixed definitions. The support code is sourced in the Kasli and KC705 board support files as it was tested on these boards. Change-Id: Iba559c7c1b7e93e1270535fd9e6650007f3794da Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4396 Tested-by: jenkins Reviewed-by: Matthias Welwarsky --- tcl/board/kasli.cfg | 1 + tcl/board/kc705.cfg | 1 + tcl/fpga/xilinx-dna.cfg | 43 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 tcl/fpga/xilinx-dna.cfg diff --git a/tcl/board/kasli.cfg b/tcl/board/kasli.cfg index 4d96a8f7c..2c5e26853 100644 --- a/tcl/board/kasli.cfg +++ b/tcl/board/kasli.cfg @@ -12,3 +12,4 @@ adapter_khz 25000 source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] source [find fpga/xilinx-xadc.cfg] +source [find fpga/xilinx-dna.cfg] diff --git a/tcl/board/kc705.cfg b/tcl/board/kc705.cfg index d6b835a5f..e032e9b21 100644 --- a/tcl/board/kc705.cfg +++ b/tcl/board/kc705.cfg @@ -4,6 +4,7 @@ source [find interface/ftdi/digilent-hs1.cfg] source [find cpld/xilinx-xc7.cfg] source [find cpld/jtagspi.cfg] source [find fpga/xilinx-xadc.cfg] +source [find fpga/xilinx-dna.cfg] adapter_khz 25000 # example command to write bitstream, soft-cpu bios and runtime: diff --git a/tcl/fpga/xilinx-dna.cfg b/tcl/fpga/xilinx-dna.cfg new file mode 100644 index 000000000..a1d5ba376 --- /dev/null +++ b/tcl/fpga/xilinx-dna.cfg @@ -0,0 +1,43 @@ +proc xilinx_dna_addr {chip} { + array set addrs { + Spartan6 0x30 + Series7 0x17 + } + return $addrs($chip) +} + +# Get the "Device DNA". +# Most Xilinx FPGA devices contain an embedded, unique device identifier. +# The identifier is nonvolatile, permanently programmed into +# the FPGA, and is unchangeable providing a great serial / tracking number. +# This function returns the DNA as a 64 bit integer with the 7 LSBs zeroed. +# This is compatible with the FUSE DNA which contains all 64 bits. +proc xilinx_get_dna {tap chip} { + set XC7_ISC_ENABLE 0x10 + set XC7_ISC_DISABLE 0x16 + set XC7_ISC_DNA [xilinx_dna_addr $chip] + + irscan $tap $XC7_ISC_ENABLE + runtest 64 + irscan $tap $XC7_ISC_DNA + scan [drscan $tap 32 0 32 0] "%08x %08x" hi lo + runtest 64 + irscan $tap $XC7_ISC_DISABLE + runtest 64 + # openocd interprets DR scans as LSB first, bit-reverse it + return [scan [string reverse [format "%032b%032bb0" $lo $hi]] "%i"] +} + +# Print out the "Device DNA" in the same format that impact uses. +proc xilinx_print_dna {dna} { + set dna [expr $dna >> 64 - 57] + echo [format "DNA = %057b (0x%016x)" $dna $dna] +} + +proc xc7_get_dna {tap} { + return [xilinx_get_dna $tap Series7] +} + +proc xc6s_get_dna {tap} { + return [xilinx_get_dna $tap Spartan6] +} From 7690a74b094347ec393c280414a182b7361d7b17 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 15 Feb 2018 10:25:50 +0100 Subject: [PATCH 86/91] flash/nor: implement flash bank deallocation in drivers with simple alloc All drivers which simply allocate one driver_priv memory block per each bank now use default_flash_free_driver_priv() Change-Id: I425bf4213c3632f02dbe11ab819c31eda9b2db62 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4417 Tested-by: jenkins Reviewed-by: Liviu Dudau Reviewed-by: Matthias Welwarsky --- src/flash/nor/ambiqmicro.c | 1 + src/flash/nor/ath79.c | 1 + src/flash/nor/atsamv.c | 1 + src/flash/nor/avrf.c | 1 + src/flash/nor/cfi.c | 1 + src/flash/nor/efm32.c | 1 + src/flash/nor/em357.c | 1 + src/flash/nor/faux.c | 3 ++- src/flash/nor/fm3.c | 1 + src/flash/nor/fm4.c | 1 + src/flash/nor/jtagspi.c | 3 ++- src/flash/nor/kinetis_ke.c | 1 + src/flash/nor/lpc2000.c | 1 + src/flash/nor/lpc288x.c | 1 + src/flash/nor/lpc2900.c | 1 + src/flash/nor/lpcspifi.c | 1 + src/flash/nor/mdr.c | 1 + src/flash/nor/mrvlqspi.c | 1 + src/flash/nor/niietcm4.c | 1 + src/flash/nor/numicro.c | 1 + src/flash/nor/ocl.c | 1 + src/flash/nor/pic32mx.c | 1 + src/flash/nor/psoc4.c | 1 + src/flash/nor/psoc6.c | 1 + src/flash/nor/sim3x.c | 3 ++- src/flash/nor/stellaris.c | 1 + src/flash/nor/stm32f1x.c | 1 + src/flash/nor/stm32f2x.c | 1 + src/flash/nor/stm32h7x.c | 1 + src/flash/nor/stm32l4x.c | 1 + src/flash/nor/stm32lx.c | 1 + src/flash/nor/stmsmi.c | 1 + src/flash/nor/str7x.c | 1 + src/flash/nor/str9x.c | 1 + src/flash/nor/str9xpec.c | 1 + src/flash/nor/tms470.c | 1 + src/flash/nor/virtual.c | 1 + src/flash/nor/xcf.c | 4 +++- src/flash/nor/xmc1xxx.c | 1 + src/flash/nor/xmc4xxx.c | 1 + 40 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index b2c30e6f4..13b2b26ae 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -901,4 +901,5 @@ struct flash_driver ambiqmicro_flash = { .erase_check = default_flash_blank_check, .protect_check = ambiqmicro_protect_check, .info = get_ambiqmicro_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/ath79.c b/src/flash/nor/ath79.c index 451e84365..c5f9eed52 100644 --- a/src/flash/nor/ath79.c +++ b/src/flash/nor/ath79.c @@ -898,4 +898,5 @@ struct flash_driver ath79_flash = { .erase_check = ath79_flash_blank_check, .protect_check = ath79_protect_check, .info = get_ath79_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index 73f023896..9c07bdf15 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -739,4 +739,5 @@ struct flash_driver atsamv_flash = { .erase_check = default_flash_blank_check, .protect_check = samv_protect_check, .info = samv_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 11cc3b2d3..65ac6015f 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -487,4 +487,5 @@ struct flash_driver avr_flash = { .erase_check = default_flash_blank_check, .protect_check = avrf_protect_check, .info = avrf_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index ac0db8271..0ae72d4a2 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -3128,4 +3128,5 @@ struct flash_driver cfi_flash = { .erase_check = default_flash_blank_check, .protect_check = cfi_protect_check, .info = get_cfi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 282b6bddd..1d70bd501 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -1133,4 +1133,5 @@ struct flash_driver efm32_flash = { .erase_check = default_flash_blank_check, .protect_check = efm32x_protect_check, .info = get_efm32x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index a11743b55..b14e0323c 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -941,4 +941,5 @@ struct flash_driver em357_flash = { .auto_probe = em357_auto_probe, .erase_check = default_flash_blank_check, .protect_check = em357_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/faux.c b/src/flash/nor/faux.c index 203eb6fff..46eda7223 100644 --- a/src/flash/nor/faux.c +++ b/src/flash/nor/faux.c @@ -136,5 +136,6 @@ struct flash_driver faux_flash = { .auto_probe = faux_probe, .erase_check = default_flash_blank_check, .protect_check = faux_protect_check, - .info = faux_info + .info = faux_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/fm3.c b/src/flash/nor/fm3.c index 6269a6536..6c619775a 100644 --- a/src/flash/nor/fm3.c +++ b/src/flash/nor/fm3.c @@ -997,4 +997,5 @@ struct flash_driver fm3_flash = { .probe = fm3_probe, .auto_probe = fm3_auto_probe, .erase_check = default_flash_blank_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c index c8fe8b66f..f5eab9c5b 100644 --- a/src/flash/nor/fm4.c +++ b/src/flash/nor/fm4.c @@ -719,4 +719,5 @@ struct flash_driver fm4_flash = { .erase = fm4_flash_erase, .erase_check = default_flash_blank_check, .write = fm4_flash_write, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index a73812d88..c28ad22f7 100644 --- a/src/flash/nor/jtagspi.c +++ b/src/flash/nor/jtagspi.c @@ -432,5 +432,6 @@ struct flash_driver jtagspi_flash = { .auto_probe = jtagspi_probe, .erase_check = default_flash_blank_check, .protect_check = jtagspi_protect_check, - .info = jtagspi_info + .info = jtagspi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index b7a6a1ece..8103b6394 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -1310,4 +1310,5 @@ struct flash_driver kinetis_ke_flash = { .erase_check = kinetis_ke_blank_check, .protect_check = kinetis_ke_protect_check, .info = kinetis_ke_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 9da5da2ca..8e15c3122 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -1579,4 +1579,5 @@ struct flash_driver lpc2000_flash = { .erase_check = lpc2000_erase_check, .protect_check = lpc2000_protect_check, .info = get_lpc2000_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpc288x.c b/src/flash/nor/lpc288x.c index a4d88de78..24729138a 100644 --- a/src/flash/nor/lpc288x.c +++ b/src/flash/nor/lpc288x.c @@ -433,4 +433,5 @@ struct flash_driver lpc288x_flash = { .auto_probe = lpc288x_probe, .erase_check = lpc288x_erase_check, .protect_check = lpc288x_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpc2900.c b/src/flash/nor/lpc2900.c index 515a3f7b2..1c65933e2 100644 --- a/src/flash/nor/lpc2900.c +++ b/src/flash/nor/lpc2900.c @@ -1598,4 +1598,5 @@ struct flash_driver lpc2900_flash = { .auto_probe = lpc2900_probe, .erase_check = lpc2900_erase_check, .protect_check = lpc2900_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/lpcspifi.c b/src/flash/nor/lpcspifi.c index 943c151e2..828c60ca6 100644 --- a/src/flash/nor/lpcspifi.c +++ b/src/flash/nor/lpcspifi.c @@ -942,4 +942,5 @@ struct flash_driver lpcspifi_flash = { .erase_check = default_flash_blank_check, .protect_check = lpcspifi_protect_check, .info = get_lpcspifi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/mdr.c b/src/flash/nor/mdr.c index 8ceb1bf46..f3916ded9 100644 --- a/src/flash/nor/mdr.c +++ b/src/flash/nor/mdr.c @@ -633,4 +633,5 @@ struct flash_driver mdr_flash = { .erase_check = default_flash_blank_check, .protect_check = mdr_protect_check, .info = get_mdr_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c index d79917058..eda6cc1ad 100644 --- a/src/flash/nor/mrvlqspi.c +++ b/src/flash/nor/mrvlqspi.c @@ -955,4 +955,5 @@ struct flash_driver mrvlqspi_flash = { .erase_check = mrvlqspi_flash_erase_check, .protect_check = mrvlqspi_protect_check, .info = mrvlqspi_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/niietcm4.c b/src/flash/nor/niietcm4.c index 4a849fd26..fd7d519a8 100644 --- a/src/flash/nor/niietcm4.c +++ b/src/flash/nor/niietcm4.c @@ -1741,4 +1741,5 @@ struct flash_driver niietcm4_flash = { .erase_check = default_flash_blank_check, .protect_check = niietcm4_protect_check, .info = get_niietcm4_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index 992baa515..4d951f0ee 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -1880,4 +1880,5 @@ struct flash_driver numicro_flash = { .auto_probe = numicro_auto_probe, .erase_check = default_flash_blank_check, .protect_check = numicro_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c index 4ae565219..895c4af21 100644 --- a/src/flash/nor/ocl.c +++ b/src/flash/nor/ocl.c @@ -340,4 +340,5 @@ struct flash_driver ocl_flash = { .erase_check = ocl_erase_check, .protect_check = ocl_protect_check, .auto_probe = ocl_auto_probe, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c index 1f148fd73..e3b802870 100644 --- a/src/flash/nor/pic32mx.c +++ b/src/flash/nor/pic32mx.c @@ -980,4 +980,5 @@ struct flash_driver pic32mx_flash = { .erase_check = default_flash_blank_check, .protect_check = pic32mx_protect_check, .info = pic32mx_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index a0240091d..47d60dee4 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -963,4 +963,5 @@ struct flash_driver psoc4_flash = { .erase_check = default_flash_blank_check, .protect_check = psoc4_protect_check, .info = get_psoc4_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 259d6679d..e5c419764 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -982,4 +982,5 @@ struct flash_driver psoc6_flash = { .erase_check = default_flash_blank_check, .protect_check = psoc6_protect_check, .info = psoc6_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index ce9a21ed5..f282ba089 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -1122,5 +1122,6 @@ struct flash_driver sim3x_flash = { .auto_probe = sim3x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sim3x_flash_protect_check, - .info = sim3x_flash_info + .info = sim3x_flash_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index d28ceee4b..79aaf3ba2 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -1452,4 +1452,5 @@ struct flash_driver stellaris_flash = { .erase_check = default_flash_blank_check, .protect_check = stellaris_protect_check, .info = get_stellaris_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index d44670768..64c91680c 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -1647,4 +1647,5 @@ struct flash_driver stm32f1x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index b0992b404..8bca62ea2 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1634,4 +1634,5 @@ struct flash_driver stm32f2x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 01e6f06dc..a15cd2531 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -1180,4 +1180,5 @@ struct flash_driver stm32h7x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = stm32x_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 6a1fa074e..e2710bd81 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -953,4 +953,5 @@ struct flash_driver stm32l4x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32l4_protect_check, .info = get_stm32l4_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index fdfaad4cf..f4dd686aa 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -965,6 +965,7 @@ struct flash_driver stm32lx_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32lx_protect_check, .info = stm32lx_get_info, + .free_driver_priv = default_flash_free_driver_priv, }; /* Static methods implementation */ diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index 781ea3b5b..c839bf74c 100644 --- a/src/flash/nor/stmsmi.c +++ b/src/flash/nor/stmsmi.c @@ -654,4 +654,5 @@ struct flash_driver stmsmi_flash = { .erase_check = default_flash_blank_check, .protect_check = stmsmi_protect_check, .info = get_stmsmi_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/str7x.c b/src/flash/nor/str7x.c index 11179f520..015202a0e 100644 --- a/src/flash/nor/str7x.c +++ b/src/flash/nor/str7x.c @@ -812,4 +812,5 @@ struct flash_driver str7x_flash = { .erase_check = default_flash_blank_check, .protect_check = str7x_protect_check, .info = get_str7x_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/str9x.c b/src/flash/nor/str9x.c index 3b7ca2aa7..37700ce36 100644 --- a/src/flash/nor/str9x.c +++ b/src/flash/nor/str9x.c @@ -679,4 +679,5 @@ struct flash_driver str9x_flash = { .auto_probe = str9x_probe, .erase_check = default_flash_blank_check, .protect_check = str9x_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index eb391e8fb..29e0977bb 100644 --- a/src/flash/nor/str9xpec.c +++ b/src/flash/nor/str9xpec.c @@ -1207,4 +1207,5 @@ struct flash_driver str9xpec_flash = { .auto_probe = str9xpec_probe, .erase_check = str9xpec_erase_check, .protect_check = str9xpec_protect_check, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index a70891e89..102bf1b15 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -1186,4 +1186,5 @@ struct flash_driver tms470_flash = { .erase_check = tms470_erase_check, .protect_check = tms470_protect_check, .info = get_tms470_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/virtual.c b/src/flash/nor/virtual.c index 06981f4f4..d5d688b36 100644 --- a/src/flash/nor/virtual.c +++ b/src/flash/nor/virtual.c @@ -231,4 +231,5 @@ struct flash_driver virtual_flash = { .erase_check = virtual_blank_check, .protect_check = virtual_protect_check, .info = virtual_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index 035791eb3..bc4b1be5e 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -636,6 +636,7 @@ static int xcf_probe(struct flash_bank *bank) fill_sector_table(bank); priv->probed = true; + /* REVISIT: Why is unchanged bank->driver_priv rewritten by same value? */ bank->driver_priv = priv; LOG_INFO("product name: %s", product_name(bank)); @@ -893,5 +894,6 @@ struct flash_driver xcf_flash = { .auto_probe = xcf_auto_probe, .erase_check = xcf_erase_check, .protect_check = xcf_protect_check, - .info = xcf_info + .info = xcf_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/xmc1xxx.c b/src/flash/nor/xmc1xxx.c index 0a76b216d..4b25398bc 100644 --- a/src/flash/nor/xmc1xxx.c +++ b/src/flash/nor/xmc1xxx.c @@ -546,4 +546,5 @@ struct flash_driver xmc1xxx_flash = { .erase = xmc1xxx_erase, .erase_check = xmc1xxx_erase_check, .write = xmc1xxx_write, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c index 5677ef0f1..0b6d48c1b 100644 --- a/src/flash/nor/xmc4xxx.c +++ b/src/flash/nor/xmc4xxx.c @@ -1356,4 +1356,5 @@ struct flash_driver xmc4xxx_flash = { .info = xmc4xxx_get_info_command, .protect_check = xmc4xxx_protect_check, .protect = xmc4xxx_protect, + .free_driver_priv = default_flash_free_driver_priv, }; From 6e6f90d1af601af0f6079f19f603a9a3a6e83da1 Mon Sep 17 00:00:00 2001 From: Michele Sardo Date: Thu, 22 Mar 2018 12:02:19 +0100 Subject: [PATCH 87/91] Fix for warnings detected by clang static analyzer Fix for potential memory leakage and for unused/unreported return error code Change-Id: Ifb2c95b60637c3a241ad4bf41d1a328c92ccea4b Signed-off-by: Michele Sardo Reviewed-on: http://openocd.zylin.com/4476 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/bluenrg-x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index c4a808047..2b568593a 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -274,6 +274,7 @@ static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, ui if (pre_bytes) { if (target_read_u32(target, pre_address, &pre_word)) { LOG_ERROR("Memory read failed"); + free(new_buffer); return ERROR_FAIL; } @@ -282,6 +283,7 @@ static int bluenrgx_write_bytes(struct target *target, uint32_t address_base, ui if (post_bytes) { if (target_read_u32(target, post_address, &post_word)) { LOG_ERROR("Memory read failed"); + free(new_buffer); return ERROR_FAIL; } @@ -450,6 +452,9 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); + if (retval != ERROR_OK) + return retval; + } /* Program chunk at end, not addressable by fast burst write algorithm */ From a28dea0fe429339e4f8d356fbff19cb17350c9ca Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Wed, 7 Mar 2018 11:31:35 -0500 Subject: [PATCH 88/91] target/cortex_m: avoid dwt comparator overflow Avoid ever overflowing the DWT_COMPARATOR array by allocating space for 16 comparators (the field is masked by 0xf). On a stm32f767zi chip (on a nucleo-767zi board) I've been seeing crashes with address sanitizer enabled due to its (apparent) 10 present comparators. This appears to be due to https://sourceforge.net/p/openocd/tickets/178/. In non-address sanitizer builds, this would likely cause some random memory to be written to in some cases. (see above bug for observations). Change-Id: I2b7d599eb326236dbc93f74b350c442c9a502c4b Signed-off-by: Cody P Schafer Reviewed-on: http://openocd.zylin.com/4458 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 14ebba318..a356350a2 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1854,6 +1854,18 @@ static struct dwt_reg dwt_comp[] = { DWT_COMPARATOR(1), DWT_COMPARATOR(2), DWT_COMPARATOR(3), + DWT_COMPARATOR(4), + DWT_COMPARATOR(5), + DWT_COMPARATOR(6), + DWT_COMPARATOR(7), + DWT_COMPARATOR(8), + DWT_COMPARATOR(9), + DWT_COMPARATOR(10), + DWT_COMPARATOR(11), + DWT_COMPARATOR(12), + DWT_COMPARATOR(13), + DWT_COMPARATOR(14), + DWT_COMPARATOR(15), #undef DWT_COMPARATOR }; @@ -1887,6 +1899,7 @@ void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) int reg, i; target_read_u32(target, DWT_CTRL, &dwtcr); + LOG_DEBUG("DWT_CTRL: 0x%" PRIx32, dwtcr); if (!dwtcr) { LOG_DEBUG("no DWT"); return; From 7829bb701f1d9b294c627142911529ca34a1120b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 21 Feb 2018 22:19:58 +0100 Subject: [PATCH 89/91] drivers/kitprog: workaround KitProg firmware bug of missing ZLP KitProg firmware does not send a zero length packet at the end of the bulk-in transmission of a length divisible by a bulk packet size. This is inconsistent with the USB specification and results in jtag_libusb_bulk_read() waits forever when a transmission of specific size is received. Limit bulk read size to expected number of bytes for problematic tranfer sizes. Use 1 second timeout as the last resort. Change-Id: Ice80306424afd76e9fbc6851911ffd5109c84501 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4426 Tested-by: jenkins Reviewed-by: Bohdan Tymkiv --- src/jtag/drivers/kitprog.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index db5b62e2e..522eb17bb 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -741,12 +741,22 @@ static int kitprog_swd_run_queue(void) break; } - /* We use the maximum buffer size here because the KitProg sometimes - * doesn't like bulk reads of fewer than 62 bytes. (?!?!) + /* KitProg firmware does not send a zero length packet + * after the bulk-in transmission of a length divisible by bulk packet + * size (64 bytes) as required by the USB specification. + * Therefore libusb would wait for continuation of transmission. + * Workaround: Limit bulk read size to expected number of bytes + * for problematic tranfer sizes. Otherwise use the maximum buffer + * size here because the KitProg sometimes doesn't like bulk reads + * of fewer than 62 bytes. (?!?!) */ + size_t read_count_workaround = SWD_MAX_BUFFER_LENGTH; + if (read_count % 64 == 0) + read_count_workaround = read_count; + ret = jtag_libusb_bulk_read(kitprog_handle->usb_handle, BULK_EP_IN | LIBUSB_ENDPOINT_IN, (char *)buffer, - SWD_MAX_BUFFER_LENGTH, 0); + read_count_workaround, 1000); if (ret > 0) { /* Handle garbage data by offsetting the initial read index */ if ((unsigned int)ret > read_count) From b08900badc3f51ac80b1b01de469e9fb7879f153 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 27 Feb 2018 17:51:49 +0100 Subject: [PATCH 90/91] nrf51: Add HWID 0x008F again HWID originally added in commit 7829f31a6dd61297e97d8e94fe98a1658eac833e was accidentally omited during refactoring in commit 52885d2b538dcd4184aae14cf2706fb97acccbd9 While on it move old ingeneering sample of 51822 to block of 51822 rev 1 Change-Id: Ie9f15563792a27a72e71df6edbcc6b04490370ed Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4437 Tested-by: jenkins --- src/flash/nor/nrf5.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 4fa62e30a..31dd5aae5 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -155,6 +155,11 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), + /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards + with built-in jlink seem to use engineering samples not listed + in the nRF51 Series Compatibility Matrix V1.0. */ + NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), + /* nRF51822 Devices (IC rev 2). */ NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), @@ -175,6 +180,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), + NRF5_DEVICE_DEF(0x008F, "51822", "QFAA", "H1", 256), /* nRF51422 Devices (IC rev 1). */ NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), @@ -198,11 +204,6 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF52832 Devices */ NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), - - /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards - with built-in jlink seem to use engineering samples not listed - in the nRF51 Series Compatibility Matrix V1.0. */ - NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), }; static int nrf5_bank_is_probed(struct flash_bank *bank) From be87994d60457ac846740dd9e5df3c8f63cf646e Mon Sep 17 00:00:00 2001 From: Stefan Arnold Date: Tue, 17 Oct 2017 10:50:13 +0200 Subject: [PATCH 91/91] flash/nor/at91samd: Add "nvmuserrow" command. Add option "nvmuserrow" to "at91samd" for changing and reading the register at 0x804000 which represents various fuses. Change-Id: I6382cc4ac15e6b9681e2f30b0ae60397a6289c3b Signed-off-by: Stefan Arnold Reviewed-on: http://openocd.zylin.com/4260 Tested-by: jenkins Reviewed-by: Tomas Vanek --- doc/openocd.texi | 20 +++ src/flash/nor/at91samd.c | 334 +++++++++++++++++++++++++++++---------- 2 files changed, 267 insertions(+), 87 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index f6795e15b..d0a3d49b8 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5319,6 +5319,26 @@ and prepares reset vector catch in case of reset halt. Command is used internally in event event reset-deassert-post. @end deffn +@deffn Command {at91samd nvmuserrow} +Writes or reads the entire 64 bit wide NVM user row register which is located at +0x804000. This register includes various fuses lock-bits and factory calibration +data. Reading the register is done by invoking this command without any +arguments. Writing is possible by giving 1 or 2 hex values. The first argument +is the register value to be written and the second one is an optional changemask. +Every bit which value in changemask is 0 will stay unchanged. The lock- and +reserved-bits are masked out and cannot be changed. + +@example +# Read user row +>at91samd nvmuserrow +NVMUSERROW: 0xFFFFFC5DD8E0C788 +# Write 0xFFFFFC5DD8E0C788 to user row +>at91samd nvmuserrow 0xFFFFFC5DD8E0C788 +# Write 0x12300 to user row but leave other bits and low byte unchanged +>at91samd nvmuserrow 0x12345 0xFFF00 +@end example +@end deffn + @end deffn @anchor{at91sam3} diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 449a283ca..64716d96f 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -83,6 +83,9 @@ #define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F)) #define SAMD_GET_DEVSEL(id) (id & 0xFF) +/* Bits to mask out lockbits in user row */ +#define NVMUSERROW_LOCKBIT_MASK ((uint64_t)0x0000FFFFFFFFFFFF) + struct samd_part { uint8_t id; const char *name; @@ -259,28 +262,38 @@ struct samd_family { uint8_t series; const struct samd_part *parts; size_t num_parts; + uint64_t nvm_userrow_res_mask; /* protect bits which are reserved, 0 -> protect */ }; /* Known SAMD families */ static const struct samd_family samd_families[] = { { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20, - samd20_parts, ARRAY_SIZE(samd20_parts) }, + samd20_parts, ARRAY_SIZE(samd20_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, - samd21_parts, ARRAY_SIZE(samd21_parts) }, + samd21_parts, ARRAY_SIZE(samd21_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09, - samd09_parts, ARRAY_SIZE(samd09_parts) }, + samd09_parts, ARRAY_SIZE(samd09_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10, - samd10_parts, ARRAY_SIZE(samd10_parts) }, + samd10_parts, ARRAY_SIZE(samd10_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11, - samd11_parts, ARRAY_SIZE(samd11_parts) }, + samd11_parts, ARRAY_SIZE(samd11_parts), + (uint64_t)0xFFFF01FFFE01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21, - saml21_parts, ARRAY_SIZE(saml21_parts) }, + saml21_parts, ARRAY_SIZE(saml21_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_22, - saml22_parts, ARRAY_SIZE(saml22_parts) }, + saml22_parts, ARRAY_SIZE(saml22_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20, - samc20_parts, ARRAY_SIZE(samc20_parts) }, + samc20_parts, ARRAY_SIZE(samc20_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21, - samc21_parts, ARRAY_SIZE(samc21_parts) }, + samc21_parts, ARRAY_SIZE(samc21_parts), + (uint64_t)0xFFFF03FFFC01FF77 }, }; struct samd_info { @@ -296,24 +309,42 @@ struct samd_info { static struct samd_info *samd_chips; - - -static const struct samd_part *samd_find_part(uint32_t id) +/** + * Gives the family structure to specific device id. + * @param id The id of the device. + * @return On failure NULL, otherwise a pointer to the structure. + */ +static const struct samd_family *samd_find_family(uint32_t id) { uint8_t processor = SAMD_GET_PROCESSOR(id); uint8_t family = SAMD_GET_FAMILY(id); uint8_t series = SAMD_GET_SERIES(id); - uint8_t devsel = SAMD_GET_DEVSEL(id); for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) { if (samd_families[i].processor == processor && samd_families[i].series == series && - samd_families[i].family == family) { - for (unsigned j = 0; j < samd_families[i].num_parts; j++) { - if (samd_families[i].parts[j].id == devsel) - return &samd_families[i].parts[j]; - } - } + samd_families[i].family == family) + return &samd_families[i]; + } + + return NULL; +} + +/** + * Gives the part structure to specific device id. + * @param id The id of the device. + * @return On failure NULL, otherwise a pointer to the structure. + */ +static const struct samd_part *samd_find_part(uint32_t id) +{ + uint8_t devsel = SAMD_GET_DEVSEL(id); + const struct samd_family *family = samd_find_family(id); + if (family == NULL) + return NULL; + + for (unsigned i = 0; i < family->num_parts; i++) { + if (family->parts[i].id == devsel) + return &family->parts[i]; } return NULL; @@ -484,6 +515,12 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd) return samd_check_error(target); } +/** + * Erases a flash-row at the given address. + * @param target Pointer to the target structure. + * @param address The address of the row. + * @return On success ERROR_OK, on failure an errorcode. + */ static int samd_erase_row(struct target *target, uint32_t address) { int res; @@ -505,49 +542,62 @@ static int samd_erase_row(struct target *target, uint32_t address) return ERROR_OK; } -static bool is_user_row_reserved_bit(uint8_t bit) +/** + * Returns the bitmask of reserved bits in register. + * @param target Pointer to the target structure. + * @param mask Bitmask, 0 -> value stays untouched. + * @return On success ERROR_OK, on failure an errorcode. + */ +static int samd_get_reservedmask(struct target *target, uint64_t *mask) { - /* See Table 9-3 in the SAMD20 datasheet for more information. */ - switch (bit) { - /* Reserved bits */ - case 3: - case 7: - /* Voltage regulator internal configuration with default value of 0x70, - * may not be changed. */ - case 17 ... 24: - /* 41 is voltage regulator internal configuration and must not be - * changed. 42 through 47 are reserved. */ - case 41 ... 47: - return true; - default: - break; + int res; + /* Get the devicetype */ + uint32_t id; + res = target_read_u32(target, SAMD_DSU + SAMD_DSU_DID, &id); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read Device ID register"); + return res; } - - return false; + const struct samd_family *family; + family = samd_find_family(id); + if (family == NULL) { + LOG_ERROR("Couldn't determine device family"); + return ERROR_FAIL; + } + *mask = family->nvm_userrow_res_mask; + return ERROR_OK; } -/* Modify the contents of the User Row in Flash. These are described in Table - * 9-3 of the SAMD20 datasheet. The User Row itself has a size of one page - * and contains a combination of "fuses" and calibration data in bits 24:17. - * We therefore try not to erase the row's contents unless we absolutely have - * to and we don't permit modifying reserved bits. */ -static int samd_modify_user_row(struct target *target, uint32_t value, - uint8_t startb, uint8_t endb) +static int read_userrow(struct target *target, uint64_t *userrow) +{ + int res; + uint8_t buffer[8]; + + res = target_read_memory(target, SAMD_USER_ROW, 4, 2, buffer); + if (res != ERROR_OK) + return res; + + *userrow = target_buffer_get_u64(target, buffer); + return ERROR_OK; +} + +/** + * Modify the contents of the User Row in Flash. The User Row itself + * has a size of one page and contains a combination of "fuses" and + * calibration data. Bits which have a value of zero in the mask will + * not be changed. Up to now devices only use the first 64 bits. + * @param target Pointer to the target structure. + * @param value_input The value to write. + * @param value_mask Bitmask, 0 -> value stays untouched. + * @return On success ERROR_OK, on failure an errorcode. + */ +static int samd_modify_user_row_masked(struct target *target, + uint64_t value_input, uint64_t value_mask) { int res; uint32_t nvm_ctrlb; bool manual_wp = true; - if (is_user_row_reserved_bit(startb) || is_user_row_reserved_bit(endb)) { - LOG_ERROR("Can't modify bits in the requested range"); - return ERROR_FAIL; - } - - /* Check if we need to do manual page write commands */ - res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb); - if (res == ERROR_OK) - manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0; - /* Retrieve the MCU's page size, in bytes. This is also the size of the * entire User Row. */ uint32_t page_size; @@ -557,44 +607,49 @@ static int samd_modify_user_row(struct target *target, uint32_t value, return res; } - /* Make sure the size is sane before we allocate. */ - assert(page_size > 0 && page_size <= SAMD_PAGE_SIZE_MAX); - - /* Make sure we're within the single page that comprises the User Row. */ - if (startb >= (page_size * 8) || endb >= (page_size * 8)) { - LOG_ERROR("Can't modify bits outside the User Row page range"); - return ERROR_FAIL; - } - - uint8_t *buf = malloc(page_size); - if (!buf) - return ERROR_FAIL; + /* Make sure the size is sane. */ + assert(page_size <= SAMD_PAGE_SIZE_MAX && + page_size >= sizeof(value_input)); + uint8_t buf[SAMD_PAGE_SIZE_MAX]; /* Read the user row (comprising one page) by words. */ res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf); if (res != ERROR_OK) - goto out_user_row; + return res; + + uint64_t value_device; + res = read_userrow(target, &value_device); + if (res != ERROR_OK) + return res; + uint64_t value_new = (value_input & value_mask) | (value_device & ~value_mask); /* We will need to erase before writing if the new value needs a '1' in any * position for which the current value had a '0'. Otherwise we can avoid * erasing. */ - uint32_t cur = buf_get_u32(buf, startb, endb - startb + 1); - if ((~cur) & value) { + if ((~value_device) & value_new) { res = samd_erase_row(target, SAMD_USER_ROW); if (res != ERROR_OK) { LOG_ERROR("Couldn't erase user row"); - goto out_user_row; + return res; } } /* Modify */ - buf_set_u32(buf, startb, endb - startb + 1, value); + target_buffer_set_u64(target, buf, value_new); /* Write the page buffer back out to the target. */ res = target_write_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf); if (res != ERROR_OK) - goto out_user_row; + return res; + /* Check if we need to do manual page write commands */ + res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, &nvm_ctrlb); + if (res == ERROR_OK) + manual_wp = (nvm_ctrlb & SAMD_NVM_CTRLB_MANW) != 0; + else { + LOG_ERROR("Read of NVM register CTRKB failed."); + return ERROR_FAIL; + } if (manual_wp) { /* Trigger flash write */ res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_WAP); @@ -602,12 +657,28 @@ static int samd_modify_user_row(struct target *target, uint32_t value, res = samd_check_error(target); } -out_user_row: - free(buf); - return res; } +/** + * Modifies the user row register to the given value. + * @param target Pointer to the target structure. + * @param value The value to write. + * @param startb The bit-offset by which the given value is shifted. + * @param endb The bit-offset of the last bit in value to write. + * @return On success ERROR_OK, on failure an errorcode. + */ +static int samd_modify_user_row(struct target *target, uint64_t value, + uint8_t startb, uint8_t endb) +{ + uint64_t mask = 0; + int i; + for (i = startb ; i <= endb ; i++) + mask |= ((uint64_t)1) << i; + + return samd_modify_user_row_masked(target, value << startb, mask); +} + static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl) { int res = ERROR_OK; @@ -644,7 +715,8 @@ static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int * corresponding to Sector 15. A '1' means unlocked and a '0' means * locked. See Table 9-3 in the SAMD20 datasheet for more details. */ - res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF, + res = samd_modify_user_row(bank->target, + set ? (uint64_t)0 : (uint64_t)UINT64_MAX, 48 + first_prot_bl, 48 + last_prot_bl); if (res != ERROR_OK) LOG_WARNING("SAMD: protect settings were not made persistent!"); @@ -945,6 +1017,83 @@ COMMAND_HANDLER(samd_handle_eeprom_command) return res; } +static COMMAND_HELPER(get_u64_from_hexarg, unsigned int num, uint64_t *value) +{ + if (num >= CMD_ARGC) { + command_print(CMD_CTX, "Too few Arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (strlen(CMD_ARGV[num]) >= 3 && + CMD_ARGV[num][0] == '0' && + CMD_ARGV[num][1] == 'x') { + char *check = NULL; + *value = strtoull(&(CMD_ARGV[num][2]), &check, 16); + if ((value == 0 && errno == ERANGE) || + check == NULL || *check != 0) { + command_print(CMD_CTX, "Invalid 64-bit hex value in argument %d.", + num + 1); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else { + command_print(CMD_CTX, "Argument %d needs to be a hex value.", num + 1); + return ERROR_COMMAND_SYNTAX_ERROR; + } + return ERROR_OK; +} + +COMMAND_HANDLER(samd_handle_nvmuserrow_command) +{ + int res = ERROR_OK; + struct target *target = get_current_target(CMD_CTX); + + if (target) { + if (CMD_ARGC > 2) { + command_print(CMD_CTX, "Too much Arguments given."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (CMD_ARGC > 0) { + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted."); + return ERROR_TARGET_NOT_HALTED; + } + + uint64_t mask; + res = samd_get_reservedmask(target, &mask); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't determine the mask for reserved bits."); + return ERROR_FAIL; + } + mask &= NVMUSERROW_LOCKBIT_MASK; + + uint64_t value; + res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 0, &value); + if (res != ERROR_OK) + return res; + if (CMD_ARGC == 2) { + uint64_t mask_temp; + res = CALL_COMMAND_HANDLER(get_u64_from_hexarg, 1, &mask_temp); + if (res != ERROR_OK) + return res; + mask &= mask_temp; + } + res = samd_modify_user_row_masked(target, value, mask); + if (res != ERROR_OK) + return res; + } + + /* read register */ + uint64_t value; + res = read_userrow(target, &value); + if (res == ERROR_OK) + command_print(CMD_CTX, "NVMUSERROW: 0x%016"PRIX64, value); + else + LOG_ERROR("NVMUSERROW could not be read."); + } + return res; +} + COMMAND_HANDLER(samd_handle_bootloader_command) { int res = ERROR_OK; @@ -1050,29 +1199,29 @@ static const struct command_registration at91samd_exec_command_handlers[] = { .name = "dsu_reset_deassert", .handler = samd_handle_reset_deassert, .mode = COMMAND_EXEC, - .help = "deasert internal reset held by DSU" + .help = "Deasert internal reset held by DSU." }, { .name = "info", .handler = samd_handle_info_command, .mode = COMMAND_EXEC, - .help = "Print information about the current at91samd chip" + .help = "Print information about the current at91samd chip " "and its flash configuration.", }, { .name = "chip-erase", .handler = samd_handle_chip_erase_command, .mode = COMMAND_EXEC, - .help = "Erase the entire Flash by using the Chip" + .help = "Erase the entire Flash by using the Chip-" "Erase feature in the Device Service Unit (DSU).", }, { .name = "set-security", .handler = samd_handle_set_security_command, .mode = COMMAND_EXEC, - .help = "Secure the chip's Flash by setting the Security Bit." - "This makes it impossible to read the Flash contents." - "The only way to undo this is to issue the chip-erase" + .help = "Secure the chip's Flash by setting the Security Bit. " + "This makes it impossible to read the Flash contents. " + "The only way to undo this is to issue the chip-erase " "command.", }, { @@ -1080,9 +1229,9 @@ static const struct command_registration at91samd_exec_command_handlers[] = { .usage = "[size_in_bytes]", .handler = samd_handle_eeprom_command, .mode = COMMAND_EXEC, - .help = "Show or set the EEPROM size setting, stored in the User Row." - "Please see Table 20-3 of the SAMD20 datasheet for allowed values." - "Changes are stored immediately but take affect after the MCU is" + .help = "Show or set the EEPROM size setting, stored in the User Row. " + "Please see Table 20-3 of the SAMD20 datasheet for allowed values. " + "Changes are stored immediately but take affect after the MCU is " "reset.", }, { @@ -1090,11 +1239,22 @@ static const struct command_registration at91samd_exec_command_handlers[] = { .usage = "[size_in_bytes]", .handler = samd_handle_bootloader_command, .mode = COMMAND_EXEC, - .help = "Show or set the bootloader size, stored in the User Row." - "Please see Table 20-2 of the SAMD20 datasheet for allowed values." - "Changes are stored immediately but take affect after the MCU is" + .help = "Show or set the bootloader size, stored in the User Row. " + "Please see Table 20-2 of the SAMD20 datasheet for allowed values. " + "Changes are stored immediately but take affect after the MCU is " "reset.", }, + { + .name = "nvmuserrow", + .usage = "[value] [mask]", + .handler = samd_handle_nvmuserrow_command, + .mode = COMMAND_EXEC, + .help = "Show or set the nvmuserrow register. It is 64 bit wide " + "and located at address 0x804000. Use the optional mask argument " + "to prevent changes at positions where the bitvalue is zero. " + "For security reasons the lock- and reserved-bits are masked out " + "in background and therefore cannot be changed.", + }, COMMAND_REGISTRATION_DONE };