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 * Author: Alexey Gerenkov <alexey@espressif.com> *
7 ***************************************************************************/
14 #include <target/target.h>
15 #include <target/target_type.h>
16 #include <target/smp.h>
17 #include "esp_xtensa_smp.h"
20 Multiprocessor stuff common:
22 The ESP Xtensa chip can have several cores in it, which can run in SMP-mode if an
23 SMP-capable OS is running. The hardware has a few features which makes
24 SMP debugging much easier.
26 First of all, there's something called a 'break network', consisting of a
27 BreakIn input and a BreakOut output on each CPU. The idea is that as soon
28 as a CPU goes into debug mode for whatever reason, it'll signal that using
29 its DebugOut pin. This signal is connected to the other CPU's DebugIn
30 input, causing this CPU also to go into debugging mode. To resume execution
31 when using only this break network, we will need to manually resume both
34 An alternative to this is the XOCDMode output and the RunStall (or DebugStall)
35 input. When these are cross-connected, a CPU that goes into debug mode will
36 halt execution entirely on the other CPU. Execution on the other CPU can be
37 resumed by either the first CPU going out of debug mode, or the second CPU
38 going into debug mode: the stall is temporarily lifted as long as the stalled
41 A third, separate, signal is CrossTrigger. This is connected in the same way
42 as the breakIn/breakOut network, but is for the TRAX (trace memory) feature;
43 it does not affect OCD in any way.
49 The ESP Xtensa chip has several Xtensa cores inside, but represent themself to the OCD
50 as one chip that works in multithreading mode under FreeRTOS OS.
51 The core that initiate the stop condition will be defined as an active cpu.
52 When one core stops, then other core will be stopped automatically by smpbreak.
53 The core that initiates stop condition will be defined as an active core, and
54 registers of this core will be transferred.
57 #define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES 5
59 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume);
61 static inline struct esp_xtensa_smp_common *target_to_esp_xtensa_smp(struct target *target)
63 return container_of(target->arch_info, struct esp_xtensa_smp_common, esp_xtensa);
66 int esp_xtensa_smp_assert_reset(struct target *target)
71 int esp_xtensa_smp_deassert_reset(struct target *target)
73 LOG_TARGET_DEBUG(target, "begin");
75 int ret = xtensa_deassert_reset(target);
78 /* in SMP mode when chip was running single-core app the other core can be left un-examined,
79 because examination is done before SOC reset. But after SOC reset it is functional and should be handled.
80 So try to examine un-examined core just after SOC reset */
81 if (target->smp && !target_was_examined(target))
82 ret = xtensa_examine(target);
86 int esp_xtensa_smp_soft_reset_halt(struct target *target)
89 struct target_list *head;
90 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
92 LOG_TARGET_DEBUG(target, "begin");
93 /* in SMP mode we need to ensure that at first we reset SOC on PRO-CPU
94 and then call xtensa_assert_reset() for all cores */
95 if (target->smp && target->coreid != 0)
97 /* Reset the SoC first */
98 if (esp_xtensa_smp->chip_ops->reset) {
99 res = esp_xtensa_smp->chip_ops->reset(target);
104 return xtensa_assert_reset(target);
106 foreach_smp_target(head, target->smp_targets) {
107 res = xtensa_assert_reset(head->target);
114 static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid)
116 struct target_list *head;
119 foreach_smp_target(head, target->smp_targets) {
121 if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
128 int esp_xtensa_smp_poll(struct target *target)
130 enum target_state old_state = target->state;
131 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
132 struct target_list *head;
134 bool other_core_resume_req = false;
136 if (target->state == TARGET_HALTED && target->smp && target->gdb_service && !target->gdb_service->target) {
137 target->gdb_service->target = get_halted_esp_xtensa_smp(target, target->gdb_service->core[1]);
138 LOG_INFO("Switch GDB target to '%s'", target_name(target->gdb_service->target));
139 if (esp_xtensa_smp->chip_ops->on_halt)
140 esp_xtensa_smp->chip_ops->on_halt(target);
141 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
145 int ret = esp_xtensa_poll(target);
150 if (target->state == TARGET_RESET) {
151 esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
152 } else if (esp_xtensa_smp->examine_other_cores > 0 &&
153 (target->state == TARGET_RUNNING || target->state == TARGET_HALTED)) {
154 LOG_TARGET_DEBUG(target, "Check for unexamined cores after reset");
155 bool all_examined = true;
156 foreach_smp_target(head, target->smp_targets) {
160 if (!target_was_examined(curr)) {
161 if (target_examine_one(curr) != ERROR_OK) {
162 LOG_DEBUG("Failed to examine!");
163 all_examined = false;
168 esp_xtensa_smp->examine_other_cores = 0;
170 esp_xtensa_smp->examine_other_cores--;
174 if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
176 ret = esp_xtensa_smp_update_halt_gdb(target, &other_core_resume_req);
180 /* Call any event callbacks that are applicable */
181 if (old_state == TARGET_DEBUG_RUNNING) {
182 target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
184 /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */
185 if (target->smp && other_core_resume_req) {
186 /* Resume xtensa_resume will handle BREAK instruction. */
187 ret = target_resume(target, 1, 0, 1, 0);
188 if (ret != ERROR_OK) {
189 LOG_ERROR("Failed to resume target");
194 if (esp_xtensa_smp->chip_ops->on_halt)
195 esp_xtensa_smp->chip_ops->on_halt(target);
196 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
203 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume)
205 struct esp_xtensa_smp_common *esp_xtensa_smp;
206 struct target *gdb_target = NULL;
207 struct target_list *head;
211 *need_resume = false;
213 if (target->gdb_service && target->gdb_service->target)
214 LOG_DEBUG("GDB target '%s'", target_name(target->gdb_service->target));
216 if (target->gdb_service && target->gdb_service->core[0] == -1) {
217 target->gdb_service->target = target;
218 target->gdb_service->core[0] = target->coreid;
219 LOG_INFO("Set GDB target to '%s'", target_name(target));
222 if (target->gdb_service)
223 gdb_target = target->gdb_service->target;
225 /* due to smpbreak config other cores can also go to HALTED state */
226 foreach_smp_target(head, target->smp_targets) {
228 LOG_DEBUG("Check target '%s'", target_name(curr));
229 /* skip calling context */
232 if (!target_was_examined(curr)) {
233 curr->state = TARGET_HALTED;
236 /* skip targets that were already halted */
237 if (curr->state == TARGET_HALTED)
239 /* Skip gdb_target; it alerts GDB so has to be polled as last one */
240 if (curr == gdb_target)
242 LOG_DEBUG("Poll target '%s'", target_name(curr));
244 esp_xtensa_smp = target_to_esp_xtensa_smp(curr);
245 /* avoid auto-resume after syscall, it will be done later */
246 esp_xtensa_smp->other_core_does_resume = true;
247 /* avoid recursion in esp_xtensa_smp_poll() */
249 if (esp_xtensa_smp->chip_ops->poll)
250 ret = esp_xtensa_smp->chip_ops->poll(curr);
252 ret = esp_xtensa_smp_poll(curr);
256 esp_xtensa_smp->other_core_does_resume = false;
259 /* after all targets were updated, poll the gdb serving target */
260 if (gdb_target && gdb_target != target) {
261 esp_xtensa_smp = target_to_esp_xtensa_smp(gdb_target);
262 if (esp_xtensa_smp->chip_ops->poll)
263 ret = esp_xtensa_smp->chip_ops->poll(gdb_target);
265 ret = esp_xtensa_smp_poll(gdb_target);
273 static inline int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break)
275 int res = xtensa_smpbreak_get(target, smp_break);
278 return xtensa_smpbreak_set(target, 0);
281 static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break)
283 return xtensa_smpbreak_set(target, smp_break);
286 static int esp_xtensa_smp_resume_cores(struct target *target,
287 int handle_breakpoints,
290 struct target_list *head;
293 LOG_TARGET_DEBUG(target, "begin");
295 foreach_smp_target(head, target->smp_targets) {
297 /* in single-core mode disabled core cannot be examined, but need to be resumed too*/
298 if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) {
299 /* resume current address, not in SMP mode */
301 int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution);
310 int esp_xtensa_smp_resume(struct target *target,
312 target_addr_t address,
313 int handle_breakpoints,
319 xtensa_smpbreak_get(target, &smp_break);
320 LOG_TARGET_DEBUG(target, "smp_break=0x%" PRIx32, smp_break);
322 /* dummy resume for smp toggle in order to reduce gdb impact */
323 if ((target->smp) && (target->gdb_service) && (target->gdb_service->core[1] != -1)) {
324 /* simulate a start and halt of target */
325 target->gdb_service->target = NULL;
326 target->gdb_service->core[0] = target->gdb_service->core[1];
327 /* fake resume at next poll we play the target core[1], see poll*/
328 LOG_TARGET_DEBUG(target, "Fake resume");
329 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
333 /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for
334 * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */
335 res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
338 res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution);
339 /* restore configured BreakInOut signals config */
340 int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
343 if (res != ERROR_OK) {
344 LOG_TARGET_ERROR(target, "Failed to prepare for resume!");
349 if (target->gdb_service)
350 target->gdb_service->core[0] = -1;
351 res = esp_xtensa_smp_resume_cores(target, handle_breakpoints, debug_execution);
356 res = xtensa_do_resume(target);
357 if (res != ERROR_OK) {
358 LOG_TARGET_ERROR(target, "Failed to resume!");
362 target->debug_reason = DBG_REASON_NOTHALTED;
363 if (!debug_execution)
364 target->state = TARGET_RUNNING;
366 target->state = TARGET_DEBUG_RUNNING;
368 target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
372 int esp_xtensa_smp_step(struct target *target,
374 target_addr_t address,
375 int handle_breakpoints)
378 uint32_t smp_break = 0;
379 struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
382 res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
386 res = xtensa_step(target, current, address, handle_breakpoints);
388 if (res == ERROR_OK) {
389 if (esp_xtensa_smp->chip_ops->on_halt)
390 esp_xtensa_smp->chip_ops->on_halt(target);
391 target_call_event_callbacks(target, TARGET_EVENT_HALTED);
395 int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
403 int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint)
405 int res = xtensa_watchpoint_add(target, watchpoint);
412 struct target_list *head;
413 foreach_smp_target(head, target->smp_targets) {
414 struct target *curr = head->target;
415 if (curr == target || !target_was_examined(curr))
417 /* Need to use high level API here because every target for core contains list of watchpoints.
418 * GDB works with active core only, so we need to duplicate every watchpoint on other cores,
419 * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */
421 res = watchpoint_add(curr, watchpoint->address, watchpoint->length,
422 watchpoint->rw, watchpoint->value, watchpoint->mask);
430 int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint)
432 int res = xtensa_watchpoint_remove(target, watchpoint);
439 struct target_list *head;
440 foreach_smp_target(head, target->smp_targets) {
441 struct target *curr = head->target;
444 /* see big comment in esp_xtensa_smp_watchpoint_add() */
446 watchpoint_remove(curr, watchpoint->address);
452 int esp_xtensa_smp_init_arch_info(struct target *target,
453 struct esp_xtensa_smp_common *esp_xtensa_smp,
454 const struct xtensa_config *xtensa_cfg,
455 struct xtensa_debug_module_config *dm_cfg,
456 const struct esp_xtensa_smp_chip_ops *chip_ops)
458 int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, xtensa_cfg, dm_cfg);
461 esp_xtensa_smp->chip_ops = chip_ops;
462 esp_xtensa_smp->examine_other_cores = ESP_XTENSA_SMP_EXAMINE_OTHER_CORES;
466 int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target)
468 return esp_xtensa_target_init(cmd_ctx, target);
471 COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode)
473 struct target *target = get_current_target(CMD_CTX);
474 if (target->smp && CMD_ARGC > 0) {
475 struct target_list *head;
477 foreach_smp_target(head, target->smp_targets) {
479 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
480 target_to_xtensa(curr));
486 return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
487 target_to_xtensa(target));
490 COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak)
492 struct target *target = get_current_target(CMD_CTX);
493 if (target->smp && CMD_ARGC > 0) {
494 struct target_list *head;
496 foreach_smp_target(head, target->smp_targets) {
498 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, curr);
504 return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, target);
507 COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts)
509 struct target *target = get_current_target(CMD_CTX);
510 if (target->smp && CMD_ARGC > 0) {
511 struct target_list *head;
513 foreach_smp_target(head, target->smp_targets) {
515 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
516 target_to_xtensa(curr));
522 return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
523 target_to_xtensa(target));
526 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable)
528 struct target *target = get_current_target(CMD_CTX);
529 if (target->smp && CMD_ARGC > 0) {
530 struct target_list *head;
532 foreach_smp_target(head, target->smp_targets) {
534 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
535 target_to_xtensa(curr));
541 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
542 target_to_xtensa(target));
545 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump)
547 struct target *target = get_current_target(CMD_CTX);
549 struct target_list *head;
551 foreach_smp_target(head, target->smp_targets) {
553 LOG_INFO("CPU%d:", curr->coreid);
554 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
555 target_to_xtensa(curr));
561 return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
562 target_to_xtensa(target));
565 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart)
567 struct target *target = get_current_target(CMD_CTX);
569 struct target_list *head;
571 foreach_smp_target(head, target->smp_targets) {
573 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
574 target_to_xtensa(curr));
580 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
581 target_to_xtensa(target));
584 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop)
586 struct target *target = get_current_target(CMD_CTX);
588 struct target_list *head;
590 foreach_smp_target(head, target->smp_targets) {
592 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
593 target_to_xtensa(curr));
599 return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
600 target_to_xtensa(target));
603 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump)
605 struct target *target = get_current_target(CMD_CTX);
607 struct target_list *head;
609 int32_t cores_max_id = 0;
610 /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */
611 foreach_smp_target(head, target->smp_targets) {
613 if (cores_max_id < curr->coreid)
614 cores_max_id = curr->coreid;
616 if (CMD_ARGC < ((uint32_t)cores_max_id + 1)) {
618 "Need %d filenames to dump to as output!",
622 foreach_smp_target(head, target->smp_targets) {
624 int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
625 target_to_xtensa(curr), CMD_ARGV[curr->coreid]);
631 return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
632 target_to_xtensa(target), CMD_ARGV[0]);
635 const struct command_registration esp_xtensa_smp_xtensa_command_handlers[] = {
637 .name = "set_permissive",
638 .handler = esp_xtensa_smp_cmd_permissive_mode,
640 .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)",
645 .handler = esp_xtensa_smp_cmd_mask_interrupts,
647 .help = "mask Xtensa interrupts at step",
648 .usage = "['on'|'off']",
652 .handler = esp_xtensa_smp_cmd_smpbreak,
654 .help = "Set the way the CPU chains OCD breaks",
656 "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
659 .name = "perfmon_enable",
660 .handler = esp_xtensa_smp_cmd_perfmon_enable,
661 .mode = COMMAND_EXEC,
662 .help = "Enable and start performance counter",
663 .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]",
666 .name = "perfmon_dump",
667 .handler = esp_xtensa_smp_cmd_perfmon_dump,
668 .mode = COMMAND_EXEC,
670 "Dump performance counter value. If no argument specified, dumps all counters.",
671 .usage = "[counter_id]",
674 .name = "tracestart",
675 .handler = esp_xtensa_smp_cmd_tracestart,
676 .mode = COMMAND_EXEC,
678 "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.",
679 .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]",
683 .handler = esp_xtensa_smp_cmd_tracestop,
684 .mode = COMMAND_EXEC,
685 .help = "Tracing: Stop current trace as started by the tracestart command",
690 .handler = esp_xtensa_smp_cmd_tracedump,
691 .mode = COMMAND_EXEC,
692 .help = "Tracing: Dump trace memory to a files. One file per core.",
693 .usage = "<outfile1> <outfile2>",
695 COMMAND_REGISTRATION_DONE
698 const struct command_registration esp_xtensa_smp_command_handlers[] = {
702 .chain = esp_xtensa_smp_xtensa_command_handlers,
704 COMMAND_REGISTRATION_DONE