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; autoselecting '%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 COMMAND_HANDLER(handle_transport_select)
256 {
257  if (CMD_ARGC > 1)
259 
260  if (CMD_ARGC == 0) {
261  /* autoselect if necessary, then return/display current config */
262  if (!session) {
263  if (!allowed_transports) {
264  command_print(CMD, "Debug adapter does not support any transports? Check config file order.");
265  return ERROR_FAIL;
266  }
267  LOG_INFO("auto-selecting first available session transport \"%s\". "
268  "To override use 'transport select <transport>'.", allowed_transports[0]);
269  int retval = transport_select(CMD_CTX, allowed_transports[0]);
270  if (retval != ERROR_OK)
271  return retval;
272  }
273  command_print(CMD, "%s", session->name);
274  return ERROR_OK;
275  }
276 
277  /* assign transport */
278  if (session) {
279  if (!strcmp(session->name, CMD_ARGV[0])) {
280  LOG_WARNING("Transport \"%s\" was already selected", session->name);
281  command_print(CMD, "%s", session->name);
282  return ERROR_OK;
283  }
284  command_print(CMD, "Can't change session's transport after the initial selection was made");
285  return ERROR_FAIL;
286  }
287 
288  /* Is this transport supported by our debug adapter?
289  * Example, "JTAG-only" means SWD is not supported.
290  *
291  * NOTE: requires adapter to have been set up, with
292  * transports declared via C.
293  */
294  if (!allowed_transports) {
295  command_print(CMD, "Debug adapter doesn't support any transports?");
296  return ERROR_FAIL;
297  }
298 
299  for (unsigned int i = 0; allowed_transports[i]; i++) {
300  if (!strcmp(allowed_transports[i], CMD_ARGV[0])) {
301  int retval = transport_select(CMD_CTX, CMD_ARGV[0]);
302  if (retval != ERROR_OK)
303  return retval;
304  command_print(CMD, "%s", session->name);
305  return ERROR_OK;
306  }
307  }
308 
309  command_print(CMD, "Debug adapter doesn't support '%s' transport", CMD_ARGV[0]);
310  return ERROR_FAIL;
311 }
312 
313 static const struct command_registration transport_commands[] = {
314  {
315  .name = "init",
316  .handler = handle_transport_init,
317  /* this would be COMMAND_CONFIG ... except that
318  * it needs to trigger event handlers that may
319  * require COMMAND_EXEC ...
320  */
321  .mode = COMMAND_ANY,
322  .help = "Initialize this session's transport",
323  .usage = ""
324  },
325  {
326  .name = "list",
327  .handler = handle_transport_list,
328  .mode = COMMAND_ANY,
329  .help = "list all built-in transports",
330  .usage = ""
331  },
332  {
333  .name = "select",
334  .handler = handle_transport_select,
335  .mode = COMMAND_ANY,
336  .help = "Select this session's transport",
337  .usage = "[transport_name]",
338  },
340 };
341 
342 static const struct command_registration transport_group[] = {
343  {
344  .name = "transport",
345  .mode = COMMAND_ANY,
346  .help = "Transport command group",
347  .chain = transport_commands,
348  .usage = ""
349  },
351 };
352 
354 {
355  return register_commands(ctx, NULL, transport_group);
356 }
const char * name
Definition: armv4_5.c:76
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:443
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:141
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:146
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:253
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:274
@ COMMAND_ANY
Definition: command.h:42
#define LOG_WARNING(expr ...)
Definition: log.h:129
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_INFO(expr ...)
Definition: log.h:126
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
const char * name
Definition: command.h:235
const char * usage
a string listing the options and arguments, required or optional
Definition: command.h:241
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:342
struct command_context * global_cmd_ctx
Definition: openocd.c:233
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:313
int transport_register_commands(struct command_context *ctx)
Definition: transport.c:353
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