OpenOCD
transport.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  * Copyright (c) 2010 by David Brownell
5  */
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
33 #include <helper/log.h>
34 #include <helper/replacements.h>
35 #include <transport/transport.h>
36 
37 extern struct command_context *global_cmd_ctx;
38 
39 /*-----------------------------------------------------------------------*/
40 
41 /*
42  * Infrastructure internals
43  */
44 
46 static struct transport *transport_list;
47 
53 static const char * const *allowed_transports;
54 
56 static struct transport *session;
57 
58 static int transport_select(struct command_context *ctx, const char *name)
59 {
60  /* name may only identify a known transport;
61  * caller guarantees session's transport isn't yet set.*/
62  for (struct transport *t = transport_list; t; t = t->next) {
63  if (strcmp(t->name, name) == 0) {
64  int retval = t->select(ctx);
65  /* select() registers commands specific to this
66  * transport, and may also reset the link, e.g.
67  * forcing it to JTAG or SWD mode.
68  */
69  if (retval == ERROR_OK)
70  session = t;
71  else
72  LOG_ERROR("Error selecting '%s' as transport", t->name);
73  return retval;
74  }
75  }
76 
77  LOG_ERROR("No transport named '%s' is available.", name);
78  return ERROR_FAIL;
79 }
80 
86 int allow_transports(struct command_context *ctx, const char * const *vector)
87 {
88  /* NOTE: caller is required to provide only a list
89  * of *valid* transport names
90  *
91  * REVISIT should we validate that? and insist there's
92  * at least one non-NULL element in that list?
93  *
94  * ... allow removals, e.g. external strapping prevents use
95  * of one transport; C code should be definitive about what
96  * can be used when all goes well.
97  */
98  if (allowed_transports || session) {
99  LOG_ERROR("Can't modify the set of allowed transports.");
100  return ERROR_FAIL;
101  }
102 
103  allowed_transports = vector;
104 
105  /* autoselect if there's no choice ... */
106  if (!vector[1]) {
107  LOG_INFO("only one transport option; autoselect '%s'", vector[0]);
108  return transport_select(ctx, vector[0]);
109  }
110 
111  return ERROR_OK;
112 }
113 
129 int transport_register(struct transport *new_transport)
130 {
131  struct transport *t;
132 
133  for (t = transport_list; t; t = t->next) {
134  if (strcmp(t->name, new_transport->name) == 0) {
135  LOG_ERROR("transport name already used");
136  return ERROR_FAIL;
137  }
138  }
139 
140  if (!new_transport->select || !new_transport->init)
141  LOG_ERROR("invalid transport %s", new_transport->name);
142 
143  /* splice this into the list */
144  new_transport->next = transport_list;
145  transport_list = new_transport;
146  LOG_DEBUG("register '%s'", new_transport->name);
147 
148  return ERROR_OK;
149 }
150 
158 {
159  /* REVISIT -- constify */
160  return session;
161 }
162 
163 /*-----------------------------------------------------------------------*/
164 
165 /*
166  * Infrastructure for Tcl interface to transports.
167  */
168 
176 COMMAND_HELPER(transport_list_parse, char ***vector)
177 {
178  char **argv;
179  unsigned n = CMD_ARGC;
180  unsigned j = 0;
181 
182  *vector = NULL;
183 
184  if (n < 1)
186 
187  /* our return vector must be NULL terminated */
188  argv = calloc(n + 1, sizeof(char *));
189  if (!argv)
190  return ERROR_FAIL;
191 
192  for (unsigned i = 0; i < n; i++) {
193  struct transport *t;
194 
195  for (t = transport_list; t; t = t->next) {
196  if (strcmp(t->name, CMD_ARGV[i]) != 0)
197  continue;
198  argv[j++] = strdup(CMD_ARGV[i]);
199  break;
200  }
201  if (!t) {
202  LOG_ERROR("no such transport '%s'", CMD_ARGV[i]);
203  goto fail;
204  }
205  }
206 
207  *vector = argv;
208  return ERROR_OK;
209 
210 fail:
211  for (unsigned i = 0; i < n; i++)
212  free(argv[i]);
213  free(argv);
214  return ERROR_FAIL;
215 }
216 
217 COMMAND_HANDLER(handle_transport_init)
218 {
219  LOG_DEBUG("%s", __func__);
220  if (!session) {
221  LOG_ERROR("session transport was not selected. Use 'transport select <transport>'");
222 
223  /* no session transport configured, print transports then fail */
224  LOG_ERROR("Transports available:");
225  const char * const *vector = allowed_transports;
226  while (*vector) {
227  LOG_ERROR("%s", *vector);
228  vector++;
229  }
230  return ERROR_FAIL;
231  }
232 
233  return session->init(CMD_CTX);
234 }
235 
236 COMMAND_HANDLER(handle_transport_list)
237 {
238  if (CMD_ARGC != 0)
240 
241  command_print(CMD, "The following transports are available:");
242 
243  for (struct transport *t = transport_list; t; t = t->next)
244  command_print(CMD, "\t%s", t->name);
245 
246  return ERROR_OK;
247 }
248 
255 static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
256 {
257  int res;
258  switch (argc) {
259  case 1: /* autoselect if necessary, then return/display current config */
260  if (!session) {
261  if (!allowed_transports) {
262  LOG_ERROR("Debug adapter does not support any transports? Check config file order.");
263  return JIM_ERR;
264  }
265  LOG_INFO("auto-selecting first available session transport \"%s\". "
266  "To override use 'transport select <transport>'.", allowed_transports[0]);
268  if (res != JIM_OK)
269  return res;
270  }
271  Jim_SetResultString(interp, session->name, -1);
272  return JIM_OK;
273  case 2: /* assign */
274  if (session) {
275  if (!strcmp(session->name, argv[1]->bytes)) {
276  LOG_WARNING("Transport \"%s\" was already selected", session->name);
277  Jim_SetResultString(interp, session->name, -1);
278  return JIM_OK;
279  } else {
280  LOG_ERROR("Can't change session's transport after the initial selection was made");
281  return JIM_ERR;
282  }
283  }
284 
285  /* Is this transport supported by our debug adapter?
286  * Example, "JTAG-only" means SWD is not supported.
287  *
288  * NOTE: requires adapter to have been set up, with
289  * transports declared via C.
290  */
291  if (!allowed_transports) {
292  LOG_ERROR("Debug adapter doesn't support any transports?");
293  return JIM_ERR;
294  }
295 
296  for (unsigned i = 0; allowed_transports[i]; i++) {
297 
298  if (strcmp(allowed_transports[i], argv[1]->bytes) == 0) {
299  if (transport_select(global_cmd_ctx, argv[1]->bytes) == ERROR_OK) {
300  Jim_SetResultString(interp, session->name, -1);
301  return JIM_OK;
302  }
303  return JIM_ERR;
304  }
305  }
306 
307  LOG_ERROR("Debug adapter doesn't support '%s' transport", argv[1]->bytes);
308  return JIM_ERR;
309  default:
310  Jim_WrongNumArgs(interp, 1, argv, "[too many parameters]");
311  return JIM_ERR;
312  }
313 }
314 
315 static const struct command_registration transport_commands[] = {
316  {
317  .name = "init",
318  .handler = handle_transport_init,
319  /* this would be COMMAND_CONFIG ... except that
320  * it needs to trigger event handlers that may
321  * require COMMAND_EXEC ...
322  */
323  .mode = COMMAND_ANY,
324  .help = "Initialize this session's transport",
325  .usage = ""
326  },
327  {
328  .name = "list",
329  .handler = handle_transport_list,
330  .mode = COMMAND_ANY,
331  .help = "list all built-in transports",
332  .usage = ""
333  },
334  {
335  .name = "select",
336  .jim_handler = jim_transport_select,
337  .mode = COMMAND_ANY,
338  .help = "Select this session's transport",
339  .usage = "[transport_name]",
340  },
342 };
343 
344 static const struct command_registration transport_group[] = {
345  {
346  .name = "transport",
347  .mode = COMMAND_ANY,
348  .help = "Transport command group",
349  .chain = transport_commands,
350  .usage = ""
351  },
353 };
354 
356 {
357  return register_commands(ctx, NULL, transport_group);
358 }
const char * name
Definition: armv4_5.c:76
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:473
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:140
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:155
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:385
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:150
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:145
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:247
static int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds)
Register one or more commands in the specified context, as children of parent (or top-level commends,...
Definition: command.h:268
@ COMMAND_ANY
Definition: command.h:42
#define LOG_WARNING(expr ...)
Definition: log.h:120
#define ERROR_FAIL
Definition: log.h:161
#define LOG_ERROR(expr ...)
Definition: log.h:123
#define LOG_INFO(expr ...)
Definition: log.h:117
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:155
const char * name
Definition: command.h:229
const char * usage
a string listing the options and arguments, required or optional
Definition: command.h:235
Wrapper for transport lifecycle operations.
Definition: transport.h:35
int(* select)(struct command_context *ctx)
When a transport is selected, this method registers its commands and activates the transport (e....
Definition: transport.h:51
int(* init)(struct command_context *ctx)
server startup uses this method to validate transport configuration.
Definition: transport.h:58
struct transport * next
Transports are stored in a singly linked list.
Definition: transport.h:71
const char * name
Each transport has a unique name, used to select it from among the alternatives.
Definition: transport.h:41
static const struct command_registration transport_group[]
Definition: transport.c:344
struct command_context * global_cmd_ctx
Definition: openocd.c:292
int allow_transports(struct command_context *ctx, const char *const *vector)
Called by debug adapter drivers, or affiliated Tcl config scripts, to declare the set of transports s...
Definition: transport.c:86
static struct transport * transport_list
List of transports known to OpenOCD.
Definition: transport.c:46
COMMAND_HELPER(transport_list_parse, char ***vector)
Makes and stores a copy of a set of transports passed as parameters to a command.
Definition: transport.c:176
static int transport_select(struct command_context *ctx, const char *name)
Definition: transport.c:58
COMMAND_HANDLER(handle_transport_init)
Definition: transport.c:217
static const char *const * allowed_transports
NULL-terminated Vector of names of transports which the currently selected debug adapter supports.
Definition: transport.c:53
static const struct command_registration transport_commands[]
Definition: transport.c:315
static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
Implements the Tcl "transport select" command, choosing the transport to be used in this debug sessio...
Definition: transport.c:255
int transport_register_commands(struct command_context *ctx)
Definition: transport.c:355
static struct transport * session
Definition: transport.c:56
struct transport * get_current_transport(void)
Returns the transport currently being used by this debug or programming session.
Definition: transport.c:157
int transport_register(struct transport *new_transport)
Registers a transport.
Definition: transport.c:129
#define NULL
Definition: usb.h:16