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 int n = CMD_ARGC;
180  unsigned int 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 int 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 int 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  return ERROR_OK;
282  }
283  command_print(CMD, "Can't change session's transport after the initial selection was made");
284  return ERROR_FAIL;
285  }
286 
287  /* Is this transport supported by our debug adapter?
288  * Example, "JTAG-only" means SWD is not supported.
289  *
290  * NOTE: requires adapter to have been set up, with
291  * transports declared via C.
292  */
293  if (!allowed_transports) {
294  command_print(CMD, "Debug adapter doesn't support any transports?");
295  return ERROR_FAIL;
296  }
297 
298  for (unsigned int i = 0; allowed_transports[i]; i++) {
299  if (!strcmp(allowed_transports[i], CMD_ARGV[0])) {
300  int retval = transport_select(CMD_CTX, CMD_ARGV[0]);
301  if (retval != ERROR_OK)
302  return retval;
303  return ERROR_OK;
304  }
305  }
306 
307  command_print(CMD, "Debug adapter doesn't support '%s' transport", CMD_ARGV[0]);
308  return ERROR_FAIL;
309 }
310 
311 static const struct command_registration transport_commands[] = {
312  {
313  .name = "init",
314  .handler = handle_transport_init,
315  /* this would be COMMAND_CONFIG ... except that
316  * it needs to trigger event handlers that may
317  * require COMMAND_EXEC ...
318  */
319  .mode = COMMAND_ANY,
320  .help = "Initialize this session's transport",
321  .usage = ""
322  },
323  {
324  .name = "list",
325  .handler = handle_transport_list,
326  .mode = COMMAND_ANY,
327  .help = "list all built-in transports",
328  .usage = ""
329  },
330  {
331  .name = "select",
332  .handler = handle_transport_select,
333  .mode = COMMAND_ANY,
334  .help = "Select this session's transport",
335  .usage = "[transport_name]",
336  },
338 };
339 
340 static const struct command_registration transport_group[] = {
341  {
342  .name = "transport",
343  .mode = COMMAND_ANY,
344  .help = "Transport command group",
345  .chain = transport_commands,
346  .usage = ""
347  },
349 };
350 
352 {
353  return register_commands(ctx, NULL, transport_group);
354 }
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:340
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:311
int transport_register_commands(struct command_context *ctx)
Definition: transport.c:351
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