1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * ESP Xtensa SMP target API for OpenOCD *
5 * Copyright (C) 2020 Espressif Systems Ltd. Co *
6 ***************************************************************************/
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 #include "esp_algorithm.h"
22 Multiprocessor stuff common:
24 The ESP Xtensa chip can have several cores in it, which can run in SMP-mode if an
25 SMP-capable OS is running. The hardware has a few features which makes
26 SMP debugging much easier.
28 First of all, there's something called a 'break network', consisting of a
29 BreakIn input and a BreakOut output on each CPU. The idea is that as soon
30 as a CPU goes into debug mode for whatever reason, it'll signal that using
31 its DebugOut pin. This signal is connected to the other CPU's DebugIn
32 input, causing this CPU also to go into debugging mode. To resume execution
33 when using only this break network, we will need to manually resume both
36 An alternative to this is the XOCDMode output and the RunStall (or DebugStall)
37 input. When these are cross-connected, a CPU that goes into debug mode will
38 halt execution entirely on the other CPU. Execution on the other CPU can be
39 resumed by either the first CPU going out of debug mode, or the second CPU
40 going into debug mode: the stall is temporarily lifted as long as the stalled
43 A third, separate, signal is CrossTrigger. This is connected in the same way
44 as the breakIn/breakOut network, but is for the TRAX (trace memory) feature;
45 it does not affect OCD in any way.
51 The ESP Xtensa chip has several Xtensa cores inside, but represent themself to the OCD
52 as one chip that works in multithreading mode under FreeRTOS OS.
53 The core that initiate the stop condition will be defined as an active cpu.
54 When one core stops, then other core will be stopped automatically by smpbreak.
55 The core that initiates stop condition will be defined as an active core, and
56 registers of this core will be transferred.
59 #define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES 5
61 static int esp_xtensa_smp_update_halt_gdb(struct target
*target
, bool *need_resume
);
63 static inline struct esp_xtensa_smp_common
*target_to_esp_xtensa_smp(struct target
*target
)
65 return container_of(target
->arch_info
, struct esp_xtensa_smp_common
, esp_xtensa
);
68 int esp_xtensa_smp_assert_reset(struct target
*target
)
73 int esp_xtensa_smp_deassert_reset(struct target
*target
)
75 LOG_TARGET_DEBUG(target
, "begin");
77 int ret
= xtensa_deassert_reset(target
);
80 /* in SMP mode when chip was running single-core app the other core can be left un-examined,
81 because examination is done before SOC reset. But after SOC reset it is functional and should be handled.
82 So try to examine un-examined core just after SOC reset */
83 if (target
->smp
&& !target_was_examined(target
))
84 ret
= xtensa_examine(target
);
88 int esp_xtensa_smp_soft_reset_halt(struct target
*target
)
91 struct target_list
*head
;
92 struct esp_xtensa_smp_common
*esp_xtensa_smp
= target_to_esp_xtensa_smp(target
);
94 LOG_TARGET_DEBUG(target
, "begin");
95 /* in SMP mode we need to ensure that at first we reset SOC on PRO-CPU
96 and then call xtensa_assert_reset() for all cores */
97 if (target
->smp
&& target
->coreid
!= 0)
99 /* Reset the SoC first */
100 if (esp_xtensa_smp
->chip_ops
->reset
) {
101 res
= esp_xtensa_smp
->chip_ops
->reset(target
);
106 return xtensa_assert_reset(target
);
108 foreach_smp_target(head
, target
->smp_targets
) {
109 res
= xtensa_assert_reset(head
->target
);
116 int esp_xtensa_smp_on_halt(struct target
*target
)
118 struct target_list
*head
;
121 return esp_xtensa_on_halt(target
);
123 foreach_smp_target(head
, target
->smp_targets
) {
124 int res
= esp_xtensa_on_halt(head
->target
);
131 static struct target
*get_halted_esp_xtensa_smp(struct target
*target
, int32_t coreid
)
133 struct target_list
*head
;
136 foreach_smp_target(head
, target
->smp_targets
) {
138 if ((curr
->coreid
== coreid
) && (curr
->state
== TARGET_HALTED
))
145 int esp_xtensa_smp_poll(struct target
*target
)
147 enum target_state old_state
= target
->state
;
148 struct esp_xtensa_smp_common
*esp_xtensa_smp
= target_to_esp_xtensa_smp(target
);
149 struct esp_xtensa_common
*esp_xtensa
= target_to_esp_xtensa(target
);
150 uint32_t old_dbg_stubs_base
= esp_xtensa
->esp
.dbg_stubs
.base
;
151 struct target_list
*head
;
153 bool other_core_resume_req
= false;
155 if (target
->state
== TARGET_HALTED
&& target
->smp
&& target
->gdb_service
&& !target
->gdb_service
->target
) {
156 target
->gdb_service
->target
= get_halted_esp_xtensa_smp(target
, target
->gdb_service
->core
[1]);
157 LOG_INFO("Switch GDB target to '%s'", target_name(target
->gdb_service
->target
));
158 if (esp_xtensa_smp
->chip_ops
->on_halt
)
159 esp_xtensa_smp
->chip_ops
->on_halt(target
);
160 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
164 int ret
= esp_xtensa_poll(target
);
168 if (esp_xtensa
->esp
.dbg_stubs
.base
&& old_dbg_stubs_base
!= esp_xtensa
->esp
.dbg_stubs
.base
) {
169 /* debug stubs base is set only in PRO-CPU TRAX register, so sync this info */
170 foreach_smp_target(head
, target
->smp_targets
) {
174 target_to_esp_xtensa(curr
)->esp
.dbg_stubs
.base
= esp_xtensa
->esp
.dbg_stubs
.base
;
179 if (target
->state
== TARGET_RESET
) {
180 esp_xtensa_smp
->examine_other_cores
= ESP_XTENSA_SMP_EXAMINE_OTHER_CORES
;
181 } else if (esp_xtensa_smp
->examine_other_cores
> 0 &&
182 (target
->state
== TARGET_RUNNING
|| target
->state
== TARGET_HALTED
)) {
183 LOG_TARGET_DEBUG(target
, "Check for unexamined cores after reset");
184 bool all_examined
= true;
185 foreach_smp_target(head
, target
->smp_targets
) {
189 if (!target_was_examined(curr
)) {
190 if (target_examine_one(curr
) != ERROR_OK
) {
191 LOG_DEBUG("Failed to examine!");
192 all_examined
= false;
197 esp_xtensa_smp
->examine_other_cores
= 0;
199 esp_xtensa_smp
->examine_other_cores
--;
203 if (old_state
!= TARGET_HALTED
&& target
->state
== TARGET_HALTED
) {
205 ret
= esp_xtensa_smp_update_halt_gdb(target
, &other_core_resume_req
);
209 /* Call any event callbacks that are applicable */
210 if (old_state
== TARGET_DEBUG_RUNNING
) {
211 target_call_event_callbacks(target
, TARGET_EVENT_DEBUG_HALTED
);
213 if (esp_xtensa_semihosting(target
, &ret
) == SEMIHOSTING_HANDLED
) {
214 if (ret
== ERROR_OK
&& esp_xtensa
->semihost
.need_resume
&&
215 !esp_xtensa_smp
->other_core_does_resume
) {
216 esp_xtensa
->semihost
.need_resume
= false;
217 /* Resume xtensa_resume will handle BREAK instruction. */
218 ret
= target_resume(target
, 1, 0, 1, 0);
219 if (ret
!= ERROR_OK
) {
220 LOG_ERROR("Failed to resume target");
226 /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */
227 if (target
->smp
&& other_core_resume_req
) {
228 /* Resume xtensa_resume will handle BREAK instruction. */
229 ret
= target_resume(target
, 1, 0, 1, 0);
230 if (ret
!= ERROR_OK
) {
231 LOG_ERROR("Failed to resume target");
236 if (esp_xtensa_smp
->chip_ops
->on_halt
)
237 esp_xtensa_smp
->chip_ops
->on_halt(target
);
238 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
245 static int esp_xtensa_smp_update_halt_gdb(struct target
*target
, bool *need_resume
)
247 struct esp_xtensa_smp_common
*esp_xtensa_smp
;
248 struct target
*gdb_target
= NULL
;
249 struct target_list
*head
;
253 *need_resume
= false;
255 if (target
->gdb_service
&& target
->gdb_service
->target
)
256 LOG_DEBUG("GDB target '%s'", target_name(target
->gdb_service
->target
));
258 if (target
->gdb_service
&& target
->gdb_service
->core
[0] == -1) {
259 target
->gdb_service
->target
= target
;
260 target
->gdb_service
->core
[0] = target
->coreid
;
261 LOG_INFO("Set GDB target to '%s'", target_name(target
));
264 if (target
->gdb_service
)
265 gdb_target
= target
->gdb_service
->target
;
267 /* due to smpbreak config other cores can also go to HALTED state */
268 foreach_smp_target(head
, target
->smp_targets
) {
270 LOG_DEBUG("Check target '%s'", target_name(curr
));
271 /* skip calling context */
274 if (!target_was_examined(curr
)) {
275 curr
->state
= TARGET_HALTED
;
278 /* skip targets that were already halted */
279 if (curr
->state
== TARGET_HALTED
)
281 /* Skip gdb_target; it alerts GDB so has to be polled as last one */
282 if (curr
== gdb_target
)
284 LOG_DEBUG("Poll target '%s'", target_name(curr
));
286 esp_xtensa_smp
= target_to_esp_xtensa_smp(curr
);
287 /* avoid auto-resume after syscall, it will be done later */
288 esp_xtensa_smp
->other_core_does_resume
= true;
289 /* avoid recursion in esp_xtensa_smp_poll() */
291 if (esp_xtensa_smp
->chip_ops
->poll
)
292 ret
= esp_xtensa_smp
->chip_ops
->poll(curr
);
294 ret
= esp_xtensa_smp_poll(curr
);
298 esp_xtensa_smp
->other_core_does_resume
= false;
299 struct esp_xtensa_common
*curr_esp_xtensa
= target_to_esp_xtensa(curr
);
300 if (curr_esp_xtensa
->semihost
.need_resume
) {
301 curr_esp_xtensa
->semihost
.need_resume
= false;
306 /* after all targets were updated, poll the gdb serving target */
307 if (gdb_target
&& gdb_target
!= target
) {
308 esp_xtensa_smp
= target_to_esp_xtensa_smp(gdb_target
);
309 if (esp_xtensa_smp
->chip_ops
->poll
)
310 ret
= esp_xtensa_smp
->chip_ops
->poll(gdb_target
);
312 ret
= esp_xtensa_smp_poll(gdb_target
);
320 static inline int esp_xtensa_smp_smpbreak_disable(struct target
*target
, uint32_t *smp_break
)
322 int res
= xtensa_smpbreak_get(target
, smp_break
);
325 return xtensa_smpbreak_set(target
, 0);
328 static inline int esp_xtensa_smp_smpbreak_restore(struct target
*target
, uint32_t smp_break
)
330 return xtensa_smpbreak_set(target
, smp_break
);
333 static int esp_xtensa_smp_resume_cores(struct target
*target
,
334 int handle_breakpoints
,
337 struct target_list
*head
;
340 LOG_TARGET_DEBUG(target
, "begin");
342 foreach_smp_target(head
, target
->smp_targets
) {
344 /* in single-core mode disabled core cannot be examined, but need to be resumed too*/
345 if ((curr
!= target
) && (curr
->state
!= TARGET_RUNNING
) && target_was_examined(curr
)) {
346 /* resume current address, not in SMP mode */
348 int res
= esp_xtensa_smp_resume(curr
, 1, 0, handle_breakpoints
, debug_execution
);
357 int esp_xtensa_smp_resume(struct target
*target
,
359 target_addr_t address
,
360 int handle_breakpoints
,
366 xtensa_smpbreak_get(target
, &smp_break
);
367 LOG_TARGET_DEBUG(target
, "smp_break=0x%" PRIx32
, smp_break
);
369 /* dummy resume for smp toggle in order to reduce gdb impact */
370 if ((target
->smp
) && (target
->gdb_service
) && (target
->gdb_service
->core
[1] != -1)) {
371 /* simulate a start and halt of target */
372 target
->gdb_service
->target
= NULL
;
373 target
->gdb_service
->core
[0] = target
->gdb_service
->core
[1];
374 /* fake resume at next poll we play the target core[1], see poll*/
375 LOG_TARGET_DEBUG(target
, "Fake resume");
376 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
380 /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for
381 * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */
382 res
= esp_xtensa_smp_smpbreak_disable(target
, &smp_break
);
385 res
= xtensa_prepare_resume(target
, current
, address
, handle_breakpoints
, debug_execution
);
386 /* restore configured BreakInOut signals config */
387 int ret
= esp_xtensa_smp_smpbreak_restore(target
, smp_break
);
390 if (res
!= ERROR_OK
) {
391 LOG_TARGET_ERROR(target
, "Failed to prepare for resume!");
396 if (target
->gdb_service
)
397 target
->gdb_service
->core
[0] = -1;
398 res
= esp_xtensa_smp_resume_cores(target
, handle_breakpoints
, debug_execution
);
403 res
= xtensa_do_resume(target
);
404 if (res
!= ERROR_OK
) {
405 LOG_TARGET_ERROR(target
, "Failed to resume!");
409 target
->debug_reason
= DBG_REASON_NOTHALTED
;
410 if (!debug_execution
)
411 target
->state
= TARGET_RUNNING
;
413 target
->state
= TARGET_DEBUG_RUNNING
;
415 target_call_event_callbacks(target
, TARGET_EVENT_RESUMED
);
419 int esp_xtensa_smp_step(struct target
*target
,
421 target_addr_t address
,
422 int handle_breakpoints
)
425 uint32_t smp_break
= 0;
426 struct esp_xtensa_smp_common
*esp_xtensa_smp
= target_to_esp_xtensa_smp(target
);
429 res
= esp_xtensa_smp_smpbreak_disable(target
, &smp_break
);
433 res
= xtensa_step(target
, current
, address
, handle_breakpoints
);
435 if (res
== ERROR_OK
) {
436 if (esp_xtensa_smp
->chip_ops
->on_halt
)
437 esp_xtensa_smp
->chip_ops
->on_halt(target
);
438 target_call_event_callbacks(target
, TARGET_EVENT_HALTED
);
442 int ret
= esp_xtensa_smp_smpbreak_restore(target
, smp_break
);
450 int esp_xtensa_smp_watchpoint_add(struct target
*target
, struct watchpoint
*watchpoint
)
452 int res
= xtensa_watchpoint_add(target
, watchpoint
);
459 struct target_list
*head
;
460 foreach_smp_target(head
, target
->smp_targets
) {
461 struct target
*curr
= head
->target
;
462 if (curr
== target
|| !target_was_examined(curr
))
464 /* Need to use high level API here because every target for core contains list of watchpoints.
465 * GDB works with active core only, so we need to duplicate every watchpoint on other cores,
466 * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */
468 res
= watchpoint_add(curr
, watchpoint
->address
, watchpoint
->length
,
469 watchpoint
->rw
, watchpoint
->value
, watchpoint
->mask
);
477 int esp_xtensa_smp_watchpoint_remove(struct target
*target
, struct watchpoint
*watchpoint
)
479 int res
= xtensa_watchpoint_remove(target
, watchpoint
);
486 struct target_list
*head
;
487 foreach_smp_target(head
, target
->smp_targets
) {
488 struct target
*curr
= head
->target
;
491 /* see big comment in esp_xtensa_smp_watchpoint_add() */
493 watchpoint_remove(curr
, watchpoint
->address
);
499 int esp_xtensa_smp_run_func_image(struct target
*target
, struct esp_algorithm_run_data
*run
, uint32_t num_args
, ...)
501 struct target
*run_target
= target
;
502 struct target_list
*head
;
504 uint32_t smp_break
= 0;
508 /* find first HALTED and examined core */
509 foreach_smp_target(head
, target
->smp_targets
) {
510 run_target
= head
->target
;
511 if (target_was_examined(run_target
) && run_target
->state
== TARGET_HALTED
)
515 LOG_ERROR("Failed to find HALTED core!");
519 res
= esp_xtensa_smp_smpbreak_disable(run_target
, &smp_break
);
524 va_start(ap
, num_args
);
525 int algo_res
= esp_algorithm_run_func_image_va(run_target
, run
, num_args
, ap
);
529 res
= esp_xtensa_smp_smpbreak_restore(run_target
, smp_break
);
536 int esp_xtensa_smp_run_onboard_func(struct target
*target
,
537 struct esp_algorithm_run_data
*run
,
542 struct target
*run_target
= target
;
543 struct target_list
*head
;
545 uint32_t smp_break
= 0;
549 /* find first HALTED and examined core */
550 foreach_smp_target(head
, target
->smp_targets
) {
551 run_target
= head
->target
;
552 if (target_was_examined(run_target
) && run_target
->state
== TARGET_HALTED
)
556 LOG_ERROR("Failed to find HALTED core!");
559 res
= esp_xtensa_smp_smpbreak_disable(run_target
, &smp_break
);
564 va_start(ap
, num_args
);
565 int algo_res
= esp_algorithm_run_onboard_func_va(run_target
, run
, func_addr
, num_args
, ap
);
569 res
= esp_xtensa_smp_smpbreak_restore(run_target
, smp_break
);
576 int esp_xtensa_smp_init_arch_info(struct target
*target
,
577 struct esp_xtensa_smp_common
*esp_xtensa_smp
,
578 struct xtensa_debug_module_config
*dm_cfg
,
579 const struct esp_xtensa_smp_chip_ops
*chip_ops
,
580 const struct esp_semihost_ops
*semihost_ops
)
582 int ret
= esp_xtensa_init_arch_info(target
, &esp_xtensa_smp
->esp_xtensa
, dm_cfg
, semihost_ops
);
585 esp_xtensa_smp
->chip_ops
= chip_ops
;
586 esp_xtensa_smp
->examine_other_cores
= ESP_XTENSA_SMP_EXAMINE_OTHER_CORES
;
590 int esp_xtensa_smp_target_init(struct command_context
*cmd_ctx
, struct target
*target
)
592 int ret
= esp_xtensa_target_init(cmd_ctx
, target
);
597 struct target_list
*head
;
598 foreach_smp_target(head
, target
->smp_targets
) {
599 struct target
*curr
= head
->target
;
600 ret
= esp_xtensa_semihosting_init(curr
);
605 ret
= esp_xtensa_semihosting_init(target
);
612 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef
)
614 struct target
*target
= get_current_target(CMD_CTX
);
615 if (target
->smp
&& CMD_ARGC
> 0) {
616 struct target_list
*head
;
618 foreach_smp_target(head
, target
->smp_targets
) {
620 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do
,
621 target_to_xtensa(curr
));
627 return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do
,
628 target_to_xtensa(target
));
631 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtopt
)
633 struct target
*target
= get_current_target(CMD_CTX
);
634 if (target
->smp
&& CMD_ARGC
> 0) {
635 struct target_list
*head
;
637 foreach_smp_target(head
, target
->smp_targets
) {
639 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do
,
640 target_to_xtensa(curr
));
646 return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do
,
647 target_to_xtensa(target
));
650 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmem
)
652 struct target
*target
= get_current_target(CMD_CTX
);
653 if (target
->smp
&& CMD_ARGC
> 0) {
654 struct target_list
*head
;
656 foreach_smp_target(head
, target
->smp_targets
) {
658 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do
,
659 target_to_xtensa(curr
));
665 return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do
,
666 target_to_xtensa(target
));
669 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmpu
)
671 struct target
*target
= get_current_target(CMD_CTX
);
672 if (target
->smp
&& CMD_ARGC
> 0) {
673 struct target_list
*head
;
675 foreach_smp_target(head
, target
->smp_targets
) {
677 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do
,
678 target_to_xtensa(curr
));
684 return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do
,
685 target_to_xtensa(target
));
688 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmmu
)
690 struct target
*target
= get_current_target(CMD_CTX
);
691 if (target
->smp
&& CMD_ARGC
> 0) {
692 struct target_list
*head
;
694 foreach_smp_target(head
, target
->smp_targets
) {
696 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do
,
697 target_to_xtensa(curr
));
703 return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do
,
704 target_to_xtensa(target
));
707 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtreg
)
709 struct target
*target
= get_current_target(CMD_CTX
);
710 if (target
->smp
&& CMD_ARGC
> 0) {
711 struct target_list
*head
;
713 foreach_smp_target(head
, target
->smp_targets
) {
715 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do
,
716 target_to_xtensa(curr
));
722 return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do
,
723 target_to_xtensa(target
));
726 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtregfmt
)
728 struct target
*target
= get_current_target(CMD_CTX
);
729 if (target
->smp
&& CMD_ARGC
> 0) {
730 struct target_list
*head
;
732 foreach_smp_target(head
, target
->smp_targets
) {
734 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do
,
735 target_to_xtensa(curr
));
741 return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do
,
742 target_to_xtensa(target
));
745 COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode
)
747 struct target
*target
= get_current_target(CMD_CTX
);
748 if (target
->smp
&& CMD_ARGC
> 0) {
749 struct target_list
*head
;
751 foreach_smp_target(head
, target
->smp_targets
) {
753 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do
,
754 target_to_xtensa(curr
));
760 return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do
,
761 target_to_xtensa(target
));
764 COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak
)
766 struct target
*target
= get_current_target(CMD_CTX
);
767 if (target
->smp
&& CMD_ARGC
> 0) {
768 struct target_list
*head
;
770 foreach_smp_target(head
, target
->smp_targets
) {
772 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do
, curr
);
778 return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do
, target
);
781 COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts
)
783 struct target
*target
= get_current_target(CMD_CTX
);
784 if (target
->smp
&& CMD_ARGC
> 0) {
785 struct target_list
*head
;
787 foreach_smp_target(head
, target
->smp_targets
) {
789 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do
,
790 target_to_xtensa(curr
));
796 return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do
,
797 target_to_xtensa(target
));
800 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable
)
802 struct target
*target
= get_current_target(CMD_CTX
);
803 if (target
->smp
&& CMD_ARGC
> 0) {
804 struct target_list
*head
;
806 foreach_smp_target(head
, target
->smp_targets
) {
808 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do
,
809 target_to_xtensa(curr
));
815 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do
,
816 target_to_xtensa(target
));
819 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump
)
821 struct target
*target
= get_current_target(CMD_CTX
);
823 struct target_list
*head
;
825 foreach_smp_target(head
, target
->smp_targets
) {
827 LOG_TARGET_INFO(curr
, ":");
828 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do
,
829 target_to_xtensa(curr
));
835 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do
,
836 target_to_xtensa(target
));
839 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart
)
841 struct target
*target
= get_current_target(CMD_CTX
);
843 struct target_list
*head
;
845 foreach_smp_target(head
, target
->smp_targets
) {
847 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do
,
848 target_to_xtensa(curr
));
854 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do
,
855 target_to_xtensa(target
));
858 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop
)
860 struct target
*target
= get_current_target(CMD_CTX
);
862 struct target_list
*head
;
864 foreach_smp_target(head
, target
->smp_targets
) {
866 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do
,
867 target_to_xtensa(curr
));
873 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do
,
874 target_to_xtensa(target
));
877 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump
)
879 struct target
*target
= get_current_target(CMD_CTX
);
881 struct target_list
*head
;
883 int32_t cores_max_id
= 0;
884 /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */
885 foreach_smp_target(head
, target
->smp_targets
) {
887 if (cores_max_id
< curr
->coreid
)
888 cores_max_id
= curr
->coreid
;
890 if (CMD_ARGC
< ((uint32_t)cores_max_id
+ 1)) {
892 "Need %d filenames to dump to as output!",
896 foreach_smp_target(head
, target
->smp_targets
) {
898 int ret
= CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do
,
899 target_to_xtensa(curr
), CMD_ARGV
[curr
->coreid
]);
905 return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do
,
906 target_to_xtensa(target
), CMD_ARGV
[0]);
909 const struct command_registration esp_xtensa_smp_xtensa_command_handlers
[] = {
912 .handler
= esp_xtensa_smp_cmd_xtdef
,
913 .mode
= COMMAND_CONFIG
,
914 .help
= "Configure Xtensa core type",
919 .handler
= esp_xtensa_smp_cmd_xtopt
,
920 .mode
= COMMAND_CONFIG
,
921 .help
= "Configure Xtensa core option",
922 .usage
= "<name> <value>",
926 .handler
= esp_xtensa_smp_cmd_xtmem
,
927 .mode
= COMMAND_CONFIG
,
928 .help
= "Configure Xtensa memory/cache option",
929 .usage
= "<type> [parameters]",
933 .handler
= esp_xtensa_smp_cmd_xtmmu
,
934 .mode
= COMMAND_CONFIG
,
935 .help
= "Configure Xtensa MMU option",
936 .usage
= "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>",
940 .handler
= esp_xtensa_smp_cmd_xtmpu
,
941 .mode
= COMMAND_CONFIG
,
942 .help
= "Configure Xtensa MPU option",
943 .usage
= "<num FG seg> <min seg size> <lockable> <executeonly>",
947 .handler
= esp_xtensa_smp_cmd_xtreg
,
948 .mode
= COMMAND_CONFIG
,
949 .help
= "Configure Xtensa register",
950 .usage
= "<regname> <regnum>",
954 .handler
= esp_xtensa_smp_cmd_xtreg
,
955 .mode
= COMMAND_CONFIG
,
956 .help
= "Configure number of Xtensa registers",
957 .usage
= "<numregs>",
961 .handler
= esp_xtensa_smp_cmd_xtregfmt
,
962 .mode
= COMMAND_CONFIG
,
963 .help
= "Configure format of Xtensa register map",
964 .usage
= "<numgregs>",
967 .name
= "set_permissive",
968 .handler
= esp_xtensa_smp_cmd_permissive_mode
,
970 .help
= "When set to 1, enable Xtensa permissive mode (less client-side checks)",
975 .handler
= esp_xtensa_smp_cmd_mask_interrupts
,
977 .help
= "mask Xtensa interrupts at step",
978 .usage
= "['on'|'off']",
982 .handler
= esp_xtensa_smp_cmd_smpbreak
,
984 .help
= "Set the way the CPU chains OCD breaks",
986 "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
989 .name
= "perfmon_enable",
990 .handler
= esp_xtensa_smp_cmd_perfmon_enable
,
991 .mode
= COMMAND_EXEC
,
992 .help
= "Enable and start performance counter",
993 .usage
= "<counter_id> <select> [mask] [kernelcnt] [tracelevel]",
996 .name
= "perfmon_dump",
997 .handler
= esp_xtensa_smp_cmd_perfmon_dump
,
998 .mode
= COMMAND_EXEC
,
1000 "Dump performance counter value. If no argument specified, dumps all counters.",
1001 .usage
= "[counter_id]",
1004 .name
= "tracestart",
1005 .handler
= esp_xtensa_smp_cmd_tracestart
,
1006 .mode
= COMMAND_EXEC
,
1008 "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.",
1009 .usage
= "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]",
1012 .name
= "tracestop",
1013 .handler
= esp_xtensa_smp_cmd_tracestop
,
1014 .mode
= COMMAND_EXEC
,
1015 .help
= "Tracing: Stop current trace as started by the tracestart command",
1019 .name
= "tracedump",
1020 .handler
= esp_xtensa_smp_cmd_tracedump
,
1021 .mode
= COMMAND_EXEC
,
1022 .help
= "Tracing: Dump trace memory to a files. One file per core.",
1023 .usage
= "<outfile1> <outfile2>",
1025 COMMAND_REGISTRATION_DONE
1028 const struct command_registration esp_xtensa_smp_command_handlers
[] = {
1032 .chain
= esp_xtensa_smp_xtensa_command_handlers
,
1034 COMMAND_REGISTRATION_DONE
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)