2dba45d0b85af4851d5a62f98211dfa351c4d18a
[openocd.git] / src / target / arm_dap.c
1 /***************************************************************************
2 * Copyright (C) 2016 by Matthias Welwarsky *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include "target/arm_adi_v5.h"
27 #include "target/arm.h"
28 #include "helper/list.h"
29 #include "helper/command.h"
30 #include "transport/transport.h"
31 #include "jtag/interface.h"
32
33 static LIST_HEAD(all_dap);
34
35 extern const struct dap_ops swd_dap_ops;
36 extern const struct dap_ops jtag_dp_ops;
37 extern struct adapter_driver *adapter_driver;
38
39 /* DAP command support */
40 struct arm_dap_object {
41 struct list_head lh;
42 struct adiv5_dap dap;
43 char *name;
44 const struct swd_driver *swd;
45 };
46
47 static void dap_instance_init(struct adiv5_dap *dap)
48 {
49 int i;
50 /* Set up with safe defaults */
51 for (i = 0; i <= DP_APSEL_MAX; i++) {
52 dap->ap[i].dap = dap;
53 dap->ap[i].ap_num = i;
54 /* memaccess_tck max is 255 */
55 dap->ap[i].memaccess_tck = 255;
56 /* Number of bits for tar autoincrement, impl. dep. at least 10 */
57 dap->ap[i].tar_autoincr_block = (1<<10);
58 /* default CSW value */
59 dap->ap[i].csw_default = CSW_AHB_DEFAULT;
60 dap->ap[i].cfg_reg = MEM_AP_REG_CFG_INVALID; /* mem_ap configuration reg (large physical addr, etc.) */
61 }
62 INIT_LIST_HEAD(&dap->cmd_journal);
63 INIT_LIST_HEAD(&dap->cmd_pool);
64 }
65
66 const char *adiv5_dap_name(struct adiv5_dap *self)
67 {
68 struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap);
69 return obj->name;
70 }
71
72 const struct swd_driver *adiv5_dap_swd_driver(struct adiv5_dap *self)
73 {
74 struct arm_dap_object *obj = container_of(self, struct arm_dap_object, dap);
75 return obj->swd;
76 }
77
78 struct adiv5_dap *adiv5_get_dap(struct arm_dap_object *obj)
79 {
80 return &obj->dap;
81 }
82 struct adiv5_dap *dap_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
83 {
84 struct arm_dap_object *obj = NULL;
85 const char *name;
86 bool found = false;
87
88 name = Jim_GetString(o, NULL);
89
90 list_for_each_entry(obj, &all_dap, lh) {
91 if (!strcmp(name, obj->name)) {
92 found = true;
93 break;
94 }
95 }
96
97 if (found)
98 return &obj->dap;
99 return NULL;
100 }
101
102 static int dap_init_all(void)
103 {
104 struct arm_dap_object *obj;
105 int retval;
106
107 LOG_DEBUG("Initializing all DAPs ...");
108
109 list_for_each_entry(obj, &all_dap, lh) {
110 struct adiv5_dap *dap = &obj->dap;
111
112 /* with hla, dap is just a dummy */
113 if (transport_is_hla())
114 continue;
115
116 /* skip taps that are disabled */
117 if (!dap->tap->enabled)
118 continue;
119
120 if (transport_is_swd()) {
121 dap->ops = &swd_dap_ops;
122 obj->swd = adapter_driver->swd_ops;
123 } else if (transport_is_dapdirect_swd()) {
124 dap->ops = adapter_driver->dap_swd_ops;
125 } else if (transport_is_dapdirect_jtag()) {
126 dap->ops = adapter_driver->dap_jtag_ops;
127 } else
128 dap->ops = &jtag_dp_ops;
129
130 retval = dap->ops->connect(dap);
131 if (retval != ERROR_OK)
132 return retval;
133 }
134
135 return ERROR_OK;
136 }
137
138 int dap_cleanup_all(void)
139 {
140 struct arm_dap_object *obj, *tmp;
141 struct adiv5_dap *dap;
142
143 list_for_each_entry_safe(obj, tmp, &all_dap, lh) {
144 dap = &obj->dap;
145 if (dap->ops && dap->ops->quit)
146 dap->ops->quit(dap);
147
148 free(obj->name);
149 free(obj);
150 }
151
152 return ERROR_OK;
153 }
154
155 enum dap_cfg_param {
156 CFG_CHAIN_POSITION,
157 CFG_IGNORE_SYSPWRUPACK,
158 CFG_DP_ID,
159 CFG_INSTANCE_ID,
160 };
161
162 static const struct jim_nvp nvp_config_opts[] = {
163 { .name = "-chain-position", .value = CFG_CHAIN_POSITION },
164 { .name = "-ignore-syspwrupack", .value = CFG_IGNORE_SYSPWRUPACK },
165 { .name = "-dp-id", .value = CFG_DP_ID },
166 { .name = "-instance-id", .value = CFG_INSTANCE_ID },
167 { .name = NULL, .value = -1 }
168 };
169
170 static int dap_configure(struct jim_getopt_info *goi, struct arm_dap_object *dap)
171 {
172 struct jim_nvp *n;
173 int e;
174
175 /* parse config ... */
176 while (goi->argc > 0) {
177 Jim_SetEmptyResult(goi->interp);
178
179 e = jim_getopt_nvp(goi, nvp_config_opts, &n);
180 if (e != JIM_OK) {
181 jim_getopt_nvp_unknown(goi, nvp_config_opts, 0);
182 return e;
183 }
184 switch (n->value) {
185 case CFG_CHAIN_POSITION: {
186 Jim_Obj *o_t;
187 e = jim_getopt_obj(goi, &o_t);
188 if (e != JIM_OK)
189 return e;
190
191 struct jtag_tap *tap;
192 tap = jtag_tap_by_jim_obj(goi->interp, o_t);
193 if (!tap) {
194 Jim_SetResultString(goi->interp, "-chain-position is invalid", -1);
195 return JIM_ERR;
196 }
197 dap->dap.tap = tap;
198 /* loop for more */
199 break;
200 }
201 case CFG_IGNORE_SYSPWRUPACK:
202 dap->dap.ignore_syspwrupack = true;
203 break;
204 case CFG_DP_ID: {
205 jim_wide w;
206 e = jim_getopt_wide(goi, &w);
207 if (e != JIM_OK) {
208 Jim_SetResultFormatted(goi->interp,
209 "create %s: bad parameter %s",
210 dap->name, n->name);
211 return JIM_ERR;
212 }
213 if (w < 0 || w > DP_TARGETSEL_DPID_MASK) {
214 Jim_SetResultFormatted(goi->interp,
215 "create %s: %s out of range",
216 dap->name, n->name);
217 return JIM_ERR;
218 }
219 dap->dap.multidrop_targetsel =
220 (dap->dap.multidrop_targetsel & DP_TARGETSEL_INSTANCEID_MASK)
221 | (w & DP_TARGETSEL_DPID_MASK);
222 dap->dap.multidrop_dp_id_valid = true;
223 break;
224 }
225 case CFG_INSTANCE_ID: {
226 jim_wide w;
227 e = jim_getopt_wide(goi, &w);
228 if (e != JIM_OK) {
229 Jim_SetResultFormatted(goi->interp,
230 "create %s: bad parameter %s",
231 dap->name, n->name);
232 return JIM_ERR;
233 }
234 if (w < 0 || w > 15) {
235 Jim_SetResultFormatted(goi->interp,
236 "create %s: %s out of range",
237 dap->name, n->name);
238 return JIM_ERR;
239 }
240 dap->dap.multidrop_targetsel =
241 (dap->dap.multidrop_targetsel & DP_TARGETSEL_DPID_MASK)
242 | ((w << DP_TARGETSEL_INSTANCEID_SHIFT) & DP_TARGETSEL_INSTANCEID_MASK);
243 dap->dap.multidrop_instance_id_valid = true;
244 break;
245 }
246 default:
247 break;
248 }
249 }
250
251 return JIM_OK;
252 }
253
254 static int dap_check_config(struct adiv5_dap *dap)
255 {
256 if (transport_is_jtag() || transport_is_dapdirect_jtag() || transport_is_hla())
257 return ERROR_OK;
258
259 struct arm_dap_object *obj;
260 bool new_multidrop = dap_is_multidrop(dap);
261 bool had_multidrop = new_multidrop;
262 uint32_t targetsel = dap->multidrop_targetsel;
263 unsigned int non_multidrop_count = had_multidrop ? 0 : 1;
264
265 list_for_each_entry(obj, &all_dap, lh) {
266 struct adiv5_dap *dap_it = &obj->dap;
267
268 if (transport_is_swd()) {
269 if (dap_is_multidrop(dap_it)) {
270 had_multidrop = true;
271 if (new_multidrop && dap_it->multidrop_targetsel == targetsel) {
272 uint32_t dp_id = targetsel & DP_TARGETSEL_DPID_MASK;
273 uint32_t instance_id = targetsel >> DP_TARGETSEL_INSTANCEID_SHIFT;
274 LOG_ERROR("%s and %s have the same multidrop selectors -dp-id 0x%08"
275 PRIx32 " and -instance-id 0x%" PRIx32,
276 obj->name, adiv5_dap_name(dap),
277 dp_id, instance_id);
278 return ERROR_FAIL;
279 }
280 } else {
281 non_multidrop_count++;
282 }
283 } else if (transport_is_dapdirect_swd()) {
284 non_multidrop_count++;
285 }
286 }
287
288 if (non_multidrop_count > 1) {
289 LOG_ERROR("Two or more SWD non multidrop DAPs are not supported");
290 return ERROR_FAIL;
291 }
292 if (had_multidrop && non_multidrop_count) {
293 LOG_ERROR("Mixing of SWD multidrop DAPs and non multidrop DAPs is not supported");
294 return ERROR_FAIL;
295 }
296
297 return ERROR_OK;
298 }
299
300 static int dap_create(struct jim_getopt_info *goi)
301 {
302 struct command_context *cmd_ctx;
303 static struct arm_dap_object *dap;
304 Jim_Obj *new_cmd;
305 Jim_Cmd *cmd;
306 const char *cp;
307 int e;
308
309 cmd_ctx = current_command_context(goi->interp);
310 assert(cmd_ctx);
311
312 if (goi->argc < 3) {
313 Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options...");
314 return JIM_ERR;
315 }
316 /* COMMAND */
317 jim_getopt_obj(goi, &new_cmd);
318 /* does this command exist? */
319 cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE);
320 if (cmd) {
321 cp = Jim_GetString(new_cmd, NULL);
322 Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp);
323 return JIM_ERR;
324 }
325
326 /* Create it */
327 dap = calloc(1, sizeof(struct arm_dap_object));
328 if (!dap)
329 return JIM_ERR;
330
331 dap_instance_init(&dap->dap);
332
333 cp = Jim_GetString(new_cmd, NULL);
334 dap->name = strdup(cp);
335
336 e = dap_configure(goi, dap);
337 if (e != JIM_OK)
338 goto err;
339
340 if (!dap->dap.tap) {
341 Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1);
342 e = JIM_ERR;
343 goto err;
344 }
345
346 e = dap_check_config(&dap->dap);
347 if (e != ERROR_OK) {
348 e = JIM_ERR;
349 goto err;
350 }
351
352 struct command_registration dap_create_commands[] = {
353 {
354 .name = cp,
355 .mode = COMMAND_ANY,
356 .help = "dap instance command group",
357 .usage = "",
358 .chain = dap_instance_commands,
359 },
360 COMMAND_REGISTRATION_DONE
361 };
362
363 /* don't expose the instance commands when using hla */
364 if (transport_is_hla())
365 dap_create_commands[0].chain = NULL;
366
367 e = register_commands_with_data(cmd_ctx, NULL, dap_create_commands, dap);
368 if (e != ERROR_OK) {
369 e = JIM_ERR;
370 goto err;
371 }
372
373 list_add_tail(&dap->lh, &all_dap);
374
375 return JIM_OK;
376
377 err:
378 free(dap->name);
379 free(dap);
380 return e;
381 }
382
383 static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
384 {
385 struct jim_getopt_info goi;
386 jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
387 if (goi.argc < 2) {
388 Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv,
389 "<name> [<dap_options> ...]");
390 return JIM_ERR;
391 }
392 return dap_create(&goi);
393 }
394
395 static int jim_dap_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
396 {
397 struct arm_dap_object *obj;
398
399 if (argc != 1) {
400 Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
401 return JIM_ERR;
402 }
403 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
404 list_for_each_entry(obj, &all_dap, lh) {
405 Jim_ListAppendElement(interp, Jim_GetResult(interp),
406 Jim_NewStringObj(interp, obj->name, -1));
407 }
408 return JIM_OK;
409 }
410
411 COMMAND_HANDLER(handle_dap_init)
412 {
413 return dap_init_all();
414 }
415
416 COMMAND_HANDLER(handle_dap_info_command)
417 {
418 struct target *target = get_current_target(CMD_CTX);
419 struct arm *arm = target_to_arm(target);
420 struct adiv5_dap *dap = arm->dap;
421 uint32_t apsel;
422
423 if (!dap) {
424 LOG_ERROR("DAP instance not available. Probably a HLA target...");
425 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
426 }
427
428 switch (CMD_ARGC) {
429 case 0:
430 apsel = dap->apsel;
431 break;
432 case 1:
433 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
434 if (apsel > DP_APSEL_MAX)
435 return ERROR_COMMAND_SYNTAX_ERROR;
436 break;
437 default:
438 return ERROR_COMMAND_SYNTAX_ERROR;
439 }
440
441 return dap_info_command(CMD, &dap->ap[apsel]);
442 }
443
444 static const struct command_registration dap_subcommand_handlers[] = {
445 {
446 .name = "create",
447 .mode = COMMAND_ANY,
448 .jim_handler = jim_dap_create,
449 .usage = "name '-chain-position' name",
450 .help = "Creates a new DAP instance",
451 },
452 {
453 .name = "names",
454 .mode = COMMAND_ANY,
455 .jim_handler = jim_dap_names,
456 .usage = "",
457 .help = "Lists all registered DAP instances by name",
458 },
459 {
460 .name = "init",
461 .mode = COMMAND_ANY,
462 .handler = handle_dap_init,
463 .usage = "",
464 .help = "Initialize all registered DAP instances"
465 },
466 {
467 .name = "info",
468 .handler = handle_dap_info_command,
469 .mode = COMMAND_EXEC,
470 .help = "display ROM table for MEM-AP of current target "
471 "(default currently selected AP)",
472 .usage = "[ap_num]",
473 },
474 COMMAND_REGISTRATION_DONE
475 };
476
477 static const struct command_registration dap_commands[] = {
478 {
479 .name = "dap",
480 .mode = COMMAND_CONFIG,
481 .help = "DAP commands",
482 .chain = dap_subcommand_handlers,
483 .usage = "",
484 },
485 COMMAND_REGISTRATION_DONE
486 };
487
488 int dap_register_commands(struct command_context *cmd_ctx)
489 {
490 return register_commands(cmd_ctx, NULL, dap_commands);
491 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)