From efb0b116dac19f511003a28e4cec9723693b9c2b Mon Sep 17 00:00:00 2001 From: Hans-Erik Floryd Date: Fri, 21 Jan 2022 12:07:56 +0100 Subject: [PATCH 01/79] flash/nor/atsame5: add LAN9255 devices Support Microchip LAN9255 devices with embedded SAME53J MCU. Signed-off-by: Hans-Erik Floryd Change-Id: Ia811c593bf7cf73e588d32873c68eb67c6fafad7 Reviewed-on: https://review.openocd.org/c/openocd/+/6811 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/flash/nor/atsame5.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index 9ab0e8113..fbf0fb2ed 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -146,6 +146,9 @@ static const struct samd_part same53_parts[] = { { 0x04, "SAME53J20A", 1024, 256 }, { 0x05, "SAME53J19A", 512, 192 }, { 0x06, "SAME53J18A", 256, 128 }, + { 0x55, "LAN9255/ZMX020", 1024, 256 }, + { 0x56, "LAN9255/ZMX019", 512, 192 }, + { 0x57, "LAN9255/ZMX018", 256, 128 }, }; /* Known SAME54 parts. */ From 5e0cc43838b898a125d7028ee1ec3c033c3b24c1 Mon Sep 17 00:00:00 2001 From: Hans-Erik Floryd Date: Fri, 21 Jan 2022 12:13:12 +0100 Subject: [PATCH 02/79] tcl/board: Add EVB-LAN9255 config Config for EVB-LAN9255, tested using Atmel-ICE debugger on J10 connector. Signed-off-by: Hans-Erik Floryd Change-Id: I8bcf779e9363499a98aa0b7d10819c53da6a19e7 Reviewed-on: https://review.openocd.org/c/openocd/+/6812 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/evb-lan9255.cfg | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tcl/board/evb-lan9255.cfg diff --git a/tcl/board/evb-lan9255.cfg b/tcl/board/evb-lan9255.cfg new file mode 100644 index 000000000..3fd6f603b --- /dev/null +++ b/tcl/board/evb-lan9255.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip LAN9255 evaluation board +# https://www.microchip.com/en-us/development-tool/EV25Y25A +# + +set CHIPNAME same53 + +source [find target/atsame5x.cfg] + +reset_config srst_only From 93f2276cdd99ad9e9d844150553621ea5d8524dd Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Wed, 12 Jan 2022 09:41:13 +0100 Subject: [PATCH 03/79] aarch64: support for aarch32 ARM_MODE_UND Fix: unrecognized psr mode: 0x1b cannot read system control register in this mode: (UNRECOGNIZED : 0x1b) Change-Id: I4dc3e72f90d57e52c0fe63cb59a7529a398757b3 Signed-off-by: Julien Massot Change-Id: Ifa5d21ae97492fde9e8c79ee7d99d8a2a871b1b5 Reviewed-on: https://review.openocd.org/c/openocd/+/6808 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/aarch64.c | 3 +++ src/target/armv8.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 30ef54792..d11fd943b 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -102,6 +102,7 @@ static int aarch64_restore_system_control_reg(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -180,6 +181,7 @@ static int aarch64_mmu_modify(struct target *target, int enable) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -1049,6 +1051,7 @@ static int aarch64_post_debug_entry(struct target *target) case ARM_MODE_FIQ: case ARM_MODE_IRQ: case ARM_MODE_HYP: + case ARM_MODE_UND: case ARM_MODE_SYS: instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); break; diff --git a/src/target/armv8.c b/src/target/armv8.c index 26116bb33..2de115712 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -77,6 +77,10 @@ static const struct { .name = "HYP", .psr = ARM_MODE_HYP, }, + { + .name = "UND", + .psr = ARM_MODE_UND, + }, { .name = "SYS", .psr = ARM_MODE_SYS, From 6541233aa78d40200092920ec4a72e3917ae3b6d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 8 Jul 2021 17:43:00 -0700 Subject: [PATCH 04/79] Combine register lists of smp targets. This is helpful when you want to pretend to gdb that your heterogeneous multicore system is homogeneous, because gdb cannot handle heterogeneous systems. This won't always works, but works fine if e.g. one of the cores has an FPU while the other does not. (Specifically, HiFive Unleashed has 1 core with no FPU, plus 4 cores with an FPU.) Signed-off-by: Tim Newsome Change-Id: I05ff4c28646778fbc00327bc510be064bfe6c9f0 Reviewed-on: https://review.openocd.org/c/openocd/+/6362 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 106 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 7c853730f..b6f4a8264 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2259,6 +2259,108 @@ static int get_reg_features_list(struct target *target, char const **feature_lis return ERROR_OK; } +/* Create a register list that's the union of all the registers of the SMP + * group this target is in. If the target is not part of an SMP group, this + * returns the same as target_get_gdb_reg_list_noread(). + */ +static int smp_reg_list_noread(struct target *target, + struct reg **combined_list[], int *combined_list_size, + enum target_register_class reg_class) +{ + if (!target->smp) + return target_get_gdb_reg_list_noread(target, combined_list, + combined_list_size, REG_CLASS_ALL); + + unsigned int combined_allocated = 256; + *combined_list = malloc(combined_allocated * sizeof(struct reg *)); + if (*combined_list == NULL) { + LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *)); + return ERROR_FAIL; + } + *combined_list_size = 0; + + struct target_list *head; + foreach_smp_target(head, target->head) { + struct reg **reg_list = NULL; + int reg_list_size; + int result = target_get_gdb_reg_list_noread(head->target, ®_list, + ®_list_size, reg_class); + if (result != ERROR_OK) { + free(*combined_list); + return result; + } + for (int i = 0; i < reg_list_size; i++) { + bool found = false; + struct reg *a = reg_list[i]; + if (a->exist) { + /* Nested loop makes this O(n^2), but this entire function with + * 5 RISC-V targets takes just 2ms on my computer. Fast enough + * for me. */ + for (int j = 0; j < *combined_list_size; j++) { + struct reg *b = (*combined_list)[j]; + if (!strcmp(a->name, b->name)) { + found = true; + if (a->size != b->size) { + LOG_ERROR("SMP register %s is %d bits on one " + "target, but %d bits on another target.", + a->name, a->size, b->size); + free(reg_list); + free(*combined_list); + return ERROR_FAIL; + } + break; + } + } + if (!found) { + LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); + if (*combined_list_size >= (int) combined_allocated) { + combined_allocated *= 2; + *combined_list = realloc(*combined_list, combined_allocated * sizeof(struct reg *)); + if (*combined_list == NULL) { + LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); + return ERROR_FAIL; + } + } + (*combined_list)[*combined_list_size] = a; + (*combined_list_size)++; + } + } + } + free(reg_list); + } + + /* Now warn the user about any registers that weren't found in every target. */ + foreach_smp_target(head, target->head) { + struct reg **reg_list = NULL; + int reg_list_size; + int result = target_get_gdb_reg_list_noread(head->target, ®_list, + ®_list_size, reg_class); + if (result != ERROR_OK) { + free(*combined_list); + return result; + } + for (int i = 0; i < *combined_list_size; i++) { + bool found = false; + struct reg *a = (*combined_list)[i]; + for (int j = 0; j < reg_list_size; j++) { + struct reg *b = reg_list[j]; + if (b->exist && !strcmp(a->name, b->name)) { + found = true; + break; + } + } + if (!found) { + LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where " + "this register does exist.", + a->name, target_name(head->target)); + } + } + free(reg_list); + } + + return ERROR_OK; +} + static int gdb_generate_target_description(struct target *target, char **tdesc_out) { int retval = ERROR_OK; @@ -2272,8 +2374,8 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int size = 0; - retval = target_get_gdb_reg_list_noread(target, ®_list, - ®_list_size, REG_CLASS_ALL); + retval = smp_reg_list_noread(target, ®_list, ®_list_size, + REG_CLASS_ALL); if (retval != ERROR_OK) { LOG_ERROR("get register list failed"); From dbbac5f11d662ab0827a997aa5d173fd62c51708 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sun, 9 Jan 2022 23:18:13 +0200 Subject: [PATCH 05/79] semihosting: use open mode flags from GDB, not from sys/stat.h Values defined in sys/stat.h are not guaranteed to match the constants defined by the GDB remote protocol, which are defined in https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags. On my local system (Manjaro 21.2.1 x86_64), for example, O_TRUNC is defined as 0x40, whereas GDB requires it to be 0x400, causing all "w" file open modes to misbehave. This patch has been tested with STM32F446. Change-Id: Ifb2c740fd689e71d6f1a4bde1edaecd76fdca910 Signed-off-by: Pavel Kirienko Reviewed-on: https://review.openocd.org/c/openocd/+/6804 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/semihosting_common.c | 40 +++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 1b65e126c..8d3f66ca5 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -52,19 +52,35 @@ #include #include +/** + * It is not possible to use O_... flags defined in sys/stat.h because they + * are not guaranteed to match the values defined by the GDB Remote Protocol. + * See https://sourceware.org/gdb/onlinedocs/gdb/Open-Flags.html#Open-Flags + */ +enum { + TARGET_O_RDONLY = 0x000, + TARGET_O_WRONLY = 0x001, + TARGET_O_RDWR = 0x002, + TARGET_O_APPEND = 0x008, + TARGET_O_CREAT = 0x200, + TARGET_O_TRUNC = 0x400, + /* O_EXCL=0x800 is not required in this implementation. */ +}; + +/* GDB remote protocol does not differentiate between text and binary open modes. */ static const int open_modeflags[12] = { - O_RDONLY, - O_RDONLY | O_BINARY, - O_RDWR, - O_RDWR | O_BINARY, - O_WRONLY | O_CREAT | O_TRUNC, - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - O_RDWR | O_CREAT | O_TRUNC, - O_RDWR | O_CREAT | O_TRUNC | O_BINARY, - O_WRONLY | O_CREAT | O_APPEND, - O_WRONLY | O_CREAT | O_APPEND | O_BINARY, - O_RDWR | O_CREAT | O_APPEND, - O_RDWR | O_CREAT | O_APPEND | O_BINARY + TARGET_O_RDONLY, + TARGET_O_RDONLY, + TARGET_O_RDWR, + TARGET_O_RDWR, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_TRUNC, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_WRONLY | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND, + TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND }; static int semihosting_common_fileio_info(struct target *target, From 5ab74bde06541ce199390ead348a3e107ee9c0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Dud=C3=A1s?= Date: Wed, 24 Nov 2021 17:13:50 +0100 Subject: [PATCH 06/79] semihosting: User defined operation, Tcl command exec on host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling a portion (0x100 - 0x107) of the user defined semihosting operation number range (0x100 - 0x1FF) to be processed with the help of the existing target event mechanism, to implement a general-purpose Tcl interface for the target available on the host, via semihosting interface. Example usage: - The user configures a Tcl command as a callback for one of the newly defined events (semihosting-user-cmd-0x10X) in the configuration file. - The target can make a semihosting call with , passing optional parameters for the call. If there is no callback registered to the user defined operation number, nothing happens. Example usage: Configure RTT automatically with the exact, linked control block location from target. Signed-off-by: Zoltán Dudás Change-Id: I10e1784b1fecd4e630d78df81cb44bf1aa2fc247 Reviewed-on: https://review.openocd.org/c/openocd/+/6748 Tested-by: jenkins Reviewed-by: Oleksij Rempel Reviewed-by: Antonio Borneo --- doc/openocd.texi | 27 +++++++ src/target/arm_semihosting.c | 7 +- src/target/riscv/riscv_semihosting.c | 4 +- src/target/semihosting_common.c | 104 ++++++++++++++++++++++++++- src/target/semihosting_common.h | 6 ++ src/target/target.c | 9 +++ src/target/target.h | 9 +++ 7 files changed, 162 insertions(+), 4 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index ed92eb4ec..e2c495473 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5185,6 +5185,22 @@ when reset disables PLLs needed to use a fast clock. @* After single-step has completed @item @b{trace-config} @* After target hardware trace configuration was changed +@item @b{semihosting-user-cmd-0x100} +@* The target made a semihosting call with user-defined operation number 0x100 +@item @b{semihosting-user-cmd-0x101} +@* The target made a semihosting call with user-defined operation number 0x101 +@item @b{semihosting-user-cmd-0x102} +@* The target made a semihosting call with user-defined operation number 0x102 +@item @b{semihosting-user-cmd-0x103} +@* The target made a semihosting call with user-defined operation number 0x103 +@item @b{semihosting-user-cmd-0x104} +@* The target made a semihosting call with user-defined operation number 0x104 +@item @b{semihosting-user-cmd-0x105} +@* The target made a semihosting call with user-defined operation number 0x105 +@item @b{semihosting-user-cmd-0x106} +@* The target made a semihosting call with user-defined operation number 0x106 +@item @b{semihosting-user-cmd-0x107} +@* The target made a semihosting call with user-defined operation number 0x107 @end itemize @quotation Note @@ -9241,6 +9257,17 @@ To make the SEMIHOSTING_SYS_EXIT call return normally, enable this option (default: disabled). @end deffn +@deffn {Command} {arm semihosting_read_user_param} +@cindex ARM semihosting +Read parameter of the semihosting call from the target. Usable in +semihosting-user-cmd-0x10* event handlers, returning a string. + +When the target makes semihosting call with operation number from range 0x100- +0x107, an optional string parameter can be passed to the server. This parameter +is valid during the run of the event handlers and is accessible with this +command. +@end deffn + @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 792474acf..507d1cd2c 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -367,10 +367,13 @@ int arm_semihosting(struct target *target, int *retval) } /* Check for ARM operation numbers. */ - if (semihosting->op >= 0 && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); + LOG_ERROR("Failed semihosting operation (0x%02X)", + semihosting->op); return 0; } } else { diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index b347212d3..1dd8e7791 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -140,7 +140,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) semihosting->word_size_bytes = riscv_xlen(target) / 8; /* Check for ARM operation numbers. */ - if (semihosting->op >= 0 && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + (semihosting->op >= 0x100 && semihosting->op <= 0x107)) { + *retval = semihosting_common(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 8d3f66ca5..9e60de572 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -154,6 +154,12 @@ int semihosting_common_init(struct target *target, void *setup, return ERROR_OK; } +/** + * User operation parameter string storage buffer. Contains valid data when the + * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. + */ +static char *semihosting_user_op_params; + /** * Portable implementation of ARM semihosting calls. * Performs the currently pending semihosting operation @@ -183,7 +189,7 @@ int semihosting_common(struct target *target) /* Enough space to hold 4 long words. */ uint8_t fields[4*8]; - LOG_DEBUG("op=0x%x, param=0x%" PRIx64, (int)semihosting->op, + LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op, semihosting->param); switch (semihosting->op) { @@ -1278,6 +1284,71 @@ int semihosting_common(struct target *target) } break; + case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107: + /** + * This is a user defined operation (while user cmds 0x100-0x1ff + * are possible, only 0x100-0x107 are currently implemented). + * + * Reads the user operation parameters from target, then fires the + * corresponding target event. When the target callbacks returned, + * cleans up the command parameter buffer. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 Contains a pointer to the bound command parameter + * string + * - field 2 Contains the command parameter string length + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + { + assert(!semihosting_user_op_params); + + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read fields for user defined command" + " op=0x%x", semihosting->op); + return retval; + } + + uint64_t addr = semihosting_get_field(target, 0, fields); + + size_t len = semihosting_get_field(target, 1, fields); + if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) { + LOG_ERROR("The maximum length for user defined command " + "parameter is %u, received length is %zu (op=0x%x)", + SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH, + len, + semihosting->op); + return ERROR_FAIL; + } + + semihosting_user_op_params = malloc(len + 1); + if (!semihosting_user_op_params) + return ERROR_FAIL; + semihosting_user_op_params[len] = 0; + + retval = target_read_buffer(target, addr, len, + (uint8_t *)(semihosting_user_op_params)); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read from target, semihosting op=0x%x", + semihosting->op); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + return retval; + } + + target_handle_event(target, semihosting->op); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + + semihosting->result = 0; + break; + } + + case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ /* * Returns the number of elapsed target ticks since execution @@ -1624,6 +1695,30 @@ COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) return ERROR_OK; } +COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct semihosting *semihosting = target->semihosting; + + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!semihosting->is_active) { + LOG_ERROR("semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + if (!semihosting_user_op_params) { + LOG_ERROR("This command is usable only from a registered user " + "semihosting event callback."); + return ERROR_FAIL; + } + + command_print_sameline(CMD, "%s", semihosting_user_op_params); + + return ERROR_OK; +} + const struct command_registration semihosting_common_handlers[] = { { "semihosting", @@ -1653,5 +1748,12 @@ const struct command_registration semihosting_common_handlers[] = { .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, + { + "semihosting_read_user_param", + .handler = handle_common_semihosting_read_user_param_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "read parameters in semihosting-user-cmd-0x10X callbacks", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index b83464ed5..6eb9ca252 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -75,8 +75,14 @@ enum semihosting_operation_numbers { SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, + SEMIHOSTING_USER_CMD_0x100 = 0x100, /* First user cmd op code */ + SEMIHOSTING_USER_CMD_0x107 = 0x107, /* Last supported user cmd op code */ + SEMIHOSTING_USER_CMD_0x1FF = 0x1FF, /* Last user cmd op code */ }; +/** Maximum allowed Tcl command segment length in bytes*/ +#define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024) + /* * Codes used by SEMIHOSTING_SYS_EXIT (formerly * SEMIHOSTING_REPORT_EXCEPTION). diff --git a/src/target/target.c b/src/target/target.c index 7cdd8d830..acfbd3df5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -236,6 +236,15 @@ static const struct jim_nvp nvp_target_event[] = { { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100, .name = "semihosting-user-cmd-0x100" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101, .name = "semihosting-user-cmd-0x101" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102, .name = "semihosting-user-cmd-0x102" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103, .name = "semihosting-user-cmd-0x103" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104, .name = "semihosting-user-cmd-0x104" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105, .name = "semihosting-user-cmd-0x105" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106, .name = "semihosting-user-cmd-0x106" }, + { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107, .name = "semihosting-user-cmd-0x107" }, + { .name = NULL, .value = -1 } }; diff --git a/src/target/target.h b/src/target/target.h index 6ef8f10e0..974630f17 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -294,6 +294,15 @@ enum target_event { TARGET_EVENT_GDB_FLASH_WRITE_END, TARGET_EVENT_TRACE_CONFIG, + + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */ + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101 = 0x101, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102 = 0x102, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103 = 0x103, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104 = 0x104, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105 = 0x105, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106 = 0x106, + TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107 = 0x107, }; struct target_event_action { From 16cc853bcfbcc8dba6eadd91b434c05387034c0a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 16 Dec 2021 01:59:14 +0100 Subject: [PATCH 07/79] target/smp: use a struct list_head to hold the smp targets Instead of reinventing a simply linked list, reuse the list helper for the list of targets in a smp cluster. Using the existing helper, that implements a double linked list, makes trivial going through the list in reverse order. Change-Id: Ib36ad2955f15cd2a601b0b9e36ca6d948b12d00f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6783 Tested-by: jenkins --- src/rtos/hwthread.c | 8 +-- src/rtos/linux.c | 16 ++---- src/server/gdb_server.c | 11 ++-- src/target/aarch64.c | 15 +++--- src/target/armv7a.c | 9 ++-- src/target/armv7a_cache.c | 9 ++-- src/target/armv7a_cache_l2x.c | 9 ++-- src/target/armv8_cache.c | 8 ++- src/target/breakpoints.c | 95 +++++++++++++++-------------------- src/target/cortex_a.c | 26 ++++------ src/target/mips_m4k.c | 22 +++----- src/target/riscv/riscv.c | 23 +++++---- src/target/smp.c | 10 ++-- src/target/smp.h | 3 +- src/target/target.c | 44 ++++++++-------- src/target/target.h | 6 ++- 16 files changed, 136 insertions(+), 178 deletions(-) diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index 3702b0b47..7c998861f 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -23,6 +23,7 @@ #include "target/target.h" #include "target/target_type.h" #include "target/register.h" +#include #include "rtos.h" #include "helper/log.h" #include "helper/types.h" @@ -107,7 +108,7 @@ static int hwthread_update_threads(struct rtos *rtos) /* determine the number of "threads" */ if (target->smp) { - for (head = target->head; head; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -123,7 +124,7 @@ static int hwthread_update_threads(struct rtos *rtos) if (target->smp) { /* loop over all threads */ - for (head = target->head; head; head = head->next) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; if (!target_was_examined(curr)) @@ -218,7 +219,8 @@ static struct target *hwthread_find_thread(struct target *target, int64_t thread if (!target) return NULL; if (target->smp) { - for (struct target_list *head = target->head; head; head = head->next) { + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { if (thread_id == threadid_from_target(head->target)) return head->target; } diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 84b4c6524..d147c1cf0 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -30,6 +30,7 @@ #include "rtos.h" #include "rtos_standard_stackings.h" #include +#include #include "server/gdb_server.h" #define LINUX_USER_KERNEL_BORDER 0xc0000000 @@ -191,16 +192,14 @@ static int linux_os_thread_reg_list(struct rtos *rtos, /* search target to perform the access */ struct reg **gdb_reg_list; struct target_list *head; - head = target->head; found = 0; - do { + foreach_smp_target(head, target->smp_targets) { if (head->target->coreid == next->core_id) { target = head->target; found = 1; break; } - head = head->next; - } while (head); + } if (found == 0) { LOG_ERROR @@ -397,7 +396,6 @@ static int get_name(struct target *target, struct threads *t) static int get_current(struct target *target, int create) { struct target_list *head; - head = target->head; uint8_t *buf; uint32_t val; uint32_t ti_addr; @@ -413,7 +411,7 @@ static int get_current(struct target *target, int create) ctt = ctt->next; } - while (head) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list; int reg_list_size; int retval; @@ -474,7 +472,6 @@ static int get_current(struct target *target, int create) } free(reg_list); - head = head->next; } free(buffer); @@ -1394,9 +1391,8 @@ static int linux_os_smp_init(struct target *target) struct linux_os *os_linux = (struct linux_os *)rtos->rtos_specific_params; struct current_thread *ct; - head = target->head; - while (head) { + foreach_smp_target(head, target->smp_targets) { if (head->target->rtos != rtos) { struct linux_os *smp_os_linux = (struct linux_os *)head->target->rtos->rtos_specific_params; @@ -1413,8 +1409,6 @@ static int linux_os_smp_init(struct target *target) os_linux->nr_cpus++; free(smp_os_linux); } - - head = head->next; } return ERROR_OK; diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b6f4a8264..537670c52 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2280,7 +2280,7 @@ static int smp_reg_list_noread(struct target *target, *combined_list_size = 0; struct target_list *head; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, @@ -2330,7 +2330,7 @@ static int smp_reg_list_noread(struct target *target, } /* Now warn the user about any registers that weren't found in every target. */ - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, @@ -3659,13 +3659,10 @@ static int gdb_target_start(struct target *target, const char *port) /* initialize all targets gdb service with the same pointer */ { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) curr->gdb_service = gdb_service; - head = head->next; } } return ret; diff --git a/src/target/aarch64.c b/src/target/aarch64.c index d11fd943b..a45322d2f 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -333,15 +333,14 @@ static int aarch64_wait_halt_one(struct target *target) static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first) { int retval = ERROR_OK; - struct target_list *head = target->head; + struct target_list *head; struct target *first = NULL; LOG_DEBUG("target %s exc %i", target_name(target), exc_target); - while (head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; struct armv8_common *armv8 = target_to_armv8(curr); - head = head->next; if (exc_target && curr == target) continue; @@ -430,7 +429,7 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) struct target_list *head; struct target *curr; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { int halted; curr = head->target; @@ -480,7 +479,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug } /* poll all targets in the group, but skip the target that serves GDB */ - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -745,7 +744,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint struct target *first = NULL; uint64_t address; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; /* skip calling target */ @@ -800,7 +799,7 @@ static int aarch64_step_restart_smp(struct target *target) struct target *curr = target; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -888,7 +887,7 @@ static int aarch64_resume(struct target *target, int current, struct target_list *head; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; diff --git a/src/target/armv7a.c b/src/target/armv7a.c index 2259fa560..d564f19ae 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -38,6 +38,7 @@ #include "arm_opcodes.h" #include "target.h" #include "target_type.h" +#include "smp.h" static void armv7a_show_fault_registers(struct target *target) { @@ -193,8 +194,7 @@ done: static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); @@ -207,15 +207,14 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; /* initialize all target in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) LOG_ERROR("smp target : outer cache already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return JIM_OK; } diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index 4078fdde2..ba6f076f0 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -26,6 +26,7 @@ #include "armv7a_cache.h" #include #include "arm_opcodes.h" +#include "smp.h" static int armv7a_l1_d_cache_sanity_check(struct target *target) { @@ -138,14 +139,10 @@ int armv7a_cache_auto_flush_all_data(struct target *target) if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr->state == TARGET_HALTED) retval = armv7a_l1_d_cache_clean_inval_all(curr); - - head = head->next; } } else retval = armv7a_l1_d_cache_clean_inval_all(target); diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c index 6b42fae53..c26d05173 100644 --- a/src/target/armv7a_cache_l2x.c +++ b/src/target/armv7a_cache_l2x.c @@ -27,6 +27,7 @@ #include #include "target.h" #include "target_type.h" +#include "smp.h" static int arm7a_l2x_sanity_check(struct target *target) { @@ -194,8 +195,7 @@ static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; - struct target_list *head = target->head; - struct target *curr; + struct target_list *head; struct armv7a_common *armv7a = target_to_armv7a(target); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -210,8 +210,8 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t /* initialize all targets in this cluster (smp target) * l2 cache must be configured after smp declaration */ - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) { @@ -220,7 +220,6 @@ static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t } armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; } - head = head->next; } return ERROR_OK; } diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index f05ac07cd..5b58d3f9f 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -23,6 +23,7 @@ #include "armv8_cache.h" #include "armv8_dpm.h" #include "armv8_opcodes.h" +#include "smp.h" /* CLIDR cache types */ #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 @@ -250,15 +251,12 @@ static int armv8_flush_all_data(struct target *target) /* look if all the other target have been flushed in order to flush level * 2 */ struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if (curr->state == TARGET_HALTED) { LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); retval = _armv8_flush_all_data(curr); } - head = head->next; } } else retval = _armv8_flush_all_data(target); diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index dd901ef25..8439ff395 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -26,6 +26,7 @@ #include "target.h" #include #include "breakpoints.h" +#include "smp.h" static const char * const breakpoint_type_strings[] = { "hardware", @@ -216,22 +217,22 @@ int breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - if (type == BKPT_SOFT) - return breakpoint_add_internal(head->target, address, length, type); - while (head) { - curr = head->target; - retval = breakpoint_add_internal(curr, address, length, type); + if (type == BKPT_SOFT) { + head = list_first_entry(target->smp_targets, struct target_list, lh); + return breakpoint_add_internal(head->target, address, length, type); + } + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return breakpoint_add_internal(target, address, length, type); } @@ -242,19 +243,17 @@ int context_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; - retval = context_breakpoint_add_internal(curr, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return context_breakpoint_add_internal(target, asid, length, type); } @@ -266,19 +265,17 @@ int hybrid_breakpoint_add(struct target *target, uint32_t length, enum breakpoint_type type) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; - retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else return hybrid_breakpoint_add_internal(target, address, asid, length, type); } @@ -345,12 +342,10 @@ void breakpoint_remove(struct target *target, target_addr_t address) if (target->smp) { unsigned int num_breakpoints = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; num_breakpoints += breakpoint_remove_internal(curr, address); - head = head->next; } if (!num_breakpoints) LOG_ERROR("no breakpoint at address " TARGET_ADDR_FMT " found", address); @@ -363,12 +358,10 @@ void breakpoint_remove_all(struct target *target) { if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; breakpoint_remove_all_internal(curr); - head = head->next; } } else { breakpoint_remove_all_internal(target); @@ -387,12 +380,10 @@ void breakpoint_clear_target(struct target *target) { if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; breakpoint_clear_target_internal(curr); - head = head->next; } } else { breakpoint_clear_target_internal(target); @@ -482,21 +473,17 @@ bye: int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) { - int retval = ERROR_OK; if (target->smp) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - retval = watchpoint_add_internal(curr, address, length, rw, value, - mask); + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + int retval = watchpoint_add_internal(curr, address, length, rw, value, mask); if (retval != ERROR_OK) return retval; - head = head->next; } - return retval; + + return ERROR_OK; } else { return watchpoint_add_internal(target, address, length, rw, value, mask); @@ -549,12 +536,10 @@ void watchpoint_remove(struct target *target, target_addr_t address) if (target->smp) { unsigned int num_watchpoints = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; num_watchpoints += watchpoint_remove_internal(curr, address); - head = head->next; } if (num_watchpoints == 0) LOG_ERROR("no watchpoint at address " TARGET_ADDR_FMT " num_watchpoints", address); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index bf65544f5..272411359 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -639,14 +639,11 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) static struct target *get_cortex_a(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -656,14 +653,12 @@ static int cortex_a_halt_smp(struct target *target) { int retval = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED) && target_was_examined(curr)) retval += cortex_a_halt(curr); - head = head->next; } return retval; } @@ -684,7 +679,7 @@ static int update_halt_gdb(struct target *target) if (target->gdb_service) gdb_target = target->gdb_service->target; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -951,11 +946,10 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) { int retval = 0; struct target_list *head; - struct target *curr; target_addr_t address; - head = target->head; - while (head) { - curr = head->target; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ @@ -963,8 +957,6 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) handle_breakpoints, 0); retval += cortex_a_internal_restart(curr); } - head = head->next; - } return retval; } diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index ca4416981..8627bce6e 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -128,14 +128,11 @@ static int mips_m4k_debug_entry(struct target *target) static struct target *get_mips_m4k(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -144,11 +141,10 @@ static int mips_m4k_halt_smp(struct target *target) { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { + + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED)) ret = mips_m4k_halt(curr); @@ -156,7 +152,6 @@ static int mips_m4k_halt_smp(struct target *target) LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid); retval = ret; } - head = head->next; } return retval; } @@ -414,12 +409,10 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han { int retval = ERROR_OK; struct target_list *head; - struct target *curr; - head = target->head; - while (head) { + foreach_smp_target(head, target->smp_targets) { int ret = ERROR_OK; - curr = head->target; + struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ ret = mips_m4k_internal_restore(curr, 1, address, @@ -431,7 +424,6 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han retval = ret; } } - head = head->next; } return retval; } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index c9840fe50..931f76290 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -13,6 +13,7 @@ #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" +#include #include "jtag/jtag.h" #include "target/register.h" #include "target/breakpoints.h" @@ -1232,13 +1233,14 @@ int riscv_halt(struct target *target) int result = ERROR_OK; if (target->smp) { - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_prep(t) != ERROR_OK) result = ERROR_FAIL; } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1247,7 +1249,7 @@ int riscv_halt(struct target *target) } } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (halt_finish(t) != ERROR_OK) return ERROR_FAIL; @@ -1469,14 +1471,15 @@ int riscv_resume( LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); int result = ERROR_OK; if (target->smp && !single_hart) { - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + struct target_list *tlist; + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_prep(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1486,7 +1489,7 @@ int riscv_resume( } } - for (struct target_list *tlist = target->head; tlist; tlist = tlist->next) { + foreach_smp_target(tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_finish(t) != ERROR_OK) return ERROR_FAIL; @@ -2180,9 +2183,8 @@ int riscv_openocd_poll(struct target *target) unsigned halts_discovered = 0; unsigned should_remain_halted = 0; unsigned should_resume = 0; - unsigned i = 0; - for (struct target_list *list = target->head; list; - list = list->next, i++) { + struct target_list *list; + foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; riscv_info_t *r = riscv_info(t); enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid); @@ -2242,8 +2244,7 @@ int riscv_openocd_poll(struct target *target) } /* Sample memory if any target is running. */ - for (struct target_list *list = target->head; list; - list = list->next, i++) { + foreach_smp_target(list, target->smp_targets) { struct target *t = list->target; if (t->state == TARGET_RUNNING) { sample_memory(target); diff --git a/src/target/smp.c b/src/target/smp.c index 518f6e458..3e1ded8bc 100644 --- a/src/target/smp.c +++ b/src/target/smp.c @@ -111,18 +111,18 @@ COMMAND_HANDLER(default_handle_smp_command) } if (!strcmp(CMD_ARGV[0], "on")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 1; return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "off")) { - foreach_smp_target(head, target->head) + foreach_smp_target(head, target->smp_targets) head->target->smp = 0; /* fixes the target display to the debugger */ - if (target->head) + if (!list_empty(target->smp_targets)) target->gdb_service->target = target; return ERROR_OK; @@ -135,9 +135,7 @@ COMMAND_HANDLER(handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; - struct target_list *head; - head = target->head; - if (head) { + if (!list_empty(target->smp_targets)) { if (CMD_ARGC == 1) { int coreid = 0; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); diff --git a/src/target/smp.h b/src/target/smp.h index 3338240ad..46fc55f75 100644 --- a/src/target/smp.h +++ b/src/target/smp.h @@ -19,10 +19,11 @@ #ifndef OPENOCD_TARGET_SMP_H #define OPENOCD_TARGET_SMP_H +#include #include "server/server.h" #define foreach_smp_target(pos, head) \ - for (pos = head; (pos); pos = pos->next) + list_for_each_entry(pos, head, lh) extern const struct command_registration smp_command_handlers[]; diff --git a/src/target/target.c b/src/target/target.c index acfbd3df5..6250d3031 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -56,6 +56,7 @@ #include "rtos/rtos.h" #include "transport/transport.h" #include "arm_cti.h" +#include "smp.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -159,6 +160,7 @@ static int64_t target_timer_next_event_value; static LIST_HEAD(target_reset_callback_list); static LIST_HEAD(target_trace_callback_list); static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; +static LIST_HEAD(empty_smp_targets); static const struct jim_nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, @@ -2272,13 +2274,15 @@ static void target_destroy(struct target *target) /* release the targets SMP list */ if (target->smp) { - struct target_list *head = target->head; - while (head) { - struct target_list *pos = head->next; + struct target_list *head, *tmp; + + list_for_each_entry_safe(head, tmp, target->smp_targets, lh) { + list_del(&head->lh); head->target->smp = 0; free(head); - head = pos; } + if (target->smp_targets != &empty_smp_targets) + free(target->smp_targets); target->smp = 0; } @@ -5786,6 +5790,9 @@ static int target_create(struct jim_getopt_info *goi) return JIM_ERR; } + /* set empty smp cluster */ + target->smp_targets = &empty_smp_targets; + /* set target number */ target->target_number = new_target_number(); @@ -5998,9 +6005,7 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) const char *targetname; int retval, len; struct target *target = NULL; - struct target_list *head, *curr, *new; - curr = NULL; - head = NULL; + struct target_list *head, *new; retval = 0; LOG_DEBUG("%d", argc); @@ -6009,6 +6014,13 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) * argv[3] ... */ + struct list_head *lh = malloc(sizeof(*lh)); + if (!lh) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + INIT_LIST_HEAD(lh); + for (i = 1; i < argc; i++) { targetname = Jim_GetString(argv[i], &len); @@ -6017,24 +6029,14 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (target) { new = malloc(sizeof(struct target_list)); new->target = target; - new->next = NULL; - if (!head) { - head = new; - curr = head; - } else { - curr->next = new; - curr = new; - } + list_add_tail(&new->lh, lh); } } /* now parse the list of cpu and put the target in smp mode*/ - curr = head; - - while (curr) { - target = curr->target; + foreach_smp_target(head, lh) { + target = head->target; target->smp = 1; - target->head = head; - curr = curr->next; + target->smp_targets = lh; } if (target && target->rtos) diff --git a/src/target/target.h b/src/target/target.h index 974630f17..1f1a35420 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -201,7 +201,9 @@ struct target { * and must be detected when symbols are offered */ struct backoff_timer backoff; int smp; /* add some target attributes for smp support */ - struct target_list *head; + struct list_head *smp_targets; /* list all targets in this smp group/cluster + * The head of the list is shared between the + * cluster, thus here there is a pointer */ /* the gdb service is there in case of smp, we have only one gdb server * for all smp target * the target attached to the gdb is changing dynamically by changing @@ -220,8 +222,8 @@ struct target { }; struct target_list { + struct list_head lh; struct target *target; - struct target_list *next; }; struct gdb_fileio_info { From a11fe473eaee235a51dba7900c08cc7629ed2794 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 16 Dec 2021 11:25:32 +0100 Subject: [PATCH 08/79] helper/list: add list_for_each_entry_direction() Use a bool flag to specify if the list should be forward or backward iterated. Change-Id: Ied19d049f46cdcb7f50137d459cc7c02014526bc Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6784 Tested-by: jenkins --- src/helper/list.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/helper/list.h b/src/helper/list.h index a7cd4ad37..552a3202a 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -656,6 +656,20 @@ static inline void list_splice_tail_init(struct list_head *list, !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) +/** + * list_for_each_entry_direction - iterate forward/backward over list of given type + * @param forward the iterate direction, true for forward, false for backward. + * @param pos the type * to use as a loop cursor. + * @param head the head for your list. + * @param member the name of the list_head within the struct. + */ +#define list_for_each_entry_direction(forward, pos, head, member) \ + for (pos = forward ? list_first_entry(head, typeof(*pos), member) \ + : list_last_entry(head, typeof(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = forward ? list_next_entry(pos, member) \ + : list_prev_entry(pos, member)) + /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() * @param pos the type * to use as a start point From 49c40a75292b1f76fa0d4bad91c993d9f7a618cf Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 16 Dec 2021 12:54:35 +0100 Subject: [PATCH 09/79] target/riscv: revive 'riscv resume_order' This functionality was lost in [1], which was merged as commit 615709d14049 ("Upstream a whole host of RISC-V changes."). Now it works as expected again. Add convenience macro foreach_smp_target_direction(). Link: [1] https://github.com/riscv/riscv-openocd/pull/567 Change-Id: I1545fa6b45b8a07e27c8ff9dcdcfa2fc4f950cd1 Signed-off-by: Tim Newsome Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6785 Tested-by: jenkins --- src/target/riscv/riscv.c | 9 ++++++--- src/target/smp.h | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 931f76290..367506dde 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1472,14 +1472,16 @@ int riscv_resume( int result = ERROR_OK; if (target->smp && !single_hart) { struct target_list *tlist; - foreach_smp_target(tlist, target->smp_targets) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_prep(t, current, address, handle_breakpoints, debug_execution) != ERROR_OK) result = ERROR_FAIL; } - foreach_smp_target(tlist, target->smp_targets) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; riscv_info_t *i = riscv_info(t); if (i->prepped) { @@ -1489,7 +1491,8 @@ int riscv_resume( } } - foreach_smp_target(tlist, target->smp_targets) { + foreach_smp_target_direction(resume_order == RO_NORMAL, + tlist, target->smp_targets) { struct target *t = tlist->target; if (resume_finish(t) != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/smp.h b/src/target/smp.h index 46fc55f75..490a49310 100644 --- a/src/target/smp.h +++ b/src/target/smp.h @@ -25,6 +25,9 @@ #define foreach_smp_target(pos, head) \ list_for_each_entry(pos, head, lh) +#define foreach_smp_target_direction(forward, pos, head) \ + list_for_each_entry_direction(forward, pos, head, lh) + extern const struct command_registration smp_command_handlers[]; int gdb_read_smp_packet(struct connection *connection, From 2a2636f138dc40be3fff06cb7bf1f126d906e0a1 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 23 Jan 2022 00:37:10 +0100 Subject: [PATCH 10/79] doxygen: fix some function prototype description Change-Id: I49311a643ea73143839d2f6bde976cfd76f8c67f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6830 Tested-by: jenkins --- src/jtag/drivers/jlink.c | 2 -- src/jtag/drivers/ulink.c | 2 -- src/jtag/jtag.h | 3 ++- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index fdf4ae778..5c218742b 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -114,8 +114,6 @@ static int jlink_flush(void); * @param in A pointer to store TDO data to, if NULL the data will be discarded. * @param in_offset A bit offset for TDO data. * @param length Amount of bits to transfer out and in. - * - * @retval This function doesn't return any value. */ static void jlink_clock_data(const uint8_t *out, unsigned out_offset, const uint8_t *tms_out, unsigned tms_offset, diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 3ae5cac62..20a036a78 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -604,8 +604,6 @@ static int ulink_get_queue_size(struct ulink *device, * Clear the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL */ static void ulink_clear_queue(struct ulink *device) { diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index def594ee3..4ec2f1e31 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -546,7 +546,8 @@ int jtag_srst_asserted(int *srst_asserted); * @param field Pointer to scan field. * @param value Pointer to scan value. * @param mask Pointer to scan mask; may be NULL. - * @returns Nothing, but calls jtag_set_error() on any error. + * + * returns Nothing, but calls jtag_set_error() on any error. */ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask); From f998a2aaf19c14b46fd7f7dd50607a0904f40bd3 Mon Sep 17 00:00:00 2001 From: Jacek Wuwer Date: Tue, 6 Apr 2021 20:08:11 +0200 Subject: [PATCH 11/79] Cadence virtual debug interface (vdebug) integration Change-Id: I1bc105b3addc3f34161c2356c482ff3011e3f2cc Signed-off-by: Jacek Wuwer Reviewed-on: https://review.openocd.org/c/openocd/+/6097 Tested-by: jenkins Reviewed-by: Oleksij Rempel Reviewed-by: zapb Reviewed-by: Antonio Borneo --- configure.ac | 15 +- doc/openocd.texi | 41 ++ src/jtag/drivers/Makefile.am | 3 + src/jtag/drivers/vdebug.c | 1076 ++++++++++++++++++++++++++++++ src/jtag/interfaces.c | 6 + tcl/board/vd_a53x2_jtag.cfg | 31 + tcl/board/vd_m4_jtag.cfg | 30 + tcl/board/vd_pulpissimo_jtag.cfg | 32 + tcl/board/vd_swerv_jtag.cfg | 32 + tcl/interface/vdebug.cfg | 33 + tcl/target/vd_aarch64.cfg | 37 + tcl/target/vd_cortex_m.cfg | 12 + tcl/target/vd_riscv.cfg | 18 + 13 files changed, 1364 insertions(+), 2 deletions(-) create mode 100644 src/jtag/drivers/vdebug.c create mode 100644 tcl/board/vd_a53x2_jtag.cfg create mode 100644 tcl/board/vd_m4_jtag.cfg create mode 100644 tcl/board/vd_pulpissimo_jtag.cfg create mode 100644 tcl/board/vd_swerv_jtag.cfg create mode 100644 tcl/interface/vdebug.cfg create mode 100644 tcl/target/vd_aarch64.cfg create mode 100644 tcl/target/vd_cortex_m.cfg create mode 100644 tcl/target/vd_riscv.cfg diff --git a/configure.ac b/configure.ac index a178284ee..68fff45c1 100644 --- a/configure.ac +++ b/configure.ac @@ -274,6 +274,10 @@ AC_ARG_ENABLE([jtag_vpi], AS_HELP_STRING([--enable-jtag_vpi], [Enable building support for JTAG VPI]), [build_jtag_vpi=$enableval], [build_jtag_vpi=no]) +AC_ARG_ENABLE([vdebug], + AS_HELP_STRING([--enable-vdebug], [Enable building support for Cadence Virtual Debug Interface]), + [build_vdebug=$enableval], [build_vdebug=no]) + AC_ARG_ENABLE([jtag_dpi], AS_HELP_STRING([--enable-jtag_dpi], [Enable building support for JTAG DPI]), [build_jtag_dpi=$enableval], [build_jtag_dpi=no]) @@ -513,6 +517,12 @@ AS_IF([test "x$build_jtag_vpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_VPI], [0], [0 if you don't want JTAG VPI.]) ]) +AS_IF([test "x$build_vdebug" = "xyes"], [ + AC_DEFINE([BUILD_VDEBUG], [1], [1 if you want Cadence vdebug interface.]) +], [ + AC_DEFINE([BUILD_VDEBUG], [0], [0 if you don't want Cadence vdebug interface.]) +]) + AS_IF([test "x$build_jtag_dpi" = "xyes"], [ AC_DEFINE([BUILD_JTAG_DPI], [1], [1 if you want JTAG DPI.]) ], [ @@ -688,8 +698,9 @@ AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) -AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes" -o "x$build_jtag_vpi" = "xyes"]) -AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes" -o "x$build_jtag_dpi" = "xyes"]) +AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"]) +AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"]) +AM_CONDITIONAL([JTAG_DPI], [test "x$build_jtag_dpi" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([AMTJTAGACCEL], [test "x$build_amtjtagaccel" = "xyes"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) diff --git a/doc/openocd.texi b/doc/openocd.texi index e2c495473..fd4a81da2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -588,6 +588,12 @@ produced, PDF schematics are easily found and it is easy to make. @* A JTAG driver acting as a client for the JTAG VPI server interface. @* Link: @url{http://github.com/fjullien/jtag_vpi} +@item @b{vdebug} +@* A driver for Cadence virtual Debug Interface to emulated or simulated targets. +It implements a client connecting to the vdebug server, which in turn communicates +with the emulated or simulated RTL model through a transactor. The current version +supports only JTAG as a transport, but other virtual transports, like DAP are planned. + @item @b{jtag_dpi} @* A JTAG driver acting as a client for the SystemVerilog Direct Programming Interface (DPI) for JTAG devices. DPI allows OpenOCD to connect to the JTAG @@ -3345,6 +3351,41 @@ This value is only used with the standard variant. @end deffn +@deffn {Interface Driver} {vdebug} +Cadence Virtual Debug Interface driver. + +@deffn {Config Command} {vdebug server} host:port +Specifies the host and TCP port number where the vdebug server runs. +@end deffn + +@deffn {Config Command} {vdebug batching} value +Specifies the batching method for the vdebug request. Possible values are +0 for no batching +1 or wr to batch write transactions together (default) +2 or rw to batch both read and write transactions +@end deffn + +@deffn {Config Command} {vdebug polling} min max +Takes two values, representing the polling interval in ms. Lower values mean faster +debugger responsiveness, but lower emulation performance. The minimum should be +around 10, maximum should not exceed 1000, which is the default gdb and keepalive +timeout value. +@end deffn + +@deffn {Config Command} {vdebug bfm_path} path clk_period +Specifies the hierarchical path and input clk period of the vdebug BFM in the design. +The hierarchical path uses Verilog notation top.inst.inst +The clock period must include the unit, for instance 40ns. +@end deffn + +@deffn {Config Command} {vdebug mem_path} path base size +Specifies the hierarchical path to the design memory instance for backdoor access. +Up to 4 memories can be specified. The hierarchical path uses Verilog notation. +The base specifies start address in the design address space, size its size in bytes. +Both values can use hexadecimal notation with prefix 0x. +@end deffn +@end deffn + @deffn {Interface Driver} {jtag_dpi} SystemVerilog Direct Programming Interface (DPI) compatible driver for JTAG devices in emulation. The driver acts as a client for the SystemVerilog diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index c2161523d..887f99bcd 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -75,6 +75,9 @@ endif if JTAG_VPI DRIVERFILES += %D%/jtag_vpi.c endif +if VDEBUG +DRIVERFILES += %D%/vdebug.c +endif if JTAG_DPI DRIVERFILES += %D%/jtag_dpi.c endif diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c new file mode 100644 index 000000000..a81740cb1 --- /dev/null +++ b/src/jtag/drivers/vdebug.c @@ -0,0 +1,1076 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ +/*---------------------------------------------------------------------------- + * Copyright 2020-2021 Cadence Design Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + *---------------------------------------------------------------------------- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *---------------------------------------------------------------------------- +*/ + +/*! + * @file + * + * @brief the virtual debug interface provides a connection between a sw debugger + * and the simulated, emulated core over a soft connection, implemented by DPI + * The vdebug debug driver currently supports JTAG transport + * TODO: implement support and test big endian platforms + * +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#ifdef HAVE_UNISTD_H +#include /* close */ +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#endif +#include +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include + +#include "jtag/interface.h" +#include "jtag/commands.h" +#include "transport/transport.h" +#include "helper/time_support.h" +#include "helper/replacements.h" +#include "helper/log.h" + +#define VD_VERSION 43 +#define VD_BUFFER_LEN 4024 +#define VD_CHEADER_LEN 24 +#define VD_SHEADER_LEN 16 + +#define VD_MAX_MEMORIES 4 +#define VD_POLL_INTERVAL 500 +#define VD_SCALE_PSTOMS 1000000000 + +/** + * @brief List of transactor types + */ +enum { + VD_BFM_JTDP = 0x0001, /* transactor DAP JTAG DP */ + VD_BFM_SWDP = 0x0002, /* transactor DAP SWD DP */ + VD_BFM_AHB = 0x0003, /* transactor AMBA AHB */ + VD_BFM_APB = 0x0004, /* transactor AMBA APB */ + VD_BFM_AXI = 0x0005, /* transactor AMBA AXI */ + VD_BFM_JTAG = 0x0006, /* transactor serial JTAG */ + VD_BFM_SWD = 0x0007, /* transactor serial SWD */ +}; + +/** + * @brief List of signals that can be read or written by the debugger + */ +enum { + VD_SIG_TCK = 0x0001, /* JTAG clock; tclk */ + VD_SIG_TDI = 0x0002, /* JTAG TDI; tdi */ + VD_SIG_TMS = 0x0004, /* JTAG TMS; tms */ + VD_SIG_RESET = 0x0008, /* DUT reset; rst */ + VD_SIG_TRST = 0x0010, /* JTAG Reset; trstn */ + VD_SIG_TDO = 0x0020, /* JTAG TDO; tdo */ + VD_SIG_POWER = 0x0100, /* BFM power; bfm_up */ + VD_SIG_TCKDIV = 0x0200, /* JTAG clock divider; tclkdiv */ + VD_SIG_BUF = 0x1000, /* memory buffer; mem */ +}; + +/** + * @brief List of errors + */ +enum { + VD_ERR_NONE = 0x0000, /* no error */ + VD_ERR_NOT_IMPL = 0x0100, /* feature not implemented */ + VD_ERR_USAGE = 0x0101, /* incorrect usage */ + VD_ERR_PARAM = 0x0102, /* incorrect parameter */ + VD_ERR_CONFIG = 0x0107, /* incorrect configuration */ + VD_ERR_NO_MEMORY = 0x0104, /* out of memory */ + VD_ERR_SHM_OPEN = 0x010a, /* cannot open shared memory */ + VD_ERR_SHM_MAP = 0x010b, /* cannot map shared memory */ + VD_ERR_SOC_OPEN = 0x011a, /* cannot open socket */ + VD_ERR_SOC_OPT = 0x011b, /* cannot set socket option */ + VD_ERR_SOC_ADDR = 0x011c, /* cannot resolve host address */ + VD_ERR_SOC_CONN = 0x011d, /* cannot connect to host */ + VD_ERR_SOC_SEND = 0x011e, /* error sending data on socket */ + VD_ERR_SOC_RECV = 0x011f, /* error receiving data from socket */ + VD_ERR_LOCKED = 0x0202, /* device locked */ + VD_ERR_NOT_RUN = 0x0204, /* transactor not running */ + VD_ERR_NOT_OPEN = 0x0205, /* transactor not open/connected */ + VD_ERR_LICENSE = 0x0206, /* cannot check out the license */ + VD_ERR_VERSION = 0x0207, /* transactor version mismatch */ + VD_ERR_TIME_OUT = 0x0301, /* time out, waiting */ + VD_ERR_NO_POWER = 0x0302, /* power out error */ + VD_ERR_BUS_ERROR = 0x0304, /* bus protocol error, like pslverr */ + VD_ERR_NO_ACCESS = 0x0306, /* no access to an object */ + VD_ERR_INV_HANDLE = 0x0307, /* invalid object handle */ + VD_ERR_INV_SCOPE = 0x0308, /* invalid scope */ +}; + +enum { + VD_CMD_OPEN = 0x01, + VD_CMD_CLOSE = 0x02, + VD_CMD_CONNECT = 0x04, + VD_CMD_DISCONNECT = 0x05, + VD_CMD_WAIT = 0x09, + VD_CMD_SIGSET = 0x0a, + VD_CMD_SIGGET = 0x0b, + VD_CMD_JTAGCLOCK = 0x0f, + VD_CMD_JTAGSHTAP = 0x1a, + VD_CMD_MEMOPEN = 0x21, + VD_CMD_MEMCLOSE = 0x22, + VD_CMD_MEMWRITE = 0x23, +}; + +enum { + VD_BATCH_NO = 0, + VD_BATCH_WO = 1, + VD_BATCH_WR = 2, +}; + +struct vd_shm { + struct { /* VD_CHEADER_LEN written by client */ + uint8_t cmd; /* 000; command */ + uint8_t type; /* 001; interface type */ + uint16_t waddr; /* 002; write pointer */ + uint16_t wbytes; /* 004; data bytes */ + uint16_t rbytes; /* 006; data bytes to read */ + uint16_t wwords; /* 008; data words */ + uint16_t rwords; /* 00a; data words to read */ + uint32_t rwdata; /* 00c; read/write data */ + uint32_t offset; /* 010; address offset */ + uint16_t offseth; /* 014; address offset 47:32 */ + uint16_t wid; /* 016; request id*/ + }; + union { /* 018; */ + uint8_t wd8[VD_BUFFER_LEN]; + uint16_t wd16[VD_BUFFER_LEN / 2]; + uint32_t wd32[VD_BUFFER_LEN / 4]; + uint64_t wd64[VD_BUFFER_LEN / 8]; + }; + struct { /* VD_SHEADER_LEN written by server */ + uint16_t rid; /* fd0: request id read */ + uint16_t awords; /* fd2: actual data words read back */ + int32_t status; /* fd4; */ + uint64_t duttime; /* fd8; */ + }; + union { /* fe0: */ + uint8_t rd8[VD_BUFFER_LEN]; + uint16_t rd16[VD_BUFFER_LEN / 2]; + uint32_t rd32[VD_BUFFER_LEN / 4]; + uint64_t rd64[VD_BUFFER_LEN / 8]; + }; + uint32_t state; /* 1f98; connection state */ + uint32_t count; /* 1f9c; */ + uint8_t dummy[96]; /* 1fa0; 48+40B+8B; */ +}; + +struct vd_client { + uint8_t trans_batch; + bool trans_first; + bool trans_last; + uint8_t mem_ndx; + uint8_t buf_width; + uint8_t addr_bits; + uint8_t bfm_type; + uint16_t sig_read; + uint16_t sig_write; + uint32_t bfm_period; + uint32_t mem_base[VD_MAX_MEMORIES]; + uint32_t mem_size[VD_MAX_MEMORIES]; + uint32_t mem_width[VD_MAX_MEMORIES]; + uint32_t mem_depth[VD_MAX_MEMORIES]; + uint16_t server_port; + uint32_t poll_cycles; + uint32_t poll_min; + uint32_t poll_max; + uint32_t targ_time; + int hsocket; + char server_name[32]; + char bfm_path[128]; + char mem_path[VD_MAX_MEMORIES][128]; + uint8_t *tdo; +}; + +struct vd_jtag_hdr { + uint64_t tlen:24; + uint64_t post:3; + uint64_t pre:3; + uint64_t cmd:2; + uint64_t wlen:16; + uint64_t rlen:16; +}; + +static struct vd_shm *pbuf; +static struct vd_client vdc; + +static int vdebug_socket_error(void) +{ +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +static int vdebug_socket_open(char *server_addr, uint32_t port) +{ + int hsock; + int rc = 0; + uint32_t buflen = sizeof(struct vd_shm); /* size of the send and rcv buffer */ + struct addrinfo *ainfo = NULL; + struct addrinfo ahint = { 0, AF_INET, SOCK_STREAM, 0, 0, NULL, NULL, NULL }; + +#ifdef _WIN32 + hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (hsock == INVALID_SOCKET) + rc = vdebug_socket_error(); +#else + uint32_t rcvwat = VD_SHEADER_LEN; /* size of the rcv header, as rcv min watermark */ + hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (hsock < 0) + rc = errno; + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVLOWAT, &rcvwat, sizeof(rcvwat)) < 0) + rc = errno; +#endif + else if (setsockopt(hsock, SOL_SOCKET, SO_SNDBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + else if (setsockopt(hsock, SOL_SOCKET, SO_RCVBUF, (const char *)&buflen, sizeof(buflen)) < 0) + rc = vdebug_socket_error(); + + if (rc) { + LOG_ERROR("socket_open: cannot set socket option, error %d", rc); + } else if (getaddrinfo(server_addr, NULL, &ahint, &ainfo) != 0) { + LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error()); + rc = VD_ERR_SOC_ADDR; + } else { + ((struct sockaddr_in *)(ainfo->ai_addr))->sin_port = htons(port); + if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) { + LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error()); + rc = VD_ERR_SOC_CONN; + } + } + + if (rc) { + close_socket(hsock); + hsock = 0; + } + + if (ainfo) + freeaddrinfo(ainfo); + + return hsock; +} + +static int vdebug_socket_receive(int hsock, struct vd_shm *pmem) +{ + int rc; + int dreceived = 0; + int offset = (uint8_t *)&pmem->rid - &pmem->cmd; + int to_receive = VD_SHEADER_LEN + pmem->rbytes; + char *pb = (char *)pmem; + + do { + rc = recv(hsock, pb + offset, to_receive, 0); + if (rc <= 0) { + LOG_WARNING("socket_receive: recv failed, error %d", rc < 0 ? vdebug_socket_error() : 0); + return rc; + } + to_receive -= rc; + offset += rc; + LOG_DEBUG_IO("socket_receive: received %d, to receive %d", rc, to_receive); + dreceived += rc; + } while (to_receive); + + return dreceived; +} + +static int vdebug_socket_send(int hsock, struct vd_shm *pmem) +{ + int rc = send(hsock, (const char *)&pmem->cmd, VD_CHEADER_LEN + pmem->wbytes, 0); + if (rc <= 0) + LOG_WARNING("socket_send: send failed, error %d", vdebug_socket_error()); + else + LOG_DEBUG_IO("socket_send: sent %d, to send 0", rc); + + return rc; +} + +static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem) +{ + if (!hsock) + return VD_ERR_SOC_OPEN; + int st = vdebug_socket_send(hsock, pmem); + if (st <= 0) + return VD_ERR_SOC_SEND; + + int rd = vdebug_socket_receive(hsock, pmem); + if (rd <= 0) + return VD_ERR_SOC_RECV; + + int rc = pmem->status; + LOG_DEBUG_IO("wait_server: cmd %02" PRIx8 " done, sent %d, rcvd %d, status %d", + pmem->cmd, st, rd, rc); + + return rc; +} + +int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) +{ + uint8_t num_pre, num_post, tdi, tms; + unsigned int num, anum, bytes, hwords, words; + unsigned int req, waddr, rwords; + int64_t ts, te; + uint8_t *tdo; + int rc; + struct vd_jtag_hdr *hdr; + + req = 0; /* beginning of request */ + waddr = 0; + rwords = 0; + pm->wbytes = pm->wwords * vdc.buf_width; + pm->rbytes = pm->rwords * vdc.buf_width; + ts = timeval_ms(); + rc = vdebug_wait_server(hsock, pm); + while (!rc && (req < count)) { /* loop over requests to read data and print out */ + hdr = (struct vd_jtag_hdr *)&pm->wd8[waddr * 4]; + hwords = hdr->wlen; + words = hdr->rlen; + anum = hdr->tlen; + num_pre = hdr->pre; + num_post = hdr->post; + if (num_post) + num = anum - num_pre - num_post + 1; + else + num = anum - num_pre; + bytes = (num + 7) / 8; + vdc.trans_last = (req + 1) < count ? 0 : 1; + vdc.trans_first = waddr ? 0 : 1; + if (hdr->cmd == 3) { /* read */ + tdo = vdc.tdo; + for (unsigned int j = 0; j < bytes; j++) { + tdo[j] = (pm->rd8[rwords * 8 + j] >> num_pre) | (pm->rd8[rwords * 8 + j + 1] << (8 - num_pre)); + LOG_DEBUG_IO("%04x D0[%02x]:%02x", pm->wid - count + req, j, tdo[j]); + } + rwords += words; /* read data offset */ + } else { + tdo = NULL; + } + waddr += sizeof(struct vd_jtag_hdr) / 4; /* waddr past header */ + tdi = (pm->wd8[waddr * 4] >> num_pre) | (pm->wd8[waddr * 4 + 1] << (8 - num_pre)); + tms = (pm->wd8[waddr * 4 + 4] >> num_pre) | (pm->wd8[waddr * 4 + 4 + 1] << (8 - num_pre)); + LOG_DEBUG("%04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x", + pm->wid - count + req, num, (vdc.trans_first << 14) | (vdc.trans_last << 15), + waddr - 2, tdi, tms, (tdo ? tdo[0] : 0xdd)); + waddr += hwords * 2; /* start of next request */ + req += 1; + } + + if (rc) { + LOG_ERROR("0x%x executing transaction", rc); + rc = ERROR_FAIL; + } + + te = timeval_ms(); + vdc.targ_time += (uint32_t)(te - ts); + pm->offseth = 0; /* reset buffer write address */ + pm->offset = 0; + pm->rwords = 0; + pm->waddr = 0; + + return rc; +} + +static int vdebug_open(int hsock, struct vd_shm *pm, const char *path, + uint8_t type, uint32_t period_ps, uint32_t sig_mask) +{ + int rc = VD_ERR_NOT_OPEN; + + pm->cmd = VD_CMD_OPEN; + pm->wid = VD_VERSION; /* client version */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + rc = vdebug_wait_server(hsock, pm); + if (rc != 0) { /* communication problem */ + LOG_ERROR("0x%x connecting to server", rc); + } else if (pm->rid < pm->wid) { + LOG_ERROR("server version %d too old for the client %d", pm->rid, pm->wid); + pm->cmd = VD_CMD_CLOSE; /* let server close the connection */ + vdebug_wait_server(hsock, pm); + rc = VD_ERR_VERSION; + } else { + pm->cmd = VD_CMD_CONNECT; + pm->type = type; /* BFM type to connect to, here JTAG */ + pm->rwdata = sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16); + pm->wbytes = strlen(path) + 1; + pm->rbytes = 12; + pm->wid = 0; /* reset wid for transaction ID */ + pm->wwords = 0; + pm->rwords = 0; + memcpy(pm->wd8, path, pm->wbytes + 1); + rc = vdebug_wait_server(hsock, pm); + vdc.sig_read = pm->rwdata >> 16; /* signal read mask */ + vdc.sig_write = pm->rwdata; /* signal write mask */ + vdc.bfm_period = period_ps; + vdc.buf_width = pm->rd32[0] / 8;/* access width in bytes */ + vdc.addr_bits = pm->rd32[2]; /* supported address bits */ + } + + if (rc) { + LOG_ERROR("0x%x connecting to BFM %s", rc, path); + return ERROR_FAIL; + } + + LOG_DEBUG("%s type %0x, period %dps, buffer %dx%dB signals r%04xw%04x", + path, type, vdc.bfm_period, VD_BUFFER_LEN / vdc.buf_width, + vdc.buf_width, vdc.sig_read, vdc.sig_write); + + return ERROR_OK; +} + +static int vdebug_close(int hsock, struct vd_shm *pm, uint8_t type) +{ + pm->cmd = VD_CMD_DISCONNECT; + pm->type = type; /* BFM type, here JTAG */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + pm->cmd = VD_CMD_CLOSE; + pm->wid = VD_VERSION; /* client version */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + LOG_DEBUG("type %0x", type); + + return ERROR_OK; +} + +static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles) +{ + if (cycles) { + pm->cmd = VD_CMD_WAIT; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = cycles; /* clock sycles to wait */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x waiting %" PRIx32 " cycles", rc, cycles); + return ERROR_FAIL; + } + LOG_DEBUG("%d cycles", cycles); + } + + return ERROR_OK; +} + +static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uint32_t value) +{ + pm->cmd = VD_CMD_SIGSET; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = (write_mask << 16) | (value & 0xffff); /* mask and value of signals to set */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x setting signals %04" PRIx32, rc, write_mask); + return ERROR_FAIL; + } + + LOG_DEBUG("setting signals %04" PRIx32 " to %04" PRIx32, write_mask, value); + + return ERROR_OK; +} + +static int vdebug_jtag_clock(int hsock, struct vd_shm *pm, uint32_t value) +{ + pm->cmd = VD_CMD_JTAGCLOCK; + pm->wbytes = 0; + pm->rbytes = 0; + pm->rwdata = value; /* divider value */ + int rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x setting jtag_clock", rc); + return ERROR_FAIL; + } + + LOG_DEBUG("setting jtag clock divider to %" PRIx32, value); + + return ERROR_OK; +} + +static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre, + const uint8_t tms_pre, uint32_t num, const uint8_t *tdi, + uint8_t num_post, const uint8_t tms_post, uint8_t *tdo, + uint8_t f_last) +{ + const uint32_t tobits = 8; + uint16_t bytes, hwords, anum, words, waddr; + int rc = 0; + + pm->cmd = VD_CMD_JTAGSHTAP; + vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO) || tdo; + if (vdc.trans_first) + waddr = 0; /* reset buffer offset */ + else + waddr = pm->offseth; /* continue from the previous transaction */ + if (num_post) /* actual number of bits to shift */ + anum = num + num_pre + num_post - 1; + else + anum = num + num_pre; + hwords = (anum + 4 * vdc.buf_width - 1) / (4 * vdc.buf_width); /* in 4B TDI/TMS words */ + words = (hwords + 1) / 2; /* in 8B TDO words to read */ + bytes = (num + 7) / 8; /* data only portion in bytes */ + /* buffer overflow check and flush */ + if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords + 64 > VD_BUFFER_LEN) { + vdc.trans_last = 1; /* force flush within 64B of buffer end */ + } else if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords > VD_BUFFER_LEN) { + /* this req does not fit, discard it */ + LOG_ERROR("%04x L:%02d O:%05x @%04x too many bits to shift", + pm->wid, anum, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr); + rc = ERROR_FAIL; + } + + if (!rc && anum) { + uint16_t i, j; + struct vd_jtag_hdr *hdr = (struct vd_jtag_hdr *)&pm->wd8[4 * waddr]; /* 8 bytes header */ + hdr->cmd = (tdo ? 3 : 1); /* R and W bits */ + hdr->pre = num_pre; + hdr->post = num_post; + hdr->tlen = anum; + hdr->wlen = hwords; + hdr->rlen = words; + pm->wid++; /* transaction ID */ + waddr += 2; /* waddr past header */ + /* TDI/TMS data follows as 32 bit word pairs {TMS,TDI} */ + pm->wd8[4 * waddr] = (tdi ? (tdi[0] << num_pre) : 0); + pm->wd8[4 * waddr + 4] = tms_pre; /* init with tms_pre */ + if (num + num_pre <= 8) /* and tms_post for num <=4 */ + pm->wd8[4 * waddr + 4] |= (tms_post << (num + num_pre - 1)); + for (i = 1, j = 4 * waddr; i < bytes; i++) { + if (i == bytes - 1 && num + num_pre <= bytes * tobits) + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); + else + pm->wd8[j + i + 4] = 0x0;/* placing 4 bytes of TMS bits into high word */ + if (!tdi) /* placing 4 bytes of TDI bits into low word */ + pm->wd8[j + i] = 0x0; + else + pm->wd8[j + i] = (tdi[i] << num_pre) | (tdi[i - 1] >> (8 - num_pre)); + if (i % 4 == 3) + j += 4; + } + + if (tdi) + if (num + num_pre > bytes * tobits) /* in case 1 additional byte needed for TDI */ + pm->wd8[j + i] = (tdi[i - 1] >> (8 - num_pre)); /* put last TDI bits there */ + + if (num + num_pre <= bytes * tobits) { /* in case no or 1 additional byte needed */ + pm->wd8[j + i + 4] = tms_post >> (8 - (num + num_pre - 1) % 8); /* may need to add higher part */ + /* in case exactly 1 additional byte needed */ + } else if (num + num_pre > bytes * tobits && anum <= (bytes + 1) * tobits) { + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); /* add whole tms_post */ + } else { /* in case 2 additional bytes, tms_post split */ + pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8);/* add lower part of tms_post */ + if (i % 4 == 3) /* next byte is in the next 32b word */ + pm->wd8[j + i + 4 + 5] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + else /* next byte is in the same 32b word */ + pm->wd8[j + i + 4 + 1] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */ + } + + if (tdo) { + pm->rwords += words; /* keep track of the words to read */ + vdc.tdo = tdo; + } + pm->wwords = waddr / 2 + hwords; /* payload size *2 to include both TDI and TMS data */ + pm->waddr++; + } + + if (!waddr) /* flush issued, but buffer empty */ + ; + else if (!vdc.trans_last) /* buffered request */ + pm->offseth = waddr + hwords * 2; /* offset for next transaction, must be even */ + else /* execute batch of requests */ + rc = vdebug_run_jtag_queue(hsock, pm, pm->waddr); + vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */ + + return rc; +} + +static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8_t ndx) +{ + int rc; + + if (!path) + return ERROR_OK; + + pm->cmd = VD_CMD_MEMOPEN; + pm->wbytes = strlen(path) + 1; /* includes terminating 0 */ + pm->rbytes = 8; + pm->wwords = 0; + pm->rwords = 0; + memcpy(pm->wd8, path, pm->wbytes); + rc = vdebug_wait_server(hsock, pm); + if (rc) { + LOG_ERROR("0x%x opening memory %s", rc, path); + } else if (ndx != pm->rd16[1]) { + LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd16[1]); + } else { + vdc.mem_width[ndx] = pm->rd16[0] / 8; /* memory width in bytes */ + vdc.mem_depth[ndx] = pm->rd32[1]; /* memory depth in words */ + LOG_DEBUG("%" PRIx8 ": %s memory %" PRIu32 "x%" PRIu32 "B, buffer %" PRIu32 "x%" PRIu32 "B", ndx, path, + vdc.mem_depth[ndx], vdc.mem_width[ndx], VD_BUFFER_LEN / vdc.mem_width[ndx], vdc.mem_width[ndx]); + } + + return ERROR_OK; +} + +static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) +{ + pm->cmd = VD_CMD_MEMCLOSE; + pm->rwdata = ndx; /* which memory */ + pm->wbytes = 0; + pm->rbytes = 0; + pm->wwords = 0; + pm->rwords = 0; + vdebug_wait_server(hsock, pm); + LOG_DEBUG("%" PRIx8 ": %s", ndx, vdc.mem_path[ndx]); +} + +static int vdebug_init(void) +{ + vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port); + pbuf = calloc(1, sizeof(struct vd_shm)); + if (!pbuf) { + close_socket(vdc.hsocket); + vdc.hsocket = 0; + LOG_ERROR("cannot allocate %lu bytes", sizeof(struct vd_shm)); + return ERROR_FAIL; + } + if (vdc.hsocket <= 0) { + free(pbuf); + pbuf = NULL; + LOG_ERROR("cannot connect to vdebug server %s:%" PRIu16, + vdc.server_name, vdc.server_port); + return ERROR_FAIL; + } + vdc.trans_first = 1; + vdc.poll_cycles = vdc.poll_max; + uint32_t sig_mask = VD_SIG_RESET | VD_SIG_TRST | VD_SIG_TCKDIV; + int rc = vdebug_open(vdc.hsocket, pbuf, vdc.bfm_path, vdc.bfm_type, vdc.bfm_period, sig_mask); + if (rc != 0) { + LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.bfm_path, rc); + close_socket(vdc.hsocket); + vdc.hsocket = 0; + free(pbuf); + pbuf = NULL; + } else { + for (uint8_t i = 0; i < vdc.mem_ndx; i++) { + rc = vdebug_mem_open(vdc.hsocket, pbuf, vdc.mem_path[i], i); + if (rc != 0) + LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.mem_path[i], rc); + } + + LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, + VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port); + } + + return rc; +} + +static int vdebug_quit(void) +{ + for (uint8_t i = 0; i < vdc.mem_ndx; i++) + if (vdc.mem_width[i]) + vdebug_mem_close(vdc.hsocket, pbuf, i); + int rc = vdebug_close(vdc.hsocket, pbuf, vdc.bfm_type); + LOG_INFO("vdebug %d disconnected from %s through %s:%" PRIu16 " rc:%d", VD_VERSION, + vdc.bfm_path, vdc.server_name, vdc.server_port, rc); + if (vdc.hsocket) + close_socket(vdc.hsocket); + free(pbuf); + pbuf = NULL; + + return ERROR_OK; +} + +static int vdebug_reset(int trst, int srst) +{ + uint16_t sig_val = 0xffff; + uint16_t sig_mask = 0; + + sig_mask |= VD_SIG_RESET; + if (srst) + sig_val &= ~VD_SIG_RESET;/* active low */ + if (transport_is_jtag()) { + sig_mask |= VD_SIG_TRST; + if (trst) + sig_val &= ~VD_SIG_TRST; /* active low */ + } + + LOG_INFO("rst trst:%d srst:%d mask:%" PRIx16 " val:%" PRIx16, trst, srst, sig_mask, sig_val); + int rc = vdebug_sig_set(vdc.hsocket, pbuf, sig_mask, sig_val); + if (rc == 0) + rc = vdebug_wait(vdc.hsocket, pbuf, 20); /* 20 clock cycles pulse */ + + return rc; +} + +static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush) +{ + LOG_INFO("tms len:%d tms:%x", num, *(const uint32_t *)tms); + + return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num, *tms, 0, NULL, 0, 0, NULL, f_flush); +} + +static int vdebug_jtag_path_move(struct pathmove_command *cmd, uint8_t f_flush) +{ + uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)]; + LOG_INFO("path num states %d", cmd->num_states); + + memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8)); + + for (uint8_t i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) + buf_set_u32(tms, i, 1, 1); + tap_set_state(cmd->path[i]); + } + + return vdebug_jtag_tms_seq(tms, cmd->num_states, f_flush); +} + +static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush) +{ + int rc = ERROR_OK; + + uint8_t cur = tap_get_state(); + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + LOG_INFO("tlr from %" PRIx8 " to %" PRIx8, cur, state); + if (cur != state) { + rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush); + tap_set_state(state); + } + + return rc; +} + +static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush) +{ + int rc = ERROR_OK; + + uint8_t cur = tap_get_state(); + uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT; + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + uint8_t tms_post = tap_get_tms_path(state, cmd->end_state); + uint8_t num_post = tap_get_tms_path_len(state, cmd->end_state); + int num_bits = jtag_scan_size(cmd); + LOG_DEBUG("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x", + num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state); + for (int i = 0; i < cmd->num_fields; i++) { + uint8_t cur_num_pre = i == 0 ? num_pre : 0; + uint8_t cur_tms_pre = i == 0 ? tms_pre : 0; + uint8_t cur_num_post = i == cmd->num_fields - 1 ? num_post : 0; + uint8_t cur_tms_post = i == cmd->num_fields - 1 ? tms_post : 0; + uint8_t cur_flush = i == cmd->num_fields - 1 ? f_flush : 0; + rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, cur_num_pre, cur_tms_pre, + cmd->fields[i].num_bits, cmd->fields[i].out_value, cur_num_post, cur_tms_post, + cmd->fields[i].in_value, cur_flush); + if (rc) + break; + } + + if (cur != cmd->end_state) + tap_set_state(cmd->end_state); + + return rc; +} + +static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush) +{ + uint8_t cur = tap_get_state(); + uint8_t tms_pre = tap_get_tms_path(cur, state); + uint8_t num_pre = tap_get_tms_path_len(cur, state); + LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state); + int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush); + if (cur != state) + tap_set_state(state); + + return rc; +} + +static int vdebug_jtag_stableclocks(int num, uint8_t f_flush) +{ + LOG_INFO("stab len:%d state cur:%x", num, tap_get_state()); + + return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush); +} + +static int vdebug_sleep(int us) +{ + LOG_INFO("sleep %d us", us); + + return vdebug_wait(vdc.hsocket, pbuf, us / 1000); +} + +static int vdebug_jtag_speed(int speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = clkmax / speed; + LOG_INFO("jclk speed:%d kHz set, BFM divider %u", speed, divval); + + return vdebug_jtag_clock(vdc.hsocket, pbuf, divval); +} + +static int vdebug_jtag_khz(int khz, int *jtag_speed) +{ + unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */ + unsigned int divval = khz ? clkmax / khz : 1; + *jtag_speed = clkmax / divval; + LOG_DEBUG("khz speed:%d from khz:%d", *jtag_speed, khz); + + return ERROR_OK; +} + +static int vdebug_jtag_div(int speed, int *khz) +{ + *khz = speed; + LOG_DEBUG("div khz:%d from speed:%d", *khz, speed); + + return ERROR_OK; +} + +static int vdebug_jtag_execute_queue(void) +{ + int rc = ERROR_OK; + + for (struct jtag_command *cmd = jtag_command_queue; rc == ERROR_OK && cmd; cmd = cmd->next) { + switch (cmd->type) { + case JTAG_RUNTEST: + rc = vdebug_jtag_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state, !cmd->next); + break; + case JTAG_STABLECLOCKS: + rc = vdebug_jtag_stableclocks(cmd->cmd.stableclocks->num_cycles, !cmd->next); + break; + case JTAG_TLR_RESET: + rc = vdebug_jtag_tlr(cmd->cmd.statemove->end_state, !cmd->next); + break; + case JTAG_PATHMOVE: + rc = vdebug_jtag_path_move(cmd->cmd.pathmove, !cmd->next); + break; + case JTAG_TMS: + rc = vdebug_jtag_tms_seq(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, !cmd->next); + break; + case JTAG_SLEEP: + rc = vdebug_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + rc = vdebug_jtag_scan(cmd->cmd.scan, !cmd->next); + break; + default: + LOG_ERROR("Unknown JTAG command type 0x%x encountered", cmd->type); + rc = ERROR_FAIL; + } + } + + return rc; +} + +COMMAND_HANDLER(vdebug_set_server) +{ + if ((CMD_ARGC != 1) || !strchr(CMD_ARGV[0], ':')) + return ERROR_COMMAND_SYNTAX_ERROR; + + char *pchar = strchr(CMD_ARGV[0], ':'); + *pchar = '\0'; + strncpy(vdc.server_name, CMD_ARGV[0], sizeof(vdc.server_name) - 1); + int port = atoi(++pchar); + if (port < 0 || port > UINT16_MAX) { + LOG_ERROR("invalid port number %d specified", port); + return ERROR_COMMAND_SYNTAX_ERROR; + } + vdc.server_port = port; + LOG_DEBUG("server: %s port %u", vdc.server_name, vdc.server_port); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_bfm) +{ + char prefix; + + if ((CMD_ARGC != 2) || (sscanf(CMD_ARGV[1], "%u%c", &vdc.bfm_period, &prefix) != 2)) + return ERROR_COMMAND_SYNTAX_ERROR; + + strncpy(vdc.bfm_path, CMD_ARGV[0], sizeof(vdc.bfm_path) - 1); + switch (prefix) { + case 'u': + vdc.bfm_period *= 1000000; + break; + case 'n': + vdc.bfm_period *= 1000; + break; + case 'p': + default: + break; + } + vdc.bfm_type = VD_BFM_JTAG; + LOG_DEBUG("bfm_path: %s clk_period %ups", vdc.bfm_path, vdc.bfm_period); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_mem) +{ + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (vdc.mem_ndx >= VD_MAX_MEMORIES) { + LOG_ERROR("mem_path declared more than %d allowed times", VD_MAX_MEMORIES); + return ERROR_FAIL; + } + + strncpy(vdc.mem_path[vdc.mem_ndx], CMD_ARGV[0], sizeof(vdc.mem_path[vdc.mem_ndx]) - 1); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], vdc.mem_base[vdc.mem_ndx]); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vdc.mem_size[vdc.mem_ndx]); + LOG_DEBUG("mem_path: set %s @ 0x%08x+0x%08x", vdc.mem_path[vdc.mem_ndx], + vdc.mem_base[vdc.mem_ndx], vdc.mem_size[vdc.mem_ndx]); + vdc.mem_ndx++; + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_batching) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (isdigit((unsigned char)CMD_ARGV[0][0])) + vdc.trans_batch = (CMD_ARGV[0][0] == '0' ? 0 : (CMD_ARGV[0][0] == '1' ? 1 : 2)); + else if (CMD_ARGV[0][0] == 'r') + vdc.trans_batch = VD_BATCH_WR; + else if (CMD_ARGV[0][0] == 'w') + vdc.trans_batch = VD_BATCH_WO; + else + vdc.trans_batch = VD_BATCH_NO; + LOG_DEBUG("batching: set to %u", vdc.trans_batch); + + return ERROR_OK; +} + +COMMAND_HANDLER(vdebug_set_polling) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + vdc.poll_min = atoi(CMD_ARGV[0]); + vdc.poll_max = atoi(CMD_ARGV[1]); + LOG_DEBUG("polling: set min %u max %u", vdc.poll_min, vdc.poll_max); + + return ERROR_OK; +} + +static const struct command_registration vdebug_command_handlers[] = { + { + .name = "server", + .handler = &vdebug_set_server, + .mode = COMMAND_CONFIG, + .help = "set the vdebug server name or address", + .usage = "", + }, + { + .name = "bfm_path", + .handler = &vdebug_set_bfm, + .mode = COMMAND_CONFIG, + .help = "set the vdebug BFM hierarchical path", + .usage = " ", + }, + { + .name = "mem_path", + .handler = &vdebug_set_mem, + .mode = COMMAND_ANY, + .help = "set the design memory for the code load", + .usage = " ", + }, + { + .name = "batching", + .handler = &vdebug_set_batching, + .mode = COMMAND_CONFIG, + .help = "set the transaction batching no|wr|rd [0|1|2]", + .usage = "", + }, + { + .name = "polling", + .handler = &vdebug_set_polling, + .mode = COMMAND_CONFIG, + .help = "set the polling pause, executing hardware cycles between min and max", + .usage = " ", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration vdebug_command[] = { + { + .name = "vdebug", + .chain = vdebug_command_handlers, + .mode = COMMAND_ANY, + .help = "vdebug command group", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface vdebug_jtag_ops = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = vdebug_jtag_execute_queue, +}; + +struct adapter_driver vdebug_adapter_driver = { + .name = "vdebug", + .transports = jtag_only, + .speed = vdebug_jtag_speed, + .khz = vdebug_jtag_khz, + .speed_div = vdebug_jtag_div, + .commands = vdebug_command, + .init = vdebug_init, + .quit = vdebug_quit, + .reset = vdebug_reset, + .jtag_ops = &vdebug_jtag_ops, +}; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 63faa9561..ddf70cc24 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -57,6 +57,9 @@ extern struct adapter_driver usb_blaster_adapter_driver; #if BUILD_JTAG_VPI == 1 extern struct adapter_driver jtag_vpi_adapter_driver; #endif +#if BUILD_VDEBUG == 1 +extern struct adapter_driver vdebug_adapter_driver; +#endif #if BUILD_JTAG_DPI == 1 extern struct adapter_driver jtag_dpi_adapter_driver; #endif @@ -168,6 +171,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_JTAG_VPI == 1 &jtag_vpi_adapter_driver, #endif +#if BUILD_VDEBUG == 1 + &vdebug_adapter_driver, +#endif #if BUILD_JTAG_DPI == 1 &jtag_dpi_adapter_driver, #endif diff --git a/tcl/board/vd_a53x2_jtag.cfg b/tcl/board/vd_a53x2_jtag.cfg new file mode 100644 index 000000000..869bc4db0 --- /dev/null +++ b/tcl/board/vd_a53x2_jtag.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex A53x2 through JTAG + +source [find interface/vdebug.cfg] + +set _CORES 2 +set _CHIPNAME a53 +set _MEMSTART 0x00000000 +set _MEMSIZE 0x1000000 +set _CPUTAPID 0x5ba00477 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.u_memory.mem_array $_MEMSTART $_MEMSIZE + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_aarch64.cfg] diff --git a/tcl/board/vd_m4_jtag.cfg b/tcl/board/vd_m4_jtag.cfg new file mode 100644 index 000000000..ca21476d2 --- /dev/null +++ b/tcl/board/vd_m4_jtag.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm Cortex m4 through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME m4 +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 +set _CPUTAPID 0x4ba00477 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 25000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 20ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.u_mcu.u_sys.u_rom.rom $_MEMSTART $_MEMSIZE + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_cortex_m.cfg] diff --git a/tcl/board/vd_pulpissimo_jtag.cfg b/tcl/board/vd_pulpissimo_jtag.cfg new file mode 100644 index 000000000..69dd9e6db --- /dev/null +++ b/tcl/board/vd_pulpissimo_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV Ibex core with Pulpissimo through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME ibex +set _HARTID 0x20 +set _CPUTAPID 0x249511c3 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 12500 +adapter srst delay 10 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 40ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[0\].sram_i.mem_array 0x1c000000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_array 0x1c008000 0x8000 +vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] diff --git a/tcl/board/vd_swerv_jtag.cfg b/tcl/board/vd_swerv_jtag.cfg new file mode 100644 index 000000000..ff6c6835f --- /dev/null +++ b/tcl/board/vd_swerv_jtag.cfg @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV swerv core with Swerv through JTAG + +source [find interface/vdebug.cfg] + +set _CHIPNAME rv32 +set _HARTID 0x00 +set _CPUTAPID 0x1000008b +set _MEMSTART 0x00000000 +set _MEMSIZE 0x10000 + +# vdebug select transport +#transport select jtag + +# JTAG reset config, frequency and reset delay +reset_config trst_and_srst +adapter speed 50000 +adapter srst delay 5 + +# BFM hierarchical path and input clk period +vdebug bfm_path tbench.u_vd_jtag_bfm 10ns + +# DMA Memories to access backdoor (up to 4) +vdebug mem_path tbench.i_ahb_ic.mem $_MEMSTART $_MEMSIZE + +# need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 +jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x01 -irmask 0x1f -expected-id $_CPUTAPID + +jtag arp_init-reset + +source [find target/vd_riscv.cfg] diff --git a/tcl/interface/vdebug.cfg b/tcl/interface/vdebug.cfg new file mode 100644 index 000000000..9cca6aaab --- /dev/null +++ b/tcl/interface/vdebug.cfg @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface + +if { [info exists VDEBUGHOST] } { + set _VDEBUGHOST $VDEBUGHOST +} else { + set _VDEBUGHOST localhost +} +if { [info exists VDEBUGPORT] } { + set _VDEBUGPORT $VDEBUGPORT +} else { + set _VDEBUGPORT 8192 +} + +adapter driver vdebug +# vdebug server:port +vdebug server $_VDEBUGHOST:$_VDEBUGPORT + +# example config debug level and log +#debug_level 3 +#log_output vd_ocd.log + +# example config listen on all interfaces, disable tcl/telnet server +bindto 0.0.0.0 +#gdb_port 3333 +#telnet_port disabled +tcl_port disabled + +# transaction batching: 0 - no batching, 1 - (default) wr, 2 - rw +vdebug batching 1 + +# Polling values +vdebug polling 100 1000 \ No newline at end of file diff --git a/tcl/target/vd_aarch64.cfg b/tcl/target/vd_aarch64.cfg new file mode 100644 index 000000000..619134aa6 --- /dev/null +++ b/tcl/target/vd_aarch64.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# Arm v8 64b Cortex A + +if {![info exists _CORES]} { + set _CORES 1 +} +if {![info exists _CHIPNAME]} { + set _CHIPNAME aarch64 +} +set _TARGETNAME $_CHIPNAME.cpu +set _CTINAME $_CHIPNAME.cti + +set DBGBASE {0x80810000 0x80910000} +set CTIBASE {0x80820000 0x80920000} + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME +$_CHIPNAME.dap apsel 1 + +for { set _core 0 } { $_core < $_CORES } { incr _core } \ +{ + cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $CTIBASE $_core] + set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ + -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core -coreid $_core" + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command $_TARGETNAME.$_core" + } else { + set _smp_command "target smp $_TARGETNAME.$_core" + } + eval $_command +} +eval $_smp_command + +# default target is core 0 +targets $_TARGETNAME.0 diff --git a/tcl/target/vd_cortex_m.cfg b/tcl/target/vd_cortex_m.cfg new file mode 100644 index 000000000..4d7b0df26 --- /dev/null +++ b/tcl/target/vd_cortex_m.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# ARM Cortex M + +if {![info exists _CHIPNAME]} { + set _CHIPNAME cortex_m +} +set _TARGETNAME $_CHIPNAME.cpu + +dap create $_CHIPNAME.dap -chain-position $_TARGETNAME + +target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap diff --git a/tcl/target/vd_riscv.cfg b/tcl/target/vd_riscv.cfg new file mode 100644 index 000000000..b42b25a3a --- /dev/null +++ b/tcl/target/vd_riscv.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Cadence virtual debug interface +# RISCV core + +if {![info exists _HARTID]} { + set _HARTID 0x00 +} +if {![info exists _CHIPNAME]} { + set _CHIPNAME riscv +} +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID + +riscv set_reset_timeout_sec 120 +riscv set_command_timeout_sec 120 +# prefer to use sba for system bus access +riscv set_prefer_sba on From 7307fd0e3faa7b3e060a722775c532bcb7f70057 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Thu, 27 Jan 2022 14:30:58 -0800 Subject: [PATCH 12/79] gdb_server: Include thread name as XML attribute Explicitly providing a thread name in the "thread" element produces better thread visualizations in downstream tools like IDEs. Signed-off-by: Ben McMorran Change-Id: I102c14ddb8b87757fa474de8e3a3f6a1cfe10d98 Reviewed-on: https://review.openocd.org/c/openocd/+/6828 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 537670c52..95720e561 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2619,8 +2619,14 @@ static int gdb_generate_thread_list(struct target *target, char **thread_list_ou if (!thread_detail->exists) continue; - xml_printf(&retval, &thread_list, &pos, &size, - "", thread_detail->threadid); + if (thread_detail->thread_name_str) + xml_printf(&retval, &thread_list, &pos, &size, + "", + thread_detail->threadid, + thread_detail->thread_name_str); + else + xml_printf(&retval, &thread_list, &pos, &size, + "", thread_detail->threadid); if (thread_detail->thread_name_str) xml_printf(&retval, &thread_list, &pos, &size, From 2c0a65baa2f17a15fcb5bb014e5dda33fecddaf8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 27 Jan 2022 10:00:06 -0800 Subject: [PATCH 13/79] Fix small memory leak. See https://github.com/riscv/riscv-openocd/pull/672 Change-Id: Ia11ab9bcf860f770ea64ad867102c74b898f6b66 Signed-off-by: Tim Newsome Reviewed-on: https://review.openocd.org/c/openocd/+/6831 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Antonio Borneo --- src/target/riscv/riscv-013.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 7af460241..2b9179d53 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2308,9 +2308,11 @@ static int init_target(struct command_context *cmd_ctx, generic_info->hart_count = &riscv013_hart_count; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; - generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); - if (!generic_info->version_specific) - return ERROR_FAIL; + if (!generic_info->version_specific) { + generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); + if (!generic_info->version_specific) + return ERROR_FAIL; + } generic_info->sample_memory = sample_memory; riscv013_info_t *info = get_info(target); From 37d506ae55587ecb6f20f56bc9b5a6f5edc1872f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 2 Feb 2022 23:55:50 +0100 Subject: [PATCH 14/79] server: remove remaining crust from dropped eCos code Commit 39650e2273bc ("ecosboard: delete bit-rotted eCos code") has removed eCos code but has left some empty function that was used during non-eCos build to replace eCos mutex. Drop the functions and the file that contain them. Change-Id: I31bc0237ea699c11bd70921660f960ee406ffa80 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6835 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/Makefile.am | 1 - src/server/server.c | 2 -- src/server/server.h | 9 --------- src/server/server_stubs.c | 30 ------------------------------ 4 files changed, 42 deletions(-) delete mode 100644 src/server/server_stubs.c diff --git a/src/server/Makefile.am b/src/server/Makefile.am index fb5248bfd..e3699f181 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -6,7 +6,6 @@ noinst_LTLIBRARIES += %D%/libserver.la %D%/server.h \ %D%/telnet_server.h \ %D%/gdb_server.h \ - %D%/server_stubs.c \ %D%/tcl_server.c \ %D%/tcl_server.h \ %D%/rtt_server.c \ diff --git a/src/server/server.c b/src/server/server.c index 3f579bfc6..1569f5a2c 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -487,10 +487,8 @@ int server_loop(struct command_context *command_context) timeout_ms = polling_period; tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ - openocd_sleep_prelude(); kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); - openocd_sleep_postlude(); } if (retval == -1) { diff --git a/src/server/server.h b/src/server/server.h index de18d2b4b..bacd1116a 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -97,15 +97,6 @@ int server_register_commands(struct command_context *context); int connection_write(struct connection *connection, const void *data, int len); int connection_read(struct connection *connection, void *data, int len); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_prelude(void); -/** - * Used by server_loop(), defined in server_stubs.c - */ -void openocd_sleep_postlude(void); - /** * Defines an extended command handler function declaration to enable * access to (and manipulation of) the server port number. diff --git a/src/server/server_stubs.c b/src/server/server_stubs.c deleted file mode 100644 index a4c017289..000000000 --- a/src/server/server_stubs.c +++ /dev/null @@ -1,30 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2009 Zachary T Welch * - * * - * 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 -#endif -#include "server.h" - -void openocd_sleep_prelude(void) -{ - /* no-op */ -} -void openocd_sleep_postlude(void) -{ - /* no-op */ -} From 254883597f2487f6e75e10c36991149679e21870 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Thu, 27 Jan 2022 14:45:16 -0800 Subject: [PATCH 15/79] rtos: threadx: Add hla_target support for ThreadX Tested with an AZ3166 dev board (which uses the STM32F412ZGT6) running the Azure RTOS ThreadX demonstration system. Signed-off-by: Ben McMorran Change-Id: I44c8f7701d9f1aaa872274166321cd7d34fb1855 Reviewed-on: https://review.openocd.org/c/openocd/+/6829 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/ThreadX.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 441b7abc5..4161e63fa 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -175,6 +175,18 @@ static const struct threadx_params threadx_params_list[] = { get_stacking_info_arm926ejs, /* fn_get_stacking_info */ is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */ }, + { + "hla_target", /* target_name */ + 4, /* pointer_width; */ + 8, /* thread_stack_offset; */ + 40, /* thread_name_offset; */ + 48, /* thread_state_offset; */ + 136, /* thread_next_offset */ + &rtos_standard_cortex_m3_stacking, /* stacking_info */ + 1, /* stacking_info_nb */ + NULL, /* fn_get_stacking_info */ + NULL, /* fn_is_thread_id_valid */ + }, }; enum threadx_symbol_values { From 94e7535be85a7bd5905dec68b6eae9a98aae0d7e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 2 Feb 2022 13:46:46 +0100 Subject: [PATCH 16/79] .gitmodules: switch away from repo.or.cz The host repo.or.cz is often offline, creating issues for cloning and building OpenOCD from scratch. Already 'jimtcl' developer has dropped repo.or.cz, triggering the OpenOCD commit 861e75f54efb ("jimtcl: switch to github"). Change also the link of the remaining submodules 'git2cl' and 'libjaylink' to their respective main repository. Change-Id: Ib513237427635359ce36a480a8f2060e2fb12ba4 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6834 Tested-by: jenkins Reviewed-by: zapb --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 23ffa2543..f2da17ed7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "tools/git2cl"] path = tools/git2cl - url = https://repo.or.cz/git2cl.git + url = https://git.savannah.nongnu.org/git/git2cl.git [submodule "jimtcl"] path = jimtcl url = https://github.com/msteveb/jimtcl.git [submodule "src/jtag/drivers/libjaylink"] path = src/jtag/drivers/libjaylink - url = https://repo.or.cz/libjaylink.git + url = https://gitlab.zapb.de/libjaylink/libjaylink.git From 29912328f07d562281e8a0db8855c8362afba546 Mon Sep 17 00:00:00 2001 From: Simon Johansson Date: Mon, 17 Jan 2022 13:30:59 +0100 Subject: [PATCH 17/79] flash/nor/stm32f2x: Fix erase of bank 2 sectors This commit corrects the erase function for stm32f2x when dealing with sectors in bank 2, for STM32F42x/43x devices with 1MB flash. On STM32F42x/43x with 1MB flash in dual bank configuration, the sector numbering is not consecutive. The last sector in bank 1 is number 7, and the first sector in bank 2 is number 12. The sector indices used by openocd, however, _are_ consecutive (0 to 15 in this case). The arguments "first" and "last" to stm32x_erase() are of this type, and so the logic surrounding sector numbers needed to be corrected. Since the two banks in dual bank mode have the same number of sectors, a sector index in bank 2 is larger than or equal to half the total number of sectors. Change-Id: I15260f8a86d9002769a1ae1c40ebdf62142dae18 Signed-off-by: Simon Johansson Reviewed-on: https://review.openocd.org/c/openocd/+/6810 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f2x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index d3e7d709c..aa0363232 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -636,8 +636,8 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, for (unsigned int i = first; i <= last; i++) { unsigned int snb; - if (stm32x_info->has_large_mem && i >= 12) - snb = (i - 12) | 0x10; + if (stm32x_info->has_large_mem && i >= (bank->num_sectors / 2)) + snb = (i - (bank->num_sectors / 2)) | 0x10; else snb = i; From 10b5ac9ccb2b51b5aad01e4cb02be84fea3ebc62 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 24 Nov 2021 19:05:21 +0100 Subject: [PATCH 18/79] target/cortex_m: fix target_to_cm() helper The third parameter of container_of() should point to the same member as target->arch_info points to, struct arm. It worked just because struct arm is the first member in struct armv7m_common. If you move arm member from the first place, OpenOCD fails heavily. Change-Id: I0c0a5221490945563e17a0a34d99a603f1d6c2ff Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6749 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/cortex_m.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index c2f836a35..cabe405ce 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -251,7 +251,7 @@ static inline struct cortex_m_common * target_to_cm(struct target *target) { return container_of(target->arch_info, - struct cortex_m_common, armv7m); + struct cortex_m_common, armv7m.arm); } static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) From e4ba76a003ce4a2336eade806a04a278c376d0b6 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 24 Nov 2021 22:11:13 +0100 Subject: [PATCH 19/79] target/armv7m,cortex_m: introduce checked arch_info cast routines target_to_armv7m() and target_to_cm() do not match the magic number so they are not suitable for use outside of target driver code. Add checked versions of pointer getters. Match the magic number to ensure the returned value points to struct of the correct type. Change-Id: If90ef7e969ef04f0f2103e0da29dcbe8e1ac1c0d Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6750 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/armv7m.h | 37 +++++++++++++++++++++++++++++++++++-- src/target/cortex_m.h | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/target/armv7m.h b/src/target/armv7m.h index d33e57492..9ac121ac3 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -255,15 +255,48 @@ struct armv7m_common { void (*pre_restore_context)(struct target *target); }; +static inline bool is_armv7m(const struct armv7m_common *armv7m) +{ + return armv7m->common_magic == ARMV7M_COMMON_MAGIC; +} + +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ static inline struct armv7m_common * target_to_armv7m(struct target *target) { return container_of(target->arch_info, struct armv7m_common, arm); } -static inline bool is_armv7m(const struct armv7m_common *armv7m) +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct armv7m_common * +target_to_armv7m_safe(struct target *target) { - return armv7m->common_magic == ARMV7M_COMMON_MAGIC; + if (!target) + return NULL; + + if (!target->arch_info) + return NULL; + + /* Check the parent type first to prevent peeking memory too far + * from arch_info pointer */ + if (!is_arm(target_to_arm(target))) + return NULL; + + struct armv7m_common *armv7m = target_to_armv7m(target); + if (!is_armv7m(armv7m)) + return NULL; + + return armv7m; } struct armv7m_algorithm { diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index cabe405ce..8fb34f46c 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -247,13 +247,6 @@ struct cortex_m_common { bool maskints_erratum; }; -static inline struct cortex_m_common * -target_to_cm(struct target *target) -{ - return container_of(target->arch_info, - struct cortex_m_common, armv7m.arm); -} - static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) { return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC; @@ -267,6 +260,40 @@ static inline bool is_cortex_m_with_dap_access(const struct cortex_m_common *cor return !cortex_m->armv7m.is_hla_target; } +/** + * @returns the pointer to the target specific struct + * without matching a magic number. + * Use in target specific service routines, where the correct + * type of arch_info is certain. + */ +static inline struct cortex_m_common * +target_to_cm(struct target *target) +{ + return container_of(target->arch_info, + struct cortex_m_common, armv7m.arm); +} + +/** + * @returns the pointer to the target specific struct + * or NULL if the magic number does not match. + * Use in a flash driver or any place where mismatch of the arch_info + * type can happen. + */ +static inline struct cortex_m_common * +target_to_cortex_m_safe(struct target *target) +{ + /* Check the parent types first to prevent peeking memory too far + * from arch_info pointer */ + if (!target_to_armv7m_safe(target)) + return NULL; + + struct cortex_m_common *cortex_m = target_to_cm(target); + if (!is_cortex_m_or_hla(cortex_m)) + return NULL; + + return cortex_m; +} + int cortex_m_examine(struct target *target); int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); From b53f5c257185e5410622ed72790affb1bda88248 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 25 Nov 2021 06:13:31 +0100 Subject: [PATCH 20/79] target/cortex_m: add Cortex-M part number getter The getter checks the magic numbers in arch_info to detect eventual type mismatch. Change-Id: I61134b05310a97ae9831517d0516c7b4240d35a5 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6751 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tarek BOCHKATI --- src/target/cortex_m.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 8fb34f46c..555401416 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -46,6 +46,7 @@ #define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) enum cortex_m_partno { + CORTEX_M_PARTNO_INVALID, CORTEX_M0_PARTNO = 0xC20, CORTEX_M1_PARTNO = 0xC21, CORTEX_M3_PARTNO = 0xC23, @@ -294,6 +295,23 @@ target_to_cortex_m_safe(struct target *target) return cortex_m; } +/** + * @returns cached value of Cortex-M part number + * or CORTEX_M_PARTNO_INVALID if the magic number does not match + * or core_info is not initialised. + */ +static inline enum cortex_m_partno cortex_m_get_partno_safe(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); + if (!cortex_m) + return CORTEX_M_PARTNO_INVALID; + + if (!cortex_m->core_info) + return CORTEX_M_PARTNO_INVALID; + + return cortex_m->core_info->partno; +} + int cortex_m_examine(struct target *target); int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); From 13cd75b6ecfd8d9cf04e56b182b6a162ad50247c Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 25 Nov 2021 06:24:52 +0100 Subject: [PATCH 21/79] flash/nor/stm32xx: fix segfault accessing Cortex-M part number Some of STM32 flash drivers read Cortex-M part number from cortex_m->core_info. In corner cases the core_info pointer was observed uninitialised even if target_was_examined() returned true. See also [1] Use the new and safe helper to get Cortex-M part number. While on it switch also target_to_cm()/target_to_armv7m() to the safe versions. This prevents a crash when the flash bank is misconfigured with non-Cortex-M target. Add missing checks for target_was_examined() to flash probes. [1] 6545: fix crash in case cortex_m->core_info is not set https://review.openocd.org/c/openocd/+/6545 Change-Id: If2471af74ebfe22f14442f48ae109b2e1bb5fa3b Signed-off-by: Tomas Vanek Fixes: f5898bd93ff8 (flash/stm32fxx.c: do not read CPUID as this info is stored in cortex_m_common) Reviewed-on: https://review.openocd.org/c/openocd/+/6752 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 10 ++++------ src/flash/nor/stm32f2x.c | 9 +++++++-- src/flash/nor/stm32h7x.c | 9 +++++++-- src/flash/nor/stm32l4x.c | 27 +++++++++++++++++++++------ 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 90cee6412..29a3b7e06 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -622,15 +622,14 @@ cleanup: static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t device_id_register = 0; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m->core_info->partno) { + switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ device_id_register = 0x40015800; break; @@ -659,15 +658,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); uint32_t flash_size_reg; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); - return ERROR_FAIL; + return ERROR_TARGET_NOT_EXAMINED; } - switch (cortex_m->core_info->partno) { + switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ flash_size_reg = 0x1FFFF7CC; break; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index aa0363232..58edca7e1 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -966,14 +966,14 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) * Only effects Rev A silicon */ struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, device_id); if (retval != ERROR_OK) return retval; - if ((*device_id & 0xfff) == 0x411 && cortex_m->core_info->partno == CORTEX_M4_PARTNO) { + if ((*device_id & 0xfff) == 0x411 + && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) { *device_id &= ~((0xFFFF << 16) | 0xfff); *device_id |= (0x1000 << 16) | 0x413; LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); @@ -1011,6 +1011,11 @@ static int stm32x_probe(struct flash_bank *bank) bank->num_prot_blocks = 0; bank->prot_blocks = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + /* if explicitly called out as OTP bank, short circuit probe */ if (stm32x_is_otp(bank)) { if (stm32x_otp_is_f7(bank)) { diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index d3f17b2b1..6d3149f94 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -759,7 +759,6 @@ static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; - struct cortex_m_common *cortex_m = target_to_cm(target); struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint16_t flash_size_in_kb; uint32_t device_id; @@ -767,6 +766,11 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->probed = false; stm32x_info->part_info = NULL; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); if (retval != ERROR_OK) return retval; @@ -800,7 +804,8 @@ static int stm32x_probe(struct flash_bank *bank) /* get flash size from target */ /* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */ retval = ERROR_FAIL; - if (device_id == DEVID_STM32H74_H75XX && cortex_m->core_info->partno == CORTEX_M4_PARTNO) + if (device_id == DEVID_STM32H74_H75XX + && cortex_m_get_partno_safe(target) == CORTEX_M4_PARTNO) LOG_WARNING("%s cannot read the flash size register", target_name(target)); else retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb); diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index e5100a015..fa8924ed3 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1633,12 +1633,13 @@ err_lock: static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { int retval; + struct target *target = bank->target; /* try reading possible IDCODE registers, in the following order */ uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5}; for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) { - retval = target_read_u32(bank->target, dbgmcu_idcode[i], id); + retval = target_read_u32(target, dbgmcu_idcode[i], id); if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff)) return ERROR_OK; } @@ -1647,12 +1648,16 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1, * to solve this read the UID64 (IEEE 64-bit unique device ID register) */ - struct cortex_m_common *cortex_m = target_to_cm(bank->target); + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1. * Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */ - if (cortex_m->core_info->partno == CORTEX_M0P_PARTNO && - cortex_m->armv7m.debug_ap && cortex_m->armv7m.debug_ap->ap_num == 1) { + if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO && + armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) { uint32_t uid64_ids; /* UID64 is contains @@ -1662,7 +1667,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) * * read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx */ - retval = target_read_u32(bank->target, UID64_IDS, &uid64_ids); + retval = target_read_u32(target, UID64_IDS, &uid64_ids); if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) { /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */ *id = DEVID_STM32WLE_WL5XX; @@ -1700,11 +1705,21 @@ static const char *get_stm32l4_bank_type_str(struct flash_bank *bank) static int stm32l4_probe(struct flash_bank *bank) { struct target *target = bank->target; - struct armv7m_common *armv7m = target_to_armv7m(target); struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; const struct stm32l4_part_info *part_info; uint16_t flash_size_kb = 0xffff; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct armv7m_common *armv7m = target_to_armv7m_safe(target); + if (!armv7m) { + LOG_ERROR("Flash requires Cortex-M target"); + return ERROR_TARGET_INVALID; + } + stm32l4_info->probed = false; /* read stm32 device id registers */ From d673521c39dcf82ce4c2e6d9d4dcdc7460c09fbe Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:40:24 -0500 Subject: [PATCH 22/79] cpld: altera-epm240: Add additional IDCODEs This adds some additional IDCODEs from the datasheet. It also adds support for customizing the tap name. Signed-off-by: Sean Anderson Change-Id: I7cda10b92c229b61836c12cd9ca410de358ede2e Reviewed-on: https://review.openocd.org/c/openocd/+/6846 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/cpld/altera-epm240.cfg | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg index 62f2b73b7..6e10188ca 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -1,6 +1,19 @@ # Altera MAXII EPM240T100C CPLD + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME epm240 +} + # see MAX II Device Handbook # Table 3-3: 32-Bit MAX II Device IDCODE # Version Part Number Manuf. ID LSB # 0000 0010 0000 1010 0001 000 0110 1110 1 -jtag newtap epm240 tap -expected-id 0x020a10dd -irlen 10 +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020a10dd \ + -expected-id 0x020a20dd \ + -expected-id 0x020a30dd \ + -expected-id 0x020a40dd \ + -expected-id 0x020a50dd \ + -expected-id 0x020a60dd From b61eae1962f008627f4593cfda9b3431e4c3c016 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:43:30 -0500 Subject: [PATCH 23/79] cpld: altera-epm240: Increase adapter speed According to the datasheet, the minimum clock period with Vccio1 = 1.5V (the lowest voltage supported) is 143ns, or around 6MHz. Set the default adapter speed to 5 MHz. Signed-off-by: Sean Anderson Change-Id: I21cad33fa7f1e25e81f43b5d2214d1fa4ec924de Reviewed-on: https://review.openocd.org/c/openocd/+/6847 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/cpld/altera-epm240.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg index 6e10188ca..ece02bbef 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -17,3 +17,7 @@ jtag newtap $_CHIPNAME tap -irlen 10 \ -expected-id 0x020a40dd \ -expected-id 0x020a50dd \ -expected-id 0x020a60dd + +# 200ns seems like a good speed +# c.f. Table 5-34: MAX II JTAG Timing Parameters +adapter speed 5000 From 3fcfe4f196f6c333ee0ba2078af9cfa3eb896761 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:45:32 -0500 Subject: [PATCH 24/79] target: Add support for ls1088a The LS1088A is an octo-core aarch64 processor from NXP in the layerscape family. The JTAG is undocumented, but I was able to figure things out from the output of `dap info`. This is the first in-tree example of using the hwthread rtos (as far as I know), so hopefully it can serve as an example to other developers. There are some ETMs, but I was unable to try them out because I got 'invalid command name "etm"' when trying to test things out. Signed-off-by: Sean Anderson Change-Id: I9b0791d27d8c41170a413a8d86431107a85feba2 Reviewed-on: https://review.openocd.org/c/openocd/+/6848 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ls1088a.cfg | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tcl/target/ls1088a.cfg diff --git a/tcl/target/ls1088a.cfg b/tcl/target/ls1088a.cfg new file mode 100644 index 000000000..136ee77a3 --- /dev/null +++ b/tcl/target/ls1088a.cfg @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1088a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1 + +set _CPU_BASE 0x81000000 +set _CPU_STRIDE 0x100000 +set _CPU_DBGOFF 0x10000 +set _CPU_CTIOFF 0x20000 + +set _TARGETS {} +for {set i 0} {$i < 8} {incr i} { + set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] + cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \ + -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] + target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ + {*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }] + lappend _TARGETS $_CHIPNAME.cpu$i +} + +target smp {*}$_TARGETS + +targets $_CHIPNAME.cpu0 + +# Seems to work OK in testing +adapter speed 10000 From d1278660afcb3315fe74def3c2ca51cf28424963 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 14 Feb 2022 17:53:11 -0500 Subject: [PATCH 25/79] target: ls1088a: Add service processor Normally the service processor is not necessary for debugging. However, if you are using the hard-coded RCW or your boot source is otherwise corrupt, then the general purpose processors will never be released from hold-off. This will cause GDB to become confused if it tries to attach, since they will appear to be running arm32 processors. To deal with this, we can release the CPUs manually with the BRRL register. This register cannot be written to from the axi target, so we need to do it from the service processor target. This involves halting the service processor, modifying the register, and then resuming it again. We try and determine what state the service processor was in to avoid resuming it if it was already halted. The reset vector for the general purpose processors is determined by the boot logation pointer registers in the device configuration unit. Normally these are set using pre-boot initialization commands, but if they are not set then they default to 0. This will cause the CPU to almost immediately hit an illegal instruction. This is fine because we will almost certainly want to attach to the processor and load a program anyway. I considered adding this as an event handler for either gdb-attach or reset-init. However, this command shouldn't be necessary most of the time, and so I don't think we should run it automatically. Signed-off-by: Sean Anderson Change-Id: I1b725292d8a11274d03af5313dc83678e10e944c Reviewed-on: https://review.openocd.org/c/openocd/+/6850 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ls1088a.cfg | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tcl/target/ls1088a.cfg b/tcl/target/ls1088a.cfg index 136ee77a3..f9ae9a134 100644 --- a/tcl/target/ls1088a.cfg +++ b/tcl/target/ls1088a.cfg @@ -36,6 +36,38 @@ for {set i 0} {$i < 8} {incr i} { target smp {*}$_TARGETS +# Service processor +target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000 + +# Normally you will not need to call this, but if you are using the hard-coded +# Reset Configuration Word (RCW) you will need to call this manually. The CPU's +# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit +# instructions. This will cause the CPU to almost immediately execute an +# illegal instruction. +# +# This code is idempotent; releasing a released CPU has no effect, although it +# will halt/resume the service processor. +add_help_text release_cpu "Release a cpu which is held off" +proc release_cpu {cpu} { + set RST_BRRL 0x1e60060 + + set old [target current] + targets $::_CHIPNAME.sp + set not_halted [string compare halted [$::_CHIPNAME.sp curstate]] + if {$not_halted} { + halt + } + + # Release the cpu; it will start executing something bogus + mem2array regs 32 $RST_BRRL 1 + mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] + + if {$not_halted} { + resume + } + targets $old +} + targets $_CHIPNAME.cpu0 # Seems to work OK in testing From e84be7088d5972ddd9bf502f8f66ac3b06ed3dda Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 11 Feb 2022 17:50:09 -0500 Subject: [PATCH 26/79] board: Add NXP LS1088ARDB This adds a board file for the NXP LS1088ARDB. This only covers the "primary" JTAG header J55, and not the PCIe header (J91). The only oddity is that the LS1088A and CPLD are muxed by adding/removing a jumper from J48. Unfortunately, it doesn't look like OpenOCD supports this CPLD beyond determining the irlen, so it's not very useful. Those who are interested in experimenting can define CWTAP to access the CPLD, but the default is to access the CPU. Signed-off-by: Sean Anderson Change-Id: Ia07436a534f86bd907aa5fe2a78a326a27855a24 Reviewed-on: https://review.openocd.org/c/openocd/+/6849 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/nxp_rdb-ls1088a.cfg | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tcl/board/nxp_rdb-ls1088a.cfg diff --git a/tcl/board/nxp_rdb-ls1088a.cfg b/tcl/board/nxp_rdb-ls1088a.cfg new file mode 100644 index 000000000..40483f2d6 --- /dev/null +++ b/tcl/board/nxp_rdb-ls1088a.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1088ARDB (Reference Design Board) +# This is for the "main" JTAG connector J55 + +transport select jtag +reset_config srst_only + +# To access the CPLD, populate J48 and add `-c 'set CWTAP 1'` to your command +# line. At the time of this writing, programming is unsupported. +if { [info exists CWTAP] } { + source [find cpld/altera-epm240.cfg] +} else { + source [find target/ls1088a.cfg] +} From bc50b8f1b299991851d4ff3eb30f583ed6aa530b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Feb 2022 16:16:31 +0100 Subject: [PATCH 27/79] gdb_server: fix double free Commit 6541233aa78d ("Combine register lists of smp targets.") unconditionally assigns the output pointers of the function smp_reg_list_noread(), even if the function fails and returns error. This causes a double free from the caller, that has assigned NULL to the pointers to simplify the error handling. Use local variables in smp_reg_list_noread() and assign the output pointers only on success. Change-Id: Ic0fd2f26520566cf322f0190780e15637c01cfae Fixes: 6541233aa78d ("Combine register lists of smp targets.") Reported-by: Michele Bisogno Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6852 Tested-by: jenkins Reviewed-by: Michele Bisogno Reviewed-by: Tim Newsome --- src/server/gdb_server.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 95720e561..f8a1aac83 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2272,12 +2272,12 @@ static int smp_reg_list_noread(struct target *target, combined_list_size, REG_CLASS_ALL); unsigned int combined_allocated = 256; - *combined_list = malloc(combined_allocated * sizeof(struct reg *)); - if (*combined_list == NULL) { + struct reg **local_list = malloc(combined_allocated * sizeof(struct reg *)); + if (!local_list) { LOG_ERROR("malloc(%zu) failed", combined_allocated * sizeof(struct reg *)); return ERROR_FAIL; } - *combined_list_size = 0; + unsigned int local_list_size = 0; struct target_list *head; foreach_smp_target(head, target->smp_targets) { @@ -2286,7 +2286,7 @@ static int smp_reg_list_noread(struct target *target, int result = target_get_gdb_reg_list_noread(head->target, ®_list, ®_list_size, reg_class); if (result != ERROR_OK) { - free(*combined_list); + free(local_list); return result; } for (int i = 0; i < reg_list_size; i++) { @@ -2296,8 +2296,8 @@ static int smp_reg_list_noread(struct target *target, /* Nested loop makes this O(n^2), but this entire function with * 5 RISC-V targets takes just 2ms on my computer. Fast enough * for me. */ - for (int j = 0; j < *combined_list_size; j++) { - struct reg *b = (*combined_list)[j]; + for (unsigned int j = 0; j < local_list_size; j++) { + struct reg *b = local_list[j]; if (!strcmp(a->name, b->name)) { found = true; if (a->size != b->size) { @@ -2305,7 +2305,7 @@ static int smp_reg_list_noread(struct target *target, "target, but %d bits on another target.", a->name, a->size, b->size); free(reg_list); - free(*combined_list); + free(local_list); return ERROR_FAIL; } break; @@ -2313,16 +2313,16 @@ static int smp_reg_list_noread(struct target *target, } if (!found) { LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name); - if (*combined_list_size >= (int) combined_allocated) { + if (local_list_size >= combined_allocated) { combined_allocated *= 2; - *combined_list = realloc(*combined_list, combined_allocated * sizeof(struct reg *)); - if (*combined_list == NULL) { + local_list = realloc(local_list, combined_allocated * sizeof(struct reg *)); + if (!local_list) { LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); return ERROR_FAIL; } } - (*combined_list)[*combined_list_size] = a; - (*combined_list_size)++; + local_list[local_list_size] = a; + local_list_size++; } } } @@ -2336,12 +2336,12 @@ static int smp_reg_list_noread(struct target *target, int result = target_get_gdb_reg_list_noread(head->target, ®_list, ®_list_size, reg_class); if (result != ERROR_OK) { - free(*combined_list); + free(local_list); return result; } - for (int i = 0; i < *combined_list_size; i++) { + for (unsigned int i = 0; i < local_list_size; i++) { bool found = false; - struct reg *a = (*combined_list)[i]; + struct reg *a = local_list[i]; for (int j = 0; j < reg_list_size; j++) { struct reg *b = reg_list[j]; if (b->exist && !strcmp(a->name, b->name)) { @@ -2358,6 +2358,8 @@ static int smp_reg_list_noread(struct target *target, free(reg_list); } + *combined_list = local_list; + *combined_list_size = local_list_size; return ERROR_OK; } From 103b1d68db5038edd9e8878c798525715590f4e1 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Feb 2022 16:56:42 +0100 Subject: [PATCH 28/79] gdb_server: check target examined while combining reg list Commit 6541233aa78d ("Combine register lists of smp targets.") assumes that all the targets in the SMP cluster are already examined and unconditionally call target_get_gdb_reg_list_noread() that will in turn return error if the target is not examined yet. Skip targets not examined yet. Add an additional check in case the register list cannot be built, e.g. because no target in the SMP cluster is examined. This should never happen, but it's better to play safe. Change-Id: I8609815c3d5144790fb05a870cb0c931540aef8a Fixes: 6541233aa78d ("Combine register lists of smp targets.") Reported-by: Michele Bisogno Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6853 Tested-by: jenkins Reviewed-by: Michele Bisogno Reviewed-by: Tim Newsome --- src/server/gdb_server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f8a1aac83..4dee7e864 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2281,6 +2281,9 @@ static int smp_reg_list_noread(struct target *target, struct target_list *head; foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, @@ -2329,8 +2332,17 @@ static int smp_reg_list_noread(struct target *target, free(reg_list); } + if (local_list_size == 0) { + LOG_ERROR("Unable to get register list"); + free(local_list); + return ERROR_FAIL; + } + /* Now warn the user about any registers that weren't found in every target. */ foreach_smp_target(head, target->smp_targets) { + if (!target_was_examined(head->target)) + continue; + struct reg **reg_list = NULL; int reg_list_size; int result = target_get_gdb_reg_list_noread(head->target, ®_list, From 8b740af10dd37b08c27588f34942154b817bf6fc Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 28 Feb 2022 10:29:44 +0100 Subject: [PATCH 29/79] flash/stm32l4x: fix maybe-uninitialized compiler error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit using gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 we get: error: ‘retval’ may be used uninitialized in this function fixes: 13cd75b6ecfd (flash/nor/stm32xx: fix segfault accessing Cortex-M part number) Change-Id: I897c40c5d2233f50a5385d251ebfa536023e5cf7 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6861 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- src/flash/nor/stm32l4x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index fa8924ed3..fd0338899 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1632,7 +1632,7 @@ err_lock: static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { - int retval; + int retval = ERROR_OK; struct target *target = bank->target; /* try reading possible IDCODE registers, in the following order */ From da7328010165be6e0188100e79b9dab5c362e13b Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 4 Jun 2021 15:04:54 +0200 Subject: [PATCH 30/79] target/tcl: Add set_reg function Change-Id: I97a01b93046cb7af289792489f77f5580312585a Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/5313 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 30 +++++++++++++++++++++ src/target/target.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index fd4a81da2..c0df9c9ac 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5003,6 +5003,21 @@ and neither store nor return those values. @end itemize @end deffn +@deffn {Command} {$target_name set_reg} dict +Set register values of the target. + +@itemize +@item @var{dict} ... Tcl dictionary with pairs of register names and values. +@end itemize + +For example, the following command sets the value 0 to the program counter (pc) +register and 0x1000 to the stack pointer (sp) register: + +@example +set_reg @{pc 0 sp 0x1000@} +@end example +@end deffn + @deffn {Command} {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} @@ -8491,6 +8506,21 @@ Debug and trace infrastructure: @end example @end deffn +@deffn {Command} {set_reg} dict +Set register values of the target. + +@itemize +@item @var{dict} ... Tcl dictionary with pairs of register names and values. +@end itemize + +For example, the following command sets the value 0 to the program counter (pc) +register and 0x1000 to the stack pointer (sp) register: + +@example +set_reg @{pc 0 sp 0x1000@} +@end example +@end deffn + @deffn {Command} {halt} [ms] @deffnx {Command} {wait_halt} [ms] The @command{halt} command first sends a halt request to the target, diff --git a/src/target/target.c b/src/target/target.c index 6250d3031..1d26cb91c 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4863,6 +4863,57 @@ void target_handle_event(struct target *target, enum target_event e) } } +static int target_jim_set_reg(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + if (argc != 2) { + Jim_WrongNumArgs(interp, 1, argv, "dict"); + return JIM_ERR; + } + + int tmp; + Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp); + + if (!dict) + return JIM_ERR; + + const unsigned int length = tmp; + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx); + const struct target *target = get_current_target(cmd_ctx); + + for (unsigned int i = 0; i < length; i += 2) { + const char *reg_name = Jim_String(dict[i]); + const char *reg_value = Jim_String(dict[i + 1]); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, + false); + + if (!reg || !reg->exist) { + Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); + return JIM_ERR; + } + + uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); + + if (!buf) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + str_to_buf(reg_value, strlen(reg_value), buf, reg->size, 0); + int retval = reg->type->set(reg, buf); + free(buf); + + if (retval != ERROR_OK) { + Jim_SetResultFormatted(interp, "failed to set '%s' to register '%s'", + reg_value, reg_name); + return JIM_ERR; + } + } + + return JIM_OK; +} + /** * Returns true only if the target has a handler for the specified event. */ @@ -5645,6 +5696,13 @@ static const struct command_registration target_instance_command_handlers[] = { "from target memory", .usage = "arrayname bitwidth address count", }, + { + .name = "set_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_set_reg, + .help = "Set target register values", + .usage = "dict", + }, { .name = "eventlist", .handler = handle_target_event_list, @@ -6727,6 +6785,13 @@ static const struct command_registration target_exec_command_handlers[] = { "and write the 8/16/32 bit values", .usage = "arrayname bitwidth address count", }, + { + .name = "set_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_set_reg, + .help = "Set target register values", + .usage = "dict", + }, { .name = "reset_nag", .handler = handle_target_reset_nag, From e8e62c5aca494fa17a5e543831b8eef3740c9b1d Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 4 Jun 2021 15:05:17 +0200 Subject: [PATCH 31/79] target/tcl: Add get_reg function Change-Id: Id1be9554d1df2c07cec3161a0fd3a586fdf18246 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/5312 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 36 ++++++++++++++++ src/target/target.c | 101 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index c0df9c9ac..2bfa0deae 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5018,6 +5018,24 @@ set_reg @{pc 0 sp 0x1000@} @end example @end deffn +@deffn {Command} {$target_name get_reg} [-force] list +Get register values from the target and return them as Tcl dictionary with pairs +of register names and values. +If option "-force" is set, the register values are read directly from the +target, bypassing any caching. + +@itemize +@item @var{list} ... List of register names +@end itemize + +For example, the following command retrieves the values from the program +counter (pc) and stack pointer (sp) register: + +@example +get_reg @{pc sp@} +@end example +@end deffn + @deffn {Command} {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} @@ -8521,6 +8539,24 @@ set_reg @{pc 0 sp 0x1000@} @end example @end deffn +@deffn {Command} {get_reg} [-force] list +Get register values from the target and return them as Tcl dictionary with pairs +of register names and values. +If option "-force" is set, the register values are read directly from the +target, bypassing any caching. + +@itemize +@item @var{list} ... List of register names +@end itemize + +For example, the following command retrieves the values from the program +counter (pc) and stack pointer (sp) register: + +@example +get_reg @{pc sp@} +@end example +@end deffn + @deffn {Command} {halt} [ms] @deffnx {Command} {wait_halt} [ms] The @command{halt} command first sends a halt request to the target, diff --git a/src/target/target.c b/src/target/target.c index 1d26cb91c..b72dc53e3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4863,6 +4863,93 @@ void target_handle_event(struct target *target, enum target_event e) } } +static int target_jim_get_reg(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + bool force = false; + + if (argc == 3) { + const char *option = Jim_GetString(argv[1], NULL); + + if (!strcmp(option, "-force")) { + argc--; + argv++; + force = true; + } else { + Jim_SetResultFormatted(interp, "invalid option '%s'", option); + return JIM_ERR; + } + } + + if (argc != 2) { + Jim_WrongNumArgs(interp, 1, argv, "[-force] list"); + return JIM_ERR; + } + + const int length = Jim_ListLength(interp, argv[1]); + + Jim_Obj *result_dict = Jim_NewDictObj(interp, NULL, 0); + + if (!result_dict) + return JIM_ERR; + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + const struct target *target = get_current_target(cmd_ctx); + + for (int i = 0; i < length; i++) { + Jim_Obj *elem = Jim_ListGetIndex(interp, argv[1], i); + + if (!elem) + return JIM_ERR; + + const char *reg_name = Jim_String(elem); + + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, + false); + + if (!reg || !reg->exist) { + Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); + return JIM_ERR; + } + + if (force) { + int retval = reg->type->get(reg); + + if (retval != ERROR_OK) { + Jim_SetResultFormatted(interp, "failed to read register '%s'", + reg_name); + return JIM_ERR; + } + } + + char *reg_value = buf_to_hex_str(reg->value, reg->size); + + if (!reg_value) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + char *tmp = alloc_printf("0x%s", reg_value); + + free(reg_value); + + if (!tmp) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + Jim_DictAddElement(interp, result_dict, elem, + Jim_NewStringObj(interp, tmp, -1)); + + free(tmp); + } + + Jim_SetResult(interp, result_dict); + + return JIM_OK; +} + static int target_jim_set_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { @@ -5696,6 +5783,13 @@ static const struct command_registration target_instance_command_handlers[] = { "from target memory", .usage = "arrayname bitwidth address count", }, + { + .name = "get_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_get_reg, + .help = "Get register values from the target", + .usage = "list", + }, { .name = "set_reg", .mode = COMMAND_EXEC, @@ -6785,6 +6879,13 @@ static const struct command_registration target_exec_command_handlers[] = { "and write the 8/16/32 bit values", .usage = "arrayname bitwidth address count", }, + { + .name = "get_reg", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_get_reg, + .help = "Get register values from the target", + .usage = "list", + }, { .name = "set_reg", .mode = COMMAND_EXEC, From 29e2a7451638d5706daf13b12211b49baafa3c42 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Tue, 22 Jun 2021 11:47:26 +0200 Subject: [PATCH 32/79] target/arm_tpiu: Make error message easier to understand Change-Id: Idddc31e34a67641c32d041c89d01fe2126ec5ddb Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6328 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm_tpiu_swo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 024521364..387ad9e9e 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -886,7 +886,8 @@ static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *o /* does this command exist? */ cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_NONE); if (cmd) { - Jim_SetResultFormatted(interp, "Command: %s Exists", obj->name); + Jim_SetResultFormatted(interp, "cannot create TPIU object because a command with name '%s' already exists", + obj->name); return JIM_ERR; } From 4a4ca07da7b53e589afe2f79d03787d89faf1d33 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Tue, 22 Jun 2021 12:59:01 +0200 Subject: [PATCH 33/79] target/arm_tpiu: Fix 'tpiu create' parameter check The current implementation crashes when executing 'tpiu create' without an object name due to an invalid memory access. Pass 'argv' instead 'goi.argv' to fix the problem. While at it, match the style of the error message to the style used for other Tcl commands. Especially, make the 'name' parameter mandatory. Change-Id: Ib2b233f8556934af61608ae93d6405585c2c40b7 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6329 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/target/arm_tpiu_swo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 387ad9e9e..3738a3bf2 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -916,7 +916,7 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 1) { - Jim_WrongNumArgs(goi.interp, 1, goi.argv, "?name? ..options..."); + Jim_WrongNumArgs(interp, 1, argv, "name ?option option ...?"); return JIM_ERR; } From 2586fec922ae9ea9bea345f40598e0367934d22c Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 26 Feb 2022 14:31:11 +0100 Subject: [PATCH 34/79] target/arm_tpiu: Fix usage of 'tpiu create' Change-Id: I1ffad65a9e6d76f4d7fbbe249d8af3beb7e7692b Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6860 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm_tpiu_swo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 3738a3bf2..bfe908142 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -1161,7 +1161,7 @@ static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { .name = "create", .mode = COMMAND_ANY, .jim_handler = jim_arm_tpiu_swo_create, - .usage = "name [-dap dap] [-ap-num num] [-address baseaddr]", + .usage = "name [-dap dap] [-ap-num num] [-baseaddr baseaddr]", .help = "Creates a new TPIU or SWO object", }, { From 57c1e491801c6e67cb8b429bcf5c0ecf1bcef27b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 17:10:12 +0100 Subject: [PATCH 35/79] flash/stm32f1x,f2x: fix endianess in slow fallback flash write Use target_write_memory() instead of target_write_u16() Change-Id: I2389fe7a5fa18c9bc9c1aad8b8ddd64608bf2566 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6705 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo --- src/flash/nor/stm32f1x.c | 5 +---- src/flash/nor/stm32f2x.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 29a3b7e06..6972bae2d 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -592,10 +592,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer, sizeof(uint16_t)); - - retval = target_write_u16(target, bank->base + offset, value); + retval = target_write_memory(target, bank->base + offset, 2, 1, buffer); if (retval != ERROR_OK) goto reset_pg_and_lock; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 58edca7e1..622ef3423 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -856,15 +856,12 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, Wait for the BSY bit to be cleared */ while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG | FLASH_PSIZE_16); if (retval != ERROR_OK) return retval; - retval = target_write_u16(target, address, value); + retval = target_write_memory(target, address, 2, 1, buffer + bytes_written); if (retval != ERROR_OK) return retval; From f583f338b086ed3a1cd471e1fd8ef99589a64dae Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Wed, 22 Sep 2021 16:15:55 +0100 Subject: [PATCH 36/79] tcl/stm32l5x|u5x: refactor common tcl code both stm32l5x and stm32u5x configs are almost identical except clock config. while at there rename target procs to avoid issues with JTAG daisy chaining. Change-Id: Ibbb1dfeb91a7f8d5d45744cf57dca2877f60e0c5 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6596 Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek Tested-by: jenkins --- tcl/target/stm32l5x.cfg | 162 +------------------------------- tcl/target/stm32u5x.cfg | 163 +-------------------------------- tcl/target/stm32x5x_common.cfg | 154 +++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 315 deletions(-) create mode 100644 tcl/target/stm32x5x_common.cfg diff --git a/tcl/target/stm32l5x.cfg b/tcl/target/stm32l5x.cfg index 0616df1cb..c43b699d2 100644 --- a/tcl/target/stm32l5x.cfg +++ b/tcl/target/stm32l5x.cfg @@ -1,10 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32l5x family +# stm32l5x devices support both JTAG and SWD transports. -# -# stm32l5 devices support both JTAG and SWD transports. -# source [find target/swj-dp.tcl] source [find mem_helper.tcl] @@ -14,78 +12,10 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32l5x } -set _ENDIAN little +source [find target/stm32x5x_common.cfg] -# Work-area is a space in RAM used for flash programming -# By default use 64kB -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x10000 -} - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - if { [using_jtag] } { - # See STM Document RM0438 - # RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers - # Corresponds to Cortex®-M33 JTAG debug port ID code - set _CPUTAPID 0x0ba04477 - } { - # SWD IDCODE (single drop, arm) - set _CPUTAPID 0x0be12477 - } -} - -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 -dap $_CHIPNAME.dap - -# use non-secure RAM by default -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -# create sec/ns flash and otp memories (sizes will be probed) -flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME - -# Common knowledges tells JTAG speed should be <= F_CPU/6. -# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on -# the safe side. -# -# Note that there is a pretty wide band where things are -# more or less stable, see http://openocd.zylin.com/#/c/3366/ -adapter speed 500 - -adapter srst delay 100 -if {[using_jtag]} { - jtag_ntrst_delay 100 -} - -reset_config srst_nogate - -if {![using_hla]} { - # if srst is not fitted use SYSRESETREQ to - # perform a soft reset - cortex_m reset_config sysresetreq -} - -proc is_secure {} { - # read Debug Security Control and Status Regsiter (DSCSR) and check CDS (bit 16) - set DSCSR [mrw 0xE000EE08] - return [expr {($DSCSR & (1 << 16)) != 0}] -} - -proc clock_config_110_mhz {} { - set offset [expr {[is_secure] ? 0x10000000 : 0}] +proc stm32l5x_clock_config {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is MSI (4MHz) after reset, set MCU freq at 110 MHz with PLL # RCC_APB1ENR1 = PWREN mww [expr {0x40021058 + $offset}] 0x10000000 @@ -111,90 +41,8 @@ proc clock_config_110_mhz {} { while {([mrw [expr {0x40021008 + $offset}]] & 0x0C) != 0x0C} {} } -proc ahb_ap_non_secure_access {} { - # SPROT=1=Non Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 -} - -proc ahb_ap_secure_access {} { - # SPROT=0=Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 -} - $_TARGETNAME configure -event reset-init { - clock_config_110_mhz + stm32l5x_clock_config # Boost JTAG frequency adapter speed 4000 } - -$_TARGETNAME configure -event reset-start { - # Reset clock is MSI (4 MHz) - adapter speed 480 -} - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP - mmw 0xE0044004 0x00000006 0 - - # Stop watchdog counters during halt - # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0044008 0x00001800 0 -} - -$_TARGETNAME configure -event halted { - set secure [is_secure] - - if {$secure} { - set secure_str "Secure" - ahb_ap_secure_access - } else { - set secure_str "Non-Secure" - ahb_ap_non_secure_access - } - - # print the secure state only when it changes - set _TARGETNAME [target current] - global $_TARGETNAME.secure - - if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { - echo "CPU in $secure_str state" - # update saved security state - set $_TARGETNAME.secure $secure - } -} - -$_TARGETNAME configure -event gdb-flash-erase-start { - set use_secure_workarea 0 - # check if FLASH_OPTR.TZEN is enabled - set FLASH_OPTR [mrw 0x40022040] - if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { - echo "TZEN option bit disabled" - ahb_ap_non_secure_access - } { - ahb_ap_secure_access - echo "TZEN option bit enabled" - - # check if FLASH_OPTR.RDP is not Level 0.5 - if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { - set use_secure_workarea 1 - } - } - - set workarea_addr [$_TARGETNAME cget -work-area-phys] - echo "workarea_addr $workarea_addr" - - if {$use_secure_workarea} { - set workarea_addr [expr {$workarea_addr | 0x10000000}] - } { - set workarea_addr [expr {$workarea_addr & ~0x10000000}] - } - - $_TARGETNAME configure -work-area-phys $workarea_addr -} - -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0044004 0x00000020 0 -} diff --git a/tcl/target/stm32u5x.cfg b/tcl/target/stm32u5x.cfg index 2c2c0e037..b627d4180 100644 --- a/tcl/target/stm32u5x.cfg +++ b/tcl/target/stm32u5x.cfg @@ -1,10 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # script for stm32u5x family +# stm32u5x devices support both JTAG and SWD transports. -# -# stm32u5 devices support both JTAG and SWD transports. -# source [find target/swj-dp.tcl] source [find mem_helper.tcl] @@ -14,78 +12,10 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32u5x } -set _ENDIAN little +source [find target/stm32x5x_common.cfg] -# Work-area is a space in RAM used for flash programming -# By default use 64kB -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x10000 -} - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - if { [using_jtag] } { - # See STM Document RM0438 - # RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers - # Corresponds to Cortex®-M33 JTAG debug port ID code - set _CPUTAPID 0x0ba04477 - } { - # SWD IDCODE (single drop, arm) - set _CPUTAPID 0x0be12477 - } -} - -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 -dap $_CHIPNAME.dap - -# use non-secure RAM by default -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -# create sec/ns flash and otp memories (sizes will be probed) -flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME - -# Common knowledges tells JTAG speed should be <= F_CPU/6. -# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on -# the safe side. -# -# Note that there is a pretty wide band where things are -# more or less stable, see http://openocd.zylin.com/#/c/3366/ -adapter speed 500 - -adapter srst delay 100 -if {[using_jtag]} { - jtag_ntrst_delay 100 -} - -reset_config srst_nogate - -if {![using_hla]} { - # if srst is not fitted use SYSRESETREQ to - # perform a soft reset - cortex_m reset_config sysresetreq -} - -proc is_secure {} { - # read Debug Security Control and Status Regsiter (DSCSR) and check CDS (bit 16) - set DSCSR [mrw 0xE000EE08] - return [expr {($DSCSR & (1 << 16)) != 0}] -} - -proc clock_config_160_mhz {} { - set offset [expr {[is_secure] ? 0x10000000 : 0}] +proc stm32u5x_clock_config {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] # MCU clock is at MSI 4MHz after reset, set MCU freq at 160 MHz with PLL # Enable voltage range 1 for frequency above 100 Mhz @@ -117,91 +47,8 @@ proc clock_config_160_mhz {} { while {([mrw [expr {0x46020C1C + $offset}]] & 0x0C) != 0x0C} {} } -proc ahb_ap_non_secure_access {} { - # SPROT=1=Non Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 -} - -proc ahb_ap_secure_access {} { - # SPROT=0=Secure access, Priv=1 - [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 -} - $_TARGETNAME configure -event reset-init { - clock_config_160_mhz + stm32u5x_clock_config # Boost JTAG frequency adapter speed 4000 } - -$_TARGETNAME configure -event reset-start { - # Reset clock is MSI (4 MHz) - adapter speed 480 -} - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP - mmw 0xE0044004 0x00000006 0 - - # Stop watchdog counters during halt - # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0044008 0x00001800 0 -} - -$_TARGETNAME configure -event halted { - set secure [is_secure] - - if {$secure} { - set secure_str "Secure" - ahb_ap_secure_access - } else { - set secure_str "Non-Secure" - ahb_ap_non_secure_access - } - - # print the secure state only when it changes - set _TARGETNAME [target current] - global $_TARGETNAME.secure - - if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { - echo "CPU in $secure_str state" - # update saved security state - set $_TARGETNAME.secure $secure - } -} - -$_TARGETNAME configure -event gdb-flash-erase-start { - set use_secure_workarea 0 - # check if FLASH_OPTR.TZEN is enabled - set FLASH_OPTR [mrw 0x40022040] - if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { - echo "TZEN option bit disabled" - ahb_ap_non_secure_access - } else { - ahb_ap_secure_access - echo "TZEN option bit enabled" - - # check if FLASH_OPTR.RDP is not Level 0.5 - if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { - set use_secure_workarea 1 - } - } - - set _TARGETNAME [target current] - set workarea_addr [$_TARGETNAME cget -work-area-phys] - echo "workarea_addr $workarea_addr" - - if {$use_secure_workarea} { - set workarea_addr [expr {$workarea_addr | 0x10000000}] - } else { - set workarea_addr [expr {$workarea_addr & ~0x10000000}] - } - - $_TARGETNAME configure -work-area-phys $workarea_addr -} - -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0044004 0x00000020 0 -} diff --git a/tcl/target/stm32x5x_common.cfg b/tcl/target/stm32x5x_common.cfg new file mode 100644 index 000000000..276d0cca0 --- /dev/null +++ b/tcl/target/stm32x5x_common.cfg @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# common script for stm32l5x and stm32u5x families + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + # STM32L5x: RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers + # STM32U5x: RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers + # Corresponds to Cortex®-M33 JTAG debug port ID code + set _CPUTAPID 0x0ba04477 + } { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x0be12477 + } +} + +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 little -dap $_CHIPNAME.dap + +# use non-secure RAM by default +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# create sec/ns flash and otp memories (sizes will be probed) +flash bank $_CHIPNAME.flash_ns stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.flash_alias_s stm32l4x 0x0C000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x0BFA0000 0 0 0 $_TARGETNAME + +# Common knowledge tells JTAG speed should be <= F_CPU/6. +# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on +# the safe side. +# +# Note that there is a pretty wide band where things are +# more or less stable, see http://review.openocd.org/3366 +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +proc stm32x5x_is_secure {} { + # read Debug Security Control and Status Register (DSCSR) and check CDS (bit 16) + set DSCSR [mrw 0xE000EE08] + return [expr {($DSCSR & (1 << 16)) != 0}] +} + +proc stm32x5x_ahb_ap_non_secure_access {} { + # SPROT=1=Non Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x4B000000 0x4F000000 +} + +proc stm32x5x_ahb_ap_secure_access {} { + # SPROT=0=Secure access, Priv=1 + [[target current] cget -dap] apcsw 0x0B000000 0x4F000000 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is MSI (4 MHz) + adapter speed 480 +} + +$_TARGETNAME configure -event examine-end { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0xE0044004 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0044008 0x00001800 0 +} + +$_TARGETNAME configure -event halted { + set secure [stm32x5x_is_secure] + + if {$secure} { + set secure_str "Secure" + stm32x5x_ahb_ap_secure_access + } else { + set secure_str "Non-Secure" + stm32x5x_ahb_ap_non_secure_access + } + + # print the secure state only when it changes + set _TARGETNAME [target current] + global $_TARGETNAME.secure + + if {![info exists $_TARGETNAME.secure] || $secure != [set $_TARGETNAME.secure]} { + echo "CPU in $secure_str state" + # update saved security state + set $_TARGETNAME.secure $secure + } +} + +$_TARGETNAME configure -event gdb-flash-erase-start { + set use_secure_workarea 0 + # check if FLASH_OPTR.TZEN is enabled + set FLASH_OPTR [mrw 0x40022040] + if {[expr {$FLASH_OPTR & 0x80000000}] == 0} { + echo "TZEN option bit disabled" + stm32x5x_ahb_ap_non_secure_access + } else { + stm32x5x_ahb_ap_secure_access + echo "TZEN option bit enabled" + + # check if FLASH_OPTR.RDP is not Level 0.5 + if {[expr {$FLASH_OPTR & 0xFF}] != 0x55} { + set use_secure_workarea 1 + } + } + + set _TARGETNAME [target current] + set workarea_addr [$_TARGETNAME cget -work-area-phys] + echo "workarea_addr $workarea_addr" + + if {$use_secure_workarea} { + set workarea_addr [expr {$workarea_addr | 0x10000000}] + } else { + set workarea_addr [expr {$workarea_addr & ~0x10000000}] + } + + $_TARGETNAME configure -work-area-phys $workarea_addr +} + +$_TARGETNAME configure -event trace-config { + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0xE0044004 0x00000020 0 +} From 4906176c77d70e89a7e1f7da54e4088c5966207f Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Fri, 25 Feb 2022 17:05:03 +0100 Subject: [PATCH 37/79] cortex_m: use LOG_TARGET_XXX Change-Id: I8be0f67442644031e6e8df3090d81af195caf82b Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6672 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/cortex_m.c | 210 +++++++++++++++++++++--------------------- 1 file changed, 104 insertions(+), 106 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 7125e9e83..108f7e790 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -185,7 +185,7 @@ static int cortex_m_load_core_reg_u32(struct target *target, break; cortex_m->slow_register_read = true; /* Polling (still) needed. */ if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { - LOG_ERROR("Timeout waiting for DCRDR transfer ready"); + LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); return ERROR_TIMEOUT_REACHED; } keep_alive(); @@ -223,7 +223,7 @@ static int cortex_m_slow_read_all_regs(struct target *target) } if (!cortex_m->slow_register_read) - LOG_DEBUG("Switching back to fast register reads"); + LOG_TARGET_DEBUG(target, "Switching back to fast register reads"); return ERROR_OK; } @@ -319,7 +319,7 @@ static int cortex_m_fast_read_all_regs(struct target *target) for (unsigned int i = 0; i < wi; i++) { if ((dhcsr[i] & S_REGRDY) == 0) { not_ready = true; - LOG_DEBUG("Register %u was not ready during fast read", i); + LOG_TARGET_DEBUG(target, "Register %u was not ready during fast read", i); } cortex_m_cumulate_dhcsr_sticky(cortex_m, dhcsr[i]); } @@ -330,7 +330,7 @@ static int cortex_m_fast_read_all_regs(struct target *target) return ERROR_TIMEOUT_REACHED; } - LOG_DEBUG("read %u 32-bit registers", wi); + LOG_TARGET_DEBUG(target, "read %u 32-bit registers", wi); unsigned int ri = 0; /* read index from r_vals array */ for (reg_id = 0; reg_id < num_regs; reg_id++) { @@ -403,7 +403,7 @@ static int cortex_m_store_core_reg_u32(struct target *target, if (cortex_m->dcb_dhcsr & S_REGRDY) break; if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) { - LOG_ERROR("Timeout waiting for DCRDR transfer ready"); + LOG_TARGET_ERROR(target, "Timeout waiting for DCRDR transfer ready"); return ERROR_TIMEOUT_REACHED; } keep_alive(); @@ -528,7 +528,7 @@ static int cortex_m_clear_halt(struct target *target) retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_DFSR, cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; - LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); return ERROR_OK; } @@ -550,7 +550,7 @@ static int cortex_m_single_step_core(struct target *target) retval = cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); if (retval != ERROR_OK) return retval; - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, "single step"); /* restore dhcsr reg */ cortex_m_clear_halt(target); @@ -590,7 +590,7 @@ static int cortex_m_endreset_event(struct target *target) retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &dcb_demcr); if (retval != ERROR_OK) return retval; - LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); + LOG_TARGET_DEBUG(target, "DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); /* this register is used for emulated dcc channel */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); @@ -629,7 +629,7 @@ static int cortex_m_endreset_event(struct target *target) /* Enable FPB */ retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { - LOG_ERROR("Failed to enable the FPB"); + LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } @@ -766,7 +766,7 @@ static int cortex_m_examine_exception_reason(struct target *target) } retval = dap_run(swjdp); if (retval == ERROR_OK) - LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32, armv7m_exception_string(armv7m->exception_number), shcsr, except_sr, cfsr, except_ar); @@ -782,7 +782,7 @@ static int cortex_m_debug_entry(struct target *target) struct arm *arm = &armv7m->arm; struct reg *r; - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, " "); /* Do this really early to minimize the window where the MASKINTS erratum * can pile up pending interrupts. */ @@ -815,7 +815,7 @@ static int cortex_m_debug_entry(struct target *target) retval = cortex_m_fast_read_all_regs(target); if (retval == ERROR_TIMEOUT_REACHED) { cortex_m->slow_register_read = true; - LOG_DEBUG("Switched to slow register read"); + LOG_TARGET_DEBUG(target, "Switched to slow register read"); } } @@ -855,7 +855,8 @@ static int cortex_m_debug_entry(struct target *target) if (armv7m->exception_number) cortex_m_examine_exception_reason(target); - LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", cpu in %s state, target->state: %s", + LOG_TARGET_DEBUG(target, "entered debug state in core mode: %s at PC 0x%" PRIx32 + ", cpu in %s state, target->state: %s", arm_mode_name(arm->core_mode), buf_get_u32(arm->pc->value, 0, 32), secure_state ? "Secure" : "Non-Secure", @@ -889,8 +890,7 @@ static int cortex_m_poll(struct target *target) * section B1.5.15 "Unrecoverable exception cases". */ if (cortex_m->dcb_dhcsr & S_LOCKUP) { - LOG_ERROR("%s -- clearing lockup after double fault", - target_name(target)); + LOG_TARGET_ERROR(target, "clearing lockup after double fault"); cortex_m_write_debug_halt_mask(target, C_HALT, 0); target->debug_reason = DBG_REASON_DBGRQ; @@ -909,7 +909,7 @@ static int cortex_m_poll(struct target *target) cortex_m->dcb_dhcsr_cumulated_sticky &= ~S_RESET_ST; if (target->state != TARGET_RESET) { target->state = TARGET_RESET; - LOG_INFO("%s: external reset detected", target_name(target)); + LOG_TARGET_INFO(target, "external reset detected"); } return ERROR_OK; } @@ -918,7 +918,7 @@ static int cortex_m_poll(struct target *target) /* Cannot switch context while running so endreset is * called with target->state == TARGET_RESET */ - LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32, + LOG_TARGET_DEBUG(target, "Exit from reset with dcb_dhcsr 0x%" PRIx32, cortex_m->dcb_dhcsr); retval = cortex_m_endreset_event(target); if (retval != ERROR_OK) { @@ -943,7 +943,6 @@ static int cortex_m_poll(struct target *target) target_call_event_callbacks(target, TARGET_EVENT_HALTED); } if (prev_target_state == TARGET_DEBUG_RUNNING) { - LOG_DEBUG(" "); retval = cortex_m_debug_entry(target); if (retval != ERROR_OK) return retval; @@ -971,7 +970,7 @@ static int cortex_m_poll(struct target *target) register_cache_invalidate(armv7m->arm.core_cache); target->state = TARGET_RUNNING; - LOG_WARNING("%s: external resume detected", target_name(target)); + LOG_TARGET_WARNING(target, "external resume detected"); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); retval = ERROR_OK; } @@ -984,20 +983,19 @@ static int cortex_m_poll(struct target *target) static int cortex_m_halt(struct target *target) { - LOG_DEBUG("target->state: %s", - target_state_name(target)); + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { - LOG_DEBUG("target was already halted"); + LOG_TARGET_DEBUG(target, "target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) - LOG_WARNING("target was in unknown state when halt was requested"); + LOG_TARGET_WARNING(target, "target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { - LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); + LOG_TARGET_ERROR(target, "can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { /* we came here in a reset_halt or reset_init sequence @@ -1031,10 +1029,10 @@ static int cortex_m_soft_reset_halt(struct target *target) * can be obtained by using 'reset halt' and 'cortex_m reset_config vectreset'. * As this reset only uses VC_CORERESET it would only ever reset the cortex_m * core, not the peripherals */ - LOG_DEBUG("soft_reset_halt is discouraged, please use 'reset halt' instead."); + LOG_TARGET_DEBUG(target, "soft_reset_halt is discouraged, please use 'reset halt' instead."); if (!cortex_m->vectreset_supported) { - LOG_ERROR("VECTRESET is not supported on this Cortex-M core"); + LOG_TARGET_ERROR(target, "VECTRESET is not supported on this Cortex-M core"); return ERROR_FAIL; } @@ -1068,15 +1066,16 @@ static int cortex_m_soft_reset_halt(struct target *target) return retval; if ((cortex_m->dcb_dhcsr & S_HALT) && (cortex_m->nvic_dfsr & DFSR_VCATCH)) { - LOG_DEBUG("system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32, - cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32, + cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr); cortex_m_poll(target); /* FIXME restore user's vector catch config */ return ERROR_OK; - } else - LOG_DEBUG("waiting for system reset-halt, " + } else { + LOG_TARGET_DEBUG(target, "waiting for system reset-halt, " "DHCSR 0x%08" PRIx32 ", %d ms", cortex_m->dcb_dhcsr, timeout); + } } timeout++; alive_sleep(1); @@ -1106,7 +1105,7 @@ static int cortex_m_resume(struct target *target, int current, struct reg *r; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1170,7 +1169,7 @@ static int cortex_m_resume(struct target *target, int current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", + LOG_TARGET_DEBUG(target, "unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")", breakpoint->address, breakpoint->unique_id); cortex_m_unset_breakpoint(target, breakpoint); @@ -1191,11 +1190,11 @@ static int cortex_m_resume(struct target *target, int current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + LOG_TARGET_DEBUG(target, "target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); + LOG_TARGET_DEBUG(target, "target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; @@ -1214,7 +1213,7 @@ static int cortex_m_step(struct target *target, int current, bool isr_timed_out = false; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1287,7 +1286,7 @@ static int cortex_m_step(struct target *target, int current, * */ if ((pc_value & 0x02) && breakpoint_find(target, pc_value & ~0x03)) { - LOG_DEBUG("Stepping over next instruction with interrupts disabled"); + LOG_TARGET_DEBUG(target, "Stepping over next instruction with interrupts disabled"); cortex_m_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts if appropriate */ @@ -1318,7 +1317,7 @@ static int cortex_m_step(struct target *target, int current, cortex_m_set_maskints_for_halt(target); } else { /* Start the core */ - LOG_DEBUG("Starting core to serve pending interrupts"); + LOG_TARGET_DEBUG(target, "Starting core to serve pending interrupts"); int64_t t_start = timeval_ms(); cortex_m_set_maskints_for_run(target); cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP); @@ -1342,7 +1341,7 @@ static int cortex_m_step(struct target *target, int current, } if (isr_timed_out) { - LOG_DEBUG("Interrupt handlers didn't complete within time, " + LOG_TARGET_DEBUG(target, "Interrupt handlers didn't complete within time, " "leaving target running"); } else { /* Step over next instruction with interrupts disabled */ @@ -1377,7 +1376,7 @@ static int cortex_m_step(struct target *target, int current, return ERROR_OK; } - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); @@ -1386,7 +1385,7 @@ static int cortex_m_step(struct target *target, int current, return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); - LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 + LOG_TARGET_DEBUG(target, "target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); @@ -1399,7 +1398,7 @@ static int cortex_m_assert_reset(struct target *target) struct armv7m_common *armv7m = &cortex_m->armv7m; enum cortex_m_soft_reset_config reset_config = cortex_m->soft_reset_config; - LOG_DEBUG("target->state: %s", + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); enum reset_types jtag_reset_config = jtag_get_reset_config(); @@ -1423,10 +1422,10 @@ static int cortex_m_assert_reset(struct target *target) if (jtag_reset_config & RESET_HAS_SRST) { adapter_assert_reset(); if (target->reset_halt) - LOG_ERROR("Target not examined, will not halt after reset!"); + LOG_TARGET_ERROR(target, "Target not examined, will not halt after reset!"); return ERROR_OK; } else { - LOG_ERROR("Target not examined, reset NOT asserted!"); + LOG_TARGET_ERROR(target, "Target not examined, reset NOT asserted!"); return ERROR_FAIL; } } @@ -1473,7 +1472,7 @@ static int cortex_m_assert_reset(struct target *target) retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); if (retval != ERROR_OK || retval2 != ERROR_OK) - LOG_INFO("AP write error, reset will not halt"); + LOG_TARGET_INFO(target, "AP write error, reset will not halt"); } if (jtag_reset_config & RESET_HAS_SRST) { @@ -1493,15 +1492,15 @@ static int cortex_m_assert_reset(struct target *target) if (!cortex_m->vectreset_supported && reset_config == CORTEX_M_RESET_VECTRESET) { reset_config = CORTEX_M_RESET_SYSRESETREQ; - LOG_WARNING("VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); - LOG_WARNING("Set 'cortex_m reset_config sysresetreq'."); + LOG_TARGET_WARNING(target, "VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead."); + LOG_TARGET_WARNING(target, "Set 'cortex_m reset_config sysresetreq'."); } - LOG_DEBUG("Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) + LOG_TARGET_DEBUG(target, "Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) ? "SYSRESETREQ" : "VECTRESET"); if (reset_config == CORTEX_M_RESET_VECTRESET) { - LOG_WARNING("Only resetting the Cortex-M core, use a reset-init event " + LOG_TARGET_WARNING(target, "Only resetting the Cortex-M core, use a reset-init event " "handler to reset any peripherals or configure hardware srst support."); } @@ -1510,11 +1509,11 @@ static int cortex_m_assert_reset(struct target *target) AIRCR_VECTKEY | ((reset_config == CORTEX_M_RESET_SYSRESETREQ) ? AIRCR_SYSRESETREQ : AIRCR_VECTRESET)); if (retval3 != ERROR_OK) - LOG_DEBUG("Ignoring AP write error right after reset"); + LOG_TARGET_DEBUG(target, "Ignoring AP write error right after reset"); retval3 = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval3 != ERROR_OK) { - LOG_ERROR("DP initialisation failed"); + LOG_TARGET_ERROR(target, "DP initialisation failed"); /* The error return value must not be propagated in this case. * SYSRESETREQ or VECTRESET have been possibly triggered * so reset processing should continue */ @@ -1550,7 +1549,7 @@ static int cortex_m_deassert_reset(struct target *target) { struct armv7m_common *armv7m = &target_to_cm(target)->armv7m; - LOG_DEBUG("target->state: %s", + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); /* deassert reset lines */ @@ -1564,7 +1563,7 @@ static int cortex_m_deassert_reset(struct target *target) int retval = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval != ERROR_OK) { - LOG_ERROR("DP initialisation failed"); + LOG_TARGET_ERROR(target, "DP initialisation failed"); return retval; } } @@ -1580,7 +1579,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; if (breakpoint->set) { - LOG_WARNING("breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); + LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); return ERROR_OK; } @@ -1589,35 +1588,36 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint while (comparator_list[fp_num].used && (fp_num < cortex_m->fp_num_code)) fp_num++; if (fp_num >= cortex_m->fp_num_code) { - LOG_ERROR("Can not find free FPB Comparator!"); + LOG_TARGET_ERROR(target, "Can not find free FPB Comparator!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->set = fp_num + 1; fpcr_value = breakpoint->address | 1; if (cortex_m->fp_rev == 0) { if (breakpoint->address > 0x1FFFFFFF) { - LOG_ERROR("Cortex-M Flash Patch Breakpoint rev.1 cannot handle HW breakpoint above address 0x1FFFFFFE"); + LOG_TARGET_ERROR(target, "Cortex-M Flash Patch Breakpoint rev.1 " + "cannot handle HW breakpoint above address 0x1FFFFFFE"); return ERROR_FAIL; } uint32_t hilo; hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW; fpcr_value = (fpcr_value & 0x1FFFFFFC) | hilo | 1; } else if (cortex_m->fp_rev > 1) { - LOG_ERROR("Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); + LOG_TARGET_ERROR(target, "Unhandled Cortex-M Flash Patch Breakpoint architecture revision"); return ERROR_FAIL; } comparator_list[fp_num].used = true; comparator_list[fp_num].fpcr_value = fpcr_value; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); - LOG_DEBUG("fpc_num %i fpcr_value 0x%" PRIx32 "", + LOG_TARGET_DEBUG(target, "fpc_num %i fpcr_value 0x%" PRIx32 "", fp_num, comparator_list[fp_num].fpcr_value); if (!cortex_m->fpb_enabled) { - LOG_DEBUG("FPB wasn't enabled, do it now"); + LOG_TARGET_DEBUG(target, "FPB wasn't enabled, do it now"); retval = cortex_m_enable_fpb(target); if (retval != ERROR_OK) { - LOG_ERROR("Failed to enable the FPB"); + LOG_TARGET_ERROR(target, "Failed to enable the FPB"); return retval; } @@ -1646,7 +1646,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint breakpoint->set = true; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, @@ -1663,11 +1663,11 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; if (breakpoint->set <= 0) { - LOG_WARNING("breakpoint not set"); + LOG_TARGET_WARNING(target, "breakpoint not set"); return ERROR_OK; } - LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, @@ -1677,7 +1677,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi if (breakpoint->type == BKPT_HARD) { unsigned int fp_num = breakpoint->set - 1; if (fp_num >= cortex_m->fp_num_code) { - LOG_DEBUG("Invalid FP Comparator number in breakpoint"); + LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint"); return ERROR_OK; } comparator_list[fp_num].used = false; @@ -1700,12 +1700,12 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->length == 3) { - LOG_DEBUG("Using a two byte breakpoint for 32bit Thumb-2 request"); + LOG_TARGET_DEBUG(target, "Using a two byte breakpoint for 32bit Thumb-2 request"); breakpoint->length = 2; } if ((breakpoint->length != 2)) { - LOG_INFO("only breakpoints of two bytes length supported"); + LOG_TARGET_INFO(target, "only breakpoints of two bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1737,7 +1737,7 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat comparator++, dwt_num++) continue; if (dwt_num >= cortex_m->dwt_num_comp) { - LOG_ERROR("Can not find free DWT Comparator"); + LOG_TARGET_ERROR(target, "Can not find free DWT Comparator"); return ERROR_FAIL; } comparator->used = true; @@ -1795,7 +1795,7 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - LOG_DEBUG("Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", watchpoint->unique_id, dwt_num, (unsigned) comparator->comp, (unsigned) comparator->mask, @@ -1809,19 +1809,19 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w struct cortex_m_dwt_comparator *comparator; if (watchpoint->set <= 0) { - LOG_WARNING("watchpoint (wpid: %d) not set", + LOG_TARGET_WARNING(target, "watchpoint (wpid: %d) not set", watchpoint->unique_id); return ERROR_OK; } unsigned int dwt_num = watchpoint->set - 1; - LOG_DEBUG("Watchpoint (ID %d) DWT%d address: 0x%08x clear", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d address: 0x%08x clear", watchpoint->unique_id, dwt_num, (unsigned) watchpoint->address); if (dwt_num >= cortex_m->dwt_num_comp) { - LOG_DEBUG("Invalid DWT Comparator number in watchpoint"); + LOG_TARGET_DEBUG(target, "Invalid DWT Comparator number in watchpoint"); return ERROR_OK; } @@ -1841,13 +1841,13 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint struct cortex_m_common *cortex_m = target_to_cm(target); if (cortex_m->dwt_comp_available < 1) { - LOG_DEBUG("no comparators?"); + LOG_TARGET_DEBUG(target, "no comparators?"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* hardware doesn't support data value masking */ if (watchpoint->mask != ~(uint32_t)0) { - LOG_DEBUG("watchpoint value masks not supported"); + LOG_TARGET_DEBUG(target, "watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1859,11 +1859,11 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint break; } if (mask == 16) { - LOG_DEBUG("unsupported watchpoint length"); + LOG_TARGET_DEBUG(target, "unsupported watchpoint length"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->address & ((1 << mask) - 1)) { - LOG_DEBUG("watchpoint address is unaligned"); + LOG_TARGET_DEBUG(target, "watchpoint address is unaligned"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1875,12 +1875,12 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint * the data, and another comparator (DATAVADDR0) matching addr. */ if (watchpoint->value) { - LOG_DEBUG("data value watchpoint not YET supported"); + LOG_TARGET_DEBUG(target, "data value watchpoint not YET supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } cortex_m->dwt_comp_available--; - LOG_DEBUG("dwt_comp_available: %d", cortex_m->dwt_comp_available); + LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } @@ -1891,7 +1891,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo /* REVISIT why check? DWT can be updated with core running ... */ if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_WARNING(target, "target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1899,7 +1899,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo cortex_m_unset_watchpoint(target, watchpoint); cortex_m->dwt_comp_available++; - LOG_DEBUG("dwt_comp_available: %d", cortex_m->dwt_comp_available); + LOG_TARGET_DEBUG(target, "dwt_comp_available: %d", cortex_m->dwt_comp_available); return ERROR_OK; } @@ -2004,18 +2004,18 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, retval = target_read_u32(target, DWT_PCSR, ®_value); if (retval != ERROR_OK) { - LOG_ERROR("Error while reading PCSR"); + LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } if (reg_value == 0) { - LOG_INFO("PCSR sampling not supported on this processor."); + LOG_TARGET_INFO(target, "PCSR sampling not supported on this processor."); return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); } gettimeofday(&timeout, NULL); timeval_add_time(&timeout, seconds, 0); - LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); + LOG_TARGET_INFO(target, "Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); /* Make sure the target is running */ target_poll(target); @@ -2023,7 +2023,7 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, retval = target_resume(target, 1, 0, 0, 0); if (retval != ERROR_OK) { - LOG_ERROR("Error while resuming target"); + LOG_TARGET_ERROR(target, "Error while resuming target"); return retval; } @@ -2044,14 +2044,14 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, } if (retval != ERROR_OK) { - LOG_ERROR("Error while reading PCSR"); + LOG_TARGET_ERROR(target, "Error while reading PCSR"); return retval; } gettimeofday(&now, NULL); if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { - LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); + LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); break; } } @@ -2162,14 +2162,14 @@ static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target int reg; target_read_u32(target, DWT_CTRL, &dwtcr); - LOG_DEBUG("DWT_CTRL: 0x%" PRIx32, dwtcr); + LOG_TARGET_DEBUG(target, "DWT_CTRL: 0x%" PRIx32, dwtcr); if (!dwtcr) { - LOG_DEBUG("no DWT"); + LOG_TARGET_DEBUG(target, "no DWT"); return; } target_read_u32(target, DWT_DEVARCH, &cm->dwt_devarch); - LOG_DEBUG("DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); + LOG_TARGET_DEBUG(target, "DWT_DEVARCH: 0x%" PRIx32, cm->dwt_devarch); cm->dwt_num_comp = (dwtcr >> 28) & 0xF; cm->dwt_comp_available = cm->dwt_num_comp; @@ -2178,7 +2178,7 @@ static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target if (!cm->dwt_comparator_list) { fail0: cm->dwt_num_comp = 0; - LOG_ERROR("out of mem"); + LOG_TARGET_ERROR(target, "out of mem"); return; } @@ -2216,7 +2216,7 @@ fail1: *register_get_last_cache_p(&target->reg_cache) = cache; cm->dwt_cache = cache; - LOG_DEBUG("DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", + LOG_TARGET_DEBUG(target, "DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", dwtcr, cm->dwt_num_comp, (dwtcr & (0xf << 24)) ? " only" : "/trigger"); @@ -2283,7 +2283,7 @@ int cortex_m_examine(struct target *target) /* Search for the MEM-AP */ retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap); if (retval != ERROR_OK) { - LOG_ERROR("Could not find MEM-AP to control the core"); + LOG_TARGET_ERROR(target, "Could not find MEM-AP to control the core"); return retval; } } else { @@ -2316,14 +2316,13 @@ int cortex_m_examine(struct target *target) } if (!cortex_m->core_info) { - LOG_ERROR("Cortex-M PARTNO 0x%x is unrecognized", core_partno); + LOG_TARGET_ERROR(target, "Cortex-M PARTNO 0x%x is unrecognized", core_partno); return ERROR_FAIL; } armv7m->arm.arch = cortex_m->core_info->arch; - LOG_INFO("%s: %s r%" PRId8 "p%" PRId8 " processor detected", - target_name(target), + LOG_TARGET_INFO(target, "%s r%" PRId8 "p%" PRId8 " processor detected", cortex_m->core_info->name, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); @@ -2334,11 +2333,11 @@ int cortex_m_examine(struct target *target) rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; if ((rev == 0) && (patch < 2)) { - LOG_WARNING("Silicon bug: single stepping may enter pending exception handler!"); + LOG_TARGET_WARNING(target, "Silicon bug: single stepping may enter pending exception handler!"); cortex_m->maskints_erratum = true; } } - LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid); + LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV4) { target_read_u32(target, MVFR0, &mvfr0); @@ -2346,7 +2345,7 @@ int cortex_m_examine(struct target *target) /* test for floating point feature on Cortex-M4 */ if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) { - LOG_DEBUG("%s floating point feature FPv4_SP found", cortex_m->core_info->name); + LOG_TARGET_DEBUG(target, "%s floating point feature FPv4_SP found", cortex_m->core_info->name); armv7m->fp_feature = FPV4_SP; } } else if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV5) { @@ -2355,10 +2354,10 @@ int cortex_m_examine(struct target *target) /* test for floating point features on Cortex-M7 */ if ((mvfr0 == MVFR0_DEFAULT_M7_SP) && (mvfr1 == MVFR1_DEFAULT_M7_SP)) { - LOG_DEBUG("%s floating point feature FPv5_SP found", cortex_m->core_info->name); + LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_SP found", cortex_m->core_info->name); armv7m->fp_feature = FPV5_SP; } else if ((mvfr0 == MVFR0_DEFAULT_M7_DP) && (mvfr1 == MVFR1_DEFAULT_M7_DP)) { - LOG_DEBUG("%s floating point feature FPv5_DP found", cortex_m->core_info->name); + LOG_TARGET_DEBUG(target, "%s floating point feature FPv5_DP found", cortex_m->core_info->name); armv7m->fp_feature = FPV5_DP; } } @@ -2428,7 +2427,7 @@ int cortex_m_examine(struct target *target) /* make sure we clear any breakpoints enabled on the target */ target_write_u32(target, cortex_m->fp_comparator_list[i].fpcr_address, 0); } - LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", + LOG_TARGET_DEBUG(target, "FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m->fp_num_code, cortex_m->fp_num_lit); @@ -2438,8 +2437,7 @@ int cortex_m_examine(struct target *target) cortex_m_dwt_setup(cortex_m, target); /* These hardware breakpoints only work for code in flash! */ - LOG_INFO("%s: target has %d breakpoints, %d watchpoints", - target_name(target), + LOG_TARGET_INFO(target, "target has %d breakpoints, %d watchpoints", cortex_m->fp_num_code, cortex_m->dwt_num_comp); } @@ -2462,7 +2460,7 @@ static int cortex_m_dcc_read(struct target *target, uint8_t *value, uint8_t *ctr *ctrl = (uint8_t)dcrdr; *value = (uint8_t)(dcrdr >> 8); - LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl); + LOG_TARGET_DEBUG(target, "data 0x%x ctrl 0x%x", *value, *ctrl); /* write ack back to software dcc register * signify we have read data */ @@ -2569,7 +2567,7 @@ 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)); if (!cortex_m) { - LOG_ERROR("No memory creating target"); + LOG_TARGET_ERROR(target, "No memory creating target"); return ERROR_FAIL; } @@ -2626,7 +2624,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) return retval; if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + LOG_TARGET_ERROR(target, "Target not examined yet"); return ERROR_FAIL; } @@ -2655,7 +2653,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) break; } if (i == ARRAY_SIZE(vec_ids)) { - LOG_ERROR("No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); + LOG_TARGET_ERROR(target, "No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -2745,7 +2743,7 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) else if (strcmp(*CMD_ARGV, "vectreset") == 0) { if (target_was_examined(target) && !cortex_m->vectreset_supported) - LOG_WARNING("VECTRESET is not supported on your Cortex-M core!"); + LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core!"); else cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; From 2b17a128841c9431f17aaad844f416eccd24f63f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 4 Oct 2021 08:34:42 -0500 Subject: [PATCH 38/79] tcl/target/ti_k3: Remove args from m3 and m4_up args serve no purpose, so drop them. Signed-off-by: Nishanth Menon Change-Id: I136394307016453d576cf524b0f02227ba26ef8a Reviewed-on: https://review.openocd.org/c/openocd/+/6626 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index d2aa53160..325ee0004 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -152,7 +152,7 @@ cti create $_CTINAME.m3 -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTI target create $_TARGETNAME.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine $_TARGETNAME.m3 configure -event reset-assert { } -proc m3_up { args } { +proc m3_up {} { # To access M3, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 0] 0x00190000 @@ -245,7 +245,7 @@ if { $_mcu_m4_cores != 0 } { target create $_TARGETNAME.m4 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine $_TARGETNAME.m4 configure -event reset-assert { } - proc m4_up { args } { + proc m4_up {} { # To access M4, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 0] 0x00190000 From c280c9835705a7d104996569068826a73b665010 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 1 Oct 2021 22:48:34 -0500 Subject: [PATCH 39/79] tcl/target/ti_k3: Add a gdb-attach event hook for m3 and m4 Add gdb-attach event to call the "up" function of m3 and m4 allowing for more seamless integration with gdb for end users. We still retain _up functions for non-gdb functionality. NOTE: we add a halt 1000 to retain the default gdb-attach hook behavior Suggested-by: Antonio Borneo Signed-off-by: Nishanth Menon Change-Id: I2e51fdbd8756f156551e589c748c3a338afa655c Reviewed-on: https://review.openocd.org/c/openocd/+/6615 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 325ee0004..8fb71482c 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -161,6 +161,12 @@ proc m3_up {} { $::_TARGETNAME.m3 arp_examine } +$_TARGETNAME.m3 configure -event gdb-attach { + m3_up + # gdb-attach default rule + halt 1000 +} + set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { @@ -253,4 +259,10 @@ if { $_mcu_m4_cores != 0 } { $::_TARGETNAME.m4 arp_examine } + + $_TARGETNAME.m4 configure -event gdb-attach { + m4_up + # gdb-attach default rule + halt 1000 + } } From 77b02b89ae689867bb38e11d3fa6ff59c8d22357 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 1 Oct 2021 23:02:23 -0500 Subject: [PATCH 40/79] tcl/target/ti_k3: Rename m3 target as sysctrl The M3 is the system controller of the system. Lets rename it to make clear what we are debugging - esp when multiple MCUs are present in the system. Signed-off-by: Nishanth Menon Change-Id: I4cd03b6068b8ce140fd254f9dd88151c4c7006d7 Reviewed-on: https://review.openocd.org/c/openocd/+/6618 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 8fb71482c..ee4a5c8b3 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -27,11 +27,11 @@ if { [info exists V8_SMP_DEBUG] } { # Common Definitions -# CM3 the very first processor - all current SoCs have it. +# System Controller is the very first processor - all current SoCs have it. set CM3_CTIBASE {0x3C016000} -# M3 power-ap unlock offsets -set _m3_ap_unlock_offsets {0xf0 0x44} +# sysctrl power-ap unlock offsets +set _sysctrl_ap_unlock_offsets {0xf0 0x44} # All the ARMV8s are the next processors. # CL0,CORE0 CL0,CORE1 CL1,CORE0 CL1,CORE1 @@ -70,8 +70,8 @@ switch $_soc { set _main1_r5_cores 0 set _main1_base_core_id 0 - # M3 power-ap unlock offsets - set _m3_ap_unlock_offsets {0xf0 0x50} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x50} } am642 { set _CHIPNAME am642 @@ -147,22 +147,22 @@ set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti -# M3 is always present -cti create $_CTINAME.m3 -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] -target create $_TARGETNAME.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine -$_TARGETNAME.m3 configure -event reset-assert { } +# sysctrl is always present +cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] +target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine +$_TARGETNAME.sysctrl configure -event reset-assert { } -proc m3_up {} { - # To access M3, we need to enable the JTAG access for the same. +proc sysctrl_up {} { + # To access sysctrl, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked - $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 0] 0x00190000 - $::_CHIPNAME.dap apreg 3 [lindex $::_m3_ap_unlock_offsets 1] 0x00102098 + $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_sysctrl_ap_unlock_offsets 1] 0x00102098 - $::_TARGETNAME.m3 arp_examine + $::_TARGETNAME.sysctrl arp_examine } -$_TARGETNAME.m3 configure -event gdb-attach { - m3_up +$_TARGETNAME.sysctrl configure -event gdb-attach { + sysctrl_up # gdb-attach default rule halt 1000 } From 4ddca7dd7186a908397570a25f7ad7454bab3a20 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Fri, 1 Oct 2021 23:18:09 -0500 Subject: [PATCH 41/79] tcl/target/ti_k3: Rename m4 target as general purpose mcu The MCU is present on few of the SoCs and is meant as General Purpose (GP) MCU of the system. Lets rename it to make clear what we are debugging - esp when multiple MCUs are present in the system. Signed-off-by: Nishanth Menon Change-Id: I16132d321daf6e9b1d893fe6f92026d5aa9eb152 Reviewed-on: https://review.openocd.org/c/openocd/+/6619 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index ee4a5c8b3..e397d2255 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -43,13 +43,13 @@ set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} -# Finally an M4F +# Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} -# M4 may be present on some very few SoCs -set _mcu_m4_cores 0 -# M4 power-ap unlock offsets -set _m4_ap_unlock_offsets {0xf0 0x60} +# General Purpose MCU (M4) may be present on some very few SoCs +set _gp_mcu_cores 0 +# General Purpose MCU power-ap unlock offsets +set _gp_mcu_ap_unlock_offsets {0xf0 0x60} # Set configuration overrides for each SOC switch $_soc { @@ -95,7 +95,7 @@ switch $_soc { set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} # M4 processor - set _mcu_m4_cores 1 + set _gp_mcu_cores 1 } j721e { set _CHIPNAME j721e @@ -246,22 +246,22 @@ if { $_main1_r5_cores != 0 } { } } -if { $_mcu_m4_cores != 0 } { - cti create $_CTINAME.m4 -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] - target create $_TARGETNAME.m4 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine - $_TARGETNAME.m4 configure -event reset-assert { } +if { $_gp_mcu_cores != 0 } { + cti create $_CTINAME.gp_mcu -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] + target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + $_TARGETNAME.gp_mcu configure -event reset-assert { } - proc m4_up {} { - # To access M4, we need to enable the JTAG access for the same. + proc gp_mcu_up {} { + # To access GP MCU, we need to enable the JTAG access for the same. # Ensure Power-AP unlocked - $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 0] 0x00190000 - $::_CHIPNAME.dap apreg 3 [lindex $::_m4_ap_unlock_offsets 1] 0x00102098 + $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 0] 0x00190000 + $::_CHIPNAME.dap apreg 3 [lindex $::_gp_mcu_ap_unlock_offsets 1] 0x00102098 - $::_TARGETNAME.m4 arp_examine + $::_TARGETNAME.gp_mcu arp_examine } - $_TARGETNAME.m4 configure -event gdb-attach { - m4_up + $_TARGETNAME.gp_mcu configure -event gdb-attach { + gp_mcu_up # gdb-attach default rule halt 1000 } From 4b12c9e8c507a1ba748de32c9ab9f3e7654c22b4 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 4 Oct 2021 09:03:49 -0500 Subject: [PATCH 42/79] tcl/target/ti_k3: Rename R5 targets to be more descriptive R5 targets are currently named r5.0..n and the only way for user to determine the actual type is external documentation. Lets just rename the target names to make them descriptive to not require external documentation for finding which R5 to connect to. NOTE: we leave the _mcu_r5_cores _main0_r5_cores _main1_r5_cores alone for now to allow existing startup proc functions to work, but we will drop it in the follow on patch. Previously: Info : starting gdb server for j721e.cpu.r5.0 on 3336 Info : Listening on port 3336 for gdb connections Info : starting gdb server for j721e.cpu.r5.1 on 3337 Info : Listening on port 3337 for gdb connections Info : starting gdb server for j721e.cpu.r5.2 on 3338 Info : Listening on port 3338 for gdb connections Info : starting gdb server for j721e.cpu.r5.3 on 3339 Info : Listening on port 3339 for gdb connections Info : starting gdb server for j721e.cpu.r5.4 on 3340 Info : Listening on port 3340 for gdb connections Info : starting gdb server for j721e.cpu.r5.5 on 3341 Info : Listening on port 3341 for gdb connections With this patch: Info : starting gdb server for j721e.cpu.mcu_r5.0 on 3336 Info : Listening on port 3336 for gdb connections Info : starting gdb server for j721e.cpu.mcu_r5.1 on 3337 Info : Listening on port 3337 for gdb connections Info : starting gdb server for j721e.cpu.main0_r5.0 on 3338 Info : Listening on port 3338 for gdb connections Info : starting gdb server for j721e.cpu.main0_r5.1 on 3339 Info : Listening on port 3339 for gdb connections Info : starting gdb server for j721e.cpu.main1_r5.0 on 3340 Info : Listening on port 3340 for gdb connections Info : starting gdb server for j721e.cpu.main1_r5.1 on 3341 Info : Listening on port 3341 for gdb connections Signed-off-by: Nishanth Menon Change-Id: I2989efe3ae3e16754f98fa1dc9363ec4c898f7c3 Reviewed-on: https://review.openocd.org/c/openocd/+/6627 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index e397d2255..6c2c2e1da 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -42,6 +42,7 @@ set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} # (0)MCU 0 (1)MCU 1 (2)MAIN_0_0 (3)MAIN_0_1 (4)MAIN_1_0 (5)MAIN_1_1 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} +set R5_NAMES {mcu_r5.0 mcu_r5.1 main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} # Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} @@ -64,11 +65,9 @@ switch $_soc { # AM654 has 1 cluster of 2 R5s cores. set _r5_cores 2 set _mcu_r5_cores 2 - set _mcu_base_core_id 0 set _main0_r5_cores 0 - set _main0_base_core_id 0 set _main1_r5_cores 0 - set _main1_base_core_id 0 + set R5_NAMES {mcu_r5.0 mcu_r5.1} # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x50} @@ -86,11 +85,9 @@ switch $_soc { # AM642 has 2 cluster of 2 R5s cores. set _r5_cores 4 set _mcu_r5_cores 0 - set _mcu_base_core_id 0 set _main0_r5_cores 2 - set _main0_base_core_id 0 set _main1_r5_cores 2 - set _main1_base_core_id 2 + set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} set R5_DBGBASE {0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} @@ -107,11 +104,8 @@ switch $_soc { # J721E has 3 clusters of 2 R5 cores each. set _r5_cores 6 set _mcu_r5_cores 2 - set _mcu_base_core_id 0 set _main0_r5_cores 2 - set _main0_base_core_id 2 set _main1_r5_cores 2 - set _main1_base_core_id 4 } j7200 { set _CHIPNAME j7200 @@ -124,11 +118,8 @@ switch $_soc { # J7200 has 2 clusters of 2 R5 cores each. set _r5_cores 4 set _mcu_r5_cores 2 - set _mcu_base_core_id 0 set _main0_r5_cores 2 - set _main0_base_core_id 2 set _main1_r5_cores 0 - set _main1_base_core_id 0 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} @@ -208,20 +199,20 @@ if { $_v8_smp_debug == 0 } { } for { set _core 0 } { $_core < $_r5_cores } { incr _core } { - cti create $_CTINAME.r5.$_core -dap $_CHIPNAME.dap -ap-num 1 \ + set _r5_name [lindex $R5_NAMES $_core] + cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $R5_CTIBASE $_core] # inactive core examination will fail - wait till startup of additional core - target create $_TARGETNAME.r5.$_core cortex_r4 -dap $_CHIPNAME.dap \ + target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine } if { $_mcu_r5_cores != 0 } { proc mcu_r5_up { args } { foreach { _core } [set args] { - set _core [expr {$_core + $::_mcu_base_core_id}] - $::_TARGETNAME.r5.$_core arp_examine - $::_TARGETNAME.r5.$_core cortex_r4 dbginit + $::_TARGETNAME.mcu_r5.$_core arp_examine + $::_TARGETNAME.mcu_r5.$_core cortex_r4 dbginit } } } @@ -229,9 +220,8 @@ if { $_mcu_r5_cores != 0 } { if { $_main0_r5_cores != 0 } { proc main0_r5_up { args } { foreach { _core } [set args] { - set _core [expr {$_core + $::_main0_base_core_id}] - $::_TARGETNAME.r5.$_core arp_examine - $::_TARGETNAME.r5.$_core cortex_r4 dbginit + $::_TARGETNAME.main0_r5.$_core arp_examine + $::_TARGETNAME.main0_r5.$_core cortex_r4 dbginit } } } @@ -239,9 +229,8 @@ if { $_main0_r5_cores != 0 } { if { $_main1_r5_cores != 0 } { proc main1_r5_up { args } { foreach { _core } [set args] { - set _core [expr {$_core + $::_main1_base_core_id}] - $::_TARGETNAME.r5.$_core arp_examine - $::_TARGETNAME.r5.$_core cortex_r4 dbginit + $::_TARGETNAME.main1_r5.$_core arp_examine + $::_TARGETNAME.main1_r5.$_core cortex_r4 dbginit } } } From 3ba2b515b528094b43d5be5056b9e52f1dc33969 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 4 Oct 2021 09:20:34 -0500 Subject: [PATCH 43/79] tcl/target/ti_k3: Add a gdb-attach event hook for r5 and simplify startup function Since we can detect the type of target as well, make the attach function name generic for the follow on cleanup patch on armv8 to use as well. Lets introduce gdb-attach event in a much cleaner fashion. We can introduce a simpler r5_up function since we now have more descriptive core names making the individual descriptive procs redundant. NOTE: we add a halt 1000 to retain the default gdb-attach hook behavior Signed-off-by: Nishanth Menon Change-Id: I31506bb2b86e63638082640eb72aa7c4c9575e93 Reviewed-on: https://review.openocd.org/c/openocd/+/6617 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 50 ++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 6c2c2e1da..883197b14 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -64,9 +64,6 @@ switch $_soc { # AM654 has 1 cluster of 2 R5s cores. set _r5_cores 2 - set _mcu_r5_cores 2 - set _main0_r5_cores 0 - set _main1_r5_cores 0 set R5_NAMES {mcu_r5.0 mcu_r5.1} # Sysctrl power-ap unlock offsets @@ -84,9 +81,6 @@ switch $_soc { # AM642 has 2 cluster of 2 R5s cores. set _r5_cores 4 - set _mcu_r5_cores 0 - set _main0_r5_cores 2 - set _main1_r5_cores 2 set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} set R5_DBGBASE {0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d418000 0x9d419000 0x9d518000 0x9d519000} @@ -103,9 +97,6 @@ switch $_soc { # J721E has 3 clusters of 2 R5 cores each. set _r5_cores 6 - set _mcu_r5_cores 2 - set _main0_r5_cores 2 - set _main1_r5_cores 2 } j7200 { set _CHIPNAME j7200 @@ -117,9 +108,6 @@ switch $_soc { # J7200 has 2 clusters of 2 R5 cores each. set _r5_cores 4 - set _mcu_r5_cores 2 - set _main0_r5_cores 2 - set _main1_r5_cores 0 set R5_DBGBASE {0x9d010000 0x9d012000 0x9d110000 0x9d112000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d118000 0x9d119000} @@ -158,6 +146,14 @@ $_TARGETNAME.sysctrl configure -event gdb-attach { halt 1000 } +proc _cpu_no_smp_up {} { + set _current_target [target current] + set _current_type [$_current_target cget -type] + + $_current_target arp_examine + $_current_target $_current_type dbginit +} + set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { @@ -206,32 +202,18 @@ for { set _core 0 } { $_core < $_r5_cores } { incr _core } { # inactive core examination will fail - wait till startup of additional core target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine -} -if { $_mcu_r5_cores != 0 } { - proc mcu_r5_up { args } { - foreach { _core } [set args] { - $::_TARGETNAME.mcu_r5.$_core arp_examine - $::_TARGETNAME.mcu_r5.$_core cortex_r4 dbginit - } + $_TARGETNAME.$_r5_name configure -event gdb-attach { + _cpu_no_smp_up + # gdb-attach default rule + halt 1000 } } -if { $_main0_r5_cores != 0 } { - proc main0_r5_up { args } { - foreach { _core } [set args] { - $::_TARGETNAME.main0_r5.$_core arp_examine - $::_TARGETNAME.main0_r5.$_core cortex_r4 dbginit - } - } -} - -if { $_main1_r5_cores != 0 } { - proc main1_r5_up { args } { - foreach { _core } [set args] { - $::_TARGETNAME.main1_r5.$_core arp_examine - $::_TARGETNAME.main1_r5.$_core cortex_r4 dbginit - } +proc r5_up { args } { + foreach _core $args { + targets $_core + _cpu_no_smp_up } } From 4ea21b95f9562ae13ef200461180bc72bbad8926 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 1 Mar 2022 09:09:55 -0600 Subject: [PATCH 44/79] tcl/target/ti_k3: Add a gdb-attach event hook for armv8 and simplify startup function Since we can detect the type of target as well, reuse the _cpu_no_smp_up function name and use the target name to simplify the _up function and maintain consistency with what we introduced for r5. Lets introduce gdb-attach event in a much cleaner fashion. NOTE: we add a halt 1000 to retain the default gdb-attach hook behavior While at it, fix a minor type of s/are/as in "Set Default target are core 0" and simplify the foreach usage. Signed-off-by: Nishanth Menon Change-Id: I3259b7c3ae4c71b06d921edfaefe17c03bb673dc Reviewed-on: https://review.openocd.org/c/openocd/+/6616 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 883197b14..f2267ca12 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -154,6 +154,16 @@ proc _cpu_no_smp_up {} { $_current_target $_current_type dbginit } +proc _armv8_smp_up {} { + for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { + $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit + $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on + } + # Set Default target as core 0 + targets $::_TARGETNAME.$::_armv8_cpu_name.0 +} + set _v8_smp_targets "" for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { @@ -165,6 +175,20 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" + + if { $_v8_smp_debug == 0 } { + $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { + _cpu_no_smp_up + # gdb-attach default rule + halt 1000 + } + } else { + $_TARGETNAME.$_armv8_cpu_name.$_core configure -event gdb-attach { + _armv8_smp_up + # gdb-attach default rule + halt 1000 + } + } } # Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs @@ -174,22 +198,15 @@ set _armv8_smp_cmd "$_armv8_cpu_name"_smp if { $_v8_smp_debug == 0 } { proc $_armv8_up_cmd { args } { - foreach { _core } [set args] { - $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine - $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit + foreach _core $args { + targets $_core + _cpu_no_smp_up } } } else { proc $_armv8_smp_cmd { args } { - for { set _core 0 } { $_core < $::_armv8_cores } { incr _core } { - $::_TARGETNAME.$::_armv8_cpu_name.$_core arp_examine - $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 dbginit - $::_TARGETNAME.$::_armv8_cpu_name.$_core aarch64 smp on - } - # Set Default target are core 0 - targets $::_TARGETNAME.$::_armv8_cpu_name.0 + _armv8_smp_up } - # Declare SMP target smp $:::_v8_smp_targets } From 9f1b4bbe706b3df40793a9573d7f6471a2442222 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 14 Oct 2021 09:55:49 -0500 Subject: [PATCH 45/79] tcl/target/ti_k3: Add J721S2 SoC Add support for the latest in TI k3 family J721S2 SoC. For further details, see http://www.ti.com/lit/pdf/spruj28 Signed-off-by: Nishanth Menon Change-Id: I608ab4513ffb6b5c4166ba423e7d0dddbbb3bbfd Reviewed-on: https://review.openocd.org/c/openocd/+/6796 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index f2267ca12..604083758 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -114,6 +114,26 @@ switch $_soc { # M3 CTI base set CM3_CTIBASE {0x20001000} } + j721s2 { + set _CHIPNAME j721s2 + set _K3_DAP_TAPID 0x0bb7502f + + # J721s2 has 1 cluster of 2 A72 cores. + set _armv8_cpu_name a72 + set _armv8_cores 2 + + # J721s2 has 3 clusters of 2 R5 cores each. + set _r5_cores 6 + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + + # M4 processor + set _gp_mcu_cores 1 + set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} + } default { echo "'$_soc' is invalid!" } From de4f52179c513cba194079f9fe1ce3a0532bdc9f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 14 Oct 2021 09:57:22 -0500 Subject: [PATCH 46/79] tcl/board: Add J721s2 EVM basic support Add basic connection details with J721s2 EVM. For further details, see https://www.ti.com/lit/zip/sprr439 Signed-off-by: Nishanth Menon Change-Id: I68f8818c492ea6e07c14f2da305671c26da801cb Reviewed-on: https://review.openocd.org/c/openocd/+/6797 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/ti_j721s2evm.cfg | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tcl/board/ti_j721s2evm.cfg diff --git a/tcl/board/ti_j721s2evm.cfg b/tcl/board/ti_j721s2evm.cfg new file mode 100644 index 000000000..72418b57b --- /dev/null +++ b/tcl/board/ti_j721s2evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments J721s2 EVM +# Link(SoM): https://www.ti.com/lit/zip/sprr439 +# + +# J721s2 EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC j721s2 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 From d323fa1d194c8b18ec7d8284e5c8a33ac2b77f07 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 3 Jan 2022 13:23:38 -0600 Subject: [PATCH 47/79] tcl/target/ti_k3: Add AM625 SoC Add support for the latest in TI k3 family AM625 SoC. For further details, see https://www.ti.com/lit/pdf/spruiv7 Signed-off-by: Nishanth Menon Change-Id: Ia54d0eab1c30a973afb1c2c61f4c5a72d29d9b78 Reviewed-on: https://review.openocd.org/c/openocd/+/6798 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ti_k3.cfg | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 604083758..254bb6971 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -88,6 +88,31 @@ switch $_soc { # M4 processor set _gp_mcu_cores 1 } + am625 { + set _CHIPNAME am625 + set _K3_DAP_TAPID 0x0bb7e02f + + # AM625 has 1 clusters of 4 A53 cores. + set _armv8_cpu_name a53 + set _armv8_cores 4 + set ARMV8_DBGBASE {0x90010000 0x90110000 0x90210000 0x90310000} + set ARMV8_CTIBASE {0x90020000 0x90120000 0x90220000 0x90320000} + + # AM625 has 1 cluster of 1 R5s core. + set _r5_cores 1 + set R5_NAMES {main0_r5.0} + set R5_DBGBASE {0x9d410000} + set R5_CTIBASE {0x9d418000} + + # sysctrl CTI base + set CM3_CTIBASE {0x20001000} + # Sysctrl power-ap unlock offsets + set _sysctrl_ap_unlock_offsets {0xf0 0x78} + + # M4 processor + set _gp_mcu_cores 1 + set _gp_mcu_ap_unlock_offsets {0xf0 0x7c} + } j721e { set _CHIPNAME j721e set _K3_DAP_TAPID 0x0bb6402f From 5ffc397278b877000f88dbe0f750b0a1611338a4 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 3 Jan 2022 13:25:28 -0600 Subject: [PATCH 48/79] tcl/board: Add AM625 EVM basic support Add basic connection details with am625 EVM/SK For further details, see https://www.ti.com/lit/zip/sprr448 Signed-off-by: Nishanth Menon Change-Id: Ibd23203ea98e34d03d2f55dac3565aa15aad744b Reviewed-on: https://review.openocd.org/c/openocd/+/6799 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/ti_am625evm.cfg | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tcl/board/ti_am625evm.cfg diff --git a/tcl/board/ti_am625evm.cfg b/tcl/board/ti_am625evm.cfg new file mode 100644 index 000000000..4906fd096 --- /dev/null +++ b/tcl/board/ti_am625evm.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021-2022 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments am625 EVM/SK +# Link: https://www.ti.com/lit/zip/sprr448 +# + +# AM625 EVM has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am625 +} + +source [find target/ti_k3.cfg] + +adapter speed 2500 From 9a6417e03595e1194f125ca33d2b60b8eac9a512 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 1 Mar 2022 23:21:20 +0100 Subject: [PATCH 49/79] tcl: don't use 'set' to retrieve the value of a variable Original TLC syntax uses 'set varname' to retrieve the value of variable 'varname'. Such archaic syntax is still valid, but the shorter '$varname' makes the code easier to read. Replace 'set varname' with '$varname'. While there, remove some useless curly brackets. Change-Id: I27310e8c05afe56ea8bd0e41d4ae2c34447b725c Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6863 Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/board/lemaker_hikey.cfg | 2 +- tcl/board/tocoding_poplar.cfg | 2 +- tcl/target/bluefield.cfg | 2 +- tcl/target/xilinx_zynqmp.cfg | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tcl/board/lemaker_hikey.cfg b/tcl/board/lemaker_hikey.cfg index ee677c34b..325b6fdda 100644 --- a/tcl/board/lemaker_hikey.cfg +++ b/tcl/board/lemaker_hikey.cfg @@ -17,7 +17,7 @@ proc core_up { args } { global _TARGETNAME # examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } diff --git a/tcl/board/tocoding_poplar.cfg b/tcl/board/tocoding_poplar.cfg index 6d2e6354e..36d5aec47 100644 --- a/tcl/board/tocoding_poplar.cfg +++ b/tcl/board/tocoding_poplar.cfg @@ -19,7 +19,7 @@ proc core_up { args } { global _TARGETNAME # examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } diff --git a/tcl/target/bluefield.cfg b/tcl/target/bluefield.cfg index 62b1e3165..dcebb2fb1 100644 --- a/tcl/target/bluefield.cfg +++ b/tcl/target/bluefield.cfg @@ -72,7 +72,7 @@ proc core_up { args } { global _TARGETNAME # Examine remaining cores - foreach _core [set args] { + foreach _core $args { ${_TARGETNAME}$_core arp_examine } } diff --git a/tcl/target/xilinx_zynqmp.cfg b/tcl/target/xilinx_zynqmp.cfg index e66289a70..2df7a4ff9 100644 --- a/tcl/target/xilinx_zynqmp.cfg +++ b/tcl/target/xilinx_zynqmp.cfg @@ -99,7 +99,7 @@ targets $_TARGETNAME.0 proc core_up { args } { global _TARGETNAME - foreach { core } [set args] { + foreach core $args { $_TARGETNAME.$core arp_examine } } From 6883567d5f734040a40c4b2c2d739fa432132cb2 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Fri, 4 Feb 2022 14:44:24 +0100 Subject: [PATCH 50/79] jtag_vpi: Minor cleanup in jtag_vpi driver Multiple smaller items addressed in jtag_vpi: - Several log prints adjusted to make them more clear to the user. - Ensured that command handlers return ERROR_COMMAND_SYNTAX_ERROR on incorrect number of arguments. - Fix in "jtag_vpi set_address": Leave the previously set address intact on error. Do not revert it to default. - Minor update of help messages for the TCL commands. - Updated macro names: SERVER_ADDRESS --> DEFAULT_SERVER_ADDRESS, the same for SERVER_PORT Change-Id: Ibe386403a179adab5edb69c77fa408aef55701bd Signed-off-by: Jan Matyas Reviewed-on: https://review.openocd.org/c/openocd/+/6845 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/jtag/drivers/jtag_vpi.c | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index 0fc688edf..eb53a5b06 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -38,8 +38,8 @@ #define NO_TAP_SHIFT 0 #define TAP_SHIFT 1 -#define SERVER_ADDRESS "127.0.0.1" -#define SERVER_PORT 5555 +#define DEFAULT_SERVER_ADDRESS "127.0.0.1" +#define DEFAULT_SERVER_PORT 5555 #define XFERT_MAX_SIZE 512 @@ -50,7 +50,7 @@ #define CMD_STOP_SIMU 4 /* jtag_vpi server port and address to connect to */ -static int server_port = SERVER_PORT; +static int server_port = DEFAULT_SERVER_PORT; static char *server_address; /* Send CMD_STOP_SIMU to server when OpenOCD exits? */ @@ -551,7 +551,7 @@ static int jtag_vpi_init(void) serv_addr.sin_port = htons(server_port); if (!server_address) - server_address = strdup(SERVER_ADDRESS); + server_address = strdup(DEFAULT_SERVER_ADDRESS); serv_addr.sin_addr.s_addr = inet_addr(server_address); @@ -604,27 +604,28 @@ static int jtag_vpi_quit(void) COMMAND_HANDLER(jtag_vpi_set_port) { - if (CMD_ARGC == 0) - LOG_WARNING("You need to set a port number"); - else - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); + if (CMD_ARGC == 0) { + LOG_ERROR("Command \"jtag_vpi set_port\" expects 1 argument (TCP port number)"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - LOG_INFO("Set server port to %u", server_port); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port); + LOG_INFO("jtag_vpi: server port set to %u", server_port); return ERROR_OK; } COMMAND_HANDLER(jtag_vpi_set_address) { - free(server_address); if (CMD_ARGC == 0) { - LOG_WARNING("You need to set an address"); - server_address = strdup(SERVER_ADDRESS); - } else - server_address = strdup(CMD_ARGV[0]); + LOG_ERROR("Command \"jtag_vpi set_address\" expects 1 argument (IP address)"); + return ERROR_COMMAND_SYNTAX_ERROR; + } - LOG_INFO("Set server address to %s", server_address); + free(server_address); + server_address = strdup(CMD_ARGV[0]); + LOG_INFO("jtag_vpi: server address set to %s", server_address); return ERROR_OK; } @@ -632,11 +633,11 @@ COMMAND_HANDLER(jtag_vpi_set_address) COMMAND_HANDLER(jtag_vpi_stop_sim_on_exit_handler) { if (CMD_ARGC != 1) { - LOG_ERROR("jtag_vpi_stop_sim_on_exit expects 1 argument (on|off)"); + LOG_ERROR("Command \"jtag_vpi stop_sim_on_exit\" expects 1 argument (on|off)"); return ERROR_COMMAND_SYNTAX_ERROR; - } else { - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); } + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], stop_sim_on_exit); return ERROR_OK; } @@ -645,14 +646,14 @@ static const struct command_registration jtag_vpi_subcommand_handlers[] = { .name = "set_port", .handler = &jtag_vpi_set_port, .mode = COMMAND_CONFIG, - .help = "set the port of the VPI server", + .help = "set the TCP port number of the jtag_vpi server (default: 5555)", .usage = "tcp_port_num", }, { .name = "set_address", .handler = &jtag_vpi_set_address, .mode = COMMAND_CONFIG, - .help = "set the address of the VPI server", + .help = "set the IP address of the jtag_vpi server (default: 127.0.0.1)", .usage = "ipv4_addr", }, { From 6673f90e08ac7fb079403dfe7011779349559f0c Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Thu, 24 Feb 2022 15:18:53 +0100 Subject: [PATCH 51/79] flash/stm32h7x: fix FLASH_WPSN_PRG mask used for protection STM32H7Ax/7Bx devices have a different WPSN mask (0xFFFFFFFF), (0xFF for STM32H74x/75x and STM32H72x/73x devices). And when supporting STM32H7Ax/7Bx devices, stm32x_protect() was not updated accordingly. Change-Id: I081217af3e5ed815b67bfdfec7f4ebaa3152a865 Signed-off-by: Tarek BOCHKATI Fixes: 0b7eca17691a (flash/stm32h7x: add support of STM32H7Ax/H7Bx devices) Reviewed-on: https://review.openocd.org/c/openocd/+/6858 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/flash/nor/stm32h7x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 6d3149f94..d2914eb39 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -531,6 +531,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t protection; if (target->state != TARGET_HALTED) { @@ -553,7 +554,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, } /* apply WRPSN mask */ - protection &= 0xff; + protection &= stm32x_info->part_info->wps_mask; LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection); From b6e4d1aa041a119ac6e6576cc8920bf22d1badf5 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 3 Mar 2022 20:56:57 +0100 Subject: [PATCH 52/79] flash/nor/sim3x: Fix typo Change-Id: I2143c81d44b49bed9585c4aaee2bb6e2165345f2 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6869 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/sim3x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/sim3x.c b/src/flash/nor/sim3x.c index 2938ed1ab..891383860 100644 --- a/src/flash/nor/sim3x.c +++ b/src/flash/nor/sim3x.c @@ -983,7 +983,7 @@ COMMAND_HANDLER(sim3x_lock) if (!dap) { /* Used debug interface doesn't support direct DAP access */ - LOG_INFO("Target can't by unlocked by this debug interface"); + LOG_INFO("Target can't be unlocked by this debug interface"); /* Core check */ ret = target_read_u32(target, CPUID, &val); From 1c22c5a82b248b7209fdc904e733b9fa29307c48 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 3 Mar 2022 20:35:10 +0100 Subject: [PATCH 53/79] flash/nor/efm32: Use Cortex-M 'core_info' field Change-Id: I5e477036e5cb7518c35df88878d53261311deb40 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6868 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/efm32.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 653878ae7..2c5a5020e 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -257,23 +257,19 @@ static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, static int efm32x_read_info(struct flash_bank *bank) { int ret; - uint32_t cpuid = 0; struct efm32x_flash_chip *efm32x_info = bank->driver_priv; struct efm32_info *efm32_info = &(efm32x_info->info); memset(efm32_info, 0, sizeof(struct efm32_info)); - ret = target_read_u32(bank->target, CPUID, &cpuid); - if (ret != ERROR_OK) - return ret; + const struct cortex_m_common *cortex_m = target_to_cm(bank->target); - if (((cpuid >> 4) & 0xfff) == 0xc23) { - /* Cortex-M3 device */ - } else if (((cpuid >> 4) & 0xfff) == 0xc24) { - /* Cortex-M4 device (WONDER GECKO) */ - } else if (((cpuid >> 4) & 0xfff) == 0xc60) { - /* Cortex-M0+ device */ - } else { + switch (cortex_m->core_info->partno) { + case CORTEX_M3_PARTNO: + case CORTEX_M4_PARTNO: + case CORTEX_M0P_PARTNO: + break; + default: LOG_ERROR("Target is not Cortex-Mx Device"); return ERROR_FAIL; } From 5b70c1f679755677c925b4e6dd2c3d8be4715717 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 21 Feb 2022 14:06:51 -0500 Subject: [PATCH 54/79] target: Add LS1046A The LS1046A is a quad-core processor from NXP in the layerscape family. This SoC is a bit tricky to program: while the AArch64 CPUs are little-endian, most of the peripherals are big-endian. Care must be taken when interpreting memory reads/writes. This processor is in the same family as the ls1012a, so the setup is similar. If you use OpenOCD to attach early in the boot process, only the cpu0 may be available. Trying to halt other CPUs will fail. To avoid this, defer examination of cpus 1-3, and provide a core_up helper (like e.g. zynqmp). Signed-off-by: Sean Anderson Change-Id: If5a1a9441fb35fea3e05dc708b42e0cb3bbf2a54 Reviewed-on: https://review.openocd.org/c/openocd/+/6854 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/ls1046a.cfg | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tcl/target/ls1046a.cfg diff --git a/tcl/target/ls1046a.cfg b/tcl/target/ls1046a.cfg new file mode 100644 index 000000000..3d96a994e --- /dev/null +++ b/tcl/target/ls1046a.cfg @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1046A + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME ls1046a +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +if { [info exists SAP_TAPID] } { + set _SAP_TAPID $SAP_TAPID +} else { + set _SAP_TAPID 0x06b3001d +} + +jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap + +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +set _CPU_BASE 0x80400000 +set _CPU_STRIDE 0x100000 +set _CPU_DBGOFF 0x10000 +set _CPU_CTIOFF 0x20000 + +set _TARGETS {} +for {set i 0} {$i < 4} {incr i} { + set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}] + cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 1 \ + -baseaddr [expr {$_BASE + $_CPU_CTIOFF}] + target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \ + -cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \ + -coreid $i {*}[expr {$i ? {-defer-examine} : {-rtos hwthread} }] + lappend _TARGETS $_CHIPNAME.cpu$i +} + +target smp {*}$_TARGETS + +jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID +target create $_CHIPNAME.sap ls1_sap -chain-position $_CHIPNAME.sap -endian big + +proc core_up { args } { + foreach core $args { + $::_CHIPNAME.cpu$core arp_examine + } +} + +targets $_CHIPNAME.cpu0 + +adapter speed 10000 From 5b9da0eed215386b856c3168ff712f9af483c0c6 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Mon, 21 Feb 2022 14:53:46 -0500 Subject: [PATCH 55/79] board: Add LS1046ARDB This adds support for the LS1046A Reference Design Board. There are several JTAG headers accessable once the case is opened, but this config is for the externally-accessable CMSIS DAP. Signed-off-by: Sean Anderson Change-Id: I0f83470da3758f0c4512ce47348c4db7de17b27e Reviewed-on: https://review.openocd.org/c/openocd/+/6855 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/nxp_rdb-ls1046a.cfg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tcl/board/nxp_rdb-ls1046a.cfg diff --git a/tcl/board/nxp_rdb-ls1046a.cfg b/tcl/board/nxp_rdb-ls1046a.cfg new file mode 100644 index 000000000..fde1829fb --- /dev/null +++ b/tcl/board/nxp_rdb-ls1046a.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# NXP LS1046ARDB (Reference Design Board) +# This is for the "console" USB port on the front panel +# You must ensure that SW4-7 is in the "off" position + +# NXP K20 +# The firmware implements the old CMSIS-DAP v1 USB HID interface +# You must pass --enable-cmsis-dap to ./configure to enable it +source [find interface/cmsis-dap.cfg] + +transport select jtag +reset_config srst_only + +source [find target/ls1046a.cfg] + +# The adapter can't handle 10MHz +adapter speed 5000 From c5a23e96878d50b64b3d6ee4e52b37f58daaa17f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 5 Mar 2022 14:00:04 +0100 Subject: [PATCH 56/79] jimtcl: add configure flag for build maintainer mode When jimtcl is built in maintainer mode, it runs extra tests at exit to look for memory leak due to jim objects not properly freed either through Jim_IncrRefCount()/Jim_DecrRefCount() or by passing it to a jim API. Add optional OpenOCD configure flag '--enable-jimtcl-maintainer' to enable jimtcl maintainer mode. Modify the implementation of macro AX_CONFIG_SUBDIR_OPTION to allow expanding a variable passed as second argument. Change-Id: Id1a39b25cee3773b172faf70803fa150182f0cd6 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6871 Tested-by: jenkins Reviewed-by: zapb --- config_subdir.m4 | 2 +- configure.ac | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/config_subdir.m4 b/config_subdir.m4 index 45a1c6c4f..2be590e44 100644 --- a/config_subdir.m4 +++ b/config_subdir.m4 @@ -7,6 +7,6 @@ AC_DEFUN([AX_CONFIG_SUBDIR_OPTION], AC_CONFIG_SUBDIRS([$1]) m4_ifblank([$2], [rm -f $srcdir/$1/configure.gnu], -[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" $2 "'\$'@"' > "$srcdir/$1/configure.gnu" +[echo -e '#!/bin/sh\nexec "`dirname "'\$'0"`/configure" '"$2"' "'\$'@"' > "$srcdir/$1/configure.gnu" ]) ]) diff --git a/configure.ac b/configure.ac index 68fff45c1..15d7229a4 100644 --- a/configure.ac +++ b/configure.ac @@ -354,6 +354,10 @@ AC_ARG_ENABLE([internal-jimtcl], AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]), [use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes]) +AC_ARG_ENABLE([jimtcl-maintainer], + AS_HELP_STRING([--enable-jimtcl-maintainer], [Enable maintainer mode when building internal jimtcl]), + [use_internal_jimtcl_maintainer=$enableval], [use_internal_jimtcl_maintainer=no]) + AC_ARG_ENABLE([internal-libjaylink], AS_HELP_STRING([--disable-internal-libjaylink], [Disable building internal libjaylink]), @@ -550,7 +554,12 @@ AS_IF([test "x$enable_buspirate" != "xno"], [ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [ - AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim]) + AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [ + jimtcl_config_options="--disable-install-jim --maintainer" + ], [ + jimtcl_config_options="--disable-install-jim" + ]) + AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options]) ], [ AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.]) ]) From 38183dc856fdb7e69c8407911ff16383f4b12247 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 7 Jun 2021 16:55:24 +0200 Subject: [PATCH 57/79] target/tcl: Add 'read_memory' and 'write_memory' These functions are meant as replacement for 'mem2array' and 'array2mem'. The main benefits of these new functions are: * They do not use Tcl arrays but lists which makes it easier to parse (generate) the data. See the Python Tcl RPC code in contrib as a negative example. * They do not operate on Tcl variables but instead return (accept) the Tcl list directly. This makes the C and Tcl code base smaller and cleaner. * The code is slightly more performant when reading / writing large amount of data. Tested with a simple Python Tcl RPC benchmark. Change-Id: Ibd6ece3360c0d002abaadc37f078b10a8bb606f8 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6307 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 78 +++++++++++ src/target/target.c | 321 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 399 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 2bfa0deae..f9acedf69 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5036,6 +5036,45 @@ get_reg @{pc sp@} @end example @end deffn +@deffn {Command} {$target_name write_memory} address width data ['phys'] +This function provides an efficient way to write to the target memory from a Tcl +script. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{data} ... Tcl list with the elements to write +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command writes two 32 bit words into the target +memory at address 0x20000000: + +@example +write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} +@end example +@end deffn + +@deffn {Command} {$target_name read_memory} address width count ['phys'] +This function provides an efficient way to read the target memory from a Tcl +script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command reads two 32 bit words from the target +memory at address 0x20000000: + +@example +read_memory 0x20000000 32 2 +@end example +@end deffn + @deffn {Command} {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} @@ -8557,6 +8596,45 @@ get_reg @{pc sp@} @end example @end deffn +@deffn {Command} {write_memory} address width data ['phys'] +This function provides an efficient way to write to the target memory from a Tcl +script. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{data} ... Tcl list with the elements to write +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command writes two 32 bit words into the target +memory at address 0x20000000: + +@example +write_memory 0x20000000 32 @{0xdeadbeef 0x00230500@} +@end example +@end deffn + +@deffn {Command} {read_memory} address width count ['phys'] +This function provides an efficient way to read the target memory from a Tcl +script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... target memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@item ['phys'] ... treat the memory address as physical instead of virtual address +@end itemize + +For example, the following command reads two 32 bit words from the target +memory at address 0x20000000: + +@example +read_memory 0x20000000 32 2 +@end example +@end deffn + @deffn {Command} {halt} [ms] @deffnx {Command} {wait_halt} [ms] The @command{halt} command first sends a halt request to the target, diff --git a/src/target/target.c b/src/target/target.c index b72dc53e3..473538ab7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4604,6 +4604,161 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, return e; } +static int target_jim_read_memory(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + /* + * argv[1] = memory address + * argv[2] = desired element width in bits + * argv[3] = number of elements to read + * argv[4] = optional "phys" + */ + + if (argc < 4 || argc > 5) { + Jim_WrongNumArgs(interp, 1, argv, "address width count ['phys']"); + return JIM_ERR; + } + + /* Arg 1: Memory address. */ + jim_wide wide_addr; + int e; + e = Jim_GetWide(interp, argv[1], &wide_addr); + + if (e != JIM_OK) + return e; + + target_addr_t addr = (target_addr_t)wide_addr; + + /* Arg 2: Bit width of one element. */ + long l; + e = Jim_GetLong(interp, argv[2], &l); + + if (e != JIM_OK) + return e; + + const unsigned int width_bits = l; + + /* Arg 3: Number of elements to read. */ + e = Jim_GetLong(interp, argv[3], &l); + + if (e != JIM_OK) + return e; + + size_t count = l; + + /* Arg 4: Optional 'phys'. */ + bool is_phys = false; + + if (argc > 4) { + const char *phys = Jim_GetString(argv[4], NULL); + + if (strcmp(phys, "phys")) { + Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys); + return JIM_ERR; + } + + is_phys = true; + } + + switch (width_bits) { + case 8: + case 16: + case 32: + case 64: + break; + default: + Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1); + return JIM_ERR; + } + + const unsigned int width = width_bits / 8; + + if ((addr + (count * width)) < addr) { + Jim_SetResultString(interp, "read_memory: addr + count wraps to zero", -1); + return JIM_ERR; + } + + if (count > 65536) { + Jim_SetResultString(interp, "read_memory: too large read request, exeeds 64K elements", -1); + return JIM_ERR; + } + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + struct target *target = get_current_target(cmd_ctx); + + const size_t buffersize = 4096; + uint8_t *buffer = malloc(buffersize); + + if (!buffer) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + Jim_Obj *result_list = Jim_NewListObj(interp, NULL, 0); + Jim_IncrRefCount(result_list); + + while (count > 0) { + const unsigned int max_chunk_len = buffersize / width; + const size_t chunk_len = MIN(count, max_chunk_len); + + int retval; + + if (is_phys) + retval = target_read_phys_memory(target, addr, width, chunk_len, buffer); + else + retval = target_read_memory(target, addr, width, chunk_len, buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + addr, width_bits, chunk_len); + Jim_SetResultString(interp, "read_memory: failed to read memory", -1); + e = JIM_ERR; + break; + } + + for (size_t i = 0; i < chunk_len ; i++) { + uint64_t v = 0; + + switch (width) { + case 8: + v = target_buffer_get_u64(target, &buffer[i * width]); + break; + case 4: + v = target_buffer_get_u32(target, &buffer[i * width]); + break; + case 2: + v = target_buffer_get_u16(target, &buffer[i * width]); + break; + case 1: + v = buffer[i]; + break; + } + + char value_buf[11]; + snprintf(value_buf, sizeof(value_buf), "0x%" PRIx64, v); + + Jim_ListAppendElement(interp, result_list, + Jim_NewStringObj(interp, value_buf, -1)); + } + + count -= chunk_len; + addr += chunk_len * width; + } + + free(buffer); + + if (e != JIM_OK) { + Jim_DecrRefCount(interp, result_list); + return e; + } + + Jim_SetResult(interp, result_list); + Jim_DecrRefCount(interp, result_list); + + return JIM_OK; +} + static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val) { char *namebuf = alloc_printf("%s(%zu)", varname, idx); @@ -4814,6 +4969,144 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, return e; } +static int target_jim_write_memory(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + /* + * argv[1] = memory address + * argv[2] = desired element width in bits + * argv[3] = list of data to write + * argv[4] = optional "phys" + */ + + if (argc < 4 || argc > 5) { + Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']"); + return JIM_ERR; + } + + /* Arg 1: Memory address. */ + int e; + jim_wide wide_addr; + e = Jim_GetWide(interp, argv[1], &wide_addr); + + if (e != JIM_OK) + return e; + + target_addr_t addr = (target_addr_t)wide_addr; + + /* Arg 2: Bit width of one element. */ + long l; + e = Jim_GetLong(interp, argv[2], &l); + + if (e != JIM_OK) + return e; + + const unsigned int width_bits = l; + size_t count = Jim_ListLength(interp, argv[3]); + + /* Arg 4: Optional 'phys'. */ + bool is_phys = false; + + if (argc > 4) { + const char *phys = Jim_GetString(argv[4], NULL); + + if (strcmp(phys, "phys")) { + Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys); + return JIM_ERR; + } + + is_phys = true; + } + + switch (width_bits) { + case 8: + case 16: + case 32: + case 64: + break; + default: + Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1); + return JIM_ERR; + } + + const unsigned int width = width_bits / 8; + + if ((addr + (count * width)) < addr) { + Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1); + return JIM_ERR; + } + + if (count > 65536) { + Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1); + return JIM_ERR; + } + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx != NULL); + struct target *target = get_current_target(cmd_ctx); + + const size_t buffersize = 4096; + uint8_t *buffer = malloc(buffersize); + + if (!buffer) { + LOG_ERROR("Failed to allocate memory"); + return JIM_ERR; + } + + size_t j = 0; + + while (count > 0) { + const unsigned int max_chunk_len = buffersize / width; + const size_t chunk_len = MIN(count, max_chunk_len); + + for (size_t i = 0; i < chunk_len; i++, j++) { + Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j); + jim_wide element_wide; + Jim_GetWide(interp, tmp, &element_wide); + + const uint64_t v = element_wide; + + switch (width) { + case 8: + target_buffer_set_u64(target, &buffer[i * width], v); + break; + case 4: + target_buffer_set_u32(target, &buffer[i * width], v); + break; + case 2: + target_buffer_set_u16(target, &buffer[i * width], v); + break; + case 1: + buffer[i] = v & 0x0ff; + break; + } + } + + count -= chunk_len; + + int retval; + + if (is_phys) + retval = target_write_phys_memory(target, addr, width, chunk_len, buffer); + else + retval = target_write_memory(target, addr, width, chunk_len, buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + addr, width_bits, chunk_len); + Jim_SetResultString(interp, "write_memory: failed to write memory", -1); + e = JIM_ERR; + break; + } + + addr += chunk_len * width; + } + + free(buffer); + + return e; +} + /* FIX? should we propagate errors here rather than printing them * and continuing? */ @@ -5797,6 +6090,20 @@ static const struct command_registration target_instance_command_handlers[] = { .help = "Set target register values", .usage = "dict", }, + { + .name = "read_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_read_memory, + .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", + .usage = "address width count ['phys']", + }, + { + .name = "write_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_write_memory, + .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", + .usage = "address width data ['phys']", + }, { .name = "eventlist", .handler = handle_target_event_list, @@ -6893,6 +7200,20 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "Set target register values", .usage = "dict", }, + { + .name = "read_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_read_memory, + .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory", + .usage = "address width count ['phys']", + }, + { + .name = "write_memory", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_write_memory, + .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", + .usage = "address width data ['phys']", + }, { .name = "reset_nag", .handler = handle_target_reset_nag, From e370e06b724f6e3a0fdd8611a3d461c2cc15735c Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 7 Jun 2021 14:40:30 +0200 Subject: [PATCH 58/79] target: Deprecate 'array2mem' and 'mem2array'' Replace 'mem2array' and 'array2mem' with a Tcl wrapper that internally uses 'read_memory' and 'write_memory'. The target-specific 'mem2array' and 'array2mem' functions remain for now. Change-Id: If24c22a76ac72d4c26916a95f7f17902b41b6d9e Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6308 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 39 ++++-------------------------- src/target/startup.tcl | 26 ++++++++++++++++++++ src/target/target.c | 54 ++++-------------------------------------- 3 files changed, 35 insertions(+), 84 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index f9acedf69..0cd9621ff 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4980,29 +4980,6 @@ use these to deal with specific reset cases. They are not otherwise documented here. @end deffn -@deffn {Command} {$target_name array2mem} arrayname width address count -@deffnx {Command} {$target_name mem2array} arrayname width address count -These provide an efficient script-oriented interface to memory. -The @code{array2mem} primitive writes bytes, halfwords, words -or double-words; while @code{mem2array} reads them. -In both cases, the TCL side uses an array, and -the target side uses raw memory. - -The efficiency comes from enabling the use of -bulk JTAG data transfer operations. -The script orientation comes from working with data -values that are packaged for use by TCL scripts; -@command{mdw} type primitives only print data they retrieve, -and neither store nor return those values. - -@itemize -@item @var{arrayname} ... is the name of an array variable -@item @var{width} ... is 8/16/32/64 - indicating the memory access size -@item @var{address} ... is the target memory address -@item @var{count} ... is the number of elements to process -@end itemize -@end deffn - @deffn {Command} {$target_name set_reg} dict Set register values of the target. @@ -5142,8 +5119,8 @@ When the current target has an MMU which is present and active, Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. -(If you want to manipulate the data instead of displaying it, -see the @code{mem2array} primitives.) +(If you want to process the data instead of displaying it, +see the @code{read_memory} primitives.) @end deffn @deffn {Command} {$target_name mwd} [phys] addr doubleword [count] @@ -8772,8 +8749,8 @@ When the current target has an MMU which is present and active, Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. -(If you want to manipulate the data instead of displaying it, -see the @code{mem2array} primitives.) +(If you want to process the data instead of displaying it, +see the @code{read_memory} primitives.) @end deffn @deffn {Command} {mwd} [phys] addr doubleword [count] @@ -11681,13 +11658,7 @@ should be passed in to the proc in question. By "low-level", we mean commands that a human would typically not invoke directly. -@itemize @bullet -@item @b{mem2array} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> - -Read memory and return as a Tcl array for script processing -@item @b{array2mem} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> - -Convert a Tcl array to memory locations and write the values +@itemize @item @b{flash banks} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}> <@var{bus_width}> <@var{target}> [@option{driver options} ...] Return information about the flash banks diff --git a/src/target/startup.tcl b/src/target/startup.tcl index cd98d68e4..0e46992b7 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -206,6 +206,32 @@ proc init_target_events {} { proc init_board {} { } +proc mem2array {arrayname bitwidth address count {phys ""}} { + echo "DEPRECATED! use 'read_memory' not 'mem2array'" + + upvar $arrayname $arrayname + set $arrayname "" + set i 0 + + foreach elem [read_memory $address $bitwidth $count {*}$phys] { + set ${arrayname}($i) $elem + incr i + } +} + +proc array2mem {arrayname bitwidth address count {phys ""}} { + echo "DEPRECATED! use 'write_memory' not 'array2mem'" + + upvar $arrayname $arrayname + set data "" + + for {set i 0} {$i < $count} {incr i} { + lappend data [expr $${arrayname}($i)] + } + + write_memory $address $bitwidth $data {*}$phys +} + # smp_on/smp_off were already DEPRECATED in v0.11.0 through http://openocd.zylin.com/4615 lappend _telnet_autocomplete_skip "aarch64 smp_on" proc "aarch64 smp_on" {args} { diff --git a/src/target/target.c b/src/target/target.c index 473538ab7..7b8271339 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4431,27 +4431,12 @@ static int new_u64_array_element(Jim_Interp *interp, const char *varname, int id return result; } -static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct command_context *context; - struct target *target; - - context = current_command_context(interp); - assert(context); - - target = get_current_target(context); - if (!target) { - LOG_ERROR("mem2array: no current target"); - return JIM_ERR; - } - - return target_mem2array(interp, target, argc - 1, argv + 1); -} - static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { int e; + LOG_WARNING("DEPRECATED! use 'read_memory' not 'mem2array'"); + /* argv[0] = name of array to receive the data * argv[1] = desired element width in bits * argv[2] = memory address @@ -4784,28 +4769,13 @@ static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t return result; } -static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct command_context *context; - struct target *target; - - context = current_command_context(interp); - assert(context); - - target = get_current_target(context); - if (!target) { - LOG_ERROR("array2mem: no current target"); - return JIM_ERR; - } - - return target_array2mem(interp, target, argc-1, argv + 1); -} - static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { int e; + LOG_WARNING("DEPRECATED! use 'write_memory' not 'array2mem'"); + /* argv[0] = name of array from which to read the data * argv[1] = desired element width in bits * argv[2] = memory address @@ -7170,22 +7140,6 @@ static const struct command_registration target_exec_command_handlers[] = { .mode = COMMAND_EXEC, .usage = "filename [offset [type]]", }, - { - .name = "mem2array", - .mode = COMMAND_EXEC, - .jim_handler = jim_mem2array, - .help = "read 8/16/32 bit memory and return as a TCL array " - "for script processing", - .usage = "arrayname bitwidth address count", - }, - { - .name = "array2mem", - .mode = COMMAND_EXEC, - .jim_handler = jim_array2mem, - .help = "convert a TCL array to memory locations " - "and write the 8/16/32 bit values", - .usage = "arrayname bitwidth address count", - }, { .name = "get_reg", .mode = COMMAND_EXEC, From be0d68eb66b513ef406ffa83102f89a8f4602914 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 25 Feb 2022 15:44:58 +0100 Subject: [PATCH 59/79] Remove all occurrences of 'mem2array' and 'array2mem' Replace deprecated commands 'mem2array' and 'array2mem' with new Tcl commands 'read_memory' and 'write_memory'. Change-Id: I116d995995396133ca782b14cce02bd1ab917a4e Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6859 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/rpc_examples/ocd_rpc_example.py | 18 ++----- tcl/board/at91cap7a-stk-sdram.cfg | 3 +- tcl/board/at91sam9g20-ek.cfg | 4 +- tcl/board/embedded-artists_lpc2478-32.cfg | 4 +- tcl/board/hilscher_nxhx10.cfg | 4 +- tcl/board/icnova_sam9g45_sodimm.cfg | 4 +- tcl/chip/atmel/at91/aic.tcl | 20 ++++---- tcl/cpu/arc/common.tcl | 5 +- tcl/mem_helper.tcl | 12 ++--- tcl/memory.tcl | 60 +++++++++-------------- tcl/target/c100helper.tcl | 24 +++++---- tcl/target/hilscher_netx500.cfg | 4 +- tcl/target/psoc4.cfg | 18 +++---- tcl/target/stm32h7x.cfg | 4 +- tcl/target/stm32mp15x.cfg | 4 +- tcl/target/stm32wlx.cfg | 4 +- tcl/target/ti_cc3220sf.cfg | 8 +-- testing/examples/cortex/cm3-ftest.cfg | 2 +- 18 files changed, 79 insertions(+), 123 deletions(-) diff --git a/contrib/rpc_examples/ocd_rpc_example.py b/contrib/rpc_examples/ocd_rpc_example.py index 3470d848b..e6146f617 100755 --- a/contrib/rpc_examples/ocd_rpc_example.py +++ b/contrib/rpc_examples/ocd_rpc_example.py @@ -95,24 +95,16 @@ class OpenOcd: return None if (len(raw) < 2) else strToHex(raw[1]) def readMemory(self, wordLen, address, n): - self.send("array unset output") # better to clear the array before - self.send("mem2array output %d 0x%x %d" % (wordLen, address, n)) - - output = [*map(int, self.send("return $output").split(" "))] - d = dict([tuple(output[i:i + 2]) for i in range(0, len(output), 2)]) - - return [d[k] for k in sorted(d.keys())] + output = self.send("read_memory 0x%x %d %d" % (address, wordLen, n)) + return [*map(lambda x: int(x, 16), output.split(" "))] def writeVariable(self, address, value): assert value is not None self.send("mww 0x%x 0x%x" % (address, value)) - def writeMemory(self, wordLen, address, n, data): - array = " ".join(["%d 0x%x" % (a, b) for a, b in enumerate(data)]) - - self.send("array unset 1986ве1т") # better to clear the array before - self.send("array set 1986ве1т { %s }" % array) - self.send("array2mem 1986ве1т 0x%x %s %d" % (wordLen, address, n)) + def writeMemory(self, wordLen, address, data): + data = "{" + ' '.join(['0x%x' % x for x in data]) + "}" + self.send("write_memory 0x%x %d %s" % (address, wordLen, data)) if __name__ == "__main__": diff --git a/tcl/board/at91cap7a-stk-sdram.cfg b/tcl/board/at91cap7a-stk-sdram.cfg index 8a371e064..182a4067f 100644 --- a/tcl/board/at91cap7a-stk-sdram.cfg +++ b/tcl/board/at91cap7a-stk-sdram.cfg @@ -32,8 +32,7 @@ $_TARGETNAME configure -event reset-start { } proc peek32 {address} { - mem2array t 32 $address 1 - return $t(0) + return [read_memory $address 32 1] } # Wait for an expression to be true with a timeout diff --git a/tcl/board/at91sam9g20-ek.cfg b/tcl/board/at91sam9g20-ek.cfg index e1cbb9120..04d9a197c 100644 --- a/tcl/board/at91sam9g20-ek.cfg +++ b/tcl/board/at91sam9g20-ek.cfg @@ -40,9 +40,7 @@ at91sam9 rdy_busy 0 0xfffff800 13 at91sam9 ce 0 0xfffff800 14 proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc at91sam9g20_reset_start { } { diff --git a/tcl/board/embedded-artists_lpc2478-32.cfg b/tcl/board/embedded-artists_lpc2478-32.cfg index 38f5e1b8e..a73d83263 100644 --- a/tcl/board/embedded-artists_lpc2478-32.cfg +++ b/tcl/board/embedded-artists_lpc2478-32.cfg @@ -8,9 +8,7 @@ source [find target/lpc2478.cfg] # Helper # proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc init_board {} { diff --git a/tcl/board/hilscher_nxhx10.cfg b/tcl/board/hilscher_nxhx10.cfg index 1875dacc0..6e2eba79e 100644 --- a/tcl/board/hilscher_nxhx10.cfg +++ b/tcl/board/hilscher_nxhx10.cfg @@ -26,9 +26,7 @@ proc flash_init { } { } proc mread32 {addr} { - set value(0) 0 - mem2array value 32 $addr 1 - return $value(0) + return [read_memory $addr 32 1] } proc init_clocks { } { diff --git a/tcl/board/icnova_sam9g45_sodimm.cfg b/tcl/board/icnova_sam9g45_sodimm.cfg index 8a0736b1f..91e0107c2 100644 --- a/tcl/board/icnova_sam9g45_sodimm.cfg +++ b/tcl/board/icnova_sam9g45_sodimm.cfg @@ -43,9 +43,7 @@ flash bank $_FLASHNAME cfi 0x10000000 0x00800000 2 2 $_TARGETNAME proc read_register {register} { - set result "" - mem2array result 32 $register 1 - return $result(0) + return [read_memory $register 32 1] } proc at91sam9g45_start { } { diff --git a/tcl/chip/atmel/at91/aic.tcl b/tcl/chip/atmel/at91/aic.tcl index b0b100270..8b8a48f3b 100644 --- a/tcl/chip/atmel/at91/aic.tcl +++ b/tcl/chip/atmel/at91/aic.tcl @@ -54,36 +54,36 @@ proc show_AIC_IMR_helper { NAME ADDR VAL } { proc show_AIC { } { global AIC_SMR - if [catch { mem2array aaa 32 $AIC_SMR [expr {32 * 4}] } msg ] { + if [catch { set aaa [read_memory $AIC_SMR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SMR] } echo "AIC_SMR: Mode & Type" global AT91C_ID for { set x 0 } { $x < 32 } { } { echo -n " " - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)] + echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } global AIC_SVR - if [catch { mem2array aaa 32 $AIC_SVR [expr {32 * 4}] } msg ] { + if [catch { set aaa [read_memory $AIC_SVR 32 [expr {32 * 4}]] } msg ] { error [format "%s (%s)" $msg AIC_SVR] } echo "AIC_SVR: Vectors" for { set x 0 } { $x < 32 } { } { echo -n " " - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) $aaa($x)] + echo -n [format "%2d: %5s 0x%08x | " $x $AT91C_ID($x) [lindex $aaa $x]] incr x - echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) $aaa($x)] + echo [format "%2d: %5s 0x%08x" $x $AT91C_ID($x) [lindex $aaa $x]] incr x } diff --git a/tcl/cpu/arc/common.tcl b/tcl/cpu/arc/common.tcl index e9a915717..b31e31a34 100644 --- a/tcl/cpu/arc/common.tcl +++ b/tcl/cpu/arc/common.tcl @@ -29,9 +29,8 @@ proc arc_common_reset { {target ""} } { # vector located at the interrupt vector base address, which is the first # entry (offset 0x00) in the vector table. set int_vector_base [arc jtag get-aux-reg 0x25] - set start_pc "" - mem2array start_pc 32 $int_vector_base 1 - arc jtag set-aux-reg 0x6 $start_pc(0) + set start_pc [read_memory $int_vector_base 32 1] + arc jtag set-aux-reg 0x6 $start_pc # It is OK to do uncached writes - register cache will be invalidated by # the reset_assert() function. diff --git a/tcl/mem_helper.tcl b/tcl/mem_helper.tcl index 9ea285a22..1c860119a 100644 --- a/tcl/mem_helper.tcl +++ b/tcl/mem_helper.tcl @@ -2,9 +2,7 @@ # mrw: "memory read word", returns value of $reg proc mrw {reg} { - set value "" - mem2array value 32 $reg 1 - return $value(0) + return [read_memory $reg 32 1] } add_usage_text mrw "address" @@ -12,9 +10,7 @@ add_help_text mrw "Returns value of word in memory." # mrh: "memory read halfword", returns value of $reg proc mrh {reg} { - set value "" - mem2array value 16 $reg 1 - return $value(0) + return [read_memory $reg 16 1] } add_usage_text mrh "address" @@ -22,9 +18,7 @@ add_help_text mrh "Returns value of halfword in memory." # mrb: "memory read byte", returns value of $reg proc mrb {reg} { - set value "" - mem2array value 8 $reg 1 - return $value(0) + return [read_memory $reg 8 1] } add_usage_text mrb "address" diff --git a/tcl/memory.tcl b/tcl/memory.tcl index 8d50ba853..ac273451d 100644 --- a/tcl/memory.tcl +++ b/tcl/memory.tcl @@ -79,108 +79,96 @@ proc address_info { ADDRESS } { } proc memread32 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 32 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 32 1] } msg ] { + return $foo } else { error "memread32: $msg" } } proc memread16 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 16 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 16 1] } msg ] { + return $foo } else { error "memread16: $msg" } } proc memread8 {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 8 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 8 1] } msg ] { + return $foo } else { error "memread8: $msg" } } proc memwrite32 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 32 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 32 $DATA } msg ] { + return $DATA } else { error "memwrite32: $msg" } } proc memwrite16 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 16 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 16 $DATA } msg ] { + return $DATA } else { error "memwrite16: $msg" } } proc memwrite8 {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 8 $ADDR 1 } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 8 $DATA } msg ] { + return $DATA } else { error "memwrite8: $msg" } } proc memread32_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 32 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 32 1 phys] } msg ] { + return $foo } else { error "memread32: $msg" } } proc memread16_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 16 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 16 1 phys] } msg ] { + return $foo } else { error "memread16: $msg" } } proc memread8_phys {ADDR} { - set foo(0) 0 - if ![ catch { mem2array foo 8 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { set foo [read_memory $ADDR 8 1 phys] } msg ] { + return $foo } else { error "memread8: $msg" } } proc memwrite32_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 32 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 32 $DATA phys } msg ] { + return $DATA } else { error "memwrite32: $msg" } } proc memwrite16_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 16 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 16 $DATA phys } msg ] { + return $DATA } else { error "memwrite16: $msg" } } proc memwrite8_phys {ADDR DATA} { - set foo(0) $DATA - if ![ catch { array2mem foo 8 $ADDR 1 phys } msg ] { - return $foo(0) + if ![ catch { write_memory $ADDR 8 $DATA phys } msg ] { + return $DATA } else { error "memwrite8: $msg" } diff --git a/tcl/target/c100helper.tcl b/tcl/target/c100helper.tcl index bdcfd8cf5..ecd7edf11 100644 --- a/tcl/target/c100helper.tcl +++ b/tcl/target/c100helper.tcl @@ -29,9 +29,7 @@ source [find mem_helper.tcl] # read a 64-bit register (memory mapped) proc mr64bit {reg} { - set value "" - mem2array value 32 $reg 2 - return $value + return [read_memory $reg 32 2] } @@ -117,19 +115,19 @@ proc showAmbaClk {} { set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_AHB_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_AHB_CLK_CNTRL [mrw $CLKCORE_AHB_CLK_CNTRL]] - mem2array value 32 $CLKCORE_AHB_CLK_CNTRL 1 + set value [read_memory $CLKCORE_AHB_CLK_CNTRL 32 1] # see if the PLL is in bypass mode - set bypass [expr {($value(0) & $PLL_CLK_BYPASS) >> 24}] + set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. - set x [expr {($value(0) & 0x0001F0000) >> 16}] + set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] - set y [expr {($value(0) & 0x00000007F)}] + set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] - set w [expr {($value(0) & 0x000000300) >> 8}] + set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Amba PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } @@ -192,19 +190,19 @@ proc showArmClk {} { set PLL_CLK_BYPASS [regs PLL_CLK_BYPASS] echo [format "CLKCORE_ARM_CLK_CNTRL (0x%x): 0x%x" $CLKCORE_ARM_CLK_CNTRL [mrw $CLKCORE_ARM_CLK_CNTRL]] - mem2array value 32 $CLKCORE_ARM_CLK_CNTRL 1 + set value [read_memory $CLKCORE_ARM_CLK_CNTRL 32 1] # see if the PLL is in bypass mode - set bypass [expr {($value(0) & $PLL_CLK_BYPASS) >> 24}] + set bypass [expr {($value & $PLL_CLK_BYPASS) >> 24}] echo [format "PLL bypass bit: %d" $bypass] if {$bypass == 1} { echo [format "Amba Clk is set to REFCLK: %d (MHz)" [expr {$CFG_REFCLKFREQ/1000000}]] } else { # nope, extract x,y,w and compute the PLL output freq. - set x [expr {($value(0) & 0x0001F0000) >> 16}] + set x [expr {($value & 0x0001F0000) >> 16}] echo [format "x: %d" $x] - set y [expr {($value(0) & 0x00000007F)}] + set y [expr {($value & 0x00000007F)}] echo [format "y: %d" $y] - set w [expr {($value(0) & 0x000000300) >> 8}] + set w [expr {($value & 0x000000300) >> 8}] echo [format "w: %d" $w] echo [format "Arm PLL Clk: %d (MHz)" [expr {($CFG_REFCLKFREQ * $y / (($w + 1) * ($x + 1) * 2))/1000000}]] } diff --git a/tcl/target/hilscher_netx500.cfg b/tcl/target/hilscher_netx500.cfg index 6d919f9dd..131bef221 100644 --- a/tcl/target/hilscher_netx500.cfg +++ b/tcl/target/hilscher_netx500.cfg @@ -26,9 +26,7 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm926ejs -endian $_ENDIAN -chain-position $_TARGETNAME proc mread32 {addr} { - set value(0) 0 - mem2array value 32 $addr 1 - return $value(0) + return [read_memory $addr 32 1] } # This function must be called on netX100/500 right after halt diff --git a/tcl/target/psoc4.cfg b/tcl/target/psoc4.cfg index cffcbc753..40f2fcab3 100644 --- a/tcl/target/psoc4.cfg +++ b/tcl/target/psoc4.cfg @@ -74,22 +74,22 @@ if {![using_hla]} { } proc psoc4_get_family_id {} { - set err [catch "mem2array romtable_pid 32 0xF0000FE0 3"] + set err [catch {set romtable_pid [read_memory 0xF0000FE0 32 3]}] if { $err } { return 0 } - if { [expr {$romtable_pid(0) & 0xffffff00 }] - || [expr {$romtable_pid(1) & 0xffffff00 }] - || [expr {$romtable_pid(2) & 0xffffff00 }] } { + if { [expr {[lindex $romtable_pid 0] & 0xffffff00 }] + || [expr {[lindex $romtable_pid 1] & 0xffffff00 }] + || [expr {[lindex $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 ) }] + set designer_id [expr {(( [lindex $romtable_pid 1] & 0xf0 ) >> 4) | (( [lindex $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 ) }] + set family_id [expr {( [lindex $romtable_pid 0] & 0xff ) | (( [lindex $romtable_pid 1] & 0xf ) << 8 ) }] return $family_id } @@ -193,9 +193,9 @@ proc ocd_process_reset_inner { MODE } { } # Set registers to reset vector values - mem2array value 32 0 2 - reg pc [expr {$value(1) & 0xfffffffe} ] - reg msp $value(0) + set value [read_memory 0x0 32 2] + reg pc [expr {[lindex $value 1] & 0xfffffffe}] + reg msp [lindex $value 0] if { $PSOC4_TEST_MODE_WORKAROUND } { catch { mww $TEST_MODE 0 } diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index f2a5c42c6..ca685c2f2 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -232,9 +232,7 @@ if {[set $_CHIPNAME.DUAL_CORE]} { # like mrw, but with target selection proc stm32h7x_mrw {used_target reg} { - set value "" - $used_target mem2array value 32 $reg 1 - return $value(0) + return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/stm32mp15x.cfg index 639fbabe0..afd5d2413 100644 --- a/tcl/target/stm32mp15x.cfg +++ b/tcl/target/stm32mp15x.cfg @@ -109,8 +109,8 @@ proc toggle_cpu0_dbg_claim0 {} { } proc detect_cpu1 {} { - $::_CHIPNAME.ap1 mem2array cpu1_prsr 32 0xE00D2314 1 - set dual_core [expr {$cpu1_prsr(0) & 1}] + set cpu1_prsr [$::_CHIPNAME.ap1 read_memory 0xE00D2314 32 1] + set dual_core [expr {$cpu1_prsr & 1}] if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} } diff --git a/tcl/target/stm32wlx.cfg b/tcl/target/stm32wlx.cfg index fafe9bcba..75f6f0288 100644 --- a/tcl/target/stm32wlx.cfg +++ b/tcl/target/stm32wlx.cfg @@ -156,9 +156,7 @@ proc stm32wlx_get_chipname {} { # like mrw, but with target selection proc stm32wlx_mrw {used_target reg} { - set value "" - $used_target mem2array value 32 $reg 1 - return $value(0) + return [$used_target read_memory $reg 32 1] } # like mmw, but with target selection diff --git a/tcl/target/ti_cc3220sf.cfg b/tcl/target/ti_cc3220sf.cfg index 74269aa66..c0a7b568d 100644 --- a/tcl/target/ti_cc3220sf.cfg +++ b/tcl/target/ti_cc3220sf.cfg @@ -26,11 +26,11 @@ proc ocd_process_reset_inner { MODE } { soft_reset_halt # Initialize MSP, PSP, and PC from vector table at flash 0x01000800 - mem2array boot 32 0x01000800 2 + set boot [read_memory 0x01000800 32 2] - reg msp $boot(0) - reg psp $boot(0) - reg pc $boot(1) + reg msp [lindex $boot 0] + reg psp [lindex $boot 0] + reg pc [lindex $boot 1] if { 0 == [string compare $MODE run ] } { resume diff --git a/testing/examples/cortex/cm3-ftest.cfg b/testing/examples/cortex/cm3-ftest.cfg index 6f3fa5c81..02c8da11a 100644 --- a/testing/examples/cortex/cm3-ftest.cfg +++ b/testing/examples/cortex/cm3-ftest.cfg @@ -50,7 +50,7 @@ proc load_and_run { name halfwords n_instr } { echo "# code to trigger $name vector" set addr 0x20000000 - # array2mem should be faster, though we'd need to + # write_memory should be faster, though we'd need to # compute the resulting $addr ourselves foreach opcode $halfwords { mwh $addr $opcode From 15a72fa644739633ccd071fab840876971228f05 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 30 Jan 2022 23:57:38 +0100 Subject: [PATCH 60/79] server: fix: remove kept_alive() from server loop The kept_alive() action is specific of a server that enjoyed an unscheduled keep_alive and want to communicate it to the keep alive logic to reschedule next keep_alive(). In server loop we are not expected to call kept_alive(). Remove it! This call was erroneously added in commit 94e75e0c06c4. Later, commit 7442b26d45dc properly added the same call in gdb_put_packet(), but incorrectly left the older in place. Change-Id: If476410f870eebfbdaccdb1366ba2e9254e2fdf6 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6836 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/server/server.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/server/server.c b/src/server/server.c index 1569f5a2c..3f2970152 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -487,7 +487,6 @@ int server_loop(struct command_context *command_context) timeout_ms = polling_period; tv.tv_usec = timeout_ms * 1000; /* Only while we're sleeping we'll let others run */ - kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } From 36e29f49e1582c4fe32e3e02600c8a49129551e5 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 31 Jan 2022 11:34:12 +0100 Subject: [PATCH 61/79] log: drop global current_time The value of this variable is not shared across functions, so the variable can be local. Change-Id: I00b0444209e81c07bb57fb732f47052ad0596728 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6837 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/helper/log.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/helper/log.c b/src/helper/log.c index 686560742..12f1790e9 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -47,7 +47,6 @@ static FILE *log_output; static struct log_callback *log_callbacks; static int64_t last_time; -static int64_t current_time; static int64_t start; @@ -440,8 +439,7 @@ static void gdb_timeout_warning(int64_t delta_time) void keep_alive(void) { - current_time = timeval_ms(); - + int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; if (delta_time > KEEP_ALIVE_TIMEOUT_MS) { @@ -469,7 +467,7 @@ void keep_alive(void) /* reset keep alive timer without sending message */ void kept_alive(void) { - current_time = timeval_ms(); + int64_t current_time = timeval_ms(); int64_t delta_time = current_time - last_time; From 99c77806fea2625dfa2b5a3234267634d0342388 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 30 Jan 2022 18:42:33 +0100 Subject: [PATCH 62/79] server: change prototype of add_service() To easily add new methods to a service, pass all the methods through a struct. While there, drop the typedef for the methods and add currently unused new methods to support keep-alive and connections during keep-alive. No change in functionality. Change-Id: I2b5e7140db95021f6e7201e9d631ee340c60b453 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6838 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/server/gdb_server.c | 13 +++++++++--- src/server/ipdbg.c | 12 +++++++++-- src/server/rtt_server.c | 12 +++++++++-- src/server/server.c | 23 +++++++++----------- src/server/server.h | 36 +++++++++++++++++++++++--------- src/server/tcl_server.c | 13 +++++++++--- src/server/telnet_server.c | 12 +++++++++-- src/target/arm_tpiu_swo.c | 15 +++++++++---- src/target/openrisc/jsp_server.c | 17 ++++++++------- 9 files changed, 107 insertions(+), 46 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 4dee7e864..b76a3ef7d 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3657,6 +3657,15 @@ static int gdb_input(struct connection *connection) return ERROR_OK; } +static const struct service_driver gdb_service_driver = { + .name = "gdb", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = gdb_new_connection, + .input_handler = gdb_input, + .connection_closed_handler = gdb_connection_closed, + .keep_client_alive_handler = NULL, +}; + static int gdb_target_start(struct target *target, const char *port) { struct gdb_service *gdb_service; @@ -3673,9 +3682,7 @@ static int gdb_target_start(struct target *target, const char *port) gdb_service->core[1] = -1; target->gdb_service = gdb_service; - ret = add_service("gdb", - port, target->gdb_max_connections, &gdb_new_connection, &gdb_input, - &gdb_connection_closed, gdb_service); + ret = add_service(&gdb_service_driver, port, target->gdb_max_connections, gdb_service); /* initialize all targets gdb service with the same pointer */ { struct target_list *head; diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index ec2fae8c0..3bbcf0714 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -587,6 +587,15 @@ static int ipdbg_on_connection_closed(struct connection *connection) return ipdbg_stop_polling(connection->service->priv); } +static const struct service_driver ipdbg_service_driver = { + .name = "ipdbg", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = ipdbg_on_new_connection, + .input_handler = ipdbg_on_connection_input, + .connection_closed_handler = ipdbg_on_connection_closed, + .keep_client_alive_handler = NULL, +}; + static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool) { @@ -618,8 +627,7 @@ static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instru char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port); - retval = add_service("ipdbg", port_str_buffer, 1, &ipdbg_on_new_connection, - &ipdbg_on_connection_input, &ipdbg_on_connection_closed, service); + retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service); if (retval == ERROR_OK) { ipdbg_add_service(service); if (hub->active_services == 0 && hub->active_connections == 0) diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c index d49e4d000..c7141c0e0 100644 --- a/src/server/rtt_server.c +++ b/src/server/rtt_server.c @@ -110,6 +110,15 @@ static int rtt_input(struct connection *connection) return ERROR_OK; } +static const struct service_driver rtt_service_driver = { + .name = "rtt", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = rtt_new_connection, + .input_handler = rtt_input, + .connection_closed_handler = rtt_connection_closed, + .keep_client_alive_handler = NULL, +}; + COMMAND_HANDLER(handle_rtt_start_command) { int ret; @@ -125,8 +134,7 @@ COMMAND_HANDLER(handle_rtt_start_command) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel); - ret = add_service("rtt", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, - rtt_new_connection, rtt_input, rtt_connection_closed, service); + ret = add_service(&rtt_service_driver, CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, service); if (ret != ERROR_OK) { free(service); diff --git a/src/server/server.c b/src/server/server.c index 3f2970152..4ec196728 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -205,13 +205,8 @@ static void free_service(struct service *c) free(c); } -int add_service(char *name, - const char *port, - int max_connections, - new_connection_handler_t new_connection_handler, - input_handler_t input_handler, - connection_closed_handler_t connection_closed_handler, - void *priv) +int add_service(const struct service_driver *driver, const char *port, + int max_connections, void *priv) { struct service *c, **p; struct hostent *hp; @@ -219,14 +214,16 @@ int add_service(char *name, c = malloc(sizeof(struct service)); - c->name = strdup(name); + c->name = strdup(driver->name); c->port = strdup(port); c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */ c->fd = -1; c->connections = NULL; - c->new_connection = new_connection_handler; - c->input = input_handler; - c->connection_closed = connection_closed_handler; + c->new_connection_during_keep_alive = driver->new_connection_during_keep_alive_handler; + c->new_connection = driver->new_connection_handler; + c->input = driver->input_handler; + c->connection_closed = driver->connection_closed_handler; + c->keep_client_alive = driver->keep_client_alive_handler; c->priv = priv; c->next = NULL; long portnumber; @@ -278,7 +275,7 @@ int add_service(char *name, c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { - LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno)); + LOG_ERROR("couldn't bind %s to socket on port %d: %s", c->name, c->portnumber, strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; @@ -309,7 +306,7 @@ int add_service(char *name, socklen_t addr_in_size = sizeof(addr_in); if (getsockname(c->fd, (struct sockaddr *)&addr_in, &addr_in_size) == 0) LOG_INFO("Listening on port %hu for %s connections", - ntohs(addr_in.sin_port), name); + ntohs(addr_in.sin_port), c->name); } else if (c->type == CONNECTION_STDINOUT) { c->fd = fileno(stdin); diff --git a/src/server/server.h b/src/server/server.h index bacd1116a..00f1a428f 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -55,9 +55,25 @@ struct connection { struct connection *next; }; -typedef int (*new_connection_handler_t)(struct connection *connection); -typedef int (*input_handler_t)(struct connection *connection); -typedef int (*connection_closed_handler_t)(struct connection *connection); +struct service_driver { + /** the name of the server */ + const char *name; + /** optional minimal setup to accept a connection during keep-alive */ + int (*new_connection_during_keep_alive_handler)(struct connection *connection); + /** + * complete code to accept a new connection. + * If 'new_connection_during_keep_alive_handler' above is present, this can be + * either called alone during the server_loop, or after the function above. + * Check the implementation in gdb_server. + * */ + int (*new_connection_handler)(struct connection *connection); + /** callback to handle incoming data */ + int (*input_handler)(struct connection *connection); + /** callback to tear down the connection */ + int (*connection_closed_handler)(struct connection *connection); + /** called periodically to send keep-alive messages on the connection */ + void (*keep_client_alive_handler)(struct connection *connection); +}; struct service { char *name; @@ -68,17 +84,17 @@ struct service { struct sockaddr_in sin; int max_connections; struct connection *connections; - new_connection_handler_t new_connection; - input_handler_t input; - connection_closed_handler_t connection_closed; + int (*new_connection_during_keep_alive)(struct connection *connection); + int (*new_connection)(struct connection *connection); + int (*input)(struct connection *connection); + int (*connection_closed)(struct connection *connection); + void (*keep_client_alive)(struct connection *connection); void *priv; struct service *next; }; -int add_service(char *name, const char *port, - int max_connections, new_connection_handler_t new_connection_handler, - input_handler_t in_handler, connection_closed_handler_t close_handler, - void *priv); +int add_service(const struct service_driver *driver, const char *port, + int max_connections, void *priv); int remove_service(const char *name, const char *port); int server_host_os_entry(void); diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index e08823224..458d7eada 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -276,6 +276,15 @@ static int tcl_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver tcl_service_driver = { + .name = "tcl", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = tcl_new_connection, + .input_handler = tcl_input, + .connection_closed_handler = tcl_closed, + .keep_client_alive_handler = NULL, +}; + int tcl_init(void) { if (strcmp(tcl_port, "disabled") == 0) { @@ -283,9 +292,7 @@ int tcl_init(void) return ERROR_OK; } - return add_service("tcl", tcl_port, CONNECTION_LIMIT_UNLIMITED, - &tcl_new_connection, &tcl_input, - &tcl_closed, NULL); + return add_service(&tcl_service_driver, tcl_port, CONNECTION_LIMIT_UNLIMITED, NULL); } COMMAND_HANDLER(handle_tcl_port_command) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 2ebcff163..791a1a548 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -946,6 +946,15 @@ static int telnet_connection_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver telnet_service_driver = { + .name = "telnet", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = telnet_new_connection, + .input_handler = telnet_input, + .connection_closed_handler = telnet_connection_closed, + .keep_client_alive_handler = NULL, +}; + int telnet_init(char *banner) { if (strcmp(telnet_port, "disabled") == 0) { @@ -963,8 +972,7 @@ int telnet_init(char *banner) telnet_service->banner = banner; - int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED, - telnet_new_connection, telnet_input, telnet_connection_closed, + int ret = add_service(&telnet_service_driver, telnet_port, CONNECTION_LIMIT_UNLIMITED, telnet_service); if (ret != ERROR_OK) { diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index bfe908142..a0eba6782 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -582,6 +582,15 @@ static int wrap_read_u32(struct target *target, struct adiv5_ap *tpiu_ap, return mem_ap_read_atomic_u32(tpiu_ap, address, value); } +static const struct service_driver arm_tpiu_swo_service_driver = { + .name = "tpiu_swo_trace", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = arm_tpiu_swo_service_new_connection, + .input_handler = arm_tpiu_swo_service_input, + .connection_closed_handler = arm_tpiu_swo_service_connection_closed, + .keep_client_alive_handler = NULL, +}; + static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command *c = jim_to_command(interp); @@ -700,10 +709,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const } priv->obj = obj; LOG_INFO("starting trace server for %s on %s", obj->name, &obj->out_filename[1]); - retval = add_service("tpiu_swo_trace", &obj->out_filename[1], - CONNECTION_LIMIT_UNLIMITED, arm_tpiu_swo_service_new_connection, - arm_tpiu_swo_service_input, arm_tpiu_swo_service_connection_closed, - priv); + retval = add_service(&arm_tpiu_swo_service_driver, &obj->out_filename[1], + CONNECTION_LIMIT_UNLIMITED, priv); if (retval != ERROR_OK) { LOG_ERROR("Can't configure trace TCP port %s", &obj->out_filename[1]); return JIM_ERR; diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index e0a4475cf..54c969424 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -195,19 +195,22 @@ static int jsp_connection_closed(struct connection *connection) return ERROR_OK; } +static const struct service_driver jsp_service_driver = { + .name = "jsp", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = jsp_new_connection, + .input_handler = jsp_input, + .connection_closed_handler = jsp_connection_closed, + .keep_client_alive_handler = NULL, +}; + int jsp_init(struct or1k_jtag *jtag_info, char *banner) { struct jsp_service *jsp_service = malloc(sizeof(struct jsp_service)); jsp_service->banner = banner; jsp_service->jtag_info = jtag_info; - return add_service("jsp", - jsp_port, - 1, - jsp_new_connection, - jsp_input, - jsp_connection_closed, - jsp_service); + return add_service(&jsp_service_driver, jsp_port, 1, jsp_service); } COMMAND_HANDLER(handle_jsp_port_command) From 5c26fd7ab8916d25cb876487d39ec45e3c936d55 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 31 Jan 2022 10:08:29 +0100 Subject: [PATCH 63/79] gdb_server: simplify logic to enable/disable gdb_log_callback() GDB client cannot always display generic messages from OpenOCD. The callback gdb_log_callback() is continuously added and removed to follow the GDB status and thus enabling/disabling sending the OpenOCD output to GDB. While this is a nice stress test for log_{add,remove}_callback(), it is also a waste of computational resources that could impact the speed of OpenOCD during GDB user interactions. Add a connection-level flag to enable/disable the log callback and simply change the flag instead of adding/removing the callback. Use an enum for the flag instead of a bool. This improves code readability and allows setting other states, e.g. keep-alive through asynchronous notification https://review.openocd.org/4828/ Change-Id: I072d3c6928dedfd0cef0abe7acf9bdd4b89dbf5b Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6839 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/server/gdb_server.c | 42 ++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b76a3ef7d..b47e312a3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -61,6 +61,13 @@ * found in most modern embedded processors. */ +enum gdb_output_flag { + /* GDB doesn't accept 'O' packets */ + GDB_OUTPUT_NO, + /* GDB accepts 'O' packets */ + GDB_OUTPUT_ALL, +}; + struct target_desc_format { char *tdesc; uint32_t tdesc_length; @@ -97,6 +104,8 @@ struct gdb_connection { struct target_desc_format target_desc; /* temporarily used for thread list support */ char *thread_list; + /* flag to mask the output from gdb_log_callback() */ + enum gdb_output_flag output_flag; }; #if 0 @@ -478,7 +487,7 @@ static int gdb_put_packet_inner(struct connection *connection, break; else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = true; @@ -489,7 +498,7 @@ static int gdb_put_packet_inner(struct connection *connection, break; else if (reply == '-') { /* Stop sending output packets for now */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); @@ -932,7 +941,7 @@ static void gdb_frontend_halted(struct target *target, struct connection *connec */ if (gdb_connection->frontend_state == TARGET_RUNNING) { /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; /* check fileio first */ if (target_get_gdb_fileio_info(target, target->fileio_info) == ERROR_OK) @@ -992,6 +1001,7 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->target_desc.tdesc = NULL; gdb_connection->target_desc.tdesc_length = 0; gdb_connection->thread_list = NULL; + gdb_connection->output_flag = GDB_OUTPUT_NO; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); @@ -1076,6 +1086,8 @@ static int gdb_new_connection(struct connection *connection) * register callback to be informed about target events */ target_register_event_callback(gdb_target_callback_event_handler, connection); + log_add_callback(gdb_log_callback, connection); + return ERROR_OK; } @@ -2728,7 +2740,7 @@ static int gdb_query_packet(struct connection *connection, cmd[len] = 0; /* We want to print all debug output to GDB connection */ - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_timer_callbacks_now(); /* some commands need to know the GDB connection, make note of current * GDB connection. */ @@ -2736,7 +2748,7 @@ static int gdb_query_packet(struct connection *connection, command_run_line(cmd_ctx, cmd); current_gdb_connection = NULL; target_call_timer_callbacks_now(); - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); } gdb_put_packet(connection, "OK", 2); @@ -2917,7 +2929,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p if (parse[0] == 'c') { gdb_running_type = 'c'; LOG_DEBUG("target %s continue", target_name(target)); - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; retval = target_resume(target, 1, 0, 0, 0); if (retval == ERROR_TARGET_NOT_HALTED) LOG_INFO("target %s was not halted when resume was requested", target_name(target)); @@ -3006,7 +3018,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p } LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id); - log_add_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_ALL; target_call_event_callbacks(ct, TARGET_EVENT_GDB_START); /* @@ -3027,7 +3039,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p "T05thread:%016"PRIx64";", thread_id); gdb_put_packet(connection, sig_reply, sig_reply_len); - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; return true; } @@ -3039,7 +3051,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p LOG_DEBUG("stepi ignored. GDB will now fetch the register state " "from the target."); gdb_sig_halted(connection); - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; } else gdb_connection->frontend_state = TARGET_RUNNING; return true; @@ -3057,7 +3069,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p /* send back signal information */ gdb_signal_reply(ct, connection); /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_connection->output_flag = GDB_OUTPUT_NO; } else gdb_connection->frontend_state = TARGET_RUNNING; } else { @@ -3387,6 +3399,10 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line, struct connection *connection = priv; struct gdb_connection *gdb_con = connection->priv; + if (gdb_con->output_flag == GDB_OUTPUT_NO) + /* No out allowed */ + return; + if (gdb_con->busy) { /* do not reply this using the O packet */ return; @@ -3489,7 +3505,7 @@ static int gdb_input_inner(struct connection *connection) case 's': { gdb_thread_packet(connection, packet, packet_size); - log_add_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_ALL; if (gdb_con->mem_write_error) { LOG_ERROR("Memory write failure!"); @@ -3532,7 +3548,7 @@ static int gdb_input_inner(struct connection *connection) gdb_sig_halted(connection); /* stop forwarding log packets! */ - log_remove_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_NO; } else { /* We're running/stepping, in which case we can * forward log output until the target is halted @@ -3604,7 +3620,7 @@ static int gdb_input_inner(struct connection *connection) * Fretcode,errno,Ctrl-C flag;call-specific attachment */ gdb_con->frontend_state = TARGET_RUNNING; - log_add_callback(gdb_log_callback, connection); + gdb_con->output_flag = GDB_OUTPUT_ALL; gdb_fileio_response_packet(connection, packet, packet_size); break; From 4e5dbecd9b1ac780181e04f8b51a4cd133c4cdbe Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 31 Jan 2022 10:51:49 +0100 Subject: [PATCH 64/79] keep-alive: drop link with log framework OpenOCD implements the GDB keep-alive by sending empty strings as output for GDB client. This has been implemented as part of the log framework, creating an odd dependency. Move the keep-alive notifications out of log framework. For the moment, keep keep_alive() inside log.c, but it should be moved in server.c This should also fix an old issue with KDE Konsole when tab alert for activity is enabled. The empty strings is sent to all the connections, including telnet, and causes the tab running OpenOCD telnet to continuously show activity even when no new text is printed. Anyway, I cannot replicate this issue anymore. Change-Id: Iebb00b00fb74b3c9665d9e1ddd3c055275bfbd43 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6840 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/helper/log.c | 36 ++++++++++++++++-------------------- src/server/gdb_server.c | 24 +++++++++++++++++++++++- src/server/server.c | 8 ++++++++ src/server/server.h | 2 ++ 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/helper/log.c b/src/helper/log.c index 12f1790e9..106d22867 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -30,6 +30,7 @@ #include "command.h" #include "replacements.h" #include "time_support.h" +#include #include @@ -110,32 +111,27 @@ static void log_puts(enum log_levels level, if (f) file = f + 1; - if (strlen(string) > 0) { - if (debug_level >= LOG_LVL_DEBUG) { - /* print with count and time information */ - int64_t t = timeval_ms() - start; + if (debug_level >= LOG_LVL_DEBUG) { + /* print with count and time information */ + int64_t t = timeval_ms() - start; #ifdef _DEBUG_FREE_SPACE_ - struct mallinfo info; - info = mallinfo(); + struct mallinfo info; + info = mallinfo(); #endif - fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" + fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()" #ifdef _DEBUG_FREE_SPACE_ - " %d" + " %d" #endif - ": %s", log_strings[level + 1], count, t, file, line, function, + ": %s", log_strings[level + 1], count, t, file, line, function, #ifdef _DEBUG_FREE_SPACE_ - info.fordblks, + info.fordblks, #endif - string); - } else { - /* if we are using gdb through pipes then we do not want any output - * to the pipe otherwise we get repeated strings */ - fprintf(log_output, "%s%s", - (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); - } + string); } else { - /* Empty strings are sent to log callbacks to keep e.g. gdbserver alive, here we do - *nothing. */ + /* if we are using gdb through pipes then we do not want any output + * to the pipe otherwise we get repeated strings */ + fprintf(log_output, "%s%s", + (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); } fflush(log_output); @@ -452,7 +448,7 @@ void keep_alive(void) last_time = current_time; /* this will keep the GDB connection alive */ - LOG_USER_N("%s", ""); + server_keep_clients_alive(); /* DANGER!!!! do not add code to invoke e.g. target event processing, * jim timer processing, etc. it can cause infinite recursion + diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b47e312a3..f5736196e 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3673,13 +3673,35 @@ static int gdb_input(struct connection *connection) return ERROR_OK; } +static void gdb_keep_client_alive(struct connection *connection) +{ + struct gdb_connection *gdb_con = connection->priv; + + if (gdb_con->busy) { + /* do not send packets, retry asap */ + return; + } + + switch (gdb_con->output_flag) { + case GDB_OUTPUT_NO: + /* no need for keep-alive */ + break; + case GDB_OUTPUT_ALL: + /* send an empty O packet */ + gdb_output_con(connection, ""); + break; + default: + break; + } +} + static const struct service_driver gdb_service_driver = { .name = "gdb", .new_connection_during_keep_alive_handler = NULL, .new_connection_handler = gdb_new_connection, .input_handler = gdb_input, .connection_closed_handler = gdb_connection_closed, - .keep_client_alive_handler = NULL, + .keep_client_alive_handler = gdb_keep_client_alive, }; static int gdb_target_start(struct target *target, const char *port) diff --git a/src/server/server.c b/src/server/server.c index 4ec196728..dd408048c 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -421,6 +421,14 @@ static int remove_services(void) return ERROR_OK; } +void server_keep_clients_alive(void) +{ + for (struct service *s = services; s; s = s->next) + if (s->keep_client_alive) + for (struct connection *c = s->connections; c; c = c->next) + s->keep_client_alive(c); +} + int server_loop(struct command_context *command_context) { struct service *service; diff --git a/src/server/server.h b/src/server/server.h index 00f1a428f..a6b1963a6 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -106,6 +106,8 @@ int server_quit(void); void server_free(void); void exit_on_signal(int sig); +void server_keep_clients_alive(void); + int server_loop(struct command_context *command_context); int server_register_commands(struct command_context *context); From b9526f1401271a00dd72cf7ec8bded32e77d41ff Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 6 Apr 2020 13:30:26 +0100 Subject: [PATCH 65/79] semihosting: permit redirection of semihosting I/O to TCP This command permits the usage of a TCP port to perform debug and stdio operations: - debug : READC, WRITEC and WRITE0 - stdio : READ, WRITE This will permit the separation of semihosting message from OpenOCD log, and separate semihosting messages per core. syntax: arm semihosting_redirect (disable | tcp [debug|stdio|all]) this allows to select which operations to be performed via TCP (debug, stdio or all (default)). Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected. tested using netcat on ubuntu Change-Id: I37053463667ba109d52429d4f98bc98d0ede298d Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/5562 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 11 ++ src/target/semihosting_common.c | 332 ++++++++++++++++++++++++++++++-- src/target/semihosting_common.h | 17 ++ 3 files changed, 343 insertions(+), 17 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 0cd9621ff..1b6d06302 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9370,6 +9370,17 @@ requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn +@deffn {Command} {arm semihosting_redirect} (@option{disable} | @option{tcp} +[@option{debug}|@option{stdio}|@option{all}) +@cindex ARM semihosting +Redirect semihosting messages to a specified TCP port. + +This command redirects debug (READC, WRITEC and WRITE0) and stdio (READ, WRITE) +semihosting operations to the specified TCP port. +The command allows to select which type of operations to redirect (debug, stdio, all (default)). +Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected. +@end deffn + @deffn {Command} {arm semihosting_cmdline} [@option{enable}|@option{disable}] @cindex ARM semihosting Set the command line to be passed to the debugger. diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 9e60de572..38035e493 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -129,6 +129,11 @@ int semihosting_common_init(struct target *target, void *setup, } semihosting->is_active = false; + semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + semihosting->tcp_connection = NULL; + semihosting->stdin_fd = -1; + semihosting->stdout_fd = -1; + semihosting->stderr_fd = -1; semihosting->is_fileio = false; semihosting->hit_fileio = false; semihosting->is_resumable = false; @@ -154,6 +159,141 @@ int semihosting_common_init(struct target *target, void *setup, return ERROR_OK; } +struct semihosting_tcp_service { + struct semihosting *semihosting; + char *name; + int error; +}; + +static bool semihosting_is_redirected(struct semihosting *semihosting, int fd) +{ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_NONE) + return false; + + bool is_read_op = false; + + switch (semihosting->op) { + /* check debug semihosting operations: READC, WRITEC and WRITE0 */ + case SEMIHOSTING_SYS_READC: + is_read_op = true; + /* fall through */ + case SEMIHOSTING_SYS_WRITEC: + case SEMIHOSTING_SYS_WRITE0: + /* debug operations are redirected when CFG is either DEBUG or ALL */ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_STDIO) + return false; + break; + + /* check stdio semihosting operations: READ and WRITE */ + case SEMIHOSTING_SYS_READ: + is_read_op = true; + /* fall through */ + case SEMIHOSTING_SYS_WRITE: + /* stdio operations are redirected when CFG is either STDIO or ALL */ + if (semihosting->redirect_cfg == SEMIHOSTING_REDIRECT_CFG_DEBUG) + return false; + break; + + default: + return false; + } + + if (is_read_op) + return fd == semihosting->stdin_fd; + + /* write operation */ + return fd == semihosting->stdout_fd || fd == semihosting->stderr_fd; +} + +static ssize_t semihosting_redirect_write(struct semihosting *semihosting, void *buf, int size) +{ + if (!semihosting->tcp_connection) { + LOG_ERROR("No connected TCP client for semihosting"); + semihosting->sys_errno = EBADF; /* Bad file number */ + return -1; + } + + struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; + + int retval = connection_write(semihosting->tcp_connection, buf, size); + + if (retval < 0) + log_socket_error(service->name); + + return retval; +} + +static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *buf, int size) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_write(semihosting, buf, size); + + /* default write */ + return write(fd, buf, size); +} + +static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size) +{ + if (!semihosting->tcp_connection) { + LOG_ERROR("No connected TCP client for semihosting"); + semihosting->sys_errno = EBADF; /* Bad file number */ + return -1; + } + + struct semihosting_tcp_service *service = semihosting->tcp_connection->service->priv; + + service->error = ERROR_OK; + semihosting->tcp_connection->input_pending = true; + + int retval = connection_read(semihosting->tcp_connection, buf, size); + + if (retval <= 0) + service->error = ERROR_SERVER_REMOTE_CLOSED; + + if (retval < 0) + log_socket_error(service->name); + + semihosting->tcp_connection->input_pending = false; + + return retval; +} + +static inline int semihosting_putchar(struct semihosting *semihosting, int fd, int c) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_write(semihosting, &c, 1); + + /* default putchar */ + return putchar(c); +} + +static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd, void *buf, int size) +{ + if (semihosting_is_redirected(semihosting, fd)) + return semihosting_redirect_read(semihosting, buf, size); + + /* default read */ + ssize_t result = read(fd, buf, size); + semihosting->sys_errno = errno; + + return result; +} + +static inline int semihosting_getchar(struct semihosting *semihosting, int fd) +{ + if (semihosting_is_redirected(semihosting, fd)) { + unsigned char c; + + if (semihosting_redirect_read(semihosting, &c, 1) > 0) + return c; + + return EOF; + } + + /* default getchar */ + return getchar(); +} + /** * User operation parameter string storage buffer. Contains valid data when the * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running. @@ -756,20 +896,23 @@ int semihosting_common(struct target *target) * - 4-7 ("w") for stdout, * - 8-11 ("a") for stderr */ if (mode < 4) { - semihosting->result = dup( - STDIN_FILENO); + int fd = dup(STDIN_FILENO); + semihosting->result = fd; + semihosting->stdin_fd = fd; semihosting->sys_errno = errno; LOG_DEBUG("dup(STDIN)=%d", (int)semihosting->result); } else if (mode < 8) { - semihosting->result = dup( - STDOUT_FILENO); + int fd = dup(STDOUT_FILENO); + semihosting->result = fd; + semihosting->stdout_fd = fd; semihosting->sys_errno = errno; LOG_DEBUG("dup(STDOUT)=%d", (int)semihosting->result); } else { - semihosting->result = dup( - STDERR_FILENO); + int fd = dup(STDERR_FILENO); + semihosting->result = fd; + semihosting->stderr_fd = fd; semihosting->sys_errno = errno; LOG_DEBUG("dup(STDERR)=%d", (int)semihosting->result); @@ -845,8 +988,7 @@ int semihosting_common(struct target *target) semihosting->result = -1; semihosting->sys_errno = ENOMEM; } else { - semihosting->result = read(fd, buf, len); - semihosting->sys_errno = errno; + semihosting->result = semihosting_read(semihosting, fd, buf, len); LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%d", fd, addr, @@ -886,7 +1028,7 @@ int semihosting_common(struct target *target) LOG_ERROR("SYS_READC not supported by semihosting fileio"); return ERROR_FAIL; } - semihosting->result = getchar(); + semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); LOG_DEBUG("getchar()=%d", (int)semihosting->result); break; @@ -1189,7 +1331,7 @@ int semihosting_common(struct target *target) free(buf); return retval; } - semihosting->result = write(fd, buf, len); + semihosting->result = semihosting_write(semihosting, fd, buf, len); semihosting->sys_errno = errno; LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%d", fd, @@ -1234,7 +1376,7 @@ int semihosting_common(struct target *target) retval = target_read_memory(target, addr, 1, 1, &c); if (retval != ERROR_OK) return retval; - putchar(c); + semihosting_putchar(semihosting, semihosting->stdout_fd, c); semihosting->result = 0; } break; @@ -1278,7 +1420,7 @@ int semihosting_common(struct target *target) return retval; if (!c) break; - putchar(c); + semihosting_putchar(semihosting, semihosting->stdout_fd, c); } while (1); semihosting->result = 0; } @@ -1557,6 +1699,70 @@ static void semihosting_set_field(struct target *target, uint64_t value, target_buffer_set_u32(target, fields + (index * 4), value); } +/* ------------------------------------------------------------------------- + * Semihosting redirect over TCP structs and functions */ + +static int semihosting_service_new_connection_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + service->semihosting->tcp_connection = connection; + + return ERROR_OK; +} + +static int semihosting_service_input_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + + if (!connection->input_pending) { + /* consume received data, not for semihosting IO */ + const int buf_len = 100; + char buf[buf_len]; + int bytes_read = connection_read(connection, buf, buf_len); + + if (bytes_read == 0) { + return ERROR_SERVER_REMOTE_CLOSED; + } else if (bytes_read == -1) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + } else if (service->error != ERROR_OK) { + return ERROR_SERVER_REMOTE_CLOSED; + } + + return ERROR_OK; +} + +static int semihosting_service_connection_closed_handler(struct connection *connection) +{ + struct semihosting_tcp_service *service = connection->service->priv; + if (service) { + free(service->name); + free(service); + } + + return ERROR_OK; +} + +static void semihosting_tcp_close_cnx(struct semihosting *semihosting) +{ + if (!semihosting->tcp_connection) + return; + + struct service *service = semihosting->tcp_connection->service; + remove_service(service->name, service->port); + semihosting->tcp_connection = NULL; + +} + +static const struct service_driver semihosting_service_driver = { + .name = "semihosting", + .new_connection_during_keep_alive_handler = NULL, + .new_connection_handler = semihosting_service_new_connection_handler, + .input_handler = semihosting_service_input_handler, + .connection_closed_handler = semihosting_service_connection_closed_handler, + .keep_client_alive_handler = NULL, +}; /* ------------------------------------------------------------------------- * Common semihosting commands handlers. */ @@ -1602,6 +1808,91 @@ COMMAND_HANDLER(handle_common_semihosting_command) return ERROR_OK; } +COMMAND_HANDLER(handle_common_semihosting_redirect_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (target == NULL) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct semihosting *semihosting = target->semihosting; + if (!semihosting) { + command_print(CMD, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + if (!semihosting->is_active) { + command_print(CMD, "semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + enum semihosting_redirect_config cfg; + const char *port; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (strcmp(CMD_ARGV[0], "disable") == 0) { + cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; + } else if (strcmp(CMD_ARGV[0], "tcp") == 0) { + if (CMD_ARGC < 2 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + port = CMD_ARGV[1]; + + cfg = SEMIHOSTING_REDIRECT_CFG_ALL; + if (CMD_ARGC == 3) { + if (strcmp(CMD_ARGV[2], "debug") == 0) + cfg = SEMIHOSTING_REDIRECT_CFG_DEBUG; + else if (strcmp(CMD_ARGV[2], "stdio") == 0) + cfg = SEMIHOSTING_REDIRECT_CFG_STDIO; + else if (strcmp(CMD_ARGV[2], "all") != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + } + } else { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + semihosting_tcp_close_cnx(semihosting); + semihosting->redirect_cfg = SEMIHOSTING_REDIRECT_CFG_NONE; + + if (cfg != SEMIHOSTING_REDIRECT_CFG_NONE) { + struct semihosting_tcp_service *service = + calloc(1, sizeof(struct semihosting_tcp_service)); + if (!service) { + LOG_ERROR("Failed to allocate semihosting TCP service."); + return ERROR_FAIL; + } + + service->semihosting = semihosting; + + service->name = alloc_printf("%s semihosting service", target_name(target)); + if (!service->name) { + LOG_ERROR("Out of memory"); + free(service); + return ERROR_FAIL; + } + + int ret = add_service(&semihosting_service_driver, + port, 1, service); + + if (ret != ERROR_OK) { + LOG_ERROR("failed to initialize %s", service->name); + free(service->name); + free(service); + return ERROR_FAIL; + } + } + + semihosting->redirect_cfg = cfg; + + return ERROR_OK; +} + COMMAND_HANDLER(handle_common_semihosting_fileio_command) { struct target *target = get_current_target(CMD_CTX); @@ -1721,35 +2012,42 @@ COMMAND_HANDLER(handle_common_semihosting_read_user_param_command) const struct command_registration semihosting_common_handlers[] = { { - "semihosting", + .name = "semihosting", .handler = handle_common_semihosting_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting operations", }, { - "semihosting_cmdline", + .name = "semihosting_redirect", + .handler = handle_common_semihosting_redirect_command, + .mode = COMMAND_EXEC, + .usage = "(disable | tcp ['debug'|'stdio'|'all'])", + .help = "redirect semihosting IO", + }, + { + .name = "semihosting_cmdline", .handler = handle_common_semihosting_cmdline, .mode = COMMAND_EXEC, .usage = "arguments", .help = "command line arguments to be passed to program", }, { - "semihosting_fileio", + .name = "semihosting_fileio", .handler = handle_common_semihosting_fileio_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting fileio operations", }, { - "semihosting_resexit", + .name = "semihosting_resexit", .handler = handle_common_semihosting_resumable_exit_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, { - "semihosting_read_user_param", + .name = "semihosting_read_user_param", .handler = handle_common_semihosting_read_user_param_command, .mode = COMMAND_EXEC, .usage = "", diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index 6eb9ca252..459faf656 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -26,6 +26,7 @@ #include #include #include "helper/replacements.h" +#include /* * According to: @@ -95,6 +96,13 @@ enum semihosting_reported_exceptions { ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35), }; +enum semihosting_redirect_config { + SEMIHOSTING_REDIRECT_CFG_NONE, + SEMIHOSTING_REDIRECT_CFG_DEBUG, + SEMIHOSTING_REDIRECT_CFG_STDIO, + SEMIHOSTING_REDIRECT_CFG_ALL, +}; + struct target; /* @@ -105,6 +113,15 @@ struct semihosting { /** A flag reporting whether semihosting is active. */ bool is_active; + /** Semihosting STDIO file descriptors */ + int stdin_fd, stdout_fd, stderr_fd; + + /** redirection configuration, NONE by default */ + enum semihosting_redirect_config redirect_cfg; + + /** Handle to redirect semihosting print via tcp */ + struct connection *tcp_connection; + /** A flag reporting whether semihosting fileio is active. */ bool is_fileio; From 414c469cdaef60eeea02dc54a94eb904555cf35d Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Wed, 2 Feb 2022 23:28:50 +0100 Subject: [PATCH 66/79] stlink: enable queuing with stlink-server API v3 ST-Link Server 2.1.0-1 fixes concurrency issue with RW_MISC command Starting from this version the ST-Link Server API is now v3. In this change we save the ST-Link Server version, and check if the API is greater or equal to 3 to enable the queuing. Change-Id: I239eb81024700514c607a269b66651f457206faa Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6876 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/stlink_usb.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 2f61bf946..325848f86 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -156,6 +156,13 @@ struct stlink_usb_priv_s { struct libusb_transfer *trans; }; +struct stlink_tcp_version { + uint32_t api; + uint32_t major; + uint32_t minor; + uint32_t build; +}; + struct stlink_tcp_priv_s { /** */ int fd; @@ -169,6 +176,8 @@ struct stlink_tcp_priv_s { uint8_t *send_buf; /** */ uint8_t *recv_buf; + /** */ + struct stlink_tcp_version version; }; struct stlink_backend_s { @@ -3532,16 +3541,19 @@ static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param) return ERROR_FAIL; } - uint32_t api_ver = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]); - uint32_t ver_major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); - uint32_t ver_minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]); - uint32_t ver_build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]); + h->tcp_backend_priv.version.api = le_to_h_u32(&h->tcp_backend_priv.recv_buf[0]); + h->tcp_backend_priv.version.major = le_to_h_u32(&h->tcp_backend_priv.recv_buf[4]); + h->tcp_backend_priv.version.minor = le_to_h_u32(&h->tcp_backend_priv.recv_buf[8]); + h->tcp_backend_priv.version.build = le_to_h_u32(&h->tcp_backend_priv.recv_buf[12]); LOG_INFO("stlink-server API v%d, version %d.%d.%d", - api_ver, ver_major, ver_minor, ver_build); + h->tcp_backend_priv.version.api, + h->tcp_backend_priv.version.major, + h->tcp_backend_priv.version.minor, + h->tcp_backend_priv.version.build); /* in stlink-server API v1 sending more than 1428 bytes will cause stlink-server * to crash in windows: select a safe default value (1K) */ - if (api_ver < 2) + if (h->tcp_backend_priv.version.api < 2) h->max_mem_packet = (1 << 10); /* refresh stlink list (re-enumerate) */ @@ -4468,11 +4480,12 @@ static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue * if (!(h->version.flags & STLINK_F_HAS_RW_MISC)) return 0; /* - * RW_MISC sequence doesn't lock the st-link, so are not safe in shared mode. + * Before stlink-server API v3, RW_MISC sequence doesn't lock the st-link, + * so are not safe in shared mode. * Don't use it with TCP backend to prevent any issue in case of sharing. * This further degrades the performance, on top of TCP server overhead. */ - if (h->backend == &stlink_tcp_backend) + if (h->backend == &stlink_tcp_backend && h->tcp_backend_priv.version.api < 3) return 0; for (i = 0; i < len; i++) { From 9cdbe61aab418bdf75bc443b16ce4cdf96732e3e Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Thu, 16 Sep 2021 17:47:31 +0100 Subject: [PATCH 67/79] tcl/stm32u5x: fix clock config used at 'reset init' Change-Id: If004a04b93be47439809ea3fa336b14de7a12277 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6597 Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek Tested-by: jenkins --- tcl/target/stm32u5x.cfg | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tcl/target/stm32u5x.cfg b/tcl/target/stm32u5x.cfg index b627d4180..44b51e2b6 100644 --- a/tcl/target/stm32u5x.cfg +++ b/tcl/target/stm32u5x.cfg @@ -22,21 +22,24 @@ proc stm32u5x_clock_config {} { # RCC_AHB3ENR = PWREN mww [expr {0x46020C94 + $offset}] 0x00000004 # delay for register clock enable (read back reg) - mrw [expr {0x56020C94 + $offset}] + mrw [expr {0x46020C94 + $offset}] # PWR_VOSR : VOS Range 1 - mww [expr {0x4602080C + $offset}] 0x00030000 - # delay for register write (read back reg) - mrw [expr {0x4602080C + $offset}] + mmw [expr {0x4602080C + $offset}] 0x00030000 0 + # while !(PWR_VOSR & VOSRDY) + while {!([mrw [expr {0x4602080C + $offset}]] & 0x00008000)} {} # FLASH_ACR : 4 WS for 160 MHz HCLK mww [expr {0x40022000 + $offset}] 0x00000004 - # RCC_PLL1CFGR => PLL1M=0000=/1, PLL1SRC=MSI 4MHz - mww [expr {0x46020C28 + $offset}] 0x00000001 + # RCC_PLL1CFGR => PLL1MBOOST=0, PLL1M=0=/1, PLL1FRACEN=0, PLL1SRC=MSI 4MHz + # PLL1REN=1, PLL1RGE => VCOInputRange=PLLInputRange_4_8 + mww [expr {0x46020C28 + $offset}] 0x00040009 + # Enable EPOD Booster + mmw [expr {0x4602080C + $offset}] 0x00040000 0 + # while !(PWR_VOSR & BOOSTRDY) + while {!([mrw [expr {0x4602080C + $offset}]] & 0x00004000)} {} # RCC_PLL1DIVR => PLL1P=PLL1Q=PLL1R=000001=/2, PLL1N=0x4F=80 # fVCO = 4 x 80 /1 = 320 # SYSCLOCK = fVCO/PLL1R = 320/2 = 160 MHz - mmw [expr {0x46020C34 + $offset}] 0x0000004F 0 - # RCC_PLL1CFGR => PLL1REN=1 - mmw [expr {0x46020C28 + $offset}] 0x00040000 0 + mww [expr {0x46020C34 + $offset}] 0x0101024F # RCC_CR |= PLL1ON mmw [expr {0x46020C00 + $offset}] 0x01000000 0 # while !(RCC_CR & PLL1RDY) From ab43721be6ff7470ff8b9771c95c1d5661a5a689 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 28 Feb 2022 13:55:26 +0100 Subject: [PATCH 68/79] flash/stm32l4x: fix auto-probe when RDP is promoted from 0 to 0.5 Considering this use case: (using STM32 L5 or U5) 1- first probe : TZEN enabled, RDP level 0 flash_regs_base |= STM32L5_REGS_SEC_OFFSET => 0x50022000 2- the user promotes the RDP to level 0.5 3- the second probe, fails to read OPTR using secure flags_regs_base: used OPTR address is 0x50022040 Step 3 fails because when RDP is level 0.5, we should use Non-Secure flash registers. To fix this, always use NS flash regs to read OPTR in probe functions. Fixes: 80d323c6e82b (flash/stm32l4x: introduce auto-probe when OPTR is changed) Change-Id: I296aa633972b0c410b927488c999584a07b912d3 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6864 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/flash/nor/stm32l4x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index fd0338899..7b35a0635 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1757,7 +1757,7 @@ static int stm32l4_probe(struct flash_bank *bank) * Ask the flash infrastructure to ensure required alignment */ bank->write_start_alignment = bank->write_end_alignment = stm32l4_info->data_width; - /* initialise the flash registers layout */ + /* Initialize the flash registers layout */ if (part_info->flags & F_HAS_L5_FLASH_REGS) stm32l4_info->flash_regs = stm32l5_ns_flash_regs; else @@ -1770,7 +1770,7 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_sync_rdp_tzen(bank); - /* for devices with trustzone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */ + /* for devices with TrustZone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) { if (part_info->flags & F_HAS_L5_FLASH_REGS) { stm32l4_info->flash_regs_base |= STM32L5_REGS_SEC_OFFSET; @@ -2046,8 +2046,19 @@ static int stm32l4_auto_probe(struct flash_bank *bank) if (stm32l4_info->probed) { uint32_t optr_cur; + /* save flash_regs_base */ + uint32_t saved_flash_regs_base = stm32l4_info->flash_regs_base; + + /* for devices with TrustZone, use NS flash registers to read OPTR */ + if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS) + stm32l4_info->flash_regs_base &= ~STM32L5_REGS_SEC_OFFSET; + /* read flash option register and re-probe if optr value is changed */ int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &optr_cur); + + /* restore saved flash_regs_base */ + stm32l4_info->flash_regs_base = saved_flash_regs_base; + if (retval != ERROR_OK) return retval; From fb43f1ff4e2f0638110ffcc4e63bee8b5361db64 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 13 Jun 2021 11:21:18 +0200 Subject: [PATCH 69/79] target: Rework 'set' variable of break-/watchpoints The 'set' variable name suggests a boolean data type which determines whether a breakpoint (or watchpoint) is active. However, it is also used to store the number of the breakpoint. This encoding leads to inconsistent value assignments: boolean and integer values are mixed. Also, associated hardware comparator numbers, which are usually numbered from 0, cannot be used directly. An additional offset is required to store the comparator numbers. In order to make the code more readable and the value assignment more consistent, change the variable name to 'is_set', its data type to 'bool' and introduce a dedicated variable for the break-/watchpoint number. In order to make the review easier, the data types of various related variables (e.g. number of breakpoints) are not changed. While at it, fix a few coding style issues. Change-Id: I2193f5639247cce6b80580d4c1c6afee916aeb82 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6319 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/aarch64.c | 48 +++++++++++++++++------------------ src/target/arc.c | 38 ++++++++++++++-------------- src/target/arm7_9_common.c | 49 ++++++++++++++++++------------------ src/target/arm_dpm.c | 6 ++--- src/target/armv8_dpm.c | 6 ++--- src/target/breakpoints.c | 6 ++--- src/target/breakpoints.h | 18 +++++++++++-- src/target/cortex_a.c | 48 +++++++++++++++++------------------ src/target/cortex_m.c | 42 +++++++++++++++---------------- src/target/esirisc.c | 16 ++++++------ src/target/lakemont.c | 4 +-- src/target/mips_m4k.c | 34 ++++++++++++------------- src/target/mips_mips64.c | 33 ++++++++++++------------ src/target/nds32.c | 2 +- src/target/nds32_v3_common.c | 6 ++--- src/target/openrisc/or1k.c | 8 +++--- src/target/riscv/riscv.c | 14 +++++------ src/target/stm8.c | 34 ++++++++++++------------- src/target/target.c | 16 ++++++------ src/target/x86_32_common.c | 30 +++++++++++----------- src/target/xscale.c | 42 ++++++++++++++++--------------- 21 files changed, 258 insertions(+), 242 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index a45322d2f..8838da927 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1236,7 +1236,7 @@ static int aarch64_set_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1249,7 +1249,7 @@ static int aarch64_set_breakpoint(struct target *target, LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) @@ -1333,7 +1333,7 @@ static int aarch64_set_breakpoint(struct target *target, breakpoint->address & 0xFFFFFFFFFFFFFFFE, breakpoint->length); - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } /* Ensure that halting debug mode is enable */ @@ -1357,7 +1357,7 @@ static int aarch64_set_context_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1371,7 +1371,7 @@ static int aarch64_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (1 << 13) | (byte_addr_select << 5) @@ -1410,7 +1410,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1435,7 +1435,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin return ERROR_FAIL; } - breakpoint->set = brp_1 + 1; + breakpoint_hw_set(breakpoint, brp_1); breakpoint->linked_brp = brp_2; control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) @@ -1490,16 +1490,16 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - int brp_i = breakpoint->set - 1; + int brp_i = breakpoint->number; int brp_j = breakpoint->linked_brp; - if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1549,12 +1549,12 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br return retval; breakpoint->linked_brp = 0; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } else { - int brp_i = breakpoint->set - 1; - if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1579,7 +1579,7 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } } else { @@ -1611,7 +1611,7 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br breakpoint->address & 0xFFFFFFFFFFFFFFFE, breakpoint->length); } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1676,7 +1676,7 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { aarch64_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available++; @@ -1696,7 +1696,7 @@ static int aarch64_set_watchpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *wp_list = aarch64->wp_list; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -1764,7 +1764,7 @@ static int aarch64_set_watchpoint(struct target *target, } wp_list[wp_i].used = 1; - watchpoint->set = wp_i + 1; + watchpoint_set(watchpoint, wp_i); return ERROR_OK; } @@ -1773,18 +1773,18 @@ static int aarch64_set_watchpoint(struct target *target, static int aarch64_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { - int retval, wp_i; + int retval; struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *wp_list = aarch64->wp_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - wp_i = watchpoint->set - 1; - if ((wp_i < 0) || (wp_i >= aarch64->wp_num)) { + int wp_i = watchpoint->number; + if (wp_i >= aarch64->wp_num) { LOG_DEBUG("Invalid WP number in watchpoint"); return ERROR_OK; } @@ -1809,7 +1809,7 @@ static int aarch64_unset_watchpoint(struct target *target, (uint32_t)wp_list[wp_i].value); if (retval != ERROR_OK) return retval; - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -1837,7 +1837,7 @@ static int aarch64_remove_watchpoint(struct target *target, { struct aarch64_common *aarch64 = target_to_aarch64(target); - if (watchpoint->set) { + if (watchpoint->is_set) { aarch64_unset_watchpoint(target, watchpoint); aarch64->wp_num_available++; } diff --git a/src/target/arc.c b/src/target/arc.c index 4b546c3b4..471f16a98 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1500,7 +1500,7 @@ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num, static int arc_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1542,7 +1542,7 @@ static int arc_set_breakpoint(struct target *target, return ERROR_COMMAND_ARGUMENT_INVALID; } - breakpoint->set = 64; /* Any nice value but 0 */ + breakpoint->is_set = true; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; @@ -1563,7 +1563,7 @@ static int arc_set_breakpoint(struct target *target, breakpoint->address, AP_AC_TT_READWRITE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); ap_list[bp_num].used = 1; ap_list[bp_num].bp_value = breakpoint->address; ap_list[bp_num].type = ARC_AP_BREAKPOINT; @@ -1588,7 +1588,7 @@ static int arc_unset_breakpoint(struct target *target, { int retval = ERROR_OK; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -1633,14 +1633,14 @@ static int arc_unset_breakpoint(struct target *target, LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } - breakpoint->set = 0; + breakpoint->is_set = false; } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; - unsigned int bp_num = breakpoint->set - 1; + unsigned int bp_num = breakpoint->number; - if ((breakpoint->set == 0) || (bp_num >= arc->actionpoints_num)) { + if (bp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in breakpoint: %" PRIu32, bp_num, breakpoint->unique_id); return ERROR_OK; @@ -1650,11 +1650,11 @@ static int arc_unset_breakpoint(struct target *target, breakpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { - breakpoint->set = 0; + breakpoint->is_set = false; ap_list[bp_num].used = 0; ap_list[bp_num].bp_value = 0; - LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %i", + LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %u", breakpoint->unique_id, bp_num); } } else { @@ -1684,7 +1684,7 @@ static int arc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state == TARGET_HALTED) { - if (breakpoint->set) + if (breakpoint->is_set) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } else { LOG_WARNING("target not halted"); @@ -1818,7 +1818,7 @@ static int arc_set_watchpoint(struct target *target, struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -1859,7 +1859,7 @@ static int arc_set_watchpoint(struct target *target, watchpoint->address, enable, AP_AC_AT_MEMORY_ADDR); if (retval == ERROR_OK) { - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); ap_list[wp_num].used = 1; ap_list[wp_num].bp_value = watchpoint->address; ap_list[wp_num].type = ARC_AP_WATCHPOINT; @@ -1878,13 +1878,13 @@ static int arc_unset_watchpoint(struct target *target, struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - unsigned int wp_num = watchpoint->set - 1; - if ((watchpoint->set == 0) || (wp_num >= arc->actionpoints_num)) { + unsigned int wp_num = watchpoint->number; + if (wp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in watchpoint: %" PRIu32, wp_num, watchpoint->unique_id); return ERROR_OK; @@ -1894,7 +1894,7 @@ static int arc_unset_watchpoint(struct target *target, watchpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_MEMORY_ADDR); if (retval == ERROR_OK) { - watchpoint->set = 0; + watchpoint->is_set = false; ap_list[wp_num].used = 0; ap_list[wp_num].bp_value = 0; @@ -1926,7 +1926,7 @@ static int arc_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) CHECK_RETVAL(arc_unset_watchpoint(target, watchpoint)); return ERROR_OK; @@ -1953,8 +1953,8 @@ static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_wat watchpoint = watchpoint->next) { if (actionpoint->bp_value == watchpoint->address) { *hit_watchpoint = watchpoint; - LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %i", - watchpoint->unique_id, watchpoint->set - 1); + LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u", + watchpoint->unique_id, watchpoint->number); return ERROR_OK; } } diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index cf77a81a7..da047c3d0 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -93,19 +93,20 @@ static void arm7_9_assign_wp(struct arm7_9_common *arm7_9, struct breakpoint *br { if (!arm7_9->wp0_used) { arm7_9->wp0_used = 1; - breakpoint->set = 1; + breakpoint_hw_set(breakpoint, 0); arm7_9->wp_available--; } else if (!arm7_9->wp1_used) { arm7_9->wp1_used = 1; - breakpoint->set = 2; + breakpoint_hw_set(breakpoint, 1); arm7_9->wp_available--; - } else + } else { LOG_ERROR("BUG: no hardware comparator available"); + } - LOG_DEBUG("BPID: %" PRIu32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %d", + LOG_DEBUG("BPID: %" PRIu32 " (0x%08" TARGET_PRIxADDR ") using hw wp: %u", breakpoint->unique_id, breakpoint->address, - breakpoint->set); + breakpoint->number); } /** @@ -203,16 +204,16 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break uint32_t mask = (breakpoint->length == 4) ? 0x3u : 0x1u; /* reassign a hw breakpoint */ - if (breakpoint->set == 0) + if (!breakpoint->is_set) arm7_9_assign_wp(arm7_9, breakpoint); - if (breakpoint->set == 1) { + if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], breakpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_NOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], breakpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffffu); @@ -226,7 +227,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break retval = jtag_execute_queue(); } else if (breakpoint->type == BKPT_SOFT) { /* did we already set this breakpoint? */ - if (breakpoint->set) + if (breakpoint->is_set) return ERROR_OK; if (breakpoint->length == 4) { @@ -277,7 +278,7 @@ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *break arm7_9->sw_breakpoint_count++; - breakpoint->set = 1; + breakpoint->is_set = true; } return retval; @@ -304,7 +305,7 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre breakpoint->unique_id, breakpoint->address); - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -312,18 +313,18 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre if (breakpoint->type == BKPT_HARD) { LOG_DEBUG("BPID: %" PRIu32 " Releasing hw wp: %d", breakpoint->unique_id, - breakpoint->set); - if (breakpoint->set == 1) { + breakpoint->is_set); + if (breakpoint->number == 0) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); arm7_9->wp0_used = 0; arm7_9->wp_available++; - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); arm7_9->wp1_used = 0; arm7_9->wp_available++; } retval = jtag_execute_queue(); - breakpoint->set = 0; + breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { @@ -368,7 +369,7 @@ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *bre EICE_W1_CONTROL_VALUE], 0); } - breakpoint->set = 0; + breakpoint->is_set = false; } return retval; @@ -491,7 +492,7 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - watchpoint->set = 1; + watchpoint_set(watchpoint, 1); arm7_9->wp0_used = 2; } else if (!arm7_9->wp1_used) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], @@ -510,7 +511,7 @@ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watch retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - watchpoint->set = 2; + watchpoint_set(watchpoint, 2); arm7_9->wp1_used = 2; } else { LOG_ERROR("BUG: no hardware comparator available"); @@ -538,25 +539,25 @@ static int arm7_9_unset_watchpoint(struct target *target, struct watchpoint *wat return ERROR_TARGET_NOT_HALTED; } - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } - if (watchpoint->set == 1) { + if (watchpoint->number == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp0_used = 0; - } else if (watchpoint->set == 2) { + } else if (watchpoint->number == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp1_used = 0; } - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -597,7 +598,7 @@ int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoin int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); - if (watchpoint->set) { + if (watchpoint->is_set) { retval = arm7_9_unset_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; @@ -1684,7 +1685,7 @@ static void arm7_9_enable_watchpoints(struct target *target) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) arm7_9_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 3e55e2e3a..e60ef225d 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -398,7 +398,7 @@ fail: * or running debugger code. */ static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, - struct dpm_bpwp *xp, int *set_p) + struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; @@ -473,7 +473,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct breakpoint *bp = dbp->bp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, - bp ? &bp->set : NULL); + bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -485,7 +485,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct watchpoint *wp = dwp->wp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, - wp ? &wp->set : NULL); + wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 188e58822..765f1b777 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -818,7 +818,7 @@ fail: * or running debugger code. */ static int dpmv8_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, - struct dpm_bpwp *xp, int *set_p) + struct dpm_bpwp *xp, bool *set_p) { int retval = ERROR_OK; bool disable; @@ -892,7 +892,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct breakpoint *bp = dbp->bp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, - bp ? &bp->set : NULL); + bp ? &bp->is_set : NULL); if (retval != ERROR_OK) goto done; } @@ -904,7 +904,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) struct watchpoint *wp = dwp->wp; retval = dpmv8_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, - wp ? &wp->set : NULL); + wp ? &wp->is_set : NULL); if (retval != ERROR_OK) goto done; } diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 8439ff395..79c68fea8 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -71,7 +71,7 @@ static int breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = 0; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; @@ -134,7 +134,7 @@ static int context_breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; @@ -188,7 +188,7 @@ static int hybrid_breakpoint_add_internal(struct target *target, (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; - (*breakpoint_p)->set = 0; + (*breakpoint_p)->is_set = false; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index b4a3511d2..b97be718c 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -39,7 +39,8 @@ struct breakpoint { uint32_t asid; int length; enum breakpoint_type type; - int set; + bool is_set; + unsigned int number; uint8_t *orig_instr; struct breakpoint *next; uint32_t unique_id; @@ -52,7 +53,8 @@ struct watchpoint { uint32_t mask; uint32_t value; enum watchpoint_rw rw; - int set; + bool is_set; + unsigned int number; struct watchpoint *next; int unique_id; }; @@ -69,6 +71,12 @@ void breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); +inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) +{ + breakpoint->is_set = true; + breakpoint->number = hw_number; +} + void watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, @@ -79,4 +87,10 @@ void watchpoint_remove(struct target *target, target_addr_t address); int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address); +inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) +{ + watchpoint->is_set = true; + watchpoint->number = number; +} + #endif /* OPENOCD_TARGET_BREAKPOINTS_H */ diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 272411359..2dc109108 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1185,7 +1185,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB) ? 2 : 4; stepbreakpoint.type = BKPT_HARD; - stepbreakpoint.set = 0; + stepbreakpoint.is_set = false; /* Disable interrupts during single step if requested */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { @@ -1265,7 +1265,7 @@ static int cortex_a_set_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1277,7 +1277,7 @@ static int cortex_a_set_breakpoint(struct target *target, LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) @@ -1342,7 +1342,7 @@ static int cortex_a_set_breakpoint(struct target *target, armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -1359,7 +1359,7 @@ static int cortex_a_set_context_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1373,7 +1373,7 @@ static int cortex_a_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; @@ -1411,7 +1411,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1436,7 +1436,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi return ERROR_FAIL; } - breakpoint->set = brp_1 + 1; + breakpoint_hw_set(breakpoint, brp_1); breakpoint->linked_brp = brp_2; control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) @@ -1485,16 +1485,16 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - int brp_i = breakpoint->set - 1; + int brp_i = breakpoint->number; int brp_j = breakpoint->linked_brp; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1533,12 +1533,12 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b if (retval != ERROR_OK) return retval; breakpoint->linked_brp = 0; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } else { - int brp_i = breakpoint->set - 1; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1557,7 +1557,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } } else { @@ -1589,7 +1589,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1655,7 +1655,7 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint * } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { cortex_a_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available++; @@ -1688,7 +1688,7 @@ static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *wat struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return retval; } @@ -1741,7 +1741,7 @@ static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *wat break; } - watchpoint->set = wrp_i + 1; + watchpoint_set(watchpoint, wrp_i); control = (address_mask << 24) | (byte_address_select << 5) | (load_store_access_control << 3) | @@ -1784,13 +1784,13 @@ static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *w struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wrp_i = watchpoint->set - 1; - if (wrp_i < 0 || wrp_i >= cortex_a->wrp_num) { + int wrp_i = watchpoint->number; + if (wrp_i >= cortex_a->wrp_num) { LOG_DEBUG("Invalid WRP number in watchpoint"); return ERROR_OK; } @@ -1809,7 +1809,7 @@ static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *w wrp_list[wrp_i].value); if (retval != ERROR_OK) return retval; - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -1851,7 +1851,7 @@ static int cortex_a_remove_watchpoint(struct target *target, struct watchpoint * { struct cortex_a_common *cortex_a = target_to_cortex_a(target); - if (watchpoint->set) { + if (watchpoint->is_set) { cortex_a->wrp_num_available++; cortex_a_unset_watchpoint(target, watchpoint); } diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 108f7e790..344cfcf61 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1090,7 +1090,7 @@ void cortex_m_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (!breakpoint->set) + if (!breakpoint->is_set) cortex_m_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -1578,7 +1578,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_TARGET_WARNING(target, "breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id); return ERROR_OK; } @@ -1591,7 +1591,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint LOG_TARGET_ERROR(target, "Can not find free FPB Comparator!"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = fp_num + 1; + breakpoint_hw_set(breakpoint, fp_num); fpcr_value = breakpoint->address | 1; if (cortex_m->fp_rev == 0) { if (breakpoint->address > 0x1FFFFFFF) { @@ -1643,15 +1643,15 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint code); if (retval != ERROR_OK) return retval; - breakpoint->set = true; + breakpoint->is_set = true; } - LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, - breakpoint->set); + (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); return ERROR_OK; } @@ -1662,20 +1662,20 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list; - if (breakpoint->set <= 0) { + if (!breakpoint->is_set) { LOG_TARGET_WARNING(target, "breakpoint not set"); return ERROR_OK; } - LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (set=%d)", + LOG_TARGET_DEBUG(target, "BPID: %" PRIu32 ", Type: %d, Address: " TARGET_ADDR_FMT " Length: %d (n=%u)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, - breakpoint->set); + (breakpoint->type == BKPT_SOFT) ? 0 : breakpoint->number); if (breakpoint->type == BKPT_HARD) { - unsigned int fp_num = breakpoint->set - 1; + unsigned int fp_num = breakpoint->number; if (fp_num >= cortex_m->fp_num_code) { LOG_TARGET_DEBUG(target, "Invalid FP Comparator number in breakpoint"); return ERROR_OK; @@ -1692,7 +1692,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi if (retval != ERROR_OK) return retval; } - breakpoint->set = false; + breakpoint->is_set = false; return ERROR_OK; } @@ -1714,7 +1714,7 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { - if (!breakpoint->set) + if (!breakpoint->is_set) return ERROR_OK; return cortex_m_unset_breakpoint(target, breakpoint); @@ -1741,7 +1741,7 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat return ERROR_FAIL; } comparator->used = true; - watchpoint->set = dwt_num + 1; + watchpoint_set(watchpoint, dwt_num); comparator->comp = watchpoint->address; target_write_u32(target, comparator->dwt_comparator_address + 0, @@ -1808,15 +1808,15 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_dwt_comparator *comparator; - if (watchpoint->set <= 0) { + if (!watchpoint->is_set) { LOG_TARGET_WARNING(target, "watchpoint (wpid: %d) not set", watchpoint->unique_id); return ERROR_OK; } - unsigned int dwt_num = watchpoint->set - 1; + unsigned int dwt_num = watchpoint->number; - LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d address: 0x%08x clear", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%u address: 0x%08x clear", watchpoint->unique_id, dwt_num, (unsigned) watchpoint->address); @@ -1831,7 +1831,7 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - watchpoint->set = false; + watchpoint->is_set = false; return ERROR_OK; } @@ -1895,7 +1895,7 @@ int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpo return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) cortex_m_unset_watchpoint(target, watchpoint); cortex_m->dwt_comp_available++; @@ -1912,10 +1912,10 @@ int cortex_m_hit_watchpoint(struct target *target, struct watchpoint **hit_watch struct cortex_m_common *cortex_m = target_to_cm(target); for (struct watchpoint *wp = target->watchpoints; wp; wp = wp->next) { - if (!wp->set) + if (!wp->is_set) continue; - unsigned int dwt_num = wp->set - 1; + unsigned int dwt_num = wp->number; struct cortex_m_dwt_comparator *comparator = cortex_m->dwt_comparator_list + dwt_num; uint32_t dwt_function; @@ -1939,7 +1939,7 @@ void cortex_m_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (!watchpoint->set) + if (!watchpoint->is_set) cortex_m_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } diff --git a/src/target/esirisc.c b/src/target/esirisc.c index e49f5f659..aadd111ee 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -504,7 +504,7 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_index + 1; + breakpoint_hw_set(breakpoint, bp_index); esirisc->breakpoints_p[bp_index] = breakpoint; /* specify instruction breakpoint address */ @@ -540,7 +540,7 @@ static int esirisc_add_breakpoints(struct target *target) LOG_DEBUG("-"); while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) esirisc_add_breakpoint(target, breakpoint); breakpoint = breakpoint->next; @@ -553,7 +553,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - int bp_index = breakpoint->set - 1; + unsigned int bp_index = breakpoint->number; uint32_t ibc; int retval; @@ -575,7 +575,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b } esirisc->breakpoints_p[bp_index] = NULL; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -630,7 +630,7 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc return ERROR_FAIL; } - watchpoint->set = wp_index + 1; + watchpoint_set(watchpoint, wp_index); esirisc->watchpoints_p[wp_index] = watchpoint; /* specify data breakpoint address */ @@ -724,7 +724,7 @@ static int esirisc_add_watchpoints(struct target *target) LOG_DEBUG("-"); while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) esirisc_add_watchpoint(target, watchpoint); watchpoint = watchpoint->next; @@ -737,7 +737,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - int wp_index = watchpoint->set - 1; + unsigned int wp_index = watchpoint->number; uint32_t dbc; int retval; @@ -759,7 +759,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w } esirisc->watchpoints_p[wp_index] = NULL; - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } diff --git a/src/target/lakemont.c b/src/target/lakemont.c index e46ee5cf8..230f53fe0 100644 --- a/src/target/lakemont.c +++ b/src/target/lakemont.c @@ -1024,10 +1024,10 @@ int lakemont_resume(struct target *t, int current, target_addr_t address, /* if breakpoints are enabled, we need to redirect these into probe mode */ struct breakpoint *activeswbp = t->breakpoints; - while (activeswbp && activeswbp->set == 0) + while (activeswbp && !activeswbp->is_set) activeswbp = activeswbp->next; struct watchpoint *activehwbp = t->watchpoints; - while (activehwbp && activehwbp->set == 0) + while (activehwbp && !activehwbp->is_set) activehwbp = activehwbp->next; if (activeswbp || activehwbp) buf_set_u32(x86_32->cache->reg_list[PMCR].value, 0, 32, 1); diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 8627bce6e..860119345 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -593,7 +593,7 @@ static void mips_m4k_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) mips_m4k_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -607,7 +607,7 @@ static int mips_m4k_set_breakpoint(struct target *target, struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -622,7 +622,7 @@ static int mips_m4k_set_breakpoint(struct target *target, breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = 1; comparator_list[bp_num].bp_value = breakpoint->address; @@ -724,7 +724,7 @@ static int mips_m4k_set_breakpoint(struct target *target, } } - breakpoint->set = 20; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -739,14 +739,14 @@ static int mips_m4k_unset_breakpoint(struct target *target, struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - int bp_num = breakpoint->set - 1; - if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints)) { + int bp_num = breakpoint->number; + if (bp_num >= mips32->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; @@ -813,7 +813,7 @@ static int mips_m4k_unset_breakpoint(struct target *target, } } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -851,7 +851,7 @@ static int mips_m4k_remove_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) + if (breakpoint->is_set) mips_m4k_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -875,7 +875,7 @@ static int mips_m4k_set_watchpoint(struct target *target, int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE | (0xff << EJTAG_DBCN_BLM_SHIFT); - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -911,7 +911,7 @@ static int mips_m4k_set_watchpoint(struct target *target, LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } - watchpoint->set = wp_num + 1; + watchpoint->number = wp_num; comparator_list[wp_num].used = 1; comparator_list[wp_num].bp_value = watchpoint->address; @@ -946,13 +946,13 @@ static int mips_m4k_unset_watchpoint(struct target *target, struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct mips32_comparator *comparator_list = mips32->data_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= mips32->num_data_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= mips32->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } @@ -960,7 +960,7 @@ static int mips_m4k_unset_watchpoint(struct target *target, comparator_list[wp_num].bp_value = 0; target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbc_offs, 0); - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -991,7 +991,7 @@ static int mips_m4k_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) mips_m4k_unset_watchpoint(target, watchpoint); mips32->num_data_bpoints_avail++; @@ -1005,7 +1005,7 @@ static void mips_m4k_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) mips_m4k_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index 56b0194e7..5d821d7cb 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -346,7 +346,7 @@ static int mips_mips64_set_breakpoint(struct target *target, { int retval; - if (bp->set) { + if (bp->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -373,7 +373,7 @@ static int mips_mips64_set_breakpoint(struct target *target, return retval; } - bp->set = true; + bp->is_set = true; return ERROR_OK; } @@ -385,7 +385,7 @@ static int mips_mips64_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (bp) { - if (!bp->set) { + if (!bp->is_set) { retval = mips_mips64_set_breakpoint(target, bp); if (retval != ERROR_OK) return retval; @@ -413,7 +413,7 @@ static int mips_mips64_set_watchpoint(struct target *target, int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE | (0xff << EJTAG_DBCN_BLM_SHIFT); - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -451,7 +451,7 @@ static int mips_mips64_set_watchpoint(struct target *target, } c = &cl[wp_num]; - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); c->used = true; c->bp_value = watchpoint->address; @@ -491,7 +491,7 @@ static int mips_mips64_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) { + if (!watchpoint->is_set) { retval = mips_mips64_set_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; @@ -506,11 +506,10 @@ static int mips_mips64_unset_hwbp(struct target *target, struct breakpoint *bp) { struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->inst_break_list; - int bp_num; - bp_num = bp->set - 1; + int bp_num = bp->number; - if ((bp_num < 0) || (bp_num >= mips64->num_inst_bpoints)) { + if (bp_num >= mips64->num_inst_bpoints) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")", bp->unique_id); return ERROR_OK; @@ -568,7 +567,7 @@ static int mips_mips64_unset_breakpoint(struct target *target, /* get pointers to arch-specific information */ int retval; - if (!bp->set) { + if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -594,7 +593,7 @@ static int mips_mips64_unset_breakpoint(struct target *target, return retval; } - bp->set = false; + bp->is_set = false; return ERROR_OK; } @@ -815,7 +814,7 @@ static int mips_mips64_remove_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (bp->set) + if (bp->is_set) retval = mips_mips64_unset_breakpoint(target, bp); if (bp->type == BKPT_HARD) @@ -831,20 +830,20 @@ static int mips_mips64_unset_watchpoint(struct target *target, struct mips64_common *mips64 = target->arch_info; struct mips64_comparator *comparator_list = mips64->data_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= mips64->num_data_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= mips64->num_data_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; comparator_list[wp_num].bp_value = 0; target_write_u64(target, comparator_list[wp_num].reg_address + 0x18, 0); - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -876,7 +875,7 @@ static int mips_mips64_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) retval = mips_mips64_unset_watchpoint(target, watchpoint); mips64->num_data_bpoints_avail++; diff --git a/src/target/nds32.c b/src/target/nds32.c index 12340ac2c..f0fb74d31 100644 --- a/src/target/nds32.c +++ b/src/target/nds32.c @@ -1653,7 +1653,7 @@ int nds32_init_arch_info(struct target *target, struct nds32 *nds32) nds32->syscall_break.asid = 0; nds32->syscall_break.length = 4; - nds32->syscall_break.set = 0; + nds32->syscall_break.is_set = false; nds32->syscall_break.orig_instr = NULL; nds32->syscall_break.next = NULL; nds32->syscall_break.unique_id = 0x515CAll + target->target_number; diff --git a/src/target/nds32_v3_common.c b/src/target/nds32_v3_common.c index b0c3de622..8ff8e30c6 100644 --- a/src/target/nds32_v3_common.c +++ b/src/target/nds32_v3_common.c @@ -78,12 +78,12 @@ static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint) struct breakpoint *syscall_break = &(nds32->syscall_break); if (nds32->virtual_hosting) { - if (syscall_break->set) { + if (syscall_break->is_set) { /** disable virtual hosting */ /* remove breakpoint at syscall entry */ target_remove_breakpoint(nds32->target, syscall_break); - syscall_break->set = 0; + syscall_break->is_set = false; uint32_t value_pc; nds32_get_mapped_reg(nds32, PC, &value_pc); @@ -209,7 +209,7 @@ static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoin syscall_break->address = syscall_address; syscall_break->type = BKPT_SOFT; - syscall_break->set = 1; + syscall_break->is_set = true; target_add_breakpoint(target, syscall_break); } diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 8fbcd9620..77fa15d50 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -923,9 +923,9 @@ static int or1k_add_breakpoint(struct target *target, struct or1k_du *du_core = or1k_to_du(or1k); uint8_t data; - LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRIu32, + LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, - breakpoint->set, breakpoint->unique_id); + breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) @@ -981,9 +981,9 @@ static int or1k_remove_breakpoint(struct target *target, struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); - LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRIu32, + LOG_DEBUG("Removing breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, id: %" PRIu32, breakpoint->address, breakpoint->length, breakpoint->type, - breakpoint->set, breakpoint->unique_id); + breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 367506dde..a266f5da3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -903,7 +903,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = true; + breakpoint->is_set = true; return ERROR_OK; } @@ -963,7 +963,7 @@ int riscv_remove_breakpoint(struct target *target, return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = false; + breakpoint->is_set = false; return ERROR_OK; } @@ -990,7 +990,7 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) int result = add_trigger(target, &trigger); if (result != ERROR_OK) return result; - watchpoint->set = true; + watchpoint->is_set = true; return ERROR_OK; } @@ -1006,7 +1006,7 @@ int riscv_remove_watchpoint(struct target *target, int result = remove_trigger(target, &trigger); if (result != ERROR_OK) return result; - watchpoint->set = false; + watchpoint->is_set = false; return ERROR_OK; } @@ -1338,9 +1338,9 @@ static int disable_triggers(struct target *target, riscv_reg_t *state) struct watchpoint *watchpoint = target->watchpoints; int i = 0; while (watchpoint) { - LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); - state[i] = watchpoint->set; - if (watchpoint->set) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->is_set); + state[i] = watchpoint->is_set; + if (watchpoint->is_set) { if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) return ERROR_FAIL; } diff --git a/src/target/stm8.c b/src/target/stm8.c index 21fc8c54f..4102082ff 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1370,7 +1370,7 @@ static void stm8_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) stm8_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -1383,7 +1383,7 @@ static int stm8_set_breakpoint(struct target *target, struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1398,7 +1398,7 @@ static int stm8_set_breakpoint(struct target *target, breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = bp_num + 1; + breakpoint_hw_set(breakpoint, bp_num); comparator_list[bp_num].used = true; comparator_list[bp_num].bp_value = breakpoint->address; comparator_list[bp_num].type = HWBRK_EXEC; @@ -1435,7 +1435,7 @@ static int stm8_set_breakpoint(struct target *target, } else { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = 1; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -1476,14 +1476,14 @@ static int stm8_unset_breakpoint(struct target *target, struct stm8_comparator *comparator_list = stm8->hw_break_list; int retval; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - int bp_num = breakpoint->set - 1; - if ((bp_num < 0) || (bp_num >= stm8->num_hw_bpoints)) { + int bp_num = breakpoint->number; + if (bp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid comparator number in breakpoint (bpid: %" PRIu32 ")", breakpoint->unique_id); return ERROR_OK; @@ -1517,7 +1517,7 @@ static int stm8_unset_breakpoint(struct target *target, } else return ERROR_FAIL; } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1533,7 +1533,7 @@ static int stm8_remove_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) + if (breakpoint->is_set) stm8_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -1550,7 +1550,7 @@ static int stm8_set_watchpoint(struct target *target, int wp_num = 0; int ret; - if (watchpoint->set) { + if (watchpoint->is_set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } @@ -1593,7 +1593,7 @@ static int stm8_set_watchpoint(struct target *target, return ret; } - watchpoint->set = wp_num + 1; + watchpoint_set(watchpoint, wp_num); LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, @@ -1627,7 +1627,7 @@ static void stm8_enable_watchpoints(struct target *target) /* set any pending watchpoints */ while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) stm8_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1640,18 +1640,18 @@ static int stm8_unset_watchpoint(struct target *target, struct stm8_common *stm8 = target_to_stm8(target); struct stm8_comparator *comparator_list = stm8->hw_break_list; - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = watchpoint->set - 1; - if ((wp_num < 0) || (wp_num >= stm8->num_hw_bpoints)) { + int wp_num = watchpoint->number; + if (wp_num >= stm8->num_hw_bpoints) { LOG_DEBUG("Invalid hw comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = false; - watchpoint->set = 0; + watchpoint->is_set = false; stm8_set_hwbreak(target, comparator_list); @@ -1669,7 +1669,7 @@ static int stm8_remove_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) stm8_unset_watchpoint(target, watchpoint); stm8->num_hw_bpoints_avail++; diff --git a/src/target/target.c b/src/target/target.c index 7b8271339..690526eb7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3967,26 +3967,26 @@ static int handle_bp_command_list(struct command_invocation *cmd) if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_hex_str(breakpoint->orig_instr, breakpoint->length); - command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, %i, 0x%s", + command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, 0x%s", breakpoint->address, breakpoint->length, - breakpoint->set, buf); + buf); free(buf); } else { if ((breakpoint->address == 0) && (breakpoint->asid != 0)) - command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i", + command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %u", breakpoint->asid, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", + command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", breakpoint->address, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); command_print(cmd, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); } else - command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", + command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u", breakpoint->address, - breakpoint->length, breakpoint->set); + breakpoint->length, breakpoint->number); } breakpoint = breakpoint->next; diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index a009bfe92..d119be148 100644 --- a/src/target/x86_32_common.c +++ b/src/target/x86_32_common.c @@ -862,7 +862,7 @@ int x86_32_common_remove_watchpoint(struct target *t, struct watchpoint *wp) { if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; - if (wp->set) + if (wp->is_set) unset_watchpoint(t, wp); return ERROR_OK; } @@ -883,7 +883,7 @@ int x86_32_common_remove_breakpoint(struct target *t, struct breakpoint *bp) LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); if (check_not_halted(t)) return ERROR_TARGET_NOT_HALTED; - if (bp->set) + if (bp->is_set) unset_breakpoint(t, bp); return ERROR_OK; @@ -995,7 +995,7 @@ static int set_hwbp(struct target *t, struct breakpoint *bp) } if (set_debug_regs(t, bp->address, hwbp_num, DR7_BP_EXECUTE, 1) != ERROR_OK) return ERROR_FAIL; - bp->set = hwbp_num + 1; + breakpoint_hw_set(bp, hwbp_num); debug_reg_list[hwbp_num].used = 1; debug_reg_list[hwbp_num].bp_value = bp->address; LOG_USER("%s hardware breakpoint %" PRIu32 " set at 0x%08" PRIx32 " (hwreg=%" PRIu8 ")", __func__, @@ -1007,9 +1007,9 @@ static int unset_hwbp(struct target *t, struct breakpoint *bp) { struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; - int hwbp_num = bp->set - 1; + int hwbp_num = bp->number; - if ((hwbp_num < 0) || (hwbp_num >= x86_32->num_hw_bpoints)) { + if (hwbp_num >= x86_32->num_hw_bpoints) { LOG_ERROR("%s invalid breakpoint number=%d, bpid=%" PRIu32, __func__, hwbp_num, bp->unique_id); return ERROR_OK; @@ -1055,7 +1055,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) __func__, readback, *bp->orig_instr); return ERROR_FAIL; } - bp->set = SW_BP_OPCODE; /* just non 0 */ + bp->is_set = true; /* add the memory patch */ struct swbp_mem_patch *new_patch = malloc(sizeof(struct swbp_mem_patch)); @@ -1134,7 +1134,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) int error = ERROR_OK; struct x86_32_common *x86_32 = target_to_x86_32(t); LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); - if (bp->set) { + if (bp->is_set) { LOG_ERROR("breakpoint already set"); return error; } @@ -1164,7 +1164,7 @@ static int set_breakpoint(struct target *t, struct breakpoint *bp) static int unset_breakpoint(struct target *t, struct breakpoint *bp) { LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, bp->type, bp->address); - if (!bp->set) { + if (!bp->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } @@ -1182,7 +1182,7 @@ static int unset_breakpoint(struct target *t, struct breakpoint *bp) return ERROR_FAIL; } } - bp->set = 0; + bp->is_set = false; return ERROR_OK; } @@ -1193,7 +1193,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) int wp_num = 0; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); - if (wp->set) { + if (wp->is_set) { LOG_ERROR("%s watchpoint already set", __func__); return ERROR_OK; } @@ -1233,7 +1233,7 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); break; } - wp->set = wp_num + 1; + watchpoint_set(wp, wp_num); debug_reg_list[wp_num].used = 1; debug_reg_list[wp_num].bp_value = wp->address; LOG_USER("'%s' watchpoint %d set at " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", @@ -1248,13 +1248,13 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) struct x86_32_common *x86_32 = target_to_x86_32(t); struct x86_32_dbg_reg *debug_reg_list = x86_32->hw_break_list; LOG_DEBUG("type=%d, addr=" TARGET_ADDR_FMT, wp->rw, wp->address); - if (!wp->set) { + if (!wp->is_set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } - int wp_num = wp->set - 1; - if ((wp_num < 0) || (wp_num >= x86_32->num_hw_bpoints)) { + int wp_num = wp->number; + if (wp_num >= x86_32->num_hw_bpoints) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } @@ -1263,7 +1263,7 @@ static int unset_watchpoint(struct target *t, struct watchpoint *wp) debug_reg_list[wp_num].used = 0; debug_reg_list[wp_num].bp_value = 0; - wp->set = 0; + wp->is_set = false; LOG_USER("'%s' watchpoint %d removed from " TARGET_ADDR_FMT " with length %" PRIu32 " (hwreg=%d)", wp->rw == WPT_READ ? "read" : wp->rw == WPT_WRITE ? diff --git a/src/target/xscale.c b/src/target/xscale.c index dd383b6e4..78bd09922 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -1087,7 +1087,7 @@ static void xscale_enable_watchpoints(struct target *target) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - if (watchpoint->set == 0) + if (!watchpoint->is_set) xscale_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } @@ -1099,7 +1099,7 @@ static void xscale_enable_breakpoints(struct target *target) /* set any pending breakpoints */ while (breakpoint) { - if (breakpoint->set == 0) + if (!breakpoint->is_set) xscale_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } @@ -1506,7 +1506,7 @@ static int xscale_deassert_reset(struct target *target) /* mark all hardware breakpoints as unset */ while (breakpoint) { if (breakpoint->type == BKPT_HARD) - breakpoint->set = 0; + breakpoint->is_set = false; breakpoint = breakpoint->next; } @@ -2088,7 +2088,7 @@ static int xscale_set_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -2098,11 +2098,13 @@ static int xscale_set_breakpoint(struct target *target, if (!xscale->ibcr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); xscale->ibcr0_used = 1; - breakpoint->set = 1; /* breakpoint set on first breakpoint register */ + /* breakpoint set on first breakpoint register */ + breakpoint_hw_set(breakpoint, 0); } else if (!xscale->ibcr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); xscale->ibcr1_used = 1; - breakpoint->set = 2; /* breakpoint set on second breakpoint register */ + /* breakpoint set on second breakpoint register */ + breakpoint_hw_set(breakpoint, 1); } else {/* bug: availability previously verified in xscale_add_breakpoint() */ LOG_ERROR("BUG: no hardware comparator available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -2133,7 +2135,7 @@ static int xscale_set_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } - breakpoint->set = 1; + breakpoint->is_set = true; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); @@ -2176,20 +2178,20 @@ static int xscale_unset_breakpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { - if (breakpoint->set == 1) { + if (breakpoint->number == 0) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); xscale->ibcr0_used = 0; - } else if (breakpoint->set == 2) { + } else if (breakpoint->number == 1) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); xscale->ibcr1_used = 0; } - breakpoint->set = 0; + breakpoint->is_set = false; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { @@ -2203,7 +2205,7 @@ static int xscale_unset_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } - breakpoint->set = 0; + breakpoint->is_set = false; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); @@ -2223,7 +2225,7 @@ static int xscale_remove_breakpoint(struct target *target, struct breakpoint *br return ERROR_TARGET_NOT_HALTED; } - if (breakpoint->set) + if (breakpoint->is_set) xscale_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) @@ -2279,13 +2281,13 @@ static int xscale_set_watchpoint(struct target *target, xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); dbcon_value |= enable; xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 1; + watchpoint_set(watchpoint, 0); xscale->dbr0_used = 1; } else if (!xscale->dbr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); dbcon_value |= enable << 2; xscale_set_reg_u32(dbcon, dbcon_value); - watchpoint->set = 2; + watchpoint_set(watchpoint, 1); xscale->dbr1_used = 1; } else { LOG_ERROR("BUG: no hardware comparator available"); @@ -2349,12 +2351,12 @@ static int xscale_unset_watchpoint(struct target *target, return ERROR_TARGET_NOT_HALTED; } - if (!watchpoint->set) { + if (!watchpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } - if (watchpoint->set == 1) { + if (watchpoint->number == 0) { if (watchpoint->length > 4) { dbcon_value &= ~0x103; /* clear DBCON[M] as well */ xscale->dbr1_used = 0; /* DBR1 was used for mask */ @@ -2363,12 +2365,12 @@ static int xscale_unset_watchpoint(struct target *target, xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr0_used = 0; - } else if (watchpoint->set == 2) { + } else if (watchpoint->number == 1) { dbcon_value &= ~0xc; xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr1_used = 0; } - watchpoint->set = 0; + watchpoint->is_set = false; return ERROR_OK; } @@ -2382,7 +2384,7 @@ static int xscale_remove_watchpoint(struct target *target, struct watchpoint *wa return ERROR_TARGET_NOT_HALTED; } - if (watchpoint->set) + if (watchpoint->is_set) xscale_unset_watchpoint(target, watchpoint); if (watchpoint->length > 4) From 92c4e634d7bb9d3fb27d9a0ca332925c7318a574 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Mar 2022 10:56:01 +0100 Subject: [PATCH 70/79] breakpoints: fix build on -fno-inline Some configuration of GCC could default to -fno-inline, causing the build to fail after commit fb43f1ff4e2f ("target: Rework 'set' variable of break-/watchpoints"). Switch the new inline functions to 'static inline', as it's widely used in the rest of the code. Change-Id: I8bf31045a137bd34ed825f4b2a9338eb3c70046d Signed-off-by: Antonio Borneo Fixes: fb43f1ff4e2f ("target: Rework 'set' variable of break-/watchpoints") Reviewed-on: https://review.openocd.org/c/openocd/+/6881 Tested-by: jenkins --- src/target/breakpoints.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index b97be718c..0a5949594 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -71,7 +71,7 @@ void breakpoint_remove_all(struct target *target); struct breakpoint *breakpoint_find(struct target *target, target_addr_t address); -inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) +static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int hw_number) { breakpoint->is_set = true; breakpoint->number = hw_number; @@ -87,7 +87,7 @@ void watchpoint_remove(struct target *target, target_addr_t address); int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address); -inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) +static inline void watchpoint_set(struct watchpoint *watchpoint, unsigned int number) { watchpoint->is_set = true; watchpoint->number = number; From 2cafa8be7320266756dd92a40d174cbc01487c15 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 4 Mar 2022 09:26:19 +0100 Subject: [PATCH 71/79] semihosting: fix mode flags for local host open() Commit dbbac5f11d66 ("semihosting: use open mode flags from GDB, not from sys/stat.h") fixes the conversion of the mode flags from ARM semihosting encoding for SEMIHOSTING_SYS_OPEN to GDB mapping for open(). Doing this, it breaks the conversion to local host's OS mapping for open(). Split the conversion array to one for GDB and one for local host. The local host conversion array is taken directly from the old code. Change-Id: I385321ddd32c3ac5cf6da3f1ce9eff76b05dd527 Fixes: dbbac5f11d66 ("semihosting: use open mode flags from GDB, not from sys/stat.h") Signed-off-by: Antonio Borneo Reported-by: Erhan Kurubas Reviewed-on: https://review.openocd.org/c/openocd/+/6870 Tested-by: jenkins --- src/target/semihosting_common.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 38035e493..bc1f417ef 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -68,7 +68,7 @@ enum { }; /* GDB remote protocol does not differentiate between text and binary open modes. */ -static const int open_modeflags[12] = { +static const int open_gdb_modeflags[12] = { TARGET_O_RDONLY, TARGET_O_RDONLY, TARGET_O_RDWR, @@ -83,6 +83,21 @@ static const int open_modeflags[12] = { TARGET_O_RDWR | TARGET_O_CREAT | TARGET_O_APPEND }; +static const int open_host_modeflags[12] = { + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY +}; + static int semihosting_common_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); static int semihosting_common_fileio_end(struct target *target, int result, @@ -886,7 +901,7 @@ int semihosting_common(struct target *target) fileio_info->identifier = "open"; fileio_info->param_1 = addr; fileio_info->param_2 = len; - fileio_info->param_3 = open_modeflags[mode]; + fileio_info->param_3 = open_gdb_modeflags[mode]; fileio_info->param_4 = 0644; } } else { @@ -922,7 +937,7 @@ int semihosting_common(struct target *target) * otherwise it will fail to reopen a previously * written file */ semihosting->result = open((char *)fn, - open_modeflags[mode], + open_host_modeflags[mode], 0644); semihosting->sys_errno = errno; LOG_DEBUG("open('%s')=%d", fn, From 1b716b9d0d42409f5ee8855f084720ff579a7737 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 28 Nov 2019 18:00:11 +0100 Subject: [PATCH 72/79] tcl/tools: Add function to measure the speed of ARM Cortex-M devices Tested on an EFM32PG12 Starter Kit. Change-Id: I2cbc36fe0d2ad2089bf8c1e7d2260daaae4ddbb4 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/5353 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/tools/test_cpu_speed.tcl | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tcl/tools/test_cpu_speed.tcl diff --git a/tcl/tools/test_cpu_speed.tcl b/tcl/tools/test_cpu_speed.tcl new file mode 100644 index 000000000..cef2bbbd7 --- /dev/null +++ b/tcl/tools/test_cpu_speed.tcl @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Description: +# Measure the CPU clock frequency of an ARM Cortex-M based device. +# +# Return: +# The CPU clock frequency in Hz. A negative value indicates that the loop +# counter was saturated. +# +# Note: +# You may need to adapt the number of cycles for your device. +# +add_help_text cortex_m_test_cpu_speed "Measure the CPU clock frequency of an ARM Cortex-M based device" +add_usage_text cortex_m_test_cpu_speed {address [timeout [cycles_per_loop]]} +proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } { + set loop_counter_start 0xffffffff + + halt + + # Backup registers and memory. + set backup_regs [get_reg -force {pc r0 xPSR}] + set backup_mem [read_memory $address 16 3] + + # We place the following code at the given address to measure the + # CPU clock frequency: + # + # 3801: subs r0, #1 + # d1fd: bne #-2 + # e7fe: b #-4 + write_memory $address 16 {0x3801 0xd1fd 0xe7fe} + + set_reg "pc $address r0 $loop_counter_start" + resume + sleep $timeout + halt + + # Get the loop counter value from register r0. + set loop_counter_end [dict values [get_reg r0]] + set loop_counter_diff [expr {$loop_counter_start - $loop_counter_end}] + + # Restore registers and memory. + set_reg $backup_regs + write_memory $address 16 $backup_mem + + if { [expr {$loop_counter_end == 0}] } { + return -1 + } + + return [expr {double($loop_counter_diff) * $cycles_per_loop / $timeout * 1000}] +} From 00d4699d0b559a0bb3e739a78f3ce1c5731f8dea Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 9 Jun 2021 11:27:57 +0200 Subject: [PATCH 73/79] arm_tpiu_swo: fix autodetection of SWO pin frequency While the documentation reports that SWO pin frequency can be omitted to let the adapter autodetect the value, the code wrongly drops an error when pin frequency is not specified. Don't require the pin frequency to be set at "enable", but verify that the adapter has properly changes it to a valid value. Change-Id: I3dfbe3256e8887ef4f03512769b06381cdc9db0d Signed-off-by: Antonio Borneo Reported-by: Karl Palsson Fixes: 184724d14e12 ("arm_tpiu_swo: add support for independent TPIU and SWO") Reviewed-on: https://review.openocd.org/c/openocd/+/6310 Tested-by: jenkins Reviewed-by: zapb --- src/target/arm_tpiu_swo.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index a0eba6782..fba3fec4f 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -625,10 +625,8 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const } if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) - if (!obj->swo_pin_freq) { - LOG_ERROR("SWO pin frequency not set"); - return JIM_ERR; - } + if (!obj->swo_pin_freq) + LOG_DEBUG("SWO pin frequency not set, will be autodetected by the adapter"); struct target *target = get_current_target(cmd_ctx); @@ -731,6 +729,17 @@ static int jim_arm_tpiu_swo_enable(Jim_Interp *interp, int argc, Jim_Obj *const return JIM_ERR; } + if (obj->pin_protocol == TPIU_SPPR_PROTOCOL_MANCHESTER || obj->pin_protocol == TPIU_SPPR_PROTOCOL_UART) + if (!swo_pin_freq) { + if (obj->swo_pin_freq) + LOG_ERROR("Adapter rejected SWO pin frequency %d Hz", obj->swo_pin_freq); + else + LOG_ERROR("Adapter does not support auto-detection of SWO pin frequency nor a default value"); + + arm_tpiu_swo_close_output(obj); + return JIM_ERR; + } + if (obj->swo_pin_freq != swo_pin_freq) LOG_INFO("SWO pin data rate adjusted by adapter to %d Hz", swo_pin_freq); obj->swo_pin_freq = swo_pin_freq; From 3fa695be2401c88dbd93b2c9dad1c098a948c4ca Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 24 Feb 2022 11:39:15 +0100 Subject: [PATCH 74/79] openocd: include config.h in every file .c Including config.h as first is required for every C file. Add it to the C files that still miss it. Change-Id: I1a210e7d3a854958a85a290b086ad8a9f5176425 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6856 Tested-by: jenkins --- src/helper/jim-nvp.c | 4 ++++ src/rtos/chromium-ec.c | 4 ++++ src/rtt/rtt.c | 4 ++++ src/rtt/tcl.c | 4 ++++ src/server/rtt_server.c | 4 ++++ src/target/rtt.c | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/src/helper/jim-nvp.c b/src/helper/jim-nvp.c index 738ed7943..0409a83cd 100644 --- a/src/helper/jim-nvp.c +++ b/src/helper/jim-nvp.c @@ -41,6 +41,10 @@ * official policies, either expressed or implied, of the Jim Tcl Project. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "jim-nvp.h" #include diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c index 1c8f4e3f4..2f1a0cf3c 100644 --- a/src/rtos/chromium-ec.c +++ b/src/rtos/chromium-ec.c @@ -7,6 +7,10 @@ * Chromium-EC RTOS Task Awareness */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c index bf3cca51b..3da3cce81 100644 --- a/src/rtt/rtt.c +++ b/src/rtt/rtt.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c index f5abf2e5e..4a34d8b98 100644 --- a/src/rtt/tcl.c +++ b/src/rtt/tcl.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c index c7141c0e0..3850c2687 100644 --- a/src/server/rtt_server.c +++ b/src/server/rtt_server.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include diff --git a/src/target/rtt.c b/src/target/rtt.c index 7e556e1cb..41830213d 100644 --- a/src/target/rtt.c +++ b/src/target/rtt.c @@ -15,6 +15,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include From 6c9dd1c6ba9fba806ed7ed6f6ecb59723beb9cad Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 24 Feb 2022 11:30:56 +0100 Subject: [PATCH 75/79] helper/bits: add BIT_ULL and GENMASK macros To support 64 bits bit and masks Replace local definition of BIT in rtos/chromium-ec Change-Id: I1f268d6e8790f1b07bf798680b797878ce81064b Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6857 Tested-by: jenkins --- src/helper/bits.h | 4 ++++ src/rtos/chromium-ec.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/helper/bits.h b/src/helper/bits.h index 00d3c0270..6151b3340 100644 --- a/src/helper/bits.h +++ b/src/helper/bits.h @@ -28,8 +28,12 @@ #include #define BIT(nr) (1UL << (nr)) +#define BIT_ULL(nr) (1ULL << (nr)) #define BITS_PER_BYTE 8 #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#define BITS_PER_LONG_LONG (BITS_PER_BYTE * sizeof(long long)) +#define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#define GENMASK_ULL(h, l) (((~0ULL) - (1ULL << (l)) + 1) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) diff --git a/src/rtos/chromium-ec.c b/src/rtos/chromium-ec.c index 2f1a0cf3c..95a228d0d 100644 --- a/src/rtos/chromium-ec.c +++ b/src/rtos/chromium-ec.c @@ -11,6 +11,7 @@ #include "config.h" #endif +#include #include #include #include @@ -20,7 +21,6 @@ #define CROS_EC_MAX_TASKS 32 #define CROS_EC_MAX_NAME 200 #define CROS_EC_IDLE_STRING "<< idle >>" -#define BIT(x) (1 << (x)) struct chromium_ec_params { const char *target_name; From 017d3ddafbfac459a799f7e60613312c61fa3195 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Thu, 17 Mar 2022 14:27:58 +0100 Subject: [PATCH 76/79] gdb_server: Improve logging of GDB-remote packets - Print also the target name, not just the packet contents. This is important when there are more GDB servers (more debug-able targets) active in one OpenOCD session. - Log also the received Ctrl-C requests coming from GDB (one byte 0x3), ACKs ("+") and NACKs ("-"). - Do not print zero-length incoming packets (this occurred when Ctrl-C packets were received). - Removed a stray apostrophe "'" that got printed in gdb_log_outgoing_packet() Signed-off-by: Jan Matyas Change-Id: If68fe0a8aa635165d0bbe6fa0e48a4645a02da67 Reviewed-on: https://review.openocd.org/c/openocd/+/6879 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 45 ++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f5736196e..82c8ce92b 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -371,11 +371,13 @@ static int gdb_write(struct connection *connection, void *data, int len) return ERROR_SERVER_REMOTE_CLOSED; } -static void gdb_log_incoming_packet(char *packet) +static void gdb_log_incoming_packet(struct connection *connection, char *packet) { if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; + struct target *target = get_target_from_connection(connection); + /* Avoid dumping non-printable characters to the terminal */ const unsigned packet_len = strlen(packet); const char *nonprint = find_nonprint_char(packet, packet_len); @@ -389,25 +391,31 @@ static void gdb_log_incoming_packet(char *packet) if (packet_prefix_printable) { const unsigned int prefix_len = colon - packet + 1; /* + 1 to include the ':' */ const unsigned int payload_len = packet_len - prefix_len; - LOG_DEBUG("received packet: %.*s", prefix_len, packet, payload_len); + LOG_TARGET_DEBUG(target, "received packet: %.*s", prefix_len, + packet, payload_len); } else { - LOG_DEBUG("received packet: ", packet_len); + LOG_TARGET_DEBUG(target, "received packet: ", packet_len); } } else { /* All chars printable, dump the packet as is */ - LOG_DEBUG("received packet: %s", packet); + LOG_TARGET_DEBUG(target, "received packet: %s", packet); } } -static void gdb_log_outgoing_packet(char *packet_buf, unsigned int packet_len, unsigned char checksum) +static void gdb_log_outgoing_packet(struct connection *connection, char *packet_buf, + unsigned int packet_len, unsigned char checksum) { if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; + struct target *target = get_target_from_connection(connection); + if (find_nonprint_char(packet_buf, packet_len)) - LOG_DEBUG("sending packet: $#%2.2x", packet_len, checksum); + LOG_TARGET_DEBUG(target, "sending packet: $#%2.2x", + packet_len, checksum); else - LOG_DEBUG("sending packet: $%.*s#%2.2x'", packet_len, packet_buf, checksum); + LOG_TARGET_DEBUG(target, "sending packet: $%.*s#%2.2x", packet_len, packet_buf, + checksum); } static int gdb_put_packet_inner(struct connection *connection, @@ -450,7 +458,7 @@ static int gdb_put_packet_inner(struct connection *connection, #endif while (1) { - gdb_log_outgoing_packet(buffer, len, my_checksum); + gdb_log_outgoing_packet(connection, buffer, len, my_checksum); char local_buffer[1024]; local_buffer[0] = '$'; @@ -483,22 +491,27 @@ static int gdb_put_packet_inner(struct connection *connection, if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = true; + gdb_log_incoming_packet(connection, ""); retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; - if (reply == '+') + if (reply == '+') { + gdb_log_incoming_packet(connection, "+"); break; - else if (reply == '-') { + } else if (reply == '-') { /* Stop sending output packets for now */ gdb_con->output_flag = GDB_OUTPUT_NO; + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); @@ -675,6 +688,7 @@ static int gdb_get_packet_inner(struct connection *connection, case '$': break; case '+': + gdb_log_incoming_packet(connection, "+"); /* According to the GDB documentation * (https://sourceware.org/gdb/onlinedocs/gdb/Packet-Acknowledgment.html): * "gdb sends a final `+` acknowledgment of the stub's `OK` @@ -692,9 +706,11 @@ static int gdb_get_packet_inner(struct connection *connection, } break; case '-': + gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative acknowledgment, but no packet pending"); break; case 0x3: + gdb_log_incoming_packet(connection, ""); gdb_con->ctrl_c = true; *len = 0; return ERROR_OK; @@ -3452,9 +3468,10 @@ static int gdb_input_inner(struct connection *connection) /* terminate with zero */ gdb_packet_buffer[packet_size] = '\0'; - gdb_log_incoming_packet(gdb_packet_buffer); - if (packet_size > 0) { + + gdb_log_incoming_packet(connection, gdb_packet_buffer); + retval = ERROR_OK; switch (packet[0]) { case 'T': /* Is thread alive? */ From f0d8c3b0e024d045262ba50a516a3bd66bf22686 Mon Sep 17 00:00:00 2001 From: Gabor Csapo Date: Fri, 18 Mar 2022 18:11:49 +0800 Subject: [PATCH 77/79] libusb_helper.h: Increase USB timeout When we debug a target that works as a USB device, halting the target causes the USB communication with the USB host to become unresponsive. The host will try to reconnect/reset/setup the unresponsive device during which communication with other devices on the same USB bus can get stalled for several seconds. If the JTAG adapter is on the same bus, we need to make sure openOCD will wait for packets at least as long as the host USB stack. Otherwise the USB stack might deliver a valid packet, but openOCD would ignore it due to the timeout. The xHCI spec uses 5 sec timeouts, so let's use that in openOCD with some margin. Use this value in all libusb calls. HID API might have a libusb backend and would probably be victim to the same bug, so it should use this timeout, too. Ticket: https://sourceforge.net/p/openocd/tickets/343/ Signed-off-by: Gabor Csapo Change-Id: Ia3dc1356e676fe550f57a4c72f7a24ba296b6af2 Reviewed-on: https://review.openocd.org/c/openocd/+/6882 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/cmsis_dap.c | 15 +++++++-------- src/jtag/drivers/libusb_helper.h | 14 ++++++++++++++ src/jtag/drivers/nulink_usb.c | 4 +++- src/jtag/drivers/rlink.c | 30 ++++++++++++++---------------- src/jtag/drivers/stlink_usb.c | 4 ++-- src/jtag/drivers/ti_icdi_usb.c | 4 ++-- src/jtag/drivers/ulink.c | 11 ++++------- 7 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index e7562d087..4621fdc99 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -48,6 +48,7 @@ #include #include "cmsis_dap.h" +#include "libusb_helper.h" static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { #if BUILD_CMSIS_DAP_USB == 1 @@ -79,8 +80,6 @@ static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; static int cmsis_dap_backend = -1; static bool swd_mode; -#define USB_TIMEOUT 1000 - /* CMSIS-DAP General Commands */ #define CMD_DAP_INFO 0x00 #define CMD_DAP_LED 0x01 @@ -360,12 +359,12 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) } uint8_t current_cmd = cmsis_dap_handle->command[0]; - int retval = dap->backend->write(dap, txlen, USB_TIMEOUT); + int retval = dap->backend->write(dap, txlen, LIBUSB_TIMEOUT_MS); if (retval < 0) return retval; /* get reply */ - retval = dap->backend->read(dap, USB_TIMEOUT); + retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS); if (retval < 0) return retval; @@ -826,7 +825,7 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) } } - int retval = dap->backend->write(dap, idx, USB_TIMEOUT); + int retval = dap->backend->write(dap, idx, LIBUSB_TIMEOUT_MS); if (retval < 0) { queued_retval = retval; goto skip; @@ -854,7 +853,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) /* get reply */ int retval = dap->backend->read(dap, timeout_ms); - if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < USB_TIMEOUT) + if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < LIBUSB_TIMEOUT_MS) return; if (retval <= 0) { @@ -929,7 +928,7 @@ static int cmsis_dap_swd_run_queue(void) cmsis_dap_swd_write_from_queue(cmsis_dap_handle); while (pending_fifo_block_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); + cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); pending_fifo_put_idx = 0; pending_fifo_get_idx = 0; @@ -953,7 +952,7 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) cmsis_dap_swd_write_from_queue(cmsis_dap_handle); if (pending_fifo_block_count >= cmsis_dap_handle->packet_count) - cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT); + cmsis_dap_swd_read_process(cmsis_dap_handle, LIBUSB_TIMEOUT_MS); } if (queued_retval != ERROR_OK) diff --git a/src/jtag/drivers/libusb_helper.h b/src/jtag/drivers/libusb_helper.h index 2ddb246b3..9d51464a7 100644 --- a/src/jtag/drivers/libusb_helper.h +++ b/src/jtag/drivers/libusb_helper.h @@ -22,6 +22,20 @@ #include +/* When we debug a target that works as a USB device, halting the target causes the + * USB communication with the USB host to become unresponsive. The host will try + * to reconnect/reset/setup the unresponsive device during which communication + * with other devices on the same USB bus can get stalled for several seconds. + * If the JTAG adapter is on the same bus, we need to make sure openOCD will wait + * for packets at least as long as the host USB stack. Otherwise the USB stack + * might deliver a valid packet, but openOCD would ignore it due to the timeout. + * The xHCI spec uses 5 sec timeouts, so let's use that in openOCD with some margin. + * + * Use this value in all libusb calls. HID API might have a libusb backend and + * would probably be victim to the same bug, so it should use this timeout, too. + */ +#define LIBUSB_TIMEOUT_MS (6000) + /* this callback should return a non NULL value only when the serial could not * be retrieved by the standard 'libusb_get_string_descriptor_ascii' */ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *device, diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index d4b8b53bc..84a4420e8 100644 --- a/src/jtag/drivers/nulink_usb.c +++ b/src/jtag/drivers/nulink_usb.c @@ -33,7 +33,9 @@ #include -#define NULINK_READ_TIMEOUT 1000 +#include "libusb_helper.h" + +#define NULINK_READ_TIMEOUT LIBUSB_TIMEOUT_MS #define NULINK_HID_MAX_SIZE (64) #define NULINK2_HID_MAX_SIZE (1024) diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 73be3c57e..0cf9dbbb2 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -59,8 +59,6 @@ #define USB_EP2IN_SIZE (USB_EP2OUT_SIZE) #define USB_EP2BANK_SIZE (512) -#define USB_TIMEOUT_MS (3 * 1000) - #define DTC_STATUS_POLL_BYTE (ST7_USB_BUF_EP0OUT + 0xff) #define ST7_PD_NBUSY_LED ST7_PD0 @@ -133,7 +131,7 @@ static int ep1_generic_commandl(struct libusb_device_handle *hdev_param, size_t hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -176,7 +174,7 @@ static ssize_t ep1_memory_read( usb_ret = jtag_libusb_bulk_write( hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -186,7 +184,7 @@ static ssize_t ep1_memory_read( usb_ret = jtag_libusb_bulk_read( hdev_param, USB_EP1IN_ADDR, (char *)buffer, length, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -241,7 +239,7 @@ static ssize_t ep1_memory_write(struct libusb_device_handle *hdev_param, uint16_ usb_ret = jtag_libusb_bulk_write( hdev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -432,7 +430,7 @@ static int dtc_start_download(void) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK) @@ -462,7 +460,7 @@ static int dtc_start_download(void) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -488,7 +486,7 @@ static int dtc_run_download( hdev_param, USB_EP2OUT_ADDR, (char *)command_buffer, USB_EP2BANK_SIZE, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err < 0) @@ -512,7 +510,7 @@ static int dtc_run_download( hdev_param, USB_EP1IN_ADDR, &dtc_status, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err < 0) @@ -533,7 +531,7 @@ static int dtc_run_download( hdev_param, USB_EP2IN_ADDR, (char *)reply_buffer, reply_buffer_size, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -954,7 +952,7 @@ static void rlink_reset(int trst, int srst) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { @@ -990,7 +988,7 @@ static void rlink_reset(int trst, int srst) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { @@ -1021,7 +1019,7 @@ static void rlink_reset(int trst, int srst) usb_err = jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)&bitmap, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); if (usb_err != ERROR_OK || transferred < 1) { @@ -1576,7 +1574,7 @@ static int rlink_init(void) jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); @@ -1601,7 +1599,7 @@ static int rlink_init(void) jtag_libusb_bulk_read( hdev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, - USB_TIMEOUT_MS, + LIBUSB_TIMEOUT_MS, &transferred ); diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 325848f86..2785d9b96 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -71,8 +71,8 @@ #define ENDPOINT_IN 0x80 #define ENDPOINT_OUT 0x00 -#define STLINK_WRITE_TIMEOUT 1000 -#define STLINK_READ_TIMEOUT 1000 +#define STLINK_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) +#define STLINK_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index c94a1102f..e48d0e269 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -37,8 +37,8 @@ #define ICDI_WRITE_ENDPOINT 0x02 #define ICDI_READ_ENDPOINT 0x83 -#define ICDI_WRITE_TIMEOUT 1000 -#define ICDI_READ_TIMEOUT 1000 +#define ICDI_WRITE_TIMEOUT (LIBUSB_TIMEOUT_MS) +#define ICDI_READ_TIMEOUT (LIBUSB_TIMEOUT_MS) #define ICDI_PACKET_SIZE 2048 #define PACKET_START "$" diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 20a036a78..50609a64b 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -56,9 +56,6 @@ /** USB interface number */ #define USB_INTERFACE 0 -/** libusb timeout in ms */ -#define USB_TIMEOUT 5000 - /** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ #define ULINK_RENUMERATION_DELAY 1500000 @@ -335,7 +332,7 @@ static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) ret = libusb_control_transfer(device->usb_device_handle, (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), - REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, USB_TIMEOUT); + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS); /* usb_control_msg() returns the number of bytes transferred during the * DATA stage of the control transfer - must be exactly 1 in this case! */ @@ -478,7 +475,7 @@ static int ulink_write_firmware_section(struct ulink *device, ret = libusb_control_transfer(device->usb_device_handle, (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (unsigned char *)data_ptr, - chunk_size, USB_TIMEOUT); + chunk_size, LIBUSB_TIMEOUT_MS); if (ret != (int)chunk_size) { /* Abort if libusb sent less data than requested */ @@ -662,7 +659,7 @@ static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) if ((newsize_out > 64) || (newsize_in > 64)) { /* New command does not fit. Execute all commands in queue before starting * new queue with the current command as first entry. */ - ret = ulink_execute_queued_commands(device, USB_TIMEOUT); + ret = ulink_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); if (ret == ERROR_OK) ret = ulink_post_process_queue(device); @@ -1960,7 +1957,7 @@ static int ulink_execute_queue(void) } if (ulink_handle->commands_in_queue > 0) { - ret = ulink_execute_queued_commands(ulink_handle, USB_TIMEOUT); + ret = ulink_execute_queued_commands(ulink_handle, LIBUSB_TIMEOUT_MS); if (ret != ERROR_OK) return ret; From c3b9ae6977a5c1c5d3252ea430ed19d0fc98fde7 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 25 Mar 2022 16:08:56 +0100 Subject: [PATCH 78/79] drivers/cmsis-dap: Remove stray whitespace Change-Id: I7b60f9e87af2f582864ce94198d0343acf7d45f2 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6883 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/jtag/drivers/cmsis_dap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 4621fdc99..63407be42 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -209,7 +209,7 @@ static bool swd_mode; * None as yet... */ static const char * const info_caps_str[INFO_CAPS__NUM_CAPS] = { - "SWD supported", + "SWD supported", "JTAG supported", "SWO-UART supported", "SWO-MANCHESTER supported", From 7c6d379cf4434c69a977af4f417fe1ab1f3f9178 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 25 Mar 2022 16:22:16 +0100 Subject: [PATCH 79/79] tcl/board: Add NXP FRDM-K64F Change-Id: I4b8fbfb2948c4295c2a34d641dd59a73c512d9fa Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6884 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- tcl/board/nxp_frdm-k64f.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tcl/board/nxp_frdm-k64f.cfg diff --git a/tcl/board/nxp_frdm-k64f.cfg b/tcl/board/nxp_frdm-k64f.cfg new file mode 100644 index 000000000..1581c9594 --- /dev/null +++ b/tcl/board/nxp_frdm-k64f.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is an NXP Freedom eval board with a single MK64FN1M0VLL12 chip. +# https://www.nxp.com/design/development-boards/freedom-development-boards/mcu-boards/freedom-development-platform-for-kinetis-k64-k63-and-k24-mcus:FRDM-K64F +# + +source [find interface/cmsis-dap.cfg] + +# Set working area to 16 KiB +set WORKAREASIZE 0x4000 + +set CHIPNAME k64f +reset_config srst_only + +source [find target/kx.cfg]