From 339763ed2d9a00ac1f2418403bd29c324d1c7e6e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 2 Dec 2023 17:06:17 +0100 Subject: [PATCH 01/55] command: rewrite command 'command mode' as COMMAND_HANDLER Another step to drop jim_handler. Change-Id: I85cb567386a5aceb36aa273f8b66cbfd4a637c3f Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8586 Tested-by: jenkins Reviewed-by: Evgeniy Naydanov --- src/helper/command.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/helper/command.c b/src/helper/command.c index 3d4379d06c..923b091a8a 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -843,22 +843,19 @@ COMMAND_HANDLER(handle_help_command) return retval; } -static char *alloc_concatenate_strings(int argc, Jim_Obj * const *argv) +static char *alloc_concatenate_strings(int argc, const char **argv) { - char *prev, *all; - int i; - assert(argc >= 1); - all = strdup(Jim_GetString(argv[0], NULL)); + char *all = strdup(argv[0]); if (!all) { LOG_ERROR("Out of memory"); return NULL; } - for (i = 1; i < argc; ++i) { - prev = all; - all = alloc_printf("%s %s", all, Jim_GetString(argv[i], NULL)); + for (int i = 1; i < argc; ++i) { + char *prev = all; + all = alloc_printf("%s %s", all, argv[i]); free(prev); if (!all) { LOG_ERROR("Out of memory"); @@ -944,17 +941,16 @@ static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_na return c->mode; } -static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_command_mode) { - struct command_context *cmd_ctx = current_command_context(interp); - enum command_mode mode = cmd_ctx->mode; + enum command_mode mode = CMD_CTX->mode; - if (argc > 1) { - char *full_name = alloc_concatenate_strings(argc - 1, argv + 1); + if (CMD_ARGC) { + char *full_name = alloc_concatenate_strings(CMD_ARGC, CMD_ARGV); if (!full_name) - return JIM_ERR; + return ERROR_FAIL; - mode = get_command_mode(interp, full_name); + mode = get_command_mode(CMD_CTX->interp, full_name); free(full_name); } @@ -975,8 +971,8 @@ static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) mode_str = "unknown"; break; } - Jim_SetResultString(interp, mode_str, -1); - return JIM_OK; + command_print(CMD, "%s", mode_str); + return ERROR_OK; } int help_del_all_commands(struct command_context *cmd_ctx) @@ -1115,7 +1111,7 @@ static const struct command_registration command_subcommand_handlers[] = { { .name = "mode", .mode = COMMAND_ANY, - .jim_handler = jim_command_mode, + .handler = handle_command_mode, .usage = "[command_name ...]", .help = "Returns the command modes allowed by a command: " "'any', 'config', or 'exec'. If no command is " From 16c5c1b353b06602d81a8a81f5243154a6c366cc Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 2 Dec 2023 17:34:57 +0100 Subject: [PATCH 02/55] command: rewrite command 'capture' as COMMAND_HANDLER While there, use Jim_EvalObj() to execute the subcommand, so any error will correctly report the TCL file and the line number that have originated the error, instead of the silly: > capture {bogus command} command.c:703: Error: invalid command name "bogus" at file "command.c", line 703 Change-Id: Ic75a6146d6cedf49e808d98501fa1a7d4235b58a Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8587 Tested-by: jenkins --- src/helper/command.c | 113 +++++++++++++------------------------------ 1 file changed, 34 insertions(+), 79 deletions(-) diff --git a/src/helper/command.c b/src/helper/command.c index 923b091a8a..218f0581ef 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -31,8 +31,7 @@ #define __THIS__FILE__ "command.c" struct log_capture_state { - Jim_Interp *interp; - Jim_Obj *output; + char *output; }; static int unregister_command(struct command_context *context, @@ -59,73 +58,6 @@ void *jimcmd_privdata(Jim_Cmd *cmd) return cmd->isproc ? NULL : cmd->u.native.privData; } -static void tcl_output(void *privData, const char *file, unsigned int line, - const char *function, const char *string) -{ - struct log_capture_state *state = privData; - Jim_AppendString(state->interp, state->output, string, strlen(string)); -} - -static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) -{ - /* capture log output and return it. A garbage collect can - * happen, so we need a reference count to this object */ - Jim_Obj *jim_output = Jim_NewStringObj(interp, "", 0); - if (!jim_output) - return NULL; - - Jim_IncrRefCount(jim_output); - - struct log_capture_state *state = malloc(sizeof(*state)); - if (!state) { - LOG_ERROR("Out of memory"); - Jim_DecrRefCount(interp, jim_output); - return NULL; - } - - state->interp = interp; - state->output = jim_output; - - log_add_callback(tcl_output, state); - - return state; -} - -/* Classic openocd commands provide progress output which we - * will capture and return as a Tcl return value. - * - * However, if a non-openocd command has been invoked, then it - * makes sense to return the tcl return value from that command. - * - * The tcl return value is empty for openocd commands that provide - * progress output. - * - * For other commands, we prepend the logs to the tcl return value. - */ -static void command_log_capture_finish(struct log_capture_state *state) -{ - if (!state) - return; - - log_remove_callback(tcl_output, state); - - int loglen; - const char *log_result = Jim_GetString(state->output, &loglen); - int reslen; - const char *cmd_result = Jim_GetString(Jim_GetResult(state->interp), &reslen); - - // Just in case the log doesn't end with a newline, we add it - if (loglen != 0 && reslen != 0 && log_result[loglen - 1] != '\n') - Jim_AppendString(state->interp, state->output, "\n", 1); - - Jim_AppendString(state->interp, state->output, cmd_result, reslen); - - Jim_SetResult(state->interp, state->output); - Jim_DecrRefCount(state->interp, state->output); - - free(state); -} - static int command_retval_set(Jim_Interp *interp, int retval) { int *return_retval = Jim_GetAssocData(interp, "retval"); @@ -680,15 +612,28 @@ COMMAND_HANDLER(handle_echo) return ERROR_OK; } -/* Return both the progress output (LOG_INFO and higher) +static void tcl_output(void *privData, const char *file, unsigned int line, + const char *function, const char *string) +{ + struct log_capture_state *state = privData; + char *old = state->output; + + state->output = alloc_printf("%s%s", old ? old : "", string); + free(old); + if (!state->output) + LOG_ERROR("Out of memory"); +} + +/* + * Return both the progress output (LOG_INFO and higher) * and the tcl return value of a command. */ -static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_command_capture) { - if (argc != 2) - return JIM_ERR; + struct log_capture_state state = {NULL}; - struct log_capture_state *state = command_log_capture_start(interp); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; /* disable polling during capture. This avoids capturing output * from polling. @@ -698,14 +643,24 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) */ bool save_poll_mask = jtag_poll_mask(); - const char *str = Jim_GetString(argv[1], NULL); - int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__); + log_add_callback(tcl_output, &state); + + int jimretval = Jim_EvalObj(CMD_CTX->interp, CMD_JIMTCL_ARGV[0]); + const char *cmd_result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL); + + log_remove_callback(tcl_output, &state); jtag_poll_unmask(save_poll_mask); - command_log_capture_finish(state); + if (state.output && *state.output) + command_print(CMD, "%s", state.output); + + if (cmd_result && *cmd_result) + command_print(CMD, "%s", cmd_result); + + free(state.output); - return retcode; + return (jimretval == JIM_OK) ? ERROR_OK : ERROR_FAIL; } struct help_entry { @@ -1133,7 +1088,7 @@ static const struct command_registration command_builtin_handlers[] = { { .name = "capture", .mode = COMMAND_ANY, - .jim_handler = jim_capture, + .handler = handle_command_capture, .help = "Capture progress output and return as tcl return value. If the " "progress output was empty, return tcl return value.", .usage = "command", From cfed1f78db635b504e4d11da537e614adfd57d3f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 5 Apr 2025 17:04:43 +0200 Subject: [PATCH 03/55] list: silent scan-build false positive With commit c023534e7b6f ("target: use list for target events") scan build incorrectly states that list_add() would be called with the field 'next' of the parameter 'head' (thus 'head->next') set to NULL. Then, list_add() would call linux_list_add() with the parameter 'next' set to NULL that will cause a NULL dereference. While this can really happen with broken code, it's not the case with the code from the change above. Add assert() in linux_list_add() to silent scan build on this false positive and to detect future incorrect use of the list. Change-Id: Iec7f3d70237312b646ac58f76ecaab2fa25eab41 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8824 Tested-by: jenkins --- src/helper/list.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helper/list.h b/src/helper/list.h index ba07f15568..89b8468ec4 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -35,6 +35,7 @@ /* begin OpenOCD changes */ +#include #include struct list_head { @@ -109,6 +110,9 @@ static inline void linux_list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { + assert(next); + assert(prev); + next->prev = new; new->next = next; new->prev = prev; From a1ecf0a03d9812c285618ed995ea818eba020be3 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 6 Apr 2025 01:20:44 +0200 Subject: [PATCH 04/55] target: don't free working areas during 'configure -chain-position' Since commit ef1cfb23947b ("Duane Ellis: "target as an [tcl] object" feature.") merged in 2008, the commands: $target_name configure -chain-position ... target create ... -chain-position ... cause the allocated working area to be freed. There is no reason for this, it is probably caused by an incorrect copy/paste from the author. Drop the call to target_free_all_working_areas(). Change-Id: I61a9303afe7fee6953669218330635c0b965b20d Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8825 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/target/target.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 8c5c8e5e30..36ad0eec83 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5128,7 +5128,6 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) return JIM_ERR; } - target_free_all_working_areas(target); e = jim_getopt_obj(goi, &o_t); if (e != JIM_OK) return e; From 4a616ca4d83919fea03bf084ff326f584de558d7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 2 Dec 2023 18:40:47 +0100 Subject: [PATCH 05/55] target: rewrite command 'invoke-event' as COMMAND_HANDLER The command shares with command 'target create' the struct jim_nvp nvp_target_event[] - Convert the 'struct jim_nvp' in 'struct nvp'. - Create an alias 'struct jim_nvp' to decouple the commands 'invoke-event' and 'target create', abusing the fact that the actual layout of the two struct's type is the same. This alias will be dropped in a following change. - Rewrite the command 'invoke-event' and the helper function target_event_name(). Change-Id: I537732fe4c08042cc02bcd0f72142254d7968fa6 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8826 Tested-by: jenkins --- src/target/target.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 36ad0eec83..3f16caaffe 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -162,7 +162,7 @@ static const char *target_strerror_safe(int err) return n->name; } -static const struct jim_nvp nvp_target_event[] = { +static const struct nvp nvp_target_event[] = { { .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" }, { .value = TARGET_EVENT_HALTED, .name = "halted" }, @@ -214,6 +214,8 @@ static const struct jim_nvp nvp_target_event[] = { { .name = NULL, .value = -1 } }; +static const struct jim_nvp *jim_nvp_target_event = (const struct jim_nvp *)nvp_target_event; + static const struct nvp nvp_target_state[] = { { .name = "unknown", .value = TARGET_UNKNOWN }, { .name = "running", .value = TARGET_RUNNING }, @@ -283,7 +285,7 @@ const char *target_state_name(const struct target *t) const char *target_event_name(enum target_event event) { const char *cp; - cp = jim_nvp_value2name_simple(nvp_target_event, event)->name; + cp = nvp_value2name(nvp_target_event, event)->name; if (!cp) { LOG_ERROR("Invalid target event: %d", (int)(event)); cp = "(*BUG*unknown*BUG*)"; @@ -4932,9 +4934,9 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) return JIM_ERR; } - e = jim_getopt_nvp(goi, nvp_target_event, &n); + e = jim_getopt_nvp(goi, jim_nvp_target_event, &n); if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_target_event, 1); + jim_getopt_nvp_unknown(goi, jim_nvp_target_event, 1); return e; } @@ -5469,26 +5471,20 @@ COMMAND_HANDLER(handle_target_debug_reason) return ERROR_OK; } -static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_invoke_event) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc != 1) { - const char *cmd_name = Jim_GetString(argv[0], NULL); - Jim_SetResultFormatted(goi.interp, "%s ", cmd_name); - return JIM_ERR; - } - struct jim_nvp *n; - int e = jim_getopt_nvp(&goi, nvp_target_event, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_target_event, 1); - return e; + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + const struct nvp *n = nvp_name2value(nvp_target_event, CMD_ARGV[0]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_target_event, NULL, CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); + + struct target *target = get_current_target(CMD_CTX); target_handle_event(target, n->value); - return JIM_OK; + return ERROR_OK; } static const struct command_registration target_instance_command_handlers[] = { @@ -5670,7 +5666,7 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "invoke-event", .mode = COMMAND_EXEC, - .jim_handler = jim_target_invoke_event, + .handler = handle_target_invoke_event, .help = "invoke handler for specified event", .usage = "event_name", }, From 29e4a366222b96aac89dbec11e5f4a83a6a83bbe Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 2 Dec 2023 23:01:44 +0100 Subject: [PATCH 06/55] target: rewrite command 'target create' as COMMAND_HANDLER Rewrite only the command, but still use the old jimtcl specific code shared with 'configure' and 'cget'. Change-Id: I7cf220e494f0ebbf123f8075b1feb9251fd7f569 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8827 Tested-by: jenkins --- src/target/target.c | 147 ++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 82 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 3f16caaffe..9d9d73a28e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5673,44 +5673,29 @@ static const struct command_registration target_instance_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static int target_create(struct jim_getopt_info *goi) +COMMAND_HANDLER(handle_target_create) { - Jim_Obj *new_cmd; - Jim_Cmd *cmd; - const char *cp; - int e; + int retval = ERROR_OK; int x; - struct target *target; - struct command_context *cmd_ctx; - cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx); - - if (goi->argc < 3) { - Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options..."); - return JIM_ERR; - } + if (CMD_ARGC < 4) + return ERROR_COMMAND_SYNTAX_ERROR; - /* COMMAND */ - jim_getopt_obj(goi, &new_cmd); - /* does this command exist? */ - cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); - if (cmd) { - cp = Jim_GetString(new_cmd, NULL); - Jim_SetResultFormatted(goi->interp, "Command/target: %s Exists", cp); - return JIM_ERR; + /* check if the target name clashes with an existing command name */ + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "Command/target: %s Exists", CMD_ARGV[0]); + return ERROR_FAIL; } /* TYPE */ - e = jim_getopt_string(goi, &cp, NULL); - if (e != JIM_OK) - return e; + const char *cp = CMD_ARGV[1]; struct transport *tr = get_current_transport(); if (tr && tr->override_target) { - e = tr->override_target(&cp); - if (e != ERROR_OK) { - LOG_ERROR("The selected transport doesn't support this target"); - return JIM_ERR; + retval = tr->override_target(&cp); + if (retval != ERROR_OK) { + command_print(CMD, "The selected transport doesn't support this target"); + return retval; } LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD"); } @@ -5722,28 +5707,29 @@ static int target_create(struct jim_getopt_info *goi) } } if (!target_types[x]) { - Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); + char *all = NULL; for (x = 0 ; target_types[x] ; x++) { - if (target_types[x + 1]) { - Jim_AppendStrings(goi->interp, - Jim_GetResult(goi->interp), - target_types[x]->name, - ", ", NULL); - } else { - Jim_AppendStrings(goi->interp, - Jim_GetResult(goi->interp), - " or ", - target_types[x]->name, NULL); + char *prev = all; + if (all) + all = alloc_printf("%s, %s", all, target_types[x]->name); + else + all = alloc_printf("%s", target_types[x]->name); + free(prev); + if (!all) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; } } - return JIM_ERR; + command_print(CMD, "Unknown target type %s, try one of %s", cp, all); + free(all); + return ERROR_FAIL; } /* Create it */ - target = calloc(1, sizeof(struct target)); + struct target *target = calloc(1, sizeof(struct target)); if (!target) { LOG_ERROR("Out of memory"); - return JIM_ERR; + return ERROR_FAIL; } /* set empty smp cluster */ @@ -5754,7 +5740,7 @@ static int target_create(struct jim_getopt_info *goi) if (!target->type) { LOG_ERROR("Out of memory"); free(target); - return JIM_ERR; + return ERROR_FAIL; } memcpy(target->type, target_types[x], sizeof(struct target_type)); @@ -5787,7 +5773,7 @@ static int target_create(struct jim_getopt_info *goi) LOG_ERROR("Out of memory"); free(target->type); free(target); - return JIM_ERR; + return ERROR_FAIL; } target->dbgmsg = NULL; @@ -5801,45 +5787,54 @@ static int target_create(struct jim_getopt_info *goi) target->gdb_port_override = NULL; target->gdb_max_connections = 1; - cp = Jim_GetString(new_cmd, NULL); - target->cmd_name = strdup(cp); + target->cmd_name = strdup(CMD_ARGV[0]); if (!target->cmd_name) { LOG_ERROR("Out of memory"); free(target->trace_info); free(target->type); free(target); - return JIM_ERR; + return ERROR_FAIL; } /* Do the rest as "configure" options */ - goi->is_configure = true; - e = target_configure(goi, target); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 2, CMD_JIMTCL_ARGV + 2); + + goi.is_configure = 1; + int e = target_configure(&goi, target); + + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); if (e == JIM_OK) { if (target->has_dap) { if (!target->dap_configured) { - Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1); - e = JIM_ERR; + command_print(CMD, "-dap ?name? required when creating target"); + retval = ERROR_COMMAND_ARGUMENT_INVALID; } } else { if (!target->tap_configured) { - Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1); - e = JIM_ERR; + command_print(CMD, "-chain-position ?name? required when creating target"); + retval = ERROR_COMMAND_ARGUMENT_INVALID; } } /* tap must be set after target was configured */ if (!target->tap) - e = JIM_ERR; + retval = ERROR_COMMAND_ARGUMENT_INVALID; + } else { + retval = ERROR_FAIL; } - if (e != JIM_OK) { + if (retval != ERROR_OK) { rtos_destroy(target); free(target->gdb_port_override); free(target->trace_info); free(target->type); free(target->private_config); free(target); - return e; + return retval; } if (target->endianness == TARGET_ENDIAN_UNKNOWN) { @@ -5848,8 +5843,8 @@ static int target_create(struct jim_getopt_info *goi) } if (target->type->target_create) { - e = (*(target->type->target_create))(target, goi->interp); - if (e != ERROR_OK) { + retval = (*target->type->target_create)(target, CMD_CTX->interp); + if (retval != ERROR_OK) { LOG_DEBUG("target_create failed"); free(target->cmd_name); rtos_destroy(target); @@ -5858,15 +5853,15 @@ static int target_create(struct jim_getopt_info *goi) free(target->type); free(target->private_config); free(target); - return JIM_ERR; + return retval; } } /* create the target specific commands */ if (target->type->commands) { - e = register_commands(cmd_ctx, NULL, target->type->commands); - if (e != ERROR_OK) - LOG_ERROR("unable to register '%s' commands", cp); + retval = register_commands(CMD_CTX, NULL, target->type->commands); + if (retval != ERROR_OK) + LOG_ERROR("unable to register '%s' commands", CMD_ARGV[0]); } /* now - create the new target name command */ @@ -5881,7 +5876,7 @@ static int target_create(struct jim_getopt_info *goi) }; const struct command_registration target_commands[] = { { - .name = cp, + .name = CMD_ARGV[0], .mode = COMMAND_ANY, .help = "target command group", .usage = "", @@ -5889,8 +5884,8 @@ static int target_create(struct jim_getopt_info *goi) }, COMMAND_REGISTRATION_DONE }; - e = register_commands_override_target(cmd_ctx, NULL, target_commands, target); - if (e != ERROR_OK) { + retval = register_commands_override_target(CMD_CTX, NULL, target_commands, target); + if (retval != ERROR_OK) { if (target->type->deinit_target) target->type->deinit_target(target); free(target->cmd_name); @@ -5899,14 +5894,14 @@ static int target_create(struct jim_getopt_info *goi) free(target->trace_info); free(target->type); free(target); - return JIM_ERR; + return retval; } /* append to end of list */ append_to_list_all_targets(target); - cmd_ctx->current_target = target; - return JIM_OK; + CMD_CTX->current_target = target; + return ERROR_OK; } COMMAND_HANDLER(handle_target_current) @@ -6027,18 +6022,6 @@ COMMAND_HANDLER(handle_target_smp) return retval; } -static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc < 3) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - " [ ...]"); - return JIM_ERR; - } - return target_create(&goi); -} - static const struct command_registration target_subcommand_handlers[] = { { .name = "init", @@ -6050,7 +6033,7 @@ static const struct command_registration target_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_CONFIG, - .jim_handler = jim_target_create, + .handler = handle_target_create, .usage = "name type '-chain-position' name [options ...]", .help = "Creates and selects a new target", }, From 1d9b34baa3c5087f2a3387523c6c556b4e4f1afb Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 2 Dec 2023 23:40:56 +0100 Subject: [PATCH 07/55] target: rewrite commands 'configure' and 'cget' as COMMAND_HANDLER Rewrite only the command, but still use the old jimtcl specific code shared with 'target create'. Change-Id: Ie5e1c9eb237531121c2d143d1732cf281dfdc9ff Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8828 Tested-by: jenkins --- src/target/target.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 9d9d73a28e..4bd2f24cca 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5223,22 +5223,28 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) return JIM_OK; } -static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_target_configure) { - struct command *c = jim_to_command(interp); + if (!CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - goi.is_configure = !strcmp(c->name, "configure"); - if (goi.argc < 1) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - "missing: -option ..."); - return JIM_ERR; - } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - return target_configure(&goi, target); + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC, CMD_JIMTCL_ARGV); + goi.is_configure = !strcmp(CMD_NAME, "configure"); + + struct target *target = get_current_target(CMD_CTX); + int e = target_configure(&goi, target); + + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + + if (e != JIM_OK) + return ERROR_FAIL; + + return ERROR_OK; } COMMAND_HANDLER(handle_target_examine) @@ -5491,14 +5497,14 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "configure", .mode = COMMAND_ANY, - .jim_handler = jim_target_configure, + .handler = handle_target_configure, .help = "configure a new target for use", .usage = "[target_attribute ...]", }, { .name = "cget", .mode = COMMAND_ANY, - .jim_handler = jim_target_configure, + .handler = handle_target_configure, .help = "returns the specified target attribute", .usage = "target_attribute", }, From 61890e3dc3201ce38e5af7f6b561389a123448e0 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 3 Dec 2023 15:41:27 +0100 Subject: [PATCH 08/55] target: rewrite function target_configure() as COMMAND_HELPER The function target_configure() is used by the commands 'target create', 'configure' and 'cget', already rewritten as COMMAND_HANDLER. Rewrite the common function as COMMAND_HELPER. While there: - fix the check on arguments, even if it should be coded better; - keep jimtcl code for target_type::target_jim_configure() and for rtos_create(); these would be rewritten later on. Change-Id: I7e5699ca6d124e34d3b2199714e3ce584bfcce80 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8829 Tested-by: jenkins --- src/target/target.c | 434 +++++++++++++++++++++++--------------------- 1 file changed, 225 insertions(+), 209 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 4bd2f24cca..99481622db 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -214,8 +214,6 @@ static const struct nvp nvp_target_event[] = { { .name = NULL, .value = -1 } }; -static const struct jim_nvp *jim_nvp_target_event = (const struct jim_nvp *)nvp_target_event; - static const struct nvp nvp_target_state[] = { { .name = "unknown", .value = TARGET_UNKNOWN }, { .name = "running", .value = TARGET_RUNNING }, @@ -238,7 +236,7 @@ static const struct nvp nvp_target_debug_reason[] = { { .name = NULL, .value = -1 }, }; -static const struct jim_nvp nvp_target_endian[] = { +static const struct nvp nvp_target_endian[] = { { .name = "big", .value = TARGET_BIG_ENDIAN }, { .name = "little", .value = TARGET_LITTLE_ENDIAN }, { .name = "be", .value = TARGET_BIG_ENDIAN }, @@ -2844,8 +2842,7 @@ COMMAND_HANDLER(handle_targets_command) marker, target_name(target), target_type_name(target), - jim_nvp_value2name_simple(nvp_target_endian, - target->endianness)->name, + nvp_value2name(nvp_target_endian, target->endianness)->name, target->tap->dotted_name, state); } @@ -4859,7 +4856,7 @@ enum target_cfg_param { TCFG_GDB_MAX_CONNECTIONS, }; -static struct jim_nvp nvp_config_opts[] = { +static struct nvp nvp_config_opts[] = { { .name = "-type", .value = TCFG_TYPE }, { .name = "-event", .value = TCFG_EVENT }, { .name = "-work-area-virt", .value = TCFG_WORK_AREA_VIRT }, @@ -4877,78 +4874,71 @@ static struct jim_nvp nvp_config_opts[] = { { .name = NULL, .value = -1 } }; -static int target_configure(struct jim_getopt_info *goi, struct target *target) +static COMMAND_HELPER(target_configure, struct target *target, unsigned int index, bool is_configure) { - struct jim_nvp *n; - Jim_Obj *o; - jim_wide w; - int e; + const struct nvp *n; + int retval; /* parse config or cget options ... */ - while (goi->argc > 0) { - Jim_SetEmptyResult(goi->interp); - /* jim_getopt_debug(goi); */ - + while (index < CMD_ARGC) { if (target->type->target_jim_configure) { /* target defines a configure function */ /* target gets first dibs on parameters */ - e = (*(target->type->target_jim_configure))(target, goi); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - index, CMD_JIMTCL_ARGV + index); + goi.is_configure = is_configure; + int e = (*target->type->target_jim_configure)(target, &goi); + index = CMD_ARGC - goi.argc; if (e == JIM_OK) { /* more? */ continue; } if (e == JIM_ERR) { /* An error */ - return e; + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + return ERROR_FAIL; } /* otherwise we 'continue' below */ } - e = jim_getopt_nvp(goi, nvp_config_opts, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_config_opts, 0); - return e; + n = nvp_name2value(nvp_config_opts, CMD_ARGV[index]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_config_opts, NULL, CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; } + index++; switch (n->value) { case TCFG_TYPE: /* not settable */ - if (goi->is_configure) { - Jim_SetResultFormatted(goi->interp, - "not settable: %s", n->name); - return JIM_ERR; - } else { -no_params: - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; - } + if (is_configure) { + command_print(CMD, "not settable: %s", n->name); + return ERROR_COMMAND_ARGUMENT_INVALID; } - Jim_SetResultString(goi->interp, - target_type_name(target), -1); + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%s", target_type_name(target)); /* loop for more */ break; + case TCFG_EVENT: - if (goi->argc == 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ..."); - return JIM_ERR; + if (index == CMD_ARGC) { + command_print(CMD, "missing event-name"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - e = jim_getopt_nvp(goi, jim_nvp_target_event, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, jim_nvp_target_event, 1); - return e; + n = nvp_name2value(nvp_target_event, CMD_ARGV[index]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_target_event, CMD_ARGV[index - 1], CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; } + index++; - if (goi->is_configure) { - if (goi->argc != 1) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); - return JIM_ERR; - } - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); - return JIM_ERR; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing event-body"); + return ERROR_COMMAND_ARGUMENT_INVALID; } } @@ -4964,20 +4954,20 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) if (&teap->list == &target->events_action) teap = NULL; - if (goi->is_configure) { + if (is_configure) { /* START_DEPRECATED_TPIU */ if (n->value == TARGET_EVENT_TRACE_CONFIG) LOG_INFO("DEPRECATED target event %s; use TPIU events {pre,post}-{enable,disable}", n->name); /* END_DEPRECATED_TPIU */ - jim_getopt_obj(goi, &o); - if (Jim_Length(o) == 0) { + if (strlen(CMD_ARGV[index]) == 0) { /* empty action, drop existing one */ if (teap) { list_del(&teap->list); Jim_DecrRefCount(teap->interp, teap->body); free(teap); } + index++; break; } @@ -4988,10 +4978,12 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) replace = false; } teap->event = n->value; - teap->interp = goi->interp; + teap->interp = CMD_CTX->interp; if (teap->body) Jim_DecrRefCount(teap->interp, teap->body); - teap->body = Jim_DuplicateObj(goi->interp, o); + /* use jim object to keep its reference on tcl file and line */ + /* TODO: need duplicate? isn't IncrRefCount enough? */ + teap->body = Jim_DuplicateObj(teap->interp, CMD_JIMTCL_ARGV[index++]); /* * FIXME: * Tcl/TK - "tk events" have a nice feature. @@ -5008,219 +5000,266 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) /* add to head of event list */ list_add(&teap->list, &target->events_action); } - Jim_SetEmptyResult(goi->interp); } else { - /* get */ - if (!teap) - Jim_SetEmptyResult(goi->interp); - else - Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body)); + /* cget */ + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (teap) + command_print(CMD, "%s", Jim_GetString(teap->body, NULL)); } } /* loop for more */ break; case TCFG_WORK_AREA_VIRT: - if (goi->is_configure) { - target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->working_area_virt = w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[index], target->working_area_virt); + index++; target->working_area_virt_spec = true; + target_free_all_working_areas(target); } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, TARGET_ADDR_FMT, target->working_area_virt); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_virt)); /* loop for more */ break; case TCFG_WORK_AREA_PHYS: - if (goi->is_configure) { - target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->working_area_phys = w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[index], target->working_area_phys); + index++; target->working_area_phys_spec = true; + target_free_all_working_areas(target); } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, TARGET_ADDR_FMT, target->working_area_phys); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_phys)); /* loop for more */ break; case TCFG_WORK_AREA_SIZE: - if (goi->is_configure) { + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index], target->working_area_size); + index++; target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->working_area_size = w; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "0x%08" PRIx32, target->working_area_size); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size)); /* loop for more */ break; case TCFG_WORK_AREA_BACKUP: - if (goi->is_configure) { + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + retval = command_parse_bool_arg(CMD_ARGV[index], &target->backup_working_area); + if (retval != ERROR_OK) + return retval; + index++; target_free_all_working_areas(target); - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - /* make this boolean */ - target->backup_working_area = (w != 0); } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, target->backup_working_area ? "1" : "0"); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area ? 1 : 0)); - /* loop for more e*/ + /* loop for more */ break; - case TCFG_ENDIAN: - if (goi->is_configure) { - e = jim_getopt_nvp(goi, nvp_target_endian, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(goi, nvp_target_endian, 1); - return e; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + n = nvp_name2value(nvp_target_endian, CMD_ARGV[index]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_target_endian, CMD_ARGV[index - 1], CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; } + index++; target->endianness = n->value; } else { - if (goi->argc != 0) - goto no_params; - } - n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); - if (!n->name) { - target->endianness = TARGET_LITTLE_ENDIAN; - n = jim_nvp_value2name_simple(nvp_target_endian, target->endianness); + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + n = nvp_value2name(nvp_target_endian, target->endianness); + if (!n->name) { + target->endianness = TARGET_LITTLE_ENDIAN; + n = nvp_value2name(nvp_target_endian, target->endianness); + } + command_print(CMD, "%s", n->name); } - Jim_SetResultString(goi->interp, n->name, -1); /* loop for more */ break; case TCFG_COREID: - if (goi->is_configure) { - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->coreid = (int32_t)w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(s32, CMD_ARGV[index], target->coreid); + index++; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%" PRIi32, target->coreid); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->coreid)); /* loop for more */ break; case TCFG_CHAIN_POSITION: - if (goi->is_configure) { - Jim_Obj *o_t; - struct jtag_tap *tap; - + if (is_configure) { if (target->has_dap) { - Jim_SetResultString(goi->interp, - "target requires -dap parameter instead of -chain-position!", -1); - return JIM_ERR; + command_print(CMD, "target requires -dap parameter instead of -chain-position!"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - e = jim_getopt_obj(goi, &o_t); - if (e != JIM_OK) - return e; - tap = jtag_tap_by_jim_obj(goi->interp, o_t); - if (!tap) - return JIM_ERR; + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[index]); + if (!tap) { + command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[index]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + index++; target->tap = tap; target->tap_configured = true; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%s", target->tap->dotted_name); } - Jim_SetResultString(goi->interp, target->tap->dotted_name, -1); - /* loop for more e*/ + /* loop for more */ break; + case TCFG_DBGBASE: - if (goi->is_configure) { - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->dbgbase = (uint32_t)w; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index], target->dbgbase); + index++; target->dbgbase_set = true; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "0x%08" PRIx32, target->dbgbase); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ break; + case TCFG_RTOS: - /* RTOS */ - { - int result = rtos_create(goi, target); - if (result != JIM_OK) - return result; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - index, CMD_JIMTCL_ARGV + index); + index++; + goi.is_configure = true; + int resval = rtos_create(&goi, target); + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + if (resval != JIM_OK) + return ERROR_FAIL; + } else { + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + if (target->rtos) + command_print(CMD, "%s", target->rtos->type->name); } /* loop for more */ break; case TCFG_DEFER_EXAMINE: - /* DEFER_EXAMINE */ - target->defer_examine = true; + if (is_configure) + target->defer_examine = true; + else + command_print(CMD, "%s", target->defer_examine ? "true" : "false"); /* loop for more */ break; case TCFG_GDB_PORT: - if (goi->is_configure) { - struct command_context *cmd_ctx = current_command_context(goi->interp); - if (cmd_ctx->mode != COMMAND_CONFIG) { - Jim_SetResultString(goi->interp, "-gdb-port must be configured before 'init'", -1); - return JIM_ERR; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + /* TODO: generalize test of COMMAND_CONFIG */ + if (CMD_CTX->mode != COMMAND_CONFIG) { + command_print(CMD, "-gdb-port must be configured before 'init'"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - const char *s; - e = jim_getopt_string(goi, &s, NULL); - if (e != JIM_OK) - return e; + char *s = strdup(CMD_ARGV[index]); + if (!s) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } free(target->gdb_port_override); - target->gdb_port_override = strdup(s); + target->gdb_port_override = s; + index++; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%s", target->gdb_port_override ? target->gdb_port_override : "undefined"); } - Jim_SetResultString(goi->interp, target->gdb_port_override ? target->gdb_port_override : "undefined", -1); /* loop for more */ break; case TCFG_GDB_MAX_CONNECTIONS: - if (goi->is_configure) { - struct command_context *cmd_ctx = current_command_context(goi->interp); - if (cmd_ctx->mode != COMMAND_CONFIG) { - Jim_SetResultString(goi->interp, "-gdb-max-connections must be configured before 'init'", -1); - return JIM_ERR; + if (is_configure) { + if (index == CMD_ARGC) { + command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (CMD_CTX->mode != COMMAND_CONFIG) { + command_print(CMD, "-gdb-max-connections must be configured before 'init'"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - e = jim_getopt_wide(goi, &w); - if (e != JIM_OK) - return e; - target->gdb_max_connections = (w < 0) ? CONNECTION_LIMIT_UNLIMITED : (int)w; + COMMAND_PARSE_NUMBER(int, CMD_ARGV[index], target->gdb_max_connections); + index++; + if (target->gdb_max_connections < 0) + target->gdb_max_connections = CONNECTION_LIMIT_UNLIMITED; } else { - if (goi->argc != 0) - goto no_params; + if (index != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "%d", target->gdb_max_connections); } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->gdb_max_connections)); + /* loop for more */ break; } - } /* while (goi->argc) */ - + } - /* done - we return */ - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(handle_target_configure) @@ -5228,23 +5267,11 @@ COMMAND_HANDLER(handle_target_configure) if (!CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; - struct jim_getopt_info goi; - - jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC, CMD_JIMTCL_ARGV); - goi.is_configure = !strcmp(CMD_NAME, "configure"); + bool is_configure = !strcmp(CMD_NAME, "configure"); struct target *target = get_current_target(CMD_CTX); - int e = target_configure(&goi, target); - - int reslen; - const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); - if (reslen > 0) - command_print(CMD, "%s", result); - - if (e != JIM_OK) - return ERROR_FAIL; - return ERROR_OK; + return CALL_COMMAND_HANDLER(target_configure, target, 0, is_configure); } COMMAND_HANDLER(handle_target_examine) @@ -5803,18 +5830,9 @@ COMMAND_HANDLER(handle_target_create) } /* Do the rest as "configure" options */ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 2, CMD_JIMTCL_ARGV + 2); - - goi.is_configure = 1; - int e = target_configure(&goi, target); - - int reslen; - const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); - if (reslen > 0) - command_print(CMD, "%s", result); - - if (e == JIM_OK) { + bool is_configure = true; + retval = CALL_COMMAND_HANDLER(target_configure, target, 2, is_configure); + if (retval == ERROR_OK) { if (target->has_dap) { if (!target->dap_configured) { command_print(CMD, "-dap ?name? required when creating target"); @@ -5829,8 +5847,6 @@ COMMAND_HANDLER(handle_target_create) /* tap must be set after target was configured */ if (!target->tap) retval = ERROR_COMMAND_ARGUMENT_INVALID; - } else { - retval = ERROR_FAIL; } if (retval != ERROR_OK) { From 9a09d38478e2fbe7a9482af11b0fafb04689355d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 6 Apr 2025 14:10:28 +0200 Subject: [PATCH 09/55] target: drop unused parameter to target_create() The parameter Jim_Interp to the target API target_create() is not used by any target. Drop it. Change-Id: I67c492078a6c808db974505f9e297c45165f64d0 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8831 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/aarch64.c | 4 ++-- src/target/arc.c | 2 +- src/target/arm11.c | 2 +- src/target/arm720t.c | 2 +- src/target/arm7tdmi.c | 2 +- src/target/arm920t.c | 2 +- src/target/arm926ejs.c | 2 +- src/target/arm946e.c | 2 +- src/target/arm966e.c | 2 +- src/target/arm9tdmi.c | 2 +- src/target/avr32_ap7k.c | 2 +- src/target/avrt.c | 4 ++-- src/target/cortex_a.c | 4 ++-- src/target/cortex_m.c | 2 +- src/target/dsp563xx.c | 2 +- src/target/dsp5680xx.c | 2 +- src/target/esirisc.c | 2 +- src/target/espressif/esp32.c | 2 +- src/target/espressif/esp32s2.c | 2 +- src/target/espressif/esp32s3.c | 2 +- src/target/fa526.c | 2 +- src/target/feroceon.c | 4 ++-- src/target/hla_target.c | 3 +-- src/target/ls1_sap.c | 2 +- src/target/mem_ap.c | 2 +- src/target/mips_m4k.c | 2 +- src/target/mips_mips64.c | 2 +- src/target/openrisc/or1k.c | 2 +- src/target/quark_d20xx.c | 2 +- src/target/quark_x10xx.c | 2 +- src/target/riscv/riscv.c | 2 +- src/target/stm8.c | 3 +-- src/target/target.c | 2 +- src/target/target_type.h | 2 +- src/target/xscale.c | 2 +- src/target/xtensa/xtensa_chip.c | 2 +- 36 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index ce7808e3ac..101cb14408 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -2814,7 +2814,7 @@ static int aarch64_init_arch_info(struct target *target, return ERROR_OK; } -static int armv8r_target_create(struct target *target, Jim_Interp *interp) +static int armv8r_target_create(struct target *target) { struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64; @@ -2833,7 +2833,7 @@ static int armv8r_target_create(struct target *target, Jim_Interp *interp) return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } -static int aarch64_target_create(struct target *target, Jim_Interp *interp) +static int aarch64_target_create(struct target *target) { struct aarch64_private_config *pc = target->private_config; struct aarch64_common *aarch64; diff --git a/src/target/arc.c b/src/target/arc.c index 8757cafedc..f2482c25ef 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1424,7 +1424,7 @@ static void arc_deinit_target(struct target *target) } -static int arc_target_create(struct target *target, Jim_Interp *interp) +static int arc_target_create(struct target *target) { struct arc_common *arc = calloc(1, sizeof(*arc)); diff --git a/src/target/arm11.c b/src/target/arm11.c index 756b36b959..583830f948 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -1079,7 +1079,7 @@ static int arm11_remove_breakpoint(struct target *target, return ERROR_OK; } -static int arm11_target_create(struct target *target, Jim_Interp *interp) +static int arm11_target_create(struct target *target) { struct arm11_common *arm11; diff --git a/src/target/arm720t.c b/src/target/arm720t.c index beab632c25..d1433dde72 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -412,7 +412,7 @@ static int arm720t_init_arch_info(struct target *target, return ERROR_OK; } -static int arm720t_target_create(struct target *target, Jim_Interp *interp) +static int arm720t_target_create(struct target *target) { struct arm720t_common *arm720t = calloc(1, sizeof(*arm720t)); diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 393d3b46af..2f59254afd 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -669,7 +669,7 @@ int arm7tdmi_init_arch_info(struct target *target, return ERROR_OK; } -static int arm7tdmi_target_create(struct target *target, Jim_Interp *interp) +static int arm7tdmi_target_create(struct target *target) { struct arm7_9_common *arm7_9; diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 53b4d9d15f..95cfd7ceb2 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -833,7 +833,7 @@ static int arm920t_init_arch_info(struct target *target, return ERROR_OK; } -static int arm920t_target_create(struct target *target, Jim_Interp *interp) +static int arm920t_target_create(struct target *target) { struct arm920t_common *arm920t; diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index add90c9978..0531106562 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -702,7 +702,7 @@ int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm return ERROR_OK; } -static int arm926ejs_target_create(struct target *target, Jim_Interp *interp) +static int arm926ejs_target_create(struct target *target) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 03f7e443fb..828e70f4bc 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -79,7 +79,7 @@ static int arm946e_init_arch_info(struct target *target, return ERROR_OK; } -static int arm946e_target_create(struct target *target, Jim_Interp *interp) +static int arm946e_target_create(struct target *target) { struct arm946e_common *arm946e = calloc(1, sizeof(struct arm946e_common)); diff --git a/src/target/arm966e.c b/src/target/arm966e.c index 8598d29d9b..b6bcc8ba97 100644 --- a/src/target/arm966e.c +++ b/src/target/arm966e.c @@ -38,7 +38,7 @@ int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e return ERROR_OK; } -static int arm966e_target_create(struct target *target, Jim_Interp *interp) +static int arm966e_target_create(struct target *target) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 7e31306b6c..8ab12de320 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -765,7 +765,7 @@ int arm9tdmi_init_arch_info(struct target *target, return ERROR_OK; } -static int arm9tdmi_target_create(struct target *target, Jim_Interp *interp) +static int arm9tdmi_target_create(struct target *target) { struct arm7_9_common *arm7_9 = calloc(1, sizeof(struct arm7_9_common)); diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index 1b051dc014..94962c2055 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -510,7 +510,7 @@ static int avr32_ap7k_init_target(struct command_context *cmd_ctx, return ERROR_OK; } -static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp) +static int avr32_ap7k_target_create(struct target *target) { struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct avr32_ap7k_common)); diff --git a/src/target/avrt.c b/src/target/avrt.c index 3afe320157..e25718bcc2 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -16,7 +16,7 @@ #define AVR_JTAG_INS_LEN 4 /* forward declarations */ -static int avr_target_create(struct target *target, Jim_Interp *interp); +static int avr_target_create(struct target *target); static int avr_init_target(struct command_context *cmd_ctx, struct target *target); static int avr_arch_state(struct target *target); @@ -68,7 +68,7 @@ struct target_type avr_target = { .init_target = avr_init_target, }; -static int avr_target_create(struct target *target, Jim_Interp *interp) +static int avr_target_create(struct target *target) { struct avr_common *avr = calloc(1, sizeof(struct avr_common)); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 9c60645586..ee27e1b217 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -3126,7 +3126,7 @@ static int cortex_a_init_arch_info(struct target *target, return ERROR_OK; } -static int cortex_a_target_create(struct target *target, Jim_Interp *interp) +static int cortex_a_target_create(struct target *target) { struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; @@ -3148,7 +3148,7 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp) return cortex_a_init_arch_info(target, cortex_a, pc->dap); } -static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) +static int cortex_r4_target_create(struct target *target) { struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index e17f23c1d3..ba9d83d79f 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -2916,7 +2916,7 @@ static int cortex_m_init_arch_info(struct target *target, return ERROR_OK; } -static int cortex_m_target_create(struct target *target, Jim_Interp *interp) +static int cortex_m_target_create(struct target *target) { struct adiv5_private_config *pc; diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 9b6f4756c9..dc85a21800 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -880,7 +880,7 @@ static void dsp563xx_invalidate_x_context(struct target *target, } } -static int dsp563xx_target_create(struct target *target, Jim_Interp *interp) +static int dsp563xx_target_create(struct target *target) { struct dsp563xx_common *dsp563xx = calloc(1, sizeof(struct dsp563xx_common)); diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index 3f9a6742c4..65efbae324 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -855,7 +855,7 @@ static int eonce_pc_store(struct target *target) return ERROR_OK; } -static int dsp5680xx_target_create(struct target *target, Jim_Interp *interp) +static int dsp5680xx_target_create(struct target *target) { struct dsp5680xx_common *dsp5680xx = calloc(1, sizeof(struct dsp5680xx_common)); diff --git a/src/target/esirisc.c b/src/target/esirisc.c index da40928da9..fac5dc72ee 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -1575,7 +1575,7 @@ static int esirisc_identify(struct target *target) return ERROR_OK; } -static int esirisc_target_create(struct target *target, Jim_Interp *interp) +static int esirisc_target_create(struct target *target) { struct jtag_tap *tap = target->tap; struct esirisc_common *esirisc; diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 4deb5e0709..399ba8e7cd 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -326,7 +326,7 @@ static const struct esp_semihost_ops esp32_semihost_ops = { .prepare = esp32_disable_wdts }; -static int esp32_target_create(struct target *target, Jim_Interp *interp) +static int esp32_target_create(struct target *target) { struct xtensa_debug_module_config esp32_dm_cfg = { .dbg_ops = &esp32_dbg_ops, diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index 4f3914f66a..b86e43e626 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -445,7 +445,7 @@ static const struct esp_semihost_ops esp32s2_semihost_ops = { .prepare = esp32s2_disable_wdts }; -static int esp32s2_target_create(struct target *target, Jim_Interp *interp) +static int esp32s2_target_create(struct target *target) { struct xtensa_debug_module_config esp32s2_dm_cfg = { .dbg_ops = &esp32s2_dbg_ops, diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 7507c11c24..82413f77fb 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -320,7 +320,7 @@ static const struct esp_semihost_ops esp32s3_semihost_ops = { .prepare = esp32s3_disable_wdts }; -static int esp32s3_target_create(struct target *target, Jim_Interp *interp) +static int esp32s3_target_create(struct target *target) { struct xtensa_debug_module_config esp32s3_dm_cfg = { .dbg_ops = &esp32s3_dbg_ops, diff --git a/src/target/fa526.c b/src/target/fa526.c index 38b7ab2e9d..d832d3e7d1 100644 --- a/src/target/fa526.c +++ b/src/target/fa526.c @@ -329,7 +329,7 @@ static int fa526_init_arch_info(struct target *target, return ERROR_OK; } -static int fa526_target_create(struct target *target, Jim_Interp *interp) +static int fa526_target_create(struct target *target) { struct arm920t_common *arm920t = calloc(1, sizeof(struct arm920t_common)); diff --git a/src/target/feroceon.c b/src/target/feroceon.c index 840ca1b62b..cf2c838b7d 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -622,7 +622,7 @@ static void feroceon_common_setup(struct target *target) arm7_9->wp1_used_default = -1; } -static int feroceon_target_create(struct target *target, Jim_Interp *interp) +static int feroceon_target_create(struct target *target) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); @@ -640,7 +640,7 @@ static int feroceon_target_create(struct target *target, Jim_Interp *interp) return ERROR_OK; } -static int dragonite_target_create(struct target *target, Jim_Interp *interp) +static int dragonite_target_create(struct target *target) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); diff --git a/src/target/hla_target.c b/src/target/hla_target.c index ef05df2027..983cd87394 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -187,8 +187,7 @@ static int adapter_init_target(struct command_context *cmd_ctx, return ERROR_OK; } -static int adapter_target_create(struct target *target, - Jim_Interp *interp) +static int adapter_target_create(struct target *target) { LOG_DEBUG("%s", __func__); struct adiv5_private_config *pc = target->private_config; diff --git a/src/target/ls1_sap.c b/src/target/ls1_sap.c index 692f4cc9e4..49335a8b9f 100644 --- a/src/target/ls1_sap.c +++ b/src/target/ls1_sap.c @@ -17,7 +17,7 @@ struct ls1_sap { struct jtag_tap *tap; }; -static int ls1_sap_target_create(struct target *target, Jim_Interp *interp) +static int ls1_sap_target_create(struct target *target) { struct ls1_sap *ls1_sap = calloc(1, sizeof(struct ls1_sap)); diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index fdc52c3071..c5618c9ccd 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -24,7 +24,7 @@ struct mem_ap { uint64_t ap_num; }; -static int mem_ap_target_create(struct target *target, Jim_Interp *interp) +static int mem_ap_target_create(struct target *target) { struct mem_ap *mem_ap; struct adiv5_private_config *pc; diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index dc74501086..4e27914a9d 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -1158,7 +1158,7 @@ static int mips_m4k_init_arch_info(struct target *target, return ERROR_OK; } -static int mips_m4k_target_create(struct target *target, Jim_Interp *interp) +static int mips_m4k_target_create(struct target *target) { struct mips_m4k_common *mips_m4k = calloc(1, sizeof(struct mips_m4k_common)); diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index 85e3779375..a181a154ee 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -1082,7 +1082,7 @@ static int mips_mips64_init_target(struct command_context *cmd_ctx, return mips64_build_reg_cache(target); } -static int mips_mips64_target_create(struct target *target, Jim_Interp *interp) +static int mips_mips64_target_create(struct target *target) { struct mips_mips64_common *mips_mips64; struct mips64_common *mips64; diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 4b9d3bca68..4aa2bd7347 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -1097,7 +1097,7 @@ static int or1k_init_target(struct command_context *cmd_ctx, return ERROR_OK; } -static int or1k_target_create(struct target *target, Jim_Interp *interp) +static int or1k_target_create(struct target *target) { if (!target->tap) return ERROR_FAIL; diff --git a/src/target/quark_d20xx.c b/src/target/quark_d20xx.c index 90cf6670ec..931f0dab7d 100644 --- a/src/target/quark_d20xx.c +++ b/src/target/quark_d20xx.c @@ -32,7 +32,7 @@ #include "lakemont.h" #include "x86_32_common.h" -static int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) +static int quark_d20xx_target_create(struct target *t) { struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common)); if (!x86_32) { diff --git a/src/target/quark_x10xx.c b/src/target/quark_x10xx.c index 0daa642b85..2abc32ab7b 100644 --- a/src/target/quark_x10xx.c +++ b/src/target/quark_x10xx.c @@ -40,7 +40,7 @@ #include "lakemont.h" #include "x86_32_common.h" -static int quark_x10xx_target_create(struct target *t, Jim_Interp *interp) +static int quark_x10xx_target_create(struct target *t) { struct x86_32_common *x86_32 = calloc(1, sizeof(*x86_32)); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 6a8577f5cb..11ef8f9b92 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -427,7 +427,7 @@ static struct target_type *get_target_type(struct target *target) } } -static int riscv_create_target(struct target *target, Jim_Interp *interp) +static int riscv_create_target(struct target *target) { LOG_DEBUG("riscv_create_target()"); target->arch_info = calloc(1, sizeof(struct riscv_info)); diff --git a/src/target/stm8.c b/src/target/stm8.c index 76482e8789..c80ea0eb20 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1106,8 +1106,7 @@ static int stm8_init_arch_info(struct target *target, return ERROR_OK; } -static int stm8_target_create(struct target *target, - Jim_Interp *interp) +static int stm8_target_create(struct target *target) { struct stm8_common *stm8 = calloc(1, sizeof(struct stm8_common)); diff --git a/src/target/target.c b/src/target/target.c index 99481622db..40c8d3ed36 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5865,7 +5865,7 @@ COMMAND_HANDLER(handle_target_create) } if (target->type->target_create) { - retval = (*target->type->target_create)(target, CMD_CTX->interp); + retval = (*target->type->target_create)(target); if (retval != ERROR_OK) { LOG_DEBUG("target_create failed"); free(target->cmd_name); diff --git a/src/target/target_type.h b/src/target/target_type.h index ce98cbad27..eddedbf34f 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -194,7 +194,7 @@ struct target_type { const struct command_registration *commands; /* called when target is created */ - int (*target_create)(struct target *target, Jim_Interp *interp); + int (*target_create)(struct target *target); /* called for various config parameters */ /* returns JIM_CONTINUE - if option not understood */ diff --git a/src/target/xscale.c b/src/target/xscale.c index 5cc790a311..84318a905f 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -3012,7 +3012,7 @@ static int xscale_init_arch_info(struct target *target, return ERROR_OK; } -static int xscale_target_create(struct target *target, Jim_Interp *interp) +static int xscale_target_create(struct target *target) { struct xscale_common *xscale; diff --git a/src/target/xtensa/xtensa_chip.c b/src/target/xtensa/xtensa_chip.c index ce6d35cabf..aab7ee37c5 100644 --- a/src/target/xtensa/xtensa_chip.c +++ b/src/target/xtensa/xtensa_chip.c @@ -81,7 +81,7 @@ static const struct xtensa_power_ops xtensa_chip_dm_pwr_ops = { .queue_reg_write = xtensa_dm_queue_pwr_reg_write }; -static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp) +static int xtensa_chip_target_create(struct target *target) { struct xtensa_debug_module_config xtensa_chip_dm_cfg = { .dbg_ops = &xtensa_chip_dm_dbg_ops, From 797dc7aba74152115898084dd00a50757b20c985 Mon Sep 17 00:00:00 2001 From: HAOUES Ahmed Date: Tue, 25 Mar 2025 14:29:30 +0100 Subject: [PATCH 10/55] flash/stm32l4x: support STM32C05/09x devices STM32C05/09x devices are similar to STM32C03/07x devices Change-Id: I77c803356c32f06699c14622828585609c90a136 Signed-off-by: HAOUES Ahmed Reviewed-on: https://review.openocd.org/c/openocd/+/8618 Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/flash/nor/stm32l4x.c | 34 ++++++++++++++++++++++++++++++++++ src/flash/nor/stm32l4x.h | 2 ++ 2 files changed, 36 insertions(+) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index fa57db8bbf..f16333201b 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -303,10 +303,18 @@ static const struct stm32l4_rev stm32c03xx_revs[] = { { 0x1000, "A" }, { 0x1001, "Z" }, }; +static const struct stm32l4_rev stm32c05xx_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32c071xx_revs[] = { { 0x1001, "Z" }, }; +static const struct stm32l4_rev stm32c09xx_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32g05_g06xx_revs[] = { { 0x1000, "A" }, }; @@ -450,6 +458,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x1FFF7000, .otp_size = 1024, }, + { + .id = DEVID_STM32C05XX, + .revs = stm32c05xx_revs, + .num_revs = ARRAY_SIZE(stm32c05xx_revs), + .device_str = "STM32C05xx", + .max_flash_size_kb = 64, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75A0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, { .id = DEVID_STM32C071XX, .revs = stm32c071xx_revs, @@ -462,6 +482,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x1FFF7000, .otp_size = 1024, }, + { + .id = DEVID_STM32C09XX, + .revs = stm32c09xx_revs, + .num_revs = ARRAY_SIZE(stm32c09xx_revs), + .device_str = "STM32C09xx", + .max_flash_size_kb = 256, + .flags = F_NONE, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75A0, + .otp_base = 0x1FFF7000, + .otp_size = 1024, + }, { .id = DEVID_STM32U53_U54XX, .revs = stm32u53_u54xx_revs, @@ -2021,7 +2053,9 @@ static int stm32l4_probe(struct flash_bank *bank) case DEVID_STM32L43_L44XX: case DEVID_STM32C01XX: case DEVID_STM32C03XX: + case DEVID_STM32C05XX: case DEVID_STM32C071XX: + case DEVID_STM32C09XX: case DEVID_STM32G05_G06XX: case DEVID_STM32G07_G08XX: case DEVID_STM32U031XX: diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 3199d4f6dc..07b3615a24 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -88,6 +88,8 @@ #define DEVID_STM32L47_L48XX 0x415 #define DEVID_STM32L43_L44XX 0x435 #define DEVID_STM32C01XX 0x443 +#define DEVID_STM32C05XX 0x44C +#define DEVID_STM32C09XX 0x44D #define DEVID_STM32C03XX 0x453 #define DEVID_STM32U53_U54XX 0x455 #define DEVID_STM32G05_G06XX 0x456 From 498e5590297e11a9c952d4210c6236fe8105241f Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Wed, 26 Mar 2025 23:05:39 +0800 Subject: [PATCH 11/55] tcl/target: Add RCPU support for Spacemit K1 Add support for the Real-Time CPU (RCPU) of K1, which is a 32-bit RISC-V N308 High-Efficiency Processor Core designed by Nuclei System Technology Co. Ltd. The JTAG interface can be configured to connect to either X60s or RCPU processors. To enable JTAG for RCPU, set TARGET to "rcpu". For example: openocd -c "set TARGET rcpu" -f interface/cmsis-dap.cfg \ -f target/spacemit-k1.cfg Change-Id: I9cd62fac332137afac17efa52702818de8f0b6f5 Signed-off-by: Junhui Liu Reviewed-on: https://review.openocd.org/c/openocd/+/8821 Reviewed-by: liangzhen Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/spacemit-k1.cfg | 50 ++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/tcl/target/spacemit-k1.cfg b/tcl/target/spacemit-k1.cfg index ef5d7833dd..e57d1adbc8 100644 --- a/tcl/target/spacemit-k1.cfg +++ b/tcl/target/spacemit-k1.cfg @@ -10,6 +10,21 @@ transport select jtag adapter speed 2000 +# Set TARGET to "rcpu" to enable JTAG for RCPU +if { [info exists TARGET] } { + set _TARGET $TARGET +} else { + set _TARGET x60 +} + +if { $_TARGET == "rcpu" } { + set CPUTAPID 0x10308A6D + set DRVAL 0xe +} else { + set CPUTAPID 0x10000E21 + set DRVAL 0xa +} + if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { @@ -23,44 +38,49 @@ if { [info exists CORES] } { } if { [info exists SECJTAG] } { - jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10000E21 + jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $CPUTAPID } else { jtag newtap pre unknown -irlen 1 -expected-id 0x00000000 -disable jtag configure pre.unknown -event tap-enable "" - jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10000E21 -disable + jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $CPUTAPID -disable jtag configure $_CHIPNAME.cpu -event tap-enable "" jtag newtap post unknown -irlen 9 -expected-id 0x08501C0D -ignore-version jtag configure post.unknown -event setup { - global _CHIPNAME + global _CHIPNAME DRVAL irscan post.unknown 0x98 - drscan post.unknown 16 0xa + drscan post.unknown 16 $DRVAL jtag tapenable pre.unknown jtag tapenable $_CHIPNAME.cpu } } -set _TARGETNAME $_CHIPNAME.cpu -set DBGBASE {0x0 0x400} -set _smp_command "target smp" +set _TARGETNAME $_CHIPNAME.cpu_$_TARGET + +if { $_TARGET == "rcpu" } { + target create $_TARGETNAME.0 riscv -chain-position $_CHIPNAME.cpu +} else { + set DBGBASE {0x0 0x400} + set _smp_command "target smp" -for { set _core 0 } { $_core < $_cores } { incr _core } { - target create $_TARGETNAME.$_core riscv -chain-position $_TARGETNAME \ - -coreid [expr {$_core % 4}] -dbgbase [lindex $DBGBASE [expr {$_core / 4}]] + for { set _core 0 } { $_core < $_cores } { incr _core } { + target create $_TARGETNAME.$_core riscv -chain-position $_CHIPNAME.cpu \ + -coreid [expr {$_core % 4}] -dbgbase [lindex $DBGBASE [expr {$_core / 4}]] - if { [expr {$_core % 4}] == 0 } { - $_TARGETNAME.$_core configure -rtos hwthread + if { [expr {$_core % 4}] == 0 } { + $_TARGETNAME.$_core configure -rtos hwthread + } + + set _smp_command "$_smp_command $_TARGETNAME.$_core" } - set _smp_command "$_smp_command $_TARGETNAME.$_core" + eval $_smp_command } -eval $_smp_command - set _SPEED 8000 $_TARGETNAME.0 configure -event examine-start { From 2aa0592e0fd90218ff55446ebb3a9233017e59f7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 6 Apr 2025 14:59:50 +0200 Subject: [PATCH 12/55] flash: stellaris: fix deprecated command The driver directly runs a TCL command that has been renamed with commit 4d99e77419e3 ("jtag/hla: Restructure commands"), while the original name has been deprecated. Update the TCL command to the new syntax. Change-Id: I2fc9ef9a209bae1d78951e253d54164b2ac00cdd Signed-off-by: Antonio Borneo Fixes: 4d99e77419e3 ("jtag/hla: Restructure commands") Reviewed-on: https://review.openocd.org/c/openocd/+/8832 Reviewed-by: zapb Tested-by: jenkins --- src/flash/nor/stellaris.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 1f53b2f35e..f7dcc6f0e3 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -1342,7 +1342,7 @@ COMMAND_HANDLER(stellaris_handle_recover_command) * cycle to recover. */ - Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", NULL, 0); + Jim_Eval_Named(CMD_CTX->interp, "catch { hla command \"debug unlock\" }", NULL, 0); if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) { retval = ERROR_OK; goto user_action; From ea775d49fc71253a95986eb5b1254b4861bdeb97 Mon Sep 17 00:00:00 2001 From: graham sanderson Date: Fri, 3 Nov 2023 15:55:41 -0500 Subject: [PATCH 13/55] flash/nor/rp2040: add RP2350 support TV: Extracted RP2040/2350 flash driver part only. Fixed style problems. Change-Id: I88a7d5aa0a239ae93d72bd5671686b19c6ca11ad Signed-off-by: Tomas Vanek Signed-off-by: graham sanderson Reviewed-on: https://review.openocd.org/c/openocd/+/8440 Tested-by: jenkins --- src/flash/nor/rp2040.c | 483 +++++++++++++++++++++++------------------ 1 file changed, 274 insertions(+), 209 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index b2ebd9c49e..c53b54754a 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -9,14 +9,19 @@ #include #include #include "spi.h" +#include /* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010 Your gdbinit should load the bootrom.elf if appropriate */ /* this is 'M' 'u', 1 (version) */ -#define BOOTROM_MAGIC 0x01754d +#define BOOTROM_RP2040_MAGIC 0x01754d +/* this is 'M' 'u', 2 (version) */ +#define BOOTROM_RP2350_MAGIC 0x02754d #define BOOTROM_MAGIC_ADDR 0x00000010 +#define RT_ARM_FUNC 0x1 + /* Call a ROM function via the debug trampoline Up to four arguments passed in r0...r3 as per ABI Function address is passed in r7 @@ -31,6 +36,48 @@ #define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') #define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') #define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') +#define FUNC_BOOTROM_STATE_RESET MAKE_TAG('S', 'R') + +// these form a bit set +#define BOOTROM_STATE_RESET_CURRENT_CORE 0x01 +#define BOOTROM_STATE_RESET_OTHER_CORE 0x02 +#define BOOTROM_STATE_RESET_GLOBAL_STATE 0x04 + +#define ACCESSCTRL_LOCK_OFFSET 0x40060000u +#define ACCESSCTRL_LOCK_DEBUG_BITS 0x00000008u +#define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u +#define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u + +// Calling bootrom functions requires the redundancy coprocessor (RCP) to be +// initialised. Usually this is done first thing by the bootrom, but the +// debugger may skip this, e.g. by resetting the cores and then running a +// NO_FLASH binary, or by reset-halting the cores before flash programming. +// +// The first case can be handled by a stub in the binary itself to initialise +// the RCP with dummy values if the bootrom has not already initialised it. +// (Note this case is only reachable via the debugger.) The second case +// requires the debugger itself to initialise the RCP, using this stub code: + +static const int rcp_init_code_bkpt_offset = 24; +static const uint16_t rcp_init_code[] = { + // Just enable the RCP which is fine if it already was (we assume no other + // co-processors are enabled at this point to save space) + 0x4806, // ldr r0, = PPB_BASE + M33_CPACR_OFFSET + 0xf45f, 0x4140, // movs r1, #M33_CPACR_CP7_BITS + 0x6001, // str r1, [r0] + // Only initialize canary seeds if they haven't been (as to do so twice is a fault) + 0xee30, 0xf710, // mrc p7, #1, r15, c0, c0, #0 + 0xd404, // bmi 1f + // Todo should we use something random here and pass it into the algorithm? + 0xec40, 0x0780, // mcrr p7, #8, r0, r0, c0 + 0xec40, 0x0781, // mcrr p7, #8, r0, r0, c1 + // Let other core know + 0xbf40, // sev + // 1: + 0xbe00, // bkpt (end of algorithm) + 0x0000, // pad + 0xed88, 0xe000 // PPB_BASE + M33_CPACR_OFFSET +}; struct rp2040_flash_bank { /* flag indicating successful flash probe */ @@ -46,33 +93,31 @@ struct rp2040_flash_bank { uint16_t jump_flash_range_program; uint16_t jump_flush_cache; uint16_t jump_enter_cmd_xip; - /* detected model of SPI flash */ - const struct flash_device *dev; + uint16_t jump_bootrom_reset_state; }; -/* guessed SPI flash description if autodetection disabled (same as win w25q16jv) */ -static const struct flash_device rp2040_default_spi_device = - FLASH_ID("autodetect disabled", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0, 0x100, 0x10000, 0); - static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol) { - uint32_t magic; + uint32_t magic, magic_addr; + bool found_rp2040_magic, found_rp2350_magic; + magic_addr = BOOTROM_MAGIC_ADDR; int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); if (err != ERROR_OK) return err; magic &= 0xffffff; /* ignore bootrom version */ - if (magic != BOOTROM_MAGIC) { - if (!((magic ^ BOOTROM_MAGIC)&0xffff)) - LOG_ERROR("Incorrect RP2040 BOOT ROM version"); - else - LOG_ERROR("RP2040 BOOT ROM not found"); + + found_rp2040_magic = magic == BOOTROM_RP2040_MAGIC; + found_rp2350_magic = magic == BOOTROM_RP2350_MAGIC; + + if (!(found_rp2040_magic || found_rp2350_magic)) { + LOG_ERROR("RP2040/RP2350 BOOT ROM not found"); return ERROR_FAIL; } /* dereference the table pointer */ uint16_t table_entry; - err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_entry); + err = target_read_u16(target, magic_addr + 4, &table_entry); if (err != ERROR_OK) return err; @@ -82,16 +127,29 @@ static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16 if (err != ERROR_OK) return err; if (entry_tag == tag) { - /* 16 bit symbol is next */ - return target_read_u16(target, table_entry + 2, symbol); + if (found_rp2350_magic) { + uint16_t flags; + /* flags are next */ + err = target_read_u16(target, table_entry + 4, &flags); + if (err != ERROR_OK) + return err; + // + if (flags & RT_ARM_FUNC) { + /* 16 bit symbol */ + return target_read_u16(target, table_entry + 2, symbol); + } + } else { + /* 16 bit symbol is next */ + return target_read_u16(target, table_entry + 2, symbol); + } } - table_entry += 4; + table_entry += found_rp2350_magic ? 6 : 4; } while (entry_tag); return ERROR_FAIL; } static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, - uint16_t func_offset, uint32_t argdata[], unsigned int n_args, unsigned int timeout_ms) + uint16_t func_offset, uint32_t argdata[], unsigned int n_args) { char *regnames[4] = { "r0", "r1", "r2", "r3" }; @@ -103,9 +161,10 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank } target_addr_t stacktop = priv->stack->address + priv->stack->size; - LOG_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args); + LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args); + LOG_DEBUG("Calling on core \"%s\"", target->cmd_name); - struct reg_param args[ARRAY_SIZE(regnames) + 2]; + struct reg_param args[ARRAY_SIZE(regnames) + 12]; struct armv7m_algorithm alg_info; for (unsigned int i = 0; i < n_args; ++i) { @@ -113,14 +172,36 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank buf_set_u32(args[i].value, 0, 32, argdata[i]); } /* Pass function pointer in r7 */ - init_reg_param(&args[n_args], "r7", 32, PARAM_OUT); - buf_set_u32(args[n_args].value, 0, 32, func_offset); - /* Setup stack */ - init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT); - buf_set_u32(args[n_args + 1].value, 0, 32, stacktop); - unsigned int n_reg_params = n_args + 2; /* User arguments + r7 + sp */ - - for (unsigned int i = 0; i < n_reg_params; ++i) + unsigned int extra_args = 0; + init_reg_param(&args[n_args + extra_args], "r7", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, func_offset); + /* Set stack pointer, have seen the caching get confused by the aliases of sp so + take the shotgun approach*/ + init_reg_param(&args[n_args + extra_args], "msp_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "msp_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "psp_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "psp_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "msp", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "psp", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + init_reg_param(&args[n_args + extra_args], "sp", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); + /* Clear stack pointer limits, as they may be above the algorithm stack */ + init_reg_param(&args[n_args + extra_args], "msplim_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + init_reg_param(&args[n_args + extra_args], "psplim_s", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + init_reg_param(&args[n_args + extra_args], "msplim_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + init_reg_param(&args[n_args + extra_args], "psplim_ns", 32, PARAM_OUT); + buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); + + for (unsigned int i = 0; i < n_args + extra_args; ++i) LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32)); /* Actually call the function */ @@ -129,82 +210,158 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank int err = target_run_algorithm( target, 0, NULL, /* No memory arguments */ - n_reg_params, args, /* User arguments + r7 + sp */ + n_args + extra_args, args, /* User arguments + r7 + SPs */ priv->jump_debug_trampoline, priv->jump_debug_trampoline_end, - timeout_ms, + 3000, /* 3s timeout */ &alg_info ); - - for (unsigned int i = 0; i < n_reg_params; ++i) + for (unsigned int i = 0; i < n_args + extra_args; ++i) destroy_reg_param(&args[i]); - if (err != ERROR_OK) - LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16, func_offset); - + LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset); return err; } -/* Finalize flash write/erase/read ID - * - flush cache - * - enters memory-mapped (XIP) mode to make flash data visible - * - deallocates target ROM func stack if previously allocated - */ -static int rp2040_finalize_stack_free(struct flash_bank *bank) +static int rp2350_init_core(struct target *target, struct rp2040_flash_bank *priv) { - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; + if (!priv->stack) { + LOG_ERROR("no stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - /* Always flush before returning to execute-in-place, to invalidate stale - * cache contents. The flush call also restores regular hardware-controlled - * chip select following a rp2040_flash_exit_xip(). - */ - LOG_DEBUG("Flushing flash cache after write behind"); - int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000); + struct armv7m_algorithm alg_info; + + // copy rcp_init code onto stack, as we don't actually need any stack during the call + if (priv->stack->size < sizeof(rcp_init_code)) { + LOG_ERROR("Working area too small for rcp_init"); + return ERROR_BUF_TOO_SMALL; + } + + // Attempt to reset ACCESSCTRL before running RCP init, in case Secure + // access to SRAM has been blocked. (Also ROM, QMI regs are needed later) + uint32_t accessctrl_lock_reg; + if (target_read_u32(target, ACCESSCTRL_LOCK_OFFSET, &accessctrl_lock_reg) != ERROR_OK) { + LOG_ERROR("Failed to read ACCESSCTRL lock register"); + // Failed to read an APB register which should always be readable from + // any security/privilege level. Something fundamental is wrong. E.g.: + // + // - The debugger is attempting to perform Secure bus accesses on a + // system where Secure debug has been disabled + // - clk_sys or busfabric clock are stopped (try doing a rescue reset) + return ERROR_FAIL; + } + if (accessctrl_lock_reg & ACCESSCTRL_LOCK_DEBUG_BITS) { + LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail.\n"); + } else { + LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET\n"); + target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); + } + + int err = target_write_memory(target, + priv->stack->address, + 1, + sizeof(rcp_init_code), + (const uint8_t *)rcp_init_code + ); if (err != ERROR_OK) { - LOG_ERROR("Failed to flush flash cache"); - /* Intentionally continue after error and try to setup xip anyway */ + LOG_ERROR("Failed to load rcp_init algorithm into RAM\n"); + return ERROR_FAIL; } - LOG_DEBUG("Configuring SSI for execute-in-place"); - err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000); - if (err != ERROR_OK) - LOG_ERROR("Failed to set SSI to XIP mode"); + LOG_DEBUG("Calling rcp_init core \"%s\" code at 0x%" PRIx16 "\n", target->cmd_name, (uint32_t)priv->stack->address); + + /* Actually call the function */ + alg_info.common_magic = ARMV7M_COMMON_MAGIC; + alg_info.core_mode = ARM_MODE_THREAD; + err = target_run_algorithm(target, + 0, NULL, /* No memory arguments */ + 0, NULL, /* No register arguments */ + priv->stack->address, + priv->stack->address + rcp_init_code_bkpt_offset, + 1000, /* 1s timeout */ + &alg_info + ); + if (err != ERROR_OK) { + LOG_ERROR("Failed to invoke rcp_init\n"); + return err; + } + + uint32_t reset_args[1] = { + BOOTROM_STATE_RESET_CURRENT_CORE + }; + if (!priv->jump_bootrom_reset_state) { + LOG_WARNING("RP2350 flash: no bootrom_reset_method\n"); + } else { + err = rp2040_call_rom_func(target, priv, priv->jump_bootrom_reset_state, reset_args, ARRAY_SIZE(reset_args)); + if (err != ERROR_OK) { + LOG_ERROR("RP2040 flash: failed to call reset core state"); + return err; + } + } - target_free_working_area(target, priv->stack); - priv->stack = NULL; return err; } -/* Prepare flash write/erase/read ID - * - allocates a stack for target ROM func - * - switches the SPI interface from memory-mapped mode to direct command mode - * Always pair with a call of rp2040_finalize_stack_free() - * after flash operation finishes or fails. - */ -static int rp2040_stack_grab_and_prep(struct flash_bank *bank) +static int setup_for_rom_call(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; - /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ - const int STACK_SIZE = 256; - int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack); + int err = ERROR_OK; + if (!priv->stack) { + /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ + const int STACK_SIZE = 256; + target_alloc_working_area(bank->target, STACK_SIZE, &priv->stack); + if (err != ERROR_OK) { + LOG_ERROR("Could not allocate stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + // Flash algorithms must run in Secure state + uint32_t dscsr; + (void)target_read_u32(target, DCB_DSCSR, &dscsr); + LOG_DEBUG("DSCSR: %08x\n", dscsr); + if (!(dscsr & DSCSR_CDS)) { + LOG_DEBUG("Setting Current Domain Secure in DSCSR\n"); + (void)target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); + (void)target_read_u32(target, DCB_DSCSR, &dscsr); + LOG_DEBUG("DSCSR*: %08x\n", dscsr); + } + + // hacky RP2350 check + if (target_to_arm(target)->arch == ARM_ARCH_V8M) { + err = rp2350_init_core(target, priv); + if (err != ERROR_OK) { + LOG_ERROR("RP2350 flash: failed to init core"); + return err; + } + } + return err; +} + +static int setup_for_raw_flash_cmd(struct flash_bank *bank) +{ + struct rp2040_flash_bank *priv = bank->driver_priv; + int err = setup_for_rom_call(bank); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0); if (err != ERROR_OK) { - LOG_ERROR("Could not allocate stack for flash programming code"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + LOG_ERROR("RP2040 flash: failed to setup for rom call"); + return err; } LOG_DEBUG("Connecting internal flash"); - err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0); if (err != ERROR_OK) { - LOG_ERROR("Failed to connect internal flash"); + LOG_ERROR("RP2040 flash: failed to connect internal flash"); return err; } LOG_DEBUG("Kicking flash out of XIP mode"); - err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_exit_xip, NULL, 0); if (err != ERROR_OK) { - LOG_ERROR("Failed to exit flash XIP mode"); + LOG_ERROR("RP2040 flash: failed to exit flash XIP mode"); return err; } @@ -217,27 +374,17 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; + struct working_area *bounce; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - struct working_area *bounce = NULL; - - int err = rp2040_stack_grab_and_prep(bank); + int err = setup_for_raw_flash_cmd(bank); if (err != ERROR_OK) - goto cleanup; - - unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize; - /* We try to allocate working area rounded down to device page size, - * al least 1 page, at most the write data size - */ - unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count); - err = target_alloc_working_area(target, chunk_size, &bounce); - if (err != ERROR_OK) { + return err; + + // Allocate as much memory as possible, rounded down to a whole number of flash pages + const unsigned int chunk_size = target_get_working_area_avail(target) & ~0xffu; + if (chunk_size == 0 || target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) { LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); - goto cleanup; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); @@ -255,8 +402,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui bounce->address, /* data */ write_size /* count */ }; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, - args, ARRAY_SIZE(args), 3000); + err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args)); if (err != ERROR_OK) { LOG_ERROR("Failed to invoke flash programming code on target"); break; @@ -266,40 +412,44 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui offset += write_size; count -= write_size; } - -cleanup: target_free_working_area(target, bounce); - rp2040_finalize_stack_free(bank); + if (err != ERROR_OK) + return err; + /* Flash is successfully programmed. We can now do a bit of poking to make the flash + contents visible to us via memory-mapped (XIP) interface in the 0x1... memory region */ + LOG_DEBUG("Flushing flash cache after write behind"); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0); + if (err != ERROR_OK) { + LOG_ERROR("RP2040 write: failed to flush flash cache"); + return err; + } + LOG_DEBUG("Configuring SSI for execute-in-place"); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_enter_cmd_xip, NULL, 0); + if (err != ERROR_OK) + LOG_ERROR("RP2040 write: failed to flush flash cache"); return err; } static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - uint32_t start_addr = bank->sectors[first].offset; uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr); - int err = rp2040_stack_grab_and_prep(bank); + int err = setup_for_raw_flash_cmd(bank); if (err != ERROR_OK) - goto cleanup; + return err; LOG_DEBUG("Remote call flash_range_erase"); uint32_t args[4] = { bank->sectors[first].offset, /* addr */ bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */ - priv->dev->sectorsize, /* block_size */ - priv->dev->erase_cmd /* block_cmd */ + 65536, /* block_size */ + 0xd8 /* block_cmd */ }; /* @@ -309,15 +459,10 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and - an optional larger "block" (size and command provided in args). + an optional larger "block" (size and command provided in args). OpenOCD's spi.c only uses "block" sizes. */ - unsigned int timeout_ms = 2000 * (last - first) + 1000; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase, - args, ARRAY_SIZE(args), timeout_ms); - -cleanup: - rp2040_finalize_stack_free(bank); + err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); return err; } @@ -325,67 +470,11 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig /* ----------------------------------------------------------------------------- Driver probing etc */ -static int rp2040_ssel_active(struct target *target, bool active) -{ - const target_addr_t qspi_ctrl_addr = 0x4001800c; - const uint32_t qspi_ctrl_outover_low = 2UL << 8; - const uint32_t qspi_ctrl_outover_high = 3UL << 8; - uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high; - uint32_t val; - - int err = target_read_u32(target, qspi_ctrl_addr, &val); - if (err != ERROR_OK) - return err; - - val = (val & ~qspi_ctrl_outover_high) | state; - - err = target_write_u32(target, qspi_ctrl_addr, val); - if (err != ERROR_OK) - return err; - - return ERROR_OK; -} - -static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid) -{ - uint32_t device_id = 0; - const target_addr_t ssi_dr0 = 0x18000060; - - int err = rp2040_ssel_active(target, true); - - /* write RDID request into SPI peripheral's FIFO */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) - err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID); - - /* by this time, there is a receive FIFO entry for every write */ - for (int count = 0; (count < 4) && (err == ERROR_OK); count++) { - uint32_t status; - err = target_read_u32(target, ssi_dr0, &status); - - device_id >>= 8; - device_id |= (status & 0xFF) << 24; - } - - if (err == ERROR_OK) - *devid = device_id >> 8; - - int err2 = rp2040_ssel_active(target, false); - if (err2 != ERROR_OK) - LOG_ERROR("SSEL inactive failed"); - - return err; -} - static int rp2040_flash_probe(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline); if (err != ERROR_OK) { LOG_ERROR("Debug trampoline not found in RP2040 ROM."); @@ -417,6 +506,7 @@ static int rp2040_flash_probe(struct flash_bank *bank) LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM."); return err; } + LOG_WARNING("GOT FLASH ERASE AT %08x\n", (int)priv->jump_flash_range_erase); err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program); if (err != ERROR_OK) { @@ -436,50 +526,25 @@ static int rp2040_flash_probe(struct flash_bank *bank) return err; } - if (bank->size) { - /* size overridden, suppress reading SPI flash ID */ - priv->dev = &rp2040_default_spi_device; - LOG_DEBUG("SPI flash autodetection disabled, using configured size"); - - } else { - /* zero bank size in cfg, read SPI flash ID and autodetect */ - err = rp2040_stack_grab_and_prep(bank); - - uint32_t device_id = 0; - if (err == ERROR_OK) - err = rp2040_spi_read_flash_id(target, &device_id); - - rp2040_finalize_stack_free(bank); - - if (err != ERROR_OK) - return err; - - /* search for a SPI flash Device ID match */ - priv->dev = NULL; - for (const struct flash_device *p = flash_devices; p->name ; p++) - if (p->device_id == device_id) { - priv->dev = p; - break; - } - - if (!priv->dev) { - LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id); - return ERROR_FAIL; - } - LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")", - priv->dev->name, priv->dev->device_id); - - bank->size = priv->dev->size_in_bytes; + err = rp2040_lookup_symbol(target, FUNC_BOOTROM_STATE_RESET, &priv->jump_bootrom_reset_state); + if (err != ERROR_OK) { + priv->jump_bootrom_reset_state = 0; +// LOG_ERROR("Function FUNC_BOOTROM_STATE_RESET not found in RP2040 ROM."); +// return err; } /* the Boot ROM flash_range_program() routine requires page alignment */ - bank->write_start_alignment = priv->dev->pagesize; - bank->write_end_alignment = priv->dev->pagesize; + bank->write_start_alignment = 256; + bank->write_end_alignment = 256; + + // Max size -- up to two devices (two chip selects) in adjacent 24-bit address windows + bank->size = 32 * 1024 * 1024; + + bank->num_sectors = bank->size / 4096; - bank->num_sectors = bank->size / priv->dev->sectorsize; - LOG_INFO("RP2040 B0 Flash Probe: %" PRIu32 " bytes @" TARGET_ADDR_FMT ", in %u sectors\n", + LOG_INFO("RP2040 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n", bank->size, bank->base, bank->num_sectors); - bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors); + bank->sectors = alloc_block_array(0, 4096, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; From 1ed49addc5030f6df414657ead6bfc70a0deabd9 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Wed, 14 Jul 2021 16:36:13 +0100 Subject: [PATCH 14/55] flash/nor/rp2040: Add RISC-V ROM algorithm batch call support And add support for A1 ROM table. TV: cortex_m smp change removed. Fixed style problems. 'uint' replaced by unsigned int Change-Id: Iff2710fa0734dc7074d8d490d8fae43dc27c0c2a Signed-off-by: Tomas Vanek Signed-off-by: Luke Wren Reviewed-on: https://review.openocd.org/c/openocd/+/8441 Tested-by: jenkins --- src/flash/nor/rp2040.c | 876 ++++++++++++++++++++++++++++------------- 1 file changed, 599 insertions(+), 277 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index c53b54754a..1e582b433a 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -11,32 +11,27 @@ #include "spi.h" #include -/* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010 - Your gdbinit should load the bootrom.elf if appropriate */ - /* this is 'M' 'u', 1 (version) */ #define BOOTROM_RP2040_MAGIC 0x01754d /* this is 'M' 'u', 2 (version) */ #define BOOTROM_RP2350_MAGIC 0x02754d #define BOOTROM_MAGIC_ADDR 0x00000010 -#define RT_ARM_FUNC 0x1 - -/* Call a ROM function via the debug trampoline - Up to four arguments passed in r0...r3 as per ABI - Function address is passed in r7 - the trampoline is needed because OpenOCD "algorithm" code insists on sw breakpoints. */ - #define MAKE_TAG(a, b) (((b)<<8) | a) -#define FUNC_DEBUG_TRAMPOLINE MAKE_TAG('D', 'T') -#define FUNC_DEBUG_TRAMPOLINE_END MAKE_TAG('D', 'E') -#define FUNC_FLASH_EXIT_XIP MAKE_TAG('E', 'X') -#define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F') -#define FUNC_FLASH_RANGE_ERASE MAKE_TAG('R', 'E') -#define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') -#define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') -#define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') -#define FUNC_BOOTROM_STATE_RESET MAKE_TAG('S', 'R') +#define FUNC_FLASH_EXIT_XIP MAKE_TAG('E', 'X') +#define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F') +#define FUNC_FLASH_RANGE_ERASE MAKE_TAG('R', 'E') +#define FUNC_FLASH_RANGE_PROGRAM MAKE_TAG('R', 'P') +#define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') +#define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') +#define FUNC_BOOTROM_STATE_RESET MAKE_TAG('S', 'R') +#define FUNC_FLASH_RESET_ADDRESS_TRANS MAKE_TAG('R', 'A') + +/* ROM table flags for RP2350 A1 ROM onwards */ +#define RT_FLAG_FUNC_RISCV 0x01 +#define RT_FLAG_FUNC_ARM_SEC 0x04 +#define RT_FLAG_FUNC_ARM_NONSEC 0x10 +#define RT_FLAG_DATA 0x40 // these form a bit set #define BOOTROM_STATE_RESET_CURRENT_CORE 0x01 @@ -48,10 +43,14 @@ #define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u #define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u -// Calling bootrom functions requires the redundancy coprocessor (RCP) to be -// initialised. Usually this is done first thing by the bootrom, but the -// debugger may skip this, e.g. by resetting the cores and then running a -// NO_FLASH binary, or by reset-halting the cores before flash programming. +#define RP2XXX_MAX_ALGO_STACK_USAGE 1024 +#define RP2XXX_MAX_RAM_ALGO_SIZE 1024 + +// Calling bootrom functions on Arm RP2350 requires the redundancy +// coprocessor (RCP) to be initialised. Usually this is done first thing by +// the bootrom, but the debugger may skip this, e.g. by resetting the cores +// and then running a NO_FLASH binary, or by reset-halting the cores before +// flash programming. // // The first case can be handled by a stub in the binary itself to initialise // the RCP with dummy values if the bootrom has not already initialised it. @@ -59,186 +58,500 @@ // requires the debugger itself to initialise the RCP, using this stub code: static const int rcp_init_code_bkpt_offset = 24; -static const uint16_t rcp_init_code[] = { +static const uint8_t rcp_init_code[] = { // Just enable the RCP which is fine if it already was (we assume no other // co-processors are enabled at this point to save space) - 0x4806, // ldr r0, = PPB_BASE + M33_CPACR_OFFSET - 0xf45f, 0x4140, // movs r1, #M33_CPACR_CP7_BITS - 0x6001, // str r1, [r0] + 0x06, 0x48, // ldr r0, = PPB_BASE + M33_CPACR_OFFSET + 0x5f, 0xf4, 0x40, 0x41, // movs r1, #M33_CPACR_CP7_BITS + 0x01, 0x60, // str r1, [r0] // Only initialize canary seeds if they haven't been (as to do so twice is a fault) - 0xee30, 0xf710, // mrc p7, #1, r15, c0, c0, #0 - 0xd404, // bmi 1f + 0x30, 0xee, 0x10, 0xf7, // mrc p7, #1, r15, c0, c0, #0 + 0x04, 0xd4, // bmi 1f // Todo should we use something random here and pass it into the algorithm? - 0xec40, 0x0780, // mcrr p7, #8, r0, r0, c0 - 0xec40, 0x0781, // mcrr p7, #8, r0, r0, c1 + 0x40, 0xec, 0x80, 0x07, // mcrr p7, #8, r0, r0, c0 + 0x40, 0xec, 0x81, 0x07, // mcrr p7, #8, r0, r0, c1 // Let other core know - 0xbf40, // sev + 0x40, 0xbf, // sev // 1: - 0xbe00, // bkpt (end of algorithm) - 0x0000, // pad - 0xed88, 0xe000 // PPB_BASE + M33_CPACR_OFFSET + 0x00, 0xbe, // bkpt (end of algorithm) + 0x00, 0x00, // pad + 0x88, 0xed, 0x00, 0xe0 // PPB_BASE + M33_CPACR_OFFSET }; +// An algorithm stub that can be concatenated with a null-terminated list of +// (PC, SP, r0-r3) records to perform a batch of ROM calls under a single +// OpenOCD algorithm call, to save on algorithm overhead: +#define ROM_CALL_BATCH_ALGO_SIZE_BYTES 32 +static const int rp2xxx_rom_call_batch_algo_bkpt_offset = ROM_CALL_BATCH_ALGO_SIZE_BYTES - 2; +static const uint8_t rp2xxx_rom_call_batch_algo_armv6m[ROM_CALL_BATCH_ALGO_SIZE_BYTES] = { +// <_start>: + 0x07, 0xa7, // add r7, pc, #28 ; (adr r7, 20 <_args>) +// <_do_next>: + 0x10, 0xcf, // ldmia r7!, {r4} + 0x00, 0x2c, // cmp r4, #0 + 0x0a, 0xd0, // beq.n 1e <_done> + 0x20, 0xcf, // ldmia r7!, {r5} + 0xad, 0x46, // mov sp, r5 + 0x0f, 0xcf, // ldmia r7!, {r0, r1, r2, r3} + 0xa0, 0x47, // blx r4 + 0xf7, 0xe7, // b.n 2 <_do_next> + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop + 0xc0, 0x46, // nop +// <_done>: + 0x00, 0xbe, // bkpt 0x0000 +// <_args>: +}; + +// The same as rom_call_batch_algo_armv6m, but clearing stack limits before setting stack: +static const uint8_t rp2xxx_rom_call_batch_algo_armv8m[ROM_CALL_BATCH_ALGO_SIZE_BYTES] = { +// <_start>: + 0x07, 0xa7, // add r7, pc, #28 ; (adr r7, 20 <_args>) + 0x00, 0x20, // movs r0, #0 + 0x80, 0xf3, 0x0a, 0x88, // msr MSPLIM, r0 + 0x80, 0xf3, 0x0b, 0x88, // msr PSPLIM, r0 +// <_do_next>: + 0x10, 0xcf, // ldmia r7!, {r4} + 0x00, 0x2c, // cmp r4, #0 + 0x05, 0xd0, // beq.n 1e <_done> + 0x20, 0xcf, // ldmia r7!, {r5} + 0xad, 0x46, // mov sp, r5 + 0x0f, 0xcf, // ldmia r7!, {r0, r1, r2, r3} + 0xa0, 0x47, // blx r4 + 0xf7, 0xe7, // b.n c <_do_next> + 0xc0, 0x46, // nop +// <_done>: + 0x00, 0xbe, // bkpt 0x0000 +// <_args>: +}; + +// The same as rom_call_batch_algo_armv6m, but placing arguments in a0-a3 on RISC-V: +static const uint8_t rp2xxx_rom_call_batch_algo_riscv[ROM_CALL_BATCH_ALGO_SIZE_BYTES] = { +// <_start>: + 0x97, 0x04, 0x00, 0x00, // auipc s1,0 + 0x93, 0x84, 0x04, 0x02, // add s1,s1,32 # 20 <_args> +// <_do_next>: + 0x98, 0x40, // lw a4,0(s1) + 0x11, 0xcb, // beqz a4,1e <_done> + 0x03, 0xa1, 0x44, 0x00, // lw sp,4(s1) + 0x88, 0x44, // lw a0,8(s1) + 0xcc, 0x44, // lw a1,12(s1) + 0x90, 0x48, // lw a2,16(s1) + 0xd4, 0x48, // lw a3,20(s1) + 0xe1, 0x04, // add s1,s1,24 + 0x02, 0x97, // jalr a4 + 0xf5, 0xb7, // j 8 <_do_next> +// <_done>: + 0x02, 0x90, // ebreak +// <_args>: +}; + +typedef struct rp2xxx_rom_call_batch_record { + uint32_t pc; + uint32_t sp; + uint32_t args[4]; +} rp2xxx_rom_call_batch_record_t; + struct rp2040_flash_bank { /* flag indicating successful flash probe */ bool probed; /* stack used by Boot ROM calls */ struct working_area *stack; + /* static code scratchpad used for RAM algorithms -- allocated in advance + so that higher-level calls can just grab all remaining workarea: */ + struct working_area *ram_algo_space; /* function jump table populated by rp2040_flash_probe() */ - uint16_t jump_debug_trampoline; - uint16_t jump_debug_trampoline_end; uint16_t jump_flash_exit_xip; uint16_t jump_connect_internal_flash; uint16_t jump_flash_range_erase; uint16_t jump_flash_range_program; uint16_t jump_flush_cache; + uint16_t jump_flash_reset_address_trans; uint16_t jump_enter_cmd_xip; uint16_t jump_bootrom_reset_state; }; -static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol) +#ifndef LOG_ROM_SYMBOL_DEBUG +#define LOG_ROM_SYMBOL_DEBUG LOG_DEBUG +#endif + +static int rp2040_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) { - uint32_t magic, magic_addr; - bool found_rp2040_magic, found_rp2350_magic; - magic_addr = BOOTROM_MAGIC_ADDR; - int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); + LOG_ROM_SYMBOL_DEBUG("Looking up ROM symbol '%c%c' in RP2040 table", tag & 0xff, (tag >> 8) & 0xff); + if (flags != RT_FLAG_FUNC_ARM_SEC && flags != RT_FLAG_DATA) { + /* Note RT flags do not exist on RP2040, so just sanity check that we + are asked for a type of thing that actually exists in the ROM table */ + LOG_ERROR("Only data and Secure Arm functions can be looked up in RP2040 ROM table"); + return ERROR_FAIL; + } + + uint16_t ptr_to_entry; + const unsigned int offset_magic_to_table_ptr = flags == RT_FLAG_DATA ? 6 : 4; + int err = target_read_u16(target, BOOTROM_MAGIC_ADDR + offset_magic_to_table_ptr, &ptr_to_entry); if (err != ERROR_OK) return err; - magic &= 0xffffff; /* ignore bootrom version */ - - found_rp2040_magic = magic == BOOTROM_RP2040_MAGIC; - found_rp2350_magic = magic == BOOTROM_RP2350_MAGIC; + uint16_t entry_tag; + do { + err = target_read_u16(target, ptr_to_entry, &entry_tag); + if (err != ERROR_OK) + return err; + if (entry_tag == tag) { + /* 16 bit symbol is next */ + err = target_read_u16(target, ptr_to_entry + 2, symbol_out); + if (err != ERROR_OK) + return err; + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); + return ERROR_OK; + } + ptr_to_entry += 4; + } while (entry_tag); + *symbol_out = 0; + return ERROR_FAIL; +} - if (!(found_rp2040_magic || found_rp2350_magic)) { - LOG_ERROR("RP2040/RP2350 BOOT ROM not found"); - return ERROR_FAIL; +static int rp2350_a0_lookup_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) +{ + LOG_ROM_SYMBOL_DEBUG("Looking up ROM symbol '%c%c' in RP2350 A0 table", tag & 0xff, (tag >> 8) & 0xff); + + /* RP2350 A0 table format is the same as RP2040 except with 16 bits of + flags after each 16-bit pointer. We ignore the flags, as each symbol + only has one datum associated with it. */ + + uint32_t magic_ptr = BOOTROM_MAGIC_ADDR; + if (flags == RT_FLAG_FUNC_RISCV) { + /* RP2350 A0 used split function tables for Arm/RISC-V -- not used on + any other device or any other version of this device. There is a + well-known RISC-V table at the top of ROM, matching the well-known + Arm table at the bottom of ROM. */ + magic_ptr = 0x7decu; + } else if (flags != RT_FLAG_FUNC_ARM_SEC) { + LOG_WARNING("Ignoring non-default flags for RP2350 A0 lookup, hope you like Secure Arm functions"); } - /* dereference the table pointer */ - uint16_t table_entry; - err = target_read_u16(target, magic_addr + 4, &table_entry); + uint16_t ptr_to_entry; + const unsigned int offset_magic_to_table_ptr = 4; + int err = target_read_u16(target, magic_ptr + offset_magic_to_table_ptr, &ptr_to_entry); if (err != ERROR_OK) return err; uint16_t entry_tag; do { - err = target_read_u16(target, table_entry, &entry_tag); + err = target_read_u16(target, ptr_to_entry, &entry_tag); if (err != ERROR_OK) return err; if (entry_tag == tag) { - if (found_rp2350_magic) { - uint16_t flags; - /* flags are next */ - err = target_read_u16(target, table_entry + 4, &flags); - if (err != ERROR_OK) - return err; - // - if (flags & RT_ARM_FUNC) { - /* 16 bit symbol */ - return target_read_u16(target, table_entry + 2, symbol); - } - } else { - /* 16 bit symbol is next */ - return target_read_u16(target, table_entry + 2, symbol); - } + err = target_read_u16(target, ptr_to_entry + 2, symbol_out); + if (err != ERROR_OK) + return err; + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); + return ERROR_OK; } - table_entry += found_rp2350_magic ? 6 : 4; + ptr_to_entry += 6; } while (entry_tag); + *symbol_out = 0; return ERROR_FAIL; } -static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, - uint16_t func_offset, uint32_t argdata[], unsigned int n_args) +static int rp2350_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) { - char *regnames[4] = { "r0", "r1", "r2", "r3" }; + LOG_ROM_SYMBOL_DEBUG("Looking up ROM symbol '%c%c' in RP2350 A1 table", tag & 0xff, (tag >> 8) & 0xff); + uint32_t ptr_to_entry; + int err = target_read_u32(target, BOOTROM_MAGIC_ADDR + 4, &ptr_to_entry); + if (err != ERROR_OK) + return err; - assert(n_args <= ARRAY_SIZE(regnames)); /* only allow register arguments */ + /* On RP2350 A1, Each entry has a flag bitmap identifying the type of its + contents. The entry contains one halfword of data for each set flag + bit. There may be both Arm and RISC-V entries under the same tag, or + separate Arm Secure/NonSecure entries (or all three, why not). */ - if (!priv->stack) { - LOG_ERROR("no stack for flash programming code"); + while (true) { + uint16_t entry_tag, entry_flags; + + err = target_read_u16(target, ptr_to_entry, &entry_tag); + if (err != ERROR_OK) + return err; + if (entry_tag == 0) { + *symbol_out = 0; + return ERROR_FAIL; + } + ptr_to_entry += 2; + + err = target_read_u16(target, ptr_to_entry, &entry_flags); + if (err != ERROR_OK) + return err; + ptr_to_entry += 2; + + uint16_t matching_flags = flags & entry_flags; + + if (tag == entry_tag && matching_flags != 0) { + /* This is our entry, seek to the correct data item and return it. */ + bool is_riscv_func = matching_flags & RT_FLAG_FUNC_RISCV; + while (!(matching_flags & 1)) { + if (entry_flags & 1) + ptr_to_entry += 2; + + matching_flags >>= 1; + entry_flags >>= 1; + } + if (is_riscv_func) { + /* For RISC-V, the table entry itself is the entry point -- trick + to make shared function implementations smaller */ + *symbol_out = ptr_to_entry; + return ERROR_OK; + } + err = target_read_u16(target, ptr_to_entry, symbol_out); + if (err != ERROR_OK) + return err; + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); + return ERROR_OK; + } + /* Skip past this entry */ + while (entry_flags) { + if (entry_flags & 1) + ptr_to_entry += 2; + + entry_flags >>= 1; + } + } +} + +static int rp2xxx_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) +{ + uint32_t magic; + int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic); + if (err != ERROR_OK) + return err; + + /* Ignore version */ + magic &= 0xffffff; + + if (magic == BOOTROM_RP2350_MAGIC) { + /* Distinguish old-style RP2350 ROM table (A0, and earlier A1 builds) + based on position of table -- a high address means it is shared with + RISC-V, i.e. new-style. */ + uint32_t table_ptr; + err = target_read_u32(target, BOOTROM_MAGIC_ADDR + 4, &table_ptr); + if (err != ERROR_OK) + return err; + if (table_ptr < 0x7c00) + return rp2350_a0_lookup_symbol(target, tag, flags, symbol_out); + else + return rp2350_lookup_rom_symbol(target, tag, flags, symbol_out); + + } else if (magic == BOOTROM_RP2040_MAGIC) { + return rp2040_lookup_rom_symbol(target, tag, flags, symbol_out); + } + LOG_ERROR("RP2040/RP2350 BOOT ROM not found"); + return ERROR_FAIL; +} + +static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2040_flash_bank *priv) +{ + const uint16_t symtype_func = is_arm(target_to_arm(target)) + ? RT_FLAG_FUNC_ARM_SEC : RT_FLAG_FUNC_RISCV; + int err; + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_EXIT_XIP, + symtype_func, &priv->jump_flash_exit_xip); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2xxx ROM."); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, + symtype_func, &priv->jump_connect_internal_flash); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2xxx ROM."); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RANGE_ERASE, symtype_func, &priv->jump_flash_range_erase); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2xxx ROM."); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RANGE_PROGRAM, symtype_func, &priv->jump_flash_range_program); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2xxx ROM."); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_FLUSH_CACHE, symtype_func, &priv->jump_flush_cache); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2xxx ROM."); + return err; + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, symtype_func, &priv->jump_enter_cmd_xip); + if (err != ERROR_OK) { + LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2xxx ROM."); + return err; + } + + // From this point are optional functions which do not exist on e.g. RP2040 + // or pre-production RP2350 ROM versions: + + err = rp2xxx_lookup_rom_symbol(target, FUNC_BOOTROM_STATE_RESET, symtype_func, &priv->jump_bootrom_reset_state); + if (err != ERROR_OK) { + priv->jump_bootrom_reset_state = 0; + LOG_WARNING("Function FUNC_BOOTROM_STATE_RESET not found in RP2xxx ROM. (probably an RP2040 or an RP2350 A0)"); + } + + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RESET_ADDRESS_TRANS, + symtype_func, &priv->jump_flash_reset_address_trans); + if (err != ERROR_OK) { + priv->jump_flash_reset_address_trans = 0; + LOG_WARNING("Function FUNC_FLASH_RESET_ADDRESS_TRANS not found in RP2xxx ROM. (probably an RP2040 or an RP2350 A0)"); + } + return ERROR_OK; +} + +// Call a list of PC + SP + r0-r3 function call tuples with a single OpenOCD +// algorithm invocation, to amortise the algorithm overhead over multiple calls: +static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2040_flash_bank *priv, + rp2xxx_rom_call_batch_record_t *calls, unsigned int n_calls) +{ + // Note +1 is for the null terminator + unsigned int batch_words = 1 + (ROM_CALL_BATCH_ALGO_SIZE_BYTES + + n_calls * sizeof(rp2xxx_rom_call_batch_record_t) + ) / sizeof(uint32_t); + + if (!priv->ram_algo_space) { + LOG_ERROR("No RAM code space allocated for ROM call"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - target_addr_t stacktop = priv->stack->address + priv->stack->size; + if (priv->ram_algo_space->size < batch_words * sizeof(uint32_t)) { + LOG_ERROR("RAM code space too small for call batch size of %u\n", n_calls); + return ERROR_BUF_TOO_SMALL; + } - LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args); + LOG_DEBUG("Calling batch of %u ROM functions:", n_calls); + for (unsigned int i = 0; i < n_calls; ++i) { + LOG_DEBUG(" func @ %" PRIx32, calls[i].pc); + LOG_DEBUG(" sp = %" PRIx32, calls[i].sp); + for (int j = 0; j < 4; ++j) + LOG_DEBUG(" a%d = %" PRIx32, j, calls[i].args[j]); + } LOG_DEBUG("Calling on core \"%s\"", target->cmd_name); - struct reg_param args[ARRAY_SIZE(regnames) + 12]; - struct armv7m_algorithm alg_info; + if (n_calls <= 0) { + LOG_DEBUG("Returning early from call of 0 ROM functions"); + return ERROR_OK; + } - for (unsigned int i = 0; i < n_args; ++i) { - init_reg_param(&args[i], regnames[i], 32, PARAM_OUT); - buf_set_u32(args[i].value, 0, 32, argdata[i]); - } - /* Pass function pointer in r7 */ - unsigned int extra_args = 0; - init_reg_param(&args[n_args + extra_args], "r7", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, func_offset); - /* Set stack pointer, have seen the caching get confused by the aliases of sp so - take the shotgun approach*/ - init_reg_param(&args[n_args + extra_args], "msp_s", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); - init_reg_param(&args[n_args + extra_args], "msp_ns", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); - init_reg_param(&args[n_args + extra_args], "psp_s", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); - init_reg_param(&args[n_args + extra_args], "psp_ns", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); - init_reg_param(&args[n_args + extra_args], "msp", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); - init_reg_param(&args[n_args + extra_args], "psp", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); - init_reg_param(&args[n_args + extra_args], "sp", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, stacktop); - /* Clear stack pointer limits, as they may be above the algorithm stack */ - init_reg_param(&args[n_args + extra_args], "msplim_s", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); - init_reg_param(&args[n_args + extra_args], "psplim_s", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); - init_reg_param(&args[n_args + extra_args], "msplim_ns", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); - init_reg_param(&args[n_args + extra_args], "psplim_ns", 32, PARAM_OUT); - buf_set_u32(args[n_args + extra_args++].value, 0, 32, 0); - - for (unsigned int i = 0; i < n_args + extra_args; ++i) - LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32)); + const uint8_t *algo_code; + if (is_arm(target_to_arm(target))) { + if (target_to_arm(target)->arch == ARM_ARCH_V8M) { + LOG_DEBUG("Using algo: rp2xxx_rom_call_batch_algo_armv8m"); + algo_code = rp2xxx_rom_call_batch_algo_armv8m; + } else { + LOG_DEBUG("Using algo: rp2xxx_rom_call_batch_algo_armv6m"); + algo_code = rp2xxx_rom_call_batch_algo_armv6m; + } + } else { + LOG_DEBUG("Using algo: rp2xxx_rom_call_batch_algo_riscv"); + algo_code = rp2xxx_rom_call_batch_algo_riscv; + } - /* Actually call the function */ - alg_info.common_magic = ARMV7M_COMMON_MAGIC; - alg_info.core_mode = ARM_MODE_THREAD; - int err = target_run_algorithm( - target, - 0, NULL, /* No memory arguments */ - n_args + extra_args, args, /* User arguments + r7 + SPs */ - priv->jump_debug_trampoline, priv->jump_debug_trampoline_end, - 3000, /* 3s timeout */ - &alg_info + int err = target_write_buffer(target, + priv->ram_algo_space->address, + ROM_CALL_BATCH_ALGO_SIZE_BYTES, + algo_code ); - for (unsigned int i = 0; i < n_args + extra_args; ++i) - destroy_reg_param(&args[i]); - if (err != ERROR_OK) - LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset); - return err; + if (err != ERROR_OK) { + LOG_ERROR("Failed to write ROM batch algorithm to RAM code space\n"); + return err; + } + err = target_write_buffer(target, + priv->ram_algo_space->address + ROM_CALL_BATCH_ALGO_SIZE_BYTES, + n_calls * sizeof(rp2xxx_rom_call_batch_record_t), + (const uint8_t *)calls + ); + if (err != ERROR_OK) { + LOG_ERROR("Failed to write ROM batch records to RAM code space\n"); + return err; + } + err = target_write_u32(target, + priv->ram_algo_space->address + (batch_words - 1) * sizeof(uint32_t), + 0 + ); + if (err != ERROR_OK) { + LOG_ERROR("Failed to write null terminator for ROM batch records\n"); + return err; + } + + // Call into the ROM batch algorithm -- this will in turn call each ROM + // call specified by the batch records. + target_addr_t algo_start_addr = priv->ram_algo_space->address; + target_addr_t algo_end_addr = priv->ram_algo_space->address + rp2xxx_rom_call_batch_algo_bkpt_offset; + unsigned int algo_timeout_ms = 3000; + if (is_arm(target_to_arm(target))) { + struct armv7m_algorithm alg_info; + alg_info.common_magic = ARMV7M_COMMON_MAGIC; + alg_info.core_mode = ARM_MODE_THREAD; + err = target_run_algorithm(target, + 0, NULL, /* No memory arguments */ + 0, NULL, /* No register arguments */ + algo_start_addr, algo_end_addr, + algo_timeout_ms, + &alg_info + ); + } else { + // Presumed RISC-V -- there is no RISCV_COMMON_MAGIC on older OpenOCD + err = target_run_algorithm(target, + 0, NULL, /* No memory arguments */ + 0, NULL, /* No register arguments */ + algo_start_addr, algo_end_addr, + algo_timeout_ms, + NULL /* Currently no RISC-V-specific algorithm info */ + ); + } + if (err != ERROR_OK) { + LOG_ERROR("Failed to call ROM function batch\n"); + /* This case is hit when loading new ROM images on FPGA, but can also be + hit on real hardware if you swap two devices with different ROM + versions without restarting OpenOCD: */ + LOG_INFO("Repopulating ROM address cache after failed ROM call"); + /* We ignore the error because we have already failed, this is just + recovery for the next attempt. */ + (void)rp2xxx_populate_rom_pointer_cache(target, priv); + return err; + } + return ERROR_OK; } -static int rp2350_init_core(struct target *target, struct rp2040_flash_bank *priv) +// Call a single ROM function, using the default algorithm stack. +static int rp2xxx_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, + uint16_t func_offset, uint32_t argdata[], unsigned int n_args) { + assert(n_args <= 4); /* only allow register arguments -- capped at just 4 on Arm */ + if (!priv->stack) { LOG_ERROR("no stack for flash programming code"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + target_addr_t stacktop = priv->stack->address + priv->stack->size; - struct armv7m_algorithm alg_info; + rp2xxx_rom_call_batch_record_t call = { + .pc = func_offset, + .sp = stacktop + }; + for (unsigned int i = 0; i < n_args; ++i) + call.args[i] = argdata[i]; - // copy rcp_init code onto stack, as we don't actually need any stack during the call - if (priv->stack->size < sizeof(rcp_init_code)) { - LOG_ERROR("Working area too small for rcp_init"); - return ERROR_BUF_TOO_SMALL; - } + return rp2xxx_call_rom_func_batch(target, priv, &call, 1); +} - // Attempt to reset ACCESSCTRL before running RCP init, in case Secure - // access to SRAM has been blocked. (Also ROM, QMI regs are needed later) +static int rp2350_init_accessctrl(struct target *target) +{ + // Attempt to reset ACCESSCTRL, in case Secure access to SRAM has been + // blocked, which will stop us from loading/running algorithms such as RCP + // init. (Also ROM, QMI regs are needed later) uint32_t accessctrl_lock_reg; if (target_read_u32(target, ACCESSCTRL_LOCK_OFFSET, &accessctrl_lock_reg) != ERROR_OK) { LOG_ERROR("Failed to read ACCESSCTRL lock register"); @@ -254,30 +567,59 @@ static int rp2350_init_core(struct target *target, struct rp2040_flash_bank *pri LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail.\n"); } else { LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET\n"); - target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); + return target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); + } + return ERROR_OK; +} + +static int rp2350_init_arm_core0(struct target *target, struct rp2040_flash_bank *priv) +{ + // Flash algorithms (and the RCP init stub called by this function) must + // run in the Secure state, so flip the state now before attempting to + // execute any code on the core. + uint32_t dscsr; + (void)target_read_u32(target, DCB_DSCSR, &dscsr); + LOG_DEBUG("DSCSR: %08x\n", dscsr); + if (!(dscsr & DSCSR_CDS)) { + LOG_DEBUG("Setting Current Domain Secure in DSCSR\n"); + (void)target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); + (void)target_read_u32(target, DCB_DSCSR, &dscsr); + LOG_DEBUG("DSCSR*: %08x\n", dscsr); + } + + if (!priv->stack) { + LOG_ERROR("No stack for flash programming code"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (!priv->ram_algo_space || priv->ram_algo_space->size < sizeof(rcp_init_code)) { + LOG_ERROR("No algorithm space for rcp_init code"); + return ERROR_BUF_TOO_SMALL; } int err = target_write_memory(target, - priv->stack->address, + priv->ram_algo_space->address, 1, sizeof(rcp_init_code), - (const uint8_t *)rcp_init_code + rcp_init_code ); if (err != ERROR_OK) { LOG_ERROR("Failed to load rcp_init algorithm into RAM\n"); return ERROR_FAIL; } - LOG_DEBUG("Calling rcp_init core \"%s\" code at 0x%" PRIx16 "\n", target->cmd_name, (uint32_t)priv->stack->address); + LOG_DEBUG("Calling rcp_init on core \"%s\", code at 0x%" PRIx32 "\n", + target->cmd_name, (uint32_t)priv->ram_algo_space->address); /* Actually call the function */ + struct armv7m_algorithm alg_info; alg_info.common_magic = ARMV7M_COMMON_MAGIC; alg_info.core_mode = ARM_MODE_THREAD; err = target_run_algorithm(target, 0, NULL, /* No memory arguments */ 0, NULL, /* No register arguments */ - priv->stack->address, - priv->stack->address + rcp_init_code_bkpt_offset, + priv->ram_algo_space->address, + priv->ram_algo_space->address + rcp_init_code_bkpt_offset, 1000, /* 1s timeout */ &alg_info ); @@ -286,80 +628,75 @@ static int rp2350_init_core(struct target *target, struct rp2040_flash_bank *pri return err; } - uint32_t reset_args[1] = { - BOOTROM_STATE_RESET_CURRENT_CORE - }; - if (!priv->jump_bootrom_reset_state) { - LOG_WARNING("RP2350 flash: no bootrom_reset_method\n"); - } else { - err = rp2040_call_rom_func(target, priv, priv->jump_bootrom_reset_state, reset_args, ARRAY_SIZE(reset_args)); - if (err != ERROR_OK) { - LOG_ERROR("RP2040 flash: failed to call reset core state"); - return err; - } - } - return err; } -static int setup_for_rom_call(struct flash_bank *bank) +static int setup_for_raw_flash_cmd(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; int err = ERROR_OK; + if (!priv->stack) { /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ - const int STACK_SIZE = 256; - target_alloc_working_area(bank->target, STACK_SIZE, &priv->stack); + err = target_alloc_working_area(bank->target, RP2XXX_MAX_ALGO_STACK_USAGE, &priv->stack); if (err != ERROR_OK) { - LOG_ERROR("Could not allocate stack for flash programming code"); + LOG_ERROR("Could not allocate stack for flash programming code -- insufficient space"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } - // Flash algorithms must run in Secure state - uint32_t dscsr; - (void)target_read_u32(target, DCB_DSCSR, &dscsr); - LOG_DEBUG("DSCSR: %08x\n", dscsr); - if (!(dscsr & DSCSR_CDS)) { - LOG_DEBUG("Setting Current Domain Secure in DSCSR\n"); - (void)target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); - (void)target_read_u32(target, DCB_DSCSR, &dscsr); - LOG_DEBUG("DSCSR*: %08x\n", dscsr); + if (!priv->ram_algo_space) { + err = target_alloc_working_area(bank->target, RP2XXX_MAX_RAM_ALGO_SIZE, &priv->ram_algo_space); + if (err != ERROR_OK) { + LOG_ERROR("Could not allocate RAM code space for ROM calls -- insufficient space"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } } - // hacky RP2350 check - if (target_to_arm(target)->arch == ARM_ARCH_V8M) { - err = rp2350_init_core(target, priv); + // hacky RP2350 check -- either RISC-V or v8-M + if (is_arm(target_to_arm(target)) ? target_to_arm(target)->arch == ARM_ARCH_V8M : true) { + err = rp2350_init_accessctrl(target); if (err != ERROR_OK) { - LOG_ERROR("RP2350 flash: failed to init core"); + LOG_ERROR("Failed to init ACCESSCTRL before ROM call"); return err; } - } - return err; -} - -static int setup_for_raw_flash_cmd(struct flash_bank *bank) -{ - struct rp2040_flash_bank *priv = bank->driver_priv; - int err = setup_for_rom_call(bank); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0); - if (err != ERROR_OK) { - LOG_ERROR("RP2040 flash: failed to setup for rom call"); - return err; - } - - LOG_DEBUG("Connecting internal flash"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0); - if (err != ERROR_OK) { - LOG_ERROR("RP2040 flash: failed to connect internal flash"); - return err; + if (is_arm(target_to_arm(target))) { + err = rp2350_init_arm_core0(target, priv); + if (err != ERROR_OK) { + LOG_ERROR("Failed to init Arm core 0 before ROM call"); + return err; + } + } + uint32_t reset_args[1] = { + BOOTROM_STATE_RESET_CURRENT_CORE + }; + if (!priv->jump_bootrom_reset_state) { + LOG_WARNING("RP2350 flash: no bootrom_reset_method\n"); + } else { + LOG_DEBUG("Clearing core 0 ROM state"); + err = rp2xxx_call_rom_func(target, priv, priv->jump_bootrom_reset_state, + reset_args, ARRAY_SIZE(reset_args)); + if (err != ERROR_OK) { + LOG_ERROR("RP2350 flash: failed to call reset core state"); + return err; + } + } } - LOG_DEBUG("Kicking flash out of XIP mode"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_exit_xip, NULL, 0); + LOG_DEBUG("Connecting flash IOs and issuing XIP exit sequence to flash"); + rp2xxx_rom_call_batch_record_t calls[2] = { + { + .pc = priv->jump_connect_internal_flash, + .sp = priv->stack->address + priv->stack->size + }, + { + .pc = priv->jump_flash_exit_xip, + .sp = priv->stack->address + priv->stack->size + } + }; + err = rp2xxx_call_rom_func_batch(bank->target, priv, calls, 2); if (err != ERROR_OK) { LOG_ERROR("RP2040 flash: failed to exit flash XIP mode"); return err; @@ -368,6 +705,25 @@ static int setup_for_raw_flash_cmd(struct flash_bank *bank) return ERROR_OK; } +static void cleanup_after_raw_flash_cmd(struct flash_bank *bank) +{ + /* OpenOCD is prone to trashing work-area allocations on target state + transitions, which leaves us with stale work area pointers in our + driver state. Best to clean up our allocations manually after + completing each flash call, so we know to make fresh ones next time. */ + LOG_DEBUG("Cleaning up after flash operations"); + struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + if (priv->stack) { + target_free_working_area(target, priv->stack); + priv->stack = 0; + } + if (priv->ram_algo_space) { + target_free_working_area(target, priv->ram_algo_space); + priv->ram_algo_space = 0; + } +} + static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset); @@ -378,13 +734,14 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui int err = setup_for_raw_flash_cmd(bank); if (err != ERROR_OK) - return err; + goto cleanup_and_return; // Allocate as much memory as possible, rounded down to a whole number of flash pages const unsigned int chunk_size = target_get_working_area_avail(target) & ~0xffu; if (chunk_size == 0 || target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) { LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + err = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + goto cleanup_and_return; } LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address); @@ -402,7 +759,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui bounce->address, /* data */ write_size /* count */ }; - err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args)); + err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args)); if (err != ERROR_OK) { LOG_ERROR("Failed to invoke flash programming code on target"); break; @@ -415,20 +772,43 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui target_free_working_area(target, bounce); if (err != ERROR_OK) - return err; + goto cleanup_and_return; + + // Flash is successfully programmed. We can now do a bit of poking to make + // the new flash contents visible to us via memory-mapped (XIP) interface + // in the 0x1... memory region. + // + // Note on RP2350 it's not *required* to call flash_enter_cmd_xip, since + // the ROM leaves flash XIPable by default in between direct-mode + // accesses, but there's no harm in calling it anyway. - /* Flash is successfully programmed. We can now do a bit of poking to make the flash - contents visible to us via memory-mapped (XIP) interface in the 0x1... memory region */ LOG_DEBUG("Flushing flash cache after write behind"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0); + err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0); + + rp2xxx_rom_call_batch_record_t finishing_calls[3] = { + { + .pc = priv->jump_flush_cache, + .sp = priv->stack->address + priv->stack->size + }, + { + .pc = priv->jump_enter_cmd_xip, + .sp = priv->stack->address + priv->stack->size + }, + { + .pc = priv->jump_flash_reset_address_trans, + .sp = priv->stack->address + priv->stack->size + } + }; + // Note the last function does not exist on older devices: + int num_finishing_calls = priv->jump_flash_reset_address_trans ? 3 : 2; + + err = rp2xxx_call_rom_func_batch(target, priv, finishing_calls, num_finishing_calls); if (err != ERROR_OK) { LOG_ERROR("RP2040 write: failed to flush flash cache"); - return err; + goto cleanup_and_return; } - LOG_DEBUG("Configuring SSI for execute-in-place"); - err = rp2040_call_rom_func(bank->target, priv, priv->jump_enter_cmd_xip, NULL, 0); - if (err != ERROR_OK) - LOG_ERROR("RP2040 write: failed to flush flash cache"); +cleanup_and_return: + cleanup_after_raw_flash_cmd(bank); return err; } @@ -441,7 +821,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig int err = setup_for_raw_flash_cmd(bank); if (err != ERROR_OK) - return err; + goto cleanup_and_return; LOG_DEBUG("Remote call flash_range_erase"); @@ -452,18 +832,13 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig 0xd8 /* block_cmd */ }; - /* - The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3: - https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf - and the particular source code for said Boot ROM function can be found here: - https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c - - In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and - an optional larger "block" (size and command provided in args). OpenOCD's spi.c only uses "block" sizes. - */ - - err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); + /* This ROM function will use the optimal mixture of 4k 20h and 64k D8h + erases, without over-erase, as long as you just tell OpenOCD that your + flash is made up of 4k sectors instead of letting it try to guess. */ + err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); +cleanup_and_return: + cleanup_after_raw_flash_cmd(bank); return err; } @@ -475,63 +850,9 @@ static int rp2040_flash_probe(struct flash_bank *bank) struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; - int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline); - if (err != ERROR_OK) { - LOG_ERROR("Debug trampoline not found in RP2040 ROM."); - return err; - } - priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */ - - err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end); - if (err != ERROR_OK) { - LOG_ERROR("Debug trampoline end not found in RP2040 ROM."); - return err; - } - priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */ - - err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM."); - return err; - } - LOG_WARNING("GOT FLASH ERASE AT %08x\n", (int)priv->jump_flash_range_erase); - - err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM."); - return err; - } - - err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip); - if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM."); + int err = rp2xxx_populate_rom_pointer_cache(target, priv); + if (err != ERROR_OK) return err; - } - - err = rp2040_lookup_symbol(target, FUNC_BOOTROM_STATE_RESET, &priv->jump_bootrom_reset_state); - if (err != ERROR_OK) { - priv->jump_bootrom_reset_state = 0; -// LOG_ERROR("Function FUNC_BOOTROM_STATE_RESET not found in RP2040 ROM."); -// return err; - } /* the Boot ROM flash_range_program() routine requires page alignment */ bank->write_start_alignment = 256; @@ -577,6 +898,7 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) { struct rp2040_flash_bank *priv; priv = malloc(sizeof(struct rp2040_flash_bank)); + memset(priv, 0, sizeof(struct rp2040_flash_bank)); priv->probed = false; /* Set up driver_priv */ From eb4a6342485a433ad01a18ef115236c2a29de900 Mon Sep 17 00:00:00 2001 From: graham sanderson Date: Sun, 24 Mar 2024 18:33:24 -0500 Subject: [PATCH 15/55] flash/nor/rp2040: RP2350 A1 changes TV: cortex_m.c changes removed. Change-Id: I85830f2d64f8afb86690737f9ae70dde5e6143e1 Signed-off-by: Tomas Vanek Signed-off-by: graham sanderson Reviewed-on: https://review.openocd.org/c/openocd/+/8442 Tested-by: jenkins --- src/flash/nor/rp2040.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index 1e582b433a..764a034c6a 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -256,13 +256,10 @@ static int rp2350_a0_lookup_symbol(struct target *target, uint16_t tag, uint16_t return ERROR_FAIL; } -static int rp2350_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_t flags, uint16_t *symbol_out) +static int rp2350_lookup_rom_symbol(struct target *target, uint32_t ptr_to_entry, + uint16_t tag, uint16_t flags, uint16_t *symbol_out) { LOG_ROM_SYMBOL_DEBUG("Looking up ROM symbol '%c%c' in RP2350 A1 table", tag & 0xff, (tag >> 8) & 0xff); - uint32_t ptr_to_entry; - int err = target_read_u32(target, BOOTROM_MAGIC_ADDR + 4, &ptr_to_entry); - if (err != ERROR_OK) - return err; /* On RP2350 A1, Each entry has a flag bitmap identifying the type of its contents. The entry contains one halfword of data for each set flag @@ -272,7 +269,7 @@ static int rp2350_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ while (true) { uint16_t entry_tag, entry_flags; - err = target_read_u16(target, ptr_to_entry, &entry_tag); + uint32_t err = target_read_u16(target, ptr_to_entry, &entry_tag); if (err != ERROR_OK) return err; if (entry_tag == 0) { @@ -341,7 +338,7 @@ static int rp2xxx_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ if (table_ptr < 0x7c00) return rp2350_a0_lookup_symbol(target, tag, flags, symbol_out); else - return rp2350_lookup_rom_symbol(target, tag, flags, symbol_out); + return rp2350_lookup_rom_symbol(target, table_ptr, tag, flags, symbol_out); } else if (magic == BOOTROM_RP2040_MAGIC) { return rp2040_lookup_rom_symbol(target, tag, flags, symbol_out); From 2e8e1a3da386685a2a572bcc85f043505a7b3d94 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 28 Jun 2024 16:41:48 +0100 Subject: [PATCH 16/55] flash/nor/rp2040: Fix up ROM table lookup for RP2350 A2 which has 16-bit well-known pointers. Change-Id: Ia0838a0b062f73a9c5751abb48f1b4d55100bd1d Signed-off-by: Tomas Vanek Signed-off-by: Luke Wren Reviewed-on: https://review.openocd.org/c/openocd/+/8443 Reviewed-by: Jonathan Bell Tested-by: jenkins --- src/flash/nor/rp2040.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index 764a034c6a..a9995f8c6d 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -331,8 +331,8 @@ static int rp2xxx_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ /* Distinguish old-style RP2350 ROM table (A0, and earlier A1 builds) based on position of table -- a high address means it is shared with RISC-V, i.e. new-style. */ - uint32_t table_ptr; - err = target_read_u32(target, BOOTROM_MAGIC_ADDR + 4, &table_ptr); + uint16_t table_ptr; + err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_ptr); if (err != ERROR_OK) return err; if (table_ptr < 0x7c00) From ca966d3d7f28875e4872e691c3fdce27867ddab0 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Thu, 25 Jul 2024 10:55:41 +0100 Subject: [PATCH 17/55] flash/nor/rp2040: Avoid ROM call timeout on long erases by splitting into chunks Also add keep_alive() to erase/program to avoid nasty GDB message. TV: Fixed style problems. Signed-off-by: Tomas Vanek Signed-off-by: Luke Wren Change-Id: Ibb18775aeed192361ae1585bfdaad03760583cf3 Reviewed-on: https://review.openocd.org/c/openocd/+/8444 Tested-by: jenkins Reviewed-by: Jonathan Bell --- src/flash/nor/rp2040.c | 63 +++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index a9995f8c6d..9151b68789 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -510,11 +510,10 @@ static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2040_flash } if (err != ERROR_OK) { LOG_ERROR("Failed to call ROM function batch\n"); - /* This case is hit when loading new ROM images on FPGA, but can also be - hit on real hardware if you swap two devices with different ROM - versions without restarting OpenOCD: */ - LOG_INFO("Repopulating ROM address cache after failed ROM call"); - /* We ignore the error because we have already failed, this is just + /* This case is hit when loading new ROM images on FPGA, but can also be hit on real + hardware if you swap two devices with different ROM versions without restarting OpenOCD: */ + LOG_ROM_SYMBOL_DEBUG("Repopulating ROM address cache after failed ROM call"); + /* We ignore the error on this next call because we have already failed, this is just recovery for the next attempt. */ (void)rp2xxx_populate_rom_pointer_cache(target, priv); return err; @@ -757,6 +756,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui write_size /* count */ }; err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args)); + keep_alive(); if (err != ERROR_OK) { LOG_ERROR("Failed to invoke flash programming code on target"); break; @@ -820,19 +820,50 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig if (err != ERROR_OK) goto cleanup_and_return; - LOG_DEBUG("Remote call flash_range_erase"); + uint32_t offset_next = bank->sectors[first].offset; + uint32_t offset_last = bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset; + + /* Break erase into multiple calls to avoid timeout on large erase. Choose 128k chunk which has + fairly low ROM call overhead and empirically seems to avoid the default keep_alive() limit + as well as our ROM call timeout. */ + const uint32_t erase_chunk_size = 128 * 1024; + + /* Promote log level for long erases to provide feedback */ + bool requires_loud_prints = offset_last - offset_next >= 2 * erase_chunk_size; + enum log_levels chunk_log_level = requires_loud_prints ? LOG_LVL_INFO : LOG_LVL_DEBUG; + + while (offset_next < offset_last) { + uint32_t remaining = offset_last - offset_next; + uint32_t call_size = remaining < erase_chunk_size ? remaining : erase_chunk_size; + /* Shorten the first call of a large erase if necessary to align subsequent calls */ + if (offset_next % erase_chunk_size != 0 && call_size == erase_chunk_size) + call_size = erase_chunk_size - offset_next % erase_chunk_size; + + LOG_CUSTOM_LEVEL(chunk_log_level, + " Erase chunk: 0x%08" PRIx32 " -> 0x%08" PRIx32, + offset_next, + offset_next + call_size - 1 + ); - uint32_t args[4] = { - bank->sectors[first].offset, /* addr */ - bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */ - 65536, /* block_size */ - 0xd8 /* block_cmd */ - }; + /* This ROM function uses the optimal mixture of 4k 20h and 64k D8h erases, without + over-erase. This is why we force the flash_bank sector size attribute to 4k even if + OpenOCD prefers to give the block size instead. */ + uint32_t args[4] = { + offset_next, + call_size, + 65536, /* block_size */ + 0xd8 /* block_cmd */ + }; + + err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); + keep_alive(); + + if (err != ERROR_OK) + break; + + offset_next += call_size; + } - /* This ROM function will use the optimal mixture of 4k 20h and 64k D8h - erases, without over-erase, as long as you just tell OpenOCD that your - flash is made up of 4k sectors instead of letting it try to guess. */ - err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); cleanup_and_return: cleanup_after_raw_flash_cmd(bank); From 8f92e520bbd76917fd3ed18b9b9bb4099044da14 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Tue, 6 Aug 2024 11:57:04 +0100 Subject: [PATCH 18/55] flash/nor/rp2040: Fix incorrect erase bounds calculation when erase region does not start at 0 Signed-off-by: Tomas Vanek Signed-off-by: Luke Wren Change-Id: I2b9db61e8ac837b6c6431aacf3b73ed3a1772fbc Reviewed-on: https://review.openocd.org/c/openocd/+/8445 Tested-by: jenkins Reviewed-by: Jonathan Bell --- src/flash/nor/rp2040.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index 9151b68789..ed8341d1ff 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -821,7 +821,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig goto cleanup_and_return; uint32_t offset_next = bank->sectors[first].offset; - uint32_t offset_last = bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset; + uint32_t offset_last = bank->sectors[last].offset + bank->sectors[last].size; /* Break erase into multiple calls to avoid timeout on large erase. Choose 128k chunk which has fairly low ROM call overhead and empirically seems to avoid the default keep_alive() limit From ba03d13c29fba9f5e4e97121c47eb3b7857aa92d Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 6 Aug 2024 17:39:44 +0200 Subject: [PATCH 19/55] flash/nor/rp2040: allow flash size override from cfg Do not enforce hard-wired size 32 MiB Signed-off-by: Tomas Vanek Change-Id: I54608f75cc13996fda38ebd5d330e3b1893c2fd9 Reviewed-on: https://review.openocd.org/c/openocd/+/8446 Tested-by: jenkins Reviewed-by: Jonathan Bell Reviewed-by: Antonio Borneo --- src/flash/nor/rp2040.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index ed8341d1ff..5faba57a08 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -887,7 +887,10 @@ static int rp2040_flash_probe(struct flash_bank *bank) bank->write_end_alignment = 256; // Max size -- up to two devices (two chip selects) in adjacent 24-bit address windows - bank->size = 32 * 1024 * 1024; + if (bank->size == 0) { + /* TODO: get real flash size */ + bank->size = 32 * 1024 * 1024; + } bank->num_sectors = bank->size / 4096; From 15d92076b0c2d6198e2f60381e4dcb645ec9a110 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 17 Jul 2024 11:49:55 +0200 Subject: [PATCH 20/55] flash/nor/rp2040: allow arbitrary ROM API call from Tcl The new flash command could be handy for a reboot to BOOTSEL mode and for making (Q)SPI flash content visible at 0x10xxxxxx address mapping area after a rescue reset. Signed-off-by: Tomas Vanek Change-Id: I1b532afcc41a4051298313e685658e86c02c53f9 Reviewed-on: https://review.openocd.org/c/openocd/+/8447 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/flash/nor/rp2040.c | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index 5faba57a08..df9284d968 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -938,8 +938,95 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) return ERROR_OK; } + +COMMAND_HANDLER(rp2040_rom_api_call_handler) +{ + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD->ctx); + + struct flash_bank *bank; + for (bank = flash_bank_list(); bank; bank = bank->next) { + if (bank->driver != &rp2040_flash) + continue; + + if (bank->target == target) + break; + } + + if (!bank) { + command_print(CMD, "[%s] No associated RP2xxx flash bank found", + target_name(target)); + return ERROR_FAIL; + } + + int retval = rp2040_flash_auto_probe(bank); + if (retval != ERROR_OK) { + command_print(CMD, "auto_probe failed"); + return retval; + } + + uint16_t tag = MAKE_TAG(CMD_ARGV[0][0], CMD_ARGV[0][1]); + + uint32_t args[4] = { 0 }; + for (unsigned int i = 0; i + 1 < CMD_ARGC && i < ARRAY_SIZE(args); i++) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i + 1], args[i]); + + retval = setup_for_raw_flash_cmd(bank); + if (retval != ERROR_OK) + goto cleanup_and_return; + + uint16_t symtype_func = is_arm(target_to_arm(target)) + ? RT_FLAG_FUNC_ARM_SEC : RT_FLAG_FUNC_RISCV; + + uint16_t fc; + retval = rp2xxx_lookup_rom_symbol(target, tag, symtype_func, &fc); + if (retval != ERROR_OK) { + command_print(CMD, "Function %.2s not found in RP2xxx ROM.", + CMD_ARGV[0]); + goto cleanup_and_return; + } + + /* command_print() output gets lost if the command is called + * in an event handler, use LOG_INFO instead */ + LOG_INFO("RP2xxx ROM API function %.2s @ %04" PRIx16, CMD_ARGV[0], fc); + + struct rp2040_flash_bank *priv = bank->driver_priv; + retval = rp2xxx_call_rom_func(target, priv, fc, args, ARRAY_SIZE(args)); + if (retval != ERROR_OK) + command_print(CMD, "RP2xxx ROM API call failed"); + +cleanup_and_return: + cleanup_after_raw_flash_cmd(bank); + return retval; +} + +static const struct command_registration rp2040_exec_command_handlers[] = { + { + .name = "rom_api_call", + .mode = COMMAND_EXEC, + .help = "arbitrary ROM API call", + .usage = "fc [p0 [p1 [p2 [p3]]]]", + .handler = rp2040_rom_api_call_handler, + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rp2040_command_handler[] = { + { + .name = "rp2xxx", + .mode = COMMAND_ANY, + .help = "rp2xxx flash controller commands", + .usage = "", + .chain = rp2040_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + const struct flash_driver rp2040_flash = { .name = "rp2040_flash", + .commands = rp2040_command_handler, .flash_bank_command = rp2040_flash_bank_command, .erase = rp2040_flash_erase, .write = rp2040_flash_write, From 2e49c99b1f919c2496c2d0140ada4ea5134c20a0 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 10 Aug 2024 16:10:43 +0200 Subject: [PATCH 21/55] flash/nor/rp2040: flash bank target switching for RP2350 RP2350 can switch either core to Cortex-M33 or RISC-V. The different architectures have to be supported as distinct targets in OpenOCD. Introduce 'rp2xxx _switch target' Tcl command to adapt flash bank to architecture changes. Keep the target and priv pointers intact until a flash operation is finished to prevent sudden change in the middle of write/erase. Signed-off-by: Tomas Vanek Change-Id: I764354ab469e253042128958dfe70c09d04d6411 Reviewed-on: https://review.openocd.org/c/openocd/+/8448 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/rp2040.c | 77 +++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index df9284d968..15a04fbb00 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -627,16 +627,13 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2040_flash_bank return err; } -static int setup_for_raw_flash_cmd(struct flash_bank *bank) +static int setup_for_raw_flash_cmd(struct target *target, struct rp2040_flash_bank *priv) { - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; - int err = ERROR_OK; if (!priv->stack) { /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */ - err = target_alloc_working_area(bank->target, RP2XXX_MAX_ALGO_STACK_USAGE, &priv->stack); + err = target_alloc_working_area(target, RP2XXX_MAX_ALGO_STACK_USAGE, &priv->stack); if (err != ERROR_OK) { LOG_ERROR("Could not allocate stack for flash programming code -- insufficient space"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -644,7 +641,7 @@ static int setup_for_raw_flash_cmd(struct flash_bank *bank) } if (!priv->ram_algo_space) { - err = target_alloc_working_area(bank->target, RP2XXX_MAX_RAM_ALGO_SIZE, &priv->ram_algo_space); + err = target_alloc_working_area(target, RP2XXX_MAX_RAM_ALGO_SIZE, &priv->ram_algo_space); if (err != ERROR_OK) { LOG_ERROR("Could not allocate RAM code space for ROM calls -- insufficient space"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -692,7 +689,7 @@ static int setup_for_raw_flash_cmd(struct flash_bank *bank) .sp = priv->stack->address + priv->stack->size } }; - err = rp2xxx_call_rom_func_batch(bank->target, priv, calls, 2); + err = rp2xxx_call_rom_func_batch(target, priv, calls, 2); if (err != ERROR_OK) { LOG_ERROR("RP2040 flash: failed to exit flash XIP mode"); return err; @@ -701,15 +698,13 @@ static int setup_for_raw_flash_cmd(struct flash_bank *bank) return ERROR_OK; } -static void cleanup_after_raw_flash_cmd(struct flash_bank *bank) +static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2040_flash_bank *priv) { /* OpenOCD is prone to trashing work-area allocations on target state transitions, which leaves us with stale work area pointers in our driver state. Best to clean up our allocations manually after completing each flash call, so we know to make fresh ones next time. */ LOG_DEBUG("Cleaning up after flash operations"); - struct rp2040_flash_bank *priv = bank->driver_priv; - struct target *target = bank->target; if (priv->stack) { target_free_working_area(target, priv->stack); priv->stack = 0; @@ -728,7 +723,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui struct target *target = bank->target; struct working_area *bounce; - int err = setup_for_raw_flash_cmd(bank); + int err = setup_for_raw_flash_cmd(target, priv); if (err != ERROR_OK) goto cleanup_and_return; @@ -780,7 +775,7 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui // accesses, but there's no harm in calling it anyway. LOG_DEBUG("Flushing flash cache after write behind"); - err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0); + err = rp2xxx_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0); rp2xxx_rom_call_batch_record_t finishing_calls[3] = { { @@ -805,18 +800,19 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui goto cleanup_and_return; } cleanup_and_return: - cleanup_after_raw_flash_cmd(bank); + cleanup_after_raw_flash_cmd(target, priv); return err; } static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; uint32_t start_addr = bank->sectors[first].offset; uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr); - int err = setup_for_raw_flash_cmd(bank); + int err = setup_for_raw_flash_cmd(target, priv); if (err != ERROR_OK) goto cleanup_and_return; @@ -855,7 +851,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig 0xd8 /* block_cmd */ }; - err = rp2xxx_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); + err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args)); keep_alive(); if (err != ERROR_OK) @@ -866,7 +862,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig cleanup_and_return: - cleanup_after_raw_flash_cmd(bank); + cleanup_after_raw_flash_cmd(target, priv); return err; } @@ -973,7 +969,8 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler) for (unsigned int i = 0; i + 1 < CMD_ARGC && i < ARRAY_SIZE(args); i++) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i + 1], args[i]); - retval = setup_for_raw_flash_cmd(bank); + struct rp2040_flash_bank *priv = bank->driver_priv; + retval = setup_for_raw_flash_cmd(target, priv); if (retval != ERROR_OK) goto cleanup_and_return; @@ -992,16 +989,51 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler) * in an event handler, use LOG_INFO instead */ LOG_INFO("RP2xxx ROM API function %.2s @ %04" PRIx16, CMD_ARGV[0], fc); - struct rp2040_flash_bank *priv = bank->driver_priv; retval = rp2xxx_call_rom_func(target, priv, fc, args, ARRAY_SIZE(args)); if (retval != ERROR_OK) command_print(CMD, "RP2xxx ROM API call failed"); cleanup_and_return: - cleanup_after_raw_flash_cmd(bank); + cleanup_after_raw_flash_cmd(target, priv); return retval; } +COMMAND_HANDLER(rp2040_switch_target_handler) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *old_target = get_target(CMD_ARGV[0]); + if (!old_target) { + command_print(CMD, "Unrecognised old target %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + struct target *new_target = get_target(CMD_ARGV[1]); + if (!new_target) { + command_print(CMD, "Unrecognised new target %s", CMD_ARGV[1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + struct flash_bank *bank; + for (bank = flash_bank_list(); bank; bank = bank->next) { + if (bank->driver == &rp2040_flash) { + if (bank->target == old_target) { + bank->target = new_target; + struct rp2040_flash_bank *priv = bank->driver_priv; + priv->probed = false; + return ERROR_OK; + } else if (bank->target == new_target) { + return ERROR_OK; + } + } + } + + command_print(CMD, "Neither old nor new target %s found in flash bank list", + CMD_ARGV[0]); + return ERROR_FAIL; +} + static const struct command_registration rp2040_exec_command_handlers[] = { { .name = "rom_api_call", @@ -1010,6 +1042,13 @@ static const struct command_registration rp2040_exec_command_handlers[] = { .usage = "fc [p0 [p1 [p2 [p3]]]]", .handler = rp2040_rom_api_call_handler, }, + { + .name = "_switch_target", + .mode = COMMAND_EXEC, + .help = "internal use", + .usage = "old_target new_target", + .handler = rp2040_switch_target_handler, + }, COMMAND_REGISTRATION_DONE }; From 69ee4457864af2657ce1b634887b26b838fc916f Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 11 Aug 2024 15:03:05 +0200 Subject: [PATCH 22/55] tcl/target/rp2350: universal config for any combination of CM/RV cores RP2350 has 2 slots where either Cortex-M33 or RISC-V can be selected. Tcl variable USE_CORE selects what cores will be configured for debug. Signed-off-by: Tomas Vanek Change-Id: I56fe1aa94304bdfd1ec98bba57cc3fa792a35f69 Reviewed-on: https://review.openocd.org/c/openocd/+/8449 Tested-by: jenkins --- tcl/target/rp2350.cfg | 206 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 tcl/target/rp2350.cfg diff --git a/tcl/target/rp2350.cfg b/tcl/target/rp2350.cfg new file mode 100644 index 0000000000..775561f062 --- /dev/null +++ b/tcl/target/rp2350.cfg @@ -0,0 +1,206 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# RP2350 is a microcontroller with dual Cortex-M33 cores or dual Hazard3 RISC-V cores. +# https://www.raspberrypi.com/documentation/microcontrollers/rp2350.html + +transport select swd + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rp2350 +} + +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x00040927 +} + +# Set to '1' to start rescue mode +if { [info exists RESCUE] } { + set _RESCUE $RESCUE +} else { + set _RESCUE 0 +} + +# Set to 'cm0' or 'cm1' for Cortex-M33 single core configuration +# To keep compatibility with RP2040 aliases '0' and '1' are provided for Cortex-M33 cores +# Use 'rv0' or 'rv1' for RISC-V single core configuration +# List more for a multicore configuration +if { [info exists USE_CORE] } { + set _USE_CORE $USE_CORE +} else { + # defaults to both Cortex-M33 cores + set _USE_CORE { cm0 cm1 } +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID + +if { [info exists SWD_MULTIDROP] } { + dap create $_CHIPNAME.dap -adiv6 -chain-position $_CHIPNAME.cpu -dp-id 0x0040927 -instance-id 0 +} else { + dap create $_CHIPNAME.dap -adiv6 -chain-position $_CHIPNAME.cpu +} + +# Cortex-M33 core 0 +if { [lsearch $_USE_CORE cm0] >= 0 || [lsearch $_USE_CORE 0] >= 0 } { + set _TARGETNAME_CM0 $_CHIPNAME.cm0 + set _TARGETNAME_0 $_TARGETNAME_CM0 +} + +# RISC-V core 0 +if { [lsearch $_USE_CORE rv0] >= 0 } { + set _TARGETNAME_RV0 $_CHIPNAME.rv0 + if { ![info exists _TARGETNAME_0] } { + set _TARGETNAME_0 $_TARGETNAME_RV0 + } +} + +# Cortex-M33 core 1 +if { [lsearch $_USE_CORE cm1] >= 0 || [lsearch $_USE_CORE 1] >= 0 } { + set _TARGETNAME_CM1 $_CHIPNAME.cm1 + set _TARGETNAME_1 $_TARGETNAME_CM1 +} + +# RISC-V core 1 +if { [lsearch $_USE_CORE rv1] >= 0 } { + set _TARGETNAME_RV1 $_CHIPNAME.rv1 + if { ![info exists _TARGETNAME_1] } { + set _TARGETNAME_1 $_TARGETNAME_RV1 + } +} + + +if { [info exists _TARGETNAME_CM0] } { + target create $_TARGETNAME_CM0 cortex_m -dap $_CHIPNAME.dap -ap-num 0x2000 + # srst does not exist; use SYSRESETREQ to perform a soft reset + $_TARGETNAME_CM0 cortex_m reset_config sysresetreq + + # After a rescue reset the cache requires invalidate to allow SPI flash + # reads from the XIP cached mapping area + $_TARGETNAME_CM0 configure -event reset-init { rp2xxx rom_api_call FC } +} + +if { [info exists _TARGETNAME_RV0] } { + target create $_TARGETNAME_RV0 riscv -dap $_CHIPNAME.dap -ap-num 0xa000 -coreid 0 + $_TARGETNAME_RV0 riscv set_enable_virt2phys off + + # Workaround for stray IO_QSPI: GPIO_QSPI_SD1_CTRL: INOVER bit in RISC-V BOOTSEL + $_TARGETNAME_RV0 configure -event reset-init { mww 0x4003002c 0 } + + if { [info exists _TARGETNAME_CM0] } { + # just for setting after init when the event become-available is not fired + $_TARGETNAME_RV0 configure -event examine-end "rp2xxx _switch_target $_TARGETNAME_CM0 $_TARGETNAME_RV0" + } +} + +if { [info exists _TARGETNAME_CM1] } { + target create $_TARGETNAME_CM1 cortex_m -dap $_CHIPNAME.dap -ap-num 0x4000 + $_TARGETNAME_CM1 cortex_m reset_config sysresetreq +} + +if { [info exists _TARGETNAME_RV1] } { + target create $_TARGETNAME_RV1 riscv -dap $_CHIPNAME.dap -ap-num 0xa000 -coreid 1 + $_TARGETNAME_RV1 riscv set_enable_virt2phys off +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} elseif { [info exists _TARGETNAME_CM0] == [info exists _TARGETNAME_CM1] + && [info exists _TARGETNAME_RV0] == [info exists _TARGETNAME_RV1] } { + set _USE_SMP 1 +} else { + set _USE_SMP 0 +} +if { $_USE_SMP } { + if { [info exists _TARGETNAME_CM0] && [info exists _TARGETNAME_CM1] } { + $_TARGETNAME_CM0 configure -rtos hwthread + $_TARGETNAME_CM1 configure -rtos hwthread + target smp $_TARGETNAME_CM0 $_TARGETNAME_CM1 + } + if { [info exists _TARGETNAME_RV0] && [info exists _TARGETNAME_RV1] } { + $_TARGETNAME_RV0 configure -rtos hwthread + $_TARGETNAME_RV1 configure -rtos hwthread + target smp $_TARGETNAME_RV0 $_TARGETNAME_RV1 + } +} + +if { [info exists _TARGETNAME_0] } { + set _FLASH_TARGET $_TARGETNAME_0 +} +if { ![info exists _FLASH_TARGET] && [info exists _TARGETNAME_1] } { + set _FLASH_TARGET $_TARGETNAME_1 + if { [info exists _TARGETNAME_CM1] && [info exists _TARGETNAME_RV1] } { + echo "Info : $_CHIPNAME.flash will be handled by $_TARGETNAME_1 without switching" + } +} +if { [info exists _FLASH_TARGET] } { + $_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE + if { [info exists _TARGETNAME_CM0] && [info exists _TARGETNAME_RV0] } { + $_TARGETNAME_RV0 configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE + echo "Info : $_CHIPNAME.flash will be handled by the active one of $_FLASH_TARGET and $_TARGETNAME_RV0 cores" + } + set _FLASHNAME $_CHIPNAME.flash + set _FLASHSIZE 0x00400000 + flash bank $_FLASHNAME rp2040_flash 0x10000000 $_FLASHSIZE 0 0 $_FLASH_TARGET +} + +if { [info exists _TARGETNAME_1] } { + # Alias to ensure gdb connecting to core 1 gets the correct memory map + flash bank $_CHIPNAME.alias virtual 0x10000000 0 0 0 $_TARGETNAME_1 $_FLASHNAME +} + +if { [info exists _TARGETNAME_0] } { + # Select core 0 + targets $_TARGETNAME_0 +} + +# Cold reset resets everything except DP +proc cold_reset { { __CHIPNAME "" } } { + if { $__CHIPNAME == "" } { + global _CHIPNAME + set __CHIPNAME $_CHIPNAME + } + poll off + # set CDBGRSTREQ (and keep set CSYSPWRUPREQ and CDBGPWRUPREQ) + $__CHIPNAME.dap dpreg 4 0x54000000 + set dpstat [$__CHIPNAME.dap dpreg 4] + if { [expr { $dpstat & 0xcc000000 }] != 0xcc000000 } { + echo "Warn : dpstat_reset failed, DP STAT $dpstat" + } + $__CHIPNAME.dap dpreg 4 0x50000000 + dap init + poll on +} + +# Rescue reset resets everything except DP and RP_AP +# Both Cortex-M33 cores stop in bootrom +proc rescue_reset { { __CHIPNAME "" } } { + if { $__CHIPNAME == "" } { + global _CHIPNAME + set __CHIPNAME $_CHIPNAME + } + poll off + # set bit RESCUE_RESTART in RP_AP: CTRL register + $__CHIPNAME.dap apreg 0x80000 0 0x80000000 + $__CHIPNAME.dap apreg 0x80000 0 0 + dap init + poll on + if { [lsearch [target names] $__CHIPNAME.cm0] < 0 } { + echo "Info : restart OpenOCD with 'set USE_CORE { cm0 cm1 }' to debug after rescue" + } +} + +if { $_RESCUE } { + init + rescue_reset +} From 22dfd0efaddaa70baf9e65aff661554c4497909a Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 13 Aug 2024 16:23:20 +0200 Subject: [PATCH 23/55] tcl/target/rp2350: workarounds for ROM API issues A0 chip: remove pad isolation A2 chip: instead of reset init fixes we will fix the flash driver with the following patch by Luke Wren: 8729: flash/nor/rp2xxx: fix flash operation after halt in RISC-V bootsel https://review.openocd.org/c/openocd/+/8729 I don't have A1 version to test. Signed-off-by: Tomas Vanek Change-Id: I9e9fab04ead929fe6e0a17c6c2f32a6f02e9beb9 Reviewed-on: https://review.openocd.org/c/openocd/+/8450 Tested-by: jenkins --- tcl/target/rp2350.cfg | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tcl/target/rp2350.cfg b/tcl/target/rp2350.cfg index 775561f062..d2465bd2fe 100644 --- a/tcl/target/rp2350.cfg +++ b/tcl/target/rp2350.cfg @@ -94,8 +94,7 @@ if { [info exists _TARGETNAME_RV0] } { target create $_TARGETNAME_RV0 riscv -dap $_CHIPNAME.dap -ap-num 0xa000 -coreid 0 $_TARGETNAME_RV0 riscv set_enable_virt2phys off - # Workaround for stray IO_QSPI: GPIO_QSPI_SD1_CTRL: INOVER bit in RISC-V BOOTSEL - $_TARGETNAME_RV0 configure -event reset-init { mww 0x4003002c 0 } + $_TARGETNAME_RV0 configure -event reset-init "_rv_reset_init" if { [info exists _TARGETNAME_CM0] } { # just for setting after init when the event become-available is not fired @@ -204,3 +203,22 @@ if { $_RESCUE } { init rescue_reset } + +proc _rv_reset_init { } { + set chip_id [format 0x%08x [read_memory 0x40000000 32 1]] + + # Version related workarounds + switch $chip_id { + 0x00004927 { # A0 + # remove IO_QSPI isolation + mww 0x40030014 0 + mww 0x4003001c 0 + mww 0x40030024 0 + mww 0x4003002c 0 + mww 0x40030034 0 + mww 0x4003003c 0 + } + } + + rp2xxx rom_api_call FC +} From 2e1a76368eed7aac8054e6ccb7c8104bad421a70 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Aug 2024 09:10:31 +0200 Subject: [PATCH 24/55] flash/nor/rp2040: detect flash size including SFDP Also keep size override by FLASHSIZE Tcl variable possible. Partially backported from former upstream rp2040.c Signed-off-by: Tomas Vanek Change-Id: I224c3644450e8b46e35714bfc5436219ffdee563 Reviewed-on: https://review.openocd.org/c/openocd/+/8451 Tested-by: jenkins --- src/flash/nor/rp2040.c | 301 +++++++++++++++++++++++++++++++++++++++-- tcl/target/rp2350.cfg | 16 ++- 2 files changed, 299 insertions(+), 18 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index 15a04fbb00..0e592f9124 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -9,6 +9,7 @@ #include #include #include "spi.h" +#include "sfdp.h" #include /* this is 'M' 'u', 1 (version) */ @@ -43,6 +44,32 @@ #define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u #define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u +#define RP2040_SSI_DR0 0x18000060 +#define RP2040_QSPI_CTRL 0x4001800c + +#define RP2040_QSPI_CTRL_OUTOVER_MASK (3ul << 8) +#define RP2040_QSPI_CTRL_OUTOVER_LOW (2ul << 8) +#define RP2040_QSPI_CTRL_OUTOVER_HIGH (3ul << 8) + +#define RP2350_QMI_DIRECT_CSR 0x400d0000 +#define RP2350_QMI_DIRECT_TX 0x400d0004 +#define RP2350_QMI_DIRECT_RX 0x400d0008 + +#define RP2350_QMI_DIRECT_CSR_EN BIT(0) +#define RP2350_QMI_DIRECT_CSR_ASSERT_CS0N BIT(2) +#define RP2350_QMI_DIRECT_TX_NOPUSH BIT(20) +#define RP2350_QMI_DIRECT_TX_OE BIT(19) + +#define RP2XXX_SYSINFO_CHIP_ID 0x40000000 +#define RP2XXX_CHIP_ID_PART_MANUFACTURER(id) ((id) & 0x0fffffff) +#define RP2XXX_CHIP_ID_MANUFACTURER 0x493 +#define RP2XXX_MK_PART(part) (((part) << 12) | (RP2XXX_CHIP_ID_MANUFACTURER << 1) | 1) +#define RP2040_CHIP_ID_PART 0x0002 +#define IS_RP2040(id) (RP2XXX_CHIP_ID_PART_MANUFACTURER(id) == RP2XXX_MK_PART(RP2040_CHIP_ID_PART)) +#define RP2350_CHIP_ID_PART 0x0004 +#define IS_RP2350(id) (RP2XXX_CHIP_ID_PART_MANUFACTURER(id) == RP2XXX_MK_PART(RP2350_CHIP_ID_PART)) +#define RP2XXX_CHIP_ID_REVISION(id) ((id) >> 28) + #define RP2XXX_MAX_ALGO_STACK_USAGE 1024 #define RP2XXX_MAX_RAM_ALGO_SIZE 1024 @@ -156,10 +183,9 @@ typedef struct rp2xxx_rom_call_batch_record { } rp2xxx_rom_call_batch_record_t; struct rp2040_flash_bank { - /* flag indicating successful flash probe */ - bool probed; - /* stack used by Boot ROM calls */ - struct working_area *stack; + bool probed; /* flag indicating successful flash probe */ + uint32_t id; /* cached SYSINFO CHIP_ID */ + struct working_area *stack; /* stack used by Boot ROM calls */ /* static code scratchpad used for RAM algorithms -- allocated in advance so that higher-level calls can just grab all remaining workarea: */ struct working_area *ram_algo_space; @@ -172,6 +198,11 @@ struct rp2040_flash_bank { uint16_t jump_flash_reset_address_trans; uint16_t jump_enter_cmd_xip; uint16_t jump_bootrom_reset_state; + + char dev_name[20]; + bool size_override; + struct flash_device spi_dev; /* detected model of SPI flash */ + unsigned int sfdp_dummy, sfdp_dummy_detect; }; #ifndef LOG_ROM_SYMBOL_DEBUG @@ -869,37 +900,276 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig /* ----------------------------------------------------------------------------- Driver probing etc */ + +static int rp2040_ssel_active(struct target *target, bool active) +{ + uint32_t state = active ? RP2040_QSPI_CTRL_OUTOVER_LOW : RP2040_QSPI_CTRL_OUTOVER_HIGH; + uint32_t val; + + int err = target_read_u32(target, RP2040_QSPI_CTRL, &val); + if (err != ERROR_OK) + return err; + + val = (val & ~RP2040_QSPI_CTRL_OUTOVER_MASK) | state; + + err = target_write_u32(target, RP2040_QSPI_CTRL, val); + if (err != ERROR_OK) + return err; + + return ERROR_OK; +} + +static int rp2040_spi_tx_rx(struct target *target, + const uint8_t *tx, unsigned int tx_len, + unsigned int dummy_len, + uint8_t *rx, unsigned int rx_len) +{ + int retval, retval2; + + retval = rp2040_ssel_active(target, true); + if (retval != ERROR_OK) { + LOG_ERROR("QSPI select failed"); + goto deselect; + } + + unsigned int tx_cnt = 0; + unsigned int rx_cnt = 0; + unsigned int xfer_len = tx_len + dummy_len + rx_len; + while (rx_cnt < xfer_len) { + int in_flight = tx_cnt - rx_cnt; + if (tx_cnt < xfer_len && in_flight < 14) { + uint32_t dr = tx_cnt < tx_len ? tx[tx_cnt] : 0; + retval = target_write_u32(target, RP2040_SSI_DR0, dr); + if (retval != ERROR_OK) + break; + + tx_cnt++; + continue; + } + uint32_t dr; + retval = target_read_u32(target, RP2040_SSI_DR0, &dr); + if (retval != ERROR_OK) + break; + + if (rx_cnt >= tx_len + dummy_len) + rx[rx_cnt - tx_len - dummy_len] = (uint8_t)dr; + + rx_cnt++; + } + +deselect: + retval2 = rp2040_ssel_active(target, false); + + if (retval != ERROR_OK) { + LOG_ERROR("QSPI Tx/Rx failed"); + return retval; + } + if (retval2 != ERROR_OK) + LOG_ERROR("QSPI deselect failed"); + + return retval2; +} + +static int rp2350_spi_tx_rx(struct target *target, + const uint8_t *tx, unsigned int tx_len, + unsigned int dummy_len, + uint8_t *rx, unsigned int rx_len) +{ + uint32_t direct_csr; + int retval = target_read_u32(target, RP2350_QMI_DIRECT_CSR, &direct_csr); + if (retval != ERROR_OK) { + LOG_ERROR("QMI DIRECT_CSR read failed"); + return retval; + } + direct_csr |= RP2350_QMI_DIRECT_CSR_EN | RP2350_QMI_DIRECT_CSR_ASSERT_CS0N; + retval = target_write_u32(target, RP2350_QMI_DIRECT_CSR, direct_csr); + if (retval != ERROR_OK) { + LOG_ERROR("QMI DIRECT mode enable failed"); + goto deselect; + } + + unsigned int tx_cnt = 0; + unsigned int rx_cnt = 0; + unsigned int xfer_len = tx_len + dummy_len + rx_len; + while (tx_cnt < xfer_len || rx_cnt < rx_len) { + int in_flight = tx_cnt - tx_len - dummy_len - rx_cnt; + if (tx_cnt < xfer_len && in_flight < 4) { + uint32_t tx_cmd; + if (tx_cnt < tx_len) + tx_cmd = tx[tx_cnt] | RP2350_QMI_DIRECT_TX_NOPUSH | RP2350_QMI_DIRECT_TX_OE; + else if (tx_cnt < tx_len + dummy_len) + tx_cmd = RP2350_QMI_DIRECT_TX_NOPUSH; + else + tx_cmd = 0; + + retval = target_write_u32(target, RP2350_QMI_DIRECT_TX, tx_cmd); + if (retval != ERROR_OK) + break; + + tx_cnt++; + continue; + } + if (rx_cnt < rx_len) { + uint32_t dr; + retval = target_read_u32(target, RP2350_QMI_DIRECT_RX, &dr); + if (retval != ERROR_OK) + break; + + rx[rx_cnt] = (uint8_t)dr; + rx_cnt++; + } + } + +deselect: + direct_csr &= ~(RP2350_QMI_DIRECT_CSR_EN | RP2350_QMI_DIRECT_CSR_ASSERT_CS0N); + int retval2 = target_write_u32(target, RP2350_QMI_DIRECT_CSR, direct_csr); + + if (retval != ERROR_OK) { + LOG_ERROR("QSPI Tx/Rx failed"); + return retval; + } + if (retval2 != ERROR_OK) + LOG_ERROR("QMI DIRECT mode disable failed"); + + return retval2; +} + +static int rp2xxx_spi_tx_rx(struct flash_bank *bank, + const uint8_t *tx, unsigned int tx_len, + unsigned int dummy_len, + uint8_t *rx, unsigned int rx_len) +{ + struct rp2040_flash_bank *priv = bank->driver_priv; + struct target *target = bank->target; + + if (IS_RP2040(priv->id)) + return rp2040_spi_tx_rx(target, tx, tx_len, dummy_len, rx, rx_len); + else if (IS_RP2350(priv->id)) + return rp2350_spi_tx_rx(target, tx, tx_len, dummy_len, rx, rx_len); + else + return ERROR_FAIL; +} + +static int rp2xxx_read_sfdp_block(struct flash_bank *bank, uint32_t addr, + unsigned int words, uint32_t *buffer) +{ + struct rp2040_flash_bank *priv = bank->driver_priv; + + uint8_t cmd[4] = { SPIFLASH_READ_SFDP }; + uint8_t data[4 * words + priv->sfdp_dummy_detect]; + + h_u24_to_be(&cmd[1], addr); + + int retval = rp2xxx_spi_tx_rx(bank, cmd, sizeof(cmd), priv->sfdp_dummy, + data, 4 * words + priv->sfdp_dummy_detect); + if (retval != ERROR_OK) + return retval; + + if (priv->sfdp_dummy_detect) { + for (unsigned int i = 0; i < priv->sfdp_dummy_detect; i++) + if (le_to_h_u32(&data[i]) == SFDP_MAGIC) { + priv->sfdp_dummy_detect = 0; + priv->sfdp_dummy = i; + break; + } + for (unsigned int i = 0; i < words; i++) + buffer[i] = le_to_h_u32(&data[4 * i + priv->sfdp_dummy]); + } else { + for (unsigned int i = 0; i < words; i++) + buffer[i] = le_to_h_u32(&data[4 * i]); + } + return retval; +} + static int rp2040_flash_probe(struct flash_bank *bank) { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; - int err = rp2xxx_populate_rom_pointer_cache(target, priv); - if (err != ERROR_OK) - return err; + int retval = target_read_u32(target, RP2XXX_SYSINFO_CHIP_ID, &priv->id); + if (retval != ERROR_OK) { + LOG_ERROR("SYSINFO CHIP_ID read failed"); + return retval; + } + if (!IS_RP2040(priv->id) && !IS_RP2350(priv->id)) { + LOG_ERROR("Unknown SYSINFO CHIP_ID 0x%08" PRIx32, priv->id); + return ERROR_FLASH_BANK_INVALID; + } + + retval = rp2xxx_populate_rom_pointer_cache(target, priv); + if (retval != ERROR_OK) + return retval; /* the Boot ROM flash_range_program() routine requires page alignment */ bank->write_start_alignment = 256; bank->write_end_alignment = 256; - // Max size -- up to two devices (two chip selects) in adjacent 24-bit address windows + uint32_t flash_id = 0; + if (priv->size_override) { + priv->spi_dev.name = "size override"; + LOG_DEBUG("SPI flash autodetection disabled, using configured size"); + } else { + bank->size = 0; + + (void)setup_for_raw_flash_cmd(target, priv); + /* ignore error, flash size detection could work anyway */ + + const uint8_t cmd[] = { SPIFLASH_READ_ID }; + uint8_t data[3]; + retval = rp2xxx_spi_tx_rx(bank, cmd, sizeof(cmd), 0, data, sizeof(data)); + if (retval == ERROR_OK) { + flash_id = le_to_h_u24(data); + + /* search for a SPI flash Device ID match */ + for (const struct flash_device *p = flash_devices; p->name ; p++) { + if (p->device_id == flash_id) { + priv->spi_dev = *p; + bank->size = p->size_in_bytes; + break; + } + } + } + + if (bank->size == 0) { + priv->sfdp_dummy_detect = 8; + priv->sfdp_dummy = 0; + retval = spi_sfdp(bank, &priv->spi_dev, &rp2xxx_read_sfdp_block); + if (retval == ERROR_OK) + bank->size = priv->spi_dev.size_in_bytes; + } + + cleanup_after_raw_flash_cmd(target, priv); + } + + snprintf(priv->dev_name, sizeof(priv->dev_name), "%s rev %u", + IS_RP2350(priv->id) ? "RP2350" : "RP2040", + RP2XXX_CHIP_ID_REVISION(priv->id)); + if (bank->size == 0) { - /* TODO: get real flash size */ - bank->size = 32 * 1024 * 1024; + LOG_ERROR("%s, QSPI Flash id = 0x%06" PRIx32 " not recognised", + priv->dev_name, flash_id); + return ERROR_FLASH_BANK_INVALID; } bank->num_sectors = bank->size / 4096; - LOG_INFO("RP2040 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n", - bank->size, bank->base, bank->num_sectors); + if (priv->size_override) { + LOG_INFO("%s, QSPI Flash size override = %u KiB in %u sectors", + priv->dev_name, bank->size / 1024, bank->num_sectors); + } else { + LOG_INFO("%s, QSPI Flash %s id = 0x%06" PRIx32 " size = %u KiB in %u sectors", + priv->dev_name, priv->spi_dev.name, flash_id, + bank->size / 1024, bank->num_sectors); + } + + free(bank->sectors); bank->sectors = alloc_block_array(0, 4096, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; - if (err == ERROR_OK) - priv->probed = true; + priv->probed = true; - return err; + return ERROR_OK; } static int rp2040_flash_auto_probe(struct flash_bank *bank) @@ -927,6 +1197,7 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) priv = malloc(sizeof(struct rp2040_flash_bank)); memset(priv, 0, sizeof(struct rp2040_flash_bank)); priv->probed = false; + priv->size_override = bank->size != 0; /* Set up driver_priv */ bank->driver_priv = priv; diff --git a/tcl/target/rp2350.cfg b/tcl/target/rp2350.cfg index d2465bd2fe..dc26cde190 100644 --- a/tcl/target/rp2350.cfg +++ b/tcl/target/rp2350.cfg @@ -19,6 +19,14 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x10000 } +# Nonzero FLASHSIZE supresses QSPI flash size detection +if { [info exists FLASHSIZE] } { + set _FLASHSIZE $FLASHSIZE +} else { + # Detect QSPI flash size based on flash ID or SFDP + set _FLASHSIZE 0 +} + if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { @@ -143,13 +151,15 @@ if { ![info exists _FLASH_TARGET] && [info exists _TARGETNAME_1] } { } } if { [info exists _FLASH_TARGET] } { - $_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE + # QSPI flash size detection during gdb connect requires to back-up RAM + set _WKA_BACKUP [expr { $_FLASHSIZE == 0 }] + $_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE -work-area-backup $_WKA_BACKUP if { [info exists _TARGETNAME_CM0] && [info exists _TARGETNAME_RV0] } { - $_TARGETNAME_RV0 configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE + $_TARGETNAME_RV0 configure -work-area-phys 0x20010000 \ + -work-area-size $_WORKAREASIZE -work-area-backup $_WKA_BACKUP echo "Info : $_CHIPNAME.flash will be handled by the active one of $_FLASH_TARGET and $_TARGETNAME_RV0 cores" } set _FLASHNAME $_CHIPNAME.flash - set _FLASHSIZE 0x00400000 flash bank $_FLASHNAME rp2040_flash 0x10000000 $_FLASHSIZE 0 0 $_FLASH_TARGET } From 20d1d4405d73fe47efc07cb109454c088a8ecbc8 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Aug 2024 09:39:42 +0200 Subject: [PATCH 25/55] flash/nor/rp2040: add missing TARGET_HALTED checks Flash erase and write require this guard, unfortunately it is also partially needed in the flash probe. Partially backported from former upstream rp2040.c Signed-off-by: Tomas Vanek Change-Id: Ie8a240e66c3ed68e08f872cbbfdd90a6d80e1f1e Reviewed-on: https://review.openocd.org/c/openocd/+/8452 Tested-by: jenkins --- src/flash/nor/rp2040.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index 0e592f9124..65c1e095b1 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -752,6 +752,12 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + struct working_area *bounce; int err = setup_for_raw_flash_cmd(target, priv); @@ -839,6 +845,12 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig { struct rp2040_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + uint32_t start_addr = bank->sectors[first].offset; uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr); @@ -1109,6 +1121,11 @@ static int rp2040_flash_probe(struct flash_bank *bank) priv->spi_dev.name = "size override"; LOG_DEBUG("SPI flash autodetection disabled, using configured size"); } else { + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + bank->size = 0; (void)setup_for_raw_flash_cmd(target, priv); @@ -1240,6 +1257,11 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler) for (unsigned int i = 0; i + 1 < CMD_ARGC && i < ARRAY_SIZE(args); i++) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i + 1], args[i]); + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + struct rp2040_flash_bank *priv = bank->driver_priv; retval = setup_for_raw_flash_cmd(target, priv); if (retval != ERROR_OK) From 26729aa8b089230bf0896c32df9a4b7ae3ef6fee Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Aug 2024 10:41:55 +0200 Subject: [PATCH 26/55] flash/nor/rp2040: improve flash write buffer size computation While on it: Define the names for the fixed flash page/sector sizes and use them instead of magic values. Fix memory leak on error return. Partially backported from former upstream rp2040.c Signed-off-by: Tomas Vanek Change-Id: If51c912f4d381ee47756a70f616ecdbee1ac0da7 Reviewed-on: https://review.openocd.org/c/openocd/+/8453 Tested-by: jenkins --- src/flash/nor/rp2040.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index 65c1e095b1..c28bc85096 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -73,6 +73,9 @@ #define RP2XXX_MAX_ALGO_STACK_USAGE 1024 #define RP2XXX_MAX_RAM_ALGO_SIZE 1024 +#define RP2XXX_ROM_API_FIXED_FLASH_PAGE 256 +#define RP2XXX_ROM_API_FIXED_FLASH_SECTOR 4096 + // Calling bootrom functions on Arm RP2350 requires the redundancy // coprocessor (RCP) to be initialised. Usually this is done first thing by // the bootrom, but the debugger may skip this, e.g. by resetting the cores @@ -758,17 +761,19 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui return ERROR_TARGET_NOT_HALTED; } - struct working_area *bounce; + struct working_area *bounce = NULL; int err = setup_for_raw_flash_cmd(target, priv); if (err != ERROR_OK) goto cleanup_and_return; - // Allocate as much memory as possible, rounded down to a whole number of flash pages - const unsigned int chunk_size = target_get_working_area_avail(target) & ~0xffu; - if (chunk_size == 0 || target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) { + unsigned int avail_pages = target_get_working_area_avail(target) / RP2XXX_ROM_API_FIXED_FLASH_PAGE; + /* We try to allocate working area rounded down to device page size, + * al least 1 page, at most the write data size */ + unsigned int chunk_size = MIN(MAX(avail_pages, 1) * RP2XXX_ROM_API_FIXED_FLASH_PAGE, count); + err = target_alloc_working_area(target, chunk_size, &bounce); + if (err != ERROR_OK) { LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue"); - err = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto cleanup_and_return; } @@ -787,7 +792,8 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui bounce->address, /* data */ write_size /* count */ }; - err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args)); + err = rp2xxx_call_rom_func(target, priv, priv->jump_flash_range_program, + args, ARRAY_SIZE(args)); keep_alive(); if (err != ERROR_OK) { LOG_ERROR("Failed to invoke flash programming code on target"); @@ -798,7 +804,6 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui offset += write_size; count -= write_size; } - target_free_working_area(target, bounce); if (err != ERROR_OK) goto cleanup_and_return; @@ -837,6 +842,8 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui goto cleanup_and_return; } cleanup_and_return: + target_free_working_area(target, bounce); + cleanup_after_raw_flash_cmd(target, priv); return err; } @@ -1113,8 +1120,8 @@ static int rp2040_flash_probe(struct flash_bank *bank) return retval; /* the Boot ROM flash_range_program() routine requires page alignment */ - bank->write_start_alignment = 256; - bank->write_end_alignment = 256; + bank->write_start_alignment = RP2XXX_ROM_API_FIXED_FLASH_PAGE; + bank->write_end_alignment = RP2XXX_ROM_API_FIXED_FLASH_PAGE; uint32_t flash_id = 0; if (priv->size_override) { @@ -1168,7 +1175,7 @@ static int rp2040_flash_probe(struct flash_bank *bank) return ERROR_FLASH_BANK_INVALID; } - bank->num_sectors = bank->size / 4096; + bank->num_sectors = bank->size / RP2XXX_ROM_API_FIXED_FLASH_SECTOR; if (priv->size_override) { LOG_INFO("%s, QSPI Flash size override = %u KiB in %u sectors", @@ -1180,7 +1187,7 @@ static int rp2040_flash_probe(struct flash_bank *bank) } free(bank->sectors); - bank->sectors = alloc_block_array(0, 4096, bank->num_sectors); + bank->sectors = alloc_block_array(0, RP2XXX_ROM_API_FIXED_FLASH_SECTOR, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; From c914cfceab54245fae1aefd70e20d0ed549f9308 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Aug 2024 10:47:36 +0200 Subject: [PATCH 27/55] flash/nor/rp2040: refactor finalizing calls and use them after erase Invalidate cache and restore flash XIP mode after erase and also in error cleanup after write/erase. Signed-off-by: Tomas Vanek Change-Id: If7e0c2d75f50f923e6bcbf0aa7bab53fe91b6cc8 Reviewed-on: https://review.openocd.org/c/openocd/+/8454 Tested-by: jenkins --- src/flash/nor/rp2040.c | 78 +++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index c28bc85096..514cea8b69 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -732,6 +732,42 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2040_flash_ba return ERROR_OK; } +static int rp2xxx_invalidate_cache_restore_xip(struct target *target, struct rp2040_flash_bank *priv) +{ + // Flash content has changed. We can now do a bit of poking to make + // the new flash contents visible to us via memory-mapped (XIP) interface + // in the 0x1... memory region. + + LOG_DEBUG("Flushing flash cache after write behind"); + + rp2xxx_rom_call_batch_record_t finishing_calls[2] = { + { + .pc = priv->jump_flush_cache, + .sp = priv->stack->address + priv->stack->size + }, + { + .sp = priv->stack->address + priv->stack->size + }, + }; + + int num_finishing_calls = 1; + // Note on RP2350 it's not *required* to call flash_enter_cmd_xip, since + // the ROM leaves flash XIPable by default in between direct-mode + // accesses + if (IS_RP2040(priv->id)) { + finishing_calls[num_finishing_calls++].pc = priv->jump_enter_cmd_xip; + } else if (priv->jump_flash_reset_address_trans) { + // Note flash_reset_address_trans function does not exist on older devices + finishing_calls[num_finishing_calls++].pc = priv->jump_flash_reset_address_trans; + } + + int retval = rp2xxx_call_rom_func_batch(target, priv, finishing_calls, num_finishing_calls); + if (retval != ERROR_OK) + LOG_ERROR("RP2040 write: failed to flush flash cache/restore XIP"); + + return retval; +} + static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2040_flash_bank *priv) { /* OpenOCD is prone to trashing work-area allocations on target state @@ -805,45 +841,12 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui count -= write_size; } - if (err != ERROR_OK) - goto cleanup_and_return; - - // Flash is successfully programmed. We can now do a bit of poking to make - // the new flash contents visible to us via memory-mapped (XIP) interface - // in the 0x1... memory region. - // - // Note on RP2350 it's not *required* to call flash_enter_cmd_xip, since - // the ROM leaves flash XIPable by default in between direct-mode - // accesses, but there's no harm in calling it anyway. - - LOG_DEBUG("Flushing flash cache after write behind"); - err = rp2xxx_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0); - - rp2xxx_rom_call_batch_record_t finishing_calls[3] = { - { - .pc = priv->jump_flush_cache, - .sp = priv->stack->address + priv->stack->size - }, - { - .pc = priv->jump_enter_cmd_xip, - .sp = priv->stack->address + priv->stack->size - }, - { - .pc = priv->jump_flash_reset_address_trans, - .sp = priv->stack->address + priv->stack->size - } - }; - // Note the last function does not exist on older devices: - int num_finishing_calls = priv->jump_flash_reset_address_trans ? 3 : 2; - - err = rp2xxx_call_rom_func_batch(target, priv, finishing_calls, num_finishing_calls); - if (err != ERROR_OK) { - LOG_ERROR("RP2040 write: failed to flush flash cache"); - goto cleanup_and_return; - } cleanup_and_return: target_free_working_area(target, bounce); + /* Don't propagate error or user gets fooled the flash write failed */ + (void)rp2xxx_invalidate_cache_restore_xip(target, priv); + cleanup_after_raw_flash_cmd(target, priv); return err; } @@ -912,6 +915,9 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig cleanup_and_return: + /* Don't propagate error or user gets fooled the flash erase failed */ + (void)rp2xxx_invalidate_cache_restore_xip(target, priv); + cleanup_after_raw_flash_cmd(target, priv); return err; } From 63f94bbab864d78e19ff86eda0836a5ff35b4a1b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Aug 2024 11:29:21 +0200 Subject: [PATCH 28/55] flash/nor/rp2040: refactoring: change rp2040 to rp2xxx While on it use calloc() instead of malloc()/memset() Drop useless implementation of rp2040_flash_free_driver_priv() - exactly same as default_flash_free_driver_priv() Code style fixes forced by checkpatch Signed-off-by: Tomas Vanek Change-Id: I5c56c4a7d586c0dcab164a45e8f6200ea9a3bd1d Reviewed-on: https://review.openocd.org/c/openocd/+/8455 Tested-by: jenkins --- src/flash/nor/Makefile.am | 2 +- src/flash/nor/driver.h | 2 +- src/flash/nor/drivers.c | 2 +- src/flash/nor/{rp2040.c => rp2xxx.c} | 102 ++++++++++++--------------- tcl/target/rp2040.cfg | 2 +- tcl/target/rp2350.cfg | 2 +- 6 files changed, 52 insertions(+), 60 deletions(-) rename src/flash/nor/{rp2040.c => rp2xxx.c} (94%) diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 147807fbaa..7a81b282b6 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -59,7 +59,7 @@ NOR_DRIVERS = \ %D%/psoc6.c \ %D%/qn908x.c \ %D%/renesas_rpchf.c \ - %D%/rp2040.c \ + %D%/rp2xxx.c \ %D%/rsl10.c \ %D%/sfdp.c \ %D%/sh_qspi.c \ diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 794566f121..3b57ef9ff0 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -289,7 +289,7 @@ extern const struct flash_driver psoc5lp_nvl_flash; extern const struct flash_driver psoc6_flash; extern const struct flash_driver qn908x_flash; extern const struct flash_driver renesas_rpchf_flash; -extern const struct flash_driver rp2040_flash; +extern const struct flash_driver rp2xxx_flash; extern const struct flash_driver rsl10_flash; extern const struct flash_driver sh_qspi_flash; extern const struct flash_driver sim3x_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 67d86243b7..3770bfbd3c 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -66,7 +66,7 @@ static const struct flash_driver * const flash_drivers[] = { &psoc6_flash, &qn908x_flash, &renesas_rpchf_flash, - &rp2040_flash, + &rp2xxx_flash, &sh_qspi_flash, &sim3x_flash, &stellaris_flash, diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2xxx.c similarity index 94% rename from src/flash/nor/rp2040.c rename to src/flash/nor/rp2xxx.c index 514cea8b69..e58fc8a29b 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2xxx.c @@ -185,14 +185,14 @@ typedef struct rp2xxx_rom_call_batch_record { uint32_t args[4]; } rp2xxx_rom_call_batch_record_t; -struct rp2040_flash_bank { +struct rp2xxx_flash_bank { bool probed; /* flag indicating successful flash probe */ uint32_t id; /* cached SYSINFO CHIP_ID */ struct working_area *stack; /* stack used by Boot ROM calls */ /* static code scratchpad used for RAM algorithms -- allocated in advance so that higher-level calls can just grab all remaining workarea: */ struct working_area *ram_algo_space; - /* function jump table populated by rp2040_flash_probe() */ + /* function jump table populated by rp2xxx_flash_probe() */ uint16_t jump_flash_exit_xip; uint16_t jump_connect_internal_flash; uint16_t jump_flash_range_erase; @@ -381,7 +381,7 @@ static int rp2xxx_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ return ERROR_FAIL; } -static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2040_flash_bank *priv) +static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2xxx_flash_bank *priv) { const uint16_t symtype_func = is_arm(target_to_arm(target)) ? RT_FLAG_FUNC_ARM_SEC : RT_FLAG_FUNC_RISCV; @@ -444,7 +444,7 @@ static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp204 // Call a list of PC + SP + r0-r3 function call tuples with a single OpenOCD // algorithm invocation, to amortise the algorithm overhead over multiple calls: -static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2040_flash_bank *priv, +static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash_bank *priv, rp2xxx_rom_call_batch_record_t *calls, unsigned int n_calls) { // Note +1 is for the null terminator @@ -556,7 +556,7 @@ static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2040_flash } // Call a single ROM function, using the default algorithm stack. -static int rp2xxx_call_rom_func(struct target *target, struct rp2040_flash_bank *priv, +static int rp2xxx_call_rom_func(struct target *target, struct rp2xxx_flash_bank *priv, uint16_t func_offset, uint32_t argdata[], unsigned int n_args) { assert(n_args <= 4); /* only allow register arguments -- capped at just 4 on Arm */ @@ -602,7 +602,7 @@ static int rp2350_init_accessctrl(struct target *target) return ERROR_OK; } -static int rp2350_init_arm_core0(struct target *target, struct rp2040_flash_bank *priv) +static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank *priv) { // Flash algorithms (and the RCP init stub called by this function) must // run in the Secure state, so flip the state now before attempting to @@ -661,7 +661,7 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2040_flash_bank return err; } -static int setup_for_raw_flash_cmd(struct target *target, struct rp2040_flash_bank *priv) +static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_bank *priv) { int err = ERROR_OK; @@ -725,14 +725,14 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2040_flash_ba }; err = rp2xxx_call_rom_func_batch(target, priv, calls, 2); if (err != ERROR_OK) { - LOG_ERROR("RP2040 flash: failed to exit flash XIP mode"); + LOG_ERROR("RP2xxx flash: failed to exit flash XIP mode"); return err; } return ERROR_OK; } -static int rp2xxx_invalidate_cache_restore_xip(struct target *target, struct rp2040_flash_bank *priv) +static int rp2xxx_invalidate_cache_restore_xip(struct target *target, struct rp2xxx_flash_bank *priv) { // Flash content has changed. We can now do a bit of poking to make // the new flash contents visible to us via memory-mapped (XIP) interface @@ -763,12 +763,12 @@ static int rp2xxx_invalidate_cache_restore_xip(struct target *target, struct rp2 int retval = rp2xxx_call_rom_func_batch(target, priv, finishing_calls, num_finishing_calls); if (retval != ERROR_OK) - LOG_ERROR("RP2040 write: failed to flush flash cache/restore XIP"); + LOG_ERROR("RP2xxx: failed to flush flash cache/restore XIP"); return retval; } -static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2040_flash_bank *priv) +static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2xxx_flash_bank *priv) { /* OpenOCD is prone to trashing work-area allocations on target state transitions, which leaves us with stale work area pointers in our @@ -785,11 +785,11 @@ static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2040_fla } } -static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +static int rp2xxx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset); - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; if (target->state != TARGET_HALTED) { @@ -851,9 +851,9 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui return err; } -static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +static int rp2xxx_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; if (target->state != TARGET_HALTED) { @@ -863,7 +863,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig uint32_t start_addr = bank->sectors[first].offset; uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; - LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr); + LOG_DEBUG("erase %d bytes starting at 0x%" PRIx32, length, start_addr); int err = setup_for_raw_flash_cmd(target, priv); if (err != ERROR_OK) @@ -1064,7 +1064,7 @@ static int rp2xxx_spi_tx_rx(struct flash_bank *bank, unsigned int dummy_len, uint8_t *rx, unsigned int rx_len) { - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; if (IS_RP2040(priv->id)) @@ -1078,7 +1078,7 @@ static int rp2xxx_spi_tx_rx(struct flash_bank *bank, static int rp2xxx_read_sfdp_block(struct flash_bank *bank, uint32_t addr, unsigned int words, uint32_t *buffer) { - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; uint8_t cmd[4] = { SPIFLASH_READ_SFDP }; uint8_t data[4 * words + priv->sfdp_dummy_detect]; @@ -1106,9 +1106,9 @@ static int rp2xxx_read_sfdp_block(struct flash_bank *bank, uint32_t addr, return retval; } -static int rp2040_flash_probe(struct flash_bank *bank) +static int rp2xxx_flash_probe(struct flash_bank *bank) { - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; int retval = target_read_u32(target, RP2XXX_SYSINFO_CHIP_ID, &priv->id); @@ -1202,31 +1202,23 @@ static int rp2040_flash_probe(struct flash_bank *bank) return ERROR_OK; } -static int rp2040_flash_auto_probe(struct flash_bank *bank) +static int rp2xxx_flash_auto_probe(struct flash_bank *bank) { - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; if (priv->probed) return ERROR_OK; - return rp2040_flash_probe(bank); -} - -static void rp2040_flash_free_driver_priv(struct flash_bank *bank) -{ - free(bank->driver_priv); - bank->driver_priv = NULL; + return rp2xxx_flash_probe(bank); } /* ----------------------------------------------------------------------------- Driver boilerplate */ -FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) +FLASH_BANK_COMMAND_HANDLER(rp2xxx_flash_bank_command) { - struct rp2040_flash_bank *priv; - priv = malloc(sizeof(struct rp2040_flash_bank)); - memset(priv, 0, sizeof(struct rp2040_flash_bank)); - priv->probed = false; + struct rp2xxx_flash_bank *priv; + priv = calloc(1, sizeof(struct rp2xxx_flash_bank)); priv->size_override = bank->size != 0; /* Set up driver_priv */ @@ -1236,7 +1228,7 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) } -COMMAND_HANDLER(rp2040_rom_api_call_handler) +COMMAND_HANDLER(rp2xxx_rom_api_call_handler) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1245,7 +1237,7 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler) struct flash_bank *bank; for (bank = flash_bank_list(); bank; bank = bank->next) { - if (bank->driver != &rp2040_flash) + if (bank->driver != &rp2xxx_flash) continue; if (bank->target == target) @@ -1258,7 +1250,7 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler) return ERROR_FAIL; } - int retval = rp2040_flash_auto_probe(bank); + int retval = rp2xxx_flash_auto_probe(bank); if (retval != ERROR_OK) { command_print(CMD, "auto_probe failed"); return retval; @@ -1275,7 +1267,7 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler) return ERROR_TARGET_NOT_HALTED; } - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; retval = setup_for_raw_flash_cmd(target, priv); if (retval != ERROR_OK) goto cleanup_and_return; @@ -1304,7 +1296,7 @@ COMMAND_HANDLER(rp2040_rom_api_call_handler) return retval; } -COMMAND_HANDLER(rp2040_switch_target_handler) +COMMAND_HANDLER(rp2xxx_switch_target_handler) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; @@ -1323,10 +1315,10 @@ COMMAND_HANDLER(rp2040_switch_target_handler) struct flash_bank *bank; for (bank = flash_bank_list(); bank; bank = bank->next) { - if (bank->driver == &rp2040_flash) { + if (bank->driver == &rp2xxx_flash) { if (bank->target == old_target) { bank->target = new_target; - struct rp2040_flash_bank *priv = bank->driver_priv; + struct rp2xxx_flash_bank *priv = bank->driver_priv; priv->probed = false; return ERROR_OK; } else if (bank->target == new_target) { @@ -1340,44 +1332,44 @@ COMMAND_HANDLER(rp2040_switch_target_handler) return ERROR_FAIL; } -static const struct command_registration rp2040_exec_command_handlers[] = { +static const struct command_registration rp2xxx_exec_command_handlers[] = { { .name = "rom_api_call", .mode = COMMAND_EXEC, .help = "arbitrary ROM API call", .usage = "fc [p0 [p1 [p2 [p3]]]]", - .handler = rp2040_rom_api_call_handler, + .handler = rp2xxx_rom_api_call_handler, }, { .name = "_switch_target", .mode = COMMAND_EXEC, .help = "internal use", .usage = "old_target new_target", - .handler = rp2040_switch_target_handler, + .handler = rp2xxx_switch_target_handler, }, COMMAND_REGISTRATION_DONE }; -static const struct command_registration rp2040_command_handler[] = { +static const struct command_registration rp2xxx_command_handler[] = { { .name = "rp2xxx", .mode = COMMAND_ANY, .help = "rp2xxx flash controller commands", .usage = "", - .chain = rp2040_exec_command_handlers, + .chain = rp2xxx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; -const struct flash_driver rp2040_flash = { - .name = "rp2040_flash", - .commands = rp2040_command_handler, - .flash_bank_command = rp2040_flash_bank_command, - .erase = rp2040_flash_erase, - .write = rp2040_flash_write, +const struct flash_driver rp2xxx_flash = { + .name = "rp2xxx", + .commands = rp2xxx_command_handler, + .flash_bank_command = rp2xxx_flash_bank_command, + .erase = rp2xxx_flash_erase, + .write = rp2xxx_flash_write, .read = default_flash_read, - .probe = rp2040_flash_probe, - .auto_probe = rp2040_flash_auto_probe, + .probe = rp2xxx_flash_probe, + .auto_probe = rp2xxx_flash_auto_probe, .erase_check = default_flash_blank_check, - .free_driver_priv = rp2040_flash_free_driver_priv + .free_driver_priv = default_flash_free_driver_priv }; diff --git a/tcl/target/rp2040.cfg b/tcl/target/rp2040.cfg index 5e78c69310..5fae390b41 100644 --- a/tcl/target/rp2040.cfg +++ b/tcl/target/rp2040.cfg @@ -99,7 +99,7 @@ if { $_USE_CORE == 1 } { # The flash is probed during gdb connect if gdb memory_map is enabled (by default). $_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE -work-area-backup 1 set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME rp2040_flash 0x10000000 0 0 0 $_FLASH_TARGET +flash bank $_FLASHNAME rp2xxx 0x10000000 0 0 0 $_FLASH_TARGET if { $_BOTH_CORES } { # Alias to ensure gdb connecting to core 1 gets the correct memory map diff --git a/tcl/target/rp2350.cfg b/tcl/target/rp2350.cfg index dc26cde190..b7617acd4c 100644 --- a/tcl/target/rp2350.cfg +++ b/tcl/target/rp2350.cfg @@ -160,7 +160,7 @@ if { [info exists _FLASH_TARGET] } { echo "Info : $_CHIPNAME.flash will be handled by the active one of $_FLASH_TARGET and $_TARGETNAME_RV0 cores" } set _FLASHNAME $_CHIPNAME.flash - flash bank $_FLASHNAME rp2040_flash 0x10000000 $_FLASHSIZE 0 0 $_FLASH_TARGET + flash bank $_FLASHNAME rp2xxx 0x10000000 $_FLASHSIZE 0 0 $_FLASH_TARGET } if { [info exists _TARGETNAME_1] } { From 9fce121366c86e77e84b9d20c7d1c7dbb38710d5 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Aug 2024 17:14:17 +0200 Subject: [PATCH 29/55] doc: document changes in rp2xxx flash driver Namely the driver name changed from rp2040_flash and added RP2350 support. Signed-off-by: Tomas Vanek Change-Id: I2ec9e62786002d71f655dbe0edc9f2e9ac4141b7 Reviewed-on: https://review.openocd.org/c/openocd/+/8456 Tested-by: jenkins --- doc/openocd.texi | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 9ff524b749..32a2895ecf 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7872,15 +7872,29 @@ locked, but can still mass erase the whole flash. @end deffn @end deffn -@deffn {Flash Driver} {rp2040} -Supports RP2040 "Raspberry Pi Pico" microcontroller. -RP2040 is a dual-core device with two CM0+ cores. Both cores share the same -Flash/RAM/MMIO address space. Non-volatile storage is achieved with an -external QSPI flash; a Boot ROM provides helper functions. +@deffn {Flash Driver} {rp2xxx} +Supports RP2040 "Raspberry Pi Pico" microcontroller and RP2350 Pico 2 +RP2040 is a dual-core device with two CM0+ cores. +RP2350 is a dual-core device with two slots switched to either Cortex-M33 +or Hazard3 RISC-V core. +Both cores share the same Flash/RAM/MMIO address space. +Non-volatile storage is achieved with an external QSPI flash; +a Boot ROM provides helper functions. @example -flash bank $_FLASHNAME rp2040_flash $_FLASHBASE $_FLASHSIZE 1 32 $_TARGETNAME +flash bank $_FLASHNAME rp2xxx $_FLASHBASE $_FLASHSIZE 0 0 $_TARGETNAME @end example + +@deffn {Command} {rp2xxx rom_api_call} fc [p0 [p1 [p2 [p3]]]] +A utility for calling ROM API function with two characters lookup code +@var{fc} and up to 4 optional parameters @var{p0 p1 p2 p3}. +The call is supported on the target where the flash bank is configured +(core0). +@end deffn + +@deffn {Command} {rp2xxx _switch_target} old_target new_target +A command used internally by rp2350.cfg when the core type is switched. +@end deffn @end deffn @deffn {Flash Driver} {rsl10} From d29c1c6d6df31f64ae5593babc65cfdffa312def Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Aug 2024 17:43:13 +0200 Subject: [PATCH 30/55] flash/nor/rp2xxx: minor code improvements Add error messages and proper error propagation. Type cleaning. Use saved chip id. Cosmetics: separating lines added. Signed-off-by: Tomas Vanek Change-Id: I151e684e1fbfc9476ec429036caf85f4c9329547 Reviewed-on: https://review.openocd.org/c/openocd/+/8457 Tested-by: jenkins Reviewed-by: Jonathan Bell --- src/flash/nor/rp2xxx.c | 49 +++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index e58fc8a29b..909d3f14d6 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -233,11 +233,13 @@ static int rp2040_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ err = target_read_u16(target, ptr_to_entry, &entry_tag); if (err != ERROR_OK) return err; + if (entry_tag == tag) { /* 16 bit symbol is next */ err = target_read_u16(target, ptr_to_entry + 2, symbol_out); if (err != ERROR_OK) return err; + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); return ERROR_OK; } @@ -277,10 +279,12 @@ static int rp2350_a0_lookup_symbol(struct target *target, uint16_t tag, uint16_t err = target_read_u16(target, ptr_to_entry, &entry_tag); if (err != ERROR_OK) return err; + if (entry_tag == tag) { err = target_read_u16(target, ptr_to_entry + 2, symbol_out); if (err != ERROR_OK) return err; + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); return ERROR_OK; } @@ -303,9 +307,10 @@ static int rp2350_lookup_rom_symbol(struct target *target, uint32_t ptr_to_entry while (true) { uint16_t entry_tag, entry_flags; - uint32_t err = target_read_u16(target, ptr_to_entry, &entry_tag); + int err = target_read_u16(target, ptr_to_entry, &entry_tag); if (err != ERROR_OK) return err; + if (entry_tag == 0) { *symbol_out = 0; return ERROR_FAIL; @@ -315,6 +320,7 @@ static int rp2350_lookup_rom_symbol(struct target *target, uint32_t ptr_to_entry err = target_read_u16(target, ptr_to_entry, &entry_flags); if (err != ERROR_OK) return err; + ptr_to_entry += 2; uint16_t matching_flags = flags & entry_flags; @@ -338,6 +344,7 @@ static int rp2350_lookup_rom_symbol(struct target *target, uint32_t ptr_to_entry err = target_read_u16(target, ptr_to_entry, symbol_out); if (err != ERROR_OK) return err; + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); return ERROR_OK; } @@ -426,18 +433,23 @@ static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2xx // From this point are optional functions which do not exist on e.g. RP2040 // or pre-production RP2350 ROM versions: + if (IS_RP2040(priv->id)) { + priv->jump_bootrom_reset_state = 0; + priv->jump_flash_reset_address_trans = 0; + return ERROR_OK; + } err = rp2xxx_lookup_rom_symbol(target, FUNC_BOOTROM_STATE_RESET, symtype_func, &priv->jump_bootrom_reset_state); if (err != ERROR_OK) { priv->jump_bootrom_reset_state = 0; - LOG_WARNING("Function FUNC_BOOTROM_STATE_RESET not found in RP2xxx ROM. (probably an RP2040 or an RP2350 A0)"); + LOG_WARNING("Function FUNC_BOOTROM_STATE_RESET not found in RP2xxx ROM. (probably an RP2350 A0)"); } err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RESET_ADDRESS_TRANS, symtype_func, &priv->jump_flash_reset_address_trans); if (err != ERROR_OK) { priv->jump_flash_reset_address_trans = 0; - LOG_WARNING("Function FUNC_FLASH_RESET_ADDRESS_TRANS not found in RP2xxx ROM. (probably an RP2040 or an RP2350 A0)"); + LOG_WARNING("Function FUNC_FLASH_RESET_ADDRESS_TRANS not found in RP2xxx ROM. (probably an RP2350 A0)"); } return ERROR_OK; } @@ -465,7 +477,7 @@ static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash for (unsigned int i = 0; i < n_calls; ++i) { LOG_DEBUG(" func @ %" PRIx32, calls[i].pc); LOG_DEBUG(" sp = %" PRIx32, calls[i].sp); - for (int j = 0; j < 4; ++j) + for (unsigned int j = 0; j < 4; ++j) LOG_DEBUG(" a%d = %" PRIx32, j, calls[i].args[j]); } LOG_DEBUG("Calling on core \"%s\"", target->cmd_name); @@ -607,14 +619,22 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank // Flash algorithms (and the RCP init stub called by this function) must // run in the Secure state, so flip the state now before attempting to // execute any code on the core. + int retval; uint32_t dscsr; - (void)target_read_u32(target, DCB_DSCSR, &dscsr); + retval = target_read_u32(target, DCB_DSCSR, &dscsr); + if (retval != ERROR_OK) { + LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); + return retval; + } + LOG_DEBUG("DSCSR: %08x\n", dscsr); if (!(dscsr & DSCSR_CDS)) { LOG_DEBUG("Setting Current Domain Secure in DSCSR\n"); - (void)target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); - (void)target_read_u32(target, DCB_DSCSR, &dscsr); - LOG_DEBUG("DSCSR*: %08x\n", dscsr); + retval = target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); + if (retval != ERROR_OK) { + LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); + return retval; + } } if (!priv->stack) { @@ -682,8 +702,7 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba } } - // hacky RP2350 check -- either RISC-V or v8-M - if (is_arm(target_to_arm(target)) ? target_to_arm(target)->arch == ARM_ARCH_V8M : true) { + if (IS_RP2350(priv->id)) { err = rp2350_init_accessctrl(target); if (err != ERROR_OK) { LOG_ERROR("Failed to init ACCESSCTRL before ROM call"); @@ -861,16 +880,16 @@ static int rp2xxx_flash_erase(struct flash_bank *bank, unsigned int first, unsig return ERROR_TARGET_NOT_HALTED; } - uint32_t start_addr = bank->sectors[first].offset; - uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr; - LOG_DEBUG("erase %d bytes starting at 0x%" PRIx32, length, start_addr); + uint32_t offset_start = bank->sectors[first].offset; + uint32_t offset_last = bank->sectors[last].offset + bank->sectors[last].size; + uint32_t length = offset_last - offset_start; + LOG_DEBUG("erase %d bytes starting at 0x%" PRIx32, length, offset_start); int err = setup_for_raw_flash_cmd(target, priv); if (err != ERROR_OK) goto cleanup_and_return; - uint32_t offset_next = bank->sectors[first].offset; - uint32_t offset_last = bank->sectors[last].offset + bank->sectors[last].size; + uint32_t offset_next = offset_start; /* Break erase into multiple calls to avoid timeout on large erase. Choose 128k chunk which has fairly low ROM call overhead and empirically seems to avoid the default keep_alive() limit From a9608871692be6cda4d73ae837b4313747370ff8 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 16 Aug 2024 22:53:36 +0200 Subject: [PATCH 31/55] flash/nor/rp2xxx: drop couple of Java-like const The compiler knows what variable remains constant during its lifetime and there is no need to emphasise constantness. Change-Id: Ib515f96a3c77afea87274f33b8ccac7a71bfb932 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/8459 Tested-by: jenkins Reviewed-by: Jonathan Bell --- src/flash/nor/rp2xxx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index 909d3f14d6..5d0255b61e 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -223,7 +223,7 @@ static int rp2040_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ } uint16_t ptr_to_entry; - const unsigned int offset_magic_to_table_ptr = flags == RT_FLAG_DATA ? 6 : 4; + unsigned int offset_magic_to_table_ptr = flags == RT_FLAG_DATA ? 6 : 4; int err = target_read_u16(target, BOOTROM_MAGIC_ADDR + offset_magic_to_table_ptr, &ptr_to_entry); if (err != ERROR_OK) return err; @@ -390,8 +390,8 @@ static int rp2xxx_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2xxx_flash_bank *priv) { - const uint16_t symtype_func = is_arm(target_to_arm(target)) - ? RT_FLAG_FUNC_ARM_SEC : RT_FLAG_FUNC_RISCV; + uint16_t symtype_func = is_arm(target_to_arm(target)) + ? RT_FLAG_FUNC_ARM_SEC : RT_FLAG_FUNC_RISCV; int err; err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_EXIT_XIP, symtype_func, &priv->jump_flash_exit_xip); From f039fe7f9d1ecfc1ca25574d5527c35db119e77b Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 16 Aug 2024 23:35:06 +0200 Subject: [PATCH 32/55] flash/nor/rp2xxx: fix endianness error struct rp2xxx_rom_call_batch_record consists of uint32_t in the host endianness. Therefore it should be converted to the target endianness not just simply copied by target_write_buffer(). Concatenate algo code, converted batch records and terminator to the host resident buffer and copy it at once to the target and save some adapter turnaround times. While on it remove typedef rp2xxx_rom_call_batch_record_t Change-Id: I0e698396003869bee5dde4141d48ddd7d62b3cbc Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/8460 Reviewed-by: Jonathan Bell Tested-by: jenkins --- src/flash/nor/rp2xxx.c | 59 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index 5d0255b61e..fce501703d 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -179,11 +179,11 @@ static const uint8_t rp2xxx_rom_call_batch_algo_riscv[ROM_CALL_BATCH_ALGO_SIZE_B // <_args>: }; -typedef struct rp2xxx_rom_call_batch_record { +struct rp2xxx_rom_call_batch_record { uint32_t pc; uint32_t sp; uint32_t args[4]; -} rp2xxx_rom_call_batch_record_t; +}; struct rp2xxx_flash_bank { bool probed; /* flag indicating successful flash probe */ @@ -457,18 +457,18 @@ static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2xx // Call a list of PC + SP + r0-r3 function call tuples with a single OpenOCD // algorithm invocation, to amortise the algorithm overhead over multiple calls: static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash_bank *priv, - rp2xxx_rom_call_batch_record_t *calls, unsigned int n_calls) + struct rp2xxx_rom_call_batch_record *calls, unsigned int n_calls) { - // Note +1 is for the null terminator - unsigned int batch_words = 1 + (ROM_CALL_BATCH_ALGO_SIZE_BYTES + - n_calls * sizeof(rp2xxx_rom_call_batch_record_t) - ) / sizeof(uint32_t); + // Note + sizeof(uint32_t) is for the null terminator + unsigned int batch_size = ROM_CALL_BATCH_ALGO_SIZE_BYTES + + n_calls * sizeof(struct rp2xxx_rom_call_batch_record) + + sizeof(uint32_t); if (!priv->ram_algo_space) { LOG_ERROR("No RAM code space allocated for ROM call"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - if (priv->ram_algo_space->size < batch_words * sizeof(uint32_t)) { + if (priv->ram_algo_space->size < batch_size) { LOG_ERROR("RAM code space too small for call batch size of %u\n", n_calls); return ERROR_BUF_TOO_SMALL; } @@ -501,32 +501,31 @@ static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash algo_code = rp2xxx_rom_call_batch_algo_riscv; } + uint8_t *batch_bf = malloc(batch_size); + if (!batch_bf) { + LOG_ERROR("No memory for batch buffer"); + return ERROR_FAIL; + } + memcpy(batch_bf, algo_code, ROM_CALL_BATCH_ALGO_SIZE_BYTES); + unsigned int words = n_calls * sizeof(struct rp2xxx_rom_call_batch_record) + / sizeof(uint32_t); + target_buffer_set_u32_array(target, + &batch_bf[ROM_CALL_BATCH_ALGO_SIZE_BYTES], words, + (const uint32_t *)calls); + /* Null terminator */ + target_buffer_set_u32(target, &batch_bf[batch_size - sizeof(uint32_t)], 0); + int err = target_write_buffer(target, priv->ram_algo_space->address, - ROM_CALL_BATCH_ALGO_SIZE_BYTES, - algo_code + batch_size, + batch_bf ); + free(batch_bf); + if (err != ERROR_OK) { LOG_ERROR("Failed to write ROM batch algorithm to RAM code space\n"); return err; } - err = target_write_buffer(target, - priv->ram_algo_space->address + ROM_CALL_BATCH_ALGO_SIZE_BYTES, - n_calls * sizeof(rp2xxx_rom_call_batch_record_t), - (const uint8_t *)calls - ); - if (err != ERROR_OK) { - LOG_ERROR("Failed to write ROM batch records to RAM code space\n"); - return err; - } - err = target_write_u32(target, - priv->ram_algo_space->address + (batch_words - 1) * sizeof(uint32_t), - 0 - ); - if (err != ERROR_OK) { - LOG_ERROR("Failed to write null terminator for ROM batch records\n"); - return err; - } // Call into the ROM batch algorithm -- this will in turn call each ROM // call specified by the batch records. @@ -579,7 +578,7 @@ static int rp2xxx_call_rom_func(struct target *target, struct rp2xxx_flash_bank } target_addr_t stacktop = priv->stack->address + priv->stack->size; - rp2xxx_rom_call_batch_record_t call = { + struct rp2xxx_rom_call_batch_record call = { .pc = func_offset, .sp = stacktop }; @@ -732,7 +731,7 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba } LOG_DEBUG("Connecting flash IOs and issuing XIP exit sequence to flash"); - rp2xxx_rom_call_batch_record_t calls[2] = { + struct rp2xxx_rom_call_batch_record calls[2] = { { .pc = priv->jump_connect_internal_flash, .sp = priv->stack->address + priv->stack->size @@ -759,7 +758,7 @@ static int rp2xxx_invalidate_cache_restore_xip(struct target *target, struct rp2 LOG_DEBUG("Flushing flash cache after write behind"); - rp2xxx_rom_call_batch_record_t finishing_calls[2] = { + struct rp2xxx_rom_call_batch_record finishing_calls[2] = { { .pc = priv->jump_flush_cache, .sp = priv->stack->address + priv->stack->size From 376d11c2e38303094976186d59502ab7d3073452 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sat, 17 Aug 2024 16:21:06 +0200 Subject: [PATCH 33/55] tcl/target/rp2040: add flash size override and reset init event Allow flash size override and suppress flash size detection by setting FLASHSIZE Tcl variable. reset-init event calls 'connect XIP' ROM API function to make flash content accessible at the XIP mapping memory area. Ported from rp2350.cfg Change-Id: I9b352b1ef6d4c6d4b78a6b61e900ce01355c8eff Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/8461 Reviewed-by: Jonathan Bell Tested-by: jenkins --- tcl/target/rp2040.cfg | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tcl/target/rp2040.cfg b/tcl/target/rp2040.cfg index 5fae390b41..f64d4322b1 100644 --- a/tcl/target/rp2040.cfg +++ b/tcl/target/rp2040.cfg @@ -20,6 +20,14 @@ if { [info exists WORKAREASIZE] } { set _WORKAREASIZE 0x10000 } +# Nonzero FLASHSIZE supresses QSPI flash size detection +if { [info exists FLASHSIZE] } { + set _FLASHSIZE $FLASHSIZE +} else { + # Detect QSPI flash size based on flash ID or SFDP + set _FLASHSIZE 0 +} + if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { @@ -74,6 +82,10 @@ if { $_USE_CORE != 1 } { target create $_TARGETNAME_0 cortex_m -dap $_CHIPNAME.dap0 -coreid 0 # srst does not exist; use SYSRESETREQ to perform a soft reset $_TARGETNAME_0 cortex_m reset_config sysresetreq + + # After a rescue reset and fi BOOTSEL is halted connect the flash to enable + # reads from the XIP cached mapping area + $_TARGETNAME_0 configure -event reset-init { rp2xxx rom_api_call 0 CX } } # core 1 @@ -95,11 +107,11 @@ if { $_USE_CORE == 1 } { } else { set _FLASH_TARGET $_TARGETNAME_0 } -# Backup the work area. The flash probe runs an algorithm on the target CPU. -# The flash is probed during gdb connect if gdb memory_map is enabled (by default). -$_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE -work-area-backup 1 +# QSPI flash size detection during gdb connect requires to back-up RAM +set _WKA_BACKUP [expr { $_FLASHSIZE == 0 }] +$_FLASH_TARGET configure -work-area-phys 0x20010000 -work-area-size $_WORKAREASIZE -work-area-backup $_WKA_BACKUP set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME rp2xxx 0x10000000 0 0 0 $_FLASH_TARGET +flash bank $_FLASHNAME rp2xxx 0x10000000 $_FLASHSIZE 0 0 $_FLASH_TARGET if { $_BOTH_CORES } { # Alias to ensure gdb connecting to core 1 gets the correct memory map From 5bb7dbc2312f4ce84224720eb258ebcae2089e28 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 13 Dec 2024 21:56:45 +0100 Subject: [PATCH 34/55] flash/nor/rp2xxx: fix flash operation after halt in RISC-V bootsel Calling ROM API set_bootrom_stack() function allows ROM API functionality after OpenOCD halt or reset halt in RISC-V bootloder (emulated ARM code) Change-Id: I3b255738d61876e876a94207804d9cbe1a7593c2 Signed-off-by: Tomas Vanek Signed-off-by: Luke Wren Reviewed-on: https://review.openocd.org/c/openocd/+/8729 Tested-by: jenkins --- src/flash/nor/rp2xxx.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index fce501703d..280f077c1c 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -26,6 +26,7 @@ #define FUNC_FLASH_FLUSH_CACHE MAKE_TAG('F', 'C') #define FUNC_FLASH_ENTER_CMD_XIP MAKE_TAG('C', 'X') #define FUNC_BOOTROM_STATE_RESET MAKE_TAG('S', 'R') +#define FUNC_BOOTROM_SET_STACK MAKE_TAG('S', 'S') #define FUNC_FLASH_RESET_ADDRESS_TRANS MAKE_TAG('R', 'A') /* ROM table flags for RP2350 A1 ROM onwards */ @@ -201,6 +202,7 @@ struct rp2xxx_flash_bank { uint16_t jump_flash_reset_address_trans; uint16_t jump_enter_cmd_xip; uint16_t jump_bootrom_reset_state; + uint16_t jump_bootrom_set_varm_stack; char dev_name[20]; bool size_override; @@ -445,6 +447,15 @@ static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2xx LOG_WARNING("Function FUNC_BOOTROM_STATE_RESET not found in RP2xxx ROM. (probably an RP2350 A0)"); } + if (!is_arm(target_to_arm(target))) { + err = rp2xxx_lookup_rom_symbol(target, FUNC_BOOTROM_SET_STACK, symtype_func, + &priv->jump_bootrom_set_varm_stack); + if (err != ERROR_OK) { + priv->jump_bootrom_set_varm_stack = 0; + LOG_WARNING("Function FUNC_BOOTROM_SET_STACK not found in RP2xxx ROM. (probably an RP2350 A0)"); + } + } + err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RESET_ADDRESS_TRANS, symtype_func, &priv->jump_flash_reset_address_trans); if (err != ERROR_OK) { @@ -720,6 +731,9 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba if (!priv->jump_bootrom_reset_state) { LOG_WARNING("RP2350 flash: no bootrom_reset_method\n"); } else { + /* This is mainly required to clear varmulet_enclosing_cpu pointers on RISC-V, in case + an Arm -> RISC-V call has been interrupted (these pointers are used to handle + reentrant calls to the ROM emulator) */ LOG_DEBUG("Clearing core 0 ROM state"); err = rp2xxx_call_rom_func(target, priv, priv->jump_bootrom_reset_state, reset_args, ARRAY_SIZE(reset_args)); @@ -728,6 +742,39 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba return err; } } + if (!is_arm(target_to_arm(target)) && priv->jump_bootrom_set_varm_stack) { + /* Pass {0, 0} to set_varmulet_user_stack() to enable automatic emulation of Arm APIs + using the ROM's default stacks. Usually the bootrom does this before exiting to user + code, but it needs to be done manually when the USB bootloader has been interrupted. */ + LOG_DEBUG("Enabling default Arm emulator stacks for RISC-V ROM calls\n"); + struct working_area *set_stack_mem_args; + err = target_alloc_working_area(target, 2 * sizeof(uint32_t), &set_stack_mem_args); + if (err != ERROR_OK) { + LOG_ERROR("Failed to allocate memory for arguments to set_varmulet_user_stack()"); + return err; + } + + err = target_write_u32(target, set_stack_mem_args->address, 0); + if (err == ERROR_OK) + err = target_write_u32(target, set_stack_mem_args->address + 4, 0); + + if (err != ERROR_OK) { + LOG_ERROR("Failed to initialise memory arguments for set_varmulet_user_stack()"); + target_free_working_area(target, set_stack_mem_args); + return err; + } + + uint32_t set_stack_register_args[1] = { + set_stack_mem_args->address + }; + err = rp2xxx_call_rom_func(target, priv, priv->jump_bootrom_set_varm_stack, + set_stack_register_args, ARRAY_SIZE(set_stack_register_args)); + target_free_working_area(target, set_stack_mem_args); + if (err != ERROR_OK) { + LOG_ERROR("Failed to initialise Arm emulation stacks for RISC-V: 0x%08" PRIx32, err); + return err; + } + } } LOG_DEBUG("Connecting flash IOs and issuing XIP exit sequence to flash"); From bf66d95be2db83da2694d20970c4b8db8e5de969 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 21 Mar 2025 21:30:13 +0100 Subject: [PATCH 35/55] flash/nor/rp2xxx: fix LOG_xxx messages Use proper format specifiers for uint16_t and uint32_t arguments. Use LOG_TARGET_DEBUG instead of target->cmd_name as a parameter. Use command_print() in command handler. Drop dots and new lines at end of messages. Change-Id: I37c7d3680a352210b1d7e69f2c9b4ba0efe6ec15 Signed-off-by: Tomas Vanek Reported-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8809 Tested-by: jenkins --- src/flash/nor/rp2xxx.c | 63 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index 280f077c1c..2b22e52eb8 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -242,7 +242,7 @@ static int rp2040_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ if (err != ERROR_OK) return err; - LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04" PRIx16, *symbol_out); return ERROR_OK; } ptr_to_entry += 4; @@ -287,7 +287,7 @@ static int rp2350_a0_lookup_symbol(struct target *target, uint16_t tag, uint16_t if (err != ERROR_OK) return err; - LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04" PRIx16, *symbol_out); return ERROR_OK; } ptr_to_entry += 6; @@ -347,7 +347,7 @@ static int rp2350_lookup_rom_symbol(struct target *target, uint32_t ptr_to_entry if (err != ERROR_OK) return err; - LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04x", *symbol_out); + LOG_ROM_SYMBOL_DEBUG(" -> found: 0x%04" PRIx16, *symbol_out); return ERROR_OK; } /* Skip past this entry */ @@ -398,38 +398,38 @@ static int rp2xxx_populate_rom_pointer_cache(struct target *target, struct rp2xx err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_EXIT_XIP, symtype_func, &priv->jump_flash_exit_xip); if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2xxx ROM."); + LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2xxx ROM"); return err; } err = rp2xxx_lookup_rom_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, symtype_func, &priv->jump_connect_internal_flash); if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2xxx ROM."); + LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2xxx ROM"); return err; } err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RANGE_ERASE, symtype_func, &priv->jump_flash_range_erase); if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2xxx ROM."); + LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2xxx ROM"); return err; } err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_RANGE_PROGRAM, symtype_func, &priv->jump_flash_range_program); if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2xxx ROM."); + LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2xxx ROM"); return err; } err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_FLUSH_CACHE, symtype_func, &priv->jump_flush_cache); if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2xxx ROM."); + LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2xxx ROM"); return err; } err = rp2xxx_lookup_rom_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, symtype_func, &priv->jump_enter_cmd_xip); if (err != ERROR_OK) { - LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2xxx ROM."); + LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2xxx ROM"); return err; } @@ -480,18 +480,17 @@ static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (priv->ram_algo_space->size < batch_size) { - LOG_ERROR("RAM code space too small for call batch size of %u\n", n_calls); + LOG_ERROR("RAM code space too small for call batch size of %u", n_calls); return ERROR_BUF_TOO_SMALL; } - LOG_DEBUG("Calling batch of %u ROM functions:", n_calls); + LOG_TARGET_DEBUG(target, "Calling batch of %u ROM functions:", n_calls); for (unsigned int i = 0; i < n_calls; ++i) { LOG_DEBUG(" func @ %" PRIx32, calls[i].pc); LOG_DEBUG(" sp = %" PRIx32, calls[i].sp); for (unsigned int j = 0; j < 4; ++j) - LOG_DEBUG(" a%d = %" PRIx32, j, calls[i].args[j]); + LOG_DEBUG(" a%u = %" PRIx32, j, calls[i].args[j]); } - LOG_DEBUG("Calling on core \"%s\"", target->cmd_name); if (n_calls <= 0) { LOG_DEBUG("Returning early from call of 0 ROM functions"); @@ -534,7 +533,7 @@ static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash free(batch_bf); if (err != ERROR_OK) { - LOG_ERROR("Failed to write ROM batch algorithm to RAM code space\n"); + LOG_ERROR("Failed to write ROM batch algorithm to RAM code space"); return err; } @@ -565,7 +564,7 @@ static int rp2xxx_call_rom_func_batch(struct target *target, struct rp2xxx_flash ); } if (err != ERROR_OK) { - LOG_ERROR("Failed to call ROM function batch\n"); + LOG_ERROR("Failed to call ROM function batch"); /* This case is hit when loading new ROM images on FPGA, but can also be hit on real hardware if you swap two devices with different ROM versions without restarting OpenOCD: */ LOG_ROM_SYMBOL_DEBUG("Repopulating ROM address cache after failed ROM call"); @@ -616,9 +615,9 @@ static int rp2350_init_accessctrl(struct target *target) return ERROR_FAIL; } if (accessctrl_lock_reg & ACCESSCTRL_LOCK_DEBUG_BITS) { - LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail.\n"); + LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail"); } else { - LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET\n"); + LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET"); return target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); } return ERROR_OK; @@ -637,9 +636,9 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank return retval; } - LOG_DEBUG("DSCSR: %08x\n", dscsr); + LOG_DEBUG("DSCSR: 0x%08" PRIx32, dscsr); if (!(dscsr & DSCSR_CDS)) { - LOG_DEBUG("Setting Current Domain Secure in DSCSR\n"); + LOG_DEBUG("Setting Current Domain Secure in DSCSR"); retval = target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); if (retval != ERROR_OK) { LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); @@ -664,12 +663,12 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank rcp_init_code ); if (err != ERROR_OK) { - LOG_ERROR("Failed to load rcp_init algorithm into RAM\n"); + LOG_ERROR("Failed to load rcp_init algorithm into RAM"); return ERROR_FAIL; } - LOG_DEBUG("Calling rcp_init on core \"%s\", code at 0x%" PRIx32 "\n", - target->cmd_name, (uint32_t)priv->ram_algo_space->address); + LOG_TARGET_DEBUG(target, "Calling rcp_init, code at " TARGET_ADDR_FMT, + priv->ram_algo_space->address); /* Actually call the function */ struct armv7m_algorithm alg_info; @@ -684,7 +683,7 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank &alg_info ); if (err != ERROR_OK) { - LOG_ERROR("Failed to invoke rcp_init\n"); + LOG_ERROR("Failed to invoke rcp_init"); return err; } @@ -729,7 +728,7 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba BOOTROM_STATE_RESET_CURRENT_CORE }; if (!priv->jump_bootrom_reset_state) { - LOG_WARNING("RP2350 flash: no bootrom_reset_method\n"); + LOG_WARNING("RP2350 flash: no bootrom_reset_method"); } else { /* This is mainly required to clear varmulet_enclosing_cpu pointers on RISC-V, in case an Arm -> RISC-V call has been interrupted (these pointers are used to handle @@ -746,7 +745,7 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba /* Pass {0, 0} to set_varmulet_user_stack() to enable automatic emulation of Arm APIs using the ROM's default stacks. Usually the bootrom does this before exiting to user code, but it needs to be done manually when the USB bootloader has been interrupted. */ - LOG_DEBUG("Enabling default Arm emulator stacks for RISC-V ROM calls\n"); + LOG_DEBUG("Enabling default Arm emulator stacks for RISC-V ROM calls"); struct working_area *set_stack_mem_args; err = target_alloc_working_area(target, 2 * sizeof(uint32_t), &set_stack_mem_args); if (err != ERROR_OK) { @@ -771,7 +770,7 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba set_stack_register_args, ARRAY_SIZE(set_stack_register_args)); target_free_working_area(target, set_stack_mem_args); if (err != ERROR_OK) { - LOG_ERROR("Failed to initialise Arm emulation stacks for RISC-V: 0x%08" PRIx32, err); + LOG_ERROR("Failed to initialise Arm emulation stacks for RISC-V"); return err; } } @@ -852,7 +851,7 @@ static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2xxx_fla static int rp2xxx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { - LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset); + LOG_DEBUG("Writing %" PRIu32 " bytes starting at 0x%" PRIx32, count, offset); struct rp2xxx_flash_bank *priv = bank->driver_priv; struct target *target = bank->target; @@ -882,7 +881,8 @@ static int rp2xxx_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui while (count > 0) { uint32_t write_size = count > chunk_size ? chunk_size : count; - LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset); + LOG_DEBUG("Writing %" PRIu32 " bytes to offset 0x%" PRIx32, + write_size, offset); err = target_write_buffer(target, bounce->address, write_size, buffer); if (err != ERROR_OK) { LOG_ERROR("Could not load data into target bounce buffer"); @@ -929,7 +929,8 @@ static int rp2xxx_flash_erase(struct flash_bank *bank, unsigned int first, unsig uint32_t offset_start = bank->sectors[first].offset; uint32_t offset_last = bank->sectors[last].offset + bank->sectors[last].size; uint32_t length = offset_last - offset_start; - LOG_DEBUG("erase %d bytes starting at 0x%" PRIx32, length, offset_start); + LOG_DEBUG("erase %" PRIu32 " bytes starting at 0x%" PRIx32, + length, offset_start); int err = setup_for_raw_flash_cmd(target, priv); if (err != ERROR_OK) @@ -1328,7 +1329,7 @@ COMMAND_HANDLER(rp2xxx_rom_api_call_handler) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i + 1], args[i]); if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); + command_print(CMD, "Target not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1343,7 +1344,7 @@ COMMAND_HANDLER(rp2xxx_rom_api_call_handler) uint16_t fc; retval = rp2xxx_lookup_rom_symbol(target, tag, symtype_func, &fc); if (retval != ERROR_OK) { - command_print(CMD, "Function %.2s not found in RP2xxx ROM.", + command_print(CMD, "Function %.2s not found in RP2xxx ROM", CMD_ARGV[0]); goto cleanup_and_return; } From 4d4c45cfd25703f39f9e2413b22d91a48c4b4565 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 21 Mar 2025 21:56:39 +0100 Subject: [PATCH 36/55] flash/nor/rp2xxx: define macro BOOTROM_MAGIC_MASK and use it instead of magic value. Change-Id: I5d006aaf990d4ef3a82e622b1e41cd2bfec359f7 Signed-off-by: Tomas Vanek Reported-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8810 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/flash/nor/rp2xxx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index 2b22e52eb8..85c5911041 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -16,6 +16,7 @@ #define BOOTROM_RP2040_MAGIC 0x01754d /* this is 'M' 'u', 2 (version) */ #define BOOTROM_RP2350_MAGIC 0x02754d +#define BOOTROM_MAGIC_MASK 0xffffff #define BOOTROM_MAGIC_ADDR 0x00000010 #define MAKE_TAG(a, b) (((b)<<8) | a) @@ -368,7 +369,7 @@ static int rp2xxx_lookup_rom_symbol(struct target *target, uint16_t tag, uint16_ return err; /* Ignore version */ - magic &= 0xffffff; + magic &= BOOTROM_MAGIC_MASK; if (magic == BOOTROM_RP2350_MAGIC) { /* Distinguish old-style RP2350 ROM table (A0, and earlier A1 builds) From cbd7987c7ca2656b60bc8964bb1d9b7819e66ccb Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Apr 2025 11:03:46 +0200 Subject: [PATCH 37/55] target: stm8: drop include file stm8.h The file stm8.h is only included by stm8.c and provides some basic declaration that can be simply part of the C file. Drop the file stm8.h and move its content in stm8.c Replace the macro 'STM8_NUM_CORE_REGS' with the existing macro 'STM8_NUM_REGS'. While there: - drop the useless include of "hello.h". Change-Id: Iecd1a27f0630cdbbfd51033d34aa3d468aa63464 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8856 Tested-by: jenkins Reviewed-by: zapb --- src/target/Makefile.am | 1 - src/target/stm8.c | 49 ++++++++++++++++++++++++++++++-- src/target/stm8.h | 63 ------------------------------------------ 3 files changed, 47 insertions(+), 66 deletions(-) delete mode 100644 src/target/stm8.h diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 1fc7d2afa6..1a76864180 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -224,7 +224,6 @@ ARC_SRC = \ %D%/avr32_mem.h \ %D%/avr32_regs.h \ %D%/semihosting_common.h \ - %D%/stm8.h \ %D%/lakemont.h \ %D%/x86_32_common.h \ %D%/arm_cti.h \ diff --git a/src/target/stm8.c b/src/target/stm8.c index c80ea0eb20..81c41f2b2a 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -13,14 +13,12 @@ #include #include "target.h" #include "target_type.h" -#include "hello.h" #include "jtag/interface.h" #include "jtag/jtag.h" #include "jtag/swim.h" #include "register.h" #include "breakpoints.h" #include "algorithm.h" -#include "stm8.h" static struct reg_cache *stm8_build_reg_cache(struct target *target); static int stm8_read_core_reg(struct target *target, unsigned int num); @@ -54,6 +52,8 @@ static const struct { { 5, "cc", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, }; +#define STM8_COMMON_MAGIC 0x53544D38U + #define STM8_NUM_REGS ARRAY_SIZE(stm8_regs) #define STM8_PC 0 #define STM8_A 1 @@ -168,6 +168,51 @@ struct stm8_comparator { enum hw_break_type type; }; +struct stm8_common { + unsigned int common_magic; + + void *arch_info; + struct reg_cache *core_cache; + uint32_t core_regs[STM8_NUM_REGS]; + + /* working area for fastdata access */ + struct working_area *fast_data_area; + + bool swim_configured; + bool bp_scanned; + uint8_t num_hw_bpoints; + uint8_t num_hw_bpoints_avail; + struct stm8_comparator *hw_break_list; + uint32_t blocksize; + uint32_t flashstart; + uint32_t flashend; + uint32_t eepromstart; + uint32_t eepromend; + uint32_t optionstart; + uint32_t optionend; + bool enable_step_irq; + + bool enable_stm8l; + uint32_t flash_cr2; + uint32_t flash_ncr2; + uint32_t flash_iapsr; + uint32_t flash_dukr; + uint32_t flash_pukr; + + /* cc value used for interrupt flags restore */ + uint32_t cc; + bool cc_valid; + + /* register cache to processor synchronization */ + int (*read_core_reg)(struct target *target, unsigned int num); + int (*write_core_reg)(struct target *target, unsigned int num); +}; + +static struct stm8_common *target_to_stm8(struct target *target) +{ + return target->arch_info; +} + static int stm8_adapter_read_memory(struct target *target, uint32_t addr, int size, int count, void *buf) { diff --git a/src/target/stm8.h b/src/target/stm8.h deleted file mode 100644 index 55e1071aba..0000000000 --- a/src/target/stm8.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* -* OpenOCD STM8 target driver -* Copyright (C) 2017 Ake Rehnman -* ake.rehnman(at)gmail.com -*/ - -#ifndef OPENOCD_TARGET_STM8_H -#define OPENOCD_TARGET_STM8_H - -struct target; - -#define STM8_COMMON_MAGIC 0x53544D38U -#define STM8_NUM_CORE_REGS 6 - -struct stm8_common { - unsigned int common_magic; - - void *arch_info; - struct reg_cache *core_cache; - uint32_t core_regs[STM8_NUM_CORE_REGS]; - - /* working area for fastdata access */ - struct working_area *fast_data_area; - - bool swim_configured; - bool bp_scanned; - uint8_t num_hw_bpoints; - uint8_t num_hw_bpoints_avail; - struct stm8_comparator *hw_break_list; - uint32_t blocksize; - uint32_t flashstart; - uint32_t flashend; - uint32_t eepromstart; - uint32_t eepromend; - uint32_t optionstart; - uint32_t optionend; - bool enable_step_irq; - - bool enable_stm8l; - uint32_t flash_cr2; - uint32_t flash_ncr2; - uint32_t flash_iapsr; - uint32_t flash_dukr; - uint32_t flash_pukr; - - /* cc value used for interrupt flags restore */ - uint32_t cc; - bool cc_valid; - - /* register cache to processor synchronization */ - int (*read_core_reg)(struct target *target, unsigned int num); - int (*write_core_reg)(struct target *target, unsigned int num); -}; - -static inline struct stm8_common * -target_to_stm8(struct target *target) -{ - return target->arch_info; -} - -#endif /* OPENOCD_TARGET_STM8_H */ From c3fae349692c7c2d0eac95a04da648ba95a558a0 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 16 Mar 2025 14:31:01 +0100 Subject: [PATCH 38/55] adapter: replace 'interface' with 'adapter driver' Comments and output strings still reference the term 'interface', while 'adapter driver' should be used. While there, drop the useless test if CMD_ARGV[0] is an empty string, as this is not possible when CMD_ARGC > 0. Change-Id: I7b46b5dd3cec53d8b5b7559d941ee9ae3bd1d89b Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8808 Tested-by: jenkins Reviewed-by: zapb --- src/jtag/adapter.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 2fcbd609e8..0bdfe7b134 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -187,7 +187,6 @@ int adapter_init(struct command_context *cmd_ctx) int adapter_quit(void) { if (is_adapter_initialized() && adapter_driver->quit) { - /* close the JTAG interface */ int result = adapter_driver->quit(); if (result != ERROR_OK) LOG_ERROR("failed: %d", result); @@ -380,7 +379,7 @@ bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path COMMAND_HANDLER(handle_adapter_name) { - /* return the name of the interface */ + /* return the name of the adapter driver */ /* TCL code might need to know the exact type... */ /* FUTURE: we allow this as a means to "set" the interface. */ @@ -414,14 +413,14 @@ COMMAND_HANDLER(handle_adapter_driver_command) { int retval; - /* check whether the interface is already configured */ + /* check whether the adapter driver is already configured */ if (adapter_driver) { - LOG_WARNING("Interface already configured, ignoring"); + LOG_WARNING("Adapter driver already configured, ignoring"); return ERROR_OK; } - /* interface name is a mandatory argument */ - if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0') + /* adapter driver name is a mandatory argument */ + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; for (unsigned int i = 0; adapter_drivers[i]; i++) { @@ -439,10 +438,10 @@ COMMAND_HANDLER(handle_adapter_driver_command) return allow_transports(CMD_CTX, adapter_driver->transports); } - /* no valid interface was found (i.e. the configuration option, - * didn't match one of the compiled-in interfaces + /* no valid adapter driver was found (i.e. the configuration option, + * didn't match one of the compiled-in drivers */ - LOG_ERROR("The specified debug interface was not found (%s)", + LOG_ERROR("The specified adapter driver was not found (%s)", CMD_ARGV[0]); command_print(CMD, "The following adapter drivers are available:"); CALL_COMMAND_HANDLER(dump_adapter_driver_list); From da50873d5ebe558ee545c1a00f31df9e23f45456 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 4 Jan 2025 18:41:41 +0100 Subject: [PATCH 39/55] adapter: list supported transports beside adapter name Modify the command 'adapter list' to output the list of transports supported by each adapter driver. Drop the line number, as there is no real interest on it. Format the output as a TCL dictionary indexed by the adapter name and containing the transports in a TCL list. E.g: dummy { jtag } ftdi { jtag swd } This format is easily handled by TCL scripts, e.g.: dict get [adapter list] ftdi Document the command output. Change-Id: I69f73b71da2f1756866a63bc2c0ba33459a29063 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8691 Tested-by: jenkins --- doc/openocd.texi | 11 +++++++++++ src/jtag/adapter.c | 14 +++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 32a2895ecf..d85812824f 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2414,6 +2414,17 @@ target. @deffn {Command} {adapter list} List the debug adapter drivers that have been built into the running copy of OpenOCD. + +The output is formatted as a Tcl dictionary indexed by the adapter name +and containing the transports in a Tcl list. +@example +dummy @{ jtag @} +ftdi @{ jtag swd @} +@end example +This format is easily handled by Tcl scripts: +@example +dict get [adapter list] ftdi +@end example @end deffn @anchor{adapter gpio} diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 0bdfe7b134..6947217461 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -393,9 +393,21 @@ COMMAND_HANDLER(handle_adapter_name) COMMAND_HANDLER(dump_adapter_driver_list) { + int max_len = 0; + for (unsigned int i = 0; adapter_drivers[i]; i++) { + int len = strlen(adapter_drivers[i]->name); + if (max_len < len) + max_len = len; + } + for (unsigned int i = 0; adapter_drivers[i]; i++) { const char *name = adapter_drivers[i]->name; - command_print(CMD, "%u: %s", i + 1, name); + const char * const *transports = adapter_drivers[i]->transports; + + command_print_sameline(CMD, "%-*s {", max_len, name); + for (unsigned int j = 0; transports[j]; j++) + command_print_sameline(CMD, " %s", transports[j]); + command_print(CMD, " }"); } return ERROR_OK; From 9a5de74423503d1bd16e16b77b4e0e6d19913057 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 4 Jan 2025 16:54:14 +0100 Subject: [PATCH 40/55] transport: deprecate auto-selection of transport Historically, if the user does not specify a transport, OpenOCD select automatically the first transport listed in the adapter driver. This auto-selection can behave differently by changing adapter, so the transport should be enforced in the configuration file. Deprecate the auto-selection and print a warning message when a transport gets auto-selected. There are two cases: - adapter offers one transport only. The code early auto-selects the transport but does not print anything. If later the user selects the transport then no deprecation will be printed during 'transport init'; - user runs 'transport select', e.g. in 'swj-dp' script, and this triggers the auto-selection and the deprecated message. Change-Id: I2e55b9dcc6da77ca937978fbfb36bc365b803f0d Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8692 Reviewed-by: Jan Matyas Reviewed-by: zapb Tested-by: jenkins --- src/transport/transport.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/transport/transport.c b/src/transport/transport.c index 0af1360369..4a1f71d406 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -52,6 +52,11 @@ static struct transport *transport_list; */ static const char * const *allowed_transports; +/** + * Adapter supports a single transport; it has been auto-selected + */ +static bool transport_single_is_autoselected; + /** * The transport being used for the current OpenOCD session. */ static struct transport *session; @@ -104,7 +109,8 @@ int allow_transports(struct command_context *ctx, const char * const *vector) /* autoselect if there's no choice ... */ if (!vector[1]) { - LOG_INFO("only one transport option; autoselecting '%s'", vector[0]); + LOG_DEBUG("only one transport option; autoselecting '%s'", vector[0]); + transport_single_is_autoselected = true; return transport_select(ctx, vector[0]); } @@ -182,6 +188,11 @@ COMMAND_HANDLER(handle_transport_init) return ERROR_FAIL; } + if (transport_single_is_autoselected) + LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " + "Use 'transport select %s' to suppress this message.", + session->name, session->name); + return session->init(CMD_CTX); } @@ -216,8 +227,9 @@ COMMAND_HANDLER(handle_transport_select) command_print(CMD, "Debug adapter does not support any transports? Check config file order."); return ERROR_FAIL; } - LOG_INFO("auto-selecting first available session transport \"%s\". " - "To override use 'transport select '.", allowed_transports[0]); + LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " + "Use 'transport select %s' to suppress this message.", + allowed_transports[0], allowed_transports[0]); int retval = transport_select(CMD_CTX, allowed_transports[0]); if (retval != ERROR_OK) return retval; @@ -229,6 +241,11 @@ COMMAND_HANDLER(handle_transport_select) /* assign transport */ if (session) { if (!strcmp(session->name, CMD_ARGV[0])) { + if (transport_single_is_autoselected) { + /* Nothing to do, but also nothing to complain */ + transport_single_is_autoselected = false; + return ERROR_OK; + } LOG_WARNING("Transport \"%s\" was already selected", session->name); return ERROR_OK; } From 236208a5ff2db5f502444b32da1df3fd17b692fb Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 22 Dec 2024 17:06:12 +0100 Subject: [PATCH 41/55] transport: use a bitmask for the transport Move the transport's names in a local array in the transport framework. Replace the string struct transport::name, that identifies the transport, with a bitmask where each bit corresponds to one of the available transports. Change-Id: I6bdf7264d5979c355299f63fcf80bf54dcd95cee Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8674 Tested-by: jenkins Reviewed-by: zapb --- src/jtag/core.c | 10 +++--- src/jtag/hla/hla_transport.c | 19 ++++++---- src/jtag/swim.c | 2 +- src/target/adi_v5_dapdirect.c | 4 +-- src/target/adi_v5_swd.c | 2 +- src/transport/transport.c | 68 +++++++++++++++++++++++++++++------ src/transport/transport.h | 28 ++++++++++++--- 7 files changed, 102 insertions(+), 31 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index 030c173be6..6dd2144c63 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -1823,7 +1823,7 @@ static int jtag_select(struct command_context *ctx) } static struct transport jtag_transport = { - .name = "jtag", + .id = TRANSPORT_JTAG, .select = jtag_select, .init = jtag_init, }; @@ -1868,7 +1868,7 @@ int adapter_resets(int trst, int srst) transport_is_swim()) { if (trst == TRST_ASSERT) { LOG_ERROR("transport %s has no trst signal", - get_current_transport()->name); + get_current_transport_name()); return ERROR_FAIL; } @@ -1884,7 +1884,7 @@ int adapter_resets(int trst, int srst) return ERROR_OK; LOG_ERROR("reset is not supported on transport %s", - get_current_transport()->name); + get_current_transport_name()); return ERROR_FAIL; } @@ -1903,7 +1903,7 @@ int adapter_assert_reset(void) return adapter_system_reset(1); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", - get_current_transport()->name); + get_current_transport_name()); else LOG_ERROR("transport is not selected"); return ERROR_FAIL; @@ -1920,7 +1920,7 @@ int adapter_deassert_reset(void) return adapter_system_reset(0); else if (get_current_transport()) LOG_ERROR("reset is not supported on %s", - get_current_transport()->name); + get_current_transport_name()); else LOG_ERROR("transport is not selected"); return ERROR_FAIL; diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index b826eb0fe6..333825eff1 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -177,15 +177,20 @@ static int hl_transport_init(struct command_context *cmd_ctx) return ERROR_FAIL; } - LOG_DEBUG("current transport %s", transport->name); + LOG_DEBUG("current transport %s", get_current_transport_name()); /* get selected transport as enum */ - tr = HL_TRANSPORT_UNKNOWN; - - if (strcmp(transport->name, "hla_swd") == 0) + switch (transport->id) { + case TRANSPORT_HLA_SWD: tr = HL_TRANSPORT_SWD; - else if (strcmp(transport->name, "hla_jtag") == 0) + break; + case TRANSPORT_HLA_JTAG: tr = HL_TRANSPORT_JTAG; + break; + default: + tr = HL_TRANSPORT_UNKNOWN; + break; + } int retval = hl_interface_open(tr); @@ -213,14 +218,14 @@ static int hl_swd_transport_select(struct command_context *cmd_ctx) } static struct transport hl_swd_transport = { - .name = "hla_swd", + .id = TRANSPORT_HLA_SWD, .select = hl_swd_transport_select, .init = hl_transport_init, .override_target = hl_interface_override_target, }; static struct transport hl_jtag_transport = { - .name = "hla_jtag", + .id = TRANSPORT_HLA_JTAG, .select = hl_jtag_transport_select, .init = hl_transport_init, .override_target = hl_interface_override_target, diff --git a/src/jtag/swim.c b/src/jtag/swim.c index de3e106a1a..004a9fd4f2 100644 --- a/src/jtag/swim.c +++ b/src/jtag/swim.c @@ -136,7 +136,7 @@ static int swim_transport_init(struct command_context *cmd_ctx) } static struct transport swim_transport = { - .name = "swim", + .id = TRANSPORT_SWIM, .select = swim_transport_select, .init = swim_transport_init, }; diff --git a/src/target/adi_v5_dapdirect.c b/src/target/adi_v5_dapdirect.c index d198dacf39..07ea313d19 100644 --- a/src/target/adi_v5_dapdirect.c +++ b/src/target/adi_v5_dapdirect.c @@ -207,13 +207,13 @@ static int dapdirect_init(struct command_context *ctx) } static struct transport dapdirect_jtag_transport = { - .name = "dapdirect_jtag", + .id = TRANSPORT_DAPDIRECT_JTAG, .select = dapdirect_jtag_select, .init = dapdirect_init, }; static struct transport dapdirect_swd_transport = { - .name = "dapdirect_swd", + .id = TRANSPORT_DAPDIRECT_SWD, .select = dapdirect_swd_select, .init = dapdirect_init, }; diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index e50f8f1371..2d286136a5 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -756,7 +756,7 @@ static int swd_init(struct command_context *ctx) } static struct transport swd_transport = { - .name = "swd", + .id = TRANSPORT_SWD, .select = swd_select, .init = swd_init, }; diff --git a/src/transport/transport.c b/src/transport/transport.c index 4a1f71d406..411b0a5e0f 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -30,6 +30,8 @@ * messaging and error handling. */ +#include +#include #include #include #include @@ -43,6 +45,20 @@ extern struct command_context *global_cmd_ctx; */ /** List of transports known to OpenOCD. */ +static const struct { + unsigned int id; + const char *name; +} transport_names[] = { + { TRANSPORT_JTAG, "jtag", }, + { TRANSPORT_SWD, "swd", }, + { TRANSPORT_HLA_JTAG, "hla_jtag", }, + { TRANSPORT_HLA_SWD, "hla_swd", }, + { TRANSPORT_DAPDIRECT_JTAG, "dapdirect_jtag", }, + { TRANSPORT_DAPDIRECT_SWD, "dapdirect_swd", }, + { TRANSPORT_SWIM, "swim", }, +}; + +/** List of transports registered in OpenOCD. */ static struct transport *transport_list; /** @@ -60,12 +76,26 @@ static bool transport_single_is_autoselected; /** * The transport being used for the current OpenOCD session. */ static struct transport *session; +static const char *transport_name(unsigned int id) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++) + if (id == transport_names[i].id) + return transport_names[i].name; + + return NULL; +} + +static bool is_transport_id_valid(unsigned int id) +{ + return (id != 0) && ((id & ~TRANSPORT_VALID_MASK) == 0) && IS_PWR_OF_2(id); +} + static int transport_select(struct command_context *ctx, const char *name) { /* name may only identify a known transport; * caller guarantees session's transport isn't yet set.*/ for (struct transport *t = transport_list; t; t = t->next) { - if (strcmp(t->name, name) == 0) { + if (!strcmp(transport_name(t->id), name)) { int retval = t->select(ctx); /* select() registers commands specific to this * transport, and may also reset the link, e.g. @@ -74,7 +104,7 @@ static int transport_select(struct command_context *ctx, const char *name) if (retval == ERROR_OK) session = t; else - LOG_ERROR("Error selecting '%s' as transport", t->name); + LOG_ERROR("Error selecting '%s' as transport", name); return retval; } } @@ -136,20 +166,28 @@ int transport_register(struct transport *new_transport) { struct transport *t; + if (!is_transport_id_valid(new_transport->id)) { + LOG_ERROR("invalid transport ID 0x%x", new_transport->id); + return ERROR_FAIL; + } + for (t = transport_list; t; t = t->next) { - if (strcmp(t->name, new_transport->name) == 0) { - LOG_ERROR("transport name already used"); + if (t->id == new_transport->id) { + LOG_ERROR("transport '%s' already registered", + transport_name(t->id)); return ERROR_FAIL; } } if (!new_transport->select || !new_transport->init) - LOG_ERROR("invalid transport %s", new_transport->name); + LOG_ERROR("invalid transport %s", + transport_name(new_transport->id)); /* splice this into the list */ new_transport->next = transport_list; transport_list = new_transport; - LOG_DEBUG("register '%s'", new_transport->name); + LOG_DEBUG("register '%s' (ID %d)", + transport_name(new_transport->id), new_transport->id); return ERROR_OK; } @@ -166,6 +204,14 @@ struct transport *get_current_transport(void) return session; } +const char *get_current_transport_name(void) +{ + if (!session || !is_transport_id_valid(session->id)) + NULL; + + return transport_name(session->id); +} + /*-----------------------------------------------------------------------*/ /* @@ -191,7 +237,7 @@ COMMAND_HANDLER(handle_transport_init) if (transport_single_is_autoselected) LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " "Use 'transport select %s' to suppress this message.", - session->name, session->name); + transport_name(session->id), transport_name(session->id)); return session->init(CMD_CTX); } @@ -204,7 +250,7 @@ COMMAND_HANDLER(handle_transport_list) command_print(CMD, "The following transports are available:"); for (struct transport *t = transport_list; t; t = t->next) - command_print(CMD, "\t%s", t->name); + command_print(CMD, "\t%s", transport_name(t->id)); return ERROR_OK; } @@ -234,19 +280,19 @@ COMMAND_HANDLER(handle_transport_select) if (retval != ERROR_OK) return retval; } - command_print(CMD, "%s", session->name); + command_print(CMD, "%s", transport_name(session->id)); return ERROR_OK; } /* assign transport */ if (session) { - if (!strcmp(session->name, CMD_ARGV[0])) { + if (!strcmp(transport_name(session->id), CMD_ARGV[0])) { if (transport_single_is_autoselected) { /* Nothing to do, but also nothing to complain */ transport_single_is_autoselected = false; return ERROR_OK; } - LOG_WARNING("Transport \"%s\" was already selected", session->name); + LOG_WARNING("Transport \"%s\" was already selected", CMD_ARGV[0]); return ERROR_OK; } command_print(CMD, "Can't change session's transport after the initial selection was made"); diff --git a/src/transport/transport.h b/src/transport/transport.h index 2e3dcc61aa..dde7c6ba76 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -12,8 +12,27 @@ #include "config.h" #endif +#include "helper/bits.h" #include "helper/command.h" +#define TRANSPORT_JTAG BIT(0) +#define TRANSPORT_SWD BIT(1) +#define TRANSPORT_HLA_JTAG BIT(2) +#define TRANSPORT_HLA_SWD BIT(3) +#define TRANSPORT_DAPDIRECT_JTAG BIT(4) +#define TRANSPORT_DAPDIRECT_SWD BIT(5) +#define TRANSPORT_SWIM BIT(6) + +/* mask for valid ID */ +#define TRANSPORT_VALID_MASK \ + (TRANSPORT_JTAG | \ + TRANSPORT_SWD | \ + TRANSPORT_HLA_JTAG | \ + TRANSPORT_HLA_SWD | \ + TRANSPORT_DAPDIRECT_JTAG | \ + TRANSPORT_DAPDIRECT_SWD | \ + TRANSPORT_SWIM) + /** * Wrapper for transport lifecycle operations. * @@ -34,11 +53,10 @@ */ struct transport { /** - * Each transport has a unique name, used to select it - * from among the alternatives. Examples might include - * "jtag", * "swd", "AVR_ISP" and more. + * Each transport has a unique ID, used to select it + * from among the alternatives. */ - const char *name; + unsigned int id; /** * When a transport is selected, this method registers @@ -75,6 +93,8 @@ int transport_register(struct transport *new_transport); struct transport *get_current_transport(void); +const char *get_current_transport_name(void); + int transport_register_commands(struct command_context *ctx); int allow_transports(struct command_context *ctx, const char * const *vector); From a500b2ce67eb80870dfbd5d73118e822ac99ef88 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 12 Feb 2025 16:39:18 +0100 Subject: [PATCH 42/55] adapter: use bitmask for driver's transports In every driver, replace the array of strings with a bitmask that lists the supported transports. Add an extra field to carry the former first listed transport as a "preferred" transport. It would be used as default when no command 'transport select' is used. This keeps backward compatibility with scripts that do not define the transport, relying on such default. Change-Id: I4976583f1a38fdcc1f85045023dc7c629001f743 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8675 Tested-by: jenkins Reviewed-by: zapb --- src/jtag/adapter.c | 12 +++--- src/jtag/drivers/am335xgpio.c | 5 +-- src/jtag/drivers/amt_jtagaccel.c | 3 +- src/jtag/drivers/angie.c | 3 +- src/jtag/drivers/arm-jtag-ew.c | 3 +- src/jtag/drivers/at91rm9200.c | 3 +- src/jtag/drivers/bcm2835gpio.c | 5 +-- src/jtag/drivers/buspirate.c | 5 +-- src/jtag/drivers/cmsis_dap.c | 5 +-- src/jtag/drivers/dmem.c | 5 +-- src/jtag/drivers/dummy.c | 3 +- src/jtag/drivers/ep93xx.c | 3 +- src/jtag/drivers/esp_usb_jtag.c | 3 +- src/jtag/drivers/ft232r.c | 3 +- src/jtag/drivers/ftdi.c | 5 +-- src/jtag/drivers/gw16012.c | 3 +- src/jtag/drivers/imx_gpio.c | 5 +-- src/jtag/drivers/jlink.c | 5 +-- src/jtag/drivers/jtag_dpi.c | 3 +- src/jtag/drivers/jtag_vpi.c | 3 +- src/jtag/drivers/kitprog.c | 5 +-- src/jtag/drivers/linuxgpiod.c | 5 +-- src/jtag/drivers/linuxspidev.c | 6 +-- src/jtag/drivers/opendous.c | 3 +- src/jtag/drivers/openjtag.c | 3 +- src/jtag/drivers/osbdm.c | 3 +- src/jtag/drivers/parport.c | 3 +- src/jtag/drivers/presto.c | 3 +- src/jtag/drivers/remote_bitbang.c | 5 +-- src/jtag/drivers/rlink.c | 3 +- src/jtag/drivers/rshim.c | 5 +-- src/jtag/drivers/stlink_usb.c | 5 +-- src/jtag/drivers/sysfsgpio.c | 5 +-- src/jtag/drivers/ulink.c | 3 +- src/jtag/drivers/usb_blaster/usb_blaster.c | 3 +- src/jtag/drivers/usbprog.c | 3 +- src/jtag/drivers/vdebug.c | 5 +-- src/jtag/drivers/vsllink.c | 5 +-- src/jtag/drivers/xds110.c | 5 +-- src/jtag/drivers/xlnx-pcie-xvc.c | 5 +-- src/jtag/hla/hla_interface.c | 3 +- src/jtag/hla/hla_interface.h | 2 - src/jtag/hla/hla_transport.c | 2 - src/jtag/interface.h | 15 +++++-- src/transport/transport.c | 47 +++++++++++++--------- src/transport/transport.h | 5 ++- 46 files changed, 129 insertions(+), 113 deletions(-) diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 6947217461..6785a74ef1 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -16,6 +16,7 @@ #include "minidriver.h" #include "interface.h" #include "interfaces.h" +#include #include /** @@ -24,7 +25,6 @@ */ struct adapter_driver *adapter_driver; -const char * const jtag_only[] = { "jtag", NULL }; enum adapter_clk_mode { CLOCK_MODE_UNSELECTED = 0, @@ -402,11 +402,12 @@ COMMAND_HANDLER(dump_adapter_driver_list) for (unsigned int i = 0; adapter_drivers[i]; i++) { const char *name = adapter_drivers[i]->name; - const char * const *transports = adapter_drivers[i]->transports; + unsigned int transport_ids = adapter_drivers[i]->transport_ids; command_print_sameline(CMD, "%-*s {", max_len, name); - for (unsigned int j = 0; transports[j]; j++) - command_print_sameline(CMD, " %s", transports[j]); + for (unsigned int j = BIT(0); j & TRANSPORT_VALID_MASK; j <<= 1) + if (j & transport_ids) + command_print_sameline(CMD, " %s", transport_name(j)); command_print(CMD, " }"); } @@ -447,7 +448,8 @@ COMMAND_HANDLER(handle_adapter_driver_command) adapter_driver = adapter_drivers[i]; - return allow_transports(CMD_CTX, adapter_driver->transports); + return allow_transports(CMD_CTX, adapter_driver->transport_ids, + adapter_driver->transport_preferred_id); } /* no valid adapter driver was found (i.e. the configuration option, diff --git a/src/jtag/drivers/am335xgpio.c b/src/jtag/drivers/am335xgpio.c index cacf4e7c79..a4727cc891 100644 --- a/src/jtag/drivers/am335xgpio.c +++ b/src/jtag/drivers/am335xgpio.c @@ -350,8 +350,6 @@ static const struct command_registration am335xgpio_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const char * const am335xgpio_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface am335xgpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -494,7 +492,8 @@ static int am335xgpio_quit(void) struct adapter_driver am335xgpio_adapter_driver = { .name = "am335xgpio", - .transports = am335xgpio_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = am335xgpio_command_handlers, .init = am335xgpio_init, diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index 80254ff074..633c20413a 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -579,7 +579,8 @@ static struct jtag_interface amt_jtagaccel_interface = { struct adapter_driver amt_jtagaccel_adapter_driver = { .name = "amt_jtagaccel", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = amtjtagaccel_command_handlers, .init = amt_jtagaccel_init, diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index 46a4c82e5b..56a118eaed 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -2388,7 +2388,8 @@ static struct jtag_interface angie_interface = { struct adapter_driver angie_adapter_driver = { .name = "angie", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = angie_init, .quit = angie_quit, diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 45e03840ea..9d8c592edb 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -486,7 +486,8 @@ static struct jtag_interface armjtagew_interface = { struct adapter_driver armjtagew_adapter_driver = { .name = "arm-jtag-ew", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = armjtagew_command_handlers, .init = armjtagew_init, diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index a77e29aa6e..ddcf857a6b 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -186,7 +186,8 @@ static struct jtag_interface at91rm9200_interface = { struct adapter_driver at91rm9200_adapter_driver = { .name = "at91rm9200", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = at91rm9200_command_handlers, .init = at91rm9200_init, diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index e8689aa037..1a105aac44 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -590,15 +590,14 @@ static int bcm2835gpio_quit(void) } -static const char * const bcm2835_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface bcm2835gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, }; struct adapter_driver bcm2835gpio_adapter_driver = { .name = "bcm2835gpio", - .transports = bcm2835_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = bcm2835gpio_command_handlers, .init = bcm2835gpio_init, diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 93f0ba3838..4283616adc 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -534,15 +534,14 @@ static const struct swd_driver buspirate_swd = { .run = buspirate_swd_run_queue, }; -static const char * const buspirate_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface buspirate_interface = { .execute_queue = buspirate_execute_queue, }; struct adapter_driver buspirate_adapter_driver = { .name = "buspirate", - .transports = buspirate_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = buspirate_command_handlers, .init = buspirate_init, diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index be9ebaed58..2bfcfcc2b0 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -2314,8 +2314,6 @@ static const struct swd_driver cmsis_dap_swd_driver = { .run = cmsis_dap_swd_run_queue, }; -static const char * const cmsis_dap_transport[] = { "swd", "jtag", NULL }; - static struct jtag_interface cmsis_dap_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = cmsis_dap_execute_queue, @@ -2323,7 +2321,8 @@ static struct jtag_interface cmsis_dap_interface = { struct adapter_driver cmsis_dap_adapter_driver = { .name = "cmsis-dap", - .transports = cmsis_dap_transport, + .transport_ids = TRANSPORT_SWD | TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_SWD, .commands = cmsis_dap_command_handlers, .init = cmsis_dap_init, diff --git a/src/jtag/drivers/dmem.c b/src/jtag/drivers/dmem.c index 4dc582115c..e50e84aeeb 100644 --- a/src/jtag/drivers/dmem.c +++ b/src/jtag/drivers/dmem.c @@ -604,11 +604,10 @@ static const struct dap_ops dmem_dap_ops = { .run = dmem_dp_run, }; -static const char *const dmem_dap_transport[] = { "dapdirect_swd", NULL }; - struct adapter_driver dmem_dap_adapter_driver = { .name = "dmem", - .transports = dmem_dap_transport, + .transport_ids = TRANSPORT_DAPDIRECT_SWD, + .transport_preferred_id = TRANSPORT_DAPDIRECT_SWD, .commands = dmem_dap_command_handlers, .init = dmem_dap_init, diff --git a/src/jtag/drivers/dummy.c b/src/jtag/drivers/dummy.c index 79b29fbae7..471668c3ab 100644 --- a/src/jtag/drivers/dummy.c +++ b/src/jtag/drivers/dummy.c @@ -140,7 +140,8 @@ static struct jtag_interface dummy_interface = { struct adapter_driver dummy_adapter_driver = { .name = "dummy", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = dummy_command_handlers, .init = &dummy_init, diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index ea9faf19b7..f3e1676f9f 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -46,7 +46,8 @@ static struct jtag_interface ep93xx_interface = { struct adapter_driver ep93xx_adapter_driver = { .name = "ep93xx", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = ep93xx_init, .quit = ep93xx_quit, diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c index 9504059543..a133035110 100644 --- a/src/jtag/drivers/esp_usb_jtag.c +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -784,7 +784,8 @@ static struct jtag_interface esp_usb_jtag_interface = { struct adapter_driver esp_usb_adapter_driver = { .name = "esp_usb_jtag", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = esp_usb_jtag_commands, .init = esp_usb_jtag_init, diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index f4e5af4dd4..f88e4b9408 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -900,7 +900,8 @@ static struct jtag_interface ft232r_interface = { struct adapter_driver ft232r_adapter_driver = { .name = "ft232r", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ft232r_command_handlers, .init = ft232r_init, diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index ec0ae4c00b..a8f6f60159 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1247,8 +1247,6 @@ static const struct swd_driver ftdi_swd = { .run = ftdi_swd_run_queue, }; -static const char * const ftdi_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface ftdi_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = ftdi_execute_queue, @@ -1256,7 +1254,8 @@ static struct jtag_interface ftdi_interface = { struct adapter_driver ftdi_adapter_driver = { .name = "ftdi", - .transports = ftdi_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ftdi_command_handlers, .init = ftdi_initialize, diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index 7200e757c7..805065f1f4 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -514,7 +514,8 @@ static struct jtag_interface gw16012_interface = { struct adapter_driver gw16012_adapter_driver = { .name = "gw16012", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = gw16012_command_handlers, .init = gw16012_init, diff --git a/src/jtag/drivers/imx_gpio.c b/src/jtag/drivers/imx_gpio.c index 18dc2ddf67..a4a76ca5a3 100644 --- a/src/jtag/drivers/imx_gpio.c +++ b/src/jtag/drivers/imx_gpio.c @@ -417,8 +417,6 @@ static const struct command_registration imx_gpio_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const char * const imx_gpio_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface imx_gpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -426,7 +424,8 @@ static struct jtag_interface imx_gpio_interface = { struct adapter_driver imx_gpio_adapter_driver = { .name = "imx_gpio", - .transports = imx_gpio_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = imx_gpio_command_handlers, .init = imx_gpio_init, diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 4d15cf5e63..9caf37f6f0 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -2264,15 +2264,14 @@ static const struct swd_driver jlink_swd = { .run = &jlink_swd_run_queue, }; -static const char * const jlink_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface jlink_interface = { .execute_queue = &jlink_execute_queue, }; struct adapter_driver jlink_adapter_driver = { .name = "jlink", - .transports = jlink_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = jlink_command_handlers, .init = &jlink_init, diff --git a/src/jtag/drivers/jtag_dpi.c b/src/jtag/drivers/jtag_dpi.c index 046186a619..d6418d39c7 100644 --- a/src/jtag/drivers/jtag_dpi.c +++ b/src/jtag/drivers/jtag_dpi.c @@ -398,7 +398,8 @@ static struct jtag_interface jtag_dpi_interface = { struct adapter_driver jtag_dpi_adapter_driver = { .name = "jtag_dpi", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = jtag_dpi_command_handlers, .init = jtag_dpi_init, .quit = jtag_dpi_quit, diff --git a/src/jtag/drivers/jtag_vpi.c b/src/jtag/drivers/jtag_vpi.c index f6cb3de5d2..fac27b3060 100644 --- a/src/jtag/drivers/jtag_vpi.c +++ b/src/jtag/drivers/jtag_vpi.c @@ -666,7 +666,8 @@ static struct jtag_interface jtag_vpi_interface = { struct adapter_driver jtag_vpi_adapter_driver = { .name = "jtag_vpi", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = jtag_vpi_command_handlers, .init = jtag_vpi_init, diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index 98b0d16681..88e301cebc 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -908,11 +908,10 @@ static const struct swd_driver kitprog_swd = { .run = kitprog_swd_run_queue, }; -static const char * const kitprog_transports[] = { "swd", NULL }; - struct adapter_driver kitprog_adapter_driver = { .name = "kitprog", - .transports = kitprog_transports, + .transport_ids = TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_SWD, .commands = kitprog_command_handlers, .init = kitprog_init, diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index eda7b1a80e..36c7e04934 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -425,8 +425,6 @@ static int linuxgpiod_init(void) return ERROR_JTAG_INIT_FAILED; } -static const char *const linuxgpiod_transport[] = { "swd", "jtag", NULL }; - static struct jtag_interface linuxgpiod_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -434,7 +432,8 @@ static struct jtag_interface linuxgpiod_interface = { struct adapter_driver linuxgpiod_adapter_driver = { .name = "linuxgpiod", - .transports = linuxgpiod_transport, + .transport_ids = TRANSPORT_SWD | TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_SWD, .init = linuxgpiod_init, .quit = linuxgpiod_quit, diff --git a/src/jtag/drivers/linuxspidev.c b/src/jtag/drivers/linuxspidev.c index 18abdc7db3..396f1a19a9 100644 --- a/src/jtag/drivers/linuxspidev.c +++ b/src/jtag/drivers/linuxspidev.c @@ -616,12 +616,10 @@ static const struct command_registration spidev_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -// Only SWD transport supported -static const char *const spidev_transports[] = { "swd", NULL }; - struct adapter_driver linuxspidev_adapter_driver = { .name = "linuxspidev", - .transports = spidev_transports, + .transport_ids = TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_SWD, .commands = spidev_command_handlers, .init = spidev_init, diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 999afb3fc7..04626cb1e5 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -229,7 +229,8 @@ static struct jtag_interface opendous_interface = { struct adapter_driver opendous_adapter_driver = { .name = "opendous", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = opendous_command_handlers, .init = opendous_init, diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 14bcc171eb..943ad854e8 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -931,7 +931,8 @@ static struct jtag_interface openjtag_interface = { struct adapter_driver openjtag_adapter_driver = { .name = "openjtag", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = openjtag_command_handlers, .init = openjtag_init, diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index 80f66d197e..de2e1f8ebe 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -684,7 +684,8 @@ static struct jtag_interface osbdm_interface = { struct adapter_driver osbdm_adapter_driver = { .name = "osbdm", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = osbdm_init, .quit = osbdm_quit, diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 3b20fe2478..143f3bde1f 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -533,7 +533,8 @@ static struct jtag_interface parport_interface = { struct adapter_driver parport_adapter_driver = { .name = "parport", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = parport_command_handlers, .init = parport_init, diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index f6e13f7eb4..84b881cdc8 100644 --- a/src/jtag/drivers/presto.c +++ b/src/jtag/drivers/presto.c @@ -528,7 +528,8 @@ static struct jtag_interface presto_interface = { struct adapter_driver presto_adapter_driver = { .name = "presto", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = presto_jtag_init, .quit = presto_jtag_quit, diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index bb608ba0a5..449c616545 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -412,8 +412,6 @@ COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command) return ERROR_COMMAND_SYNTAX_ERROR; } -static const char * const remote_bitbang_transports[] = { "jtag", "swd", NULL }; - COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_use_remote_sleep_command) { if (CMD_ARGC != 1) @@ -484,7 +482,8 @@ static struct jtag_interface remote_bitbang_interface = { struct adapter_driver remote_bitbang_adapter_driver = { .name = "remote_bitbang", - .transports = remote_bitbang_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = remote_bitbang_command_handlers, .init = &remote_bitbang_init, diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 6ea3729a5f..a818996255 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -1675,7 +1675,8 @@ static struct jtag_interface rlink_interface = { struct adapter_driver rlink_adapter_driver = { .name = "rlink", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = rlink_init, .quit = rlink_quit, diff --git a/src/jtag/drivers/rshim.c b/src/jtag/drivers/rshim.c index b37fe8c453..89bdadd698 100644 --- a/src/jtag/drivers/rshim.c +++ b/src/jtag/drivers/rshim.c @@ -508,11 +508,10 @@ static const struct dap_ops rshim_dap_ops = { .quit = rshim_disconnect, }; -static const char *const rshim_dap_transport[] = { "dapdirect_swd", NULL }; - struct adapter_driver rshim_dap_adapter_driver = { .name = "rshim", - .transports = rshim_dap_transport, + .transport_ids = TRANSPORT_DAPDIRECT_SWD, + .transport_preferred_id = TRANSPORT_DAPDIRECT_SWD, .commands = rshim_dap_command_handlers, .init = rshim_dap_init, diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index d77f28b0f4..e018f71cd9 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -5217,11 +5217,10 @@ static const struct swim_driver stlink_swim_ops = { .reconnect = stlink_swim_op_reconnect, }; -static const char *const stlink_dap_transport[] = { "dapdirect_swd", "dapdirect_jtag", "swim", NULL }; - struct adapter_driver stlink_dap_adapter_driver = { .name = "st-link", - .transports = stlink_dap_transport, + .transport_ids = TRANSPORT_DAPDIRECT_SWD | TRANSPORT_DAPDIRECT_JTAG | TRANSPORT_SWIM, + .transport_preferred_id = TRANSPORT_DAPDIRECT_SWD, .commands = stlink_dap_command_handlers, .init = stlink_dap_init, diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index ccd3974a42..279b35377c 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -545,8 +545,6 @@ static const struct command_registration sysfsgpio_command_handlers[] = { static int sysfsgpio_init(void); static int sysfsgpio_quit(void); -static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL }; - static struct jtag_interface sysfsgpio_interface = { .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, @@ -554,7 +552,8 @@ static struct jtag_interface sysfsgpio_interface = { struct adapter_driver sysfsgpio_adapter_driver = { .name = "sysfsgpio", - .transports = sysfsgpio_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = sysfsgpio_command_handlers, .init = sysfsgpio_init, diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 0a13bf6d44..417d560cde 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -2271,7 +2271,8 @@ static struct jtag_interface ulink_interface = { struct adapter_driver ulink_adapter_driver = { .name = "ulink", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ulink_command_handlers, .init = ulink_init, diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 1782cc424e..81344664e2 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -1057,7 +1057,8 @@ static struct jtag_interface usb_blaster_interface = { struct adapter_driver usb_blaster_adapter_driver = { .name = "usb_blaster", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .commands = ublast_command_handlers, .init = ublast_init, diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 24407f0037..264b45f721 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -590,7 +590,8 @@ static struct jtag_interface usbprog_interface = { struct adapter_driver usbprog_adapter_driver = { .name = "usbprog", - .transports = jtag_only, + .transport_ids = TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_JTAG, .init = usbprog_init, .quit = usbprog_quit, diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c index fd1e6a7e7b..38685950a8 100644 --- a/src/jtag/drivers/vdebug.c +++ b/src/jtag/drivers/vdebug.c @@ -1342,11 +1342,10 @@ static const struct dap_ops vdebug_dap_ops = { .quit = NULL, /* optional */ }; -static const char *const vdebug_transports[] = { "jtag", "dapdirect_swd", NULL }; - struct adapter_driver vdebug_adapter_driver = { .name = "vdebug", - .transports = vdebug_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_DAPDIRECT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .speed = vdebug_jtag_speed, .khz = vdebug_jtag_khz, .speed_div = vdebug_jtag_div, diff --git a/src/jtag/drivers/vsllink.c b/src/jtag/drivers/vsllink.c index c10ed13800..145f0682ac 100644 --- a/src/jtag/drivers/vsllink.c +++ b/src/jtag/drivers/vsllink.c @@ -913,8 +913,6 @@ static const struct command_registration vsllink_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -static const char * const vsllink_transports[] = {"jtag", "swd", NULL}; - static const struct swd_driver vsllink_swd_driver = { .init = vsllink_swd_init, .switch_seq = vsllink_swd_switch_seq, @@ -930,7 +928,8 @@ static struct jtag_interface vsllink_interface = { struct adapter_driver vsllink_adapter_driver = { .name = "vsllink", - .transports = vsllink_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = vsllink_command_handlers, .init = vsllink_init, diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index c84371001f..d1bb705908 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -2058,15 +2058,14 @@ static const struct swd_driver xds110_swd_driver = { .run = xds110_swd_run_queue, }; -static const char * const xds110_transport[] = { "swd", "jtag", NULL }; - static struct jtag_interface xds110_interface = { .execute_queue = xds110_execute_queue, }; struct adapter_driver xds110_adapter_driver = { .name = "xds110", - .transports = xds110_transport, + .transport_ids = TRANSPORT_SWD | TRANSPORT_JTAG, + .transport_preferred_id = TRANSPORT_SWD, .commands = xds110_command_handlers, .init = xds110_init, diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c index 37c6777e4e..3baa183d95 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -690,11 +690,10 @@ static const struct swd_driver xlnx_pcie_xvc_swd_ops = { .run = xlnx_pcie_xvc_swd_run_queue, }; -static const char * const xlnx_pcie_xvc_transports[] = { "jtag", "swd", NULL }; - struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .name = "xlnx_pcie_xvc", - .transports = xlnx_pcie_xvc_transports, + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, .commands = xlnx_pcie_xvc_command_handlers, .init = &xlnx_pcie_xvc_init, diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 96862b0d05..a9d196ccec 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -367,7 +367,8 @@ static const struct command_registration hl_interface_command_handlers[] = { struct adapter_driver hl_adapter_driver = { .name = "hla", - .transports = hl_transports, + .transport_ids = TRANSPORT_HLA_SWD | TRANSPORT_HLA_JTAG, + .transport_preferred_id = TRANSPORT_HLA_SWD, .commands = hl_interface_command_handlers, .init = hl_interface_init, diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index f1550d9915..c0ee05498d 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -15,8 +15,6 @@ struct target; /** */ enum e_hl_transports; -/** */ -extern const char *hl_transports[]; #define HLA_MAX_USB_IDS 16 diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index 333825eff1..d8ece0776b 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -231,8 +231,6 @@ static struct transport hl_jtag_transport = { .override_target = hl_interface_override_target, }; -const char *hl_transports[] = { "hla_swd", "hla_jtag", NULL }; - static void hl_constructor(void) __attribute__ ((constructor)); static void hl_constructor(void) { diff --git a/src/jtag/interface.h b/src/jtag/interface.h index b2d7123fd4..475dbed36e 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -17,6 +17,7 @@ #include #include #include +#include /* @file * The "Cable Helper API" is what the cable drivers can use to help @@ -208,8 +209,16 @@ struct adapter_driver { /** The name of the interface driver. */ const char * const name; - /** transports supported in C code (NULL terminated vector) */ - const char * const *transports; + /** + * Bitmask of transport IDs supported in C code. + */ + unsigned int transport_ids; + + /** + * ID of transport that gets auto-selected when not specified by the user. + * The auto-selection of transport is DEPRECATED. + */ + unsigned int transport_preferred_id; /** * The interface driver may register additional commands to expose @@ -354,8 +363,6 @@ struct adapter_driver { const struct swim_driver *swim_ops; }; -extern const char * const jtag_only[]; - int adapter_resets(int assert_trst, int assert_srst); int adapter_assert_reset(void); int adapter_deassert_reset(void); diff --git a/src/transport/transport.c b/src/transport/transport.c index 411b0a5e0f..b7a3913cc4 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -62,11 +62,15 @@ static const struct { static struct transport *transport_list; /** - * NULL-terminated Vector of names of transports which the - * currently selected debug adapter supports. This is declared - * by the time that adapter is fully set up. + * Bitmask of transport IDs which the currently selected debug adapter supports. + * This is declared by the time that adapter is fully set up. */ -static const char * const *allowed_transports; +static unsigned int allowed_transports; + +/** + * Transport ID auto-selected when not specified by the user. + */ +static unsigned int preferred_transport; /** * Adapter supports a single transport; it has been auto-selected @@ -76,7 +80,7 @@ static bool transport_single_is_autoselected; /** * The transport being used for the current OpenOCD session. */ static struct transport *session; -static const char *transport_name(unsigned int id) +const char *transport_name(unsigned int id) { for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++) if (id == transport_names[i].id) @@ -118,13 +122,14 @@ static int transport_select(struct command_context *ctx, const char *name) * to declare the set of transports supported by an adapter. When * there is only one member of that set, it is automatically selected. */ -int allow_transports(struct command_context *ctx, const char * const *vector) +int allow_transports(struct command_context *ctx, unsigned int transport_ids, + unsigned int transport_preferred_id) { /* NOTE: caller is required to provide only a list - * of *valid* transport names + * of *valid* transports * * REVISIT should we validate that? and insist there's - * at least one non-NULL element in that list? + * at least one valid element in that list? * * ... allow removals, e.g. external strapping prevents use * of one transport; C code should be definitive about what @@ -135,13 +140,14 @@ int allow_transports(struct command_context *ctx, const char * const *vector) return ERROR_FAIL; } - allowed_transports = vector; + allowed_transports = transport_ids; + preferred_transport = transport_preferred_id; /* autoselect if there's no choice ... */ - if (!vector[1]) { - LOG_DEBUG("only one transport option; autoselecting '%s'", vector[0]); + if (IS_PWR_OF_2(transport_ids)) { + LOG_DEBUG("only one transport option; autoselecting '%s'", transport_name(transport_ids)); transport_single_is_autoselected = true; - return transport_select(ctx, vector[0]); + return transport_select(ctx, transport_name(transport_ids)); } return ERROR_OK; @@ -226,10 +232,9 @@ COMMAND_HANDLER(handle_transport_init) /* no session transport configured, print transports then fail */ LOG_ERROR("Transports available:"); - const char * const *vector = allowed_transports; - while (*vector) { - LOG_ERROR("%s", *vector); - vector++; + for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) { + if (i & allowed_transports) + LOG_ERROR("%s", transport_name(i)); } return ERROR_FAIL; } @@ -275,8 +280,9 @@ COMMAND_HANDLER(handle_transport_select) } LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " "Use 'transport select %s' to suppress this message.", - allowed_transports[0], allowed_transports[0]); - int retval = transport_select(CMD_CTX, allowed_transports[0]); + transport_name(preferred_transport), + transport_name(preferred_transport)); + int retval = transport_select(CMD_CTX, transport_name(preferred_transport)); if (retval != ERROR_OK) return retval; } @@ -310,8 +316,9 @@ COMMAND_HANDLER(handle_transport_select) return ERROR_FAIL; } - for (unsigned int i = 0; allowed_transports[i]; i++) { - if (!strcmp(allowed_transports[i], CMD_ARGV[0])) { + for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) { + if ((i & allowed_transports) + && !strcmp(transport_name(i), CMD_ARGV[0])) { int retval = transport_select(CMD_CTX, CMD_ARGV[0]); if (retval != ERROR_OK) return retval; diff --git a/src/transport/transport.h b/src/transport/transport.h index dde7c6ba76..f6f0f4f4db 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -95,9 +95,12 @@ struct transport *get_current_transport(void); const char *get_current_transport_name(void); +const char *transport_name(unsigned int id); + int transport_register_commands(struct command_context *ctx); -int allow_transports(struct command_context *ctx, const char * const *vector); +int allow_transports(struct command_context *ctx, unsigned int transport_ids, + unsigned int transport_preferred_id); bool transport_is_jtag(void); bool transport_is_swd(void); From 8485eb141554851d6cfcf6faf47c5934d13bf040 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 22 Dec 2024 23:59:19 +0100 Subject: [PATCH 43/55] transport: validate the transport id's from the driver Verify that it contains only valid transports. While JTAG and SWD are the more permissive transports, the respective 'dapdirect' versions are slightly limited, and the respective 'hla' versions are even more limited. A driver should not provide two version of the same transport. Verify that only one JTAG and only one SWD transport is present. Verify that the preferred transport is valid too. Change-Id: Iace2f881dd65fc763e81b33e6a7113961a7008af Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8676 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Jan Matyas --- src/transport/transport.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/transport/transport.c b/src/transport/transport.c index b7a3913cc4..59f76ad31d 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -125,21 +125,37 @@ static int transport_select(struct command_context *ctx, const char *name) int allow_transports(struct command_context *ctx, unsigned int transport_ids, unsigned int transport_preferred_id) { - /* NOTE: caller is required to provide only a list - * of *valid* transports - * - * REVISIT should we validate that? and insist there's - * at least one valid element in that list? - * - * ... allow removals, e.g. external strapping prevents use - * of one transport; C code should be definitive about what - * can be used when all goes well. - */ if (allowed_transports || session) { LOG_ERROR("Can't modify the set of allowed transports."); return ERROR_FAIL; } + /* validate the values in transport_ids and transport_preferred_id */ + if (transport_ids == 0 || (transport_ids & ~TRANSPORT_VALID_MASK) != 0) { + LOG_ERROR("BUG: Unknown transport IDs %lu", transport_ids & ~TRANSPORT_VALID_MASK); + return ERROR_FAIL; + } + + if ((transport_ids & transport_preferred_id) == 0 + || !IS_PWR_OF_2(transport_preferred_id)) { + LOG_ERROR("BUG: Invalid adapter transport_preferred_id"); + return ERROR_FAIL; + } + + unsigned int mask = transport_ids & + (TRANSPORT_JTAG | TRANSPORT_HLA_JTAG | TRANSPORT_DAPDIRECT_JTAG); + if (mask && !IS_PWR_OF_2(mask)) { + LOG_ERROR("BUG: Multiple JTAG transports"); + return ERROR_FAIL; + } + + mask = transport_ids & + (TRANSPORT_SWD | TRANSPORT_HLA_SWD | TRANSPORT_DAPDIRECT_SWD); + if (mask && !IS_PWR_OF_2(mask)) { + LOG_ERROR("BUG: Multiple SWD transports"); + return ERROR_FAIL; + } + allowed_transports = transport_ids; preferred_transport = transport_preferred_id; From 9643379d30fee381e92200ef9ed0caaeae580dad Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 31 Dec 2024 16:29:46 +0100 Subject: [PATCH 44/55] transport: use helper/list.h for the list of transports No behavioral change, just use the list's helpers. Change-Id: I69712648ef77689bfe6acc4811adad7293fb9009 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8684 Reviewed-by: zapb Tested-by: jenkins --- src/transport/transport.c | 14 ++++++++------ src/transport/transport.h | 5 +++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/transport/transport.c b/src/transport/transport.c index 59f76ad31d..8a210fe94c 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -59,7 +60,7 @@ static const struct { }; /** List of transports registered in OpenOCD. */ -static struct transport *transport_list; +static OOCD_LIST_HEAD(transport_list); /** * Bitmask of transport IDs which the currently selected debug adapter supports. @@ -98,7 +99,8 @@ static int transport_select(struct command_context *ctx, const char *name) { /* name may only identify a known transport; * caller guarantees session's transport isn't yet set.*/ - for (struct transport *t = transport_list; t; t = t->next) { + struct transport *t; + list_for_each_entry(t, &transport_list, lh) { if (!strcmp(transport_name(t->id), name)) { int retval = t->select(ctx); /* select() registers commands specific to this @@ -193,7 +195,7 @@ int transport_register(struct transport *new_transport) return ERROR_FAIL; } - for (t = transport_list; t; t = t->next) { + list_for_each_entry(t, &transport_list, lh) { if (t->id == new_transport->id) { LOG_ERROR("transport '%s' already registered", transport_name(t->id)); @@ -206,8 +208,7 @@ int transport_register(struct transport *new_transport) transport_name(new_transport->id)); /* splice this into the list */ - new_transport->next = transport_list; - transport_list = new_transport; + list_add(&new_transport->lh, &transport_list); LOG_DEBUG("register '%s' (ID %d)", transport_name(new_transport->id), new_transport->id); @@ -270,7 +271,8 @@ COMMAND_HANDLER(handle_transport_list) command_print(CMD, "The following transports are available:"); - for (struct transport *t = transport_list; t; t = t->next) + struct transport *t; + list_for_each_entry(t, &transport_list, lh) command_print(CMD, "\t%s", transport_name(t->id)); return ERROR_OK; diff --git a/src/transport/transport.h b/src/transport/transport.h index f6f0f4f4db..5445bcf3b2 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -14,6 +14,7 @@ #include "helper/bits.h" #include "helper/command.h" +#include "helper/list.h" #define TRANSPORT_JTAG BIT(0) #define TRANSPORT_SWD BIT(1) @@ -84,9 +85,9 @@ struct transport { int (*override_target)(const char **targetname); /** - * Transports are stored in a singly linked list. + * Transports are stored in a linked list. */ - struct transport *next; + struct list_head lh; }; int transport_register(struct transport *new_transport); From 98c09dc257739440f25f5cd23ca9bbd495e5742a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 31 Dec 2024 17:01:41 +0100 Subject: [PATCH 45/55] transport: store the transports sorted by alphabetic name order While this operation has no real interest so far, it will be used later to avoid listing twice protocols with the same name. Change-Id: I59f3634830f94dc992d28863cf29d5d869726918 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8685 Tested-by: jenkins Reviewed-by: zapb --- src/transport/transport.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/transport/transport.c b/src/transport/transport.c index 8a210fe94c..755e21054e 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -59,7 +59,7 @@ static const struct { { TRANSPORT_SWIM, "swim", }, }; -/** List of transports registered in OpenOCD. */ +/** List of transports registered in OpenOCD, alphabetically sorted per name. */ static OOCD_LIST_HEAD(transport_list); /** @@ -207,8 +207,14 @@ int transport_register(struct transport *new_transport) LOG_ERROR("invalid transport %s", transport_name(new_transport->id)); - /* splice this into the list */ - list_add(&new_transport->lh, &transport_list); + /* splice this into the list, sorted in alphabetic order */ + list_for_each_entry(t, &transport_list, lh) { + if (strcmp(transport_name(t->id), + transport_name(new_transport->id)) >= 0) + break; + } + list_add_tail(&new_transport->lh, &t->lh); + LOG_DEBUG("register '%s' (ID %d)", transport_name(new_transport->id), new_transport->id); From c1c4d489df4bbbc2902c0e4ef744157994f1b22a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 12 Feb 2025 16:30:46 +0100 Subject: [PATCH 46/55] transport: allow transport name jtag/swd for hla and dapdirect The transport used on adapter's wires is either 'jtag' or 'swd' but, depending on the adapter, in the command 'transport select' we have to use either 'jtag' or 'swd' or the similar 'hla_jtag', 'hla_swd', 'dapdirect_jtag' or 'dapdirect_swd'. This becomes cumbersome when we just want to change adapter and we get forced to modify the 'transport select' command too. There is no reason for an adapter driver to support two of the similar transports. In fact 'dapdirect' one is a superset of the 'hla', and the native 'jtag' or 'swd' is a superset of the 'dapdirect' one. While the adapter could support more than one similar transports, its adapter driver should only support the most complete of these similar transports. Modify the 'transport select' code to accept 'jtag' or 'swd' for the 'dapdirect' and the 'hla' adapters too. Issue a deprecated message for the old 'dapdirect' and 'hla' transport names. In command 'transport list', print only the transport names that can be selected through 'transport select' skipping information about 'dapdirect' and 'hla' versions and avoid duplicated entries. This improvement was listed in the TODO file. Update it! Change-Id: I626b50e7a94c141c042eab388cd1ffe77eb864c2 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8677 Tested-by: jenkins --- README | 2 +- TODO | 2 - doc/openocd.texi | 14 +++--- src/transport/transport.c | 93 +++++++++++++++++++++++++++------------ 4 files changed, 70 insertions(+), 41 deletions(-) diff --git a/README b/README index fba758cfef..d9cc8f3eb0 100644 --- a/README +++ b/README @@ -42,7 +42,7 @@ openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" \ ``` ``` -openocd -f interface/stlink.cfg -c "transport select hla_swd" \ +openocd -f interface/stlink.cfg -c "transport select swd" \ -f target/stm32l0.cfg ``` diff --git a/TODO b/TODO index e4dded0ce6..239b358f57 100644 --- a/TODO +++ b/TODO @@ -60,8 +60,6 @@ changes pending in gerrit. to replicate it in the drivers, apart in case the driver sets TRST independently - add .hla_ops to "adapter" -- HLA is a API level (.hla_ops). Transport should simply be {jtag,swd}, - not {hla_jtag,hla_swd}. @subsection thelistadapterjtagcore JTAG Core diff --git a/doc/openocd.texi b/doc/openocd.texi index d85812824f..f557a55fee 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -3783,10 +3783,8 @@ JTAG supports both debugging and boundary scan testing. Flash programming support is built on top of debug support. JTAG transport is selected with the command @command{transport select -jtag}. Unless your adapter uses either @ref{hla_interface,the hla interface -driver} (in which case the command is @command{transport select hla_jtag}) -or @ref{st_link_dap_interface,the st-link interface driver} (in which case -the command is @command{transport select dapdirect_jtag}). +jtag}. This command has to be used also for @ref{hla_interface,the hla interface +driver} and @ref{st_link_dap_interface,the st-link interface driver}. @subsection SWD Transport @cindex SWD @@ -3799,10 +3797,8 @@ Flash programming support is built on top of debug support. (Some processors support both JTAG and SWD.) SWD transport is selected with the command @command{transport select -swd}. Unless your adapter uses either @ref{hla_interface,the hla interface -driver} (in which case the command is @command{transport select hla_swd}) -or @ref{st_link_dap_interface,the st-link interface driver} (in which case -the command is @command{transport select dapdirect_swd}). +swd}. This command has to be used also for @ref{hla_interface,the hla interface +driver} and @ref{st_link_dap_interface,the st-link interface driver}. @deffn {Config Command} {swd newdap} ... Declares a single DAP which uses SWD transport. @@ -10889,7 +10885,7 @@ baud with our custom divisor to get 12MHz) @item OpenOCD invocation line: @example openocd -f interface/stlink.cfg \ --c "transport select dapdirect_swd" \ +-c "transport select swd" \ -f target/stm32l1.cfg \ -c "stm32l1.tpiu configure -protocol uart" \ -c "stm32l1.tpiu configure -traceclk 24000000 -pin-freq 12000000" \ diff --git a/src/transport/transport.c b/src/transport/transport.c index 755e21054e..ab5be490fb 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -49,14 +49,16 @@ extern struct command_context *global_cmd_ctx; static const struct { unsigned int id; const char *name; + const char *full_name; + const char *deprecated_name; } transport_names[] = { - { TRANSPORT_JTAG, "jtag", }, - { TRANSPORT_SWD, "swd", }, - { TRANSPORT_HLA_JTAG, "hla_jtag", }, - { TRANSPORT_HLA_SWD, "hla_swd", }, - { TRANSPORT_DAPDIRECT_JTAG, "dapdirect_jtag", }, - { TRANSPORT_DAPDIRECT_SWD, "dapdirect_swd", }, - { TRANSPORT_SWIM, "swim", }, + { TRANSPORT_JTAG, "jtag", "jtag", NULL, }, + { TRANSPORT_SWD, "swd", "swd", NULL, }, + { TRANSPORT_HLA_JTAG, "jtag", "jtag (hla)", "hla_jtag", }, + { TRANSPORT_HLA_SWD, "swd", "swd (hla)", "hla_swd", }, + { TRANSPORT_DAPDIRECT_JTAG, "jtag", "jtag (dapdirect)", "dapdirect_jtag", }, + { TRANSPORT_DAPDIRECT_SWD, "swd", "swd (dapdirect)", "dapdirect_swd", }, + { TRANSPORT_SWIM, "swim", "swim", NULL, }, }; /** List of transports registered in OpenOCD, alphabetically sorted per name. */ @@ -90,18 +92,36 @@ const char *transport_name(unsigned int id) return NULL; } +static const char *transport_full_name(unsigned int id) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++) + if (id == transport_names[i].id) + return transport_names[i].full_name; + + return NULL; +} + +static const char *transport_deprecated_name(unsigned int id) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++) + if (id == transport_names[i].id) + return transport_names[i].deprecated_name; + + return NULL; +} + static bool is_transport_id_valid(unsigned int id) { return (id != 0) && ((id & ~TRANSPORT_VALID_MASK) == 0) && IS_PWR_OF_2(id); } -static int transport_select(struct command_context *ctx, const char *name) +static int transport_select(struct command_context *ctx, unsigned int transport_id) { /* name may only identify a known transport; * caller guarantees session's transport isn't yet set.*/ struct transport *t; list_for_each_entry(t, &transport_list, lh) { - if (!strcmp(transport_name(t->id), name)) { + if (t->id == transport_id) { int retval = t->select(ctx); /* select() registers commands specific to this * transport, and may also reset the link, e.g. @@ -110,12 +130,14 @@ static int transport_select(struct command_context *ctx, const char *name) if (retval == ERROR_OK) session = t; else - LOG_ERROR("Error selecting '%s' as transport", name); + LOG_ERROR("Error selecting '%s' as transport", + transport_full_name(transport_id)); return retval; } } - LOG_ERROR("No transport named '%s' is available.", name); + LOG_ERROR("No transport named '%s' is available.", + transport_full_name(transport_id)); return ERROR_FAIL; } @@ -165,7 +187,7 @@ int allow_transports(struct command_context *ctx, unsigned int transport_ids, if (IS_PWR_OF_2(transport_ids)) { LOG_DEBUG("only one transport option; autoselecting '%s'", transport_name(transport_ids)); transport_single_is_autoselected = true; - return transport_select(ctx, transport_name(transport_ids)); + return transport_select(ctx, transport_ids); } return ERROR_OK; @@ -205,7 +227,7 @@ int transport_register(struct transport *new_transport) if (!new_transport->select || !new_transport->init) LOG_ERROR("invalid transport %s", - transport_name(new_transport->id)); + transport_full_name(new_transport->id)); /* splice this into the list, sorted in alphabetic order */ list_for_each_entry(t, &transport_list, lh) { @@ -216,7 +238,7 @@ int transport_register(struct transport *new_transport) list_add_tail(&new_transport->lh, &t->lh); LOG_DEBUG("register '%s' (ID %d)", - transport_name(new_transport->id), new_transport->id); + transport_full_name(new_transport->id), new_transport->id); return ERROR_OK; } @@ -238,7 +260,7 @@ const char *get_current_transport_name(void) if (!session || !is_transport_id_valid(session->id)) NULL; - return transport_name(session->id); + return transport_full_name(session->id); } /*-----------------------------------------------------------------------*/ @@ -257,7 +279,7 @@ COMMAND_HANDLER(handle_transport_init) LOG_ERROR("Transports available:"); for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) { if (i & allowed_transports) - LOG_ERROR("%s", transport_name(i)); + LOG_ERROR("%s", transport_full_name(i)); } return ERROR_FAIL; } @@ -265,7 +287,7 @@ COMMAND_HANDLER(handle_transport_init) if (transport_single_is_autoselected) LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " "Use 'transport select %s' to suppress this message.", - transport_name(session->id), transport_name(session->id)); + transport_full_name(session->id), transport_name(session->id)); return session->init(CMD_CTX); } @@ -278,8 +300,14 @@ COMMAND_HANDLER(handle_transport_list) command_print(CMD, "The following transports are available:"); struct transport *t; - list_for_each_entry(t, &transport_list, lh) - command_print(CMD, "\t%s", transport_name(t->id)); + const char *prev_name = NULL; + /* list is sorted, don't print duplicated transport names */ + list_for_each_entry(t, &transport_list, lh) { + const char *name = transport_name(t->id); + if (!prev_name || strcmp(prev_name, name)) + command_print(CMD, "\t%s", name); + prev_name = name; + } return ERROR_OK; } @@ -304,19 +332,21 @@ COMMAND_HANDLER(handle_transport_select) } LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". " "Use 'transport select %s' to suppress this message.", - transport_name(preferred_transport), + transport_full_name(preferred_transport), transport_name(preferred_transport)); - int retval = transport_select(CMD_CTX, transport_name(preferred_transport)); + int retval = transport_select(CMD_CTX, preferred_transport); if (retval != ERROR_OK) return retval; } - command_print(CMD, "%s", transport_name(session->id)); + command_print(CMD, "%s", transport_full_name(session->id)); return ERROR_OK; } /* assign transport */ if (session) { - if (!strcmp(transport_name(session->id), CMD_ARGV[0])) { + if (!strcmp(transport_name(session->id), CMD_ARGV[0]) + || (transport_deprecated_name(session->id) + && !strcmp(transport_deprecated_name(session->id), CMD_ARGV[0]))) { if (transport_single_is_autoselected) { /* Nothing to do, but also nothing to complain */ transport_single_is_autoselected = false; @@ -341,12 +371,17 @@ COMMAND_HANDLER(handle_transport_select) } for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) { - if ((i & allowed_transports) - && !strcmp(transport_name(i), CMD_ARGV[0])) { - int retval = transport_select(CMD_CTX, CMD_ARGV[0]); - if (retval != ERROR_OK) - return retval; - return ERROR_OK; + if (!(i & allowed_transports)) + continue; + + if (!strcmp(transport_name(i), CMD_ARGV[0])) + return transport_select(CMD_CTX, i); + + if (transport_deprecated_name(i) + && !strcmp(transport_deprecated_name(i), CMD_ARGV[0])) { + LOG_WARNING("DEPRECATED! use 'transport select %s', not 'transport select %s'", + transport_name(i), transport_deprecated_name(i)); + return transport_select(CMD_CTX, i); } } From ad53fe659b46657ddf16a08f8dc4f4d0c5df8901 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 23 Dec 2024 18:10:10 +0100 Subject: [PATCH 47/55] tcl: convert transport select to jtag and swd Convert every transport select command: - hla_swd -> swd - dapdirect_swd -> swd - hla_jtag -> jtag - dapdirect_jtag -> jtag Change-Id: I81971e06f7aefd21a570a4e098cf3822a775464b Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8678 Reviewed-by: zapb Tested-by: jenkins --- tcl/board/ek-lm4f120xl.cfg | 2 +- tcl/board/ek-lm4f232.cfg | 2 +- tcl/board/st_b-l475e-iot01a.cfg | 2 +- tcl/board/st_nucleo_f0.cfg | 2 +- tcl/board/st_nucleo_f103rb.cfg | 2 +- tcl/board/st_nucleo_f3.cfg | 2 +- tcl/board/st_nucleo_f4.cfg | 2 +- tcl/board/st_nucleo_f7.cfg | 2 +- tcl/board/st_nucleo_g0.cfg | 2 +- tcl/board/st_nucleo_g4.cfg | 2 +- tcl/board/st_nucleo_h743zi.cfg | 2 +- tcl/board/st_nucleo_h745zi.cfg | 2 +- tcl/board/st_nucleo_l073rz.cfg | 2 +- tcl/board/st_nucleo_l1.cfg | 2 +- tcl/board/st_nucleo_l4.cfg | 2 +- tcl/board/st_nucleo_l5.cfg | 2 +- tcl/board/st_nucleo_wb55.cfg | 2 +- tcl/board/stm320518_eval_stlink.cfg | 2 +- tcl/board/stm3220g_eval_stlink.cfg | 2 +- tcl/board/stm3241g_eval_stlink.cfg | 2 +- tcl/board/stm32429i_eval_stlink.cfg | 2 +- tcl/board/stm32439i_eval_stlink.cfg | 2 +- tcl/board/stm32f0discovery.cfg | 2 +- tcl/board/stm32f3discovery.cfg | 2 +- tcl/board/stm32f412g-disco.cfg | 2 +- tcl/board/stm32f413h-disco.cfg | 2 +- tcl/board/stm32f429disc1.cfg | 2 +- tcl/board/stm32f429discovery.cfg | 2 +- tcl/board/stm32f469discovery.cfg | 2 +- tcl/board/stm32f469i-disco.cfg | 2 +- tcl/board/stm32f4discovery.cfg | 2 +- tcl/board/stm32f723e-disco.cfg | 2 +- tcl/board/stm32f746g-disco.cfg | 2 +- tcl/board/stm32f769i-disco.cfg | 2 +- tcl/board/stm32f7discovery.cfg | 2 +- tcl/board/stm32h735g-disco.cfg | 2 +- tcl/board/stm32h745i-disco.cfg | 2 +- tcl/board/stm32h747i-disco.cfg | 2 +- tcl/board/stm32h750b-disco.cfg | 2 +- tcl/board/stm32h7b3i-disco.cfg | 2 +- tcl/board/stm32h7x3i_eval.cfg | 2 +- tcl/board/stm32l0discovery.cfg | 2 +- tcl/board/stm32l476g-disco.cfg | 2 +- tcl/board/stm32l496g-disco.cfg | 2 +- tcl/board/stm32l4discovery.cfg | 2 +- tcl/board/stm32l4p5g-disco.cfg | 2 +- tcl/board/stm32l4r9i-disco.cfg | 2 +- tcl/board/stm32ldiscovery.cfg | 2 +- tcl/board/stm32mp13x_dk.cfg | 2 +- tcl/board/stm32mp15x_dk2.cfg | 2 +- tcl/board/stm32vldiscovery.cfg | 2 +- tcl/board/ti_dk-tm4c129.cfg | 2 +- tcl/board/ti_ek-tm4c123gxl.cfg | 2 +- tcl/board/ti_ek-tm4c1294xl.cfg | 2 +- tcl/board/vd_a53x2_dap.cfg | 2 +- tcl/board/vd_a75x4_dap.cfg | 2 +- tcl/board/vd_m4_dap.cfg | 2 +- tcl/interface/nulink.cfg | 2 +- tcl/interface/rshim.cfg | 2 +- tcl/interface/stlink.cfg | 4 ++-- 60 files changed, 61 insertions(+), 61 deletions(-) diff --git a/tcl/board/ek-lm4f120xl.cfg b/tcl/board/ek-lm4f120xl.cfg index db8b2010ba..44b1b1ea12 100644 --- a/tcl/board/ek-lm4f120xl.cfg +++ b/tcl/board/ek-lm4f120xl.cfg @@ -12,7 +12,7 @@ # source [find interface/ti-icdi.cfg] -transport select hla_jtag +transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f120h5qr diff --git a/tcl/board/ek-lm4f232.cfg b/tcl/board/ek-lm4f232.cfg index 89b2c3ce88..bb7f9ea5b0 100644 --- a/tcl/board/ek-lm4f232.cfg +++ b/tcl/board/ek-lm4f232.cfg @@ -12,7 +12,7 @@ # source [find interface/ti-icdi.cfg] -transport select hla_jtag +transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME lm4f23x diff --git a/tcl/board/st_b-l475e-iot01a.cfg b/tcl/board/st_b-l475e-iot01a.cfg index 3f3db125c8..5bdbdb4a26 100644 --- a/tcl/board/st_b-l475e-iot01a.cfg +++ b/tcl/board/st_b-l475e-iot01a.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 96KB set WORKAREASIZE 0x18000 diff --git a/tcl/board/st_nucleo_f0.cfg b/tcl/board/st_nucleo_f0.cfg index 00c131fd64..4d80711275 100644 --- a/tcl/board/st_nucleo_f0.cfg +++ b/tcl/board/st_nucleo_f0.cfg @@ -10,7 +10,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32f0x.cfg] diff --git a/tcl/board/st_nucleo_f103rb.cfg b/tcl/board/st_nucleo_f103rb.cfg index 892bdda99d..1b440ed9e7 100644 --- a/tcl/board/st_nucleo_f103rb.cfg +++ b/tcl/board/st_nucleo_f103rb.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32f1x.cfg] diff --git a/tcl/board/st_nucleo_f3.cfg b/tcl/board/st_nucleo_f3.cfg index 38f49e3d5f..8ff57eecee 100644 --- a/tcl/board/st_nucleo_f3.cfg +++ b/tcl/board/st_nucleo_f3.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32f3x.cfg] diff --git a/tcl/board/st_nucleo_f4.cfg b/tcl/board/st_nucleo_f4.cfg index 7617a17580..574417c967 100644 --- a/tcl/board/st_nucleo_f4.cfg +++ b/tcl/board/st_nucleo_f4.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32f4x.cfg] diff --git a/tcl/board/st_nucleo_f7.cfg b/tcl/board/st_nucleo_f7.cfg index 41f8b21291..eaf79669ca 100644 --- a/tcl/board/st_nucleo_f7.cfg +++ b/tcl/board/st_nucleo_f7.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32f7x.cfg] diff --git a/tcl/board/st_nucleo_g0.cfg b/tcl/board/st_nucleo_g0.cfg index f22a7e397e..c68d3d0e5a 100644 --- a/tcl/board/st_nucleo_g0.cfg +++ b/tcl/board/st_nucleo_g0.cfg @@ -12,7 +12,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32g0x.cfg] diff --git a/tcl/board/st_nucleo_g4.cfg b/tcl/board/st_nucleo_g4.cfg index 309f7a4c84..3debdc3815 100644 --- a/tcl/board/st_nucleo_g4.cfg +++ b/tcl/board/st_nucleo_g4.cfg @@ -12,7 +12,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32g4x.cfg] diff --git a/tcl/board/st_nucleo_h743zi.cfg b/tcl/board/st_nucleo_h743zi.cfg index be2d42fb8a..a996d744b1 100644 --- a/tcl/board/st_nucleo_h743zi.cfg +++ b/tcl/board/st_nucleo_h743zi.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32h7x_dual_bank.cfg] diff --git a/tcl/board/st_nucleo_h745zi.cfg b/tcl/board/st_nucleo_h745zi.cfg index 84865f422d..697d1972a0 100644 --- a/tcl/board/st_nucleo_h745zi.cfg +++ b/tcl/board/st_nucleo_h745zi.cfg @@ -3,7 +3,7 @@ # This is an ST NUCLEO-H745ZI-Q board with single STM32H745ZITx chip. source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # STM32H745xx devices are dual core (Cortex-M7 and Cortex-M4) set DUAL_CORE 1 diff --git a/tcl/board/st_nucleo_l073rz.cfg b/tcl/board/st_nucleo_l073rz.cfg index 317c86e21d..d1a2e07689 100644 --- a/tcl/board/st_nucleo_l073rz.cfg +++ b/tcl/board/st_nucleo_l073rz.cfg @@ -4,7 +4,7 @@ # http://www.st.com/en/evaluation-tools/nucleo-l073rz.html source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set WORKAREASIZE 0x2000 diff --git a/tcl/board/st_nucleo_l1.cfg b/tcl/board/st_nucleo_l1.cfg index d7474d0fe2..0ffc71dfee 100644 --- a/tcl/board/st_nucleo_l1.cfg +++ b/tcl/board/st_nucleo_l1.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32l1x_dual_bank.cfg] diff --git a/tcl/board/st_nucleo_l4.cfg b/tcl/board/st_nucleo_l4.cfg index b0a75afe02..dad3cc4b9a 100644 --- a/tcl/board/st_nucleo_l4.cfg +++ b/tcl/board/st_nucleo_l4.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32l4x.cfg] diff --git a/tcl/board/st_nucleo_l5.cfg b/tcl/board/st_nucleo_l5.cfg index 626914aa75..f3cb680c25 100644 --- a/tcl/board/st_nucleo_l5.cfg +++ b/tcl/board/st_nucleo_l5.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32l5x.cfg] diff --git a/tcl/board/st_nucleo_wb55.cfg b/tcl/board/st_nucleo_wb55.cfg index ab7307c683..79ddb1ccd2 100644 --- a/tcl/board/st_nucleo_wb55.cfg +++ b/tcl/board/st_nucleo_wb55.cfg @@ -6,7 +6,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32wbx.cfg] diff --git a/tcl/board/stm320518_eval_stlink.cfg b/tcl/board/stm320518_eval_stlink.cfg index 997bb4af95..8f4652eff9 100644 --- a/tcl/board/stm320518_eval_stlink.cfg +++ b/tcl/board/stm320518_eval_stlink.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 8KB set WORKAREASIZE 0x2000 diff --git a/tcl/board/stm3220g_eval_stlink.cfg b/tcl/board/stm3220g_eval_stlink.cfg index 4233d04f15..d212bbc298 100644 --- a/tcl/board/stm3220g_eval_stlink.cfg +++ b/tcl/board/stm3220g_eval_stlink.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm3241g_eval_stlink.cfg b/tcl/board/stm3241g_eval_stlink.cfg index 3bccd28661..e1ab2026b4 100644 --- a/tcl/board/stm3241g_eval_stlink.cfg +++ b/tcl/board/stm3241g_eval_stlink.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32429i_eval_stlink.cfg b/tcl/board/stm32429i_eval_stlink.cfg index 7d04aa7f3a..ec7e10c437 100644 --- a/tcl/board/stm32429i_eval_stlink.cfg +++ b/tcl/board/stm32429i_eval_stlink.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32439i_eval_stlink.cfg b/tcl/board/stm32439i_eval_stlink.cfg index b9ea084dfd..bac64c81a5 100644 --- a/tcl/board/stm32439i_eval_stlink.cfg +++ b/tcl/board/stm32439i_eval_stlink.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32f0discovery.cfg b/tcl/board/stm32f0discovery.cfg index 398ecc1037..9a8e921538 100644 --- a/tcl/board/stm32f0discovery.cfg +++ b/tcl/board/stm32f0discovery.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set WORKAREASIZE 0x2000 source [find target/stm32f0x.cfg] diff --git a/tcl/board/stm32f3discovery.cfg b/tcl/board/stm32f3discovery.cfg index 73c349a6ef..661082acfa 100644 --- a/tcl/board/stm32f3discovery.cfg +++ b/tcl/board/stm32f3discovery.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32f3x.cfg] diff --git a/tcl/board/stm32f412g-disco.cfg b/tcl/board/stm32f412g-disco.cfg index 30a9537f0b..e278062919 100644 --- a/tcl/board/stm32f412g-disco.cfg +++ b/tcl/board/stm32f412g-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32f413h-disco.cfg b/tcl/board/stm32f413h-disco.cfg index c82d0d4349..9a72c121c5 100644 --- a/tcl/board/stm32f413h-disco.cfg +++ b/tcl/board/stm32f413h-disco.cfg @@ -10,7 +10,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32f429disc1.cfg b/tcl/board/stm32f429disc1.cfg index 0a8e7ef4e6..a5646c9ecc 100644 --- a/tcl/board/stm32f429disc1.cfg +++ b/tcl/board/stm32f429disc1.cfg @@ -7,7 +7,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32f4x.cfg] diff --git a/tcl/board/stm32f429discovery.cfg b/tcl/board/stm32f429discovery.cfg index 865602ab69..735254e7f6 100644 --- a/tcl/board/stm32f429discovery.cfg +++ b/tcl/board/stm32f429discovery.cfg @@ -7,7 +7,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32f469discovery.cfg b/tcl/board/stm32f469discovery.cfg index c9acbbbd0c..7d39929064 100644 --- a/tcl/board/stm32f469discovery.cfg +++ b/tcl/board/stm32f469discovery.cfg @@ -7,7 +7,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32f469i-disco.cfg b/tcl/board/stm32f469i-disco.cfg index 63c42c64e9..45ec9a2691 100644 --- a/tcl/board/stm32f469i-disco.cfg +++ b/tcl/board/stm32f469i-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32f4discovery.cfg b/tcl/board/stm32f4discovery.cfg index d96e2dbd34..73ede7ed71 100644 --- a/tcl/board/stm32f4discovery.cfg +++ b/tcl/board/stm32f4discovery.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 64KB set WORKAREASIZE 0x10000 diff --git a/tcl/board/stm32f723e-disco.cfg b/tcl/board/stm32f723e-disco.cfg index 0207956206..8acefff4c3 100644 --- a/tcl/board/stm32f723e-disco.cfg +++ b/tcl/board/stm32f723e-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 128KB set WORKAREASIZE 0x20000 diff --git a/tcl/board/stm32f746g-disco.cfg b/tcl/board/stm32f746g-disco.cfg index 75ff4ec1e2..04ed72cc50 100644 --- a/tcl/board/stm32f746g-disco.cfg +++ b/tcl/board/stm32f746g-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 256KB set WORKAREASIZE 0x40000 diff --git a/tcl/board/stm32f769i-disco.cfg b/tcl/board/stm32f769i-disco.cfg index cd6383a700..89e197c525 100644 --- a/tcl/board/stm32f769i-disco.cfg +++ b/tcl/board/stm32f769i-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 256KB set WORKAREASIZE 0x40000 diff --git a/tcl/board/stm32f7discovery.cfg b/tcl/board/stm32f7discovery.cfg index 6fd6c64b3d..3f3bceb845 100644 --- a/tcl/board/stm32f7discovery.cfg +++ b/tcl/board/stm32f7discovery.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK/V2-1 source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 256KB set WORKAREASIZE 0x40000 diff --git a/tcl/board/stm32h735g-disco.cfg b/tcl/board/stm32h735g-disco.cfg index 327a36418c..e839c7a547 100644 --- a/tcl/board/stm32h735g-disco.cfg +++ b/tcl/board/stm32h735g-disco.cfg @@ -7,7 +7,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set CHIPNAME stm32h735igk6 diff --git a/tcl/board/stm32h745i-disco.cfg b/tcl/board/stm32h745i-disco.cfg index 9da1daefc6..700f141d26 100644 --- a/tcl/board/stm32h745i-disco.cfg +++ b/tcl/board/stm32h745i-disco.cfg @@ -7,7 +7,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set CHIPNAME stm32h745xih6 diff --git a/tcl/board/stm32h747i-disco.cfg b/tcl/board/stm32h747i-disco.cfg index 7f8eda8c45..e95ad8a12b 100644 --- a/tcl/board/stm32h747i-disco.cfg +++ b/tcl/board/stm32h747i-disco.cfg @@ -7,7 +7,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set CHIPNAME stm32h747xih6 diff --git a/tcl/board/stm32h750b-disco.cfg b/tcl/board/stm32h750b-disco.cfg index 8b254f21fd..8f0f15b53e 100644 --- a/tcl/board/stm32h750b-disco.cfg +++ b/tcl/board/stm32h750b-disco.cfg @@ -7,7 +7,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set CHIPNAME stm32h750xbh6 diff --git a/tcl/board/stm32h7b3i-disco.cfg b/tcl/board/stm32h7b3i-disco.cfg index df0d0a6f27..de009570f5 100644 --- a/tcl/board/stm32h7b3i-disco.cfg +++ b/tcl/board/stm32h7b3i-disco.cfg @@ -7,7 +7,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set CHIPNAME stm32h7b3lih6q diff --git a/tcl/board/stm32h7x3i_eval.cfg b/tcl/board/stm32h7x3i_eval.cfg index 508f10d5d1..1880bb871e 100644 --- a/tcl/board/stm32h7x3i_eval.cfg +++ b/tcl/board/stm32h7x3i_eval.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32h7x_dual_bank.cfg] diff --git a/tcl/board/stm32l0discovery.cfg b/tcl/board/stm32l0discovery.cfg index 59aed3405d..06d02ed024 100644 --- a/tcl/board/stm32l0discovery.cfg +++ b/tcl/board/stm32l0discovery.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set WORKAREASIZE 0x2000 source [find target/stm32l0.cfg] diff --git a/tcl/board/stm32l476g-disco.cfg b/tcl/board/stm32l476g-disco.cfg index fe33ffefb9..e3d4de3c0d 100644 --- a/tcl/board/stm32l476g-disco.cfg +++ b/tcl/board/stm32l476g-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 96KB set WORKAREASIZE 0x18000 diff --git a/tcl/board/stm32l496g-disco.cfg b/tcl/board/stm32l496g-disco.cfg index 823fa6e380..a715bb058d 100644 --- a/tcl/board/stm32l496g-disco.cfg +++ b/tcl/board/stm32l496g-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 96KB set WORKAREASIZE 0x18000 diff --git a/tcl/board/stm32l4discovery.cfg b/tcl/board/stm32l4discovery.cfg index 64a456b612..7f724f9bd2 100644 --- a/tcl/board/stm32l4discovery.cfg +++ b/tcl/board/stm32l4discovery.cfg @@ -8,7 +8,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32l4x.cfg] diff --git a/tcl/board/stm32l4p5g-disco.cfg b/tcl/board/stm32l4p5g-disco.cfg index 33bb9a7662..86c05a18d4 100644 --- a/tcl/board/stm32l4p5g-disco.cfg +++ b/tcl/board/stm32l4p5g-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 96KB set WORKAREASIZE 0x18000 diff --git a/tcl/board/stm32l4r9i-disco.cfg b/tcl/board/stm32l4r9i-disco.cfg index cbb86669f0..de23cc1ae5 100644 --- a/tcl/board/stm32l4r9i-disco.cfg +++ b/tcl/board/stm32l4r9i-disco.cfg @@ -6,7 +6,7 @@ # This is for using the onboard STLINK source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd # increase working area to 96KB set WORKAREASIZE 0x18000 diff --git a/tcl/board/stm32ldiscovery.cfg b/tcl/board/stm32ldiscovery.cfg index e39b52295a..38b8a8bd0a 100644 --- a/tcl/board/stm32ldiscovery.cfg +++ b/tcl/board/stm32ldiscovery.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set WORKAREASIZE 0x4000 source [find target/stm32l1.cfg] diff --git a/tcl/board/stm32mp13x_dk.cfg b/tcl/board/stm32mp13x_dk.cfg index 08377ca76a..8ece24844c 100644 --- a/tcl/board/stm32mp13x_dk.cfg +++ b/tcl/board/stm32mp13x_dk.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32mp13x.cfg] diff --git a/tcl/board/stm32mp15x_dk2.cfg b/tcl/board/stm32mp15x_dk2.cfg index 0e71e05ee0..ba1c7f78a6 100644 --- a/tcl/board/stm32mp15x_dk2.cfg +++ b/tcl/board/stm32mp15x_dk2.cfg @@ -6,7 +6,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32mp15x.cfg] diff --git a/tcl/board/stm32vldiscovery.cfg b/tcl/board/stm32vldiscovery.cfg index 57852bfd4f..d79c62ea43 100644 --- a/tcl/board/stm32vldiscovery.cfg +++ b/tcl/board/stm32vldiscovery.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd set WORKAREASIZE 0x2000 source [find target/stm32f1x.cfg] diff --git a/tcl/board/ti_dk-tm4c129.cfg b/tcl/board/ti_dk-tm4c129.cfg index d8210e32d2..e0574fa870 100644 --- a/tcl/board/ti_dk-tm4c129.cfg +++ b/tcl/board/ti_dk-tm4c129.cfg @@ -8,7 +8,7 @@ source [find interface/ti-icdi.cfg] -transport select hla_jtag +transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c129xnczad diff --git a/tcl/board/ti_ek-tm4c123gxl.cfg b/tcl/board/ti_ek-tm4c123gxl.cfg index 91390fa82f..7b8fc267f5 100644 --- a/tcl/board/ti_ek-tm4c123gxl.cfg +++ b/tcl/board/ti_ek-tm4c123gxl.cfg @@ -8,7 +8,7 @@ source [find interface/ti-icdi.cfg] -transport select hla_jtag +transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c123gh6pm diff --git a/tcl/board/ti_ek-tm4c1294xl.cfg b/tcl/board/ti_ek-tm4c1294xl.cfg index 63612c686b..8cceb49c96 100644 --- a/tcl/board/ti_ek-tm4c1294xl.cfg +++ b/tcl/board/ti_ek-tm4c1294xl.cfg @@ -8,7 +8,7 @@ source [find interface/ti-icdi.cfg] -transport select hla_jtag +transport select jtag set WORKAREASIZE 0x8000 set CHIPNAME tm4c1294ncpdt diff --git a/tcl/board/vd_a53x2_dap.cfg b/tcl/board/vd_a53x2_dap.cfg index bcf8b44098..3251afd066 100644 --- a/tcl/board/vd_a53x2_dap.cfg +++ b/tcl/board/vd_a53x2_dap.cfg @@ -13,7 +13,7 @@ set DBGBASE {0x80810000 0x80910000} set CTIBASE {0x80820000 0x80920000} # vdebug select transport -transport select dapdirect_swd +transport select swd # JTAG reset config, frequency and reset delay adapter speed 50000 diff --git a/tcl/board/vd_a75x4_dap.cfg b/tcl/board/vd_a75x4_dap.cfg index 5c2a2efe87..2f4406b038 100644 --- a/tcl/board/vd_a75x4_dap.cfg +++ b/tcl/board/vd_a75x4_dap.cfg @@ -13,7 +13,7 @@ set DBGBASE {0x01010000 0x01110000 0x01210000 0x01310000} set CTIBASE {0x01020000 0x01120000 0x01220000 0x01320000} # vdebug select transport -transport select dapdirect_swd +transport select swd # JTAG reset config, frequency and reset delay adapter speed 200000 diff --git a/tcl/board/vd_m4_dap.cfg b/tcl/board/vd_m4_dap.cfg index 5d3605aa37..f56334e834 100644 --- a/tcl/board/vd_m4_dap.cfg +++ b/tcl/board/vd_m4_dap.cfg @@ -9,7 +9,7 @@ set MEMSTART 0x00000000 set MEMSIZE 0x10000 # vdebug select transport -transport select dapdirect_swd +transport select swd adapter speed 25000 adapter srst delay 5 diff --git a/tcl/interface/nulink.cfg b/tcl/interface/nulink.cfg index 48dc20e241..be68347e73 100644 --- a/tcl/interface/nulink.cfg +++ b/tcl/interface/nulink.cfg @@ -10,4 +10,4 @@ hla device_desc "Nu-Link" hla vid_pid 0x0416 0x511b 0x0416 0x511c 0x0416 0x511d 0x0416 0x5200 0x0416 0x5201 # Only swd is supported -transport select hla_swd +transport select swd diff --git a/tcl/interface/rshim.cfg b/tcl/interface/rshim.cfg index 1d5da593e7..327212f681 100644 --- a/tcl/interface/rshim.cfg +++ b/tcl/interface/rshim.cfg @@ -5,4 +5,4 @@ # adapter driver rshim -transport select dapdirect_swd +transport select swd diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg index 99c81c180c..962d192ec5 100644 --- a/tcl/interface/stlink.cfg +++ b/tcl/interface/stlink.cfg @@ -13,8 +13,8 @@ adapter driver st-link st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 -# transport select dapdirect_jtag -# transport select dapdirect_swd +# transport select jtag +# transport select swd # transport select swim # Optionally specify the serial number of usb device From 420f637cab324541230fbff0dea447cf40df3b0f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 23 Dec 2024 20:20:08 +0100 Subject: [PATCH 48/55] stlink: simplify the use of deprecated HLA transport Commit 34ec5536c0ba ("stlink: deprecate HLA support") makes hard to use the still functional HLA transport with the stlink listed in board config files. Now that the prefixes 'hla_' and 'dapdirect_' has been dropped from the transport name, allow overriding the transport by using the 'stlink-hla' script in front of the board file, e.g.: openocd -f interface/stlink-hla.cfg -f board/st_nucleo_f4.cfg Revert the documentation changes of the change above. Improve the documentation to explain how to use the compatibility HLA mode. Improve the error message in stlink driver to guide the user to update the stlink firmware and to use the compatibility HLA mode. Change-Id: I5d0bc7954511692cebe024bda2aaa72767b97681 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/8679 Tested-by: jenkins --- doc/openocd.texi | 21 +++++++++++++++++++-- src/jtag/drivers/stlink_usb.c | 7 ++++++- tcl/interface/stlink.cfg | 6 ++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index f557a55fee..cbe5e86dab 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2497,7 +2497,7 @@ This command is only available if your libusb1 is at least version 1.0.16. Specifies the @var{serial_string} of the adapter to use. If this command is not specified, serial strings are not checked. Only the following adapter drivers use the serial string from this command: -arm-jtag-ew, cmsis_dap, esp_usb_jtag, ft232r, ftdi, hla (ti-icdi), jlink, kitprog, opendus, +arm-jtag-ew, cmsis_dap, esp_usb_jtag, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus, openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110. @end deffn @@ -3205,16 +3205,19 @@ that OpenOCD would normally use to access the target. Currently supported adapters include the STMicroelectronics ST-LINK, TI ICDI and Nuvoton Nu-Link. + ST-LINK firmware version >= V2.J21.S4 recommended due to issues with earlier versions of firmware where serial number is reset after first use. Suggest using ST firmware update utility to upgrade ST-LINK firmware even if current version reported is V2.J21.S4. +The ST-LINK firmware update utility is available for download from +@url{https://www.st.com/en/development-tools/stsw-link007.html, ST website}. @deffn {Config Command} {hla device_desc} description Currently Not Supported. @end deffn -@deffn {Config Command} {hla layout} (@option{icdi}|@option{nulink}) +@deffn {Config Command} {hla layout} (@option{stlink}|@option{icdi}|@option{nulink}) Specifies the adapter layout to use. @end deffn @@ -3222,6 +3225,15 @@ Specifies the adapter layout to use. Pairs of vendor IDs and product IDs of the device. @end deffn +@deffn {Config Command} {hla stlink_backend} (usb | tcp [port]) +@emph{ST-Link only:} Choose between 'exclusive' USB communication (the default backend) or +'shared' mode using ST-Link TCP server (the default port is 7184). + +@emph{Note:} ST-Link TCP server is a binary application provided by ST +available from @url{https://www.st.com/en/development-tools/st-link-server.html, +ST-LINK server software module}. +@end deffn + @deffn {Command} {hla command} command Execute a custom adapter-specific command. The @var{command} string is passed as is to the underlying adapter layout handler. @@ -3236,6 +3248,11 @@ directly access the arm ADIv5 DAP. The older API that requires HLA transport is deprecated and will be dropped from OpenOCD. In mean time it's still available by using @file{interface/stlink-hla.cfg}. +The HLA interface file can be put as first command line argument to +force using is in place of the default DAP API. +@example +openocd -f interface/stlink-hla.cfg -f board/st_nucleo_f4.cfg +@end example The new API provide access to multiple AP on the same DAP, but the maximum number of the AP port is limited by the specific firmware version diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index e018f71cd9..5ee1f85261 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -5143,7 +5143,12 @@ static int stlink_dap_init(void) if ((mode != STLINK_MODE_DEBUG_SWIM) && !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) { - LOG_ERROR("ST-Link version does not support DAP direct transport"); + LOG_ERROR("The firmware in the ST-Link adapter only supports deprecated HLA."); + LOG_ERROR("Please consider updating the ST-Link firmware with a version"); + LOG_ERROR("newer that V2J24 (2015), available for downloading on ST website:"); + LOG_ERROR(" https://www.st.com/en/development-tools/stsw-link007.html"); + LOG_ERROR("In mean time, you can re-run OpenOCD for ST-Link HLA as:"); + LOG_ERROR(" openocd -f interface/stlink-hla.cfg ..."); return ERROR_FAIL; } return ERROR_OK; diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg index 962d192ec5..48c5656615 100644 --- a/tcl/interface/stlink.cfg +++ b/tcl/interface/stlink.cfg @@ -10,6 +10,12 @@ # SWIM transport is natively supported # +if { [adapter name] == "hla" } { + # Deprecated HLA adapter driver already selected. + # Quit silently, as the ST-LINK driver already complains. + return +} + adapter driver st-link st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 0x0483 0x3754 0x0483 0x3755 0x0483 0x3757 From d8a2f6dbcf5f0554def22d02f503fb242a604f84 Mon Sep 17 00:00:00 2001 From: "R. Diez" Date: Fri, 11 Apr 2025 15:30:22 +0200 Subject: [PATCH 49/55] configure.ac: show the Amontec JTAG-Accelerator driver in the config summary Also enable this driver by default (auto). Change-Id: I7f592dd697c6ee150a81e151ff2333447cd9130d Signed-off-by: R. Diez Reviewed-on: https://review.openocd.org/c/openocd/+/8835 Tested-by: jenkins Reviewed-by: zapb Reviewed-by: Antonio Borneo --- configure.ac | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 84ca03bf07..5c516efd16 100644 --- a/configure.ac +++ b/configure.ac @@ -190,6 +190,9 @@ m4_define([JTAG_VPI_ADAPTER], m4_define([RSHIM_ADAPTER], [[[rshim], [BlueField SoC via rshim], [RSHIM]]]) +m4_define([AMTJTAGACCEL_ADAPTER], + [[[amtjtagaccel], [Amontec JTAG-Accelerator driver], [AMTJTAGACCEL]]]) + # The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter # because there is an M4 macro called 'adapter'. m4_define([DUMMY_ADAPTER], @@ -320,6 +323,7 @@ AC_ARG_ADAPTERS([ JTAG_DPI_ADAPTER, JTAG_VPI_ADAPTER, RSHIM_ADAPTER, + AMTJTAGACCEL_ADAPTER, PCIE_ADAPTERS, LIBJAYLINK_ADAPTERS ],[auto]) @@ -338,10 +342,6 @@ AC_ARG_ENABLE([parport_giveio], [Enable use of giveio for parport (for CygWin only)]), [parport_use_giveio=$enableval], [parport_use_giveio=]) -AC_ARG_ENABLE([amtjtagaccel], - AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]), - [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no]) - AS_CASE(["${host_cpu}"], [arm*|aarch64], [ AC_ARG_ENABLE([bcm2835gpio], @@ -576,12 +576,6 @@ AS_IF([test "x$parport_use_giveio" = "xyes"], [ AC_DEFINE([PARPORT_USE_GIVEIO], [0], [0 if you don't want parport to use giveio.]) ]) -AS_IF([test "x$build_amtjtagaccel" = "xyes"], [ - AC_DEFINE([BUILD_AMTJTAGACCEL], [1], [1 if you want the Amontec JTAG-Accelerator driver.]) -], [ - AC_DEFINE([BUILD_AMTJTAGACCEL], [0], [0 if you don't want the Amontec JTAG-Accelerator driver.]) -]) - AS_IF([test "x$build_gw16012" = "xyes"], [ AC_DEFINE([BUILD_GW16012], [1], [1 if you want the Gateworks GW16012 driver.]) ], [ @@ -719,6 +713,7 @@ PROCESS_ADAPTERS([JTAG_DPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([JTAG_VPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([RSHIM_ADAPTER], ["x$can_build_rshim" = "xyes"], [internal error: validation should happen beforehand]) +PROCESS_ADAPTERS([AMTJTAGACCEL_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused]) AS_IF([test "x$enable_linuxgpiod" != "xno"], [ @@ -771,7 +766,6 @@ AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "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"]) AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"]) AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"]) @@ -877,6 +871,7 @@ m4_foreach([adapter], [USB1_ADAPTERS, JTAG_DPI_ADAPTER, JTAG_VPI_ADAPTER, RSHIM_ADAPTER, + AMTJTAGACCEL_ADAPTER, DUMMY_ADAPTER, OPTIONAL_LIBRARIES, COVERAGE], From fdd76c899f423c09e4fb4311387eeebfc215650e Mon Sep 17 00:00:00 2001 From: "R. Diez" Date: Thu, 10 Apr 2025 20:57:49 +0200 Subject: [PATCH 50/55] configure.ac: show the sysfsgpio adapter in the config summary Also enable this adapter by default (auto). Change-Id: I43b9f1a1873b381d015114da57efc1d78e6e7780 Signed-off-by: R. Diez Reviewed-on: https://review.openocd.org/c/openocd/+/8834 Tested-by: jenkins Reviewed-by: Antonio Borneo --- configure.ac | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index 5c516efd16..9db378702e 100644 --- a/configure.ac +++ b/configure.ac @@ -164,6 +164,9 @@ m4_define([LIBFTDI_USB1_ADAPTERS], m4_define([LIBGPIOD_ADAPTERS], [[[linuxgpiod], [Linux GPIO bitbang through libgpiod], [LINUXGPIOD]]]) +m4_define([SYSFSGPIO_ADAPTER], + [[[sysfsgpio], [Linux GPIO bitbang through sysfs], [SYSFSGPIO]]]) + m4_define([REMOTE_BITBANG_ADAPTER], [[[remote_bitbang], [Remote Bitbang driver], [REMOTE_BITBANG]]]) @@ -315,6 +318,7 @@ AC_ARG_ADAPTERS([ LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, + SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, LINUXSPIDEV_ADAPTER, SERIAL_PORT_ADAPTERS, @@ -379,10 +383,6 @@ AC_ARG_ENABLE([gw16012], AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]), [build_gw16012=$enableval], [build_gw16012=no]) -AC_ARG_ENABLE([sysfsgpio], - AS_HELP_STRING([--enable-sysfsgpio], [Enable building support for programming driven via sysfs gpios.]), - [build_sysfsgpio=$enableval], [build_sysfsgpio=no]) - can_build_rshim=no AS_CASE([$host_os], @@ -391,10 +391,6 @@ AS_CASE([$host_os], can_build_rshim=yes ], [ - AS_IF([test "x$build_sysfsgpio" = "xyes"], [ - AC_MSG_ERROR([sysfsgpio is only available on linux]) - ]) - AS_CASE([$host_os], [freebsd*], [ can_build_rshim=yes ], @@ -604,13 +600,6 @@ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ ]) ]) -AS_IF([test "x$build_sysfsgpio" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_SYSFSGPIO], [1], [1 if you want the SysfsGPIO driver.]) -], [ - AC_DEFINE([BUILD_SYSFSGPIO], [0], [0 if you don't want SysfsGPIO driver.]) -]) - PKG_CHECK_MODULES([LIBUSB1], [libusb-1.0], [ use_libusb1=yes AC_DEFINE([HAVE_LIBUSB1], [1], [Define if you have libusb-1.x]) @@ -702,6 +691,7 @@ PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libu PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) PROCESS_ADAPTERS([LIBFTDI_USB1_ADAPTERS], ["x$use_libftdi" = "xyes" -a "x$use_libusb1" = "xyes"], [libftdi and libusb-1.x]) PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [Linux libgpiod]) +PROCESS_ADAPTERS([SYSFSGPIO_ADAPTER], ["x$is_linux" = "xyes"], [Linux sysfs]) PROCESS_ADAPTERS([REMOTE_BITBANG_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build]) @@ -720,6 +710,10 @@ AS_IF([test "x$enable_linuxgpiod" != "xno"], [ build_bitbang=yes ]) +AS_IF([test "x$enable_sysfsgpio" != "xno"], [ + build_bitbang=yes +]) + AS_IF([test "x$enable_remote_bitbang" != "xno"], [ build_bitbang=yes ]) @@ -767,7 +761,6 @@ AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) -AM_CONDITIONAL([SYSFSGPIO], [test "x$build_sysfsgpio" = "xyes"]) AM_CONDITIONAL([USE_LIBUSB1], [test "x$use_libusb1" = "xyes"]) AM_CONDITIONAL([IS_CYGWIN], [test "x$is_cygwin" = "xyes"]) AM_CONDITIONAL([IS_MINGW], [test "x$is_mingw" = "xyes"]) @@ -864,6 +857,7 @@ m4_foreach([adapter], [USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, + SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, LINUXSPIDEV_ADAPTER, From 639b7432b81b8851155ab0d539c74ac183bb9bfa Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 13 Dec 2024 07:34:38 +0000 Subject: [PATCH 51/55] tcl/board: Add config for NUCLEO-U083RC Tested with NUCLEO-U083RC development board. Change-Id: I5e7ed1a9a19dbab70ee3155f92d67874c33b1ac2 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/8649 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/st/nucleo-u083rc.cfg | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tcl/board/st/nucleo-u083rc.cfg diff --git a/tcl/board/st/nucleo-u083rc.cfg b/tcl/board/st/nucleo-u083rc.cfg new file mode 100644 index 0000000000..7b878adbc0 --- /dev/null +++ b/tcl/board/st/nucleo-u083rc.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# NUCLEO-U083RC +# https://www.st.com/en/evaluation-tools/nucleo-u083rc.html + +source [find interface/stlink.cfg] + +transport select dapdirect_swd + +source [find target/stm32u0x.cfg] + +reset_config srst_only From 98c95df228dd47ea736cea79a63f3302704cc669 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 14 Apr 2025 09:09:49 +0200 Subject: [PATCH 52/55] doc/openocd: Fix Tcl spelling Use 'Tcl' because it is the official spelling. While at it, fix some misspellings of 'Jim Tcl'. Change-Id: I084541a1cc0276d15a263b843ba740da04efc30a Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/8852 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 88 ++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index cbe5e86dab..e0bdd5ca09 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -62,7 +62,7 @@ Documentation License''. * About:: About OpenOCD * Developers:: OpenOCD Developer Resources * Debug Adapter Hardware:: Debug Adapter Hardware -* About Jim-Tcl:: About Jim-Tcl +* About Jim Tcl:: About Jim Tcl * Running:: Running OpenOCD * OpenOCD Project Setup:: OpenOCD Project Setup * Config File Guidelines:: Config File Guidelines @@ -629,43 +629,43 @@ This is deprecated from Linux v5.3; prefer using @b{linuxgpiod}. @end itemize -@node About Jim-Tcl -@chapter About Jim-Tcl -@cindex Jim-Tcl +@node About Jim Tcl +@chapter About Jim Tcl +@cindex Jim Tcl @cindex tcl -OpenOCD uses a small ``Tcl Interpreter'' known as Jim-Tcl. +OpenOCD uses a small ``Tcl Interpreter'' known as Jim Tcl. This programming language provides a simple and extensible command interpreter. -All commands presented in this Guide are extensions to Jim-Tcl. +All commands presented in this Guide are extensions to Jim Tcl. You can use them as simple commands, without needing to learn much of anything about Tcl. Alternatively, you can write Tcl programs with them. You can learn more about Jim at its website, @url{http://jim.tcl.tk}. There is an active and responsive community, get on the mailing list -if you have any questions. Jim-Tcl maintainers also lurk on the +if you have any questions. Jim Tcl maintainers also lurk on the OpenOCD mailing list. @itemize @bullet @item @b{Jim vs. Tcl} -@* Jim-Tcl is a stripped down version of the well known Tcl language, -which can be found here: @url{http://www.tcl.tk}. Jim-Tcl has far -fewer features. Jim-Tcl is several dozens of .C files and .H files and +@* Jim Tcl is a stripped down version of the well known Tcl language, +which can be found here: @url{http://www.tcl.tk}. Jim Tcl has far +fewer features. Jim Tcl is several dozens of .C files and .H files and implements the basic Tcl command set. In contrast: Tcl 8.6 is a 4.2 MB .zip file containing 1540 files. @item @b{Missing Features} @* Our practice has been: Add/clone the real Tcl feature if/when -needed. We welcome Jim-Tcl improvements, not bloat. Also there -are a large number of optional Jim-Tcl features that are not +needed. We welcome Jim Tcl improvements, not bloat. Also there +are a large number of optional Jim Tcl features that are not enabled in OpenOCD. @item @b{Scripts} -@* OpenOCD configuration scripts are Jim-Tcl Scripts. OpenOCD's +@* OpenOCD configuration scripts are Jim Tcl Scripts. OpenOCD's command interpreter today is a mixture of (newer) -Jim-Tcl commands, and the (older) original command interpreter. +Jim Tcl commands, and the (older) original command interpreter. @item @b{Commands} @* At the OpenOCD telnet command line (or via the GDB monitor command) one @@ -674,10 +674,10 @@ Some of the commands documented in this guide are implemented as Tcl scripts, from a @file{startup.tcl} file internal to the server. @item @b{Historical Note} -@* Jim-Tcl was introduced to OpenOCD in spring 2008. Fall 2010, -before OpenOCD 0.5 release, OpenOCD switched to using Jim-Tcl -as a Git submodule, which greatly simplified upgrading Jim-Tcl -to benefit from new features and bugfixes in Jim-Tcl. +@* Jim Tcl was introduced to OpenOCD in spring 2008. Fall 2010, +before OpenOCD 0.5 release, OpenOCD switched to using Jim Tcl +as a Git submodule, which greatly simplified upgrading Jim Tcl +to benefit from new features and bugfixes in Jim Tcl. @item @b{Need a crash course in Tcl?} @*@xref{Tcl Crash Course}. @@ -796,7 +796,7 @@ those channels. If you are having problems, you can enable internal debug messages via the @option{-d} option. -Also it is possible to interleave Jim-Tcl commands w/config scripts using the +Also it is possible to interleave Jim Tcl commands w/config scripts using the @option{-c} command line switch. To enable debug output (when reporting problems or working on OpenOCD @@ -962,7 +962,7 @@ that can be tested in a later script. @end quotation Here we will focus on the simpler solution: one user config -file, including basic configuration plus any TCL procedures +file, including basic configuration plus any Tcl procedures to simplify your work. @section User Config Files @@ -1432,7 +1432,7 @@ In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables. -The full Tcl/Tk language supports ``namespaces'', but Jim-Tcl does not. +The full Tcl/Tk language supports ``namespaces'', but Jim Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file. @@ -1552,7 +1552,7 @@ configuration files for other JTAG tools Some of this code could probably be shared between different boards. For example, setting up a DRAM controller often doesn't differ by much except the bus width (16 bits or 32?) and memory timings, so a -reusable TCL procedure loaded by the @file{target.cfg} file might take +reusable Tcl procedure loaded by the @file{target.cfg} file might take those as parameters. Similarly with oscillator, PLL, and clock setup; and disabling the watchdog. @@ -2137,7 +2137,7 @@ corresponding subsystems: @end deffn At last, @command{init} executes all the commands that are specified in -the TCL list @var{post_init_commands}. The commands are executed in the +the Tcl list @var{post_init_commands}. The commands are executed in the same order they occupy in the list. If one of the commands fails, then the error is propagated and OpenOCD fails too. @example @@ -2222,7 +2222,7 @@ cause initialization to fail with "Unknown remote qXfer reply: OK". @deffn {Config Command} {tcl port} [number] Specify or query the port used for a simplified RPC -connection that can be used by clients to issue TCL commands and get the +connection that can be used by clients to issue Tcl commands and get the output from the Tcl engine. Intended as a machine interface. When not specified during the configuration stage, @@ -2233,7 +2233,7 @@ When specified as "disabled", this service is not activated. @deffn {Config Command} {telnet port} [number] Specify or query the port on which to listen for incoming telnet connections. -This port is intended for interaction with one human through TCL commands. +This port is intended for interaction with one human through Tcl commands. When not specified during the configuration stage, the port @var{number} defaults to 4444. When specified as "disabled", this service is not activated. @@ -2304,7 +2304,7 @@ The file name is @i{target_name}.xml. Hardware debuggers are parts of asynchronous systems, where significant events can happen at any time. The OpenOCD server needs to detect some of these events, -so it can report them to through TCL command line +so it can report them to through Tcl command line or to GDB. Examples of such events include: @@ -2345,7 +2345,7 @@ specific information about the current state is printed. An optional parameter allows background polling to be enabled and disabled. -You could use this from the TCL command shell, or +You could use this from the Tcl command shell, or from GDB using @command{monitor poll} command. Leave background polling enabled while you're using GDB. @example @@ -4527,7 +4527,7 @@ mechanism for debugger targets.) See the next section for information about the available events. The @code{configure} subcommand assigns an event handler, -a TCL string which is evaluated when the event is triggered. +a Tcl string which is evaluated when the event is triggered. The @code{cget} subcommand returns that handler. @end deffn @@ -4786,7 +4786,7 @@ The instance number is in bits 28..31 of DLPIDR value. @deffn {Command} {dap names} This command returns a list of all registered DAP objects. It it useful mainly -for TCL scripting. +for Tcl scripting. @end deffn @deffn {Command} {dap info} [@var{num}|@option{root}] @@ -5775,7 +5775,7 @@ until the programming session is finished. If you use @ref{programmingusinggdb,,Programming using GDB}, the target is prepared automatically in the event gdb-flash-erase-start -The jimtcl script @command{program} calls @command{reset init} explicitly. +The Tcl script @command{program} calls @command{reset init} explicitly. @section Erasing, Reading, Writing to Flash @cindex flash erasing @@ -7462,18 +7462,18 @@ mspm0_board_reset @end itemize -@deffn {TCL proc} {mspm0_board_reset} +@deffn {Tcl proc} {mspm0_board_reset} Performs an nRST toggle on the device. @end deffn -@deffn {TCL proc} {mspm0_mass_erase} +@deffn {Tcl proc} {mspm0_mass_erase} Sends the mass erase command to the SEC-AP mailbox and then performs an nRST toggle. Once the command has been fully processed by the ROM, all MAIN memory will be erased. NOTE: This command is not supported on MSPM0C* family of devices. @end deffn -@deffn {TCL proc} {mspm0_factory_reset} +@deffn {Tcl proc} {mspm0_factory_reset} Sends the factory reset command to the SEC-AP mailbox and then performs an nRST toggle. Once the command has been fully processed by the ROM, all MAIN memory will be erased and NONMAIN will be reset to its default @@ -7772,7 +7772,7 @@ flash bank super_flash_toc2_cm4 psoc6 0x16007C00 0 0 0 \ psoc6-specific commands @deffn {Command} {psoc6 reset_halt} -Command can be used to simulate broken Vector Catch from gdbinit or tcl scripts. +Command can be used to simulate broken Vector Catch from gdbinit or Tcl scripts. When invoked for CM0+ target, it will set break point at application entry point and issue SYSRESETREQ. This will reset both cores and all peripherals. CM0+ will reset CM4 during boot anyway so this is safe. On CM4 target, VECTRESET is used @@ -8987,7 +8987,7 @@ OpenOCD implements numerous ways to program the target flash, whether internal o Programming can be achieved by either using @ref{programmingusinggdb,,Programming using GDB}, or using the commands given in @ref{flashprogrammingcommands,,Flash Programming Commands}. -@*To simplify using the flash commands directly a jimtcl script is available that handles the programming and verify stage. +@*To simplify using the flash commands directly a Tcl script is available that handles the programming and verify stage. OpenOCD will program/verify/reset the target and optionally shutdown. The script is executed as follows and by default the following actions will be performed. @@ -9269,7 +9269,7 @@ non-zero exit code to the parent process. If user types CTRL-C or kills OpenOCD, the command @command{shutdown} will be automatically executed to cause OpenOCD to exit. -It is possible to specify, in the TCL list @var{pre_shutdown_commands} , a +It is possible to specify, in the Tcl list @var{pre_shutdown_commands} , a set of commands to be automatically executed before @command{shutdown} , e.g.: @example lappend pre_shutdown_commands @{echo "Goodbye, my friend ..."@} @@ -9858,7 +9858,7 @@ Add or replace usage text on the given @var{command_name}. @deffn {Command} {ms} Returns current time since the Epoch in ms (See: @url{https://en.wikipedia.org/wiki/Epoch_(computing)}). -Useful to compute delays in TCL. +Useful to compute delays in Tcl. @end deffn @node Architecture and Core Commands @@ -10175,7 +10175,7 @@ of the CTI. @deffn {Command} {cti names} Prints a list of names of all CTI objects created. This command is mainly -useful in TCL scripting. +useful in Tcl scripting. @end deffn @section Generic ARM @@ -10819,7 +10819,7 @@ protocol used for trace data: @end itemize @item @code{-event} @var{event_name} @var{event_body} -- assigns an event handler, -a TCL string which is evaluated when the event is triggered. The events +a Tcl string which is evaluated when the event is triggered. The events @code{pre-enable}, @code{post-enable}, @code{pre-disable} and @code{post-disable} are defined for TPIU/SWO. A typical use case for the event @code{pre-enable} is to enable the trace clock @@ -11643,7 +11643,7 @@ capabilities than most of the other processors and in addition there is an extension interface that allows SoC designers to add custom registers and instructions. For the OpenOCD that mostly means that set of core and AUX registers in target will vary and is not fixed for a particular processor -model. To enable extensibility several TCL commands are provided that allow to +model. To enable extensibility several Tcl commands are provided that allow to describe those optional registers in OpenOCD configuration files. Moreover those commands allow for a dynamic target features discovery. @@ -11798,12 +11798,12 @@ configuration comprises two categories: @end enumerate All common Xtensa support is built into the OpenOCD Xtensa target layer and -is enabled through a combination of TCL scripts: the target-specific +is enabled through a combination of Tcl scripts: the target-specific @file{target/xtensa.cfg} and a board-specific @file{board/xtensa-*.cfg}, similar to other target architectures. Importantly, core-specific configuration information must be provided by -the user, and takes the form of an @file{xtensa-core-XXX.cfg} TCL script that +the user, and takes the form of an @file{xtensa-core-XXX.cfg} Tcl script that defines the core's configurable features through a series of Xtensa configuration commands (detailed below). @@ -13376,7 +13376,7 @@ learning Tcl, the intent of this chapter is to give you some idea of how the Tcl scripts work. This chapter is written with two audiences in mind. (1) OpenOCD users -who need to understand a bit more of how Jim-Tcl works so they can do +who need to understand a bit more of how Jim Tcl works so they can do something useful, and (2) those that want to add a new command to OpenOCD. @@ -13536,7 +13536,7 @@ Often many of those parameters are in @{curly-braces@} - thus the variables inside are not expanded or replaced until later. Remember that every Tcl command looks like the classic ``main( argc, -argv )'' function in C. In JimTCL - they actually look like this: +argv )'' function in C. In Jim Tcl - they actually look like this: @example int From efafdd3c552e004525b4515c70ac03765e9b6fd6 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 14 Apr 2025 09:11:36 +0200 Subject: [PATCH 53/55] doc/manual: Fix Tcl spelling Use 'Tcl' because it is the official spelling. While at it, fix some misspellings of 'Jim Tcl'. Change-Id: I2d96f63b0dbc96ae62fe00ae41d2eb16897250fb Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/8853 Tested-by: jenkins Reviewed-by: Antonio Borneo --- README | 4 ++-- TODO | 18 +++++++++--------- doc/manual/helper.txt | 2 +- doc/manual/jtag.txt | 4 ++-- doc/manual/primer/docs.txt | 2 +- doc/manual/primer/tcl.txt | 28 ++++++++++++++-------------- doc/manual/scripting.txt | 14 +++++++------- doc/manual/server.txt | 34 +++++++++++++++++----------------- doc/manual/style.txt | 6 +++--- 9 files changed, 56 insertions(+), 56 deletions(-) diff --git a/README b/README index d9cc8f3eb0..875c85de3b 100644 --- a/README +++ b/README @@ -8,10 +8,10 @@ layered architecture of JTAG interface and TAP support including: - debug target support (e.g. ARM, MIPS): single-stepping, breakpoints/watchpoints, gprof profiling, etc; - flash chip drivers (e.g. CFI, NAND, internal flash); -- embedded TCL interpreter for easy scripting. +- embedded Tcl interpreter for easy scripting. Several network interfaces are available for interacting with OpenOCD: -telnet, TCL, and GDB. The GDB server enables OpenOCD to function as a +telnet, Tcl, and GDB. The GDB server enables OpenOCD to function as a "remote target" for source-level debugging of embedded systems using the GNU GDB program (and the others who talk GDB protocol, e.g. IDA Pro). diff --git a/TODO b/TODO index 239b358f57..803692d58e 100644 --- a/TODO +++ b/TODO @@ -12,14 +12,14 @@ may have evolved an idea since it was added here. Feel free to send patches to add or clarify items on this list, too. -@section thelisttcl TCL +@section thelisttcl Tcl -This section provides possible things to improve with OpenOCD's TCL support. +This section provides possible things to improve with OpenOCD's Tcl support. - Fix problem with incorrect line numbers reported for a syntax error in a reset init event. -- organize the TCL configurations: +- organize the Tcl configurations: - provide more directory structure for boards/targets? - factor configurations into layers (encapsulation and re-use) @@ -27,15 +27,15 @@ This section provides possible things to improve with OpenOCD's TCL support. parameters. Currently variables assigned through one such parameter command/script are unset before the next one is invoked. -- Isolate all TCL command support: +- Isolate all Tcl command support: - Pure C CLI implementations using --disable-builtin-tcl. - Allow developers to build new dongles using OpenOCD's JTAG core. - At first, provide only low-level JTAG support; target layer and above rely heavily on scripting event mechanisms. - - Allow full TCL support? add --with-tcl=/path/to/installed/tcl - - Move TCL support out of foo.[ch] and into foo_tcl.[ch] (other ideas?) + - Allow full Tcl support? add --with-tcl=/path/to/installed/tcl + - Move Tcl support out of foo.[ch] and into foo_tcl.[ch] (other ideas?) - See src/jtag/core.c and src/jtag/tcl.c for an example. - - allow some of these TCL command modules to be dynamically loadable? + - allow some of these Tcl command modules to be dynamically loadable? @section thelistadapter Adapter @@ -75,7 +75,7 @@ directly in minidriver API for better embedded host performance. The following tasks have been suggested for adding new core JTAG support: -- Improve autodetection of TAPs by supporting tcl escape procedures that +- Improve autodetection of TAPs by supporting Tcl escape procedures that can configure discovered TAPs based on IDCODE value ... they could: - Remove guessing for irlen - Allow non-default irmask/ircapture values @@ -133,7 +133,7 @@ TCP/IP packets handled by the server. - add BSDL support? A few possible options for the above: - -# Fake a TCL equivalent? + -# Fake a Tcl equivalent? -# Integrate an existing library? -# Write a new C implementation a la Jim? diff --git a/doc/manual/helper.txt b/doc/manual/helper.txt index b59fd664fb..6cf3c977bf 100644 --- a/doc/manual/helper.txt +++ b/doc/manual/helper.txt @@ -21,7 +21,7 @@ portability API. /** @page helperjim OpenOCD Jim API -The Jim API provides access to a small-footprint TCL implementation. +The Jim API provides access to a small-footprint Tcl implementation. Visit http://jim.tcl.tk/ for more information on Jim. diff --git a/doc/manual/jtag.txt b/doc/manual/jtag.txt index 2653fc78f5..5eb945013b 100644 --- a/doc/manual/jtag.txt +++ b/doc/manual/jtag.txt @@ -15,7 +15,7 @@ asynchronous transactions. - used by other modules - @subpage jtagtcl - - @b private TCL handling routines + - @b private Tcl handling routines - defined in @c src/jtag/tcl.c - registers and handles Jim commands that configure and use the JTAG core @@ -47,7 +47,7 @@ This section needs to be expanded. */ -/** @page jtagtcl JTAG TCL API +/** @page jtagtcl JTAG Tcl API This section needs to be expanded. diff --git a/doc/manual/primer/docs.txt b/doc/manual/primer/docs.txt index b1c0531375..1aefa17e6d 100644 --- a/doc/manual/primer/docs.txt +++ b/doc/manual/primer/docs.txt @@ -6,7 +6,7 @@ OpenOCD presently produces several kinds of documentation: - The User's Guide: - Focuses on using the OpenOCD software. - Details the installation, usage, and customization. - - Provides descriptions of public Jim/TCL script commands. + - Provides descriptions of public Jim Tcl script commands. - Written using GNU texinfo. - Created with 'make pdf' or 'make html'. - See @subpage primertexinfo and @ref styletexinfo. diff --git a/doc/manual/primer/tcl.txt b/doc/manual/primer/tcl.txt index eba2f552d0..6874f5566c 100644 --- a/doc/manual/primer/tcl.txt +++ b/doc/manual/primer/tcl.txt @@ -1,6 +1,6 @@ -/** @page primertcl OpenOCD TCL Primer +/** @page primertcl OpenOCD Tcl Primer -The @subpage scripting page provides additional TCL Primer material. +The @subpage scripting page provides additional Tcl Primer material. @verbatim @@ -8,15 +8,15 @@ The @subpage scripting page provides additional TCL Primer material. **************************************** This is a short introduction to 'un-scare' you about the language -known as TCL. It is structured as a guided tour through the files +known as Tcl. It is structured as a guided tour through the files written by me [Duane Ellis] - in early July 2008 for OpenOCD. Which uses the "JIM" embedded Tcl clone-ish language. -Thing described here are *totally* TCL generic... not Jim specific. +Thing described here are *totally* Tcl generic... not Jim specific. The goal of this document is to encourage you to add your own set of -chips to the TCL package - and most importantly you should know where +chips to the Tcl package - and most importantly you should know where you should put them - so they end up in an organized way. --Duane Ellis. @@ -57,14 +57,14 @@ Definition: Open: at91sam7x256.tcl === TCL TOUR === -A walk through --- For those who are new to TCL. +A walk through --- For those who are new to Tcl. Examine the file: at91sam7x256.tcl It starts with: source [find path/filename.tcl] -In TCL - this is very important. +In Tcl - this is very important. Rule #1 Everything is a string. Rule #2 If you think other wise See #1. @@ -130,7 +130,7 @@ First, there is a "for" loop - at level 0 This means it is evaluated when the file is parsed. == SIDEBAR: About The FOR command == -In TCL, "FOR" is a funny thing, it is not what you think it is. +In Tcl, "FOR" is a funny thing, it is not what you think it is. Syntactically - FOR is a just a command, it is not language construct like for(;;) in C... @@ -191,7 +191,7 @@ proc create_mask { MSB LSB } { Like "for" - PROC is really just a command that takes 3 parameters. The (1) NAME of the function, a (2) LIST of parameters, and a (3) BODY -Again, this is at "level 0" so it is a global function. (Yes, TCL +Again, this is at "level 0" so it is a global function. (Yes, Tcl supports local functions, you put them inside of a function} You'll see in some cases, I nest [brackets] a lot and in others I'm @@ -257,7 +257,7 @@ For example - 'show_mmr32_reg' is given the NAME of the register to display. The assumption is - the NAME is a global variable holding the address of that MMR. -The code does some tricks. The [set [set NAME]] is the TCL way +The code does some tricks. The [set [set NAME]] is the Tcl way of doing double variable interpolation - like makefiles... In a makefile or shell script you may have seen this: @@ -272,7 +272,7 @@ In a makefile or shell script you may have seen this: #BUILD = mac FOO = ${FOO_${BUILD}} -The "double [set] square bracket" thing is the TCL way, nothing more. +The "double [set] square bracket" thing is the Tcl way, nothing more. ---- @@ -352,7 +352,7 @@ tricks with interpretors. Function: show_mmr32_bits() -In this case, we use the special TCL command "upvar" which tcl's way +In this case, we use the special Tcl command "upvar" which is the Tcl way of passing things by reference. In this case, we want to reach up into the callers lexical scope and find the array named "NAMES" @@ -373,7 +373,7 @@ are basically identical... Second - there can be many of them. -In this case - I do some more TCL tricks to dynamically +In this case - I do some more Tcl tricks to dynamically create functions out of thin air. Some assumptions: @@ -409,7 +409,7 @@ And - declare that variable as GLOBAL so the world can find it. Then - we dynamically create a function - based on the register name. Look carefully at how that is done. You'll notice the FUNCTION BODY is -a string - not something in {braces}. Why? This is because we need TCL +a string - not something in {braces}. Why? This is because we need Tcl to evaluate the contents of that string "*NOW*" - when $vn exists not later, when the function "show_FOO" is invoked. diff --git a/doc/manual/scripting.txt b/doc/manual/scripting.txt index f8764e2d7c..48ba99bdaa 100644 --- a/doc/manual/scripting.txt +++ b/doc/manual/scripting.txt @@ -4,11 +4,11 @@ The scripting support is intended for developers of OpenOCD. It is not the intention that normal OpenOCD users will -use tcl scripting extensively, write lots of clever scripts, +use Tcl scripting extensively, write lots of clever scripts, or contribute back to OpenOCD. Target scripts can contain new procedures that end users may -tinker to their needs without really understanding tcl. +tinker to their needs without really understanding Tcl. Since end users are not expected to mess with the scripting language, the choice of language is not terribly important @@ -38,16 +38,16 @@ Default implementation of procedures in tcl/procedures.tcl. and will have no externally visible consequences. Tcl has an advantage in that it's syntax is backwards compatible with the current OpenOCD syntax. -- external scripting. Low level tcl functions will be defined - that return machine readable output. These low level tcl - functions constitute the tcl api. flash_banks is such - a low level tcl proc. "flash banks" is an example of +- external scripting. Low level Tcl functions will be defined + that return machine readable output. These low level Tcl + functions constitute the Tcl api. flash_banks is such + a low level Tcl proc. "flash banks" is an example of a command that has human readable output. The human readable output is expected to change in between versions of OpenOCD. The output from flash_banks may not be in the preferred form for the client. The client then has two choices a) parse the output from flash_banks - or b) write a small piece of tcl to output the + or b) write a small piece of Tcl to output the flash_banks output to a more suitable form. The latter may be simpler. diff --git a/doc/manual/server.txt b/doc/manual/server.txt index 8041c3df3d..20e48c1f43 100644 --- a/doc/manual/server.txt +++ b/doc/manual/server.txt @@ -43,7 +43,7 @@ with a script language: What follows hopefully shows how the plans to solve these problems materialized and help to explain the grand roadmap plan. -@subsection serverdocsjim Why JimTCL? The Internal Script Language +@subsection serverdocsjim Why Jim Tcl? The Internal Script Language At the time, the existing "command context schema" was proving itself insufficient. However, the problem was also considered from another @@ -57,14 +57,14 @@ OpenOCD. Yuck. OpenOCD already has a complex enough build system, why make it worse? The goal was to add a simple language that would be moderately easy to -work with and be self-contained. JimTCL is a single C and single H +work with and be self-contained. Jim Tcl is a single C and single H file, allowing OpenOCD to avoid the spider web of dependent packages. -@section serverdocstcl TCL Server Port +@section serverdocstcl Tcl Server Port -The TCL Server port was added in mid-2008. With embedded TCL, we can +The Tcl Server port was added in mid-2008. With embedded Tcl, we can write scripts internally to help things, or we can write "C" code that -interfaces well with TCL. +interfaces well with Tcl. From there, the developers wanted to create an external front-end that would be @a very usable and that @a any language could utilize, @@ -78,7 +78,7 @@ also support a high degree of interoperability with multiple systems. They are not human-centric protocols; more correctly, they are rigid, terse, simple ASCII protocols that are easily parsable by a script. -Thus, the TCL server -- a 'machine' type socket interface -- was added +Thus, the Tcl server -- a 'machine' type socket interface -- was added with the hope was it would output simple "name-value" pair type data. At the time, simple name/value pairs seemed reasonably easier to do at the time, though Maybe it should output JSON; @@ -107,7 +107,7 @@ What works easier and is less work is what is already present in every platform? The answer: A web browser. In other words, OpenOCD could serve out embedded web pages via "localhost" to your browser. -Long before OpenOCD had a TCL command line, Zylin AS built their ZY1000 +Long before OpenOCD had a Tcl command line, Zylin AS built their ZY1000 device with a built-in HTTP server. Later, they were willing to both contribute and integrate most of that work into the main tree. @@ -128,8 +128,8 @@ every language has it's own set of wack-ness, parameter marshaling is painful. What about "callbacks" and structures, and other mess. Imagine -debugging that system. When JimTCL was introduced Spencer Oliver had -quite a few well-put concerns (Summer 2008) about the idea of "TCL" +debugging that system. When Jim Tcl was introduced Spencer Oliver had +quite a few well-put concerns (Summer 2008) about the idea of "Tcl" taking over OpenOCD. His concern is and was: how do you debug something written in 2 different languages? A "SWIG" front-end is unlikely to help that situation. @@ -143,7 +143,7 @@ to Localhost or remote host, however one might want to make it work. A socket interface is very simple. One could write a Java application and serve it out via the embedded web server, could it - or something -like it talk to the built in TCL server? Yes, absolutely! We are on to +like it talk to the built in Tcl server? Yes, absolutely! We are on to something here. @subsection serverdocplatforms Platform Permutations @@ -167,9 +167,9 @@ the Socket Approach is used. @subsection serverdocfuture Development Scale Out -During 2008, Duane Ellis created some TCL scripts to display peripheral -register contents. For example, look at the sam7 TCL scripts, and the -stm32 TCL scripts. The hope was others would create more. +During 2008, Duane Ellis created some Tcl scripts to display peripheral +register contents. For example, look at the sam7 Tcl scripts, and the +stm32 Tcl scripts. The hope was others would create more. A good example of this is display/view the peripheral registers on @@ -208,7 +208,7 @@ upon it, sometimes that is the only scheme available. As a small group of developers, supporting all the platforms and targets in the debugger will be difficult, as there are enough problem with the plethora of Adapters, Chips, and different target boards. -Yes, the TCL interface might be suitable, but it has not received much +Yes, the Tcl interface might be suitable, but it has not received much love or attention. Perhaps it will after you read and understand this. One reason might be, this adds one more host side requirement to make @@ -247,8 +247,8 @@ Altogether, it provides a universally accessible GUI for OpenOCD. @section serverdocshtml Simple HTML Pages -There is (or could be) a simple "Jim TCL" function to read a memory -location. If that can be tied into a TCL script that can modify the +There is (or could be) a simple "Jim Tcl" function to read a memory +location. If that can be tied into a Tcl script that can modify the HTTP text, then we have a simple script-based web server with a JTAG engine under the hood. @@ -275,7 +275,7 @@ bit-banging JTAG Adapter serving web pages. @subsection serverdocshtmladv Advanced HTML Pages -Java or JavaScript could be used to talk back to the TCL port. One +Java or JavaScript could be used to talk back to the Tcl port. One could write a Java, AJAX, FLASH, or some other developer friendly toolbox and get a real cross-platform GUI interface. Sure, the interface is not native - but it is 100% cross-platform! diff --git a/doc/manual/style.txt b/doc/manual/style.txt index dc27e8767a..f7a12988fc 100644 --- a/doc/manual/style.txt +++ b/doc/manual/style.txt @@ -27,12 +27,12 @@ providing documentation, either as part of the C code or stand-alone. Feedback would be welcome to improve the OpenOCD guidelines. */ -/** @page styletcl TCL Style Guide +/** @page styletcl Tcl Style Guide -OpenOCD needs to expand its Jim/TCL Style Guide. +OpenOCD needs to expand its Jim Tcl Style Guide. Many of the guidelines listed on the @ref stylec page should apply to -OpenOCD's Jim/TCL code as well. +OpenOCD's Jim Tcl code as well. */ /** @page stylec C Style Guide From d567824f2ac267f61944aa839911f0b5bee98c4a Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 17 Aug 2024 12:35:30 +0200 Subject: [PATCH 54/55] doc/manual: Add guideline for configuration files The goal of this guideline is to have consistent and well-structured configurations files. The focus of this patch is on filenames and directory structure. A guideline for the content of the files should be included in a subsequent patch. This patch addresses a long outstanding task listed in 'Pending and Open Tasks'. Change-Id: Ib32dd8b9ed15c3f647cd8d74cfc79edf0e79a3df Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/8854 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/manual/config_files.txt | 117 ++++++++++++++++++++++++++++++++++++ doc/manual/main.txt | 2 + 2 files changed, 119 insertions(+) create mode 100644 doc/manual/config_files.txt diff --git a/doc/manual/config_files.txt b/doc/manual/config_files.txt new file mode 100644 index 0000000000..db1cc14191 --- /dev/null +++ b/doc/manual/config_files.txt @@ -0,0 +1,117 @@ +/** @page config_files Configuration Files + +This page gives an overview of the different configuration files, what purpose they serve and how they are structured. +The goal of this guide is to ensure well-structured and consistent configuration files. + +All configuration files are stored in the @c tcl directory of the project directory. +These files must follow the @ref styletcl and @ref naming_convention. +There are different types of configuration files: + +- @ref interface_configs +- @ref target_configs +- @ref board_configs + +@note This guideline must be followed for new configuration files. +There may be configuration files that do not comply with this guide for legacy reasons. + + +@section interface_configs Interface + +This configuration file represents a debug (interface) adapter. +This is usually a USB device that provides an interface to one or more transports such as JTAG or SWD. +Other interfaces like ethernet or parallel port are also represented. + +A debug adapter configuration file must use the following scheme: + +@verbatim +tcl/interface/[vendor]/.cfg +@endverbatim + +The `vendor` directory for debug adapters is often omitted because multiple adapters from the same vendor can be represented by a common configuration file. +One counter example are FTDI-based debug adapters. +There are various devices, either standalone or development boards which use FTDI chips but use different chip models or settings. +Their corresponding configuration files are stored in the `ftdi` folder. + +The name of the `vendor` folder can also be a more generic term such as `parport` as it is used for parallel port based debug adapters. + +If it is foreseeable that new configuration files will be added in the future, create a `vendor` directory even if there is only a single file at the moment. +This prevents that files have to be moved in the future. + +@section target_configs Target + +This configuration file represents an actual chip. +For example, a microcontroller, FPGA, CPLD, or system on chip (SoC). +A target configuration file always represents an entire device series or family. + +A target configuration file must use the following scheme: + +@verbatim +tcl/target//.cfg +@endverbatim + +Use the device series or family as `target name`. +For example, the configuration file for the nRF54L series from Nordic Semiconductor is located here: + +@verbatim +tcl/target/nordic/nrf54l.cfg +@endverbatim + +If there are many similarities between different targets, use a common file to share large pieces of code. +Do not use a single file to represent multiple device series or families. + +@section board_configs Board + +This configuration file represents a circuit board, for example, a development board. +A board may also contain an on-board debug adapter. + +A board configuration file includes existing target and, if available, interface configuration files, since a target is used on many boards. + +Reuse existing target and interface configuration files whenever possible. +If a board needs an external debug adapter, do @b not write adapter specific configuration files. + + +A board configuration file must use the following scheme: + +@verbatim +tcl/board//[-suffix].cfg +@endverbatim + +For example, the board configuration file for the NUCLEO-U083RC from STMicroelectronics is located here: + +@verbatim +tcl/board/st/nucleo-u083rc.cfg +@endverbatim + +In case a board supports different features, a `suffix` can be used to indicate this. +Make sure that the suffix is short and meaningful. + +For example, the on-board debug adapter of the FRDM-KV11Z development board can be flashed with a SEGGER J-Link compatible firmware. +Hence, there is the following configuration file: + +@verbatim +tcl/board/nxp/frdm-kv11z-jlink.cfg +@endverbatim + +The use of a suffix should be chosen carefully. +In many cases it is sufficient to make a certain feature accessible via a variable. + +Use a single configuration file for each board. +If there are many similarities between different boards, use a common file to share large pieces of code. + + +@section naming_convention Naming Convention + + +The following naming conventions for configuration files and directories must be used: + +- Use only lower-case letters and digits for directory and filenames +- Use hyphen characters between consecutive words in identifiers (e.g. `more-than-one-word`) + +- Use a common abbreviation for the vendor name, such as + - @c ti for Texas Instruments + - @c st for STMicroelectronics + - @c silabs for Silicon Labs + +An extensive list of abbreviations for vendor names can be found [here](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/vendor-prefixes.yaml). + + */ diff --git a/doc/manual/main.txt b/doc/manual/main.txt index c28fbe2288..9da546b6d2 100644 --- a/doc/manual/main.txt +++ b/doc/manual/main.txt @@ -21,6 +21,8 @@ check the mailing list archives to find the status of your feature (or bug). - The @subpage releases page describes the project's release process. - The @subpage endianness provides hints about writing and testing endianness independent code for OpenOCD. +- The @subpage config_files page provides a guide for writing configuration files + for OpenOCD. @ref primer provide introductory materials for new developers on various specific topics. From afbd01b0a46f3a81fe6076c002ad66973dcfb64c Mon Sep 17 00:00:00 2001 From: Samuel Obuch Date: Thu, 13 Feb 2025 14:28:27 +0100 Subject: [PATCH 55/55] github/workflow: fix warnings for github actions - update runner to ubuntu-latest - pass GITHUB_TOKEN to delete-tag-and-release as input Change-Id: I83d69cfd7af7c44e67b1115ac843a0b41d6f87b9 Signed-off-by: Samuel Obuch Reviewed-on: https://review.openocd.org/c/openocd/+/8756 Reviewed-by: Antonio Borneo Tested-by: jenkins --- .github/workflows/snapshot.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 36b2f3bb3d..755e8f4e14 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -8,7 +8,7 @@ name: OpenOCD Snapshot jobs: package: - runs-on: [ubuntu-20.04] + runs-on: [ubuntu-latest] env: DL_DIR: ../downloads BUILD_DIR: ../build @@ -102,8 +102,8 @@ jobs: # add missing dlls cd $HOST-root/usr cp `$HOST-gcc --print-file-name=libwinpthread-1.dll` ./bin/ - # required by libftdi1.dll. For the gcc-mingw-10.3.x or later "libgcc_s_dw2-1.dll" will need to be copied. - cp `$HOST-gcc --print-file-name=libgcc_s_sjlj-1.dll` ./bin/ + # required by libftdi1.dll + cp `$HOST-gcc --print-file-name=libgcc_s_dw2-1.dll` ./bin/ # prepare the artifact ARTIFACT="openocd-${OPENOCD_TAG}-${HOST}.tar.gz" tar -czf $ARTIFACT * @@ -119,8 +119,7 @@ jobs: with: delete_release: true tag_name: ${{ env.RELEASE_NAME }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + github_token: ${{ secrets.GITHUB_TOKEN }} - name: Create Release uses: ncipollo/release-action@v1 with: