target: clarify usage of `coreid`
[openocd.git] / src / target / espressif / esp_xtensa_smp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * ESP Xtensa SMP target API for OpenOCD *
5 * Copyright (C) 2020 Espressif Systems Ltd. Co *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "assert.h"
13 #include <target/target.h>
14 #include <target/target_type.h>
15 #include <target/smp.h>
16 #include <target/semihosting_common.h>
17 #include "esp_xtensa_smp.h"
18 #include "esp_xtensa_semihosting.h"
19
20 /*
21 Multiprocessor stuff common:
22
23 The ESP Xtensa chip can have several cores in it, which can run in SMP-mode if an
24 SMP-capable OS is running. The hardware has a few features which makes
25 SMP debugging much easier.
26
27 First of all, there's something called a 'break network', consisting of a
28 BreakIn input and a BreakOut output on each CPU. The idea is that as soon
29 as a CPU goes into debug mode for whatever reason, it'll signal that using
30 its DebugOut pin. This signal is connected to the other CPU's DebugIn
31 input, causing this CPU also to go into debugging mode. To resume execution
32 when using only this break network, we will need to manually resume both
33 CPUs.
34
35 An alternative to this is the XOCDMode output and the RunStall (or DebugStall)
36 input. When these are cross-connected, a CPU that goes into debug mode will
37 halt execution entirely on the other CPU. Execution on the other CPU can be
38 resumed by either the first CPU going out of debug mode, or the second CPU
39 going into debug mode: the stall is temporarily lifted as long as the stalled
40 CPU is in debug mode.
41
42 A third, separate, signal is CrossTrigger. This is connected in the same way
43 as the breakIn/breakOut network, but is for the TRAX (trace memory) feature;
44 it does not affect OCD in any way.
45 */
46
47 /*
48 Multiprocessor stuff:
49
50 The ESP Xtensa chip has several Xtensa cores inside, but represent themself to the OCD
51 as one chip that works in multithreading mode under FreeRTOS OS.
52 The core that initiate the stop condition will be defined as an active cpu.
53 When one core stops, then other core will be stopped automatically by smpbreak.
54 The core that initiates stop condition will be defined as an active core, and
55 registers of this core will be transferred.
56 */
57
58 #define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES 5
59
60 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume);
61
62 static inline struct esp_xtensa_smp_common *target_to_esp_xtensa_smp(struct target *target)
63 {
64 return container_of(target->arch_info, struct esp_xtensa_smp_common, esp_xtensa);
65 }
66
67 int esp_xtensa_smp_assert_reset(struct target *target)
68 {
69 return ERROR_OK;
70 }
71
72 int esp_xtensa_smp_deassert_reset(struct target *target)
73 {
74 LOG_TARGET_DEBUG(target, "begin");
75
76 int ret = xtensa_deassert_reset(target);
77 if (ret != ERROR_OK)
78 return ret;
79 /* in SMP mode when chip was running single-core app the other core can be left un-examined,
80 because examination is done before SOC reset. But after SOC reset it is functional and should be handled.
81 So try to examine un-examined core just after SOC reset */
82 if (target->smp && !target_was_examined(target))
83 ret = xtensa_examine(target);
84 return ret;
85 }
86
87 int esp_xtensa_smp_soft_reset_halt(struct target *target)
88 {
89 int res;
90 struct target_list *head;
91 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
92
93 LOG_TARGET_DEBUG(target, "begin");
94 /* in SMP mode we need to ensure that at first we reset SOC on PRO-CPU
95 and then call xtensa_assert_reset() for all cores */
96 if (target->smp && target->coreid != 0)
97 return ERROR_OK;
98 /* Reset the SoC first */
99 if (esp_xtensa_smp->chip_ops->reset) {
100 res = esp_xtensa_smp->chip_ops->reset(target);
101 if (res != ERROR_OK)
102 return res;
103 }
104 if (!target->smp)
105 return xtensa_assert_reset(target);
106
107 foreach_smp_target(head, target->smp_targets) {
108 res = xtensa_assert_reset(head->target);
109 if (res != ERROR_OK)
110 return res;
111 }
112 return ERROR_OK;
113 }
114
115 int esp_xtensa_smp_on_halt(struct target *target)
116 {
117 struct target_list *head;
118
119 if (!target->smp)
120 return esp_xtensa_on_halt(target);
121
122 foreach_smp_target(head, target->smp_targets) {
123 int res = esp_xtensa_on_halt(head->target);
124 if (res != ERROR_OK)
125 return res;
126 }
127 return ERROR_OK;
128 }
129
130 static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid)
131 {
132 struct target_list *head;
133 struct target *curr;
134
135 foreach_smp_target(head, target->smp_targets) {
136 curr = head->target;
137 if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
138 return curr;
139 }
140
141 return target;
142 }
143
144 int esp_xtensa_smp_poll(struct target *target)
145 {
146 enum target_state old_state = target->state;
147 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
148 struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target);
149 uint32_t old_dbg_stubs_base = esp_xtensa->esp.dbg_stubs.base;
150 struct target_list *head;
151 struct target *curr;
152 bool other_core_resume_req = false;
153
154 if (target->state == TARGET_HALTED && target->smp && target->gdb_service && !target->gdb_service->target) {
155 target->gdb_service->target = get_halted_esp_xtensa_smp(target, target->gdb_service->core[1]);
156 LOG_INFO("Switch GDB target to '%s'", target_name(target->gdb_service->target));
157 if (esp_xtensa_smp->chip_ops->on_halt)
158 esp_xtensa_smp->chip_ops->on_halt(target);
159 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
160 return ERROR_OK;
161 }
162
163 int ret = esp_xtensa_poll(target);
164 if (ret != ERROR_OK)
165 return ret;
166
167 if (esp_xtensa->esp.dbg_stubs.base && old_dbg_stubs_base != esp_xtensa->esp.dbg_stubs.base) {
168 /* debug stubs base is set only in PRO-CPU TRAX register, so sync this info */
169 foreach_smp_target(head, target->smp_targets) {
170 curr = head->target;
171 if (curr == target)
172 continue;
173 target_to_esp_xtensa(curr)->esp.dbg_stubs.base = esp_xtensa->esp.dbg_stubs.base;
174 }
175 }
176
177 if (target->smp) {
178 if (target->state == TARGET_RESET) {
179 esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
180 } else if (esp_xtensa_smp->examine_other_cores > 0 &&
181 (target->state == TARGET_RUNNING || target->state == TARGET_HALTED)) {
182 LOG_TARGET_DEBUG(target, "Check for unexamined cores after reset");
183 bool all_examined = true;
184 foreach_smp_target(head, target->smp_targets) {
185 curr = head->target;
186 if (curr == target)
187 continue;
188 if (!target_was_examined(curr)) {
189 if (target_examine_one(curr) != ERROR_OK) {
190 LOG_DEBUG("Failed to examine!");
191 all_examined = false;
192 }
193 }
194 }
195 if (all_examined)
196 esp_xtensa_smp->examine_other_cores = 0;
197 else
198 esp_xtensa_smp->examine_other_cores--;
199 }
200 }
201
202 if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
203 if (target->smp) {
204 ret = esp_xtensa_smp_update_halt_gdb(target, &other_core_resume_req);
205 if (ret != ERROR_OK)
206 return ret;
207 }
208 /* Call any event callbacks that are applicable */
209 if (old_state == TARGET_DEBUG_RUNNING) {
210 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
211 } else {
212 if (esp_xtensa_semihosting(target, &ret) == SEMIHOSTING_HANDLED) {
213 if (ret == ERROR_OK && esp_xtensa->semihost.need_resume &&
214 !esp_xtensa_smp->other_core_does_resume) {
215 esp_xtensa->semihost.need_resume = false;
216 /* Resume xtensa_resume will handle BREAK instruction. */
217 ret = target_resume(target, 1, 0, 1, 0);
218 if (ret != ERROR_OK) {
219 LOG_ERROR("Failed to resume target");
220 return ret;
221 }
222 }
223 return ret;
224 }
225 /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */
226 if (target->smp && other_core_resume_req) {
227 /* Resume xtensa_resume will handle BREAK instruction. */
228 ret = target_resume(target, 1, 0, 1, 0);
229 if (ret != ERROR_OK) {
230 LOG_ERROR("Failed to resume target");
231 return ret;
232 }
233 return ERROR_OK;
234 }
235 if (esp_xtensa_smp->chip_ops->on_halt)
236 esp_xtensa_smp->chip_ops->on_halt(target);
237 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
238 }
239 }
240
241 return ERROR_OK;
242 }
243
244 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume)
245 {
246 struct esp_xtensa_smp_common *esp_xtensa_smp;
247 struct target *gdb_target = NULL;
248 struct target_list *head;
249 struct target *curr;
250 int ret = ERROR_OK;
251
252 *need_resume = false;
253
254 if (target->gdb_service && target->gdb_service->target)
255 LOG_DEBUG("GDB target '%s'", target_name(target->gdb_service->target));
256
257 if (target->gdb_service && target->gdb_service->core[0] == -1) {
258 target->gdb_service->target = target;
259 target->gdb_service->core[0] = target->coreid;
260 LOG_INFO("Set GDB target to '%s'", target_name(target));
261 }
262
263 if (target->gdb_service)
264 gdb_target = target->gdb_service->target;
265
266 /* due to smpbreak config other cores can also go to HALTED state */
267 foreach_smp_target(head, target->smp_targets) {
268 curr = head->target;
269 LOG_DEBUG("Check target '%s'", target_name(curr));
270 /* skip calling context */
271 if (curr == target)
272 continue;
273 if (!target_was_examined(curr)) {
274 curr->state = TARGET_HALTED;
275 continue;
276 }
277 /* skip targets that were already halted */
278 if (curr->state == TARGET_HALTED)
279 continue;
280 /* Skip gdb_target; it alerts GDB so has to be polled as last one */
281 if (curr == gdb_target)
282 continue;
283 LOG_DEBUG("Poll target '%s'", target_name(curr));
284
285 esp_xtensa_smp = target_to_esp_xtensa_smp(curr);
286 /* avoid auto-resume after syscall, it will be done later */
287 esp_xtensa_smp->other_core_does_resume = true;
288 /* avoid recursion in esp_xtensa_smp_poll() */
289 curr->smp = 0;
290 if (esp_xtensa_smp->chip_ops->poll)
291 ret = esp_xtensa_smp->chip_ops->poll(curr);
292 else
293 ret = esp_xtensa_smp_poll(curr);
294 curr->smp = 1;
295 if (ret != ERROR_OK)
296 return ret;
297 esp_xtensa_smp->other_core_does_resume = false;
298 struct esp_xtensa_common *curr_esp_xtensa = target_to_esp_xtensa(curr);
299 if (curr_esp_xtensa->semihost.need_resume) {
300 curr_esp_xtensa->semihost.need_resume = false;
301 *need_resume = true;
302 }
303 }
304
305 /* after all targets were updated, poll the gdb serving target */
306 if (gdb_target && gdb_target != target) {
307 esp_xtensa_smp = target_to_esp_xtensa_smp(gdb_target);
308 if (esp_xtensa_smp->chip_ops->poll)
309 ret = esp_xtensa_smp->chip_ops->poll(gdb_target);
310 else
311 ret = esp_xtensa_smp_poll(gdb_target);
312 }
313
314 LOG_DEBUG("exit");
315
316 return ret;
317 }
318
319 static inline int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break)
320 {
321 int res = xtensa_smpbreak_get(target, smp_break);
322 if (res != ERROR_OK)
323 return res;
324 return xtensa_smpbreak_set(target, 0);
325 }
326
327 static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break)
328 {
329 return xtensa_smpbreak_set(target, smp_break);
330 }
331
332 static int esp_xtensa_smp_resume_cores(struct target *target,
333 int handle_breakpoints,
334 int debug_execution)
335 {
336 struct target_list *head;
337 struct target *curr;
338
339 LOG_TARGET_DEBUG(target, "begin");
340
341 foreach_smp_target(head, target->smp_targets) {
342 curr = head->target;
343 /* in single-core mode disabled core cannot be examined, but need to be resumed too*/
344 if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) {
345 /* resume current address, not in SMP mode */
346 curr->smp = 0;
347 int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution);
348 curr->smp = 1;
349 if (res != ERROR_OK)
350 return res;
351 }
352 }
353 return ERROR_OK;
354 }
355
356 int esp_xtensa_smp_resume(struct target *target,
357 int current,
358 target_addr_t address,
359 int handle_breakpoints,
360 int debug_execution)
361 {
362 int res;
363 uint32_t smp_break;
364
365 xtensa_smpbreak_get(target, &smp_break);
366 LOG_TARGET_DEBUG(target, "smp_break=0x%" PRIx32, smp_break);
367
368 /* dummy resume for smp toggle in order to reduce gdb impact */
369 if ((target->smp) && (target->gdb_service) && (target->gdb_service->core[1] != -1)) {
370 /* simulate a start and halt of target */
371 target->gdb_service->target = NULL;
372 target->gdb_service->core[0] = target->gdb_service->core[1];
373 /* fake resume at next poll we play the target core[1], see poll*/
374 LOG_TARGET_DEBUG(target, "Fake resume");
375 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
376 return ERROR_OK;
377 }
378
379 /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for
380 * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */
381 res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
382 if (res != ERROR_OK)
383 return res;
384 res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution);
385 /* restore configured BreakInOut signals config */
386 int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
387 if (ret != ERROR_OK)
388 return ret;
389 if (res != ERROR_OK) {
390 LOG_TARGET_ERROR(target, "Failed to prepare for resume!");
391 return res;
392 }
393
394 if (target->smp) {
395 if (target->gdb_service)
396 target->gdb_service->core[0] = -1;
397 res = esp_xtensa_smp_resume_cores(target, handle_breakpoints, debug_execution);
398 if (res != ERROR_OK)
399 return res;
400 }
401
402 res = xtensa_do_resume(target);
403 if (res != ERROR_OK) {
404 LOG_TARGET_ERROR(target, "Failed to resume!");
405 return res;
406 }
407
408 target->debug_reason = DBG_REASON_NOTHALTED;
409 if (!debug_execution)
410 target->state = TARGET_RUNNING;
411 else
412 target->state = TARGET_DEBUG_RUNNING;
413
414 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
415 return ERROR_OK;
416 }
417
418 int esp_xtensa_smp_step(struct target *target,
419 int current,
420 target_addr_t address,
421 int handle_breakpoints)
422 {
423 int res;
424 uint32_t smp_break = 0;
425 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
426
427 if (target->smp) {
428 res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
429 if (res != ERROR_OK)
430 return res;
431 }
432 res = xtensa_step(target, current, address, handle_breakpoints);
433
434 if (res == ERROR_OK) {
435 if (esp_xtensa_smp->chip_ops->on_halt)
436 esp_xtensa_smp->chip_ops->on_halt(target);
437 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
438 }
439
440 if (target->smp) {
441 int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
442 if (ret != ERROR_OK)
443 return ret;
444 }
445
446 return res;
447 }
448
449 int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint)
450 {
451 int res = xtensa_watchpoint_add(target, watchpoint);
452 if (res != ERROR_OK)
453 return res;
454
455 if (!target->smp)
456 return ERROR_OK;
457
458 struct target_list *head;
459 foreach_smp_target(head, target->smp_targets) {
460 struct target *curr = head->target;
461 if (curr == target || !target_was_examined(curr))
462 continue;
463 /* Need to use high level API here because every target for core contains list of watchpoints.
464 * GDB works with active core only, so we need to duplicate every watchpoint on other cores,
465 * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */
466 curr->smp = 0;
467 res = watchpoint_add(curr, watchpoint->address, watchpoint->length,
468 watchpoint->rw, watchpoint->value, watchpoint->mask);
469 curr->smp = 1;
470 if (res != ERROR_OK)
471 return res;
472 }
473 return ERROR_OK;
474 }
475
476 int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint)
477 {
478 int res = xtensa_watchpoint_remove(target, watchpoint);
479 if (res != ERROR_OK)
480 return res;
481
482 if (!target->smp)
483 return ERROR_OK;
484
485 struct target_list *head;
486 foreach_smp_target(head, target->smp_targets) {
487 struct target *curr = head->target;
488 if (curr == target)
489 continue;
490 /* see big comment in esp_xtensa_smp_watchpoint_add() */
491 curr->smp = 0;
492 watchpoint_remove(curr, watchpoint->address);
493 curr->smp = 1;
494 }
495 return ERROR_OK;
496 }
497
498 int esp_xtensa_smp_init_arch_info(struct target *target,
499 struct esp_xtensa_smp_common *esp_xtensa_smp,
500 struct xtensa_debug_module_config *dm_cfg,
501 const struct esp_xtensa_smp_chip_ops *chip_ops,
502 const struct esp_semihost_ops *semihost_ops)
503 {
504 int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, dm_cfg, semihost_ops);
505 if (ret != ERROR_OK)
506 return ret;
507 esp_xtensa_smp->chip_ops = chip_ops;
508 esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
509 return ERROR_OK;
510 }
511
512 int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target)
513 {
514 int ret = esp_xtensa_target_init(cmd_ctx, target);
515 if (ret != ERROR_OK)
516 return ret;
517
518 if (target->smp) {
519 struct target_list *head;
520 foreach_smp_target(head, target->smp_targets) {
521 struct target *curr = head->target;
522 ret = esp_xtensa_semihosting_init(curr);
523 if (ret != ERROR_OK)
524 return ret;
525 }
526 } else {
527 ret = esp_xtensa_semihosting_init(target);
528 if (ret != ERROR_OK)
529 return ret;
530 }
531 return ERROR_OK;
532 }
533
534 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef)
535 {
536 struct target *target = get_current_target(CMD_CTX);
537 if (target->smp && CMD_ARGC > 0) {
538 struct target_list *head;
539 struct target *curr;
540 foreach_smp_target(head, target->smp_targets) {
541 curr = head->target;
542 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
543 target_to_xtensa(curr));
544 if (ret != ERROR_OK)
545 return ret;
546 }
547 return ERROR_OK;
548 }
549 return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
550 target_to_xtensa(target));
551 }
552
553 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtopt)
554 {
555 struct target *target = get_current_target(CMD_CTX);
556 if (target->smp && CMD_ARGC > 0) {
557 struct target_list *head;
558 struct target *curr;
559 foreach_smp_target(head, target->smp_targets) {
560 curr = head->target;
561 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
562 target_to_xtensa(curr));
563 if (ret != ERROR_OK)
564 return ret;
565 }
566 return ERROR_OK;
567 }
568 return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
569 target_to_xtensa(target));
570 }
571
572 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmem)
573 {
574 struct target *target = get_current_target(CMD_CTX);
575 if (target->smp && CMD_ARGC > 0) {
576 struct target_list *head;
577 struct target *curr;
578 foreach_smp_target(head, target->smp_targets) {
579 curr = head->target;
580 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
581 target_to_xtensa(curr));
582 if (ret != ERROR_OK)
583 return ret;
584 }
585 return ERROR_OK;
586 }
587 return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
588 target_to_xtensa(target));
589 }
590
591 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmpu)
592 {
593 struct target *target = get_current_target(CMD_CTX);
594 if (target->smp && CMD_ARGC > 0) {
595 struct target_list *head;
596 struct target *curr;
597 foreach_smp_target(head, target->smp_targets) {
598 curr = head->target;
599 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
600 target_to_xtensa(curr));
601 if (ret != ERROR_OK)
602 return ret;
603 }
604 return ERROR_OK;
605 }
606 return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
607 target_to_xtensa(target));
608 }
609
610 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmmu)
611 {
612 struct target *target = get_current_target(CMD_CTX);
613 if (target->smp && CMD_ARGC > 0) {
614 struct target_list *head;
615 struct target *curr;
616 foreach_smp_target(head, target->smp_targets) {
617 curr = head->target;
618 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
619 target_to_xtensa(curr));
620 if (ret != ERROR_OK)
621 return ret;
622 }
623 return ERROR_OK;
624 }
625 return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
626 target_to_xtensa(target));
627 }
628
629 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtreg)
630 {
631 struct target *target = get_current_target(CMD_CTX);
632 if (target->smp && CMD_ARGC > 0) {
633 struct target_list *head;
634 struct target *curr;
635 foreach_smp_target(head, target->smp_targets) {
636 curr = head->target;
637 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
638 target_to_xtensa(curr));
639 if (ret != ERROR_OK)
640 return ret;
641 }
642 return ERROR_OK;
643 }
644 return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
645 target_to_xtensa(target));
646 }
647
648 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtregfmt)
649 {
650 struct target *target = get_current_target(CMD_CTX);
651 if (target->smp && CMD_ARGC > 0) {
652 struct target_list *head;
653 struct target *curr;
654 foreach_smp_target(head, target->smp_targets) {
655 curr = head->target;
656 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
657 target_to_xtensa(curr));
658 if (ret != ERROR_OK)
659 return ret;
660 }
661 return ERROR_OK;
662 }
663 return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
664 target_to_xtensa(target));
665 }
666
667 COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode)
668 {
669 struct target *target = get_current_target(CMD_CTX);
670 if (target->smp && CMD_ARGC > 0) {
671 struct target_list *head;
672 struct target *curr;
673 foreach_smp_target(head, target->smp_targets) {
674 curr = head->target;
675 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
676 target_to_xtensa(curr));
677 if (ret != ERROR_OK)
678 return ret;
679 }
680 return ERROR_OK;
681 }
682 return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
683 target_to_xtensa(target));
684 }
685
686 COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak)
687 {
688 struct target *target = get_current_target(CMD_CTX);
689 if (target->smp && CMD_ARGC > 0) {
690 struct target_list *head;
691 struct target *curr;
692 foreach_smp_target(head, target->smp_targets) {
693 curr = head->target;
694 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, curr);
695 if (ret != ERROR_OK)
696 return ret;
697 }
698 return ERROR_OK;
699 }
700 return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, target);
701 }
702
703 COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts)
704 {
705 struct target *target = get_current_target(CMD_CTX);
706 if (target->smp && CMD_ARGC > 0) {
707 struct target_list *head;
708 struct target *curr;
709 foreach_smp_target(head, target->smp_targets) {
710 curr = head->target;
711 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
712 target_to_xtensa(curr));
713 if (ret != ERROR_OK)
714 return ret;
715 }
716 return ERROR_OK;
717 }
718 return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
719 target_to_xtensa(target));
720 }
721
722 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable)
723 {
724 struct target *target = get_current_target(CMD_CTX);
725 if (target->smp && CMD_ARGC > 0) {
726 struct target_list *head;
727 struct target *curr;
728 foreach_smp_target(head, target->smp_targets) {
729 curr = head->target;
730 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
731 target_to_xtensa(curr));
732 if (ret != ERROR_OK)
733 return ret;
734 }
735 return ERROR_OK;
736 }
737 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
738 target_to_xtensa(target));
739 }
740
741 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump)
742 {
743 struct target *target = get_current_target(CMD_CTX);
744 if (target->smp) {
745 struct target_list *head;
746 struct target *curr;
747 foreach_smp_target(head, target->smp_targets) {
748 curr = head->target;
749 LOG_TARGET_INFO(curr, ":");
750 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
751 target_to_xtensa(curr));
752 if (ret != ERROR_OK)
753 return ret;
754 }
755 return ERROR_OK;
756 }
757 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
758 target_to_xtensa(target));
759 }
760
761 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart)
762 {
763 struct target *target = get_current_target(CMD_CTX);
764 if (target->smp) {
765 struct target_list *head;
766 struct target *curr;
767 foreach_smp_target(head, target->smp_targets) {
768 curr = head->target;
769 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
770 target_to_xtensa(curr));
771 if (ret != ERROR_OK)
772 return ret;
773 }
774 return ERROR_OK;
775 }
776 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
777 target_to_xtensa(target));
778 }
779
780 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop)
781 {
782 struct target *target = get_current_target(CMD_CTX);
783 if (target->smp) {
784 struct target_list *head;
785 struct target *curr;
786 foreach_smp_target(head, target->smp_targets) {
787 curr = head->target;
788 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
789 target_to_xtensa(curr));
790 if (ret != ERROR_OK)
791 return ret;
792 }
793 return ERROR_OK;
794 }
795 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
796 target_to_xtensa(target));
797 }
798
799 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump)
800 {
801 struct target *target = get_current_target(CMD_CTX);
802 if (target->smp) {
803 struct target_list *head;
804 struct target *curr;
805 int32_t cores_max_id = 0;
806 /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */
807 foreach_smp_target(head, target->smp_targets) {
808 curr = head->target;
809 if (cores_max_id < curr->coreid)
810 cores_max_id = curr->coreid;
811 }
812 if (CMD_ARGC < ((uint32_t)cores_max_id + 1)) {
813 command_print(CMD,
814 "Need %d filenames to dump to as output!",
815 cores_max_id + 1);
816 return ERROR_FAIL;
817 }
818 foreach_smp_target(head, target->smp_targets) {
819 curr = head->target;
820 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
821 target_to_xtensa(curr), CMD_ARGV[curr->coreid]);
822 if (ret != ERROR_OK)
823 return ret;
824 }
825 return ERROR_OK;
826 }
827 return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
828 target_to_xtensa(target), CMD_ARGV[0]);
829 }
830
831 const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = {
832 {
833 .name = "xtdef",
834 .handler = esp_xtensa_smp_cmd_xtdef,
835 .mode = COMMAND_CONFIG,
836 .help = "Configure Xtensa core type",
837 .usage = "<type>",
838 },
839 {
840 .name = "xtopt",
841 .handler = esp_xtensa_smp_cmd_xtopt,
842 .mode = COMMAND_CONFIG,
843 .help = "Configure Xtensa core option",
844 .usage = "<name> <value>",
845 },
846 {
847 .name = "xtmem",
848 .handler = esp_xtensa_smp_cmd_xtmem,
849 .mode = COMMAND_CONFIG,
850 .help = "Configure Xtensa memory/cache option",
851 .usage = "<type> [parameters]",
852 },
853 {
854 .name = "xtmmu",
855 .handler = esp_xtensa_smp_cmd_xtmmu,
856 .mode = COMMAND_CONFIG,
857 .help = "Configure Xtensa MMU option",
858 .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>",
859 },
860 {
861 .name = "xtmpu",
862 .handler = esp_xtensa_smp_cmd_xtmpu,
863 .mode = COMMAND_CONFIG,
864 .help = "Configure Xtensa MPU option",
865 .usage = "<num FG seg> <min seg size> <lockable> <executeonly>",
866 },
867 {
868 .name = "xtreg",
869 .handler = esp_xtensa_smp_cmd_xtreg,
870 .mode = COMMAND_CONFIG,
871 .help = "Configure Xtensa register",
872 .usage = "<regname> <regnum>",
873 },
874 {
875 .name = "xtregs",
876 .handler = esp_xtensa_smp_cmd_xtreg,
877 .mode = COMMAND_CONFIG,
878 .help = "Configure number of Xtensa registers",
879 .usage = "<numregs>",
880 },
881 {
882 .name = "xtregfmt",
883 .handler = esp_xtensa_smp_cmd_xtregfmt,
884 .mode = COMMAND_CONFIG,
885 .help = "Configure format of Xtensa register map",
886 .usage = "<numgregs>",
887 },
888 {
889 .name = "set_permissive",
890 .handler = esp_xtensa_smp_cmd_permissive_mode,
891 .mode = COMMAND_ANY,
892 .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)",
893 .usage = "[0|1]",
894 },
895 {
896 .name = "maskisr",
897 .handler = esp_xtensa_smp_cmd_mask_interrupts,
898 .mode = COMMAND_ANY,
899 .help = "mask Xtensa interrupts at step",
900 .usage = "['on'|'off']",
901 },
902 {
903 .name = "smpbreak",
904 .handler = esp_xtensa_smp_cmd_smpbreak,
905 .mode = COMMAND_ANY,
906 .help = "Set the way the CPU chains OCD breaks",
907 .usage =
908 "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
909 },
910 {
911 .name = "perfmon_enable",
912 .handler = esp_xtensa_smp_cmd_perfmon_enable,
913 .mode = COMMAND_EXEC,
914 .help = "Enable and start performance counter",
915 .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]",
916 },
917 {
918 .name = "perfmon_dump",
919 .handler = esp_xtensa_smp_cmd_perfmon_dump,
920 .mode = COMMAND_EXEC,
921 .help =
922 "Dump performance counter value. If no argument specified, dumps all counters.",
923 .usage = "[counter_id]",
924 },
925 {
926 .name = "tracestart",
927 .handler = esp_xtensa_smp_cmd_tracestart,
928 .mode = COMMAND_EXEC,
929 .help =
930 "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.",
931 .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]",
932 },
933 {
934 .name = "tracestop",
935 .handler = esp_xtensa_smp_cmd_tracestop,
936 .mode = COMMAND_EXEC,
937 .help = "Tracing: Stop current trace as started by the tracestart command",
938 .usage = "",
939 },
940 {
941 .name = "tracedump",
942 .handler = esp_xtensa_smp_cmd_tracedump,
943 .mode = COMMAND_EXEC,
944 .help = "Tracing: Dump trace memory to a files. One file per core.",
945 .usage = "<outfile1> <outfile2>",
946 },
947 COMMAND_REGISTRATION_DONE
948 };
949
950 const struct command_registration esp_xtensa_smp_command_handlers[] = {
951 {
952 .name = "xtensa",
953 .usage = "",
954 .chain = esp_xtensa_smp_xtensa_command_handlers,
955 },
956 COMMAND_REGISTRATION_DONE
957 };

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)