target/espressif: remove author lines from esp32xx and xtensa files
[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 "esp_xtensa_smp.h"
17
18 /*
19 Multiprocessor stuff common:
20
21 The ESP Xtensa chip can have several cores in it, which can run in SMP-mode if an
22 SMP-capable OS is running. The hardware has a few features which makes
23 SMP debugging much easier.
24
25 First of all, there's something called a 'break network', consisting of a
26 BreakIn input and a BreakOut output on each CPU. The idea is that as soon
27 as a CPU goes into debug mode for whatever reason, it'll signal that using
28 its DebugOut pin. This signal is connected to the other CPU's DebugIn
29 input, causing this CPU also to go into debugging mode. To resume execution
30 when using only this break network, we will need to manually resume both
31 CPUs.
32
33 An alternative to this is the XOCDMode output and the RunStall (or DebugStall)
34 input. When these are cross-connected, a CPU that goes into debug mode will
35 halt execution entirely on the other CPU. Execution on the other CPU can be
36 resumed by either the first CPU going out of debug mode, or the second CPU
37 going into debug mode: the stall is temporarily lifted as long as the stalled
38 CPU is in debug mode.
39
40 A third, separate, signal is CrossTrigger. This is connected in the same way
41 as the breakIn/breakOut network, but is for the TRAX (trace memory) feature;
42 it does not affect OCD in any way.
43 */
44
45 /*
46 Multiprocessor stuff:
47
48 The ESP Xtensa chip has several Xtensa cores inside, but represent themself to the OCD
49 as one chip that works in multithreading mode under FreeRTOS OS.
50 The core that initiate the stop condition will be defined as an active cpu.
51 When one core stops, then other core will be stopped automatically by smpbreak.
52 The core that initiates stop condition will be defined as an active core, and
53 registers of this core will be transferred.
54 */
55
56 #define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES 5
57
58 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume);
59
60 static inline struct esp_xtensa_smp_common *target_to_esp_xtensa_smp(struct target *target)
61 {
62 return container_of(target->arch_info, struct esp_xtensa_smp_common, esp_xtensa);
63 }
64
65 int esp_xtensa_smp_assert_reset(struct target *target)
66 {
67 return ERROR_OK;
68 }
69
70 int esp_xtensa_smp_deassert_reset(struct target *target)
71 {
72 LOG_TARGET_DEBUG(target, "begin");
73
74 int ret = xtensa_deassert_reset(target);
75 if (ret != ERROR_OK)
76 return ret;
77 /* in SMP mode when chip was running single-core app the other core can be left un-examined,
78 because examination is done before SOC reset. But after SOC reset it is functional and should be handled.
79 So try to examine un-examined core just after SOC reset */
80 if (target->smp && !target_was_examined(target))
81 ret = xtensa_examine(target);
82 return ret;
83 }
84
85 int esp_xtensa_smp_soft_reset_halt(struct target *target)
86 {
87 int res;
88 struct target_list *head;
89 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
90
91 LOG_TARGET_DEBUG(target, "begin");
92 /* in SMP mode we need to ensure that at first we reset SOC on PRO-CPU
93 and then call xtensa_assert_reset() for all cores */
94 if (target->smp && target->coreid != 0)
95 return ERROR_OK;
96 /* Reset the SoC first */
97 if (esp_xtensa_smp->chip_ops->reset) {
98 res = esp_xtensa_smp->chip_ops->reset(target);
99 if (res != ERROR_OK)
100 return res;
101 }
102 if (!target->smp)
103 return xtensa_assert_reset(target);
104
105 foreach_smp_target(head, target->smp_targets) {
106 res = xtensa_assert_reset(head->target);
107 if (res != ERROR_OK)
108 return res;
109 }
110 return ERROR_OK;
111 }
112
113 static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid)
114 {
115 struct target_list *head;
116 struct target *curr;
117
118 foreach_smp_target(head, target->smp_targets) {
119 curr = head->target;
120 if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
121 return curr;
122 }
123
124 return target;
125 }
126
127 int esp_xtensa_smp_poll(struct target *target)
128 {
129 enum target_state old_state = target->state;
130 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
131 struct target_list *head;
132 struct target *curr;
133 bool other_core_resume_req = false;
134
135 if (target->state == TARGET_HALTED && target->smp && target->gdb_service && !target->gdb_service->target) {
136 target->gdb_service->target = get_halted_esp_xtensa_smp(target, target->gdb_service->core[1]);
137 LOG_INFO("Switch GDB target to '%s'", target_name(target->gdb_service->target));
138 if (esp_xtensa_smp->chip_ops->on_halt)
139 esp_xtensa_smp->chip_ops->on_halt(target);
140 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
141 return ERROR_OK;
142 }
143
144 int ret = esp_xtensa_poll(target);
145 if (ret != ERROR_OK)
146 return ret;
147
148 if (target->smp) {
149 if (target->state == TARGET_RESET) {
150 esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
151 } else if (esp_xtensa_smp->examine_other_cores > 0 &&
152 (target->state == TARGET_RUNNING || target->state == TARGET_HALTED)) {
153 LOG_TARGET_DEBUG(target, "Check for unexamined cores after reset");
154 bool all_examined = true;
155 foreach_smp_target(head, target->smp_targets) {
156 curr = head->target;
157 if (curr == target)
158 continue;
159 if (!target_was_examined(curr)) {
160 if (target_examine_one(curr) != ERROR_OK) {
161 LOG_DEBUG("Failed to examine!");
162 all_examined = false;
163 }
164 }
165 }
166 if (all_examined)
167 esp_xtensa_smp->examine_other_cores = 0;
168 else
169 esp_xtensa_smp->examine_other_cores--;
170 }
171 }
172
173 if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
174 if (target->smp) {
175 ret = esp_xtensa_smp_update_halt_gdb(target, &other_core_resume_req);
176 if (ret != ERROR_OK)
177 return ret;
178 }
179 /* Call any event callbacks that are applicable */
180 if (old_state == TARGET_DEBUG_RUNNING) {
181 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
182 } else {
183 /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */
184 if (target->smp && other_core_resume_req) {
185 /* Resume xtensa_resume will handle BREAK instruction. */
186 ret = target_resume(target, 1, 0, 1, 0);
187 if (ret != ERROR_OK) {
188 LOG_ERROR("Failed to resume target");
189 return ret;
190 }
191 return ERROR_OK;
192 }
193 if (esp_xtensa_smp->chip_ops->on_halt)
194 esp_xtensa_smp->chip_ops->on_halt(target);
195 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
196 }
197 }
198
199 return ERROR_OK;
200 }
201
202 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume)
203 {
204 struct esp_xtensa_smp_common *esp_xtensa_smp;
205 struct target *gdb_target = NULL;
206 struct target_list *head;
207 struct target *curr;
208 int ret = ERROR_OK;
209
210 *need_resume = false;
211
212 if (target->gdb_service && target->gdb_service->target)
213 LOG_DEBUG("GDB target '%s'", target_name(target->gdb_service->target));
214
215 if (target->gdb_service && target->gdb_service->core[0] == -1) {
216 target->gdb_service->target = target;
217 target->gdb_service->core[0] = target->coreid;
218 LOG_INFO("Set GDB target to '%s'", target_name(target));
219 }
220
221 if (target->gdb_service)
222 gdb_target = target->gdb_service->target;
223
224 /* due to smpbreak config other cores can also go to HALTED state */
225 foreach_smp_target(head, target->smp_targets) {
226 curr = head->target;
227 LOG_DEBUG("Check target '%s'", target_name(curr));
228 /* skip calling context */
229 if (curr == target)
230 continue;
231 if (!target_was_examined(curr)) {
232 curr->state = TARGET_HALTED;
233 continue;
234 }
235 /* skip targets that were already halted */
236 if (curr->state == TARGET_HALTED)
237 continue;
238 /* Skip gdb_target; it alerts GDB so has to be polled as last one */
239 if (curr == gdb_target)
240 continue;
241 LOG_DEBUG("Poll target '%s'", target_name(curr));
242
243 esp_xtensa_smp = target_to_esp_xtensa_smp(curr);
244 /* avoid auto-resume after syscall, it will be done later */
245 esp_xtensa_smp->other_core_does_resume = true;
246 /* avoid recursion in esp_xtensa_smp_poll() */
247 curr->smp = 0;
248 if (esp_xtensa_smp->chip_ops->poll)
249 ret = esp_xtensa_smp->chip_ops->poll(curr);
250 else
251 ret = esp_xtensa_smp_poll(curr);
252 curr->smp = 1;
253 if (ret != ERROR_OK)
254 return ret;
255 esp_xtensa_smp->other_core_does_resume = false;
256 }
257
258 /* after all targets were updated, poll the gdb serving target */
259 if (gdb_target && gdb_target != target) {
260 esp_xtensa_smp = target_to_esp_xtensa_smp(gdb_target);
261 if (esp_xtensa_smp->chip_ops->poll)
262 ret = esp_xtensa_smp->chip_ops->poll(gdb_target);
263 else
264 ret = esp_xtensa_smp_poll(gdb_target);
265 }
266
267 LOG_DEBUG("exit");
268
269 return ret;
270 }
271
272 static inline int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break)
273 {
274 int res = xtensa_smpbreak_get(target, smp_break);
275 if (res != ERROR_OK)
276 return res;
277 return xtensa_smpbreak_set(target, 0);
278 }
279
280 static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break)
281 {
282 return xtensa_smpbreak_set(target, smp_break);
283 }
284
285 static int esp_xtensa_smp_resume_cores(struct target *target,
286 int handle_breakpoints,
287 int debug_execution)
288 {
289 struct target_list *head;
290 struct target *curr;
291
292 LOG_TARGET_DEBUG(target, "begin");
293
294 foreach_smp_target(head, target->smp_targets) {
295 curr = head->target;
296 /* in single-core mode disabled core cannot be examined, but need to be resumed too*/
297 if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) {
298 /* resume current address, not in SMP mode */
299 curr->smp = 0;
300 int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution);
301 curr->smp = 1;
302 if (res != ERROR_OK)
303 return res;
304 }
305 }
306 return ERROR_OK;
307 }
308
309 int esp_xtensa_smp_resume(struct target *target,
310 int current,
311 target_addr_t address,
312 int handle_breakpoints,
313 int debug_execution)
314 {
315 int res;
316 uint32_t smp_break;
317
318 xtensa_smpbreak_get(target, &smp_break);
319 LOG_TARGET_DEBUG(target, "smp_break=0x%" PRIx32, smp_break);
320
321 /* dummy resume for smp toggle in order to reduce gdb impact */
322 if ((target->smp) && (target->gdb_service) && (target->gdb_service->core[1] != -1)) {
323 /* simulate a start and halt of target */
324 target->gdb_service->target = NULL;
325 target->gdb_service->core[0] = target->gdb_service->core[1];
326 /* fake resume at next poll we play the target core[1], see poll*/
327 LOG_TARGET_DEBUG(target, "Fake resume");
328 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
329 return ERROR_OK;
330 }
331
332 /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for
333 * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */
334 res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
335 if (res != ERROR_OK)
336 return res;
337 res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution);
338 /* restore configured BreakInOut signals config */
339 int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
340 if (ret != ERROR_OK)
341 return ret;
342 if (res != ERROR_OK) {
343 LOG_TARGET_ERROR(target, "Failed to prepare for resume!");
344 return res;
345 }
346
347 if (target->smp) {
348 if (target->gdb_service)
349 target->gdb_service->core[0] = -1;
350 res = esp_xtensa_smp_resume_cores(target, handle_breakpoints, debug_execution);
351 if (res != ERROR_OK)
352 return res;
353 }
354
355 res = xtensa_do_resume(target);
356 if (res != ERROR_OK) {
357 LOG_TARGET_ERROR(target, "Failed to resume!");
358 return res;
359 }
360
361 target->debug_reason = DBG_REASON_NOTHALTED;
362 if (!debug_execution)
363 target->state = TARGET_RUNNING;
364 else
365 target->state = TARGET_DEBUG_RUNNING;
366
367 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
368 return ERROR_OK;
369 }
370
371 int esp_xtensa_smp_step(struct target *target,
372 int current,
373 target_addr_t address,
374 int handle_breakpoints)
375 {
376 int res;
377 uint32_t smp_break = 0;
378 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
379
380 if (target->smp) {
381 res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
382 if (res != ERROR_OK)
383 return res;
384 }
385 res = xtensa_step(target, current, address, handle_breakpoints);
386
387 if (res == ERROR_OK) {
388 if (esp_xtensa_smp->chip_ops->on_halt)
389 esp_xtensa_smp->chip_ops->on_halt(target);
390 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
391 }
392
393 if (target->smp) {
394 int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
395 if (ret != ERROR_OK)
396 return ret;
397 }
398
399 return res;
400 }
401
402 int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint)
403 {
404 int res = xtensa_watchpoint_add(target, watchpoint);
405 if (res != ERROR_OK)
406 return res;
407
408 if (!target->smp)
409 return ERROR_OK;
410
411 struct target_list *head;
412 foreach_smp_target(head, target->smp_targets) {
413 struct target *curr = head->target;
414 if (curr == target || !target_was_examined(curr))
415 continue;
416 /* Need to use high level API here because every target for core contains list of watchpoints.
417 * GDB works with active core only, so we need to duplicate every watchpoint on other cores,
418 * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */
419 curr->smp = 0;
420 res = watchpoint_add(curr, watchpoint->address, watchpoint->length,
421 watchpoint->rw, watchpoint->value, watchpoint->mask);
422 curr->smp = 1;
423 if (res != ERROR_OK)
424 return res;
425 }
426 return ERROR_OK;
427 }
428
429 int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint)
430 {
431 int res = xtensa_watchpoint_remove(target, watchpoint);
432 if (res != ERROR_OK)
433 return res;
434
435 if (!target->smp)
436 return ERROR_OK;
437
438 struct target_list *head;
439 foreach_smp_target(head, target->smp_targets) {
440 struct target *curr = head->target;
441 if (curr == target)
442 continue;
443 /* see big comment in esp_xtensa_smp_watchpoint_add() */
444 curr->smp = 0;
445 watchpoint_remove(curr, watchpoint->address);
446 curr->smp = 1;
447 }
448 return ERROR_OK;
449 }
450
451 int esp_xtensa_smp_init_arch_info(struct target *target,
452 struct esp_xtensa_smp_common *esp_xtensa_smp,
453 const struct xtensa_config *xtensa_cfg,
454 struct xtensa_debug_module_config *dm_cfg,
455 const struct esp_xtensa_smp_chip_ops *chip_ops)
456 {
457 int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, xtensa_cfg, dm_cfg);
458 if (ret != ERROR_OK)
459 return ret;
460 esp_xtensa_smp->chip_ops = chip_ops;
461 esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
462 return ERROR_OK;
463 }
464
465 int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target)
466 {
467 return esp_xtensa_target_init(cmd_ctx, target);
468 }
469
470 COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode)
471 {
472 struct target *target = get_current_target(CMD_CTX);
473 if (target->smp && CMD_ARGC > 0) {
474 struct target_list *head;
475 struct target *curr;
476 foreach_smp_target(head, target->smp_targets) {
477 curr = head->target;
478 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
479 target_to_xtensa(curr));
480 if (ret != ERROR_OK)
481 return ret;
482 }
483 return ERROR_OK;
484 }
485 return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
486 target_to_xtensa(target));
487 }
488
489 COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak)
490 {
491 struct target *target = get_current_target(CMD_CTX);
492 if (target->smp && CMD_ARGC > 0) {
493 struct target_list *head;
494 struct target *curr;
495 foreach_smp_target(head, target->smp_targets) {
496 curr = head->target;
497 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, curr);
498 if (ret != ERROR_OK)
499 return ret;
500 }
501 return ERROR_OK;
502 }
503 return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, target);
504 }
505
506 COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts)
507 {
508 struct target *target = get_current_target(CMD_CTX);
509 if (target->smp && CMD_ARGC > 0) {
510 struct target_list *head;
511 struct target *curr;
512 foreach_smp_target(head, target->smp_targets) {
513 curr = head->target;
514 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
515 target_to_xtensa(curr));
516 if (ret != ERROR_OK)
517 return ret;
518 }
519 return ERROR_OK;
520 }
521 return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
522 target_to_xtensa(target));
523 }
524
525 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable)
526 {
527 struct target *target = get_current_target(CMD_CTX);
528 if (target->smp && CMD_ARGC > 0) {
529 struct target_list *head;
530 struct target *curr;
531 foreach_smp_target(head, target->smp_targets) {
532 curr = head->target;
533 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
534 target_to_xtensa(curr));
535 if (ret != ERROR_OK)
536 return ret;
537 }
538 return ERROR_OK;
539 }
540 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
541 target_to_xtensa(target));
542 }
543
544 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump)
545 {
546 struct target *target = get_current_target(CMD_CTX);
547 if (target->smp) {
548 struct target_list *head;
549 struct target *curr;
550 foreach_smp_target(head, target->smp_targets) {
551 curr = head->target;
552 LOG_INFO("CPU%d:", curr->coreid);
553 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
554 target_to_xtensa(curr));
555 if (ret != ERROR_OK)
556 return ret;
557 }
558 return ERROR_OK;
559 }
560 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
561 target_to_xtensa(target));
562 }
563
564 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart)
565 {
566 struct target *target = get_current_target(CMD_CTX);
567 if (target->smp) {
568 struct target_list *head;
569 struct target *curr;
570 foreach_smp_target(head, target->smp_targets) {
571 curr = head->target;
572 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
573 target_to_xtensa(curr));
574 if (ret != ERROR_OK)
575 return ret;
576 }
577 return ERROR_OK;
578 }
579 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
580 target_to_xtensa(target));
581 }
582
583 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop)
584 {
585 struct target *target = get_current_target(CMD_CTX);
586 if (target->smp) {
587 struct target_list *head;
588 struct target *curr;
589 foreach_smp_target(head, target->smp_targets) {
590 curr = head->target;
591 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
592 target_to_xtensa(curr));
593 if (ret != ERROR_OK)
594 return ret;
595 }
596 return ERROR_OK;
597 }
598 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
599 target_to_xtensa(target));
600 }
601
602 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump)
603 {
604 struct target *target = get_current_target(CMD_CTX);
605 if (target->smp) {
606 struct target_list *head;
607 struct target *curr;
608 int32_t cores_max_id = 0;
609 /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */
610 foreach_smp_target(head, target->smp_targets) {
611 curr = head->target;
612 if (cores_max_id < curr->coreid)
613 cores_max_id = curr->coreid;
614 }
615 if (CMD_ARGC < ((uint32_t)cores_max_id + 1)) {
616 command_print(CMD,
617 "Need %d filenames to dump to as output!",
618 cores_max_id + 1);
619 return ERROR_FAIL;
620 }
621 foreach_smp_target(head, target->smp_targets) {
622 curr = head->target;
623 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
624 target_to_xtensa(curr), CMD_ARGV[curr->coreid]);
625 if (ret != ERROR_OK)
626 return ret;
627 }
628 return ERROR_OK;
629 }
630 return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
631 target_to_xtensa(target), CMD_ARGV[0]);
632 }
633
634 const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = {
635 {
636 .name = "set_permissive",
637 .handler = esp_xtensa_smp_cmd_permissive_mode,
638 .mode = COMMAND_ANY,
639 .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)",
640 .usage = "[0|1]",
641 },
642 {
643 .name = "maskisr",
644 .handler = esp_xtensa_smp_cmd_mask_interrupts,
645 .mode = COMMAND_ANY,
646 .help = "mask Xtensa interrupts at step",
647 .usage = "['on'|'off']",
648 },
649 {
650 .name = "smpbreak",
651 .handler = esp_xtensa_smp_cmd_smpbreak,
652 .mode = COMMAND_ANY,
653 .help = "Set the way the CPU chains OCD breaks",
654 .usage =
655 "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
656 },
657 {
658 .name = "perfmon_enable",
659 .handler = esp_xtensa_smp_cmd_perfmon_enable,
660 .mode = COMMAND_EXEC,
661 .help = "Enable and start performance counter",
662 .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]",
663 },
664 {
665 .name = "perfmon_dump",
666 .handler = esp_xtensa_smp_cmd_perfmon_dump,
667 .mode = COMMAND_EXEC,
668 .help =
669 "Dump performance counter value. If no argument specified, dumps all counters.",
670 .usage = "[counter_id]",
671 },
672 {
673 .name = "tracestart",
674 .handler = esp_xtensa_smp_cmd_tracestart,
675 .mode = COMMAND_EXEC,
676 .help =
677 "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.",
678 .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]",
679 },
680 {
681 .name = "tracestop",
682 .handler = esp_xtensa_smp_cmd_tracestop,
683 .mode = COMMAND_EXEC,
684 .help = "Tracing: Stop current trace as started by the tracestart command",
685 .usage = "",
686 },
687 {
688 .name = "tracedump",
689 .handler = esp_xtensa_smp_cmd_tracedump,
690 .mode = COMMAND_EXEC,
691 .help = "Tracing: Dump trace memory to a files. One file per core.",
692 .usage = "<outfile1> <outfile2>",
693 },
694 COMMAND_REGISTRATION_DONE
695 };
696
697 const struct command_registration esp_xtensa_smp_command_handlers[] = {
698 {
699 .name = "xtensa",
700 .usage = "",
701 .chain = esp_xtensa_smp_xtensa_command_handlers,
702 },
703 COMMAND_REGISTRATION_DONE
704 };

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)