OpenOCD
esp_xtensa_smp.c
Go to the documentation of this file.
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>
17 #include "esp_xtensa_smp.h"
18 #include "esp_xtensa_semihosting.h"
19 #include "esp_algorithm.h"
20 
21 /*
22 Multiprocessor stuff common:
23 
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.
27 
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
34 CPUs.
35 
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
41 CPU is in debug mode.
42 
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.
46 */
47 
48 /*
49 Multiprocessor stuff:
50 
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.
57 */
58 
59 #define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES 5
60 
61 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume);
62 
64 {
66 }
67 
69 {
70  return ERROR_OK;
71 }
72 
74 {
75  LOG_TARGET_DEBUG(target, "begin");
76 
77  int ret = xtensa_deassert_reset(target);
78  if (ret != ERROR_OK)
79  return ret;
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 */
84  ret = xtensa_examine(target);
85  return ret;
86 }
87 
89 {
90  int res;
91  struct target_list *head;
92  struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
93 
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) {
99  if (head->target != target)
100  return ERROR_OK;
101  }
102  /* Reset the SoC first */
103  if (esp_xtensa_smp->chip_ops->reset) {
104  res = esp_xtensa_smp->chip_ops->reset(target);
105  if (res != ERROR_OK)
106  return res;
107  }
108  if (!target->smp)
109  return xtensa_assert_reset(target);
110 
112  res = xtensa_assert_reset(head->target);
113  if (res != ERROR_OK)
114  return res;
115  }
116  return ERROR_OK;
117 }
118 
120 {
121  struct target_list *head;
122 
123  if (!target->smp)
124  return esp_xtensa_on_halt(target);
125 
127  int res = esp_xtensa_on_halt(head->target);
128  if (res != ERROR_OK)
129  return res;
130  }
131  return ERROR_OK;
132 }
133 
134 static struct target *get_halted_esp_xtensa_smp(struct target *target, int32_t coreid)
135 {
136  struct target_list *head;
137  struct target *curr;
138 
140  curr = head->target;
141  if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
142  return curr;
143  }
144 
145  return target;
146 }
147 
149 {
150  enum target_state old_state = target->state;
151  struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
152  struct esp_xtensa_common *esp_xtensa = target_to_esp_xtensa(target);
153  uint32_t old_dbg_stubs_base = esp_xtensa->esp.dbg_stubs.base;
154  struct target_list *head;
155  struct target *curr;
156  bool other_core_resume_req = false;
157 
160  LOG_INFO("Switch GDB target to '%s'", target_name(target->gdb_service->target));
161  if (esp_xtensa_smp->chip_ops->on_halt)
162  esp_xtensa_smp->chip_ops->on_halt(target);
164  return ERROR_OK;
165  }
166 
167  int ret = esp_xtensa_poll(target);
168  if (ret != ERROR_OK)
169  return ret;
170 
171  if (esp_xtensa->esp.dbg_stubs.base && old_dbg_stubs_base != esp_xtensa->esp.dbg_stubs.base) {
172  /* debug stubs base is set only in PRO-CPU TRAX register, so sync this info */
174  curr = head->target;
175  if (curr == target)
176  continue;
177  target_to_esp_xtensa(curr)->esp.dbg_stubs.base = esp_xtensa->esp.dbg_stubs.base;
178  }
179  }
180 
181  if (target->smp) {
182  if (target->state == TARGET_RESET) {
184  } else if (esp_xtensa_smp->examine_other_cores > 0 &&
186  LOG_TARGET_DEBUG(target, "Check for unexamined cores after reset");
187  bool all_examined = true;
189  curr = head->target;
190  if (curr == target)
191  continue;
192  if (!target_was_examined(curr)) {
193  if (target_examine_one(curr) != ERROR_OK) {
194  LOG_DEBUG("Failed to examine!");
195  all_examined = false;
196  }
197  }
198  }
199  if (all_examined)
200  esp_xtensa_smp->examine_other_cores = 0;
201  else
202  esp_xtensa_smp->examine_other_cores--;
203  }
204  }
205 
206  if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
207  if (target->smp) {
208  ret = esp_xtensa_smp_update_halt_gdb(target, &other_core_resume_req);
209  if (ret != ERROR_OK)
210  return ret;
211  }
212  /* Call any event callbacks that are applicable */
213  if (old_state == TARGET_DEBUG_RUNNING) {
215  } else {
217  if (ret == ERROR_OK && esp_xtensa->semihost.need_resume &&
218  !esp_xtensa_smp->other_core_does_resume) {
219  esp_xtensa->semihost.need_resume = false;
220  /* Resume xtensa_resume will handle BREAK instruction. */
221  ret = target_resume(target, 1, 0, 1, 0);
222  if (ret != ERROR_OK) {
223  LOG_ERROR("Failed to resume target");
224  return ret;
225  }
226  }
227  return ret;
228  }
229  /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */
230  if (target->smp && other_core_resume_req) {
231  /* Resume xtensa_resume will handle BREAK instruction. */
232  ret = target_resume(target, 1, 0, 1, 0);
233  if (ret != ERROR_OK) {
234  LOG_ERROR("Failed to resume target");
235  return ret;
236  }
237  return ERROR_OK;
238  }
239  if (esp_xtensa_smp->chip_ops->on_halt)
240  esp_xtensa_smp->chip_ops->on_halt(target);
242  }
243  }
244 
245  return ERROR_OK;
246 }
247 
248 static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume)
249 {
250  struct esp_xtensa_smp_common *esp_xtensa_smp;
251  struct target *gdb_target = NULL;
252  struct target_list *head;
253  struct target *curr;
254  int ret = ERROR_OK;
255 
256  *need_resume = false;
257 
259  LOG_DEBUG("GDB target '%s'", target_name(target->gdb_service->target));
260 
261  if (target->gdb_service && target->gdb_service->core[0] == -1) {
264  LOG_INFO("Set GDB target to '%s'", target_name(target));
265  }
266 
267  if (target->gdb_service)
268  gdb_target = target->gdb_service->target;
269 
270  /* due to smpbreak config other cores can also go to HALTED state */
272  curr = head->target;
273  LOG_DEBUG("Check target '%s'", target_name(curr));
274  /* skip calling context */
275  if (curr == target)
276  continue;
277  if (!target_was_examined(curr)) {
278  curr->state = TARGET_HALTED;
279  continue;
280  }
281  /* skip targets that were already halted */
282  if (curr->state == TARGET_HALTED)
283  continue;
284  /* Skip gdb_target; it alerts GDB so has to be polled as last one */
285  if (curr == gdb_target)
286  continue;
287  LOG_DEBUG("Poll target '%s'", target_name(curr));
288 
289  esp_xtensa_smp = target_to_esp_xtensa_smp(curr);
290  /* avoid auto-resume after syscall, it will be done later */
291  esp_xtensa_smp->other_core_does_resume = true;
292  /* avoid recursion in esp_xtensa_smp_poll() */
293  curr->smp = 0;
294  if (esp_xtensa_smp->chip_ops->poll)
295  ret = esp_xtensa_smp->chip_ops->poll(curr);
296  else
297  ret = esp_xtensa_smp_poll(curr);
298  curr->smp = 1;
299  if (ret != ERROR_OK)
300  return ret;
301  esp_xtensa_smp->other_core_does_resume = false;
302  struct esp_xtensa_common *curr_esp_xtensa = target_to_esp_xtensa(curr);
303  if (curr_esp_xtensa->semihost.need_resume) {
304  curr_esp_xtensa->semihost.need_resume = false;
305  *need_resume = true;
306  }
307  }
308 
309  /* after all targets were updated, poll the gdb serving target */
310  if (gdb_target && gdb_target != target) {
311  esp_xtensa_smp = target_to_esp_xtensa_smp(gdb_target);
312  if (esp_xtensa_smp->chip_ops->poll)
313  ret = esp_xtensa_smp->chip_ops->poll(gdb_target);
314  else
315  ret = esp_xtensa_smp_poll(gdb_target);
316  }
317 
318  LOG_DEBUG("exit");
319 
320  return ret;
321 }
322 
323 static inline int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break)
324 {
325  int res = xtensa_smpbreak_get(target, smp_break);
326  if (res != ERROR_OK)
327  return res;
328  return xtensa_smpbreak_set(target, 0);
329 }
330 
331 static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break)
332 {
333  return xtensa_smpbreak_set(target, smp_break);
334 }
335 
337  int handle_breakpoints,
338  int debug_execution)
339 {
340  struct target_list *head;
341  struct target *curr;
342 
343  LOG_TARGET_DEBUG(target, "begin");
344 
346  curr = head->target;
347  /* in single-core mode disabled core cannot be examined, but need to be resumed too*/
348  if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) {
349  /* resume current address, not in SMP mode */
350  curr->smp = 0;
351  int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution);
352  curr->smp = 1;
353  if (res != ERROR_OK)
354  return res;
355  }
356  }
357  return ERROR_OK;
358 }
359 
361  int current,
362  target_addr_t address,
363  int handle_breakpoints,
364  int debug_execution)
365 {
366  int res;
367  uint32_t smp_break;
368 
369  xtensa_smpbreak_get(target, &smp_break);
370  LOG_TARGET_DEBUG(target, "smp_break=0x%" PRIx32, smp_break);
371 
372  /* dummy resume for smp toggle in order to reduce gdb impact */
373  if ((target->smp) && (target->gdb_service) && (target->gdb_service->core[1] != -1)) {
374  /* simulate a start and halt of target */
377  /* fake resume at next poll we play the target core[1], see poll*/
378  LOG_TARGET_DEBUG(target, "Fake resume");
380  return ERROR_OK;
381  }
382 
383  /* xtensa_prepare_resume() can step over breakpoint/watchpoint and generate signals on BreakInOut circuit for
384  * other cores. So disconnect this core from BreakInOut circuit and do xtensa_prepare_resume(). */
385  res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
386  if (res != ERROR_OK)
387  return res;
388  res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution);
389  /* restore configured BreakInOut signals config */
390  int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
391  if (ret != ERROR_OK)
392  return ret;
393  if (res != ERROR_OK) {
394  LOG_TARGET_ERROR(target, "Failed to prepare for resume!");
395  return res;
396  }
397 
398  if (target->smp) {
399  if (target->gdb_service)
400  target->gdb_service->core[0] = -1;
401  res = esp_xtensa_smp_resume_cores(target, handle_breakpoints, debug_execution);
402  if (res != ERROR_OK)
403  return res;
404  }
405 
406  res = xtensa_do_resume(target);
407  if (res != ERROR_OK) {
408  LOG_TARGET_ERROR(target, "Failed to resume!");
409  return res;
410  }
411 
413  if (!debug_execution)
415  else
417 
419  return ERROR_OK;
420 }
421 
423  int current,
424  target_addr_t address,
425  int handle_breakpoints)
426 {
427  int res;
428  uint32_t smp_break = 0;
429  struct esp_xtensa_smp_common *esp_xtensa_smp = target_to_esp_xtensa_smp(target);
430 
431  if (target->smp) {
432  res = esp_xtensa_smp_smpbreak_disable(target, &smp_break);
433  if (res != ERROR_OK)
434  return res;
435  }
436  res = xtensa_step(target, current, address, handle_breakpoints);
437 
438  if (res == ERROR_OK) {
439  if (esp_xtensa_smp->chip_ops->on_halt)
440  esp_xtensa_smp->chip_ops->on_halt(target);
442  }
443 
444  if (target->smp) {
445  int ret = esp_xtensa_smp_smpbreak_restore(target, smp_break);
446  if (ret != ERROR_OK)
447  return ret;
448  }
449 
450  return res;
451 }
452 
454 {
456  if (res != ERROR_OK)
457  return res;
458 
459  if (!target->smp)
460  return ERROR_OK;
461 
462  struct target_list *head;
464  struct target *curr = head->target;
465  if (curr == target || !target_was_examined(curr))
466  continue;
467  /* Need to use high level API here because every target for core contains list of watchpoints.
468  * GDB works with active core only, so we need to duplicate every watchpoint on other cores,
469  * otherwise watchpoint_free() on active core can fail if WP has been initially added on another core. */
470  curr->smp = 0;
473  curr->smp = 1;
474  if (res != ERROR_OK)
475  return res;
476  }
477  return ERROR_OK;
478 }
479 
481 {
483  if (res != ERROR_OK)
484  return res;
485 
486  if (!target->smp)
487  return ERROR_OK;
488 
489  struct target_list *head;
491  struct target *curr = head->target;
492  if (curr == target)
493  continue;
494  /* see big comment in esp_xtensa_smp_watchpoint_add() */
495  curr->smp = 0;
497  curr->smp = 1;
498  }
499  return ERROR_OK;
500 }
501 
502 int esp_xtensa_smp_run_func_image(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, ...)
503 {
504  struct target *run_target = target;
505  struct target_list *head;
506  va_list ap;
507  uint32_t smp_break = 0;
508  int res;
509 
510  if (target->smp) {
511  /* find first HALTED and examined core */
513  run_target = head->target;
514  if (target_was_examined(run_target) && run_target->state == TARGET_HALTED)
515  break;
516  }
517  if (!head) {
518  LOG_ERROR("Failed to find HALTED core!");
519  return ERROR_FAIL;
520  }
521 
522  res = esp_xtensa_smp_smpbreak_disable(run_target, &smp_break);
523  if (res != ERROR_OK)
524  return res;
525  }
526 
527  va_start(ap, num_args);
528  int algo_res = esp_algorithm_run_func_image_va(run_target, run, num_args, ap);
529  va_end(ap);
530 
531  if (target->smp) {
532  res = esp_xtensa_smp_smpbreak_restore(run_target, smp_break);
533  if (res != ERROR_OK)
534  return res;
535  }
536  return algo_res;
537 }
538 
540  struct esp_algorithm_run_data *run,
541  uint32_t func_addr,
542  uint32_t num_args,
543  ...)
544 {
545  struct target *run_target = target;
546  struct target_list *head;
547  va_list ap;
548  uint32_t smp_break = 0;
549  int res;
550 
551  if (target->smp) {
552  /* find first HALTED and examined core */
554  run_target = head->target;
555  if (target_was_examined(run_target) && run_target->state == TARGET_HALTED)
556  break;
557  }
558  if (!head) {
559  LOG_ERROR("Failed to find HALTED core!");
560  return ERROR_FAIL;
561  }
562  res = esp_xtensa_smp_smpbreak_disable(run_target, &smp_break);
563  if (res != ERROR_OK)
564  return res;
565  }
566 
567  va_start(ap, num_args);
568  int algo_res = esp_algorithm_run_onboard_func_va(run_target, run, func_addr, num_args, ap);
569  va_end(ap);
570 
571  if (target->smp) {
572  res = esp_xtensa_smp_smpbreak_restore(run_target, smp_break);
573  if (res != ERROR_OK)
574  return res;
575  }
576  return algo_res;
577 }
578 
580  struct esp_xtensa_smp_common *esp_xtensa_smp,
581  struct xtensa_debug_module_config *dm_cfg,
582  const struct esp_xtensa_smp_chip_ops *chip_ops,
583  const struct esp_semihost_ops *semihost_ops)
584 {
585  int ret = esp_xtensa_init_arch_info(target, &esp_xtensa_smp->esp_xtensa, dm_cfg, semihost_ops);
586  if (ret != ERROR_OK)
587  return ret;
588  esp_xtensa_smp->chip_ops = chip_ops;
590  return ERROR_OK;
591 }
592 
594 {
595  int ret = esp_xtensa_target_init(cmd_ctx, target);
596  if (ret != ERROR_OK)
597  return ret;
598 
599  if (target->smp) {
600  struct target_list *head;
602  struct target *curr = head->target;
603  ret = esp_xtensa_semihosting_init(curr);
604  if (ret != ERROR_OK)
605  return ret;
606  }
607  } else {
609  if (ret != ERROR_OK)
610  return ret;
611  }
612  return ERROR_OK;
613 }
614 
615 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef)
616 {
618  if (target->smp && CMD_ARGC > 0) {
619  struct target_list *head;
620  struct target *curr;
622  curr = head->target;
623  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
624  target_to_xtensa(curr));
625  if (ret != ERROR_OK)
626  return ret;
627  }
628  return ERROR_OK;
629  }
630  return CALL_COMMAND_HANDLER(xtensa_cmd_xtdef_do,
632 }
633 
634 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtopt)
635 {
637  if (target->smp && CMD_ARGC > 0) {
638  struct target_list *head;
639  struct target *curr;
641  curr = head->target;
642  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
643  target_to_xtensa(curr));
644  if (ret != ERROR_OK)
645  return ret;
646  }
647  return ERROR_OK;
648  }
649  return CALL_COMMAND_HANDLER(xtensa_cmd_xtopt_do,
651 }
652 
653 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmem)
654 {
656  if (target->smp && CMD_ARGC > 0) {
657  struct target_list *head;
658  struct target *curr;
660  curr = head->target;
661  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
662  target_to_xtensa(curr));
663  if (ret != ERROR_OK)
664  return ret;
665  }
666  return ERROR_OK;
667  }
668  return CALL_COMMAND_HANDLER(xtensa_cmd_xtmem_do,
670 }
671 
672 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmpu)
673 {
675  if (target->smp && CMD_ARGC > 0) {
676  struct target_list *head;
677  struct target *curr;
679  curr = head->target;
680  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
681  target_to_xtensa(curr));
682  if (ret != ERROR_OK)
683  return ret;
684  }
685  return ERROR_OK;
686  }
687  return CALL_COMMAND_HANDLER(xtensa_cmd_xtmpu_do,
689 }
690 
691 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtmmu)
692 {
694  if (target->smp && CMD_ARGC > 0) {
695  struct target_list *head;
696  struct target *curr;
698  curr = head->target;
699  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
700  target_to_xtensa(curr));
701  if (ret != ERROR_OK)
702  return ret;
703  }
704  return ERROR_OK;
705  }
706  return CALL_COMMAND_HANDLER(xtensa_cmd_xtmmu_do,
708 }
709 
710 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtreg)
711 {
713  if (target->smp && CMD_ARGC > 0) {
714  struct target_list *head;
715  struct target *curr;
717  curr = head->target;
718  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
719  target_to_xtensa(curr));
720  if (ret != ERROR_OK)
721  return ret;
722  }
723  return ERROR_OK;
724  }
725  return CALL_COMMAND_HANDLER(xtensa_cmd_xtreg_do,
727 }
728 
729 COMMAND_HANDLER(esp_xtensa_smp_cmd_xtregfmt)
730 {
732  if (target->smp && CMD_ARGC > 0) {
733  struct target_list *head;
734  struct target *curr;
736  curr = head->target;
737  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
738  target_to_xtensa(curr));
739  if (ret != ERROR_OK)
740  return ret;
741  }
742  return ERROR_OK;
743  }
744  return CALL_COMMAND_HANDLER(xtensa_cmd_xtregfmt_do,
746 }
747 
748 COMMAND_HANDLER(esp_xtensa_smp_cmd_permissive_mode)
749 {
751  if (target->smp && CMD_ARGC > 0) {
752  struct target_list *head;
753  struct target *curr;
755  curr = head->target;
756  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
757  target_to_xtensa(curr));
758  if (ret != ERROR_OK)
759  return ret;
760  }
761  return ERROR_OK;
762  }
763  return CALL_COMMAND_HANDLER(xtensa_cmd_permissive_mode_do,
765 }
766 
767 COMMAND_HANDLER(esp_xtensa_smp_cmd_smpbreak)
768 {
770  if (target->smp && CMD_ARGC > 0) {
771  struct target_list *head;
772  struct target *curr;
774  curr = head->target;
775  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, curr);
776  if (ret != ERROR_OK)
777  return ret;
778  }
779  return ERROR_OK;
780  }
781  return CALL_COMMAND_HANDLER(xtensa_cmd_smpbreak_do, target);
782 }
783 
784 COMMAND_HANDLER(esp_xtensa_smp_cmd_mask_interrupts)
785 {
787  if (target->smp && CMD_ARGC > 0) {
788  struct target_list *head;
789  struct target *curr;
791  curr = head->target;
792  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
793  target_to_xtensa(curr));
794  if (ret != ERROR_OK)
795  return ret;
796  }
797  return ERROR_OK;
798  }
799  return CALL_COMMAND_HANDLER(xtensa_cmd_mask_interrupts_do,
801 }
802 
803 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_enable)
804 {
806  if (target->smp && CMD_ARGC > 0) {
807  struct target_list *head;
808  struct target *curr;
810  curr = head->target;
811  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
812  target_to_xtensa(curr));
813  if (ret != ERROR_OK)
814  return ret;
815  }
816  return ERROR_OK;
817  }
818  return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_enable_do,
820 }
821 
822 COMMAND_HANDLER(esp_xtensa_smp_cmd_perfmon_dump)
823 {
825  if (target->smp) {
826  struct target_list *head;
827  struct target *curr;
829  curr = head->target;
830  LOG_TARGET_INFO(curr, ":");
831  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
832  target_to_xtensa(curr));
833  if (ret != ERROR_OK)
834  return ret;
835  }
836  return ERROR_OK;
837  }
838  return CALL_COMMAND_HANDLER(xtensa_cmd_perfmon_dump_do,
840 }
841 
842 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestart)
843 {
845  if (target->smp) {
846  struct target_list *head;
847  struct target *curr;
849  curr = head->target;
850  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
851  target_to_xtensa(curr));
852  if (ret != ERROR_OK)
853  return ret;
854  }
855  return ERROR_OK;
856  }
857  return CALL_COMMAND_HANDLER(xtensa_cmd_tracestart_do,
859 }
860 
861 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracestop)
862 {
864  if (target->smp) {
865  struct target_list *head;
866  struct target *curr;
868  curr = head->target;
869  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
870  target_to_xtensa(curr));
871  if (ret != ERROR_OK)
872  return ret;
873  }
874  return ERROR_OK;
875  }
876  return CALL_COMMAND_HANDLER(xtensa_cmd_tracestop_do,
878 }
879 
880 COMMAND_HANDLER(esp_xtensa_smp_cmd_tracedump)
881 {
883  if (target->smp) {
884  struct target_list *head;
885  struct target *curr;
886  int32_t cores_max_id = 0;
887  /* assume that core IDs are assigned to SMP targets sequentially: 0,1,2... */
889  curr = head->target;
890  if (cores_max_id < curr->coreid)
891  cores_max_id = curr->coreid;
892  }
893  if (CMD_ARGC < ((uint32_t)cores_max_id + 1)) {
895  "Need %d filenames to dump to as output!",
896  cores_max_id + 1);
897  return ERROR_FAIL;
898  }
900  curr = head->target;
901  int ret = CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
902  target_to_xtensa(curr), CMD_ARGV[curr->coreid]);
903  if (ret != ERROR_OK)
904  return ret;
905  }
906  return ERROR_OK;
907  }
908  return CALL_COMMAND_HANDLER(xtensa_cmd_tracedump_do,
910 }
911 
913  {
914  .name = "xtdef",
915  .handler = esp_xtensa_smp_cmd_xtdef,
916  .mode = COMMAND_CONFIG,
917  .help = "Configure Xtensa core type",
918  .usage = "<type>",
919  },
920  {
921  .name = "xtopt",
922  .handler = esp_xtensa_smp_cmd_xtopt,
923  .mode = COMMAND_CONFIG,
924  .help = "Configure Xtensa core option",
925  .usage = "<name> <value>",
926  },
927  {
928  .name = "xtmem",
929  .handler = esp_xtensa_smp_cmd_xtmem,
930  .mode = COMMAND_CONFIG,
931  .help = "Configure Xtensa memory/cache option",
932  .usage = "<type> [parameters]",
933  },
934  {
935  .name = "xtmmu",
936  .handler = esp_xtensa_smp_cmd_xtmmu,
937  .mode = COMMAND_CONFIG,
938  .help = "Configure Xtensa MMU option",
939  .usage = "<NIREFILLENTRIES> <NDREFILLENTRIES> <IVARWAY56> <DVARWAY56>",
940  },
941  {
942  .name = "xtmpu",
943  .handler = esp_xtensa_smp_cmd_xtmpu,
944  .mode = COMMAND_CONFIG,
945  .help = "Configure Xtensa MPU option",
946  .usage = "<num FG seg> <min seg size> <lockable> <executeonly>",
947  },
948  {
949  .name = "xtreg",
950  .handler = esp_xtensa_smp_cmd_xtreg,
951  .mode = COMMAND_CONFIG,
952  .help = "Configure Xtensa register",
953  .usage = "<regname> <regnum>",
954  },
955  {
956  .name = "xtregs",
957  .handler = esp_xtensa_smp_cmd_xtreg,
958  .mode = COMMAND_CONFIG,
959  .help = "Configure number of Xtensa registers",
960  .usage = "<numregs>",
961  },
962  {
963  .name = "xtregfmt",
964  .handler = esp_xtensa_smp_cmd_xtregfmt,
965  .mode = COMMAND_CONFIG,
966  .help = "Configure format of Xtensa register map",
967  .usage = "<numgregs>",
968  },
969  {
970  .name = "set_permissive",
971  .handler = esp_xtensa_smp_cmd_permissive_mode,
972  .mode = COMMAND_ANY,
973  .help = "When set to 1, enable Xtensa permissive mode (less client-side checks)",
974  .usage = "[0|1]",
975  },
976  {
977  .name = "maskisr",
978  .handler = esp_xtensa_smp_cmd_mask_interrupts,
979  .mode = COMMAND_ANY,
980  .help = "mask Xtensa interrupts at step",
981  .usage = "['on'|'off']",
982  },
983  {
984  .name = "smpbreak",
985  .handler = esp_xtensa_smp_cmd_smpbreak,
986  .mode = COMMAND_ANY,
987  .help = "Set the way the CPU chains OCD breaks",
988  .usage =
989  "[none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]",
990  },
991  {
992  .name = "perfmon_enable",
993  .handler = esp_xtensa_smp_cmd_perfmon_enable,
994  .mode = COMMAND_EXEC,
995  .help = "Enable and start performance counter",
996  .usage = "<counter_id> <select> [mask] [kernelcnt] [tracelevel]",
997  },
998  {
999  .name = "perfmon_dump",
1000  .handler = esp_xtensa_smp_cmd_perfmon_dump,
1001  .mode = COMMAND_EXEC,
1002  .help =
1003  "Dump performance counter value. If no argument specified, dumps all counters.",
1004  .usage = "[counter_id]",
1005  },
1006  {
1007  .name = "tracestart",
1008  .handler = esp_xtensa_smp_cmd_tracestart,
1009  .mode = COMMAND_EXEC,
1010  .help =
1011  "Tracing: Set up and start a trace. Optionally set stop trigger address and amount of data captured after.",
1012  .usage = "[pc <pcval>/[maskbitcount]] [after <n> [ins|words]]",
1013  },
1014  {
1015  .name = "tracestop",
1016  .handler = esp_xtensa_smp_cmd_tracestop,
1017  .mode = COMMAND_EXEC,
1018  .help = "Tracing: Stop current trace as started by the tracestart command",
1019  .usage = "",
1020  },
1021  {
1022  .name = "tracedump",
1023  .handler = esp_xtensa_smp_cmd_tracedump,
1024  .mode = COMMAND_EXEC,
1025  .help = "Tracing: Dump trace memory to a files. One file per core.",
1026  .usage = "<outfile1> <outfile2>",
1027  },
1029 };
1030 
1032  {
1033  .name = "xtensa",
1034  .usage = "",
1036  },
1038 };
int watchpoint_add(struct target *target, target_addr_t address, unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask)
Definition: breakpoints.c:568
int watchpoint_remove(struct target *target, target_addr_t address)
Definition: breakpoints.c:605
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:443
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:141
#define CALL_COMMAND_HANDLER(name, extra ...)
Use this to macro to call a command helper (or a nested handler).
Definition: command.h:118
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:146
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:253
@ COMMAND_CONFIG
Definition: command.h:41
@ COMMAND_ANY
Definition: command.h:42
@ COMMAND_EXEC
Definition: command.h:40
static int esp_algorithm_run_func_image_va(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, va_list ap)
Loads and runs stub from specified image.
static int esp_algorithm_run_onboard_func_va(struct target *target, struct esp_algorithm_run_data *run, target_addr_t func_addr, uint32_t num_args, va_list ap)
Runs pre-compiled on-board function.
int esp_xtensa_init_arch_info(struct target *target, struct esp_xtensa_common *esp_xtensa, struct xtensa_debug_module_config *dm_cfg, const struct esp_semihost_ops *semihost_ops)
Definition: esp_xtensa.c:65
int esp_xtensa_poll(struct target *target)
Definition: esp_xtensa.c:105
int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target)
Definition: esp_xtensa.c:82
int esp_xtensa_on_halt(struct target *target)
Definition: esp_xtensa.c:58
static struct esp_xtensa_common * target_to_esp_xtensa(struct target *target)
Definition: esp_xtensa.h:24
int esp_xtensa_semihosting_init(struct target *target)
int esp_xtensa_semihosting(struct target *target, int *retval)
Checks and processes an ESP Xtensa semihosting request.
int esp_xtensa_smp_run_onboard_func(struct target *target, struct esp_algorithm_run_data *run, uint32_t func_addr, uint32_t num_args,...)
int esp_xtensa_smp_init_arch_info(struct target *target, struct esp_xtensa_smp_common *esp_xtensa_smp, struct xtensa_debug_module_config *dm_cfg, const struct esp_xtensa_smp_chip_ops *chip_ops, const struct esp_semihost_ops *semihost_ops)
const struct command_registration esp_xtensa_smp_command_handlers[]
#define ESP_XTENSA_SMP_EXAMINE_OTHER_CORES
static int esp_xtensa_smp_update_halt_gdb(struct target *target, bool *need_resume)
COMMAND_HANDLER(esp_xtensa_smp_cmd_xtdef)
int esp_xtensa_smp_soft_reset_halt(struct target *target)
int esp_xtensa_smp_deassert_reset(struct target *target)
const struct command_registration esp_xtensa_smp_xtensa_command_handlers[]
int esp_xtensa_smp_step(struct target *target, int current, target_addr_t address, int handle_breakpoints)
static int esp_xtensa_smp_resume_cores(struct target *target, int handle_breakpoints, int debug_execution)
static struct esp_xtensa_smp_common * target_to_esp_xtensa_smp(struct target *target)
static int esp_xtensa_smp_smpbreak_disable(struct target *target, uint32_t *smp_break)
int esp_xtensa_smp_watchpoint_remove(struct target *target, struct watchpoint *watchpoint)
int esp_xtensa_smp_run_func_image(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args,...)
static int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_t smp_break)
int esp_xtensa_smp_target_init(struct command_context *cmd_ctx, struct target *target)
int esp_xtensa_smp_on_halt(struct target *target)
int esp_xtensa_smp_watchpoint_add(struct target *target, struct watchpoint *watchpoint)
int esp_xtensa_smp_assert_reset(struct target *target)
int esp_xtensa_smp_poll(struct target *target)
int esp_xtensa_smp_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution)
static struct target * get_halted_esp_xtensa_smp(struct target *target, int32_t coreid)
#define list_first_entry(ptr, type, member)
Definition: list.h:127
#define LOG_TARGET_INFO(target, fmt_str,...)
Definition: log.h:152
#define ERROR_FAIL
Definition: log.h:170
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:158
#define LOG_TARGET_DEBUG(target, fmt_str,...)
Definition: log.h:149
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_INFO(expr ...)
Definition: log.h:126
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__((unused))
Definition: opcodes.h:117
struct target * target
Definition: rtt/rtt.c:26
@ SEMIHOSTING_HANDLED
#define foreach_smp_target(pos, head)
Definition: smp.h:15
const char * name
Definition: command.h:235
Algorithm run data.
struct esp_dbg_stubs dbg_stubs
Definition: esp.h:81
uint32_t base
Address.
Definition: esp.h:70
Semihost calls handling operations.
struct esp_semihost_data semihost
Definition: esp_xtensa.h:20
struct esp_common esp
Definition: esp_xtensa.h:19
int(* poll)(struct target *target)
int(* on_halt)(struct target *target)
int(* reset)(struct target *target)
struct esp_xtensa_common esp_xtensa
const struct esp_xtensa_smp_chip_ops * chip_ops
int32_t core[2]
Definition: target.h:100
struct target * target
Definition: target.h:95
struct target * target
Definition: target.h:214
Definition: target.h:116
int32_t coreid
Definition: target.h:120
struct gdb_service * gdb_service
Definition: target.h:199
enum target_debug_reason debug_reason
Definition: target.h:154
enum target_state state
Definition: target.h:157
struct list_head * smp_targets
Definition: target.h:188
unsigned int smp
Definition: target.h:187
void * arch_info
Definition: target.h:164
uint64_t mask
Definition: breakpoints.h:44
enum watchpoint_rw rw
Definition: breakpoints.h:46
unsigned int length
Definition: breakpoints.h:43
uint64_t value
Definition: breakpoints.h:45
target_addr_t address
Definition: breakpoints.h:42
int target_call_event_callbacks(struct target *target, enum target_event event)
Definition: target.c:1764
int target_examine_one(struct target *target)
Examine the specified target, letting it perform any Initialisation that requires JTAG access.
Definition: target.c:672
struct target * get_current_target(struct command_context *cmd_ctx)
Definition: target.c:458
int target_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution)
Make the target (re)start executing using its saved execution context (possibly with some modificatio...
Definition: target.c:556
@ DBG_REASON_NOTHALTED
Definition: target.h:74
static bool target_was_examined(const struct target *target)
Definition: target.h:436
@ TARGET_EVENT_HALTED
Definition: target.h:252
@ TARGET_EVENT_RESUMED
Definition: target.h:253
@ TARGET_EVENT_DEBUG_HALTED
Definition: target.h:271
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233
target_state
Definition: target.h:53
@ TARGET_RESET
Definition: target.h:57
@ TARGET_DEBUG_RUNNING
Definition: target.h:58
@ TARGET_HALTED
Definition: target.h:56
@ TARGET_RUNNING
Definition: target.h:55
uint64_t target_addr_t
Definition: types.h:335
#define container_of(ptr, type, member)
Cast a member of a structure out to the containing structure.
Definition: types.h:68
#define NULL
Definition: usb.h:16
int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint)
Definition: xtensa.c:2646
int xtensa_prepare_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution)
Definition: xtensa.c:1593
int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints)
Definition: xtensa.c:1944
int xtensa_smpbreak_set(struct target *target, uint32_t set)
Definition: xtensa.c:944
int xtensa_examine(struct target *target)
Definition: xtensa.c:886
int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint)
Definition: xtensa.c:2702
int xtensa_smpbreak_get(struct target *target, uint32_t *val)
Definition: xtensa.c:968
int xtensa_do_resume(struct target *target)
Definition: xtensa.c:1656
int xtensa_deassert_reset(struct target *target)
Definition: xtensa.c:1182
int xtensa_assert_reset(struct target *target)
Definition: xtensa.c:1161
static struct xtensa * target_to_xtensa(struct target *target)
Definition: xtensa.h:291