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/align.h>
34 #include <helper/bits.h>
35 #include <helper/list.h>
36 #include <helper/log.h>
37 #include <helper/replacements.h>
38 #include <transport/transport.h>
39 
40 extern struct command_context *global_cmd_ctx;
41 
42 /*-----------------------------------------------------------------------*/
43 
44 /*
45  * Infrastructure internals
46  */
47 
49 static const struct {
50  unsigned int id;
51  const char *name;
52  const char *full_name;
53  const char *deprecated_name;
54 } transport_names[] = {
55  { TRANSPORT_JTAG, "jtag", "jtag", NULL, },
56  { TRANSPORT_SWD, "swd", "swd", NULL, },
57  { TRANSPORT_HLA_JTAG, "jtag", "jtag (hla)", "hla_jtag", },
58  { TRANSPORT_HLA_SWD, "swd", "swd (hla)", "hla_swd", },
59  { TRANSPORT_DAPDIRECT_JTAG, "jtag", "jtag (dapdirect)", "dapdirect_jtag", },
60  { TRANSPORT_DAPDIRECT_SWD, "swd", "swd (dapdirect)", "dapdirect_swd", },
61  { TRANSPORT_SWIM, "swim", "swim", NULL, },
62 };
63 
65 static OOCD_LIST_HEAD(transport_list);
66 
71 static unsigned int allowed_transports;
72 
76 static unsigned int preferred_transport;
77 
82 
84 static struct transport *session;
85 
86 const char *transport_name(unsigned int id)
87 {
88  for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++)
89  if (id == transport_names[i].id)
90  return transport_names[i].name;
91 
92  return NULL;
93 }
94 
95 static const char *transport_full_name(unsigned int id)
96 {
97  for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++)
98  if (id == transport_names[i].id)
99  return transport_names[i].full_name;
100 
101  return NULL;
102 }
103 
104 static const char *transport_deprecated_name(unsigned int id)
105 {
106  for (unsigned int i = 0; i < ARRAY_SIZE(transport_names); i++)
107  if (id == transport_names[i].id)
108  return transport_names[i].deprecated_name;
109 
110  return NULL;
111 }
112 
113 static bool is_transport_id_valid(unsigned int id)
114 {
115  return (id != 0) && ((id & ~TRANSPORT_VALID_MASK) == 0) && IS_PWR_OF_2(id);
116 }
117 
118 static int transport_select(struct command_context *ctx, unsigned int transport_id)
119 {
120  /* name may only identify a known transport;
121  * caller guarantees session's transport isn't yet set.*/
122  struct transport *t;
123  list_for_each_entry(t, &transport_list, lh) {
124  if (t->id == transport_id) {
125  int retval = t->select(ctx);
126  /* select() registers commands specific to this
127  * transport, and may also reset the link, e.g.
128  * forcing it to JTAG or SWD mode.
129  */
130  if (retval == ERROR_OK)
131  session = t;
132  else
133  LOG_ERROR("Error selecting '%s' as transport",
134  transport_full_name(transport_id));
135  return retval;
136  }
137  }
138 
139  LOG_ERROR("No transport named '%s' is available.",
140  transport_full_name(transport_id));
141  return ERROR_FAIL;
142 }
143 
149 int allow_transports(struct command_context *ctx, unsigned int transport_ids,
150  unsigned int transport_preferred_id)
151 {
152  if (allowed_transports || session) {
153  LOG_ERROR("Can't modify the set of allowed transports.");
154  return ERROR_FAIL;
155  }
156 
157  /* validate the values in transport_ids and transport_preferred_id */
158  if (transport_ids == 0 || (transport_ids & ~TRANSPORT_VALID_MASK) != 0) {
159  LOG_ERROR("BUG: Unknown transport IDs %lu", transport_ids & ~TRANSPORT_VALID_MASK);
160  return ERROR_FAIL;
161  }
162 
163  if ((transport_ids & transport_preferred_id) == 0
164  || !IS_PWR_OF_2(transport_preferred_id)) {
165  LOG_ERROR("BUG: Invalid adapter transport_preferred_id");
166  return ERROR_FAIL;
167  }
168 
169  unsigned int mask = transport_ids &
171  if (mask && !IS_PWR_OF_2(mask)) {
172  LOG_ERROR("BUG: Multiple JTAG transports");
173  return ERROR_FAIL;
174  }
175 
176  mask = transport_ids &
178  if (mask && !IS_PWR_OF_2(mask)) {
179  LOG_ERROR("BUG: Multiple SWD transports");
180  return ERROR_FAIL;
181  }
182 
183  allowed_transports = transport_ids;
184  preferred_transport = transport_preferred_id;
185 
186  /* autoselect if there's no choice ... */
187  if (IS_PWR_OF_2(transport_ids)) {
188  LOG_DEBUG("only one transport option; autoselecting '%s'", transport_name(transport_ids));
190  return transport_select(ctx, transport_ids);
191  }
192 
193  return ERROR_OK;
194 }
195 
211 int transport_register(struct transport *new_transport)
212 {
213  struct transport *t;
214 
215  if (!is_transport_id_valid(new_transport->id)) {
216  LOG_ERROR("invalid transport ID 0x%x", new_transport->id);
217  return ERROR_FAIL;
218  }
219 
220  list_for_each_entry(t, &transport_list, lh) {
221  if (t->id == new_transport->id) {
222  LOG_ERROR("transport '%s' already registered",
223  transport_name(t->id));
224  return ERROR_FAIL;
225  }
226  }
227 
228  if (!new_transport->select || !new_transport->init)
229  LOG_ERROR("invalid transport %s",
230  transport_full_name(new_transport->id));
231 
232  /* splice this into the list, sorted in alphabetic order */
233  list_for_each_entry(t, &transport_list, lh) {
234  if (strcmp(transport_name(t->id),
235  transport_name(new_transport->id)) >= 0)
236  break;
237  }
238  list_add_tail(&new_transport->lh, &t->lh);
239 
240  LOG_DEBUG("register '%s' (ID %d)",
241  transport_full_name(new_transport->id), new_transport->id);
242 
243  return ERROR_OK;
244 }
245 
253 {
254  /* REVISIT -- constify */
255  return session;
256 }
257 
258 const char *get_current_transport_name(void)
259 {
261  NULL;
262 
263  return transport_full_name(session->id);
264 }
265 
266 /*-----------------------------------------------------------------------*/
267 
268 /*
269  * Infrastructure for Tcl interface to transports.
270  */
271 
272 COMMAND_HANDLER(handle_transport_init)
273 {
274  LOG_DEBUG("%s", __func__);
275  if (!session) {
276  LOG_ERROR("session transport was not selected. Use 'transport select <transport>'");
277 
278  /* no session transport configured, print transports then fail */
279  LOG_ERROR("Transports available:");
280  for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) {
281  if (i & allowed_transports)
282  LOG_ERROR("%s", transport_full_name(i));
283  }
284  return ERROR_FAIL;
285  }
286 
288  LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". "
289  "Use 'transport select %s' to suppress this message.",
291 
292  return session->init(CMD_CTX);
293 }
294 
295 COMMAND_HANDLER(handle_transport_list)
296 {
297  if (CMD_ARGC != 0)
299 
300  command_print(CMD, "The following transports are available:");
301 
302  struct transport *t;
303  const char *prev_name = NULL;
304  /* list is sorted, don't print duplicated transport names */
305  list_for_each_entry(t, &transport_list, lh) {
306  const char *name = transport_name(t->id);
307  if (!prev_name || strcmp(prev_name, name))
308  command_print(CMD, "\t%s", name);
309  prev_name = name;
310  }
311 
312  return ERROR_OK;
313 }
314 
321 COMMAND_HANDLER(handle_transport_select)
322 {
323  if (CMD_ARGC > 1)
325 
326  if (CMD_ARGC == 0) {
327  /* autoselect if necessary, then return/display current config */
328  if (!session) {
329  if (!allowed_transports) {
330  command_print(CMD, "Debug adapter does not support any transports? Check config file order.");
331  return ERROR_FAIL;
332  }
333  LOG_WARNING("DEPRECATED: auto-selecting transport \"%s\". "
334  "Use 'transport select %s' to suppress this message.",
338  if (retval != ERROR_OK)
339  return retval;
340  }
342  return ERROR_OK;
343  }
344 
345  /* assign transport */
346  if (session) {
347  if (!strcmp(transport_name(session->id), CMD_ARGV[0])
349  && !strcmp(transport_deprecated_name(session->id), CMD_ARGV[0]))) {
351  /* Nothing to do, but also nothing to complain */
353  return ERROR_OK;
354  }
355  LOG_WARNING("Transport \"%s\" was already selected", CMD_ARGV[0]);
356  return ERROR_OK;
357  }
358  command_print(CMD, "Can't change session's transport after the initial selection was made");
359  return ERROR_FAIL;
360  }
361 
362  /* Is this transport supported by our debug adapter?
363  * Example, "JTAG-only" means SWD is not supported.
364  *
365  * NOTE: requires adapter to have been set up, with
366  * transports declared via C.
367  */
368  if (!allowed_transports) {
369  command_print(CMD, "Debug adapter doesn't support any transports?");
370  return ERROR_FAIL;
371  }
372 
373  for (unsigned int i = BIT(0); i & TRANSPORT_VALID_MASK; i <<= 1) {
374  if (!(i & allowed_transports))
375  continue;
376 
377  if (!strcmp(transport_name(i), CMD_ARGV[0]))
378  return transport_select(CMD_CTX, i);
379 
381  && !strcmp(transport_deprecated_name(i), CMD_ARGV[0])) {
382  LOG_WARNING("DEPRECATED! use 'transport select %s', not 'transport select %s'",
384  return transport_select(CMD_CTX, i);
385  }
386  }
387 
388  command_print(CMD, "Debug adapter doesn't support '%s' transport", CMD_ARGV[0]);
389  return ERROR_FAIL;
390 }
391 
392 static const struct command_registration transport_commands[] = {
393  {
394  .name = "init",
395  .handler = handle_transport_init,
396  /* this would be COMMAND_CONFIG ... except that
397  * it needs to trigger event handlers that may
398  * require COMMAND_EXEC ...
399  */
400  .mode = COMMAND_ANY,
401  .help = "Initialize this session's transport",
402  .usage = ""
403  },
404  {
405  .name = "list",
406  .handler = handle_transport_list,
407  .mode = COMMAND_ANY,
408  .help = "list all built-in transports",
409  .usage = ""
410  },
411  {
412  .name = "select",
413  .handler = handle_transport_select,
414  .mode = COMMAND_ANY,
415  .help = "Select this session's transport",
416  .usage = "[transport_name]",
417  },
419 };
420 
421 static const struct command_registration transport_group[] = {
422  {
423  .name = "transport",
424  .mode = COMMAND_ANY,
425  .help = "Transport command group",
426  .chain = transport_commands,
427  .usage = ""
428  },
430 };
431 
433 {
434  return register_commands(ctx, NULL, transport_group);
435 }
#define IS_PWR_OF_2(x)
Definition: align.h:24
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:376
#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
int mask
Definition: esirisc.c:1740
static void list_add_tail(struct list_head *new, struct list_head *head)
Definition: list.h:203
#define list_for_each_entry(p, h, field)
Definition: list.h:155
#define LOG_WARNING(expr ...)
Definition: log.h:130
#define ERROR_FAIL
Definition: log.h:174
#define LOG_ERROR(expr ...)
Definition: log.h:133
#define LOG_DEBUG(expr ...)
Definition: log.h:110
#define ERROR_OK
Definition: log.h:168
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__((unused))
Definition: opcodes.h:117
#define BIT(nr)
Definition: stm32l4x.h:18
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:55
int(* select)(struct command_context *ctx)
When a transport is selected, this method registers its commands and activates the transport (e....
Definition: transport.h:70
int(* init)(struct command_context *ctx)
server startup uses this method to validate transport configuration.
Definition: transport.h:77
unsigned int id
Each transport has a unique ID, used to select it from among the alternatives.
Definition: transport.h:60
struct list_head lh
Transports are stored in a linked list.
Definition: transport.h:90
static const struct command_registration transport_group[]
Definition: transport.c:421
struct command_context * global_cmd_ctx
Definition: openocd.c:233
static bool transport_single_is_autoselected
Adapter supports a single transport; it has been auto-selected.
Definition: transport.c:81
const char * full_name
Definition: transport.c:52
int allow_transports(struct command_context *ctx, unsigned int transport_ids, unsigned int transport_preferred_id)
Called by debug adapter drivers, or affiliated Tcl config scripts, to declare the set of transports s...
Definition: transport.c:149
static const char * transport_deprecated_name(unsigned int id)
Definition: transport.c:104
COMMAND_HANDLER(handle_transport_init)
Definition: transport.c:272
static const char * transport_full_name(unsigned int id)
Definition: transport.c:95
static const struct @128 transport_names[]
List of transports known to OpenOCD.
static unsigned int preferred_transport
Transport ID auto-selected when not specified by the user.
Definition: transport.c:76
static OOCD_LIST_HEAD(transport_list)
List of transports registered in OpenOCD, alphabetically sorted per name.
static const struct command_registration transport_commands[]
Definition: transport.c:392
const char * name
Definition: transport.c:51
const char * get_current_transport_name(void)
Definition: transport.c:258
static unsigned int allowed_transports
Bitmask of transport IDs which the currently selected debug adapter supports.
Definition: transport.c:71
unsigned int id
Definition: transport.c:50
int transport_register_commands(struct command_context *ctx)
Definition: transport.c:432
static struct transport * session
Definition: transport.c:84
static bool is_transport_id_valid(unsigned int id)
Definition: transport.c:113
const char * transport_name(unsigned int id)
Definition: transport.c:86
static int transport_select(struct command_context *ctx, unsigned int transport_id)
Definition: transport.c:118
struct transport * get_current_transport(void)
Returns the transport currently being used by this debug or programming session.
Definition: transport.c:252
int transport_register(struct transport *new_transport)
Registers a transport.
Definition: transport.c:211
const char * deprecated_name
Definition: transport.c:53
#define TRANSPORT_SWIM
Definition: transport.h:25
#define TRANSPORT_DAPDIRECT_JTAG
Definition: transport.h:23
#define TRANSPORT_HLA_JTAG
Definition: transport.h:21
#define TRANSPORT_VALID_MASK
Definition: transport.h:28
#define TRANSPORT_DAPDIRECT_SWD
Definition: transport.h:24
#define TRANSPORT_SWD
Definition: transport.h:20
#define TRANSPORT_HLA_SWD
Definition: transport.h:22
#define TRANSPORT_JTAG
Definition: transport.h:19
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
#define NULL
Definition: usb.h:16