target/espressif: add algorithm support to execute code on target
[openocd.git] / src / target / espressif / esp32_apptrace.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * ESP32xx application tracing module for OpenOCD *
5 * Copyright (C) 2017 Espressif Systems Ltd. *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #ifdef HAVE_ARPA_INET_H
13 #include <arpa/inet.h>
14 #endif
15
16 #ifdef HAVE_NETDB_H
17 #include <netdb.h>
18 #endif
19
20 #ifndef _WIN32
21 #include <netinet/tcp.h>
22 #include <sys/ioctl.h>
23 #endif
24
25 #include <helper/list.h>
26 #include <helper/time_support.h>
27 #include <target/target.h>
28 #include <target/target_type.h>
29 #include <target/smp.h>
30 #include <server/server.h>
31 #include "esp_xtensa.h"
32 #include "esp_xtensa_smp.h"
33 #include "esp_xtensa_apptrace.h"
34 #include "esp32_apptrace.h"
35 #include "esp32_sysview.h"
36 #include "segger_sysview.h"
37
38 #define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15)
39 #define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15))
40
41 #define ESP32_APPTRACE_USER_BLOCK_HDR_SZ 4
42
43 #define ESP_APPTRACE_CMD_MODE_GEN 0
44 #define ESP_APPTRACE_CMD_MODE_SYSVIEW 1
45 #define ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE 2
46 #define ESP_APPTRACE_CMD_MODE_SYNC 3
47
48 #define ESP32_APPTRACE_TGT_STATE_TMO 5000
49 #define ESP_APPTRACE_BLOCKS_POOL_SZ 10
50
51 struct esp32_apptrace_dest_file_data {
52 int fout;
53 };
54
55 struct esp32_apptrace_dest_tcp_data {
56 int sockfd;
57 };
58
59 struct esp32_apptrace_target_state {
60 int running;
61 uint32_t block_id;
62 uint32_t data_len;
63 };
64
65 struct esp_apptrace_target2host_hdr {
66 uint16_t block_sz;
67 uint16_t wr_sz;
68 };
69 #define APPTRACE_BLOCK_SIZE_OFFSET 0
70 #define APPTRACE_WR_SIZE_OFFSET 2
71
72 struct esp32_apptrace_block {
73 struct list_head node;
74 uint8_t *data;
75 uint32_t data_len;
76 };
77
78 static int esp32_apptrace_data_processor(void *priv);
79 static int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx,
80 struct esp32_apptrace_target_state *target_state,
81 uint32_t *fired_target_num);
82 static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx,
83 struct esp32_apptrace_target_state *targets);
84 static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx);
85 static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx,
86 struct esp32_apptrace_block *block);
87 static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx);
88 static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx);
89
90 static const bool s_time_stats_enable = true;
91
92 /*********************************************************************
93 * Trace destination API
94 **********************************************************************/
95
96 static int esp32_apptrace_file_dest_write(void *priv, uint8_t *data, int size)
97 {
98 struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv;
99
100 int wr_sz = write(dest_data->fout, data, size);
101 if (wr_sz != size) {
102 LOG_ERROR("Failed to write %d bytes to out file (%d)! Written %d.", size, errno, wr_sz);
103 return ERROR_FAIL;
104 }
105 return ERROR_OK;
106 }
107
108 static int esp32_apptrace_file_dest_cleanup(void *priv)
109 {
110 struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv;
111
112 if (dest_data->fout > 0)
113 close(dest_data->fout);
114 free(dest_data);
115 return ERROR_OK;
116 }
117
118 static int esp32_apptrace_file_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name)
119 {
120 struct esp32_apptrace_dest_file_data *dest_data = calloc(1, sizeof(*dest_data));
121 if (!dest_data) {
122 LOG_ERROR("Failed to alloc mem for file dest!");
123 return ERROR_FAIL;
124 }
125
126 LOG_INFO("Open file %s", dest_name);
127 dest_data->fout = open(dest_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
128 if (dest_data->fout <= 0) {
129 LOG_ERROR("Failed to open file %s", dest_name);
130 free(dest_data);
131 return ERROR_FAIL;
132 }
133
134 dest->priv = dest_data;
135 dest->write = esp32_apptrace_file_dest_write;
136 dest->clean = esp32_apptrace_file_dest_cleanup;
137 dest->log_progress = true;
138
139 return ERROR_OK;
140 }
141
142 static int esp32_apptrace_console_dest_write(void *priv, uint8_t *data, int size)
143 {
144 LOG_USER_N("%.*s", size, data);
145 return ERROR_OK;
146 }
147
148 static int esp32_apptrace_console_dest_cleanup(void *priv)
149 {
150 return ERROR_OK;
151 }
152
153 static int esp32_apptrace_console_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name)
154 {
155 dest->priv = NULL;
156 dest->write = esp32_apptrace_console_dest_write;
157 dest->clean = esp32_apptrace_console_dest_cleanup;
158 dest->log_progress = false;
159
160 return ERROR_OK;
161 }
162
163 static int esp32_apptrace_tcp_dest_write(void *priv, uint8_t *data, int size)
164 {
165 struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv;
166 int wr_sz = write_socket(dest_data->sockfd, data, size);
167 if (wr_sz != size) {
168 LOG_ERROR("Failed to write %u bytes to out socket (%d)! Written %d.", size, errno, wr_sz);
169 return ERROR_FAIL;
170 }
171 return ERROR_OK;
172 }
173
174 static int esp32_apptrace_tcp_dest_cleanup(void *priv)
175 {
176 struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv;
177
178 if (dest_data->sockfd > 0)
179 close_socket(dest_data->sockfd);
180 free(dest_data);
181 return ERROR_OK;
182 }
183
184 static int esp32_apptrace_tcp_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name)
185 {
186 const char *port_sep = strchr(dest_name, ':');
187 /* separator not found, or was the first or the last character */
188 if (!port_sep || port_sep == dest_name || port_sep == dest_name + strlen(dest_name) - 1) {
189 LOG_ERROR("apptrace: Invalid connection URI, format should be tcp://host:port");
190 return ERROR_COMMAND_ARGUMENT_INVALID;
191 }
192 size_t hostname_len = port_sep - dest_name;
193
194 char hostname[64] = { 0 };
195 if (hostname_len >= sizeof(hostname)) {
196 LOG_ERROR("apptrace: Hostname too long");
197 return ERROR_COMMAND_ARGUMENT_INVALID;
198 }
199 memcpy(hostname, dest_name, hostname_len);
200
201 const char *port_str = port_sep + 1;
202 struct addrinfo *ai;
203 int flags = 0;
204 #ifdef AI_NUMERICSERV
205 flags |= AI_NUMERICSERV;
206 #endif /* AI_NUMERICSERV */
207 struct addrinfo hint = {
208 .ai_family = AF_UNSPEC,
209 .ai_socktype = SOCK_STREAM,
210 .ai_protocol = 0,
211 .ai_flags = flags
212 };
213 int res = getaddrinfo(hostname, port_str, &hint, &ai);
214 if (res != 0) {
215 LOG_ERROR("apptrace: Failed to resolve host name: %s", hostname);
216 return ERROR_FAIL;
217 }
218 int sockfd = -1;
219 for (struct addrinfo *ai_it = ai; ai_it; ai_it = ai_it->ai_next) {
220 sockfd = socket(ai_it->ai_family, ai_it->ai_socktype, ai_it->ai_protocol);
221 if (sockfd < 0) {
222 LOG_DEBUG("apptrace: Failed to create socket (%d, %d, %d) (%s)",
223 ai_it->ai_family,
224 ai_it->ai_socktype,
225 ai_it->ai_protocol,
226 strerror(errno));
227 continue;
228 }
229
230 char cur_hostname[NI_MAXHOST];
231 char cur_portname[NI_MAXSERV];
232 res =
233 getnameinfo(ai_it->ai_addr, ai_it->ai_addrlen, cur_hostname,
234 sizeof(cur_hostname),
235 cur_portname, sizeof(cur_portname),
236 NI_NUMERICHOST | NI_NUMERICSERV);
237 if (res != 0)
238 continue;
239
240 LOG_INFO("apptrace: Trying to connect to %s:%s", cur_hostname, cur_portname);
241 if (connect(sockfd, ai_it->ai_addr, ai_it->ai_addrlen) < 0) {
242 close_socket(sockfd);
243 sockfd = -1;
244 LOG_WARNING("apptrace: Connection failed (%s)", strerror(errno));
245 continue;
246 }
247 break;
248 }
249 freeaddrinfo(ai);
250 if (sockfd < 0) {
251 LOG_ERROR("apptrace: Could not connect to %s:%s", hostname, port_str);
252 return ERROR_FAIL;
253 }
254 LOG_INFO("apptrace: Connected!");
255
256 struct esp32_apptrace_dest_tcp_data *dest_data = calloc(1, sizeof(struct esp32_apptrace_dest_tcp_data));
257 if (!dest_data) {
258 LOG_ERROR("apptrace: Failed to alloc mem for tcp dest!");
259 close_socket(sockfd);
260 return ERROR_FAIL;
261 }
262
263 dest_data->sockfd = sockfd;
264 dest->priv = dest_data;
265 dest->write = esp32_apptrace_tcp_dest_write;
266 dest->clean = esp32_apptrace_tcp_dest_cleanup;
267 dest->log_progress = true;
268
269 return ERROR_OK;
270 }
271
272 int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests)
273 {
274 int res;
275 unsigned int i;
276
277 for (i = 0; i < max_dests; i++) {
278 if (strncmp(dest_paths[i], "file://", 7) == 0)
279 res = esp32_apptrace_file_dest_init(&dest[i], &dest_paths[i][7]);
280 else if (strncmp(dest_paths[i], "con:", 4) == 0)
281 res = esp32_apptrace_console_dest_init(&dest[i], NULL);
282 else if (strncmp(dest_paths[i], "tcp://", 6) == 0)
283 res = esp32_apptrace_tcp_dest_init(&dest[i], &dest_paths[i][6]);
284 else
285 break;
286
287 if (res != ERROR_OK) {
288 LOG_ERROR("apptrace: Failed to init trace data destination '%s'!", dest_paths[i]);
289 return 0;
290 }
291 }
292
293 return i;
294 }
295
296 int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests)
297 {
298 for (unsigned int i = 0; i < max_dests; i++) {
299 if (dest[i].clean && dest[i].priv) {
300 int res = dest[i].clean(dest[i].priv);
301 dest[i].priv = NULL;
302 return res;
303 }
304 }
305 return ERROR_OK;
306 }
307
308 /*********************************************************************
309 * Trace data blocks management API
310 **********************************************************************/
311 static void esp32_apptrace_blocks_pool_cleanup(struct esp32_apptrace_cmd_ctx *ctx)
312 {
313 struct esp32_apptrace_block *cur;
314 struct list_head *head = &ctx->free_trace_blocks;
315 struct list_head *tmp, *pos;
316
317 list_for_each_safe(pos, tmp, head) {
318 cur = list_entry(pos, struct esp32_apptrace_block, node);
319 if (cur) {
320 list_del(&cur->node);
321 free(cur->data);
322 free(cur);
323 }
324 }
325
326 head = &ctx->ready_trace_blocks;
327
328 list_for_each_safe(pos, tmp, head) {
329 cur = list_entry(pos, struct esp32_apptrace_block, node);
330 if (cur) {
331 list_del(&cur->node);
332 free(cur->data);
333 free(cur);
334 }
335 }
336 }
337
338 struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx)
339 {
340 struct esp32_apptrace_block *block = NULL;
341
342 if (!list_empty(&ctx->free_trace_blocks)) {
343 /*get first */
344 block = list_first_entry(&ctx->free_trace_blocks, struct esp32_apptrace_block, node);
345 list_del(&block->node);
346 }
347
348 return block;
349 }
350
351 static int esp32_apptrace_ready_block_put(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block)
352 {
353 LOG_DEBUG("esp32_apptrace_ready_block_put");
354 /* add to ready blocks list */
355 INIT_LIST_HEAD(&block->node);
356 list_add(&block->node, &ctx->ready_trace_blocks);
357
358 return ERROR_OK;
359 }
360
361 static struct esp32_apptrace_block *esp32_apptrace_ready_block_get(struct esp32_apptrace_cmd_ctx *ctx)
362 {
363 if (list_empty(&ctx->ready_trace_blocks))
364 return NULL;
365
366 struct esp32_apptrace_block *block =
367 list_last_entry(&ctx->ready_trace_blocks, struct esp32_apptrace_block, node);
368
369 /* remove it from ready list */
370 list_del(&block->node);
371
372 return block;
373 }
374
375 static int esp32_apptrace_block_free(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block)
376 {
377 /* add to free blocks list */
378 INIT_LIST_HEAD(&block->node);
379 list_add(&block->node, &ctx->free_trace_blocks);
380
381 return ERROR_OK;
382 }
383
384 static int esp32_apptrace_wait_tracing_finished(struct esp32_apptrace_cmd_ctx *ctx)
385 {
386 int64_t timeout = timeval_ms() + (LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 70000 : 5000);
387 while (!list_empty(&ctx->ready_trace_blocks)) {
388 alive_sleep(100);
389 if (timeval_ms() >= timeout) {
390 LOG_ERROR("Failed to wait for pended trace blocks!");
391 return ERROR_FAIL;
392 }
393 }
394 /* signal timer callback to stop */
395 ctx->running = 0;
396 target_unregister_timer_callback(esp32_apptrace_data_processor, ctx);
397 return ERROR_OK;
398 }
399
400 /*********************************************************************
401 * Trace commands
402 **********************************************************************/
403
404 int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode)
405 {
406 struct target *target = get_current_target(CMD_CTX);
407
408 memset(cmd_ctx, 0, sizeof(struct esp32_apptrace_cmd_ctx));
409 cmd_ctx->target = target;
410 cmd_ctx->mode = mode;
411 cmd_ctx->target_state = target->state;
412 cmd_ctx->cmd = cmd;
413
414 if (target->smp) {
415 struct target_list *head;
416 struct target *curr;
417 unsigned int i = 0;
418 cmd_ctx->cores_num = 0;
419 foreach_smp_target(head, target->smp_targets) {
420 curr = head->target;
421 if (i == ESP32_APPTRACE_MAX_CORES_NUM) {
422 command_print(cmd, "Too many cores configured! Max %d cores are supported.",
423 ESP32_APPTRACE_MAX_CORES_NUM);
424 return ERROR_FAIL;
425 }
426 if (!target_was_examined(curr))
427 continue;
428 cmd_ctx->cores_num++;
429 cmd_ctx->cpus[i++] = curr;
430 }
431 } else {
432 cmd_ctx->cores_num = 1;
433 cmd_ctx->cpus[0] = target;
434 }
435 /* some relies on ESP32_APPTRACE_MAX_CORES_NUM
436 * TODO: remove that dependency */
437 assert(cmd_ctx->cores_num <= ESP32_APPTRACE_MAX_CORES_NUM && "Too many cores number!");
438
439 struct xtensa *xtensa = target->arch_info;
440 if (xtensa->common_magic == XTENSA_COMMON_MAGIC) {
441 cmd_ctx->hw = target_to_esp_xtensa(target)->apptrace.hw;
442 } else { /* TODO: riscv is not supported yet */
443 command_print(cmd, "Unsupported target arch 0x%X", xtensa->common_magic);
444 return ERROR_FAIL;
445 }
446
447 cmd_ctx->max_trace_block_sz = cmd_ctx->hw->max_block_size_get(cmd_ctx->cpus[0]);
448 if (cmd_ctx->max_trace_block_sz == 0) {
449 command_print(cmd, "Failed to get max trace block size!");
450 return ERROR_FAIL;
451 }
452 LOG_INFO("Total trace memory: %" PRIu32 " bytes", cmd_ctx->max_trace_block_sz);
453
454 INIT_LIST_HEAD(&cmd_ctx->ready_trace_blocks);
455 INIT_LIST_HEAD(&cmd_ctx->free_trace_blocks);
456 for (unsigned int i = 0; i < ESP_APPTRACE_BLOCKS_POOL_SZ; i++) {
457 struct esp32_apptrace_block *block = calloc(1, sizeof(struct esp32_apptrace_block));
458 if (!block) {
459 command_print(cmd, "Failed to alloc trace buffer entry!");
460 esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
461 return ERROR_FAIL;
462 }
463 block->data = malloc(cmd_ctx->max_trace_block_sz);
464 if (!block->data) {
465 free(block);
466 command_print(cmd, "Failed to alloc trace buffer %" PRIu32 " bytes!", cmd_ctx->max_trace_block_sz);
467 esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
468 return ERROR_FAIL;
469 }
470 INIT_LIST_HEAD(&block->node);
471 list_add(&block->node, &cmd_ctx->free_trace_blocks);
472 }
473
474 cmd_ctx->running = 1;
475 if (cmd_ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) {
476 int res = target_register_timer_callback(esp32_apptrace_data_processor,
477 0,
478 TARGET_TIMER_TYPE_PERIODIC,
479 cmd_ctx);
480 if (res != ERROR_OK) {
481 command_print(cmd, "Failed to start trace data timer callback (%d)!", res);
482 esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
483 return ERROR_FAIL;
484 }
485 }
486
487 if (s_time_stats_enable) {
488 cmd_ctx->stats.min_blk_read_time = 1000000.0;
489 cmd_ctx->stats.min_blk_proc_time = 1000000.0;
490 }
491 if (duration_start(&cmd_ctx->idle_time) != 0) {
492 command_print(cmd, "Failed to start idle time measurement!");
493 esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
494 return ERROR_FAIL;
495 }
496
497 return ERROR_OK;
498 }
499
500 int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx)
501 {
502 esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
503 return ERROR_OK;
504 }
505
506 #define ESP32_APPTRACE_CMD_NUM_ARG_CHECK(_cmd_, _arg_, _start_, _end_) \
507 do { \
508 if ((_arg_) == 0 && (_start_) == (_end_)) { \
509 command_print(_cmd_, "Invalid '" # _arg_ "' arg!"); \
510 return; \
511 } \
512 } while (0)
513
514 void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx,
515 struct esp32_apptrace_cmd_data *cmd_data,
516 const char **argv,
517 int argc)
518 {
519 char *end;
520
521 cmd_data->poll_period = strtoul(argv[0], &end, 10);
522 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->poll_period, argv[0], end);
523 if (argc > 1) {
524 cmd_data->max_len = strtoul(argv[1], &end, 10);
525 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->max_len, argv[1], end);
526 if (argc > 2) {
527 int32_t tmo = strtol(argv[2], &end, 10);
528 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, tmo, argv[2], end);
529 cmd_ctx->stop_tmo = 1.0 * tmo;
530 if (argc > 3) {
531 cmd_data->wait4halt = strtoul(argv[3], &end, 10);
532 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->wait4halt, argv[3], end);
533 if (argc > 4) {
534 cmd_data->skip_len = strtoul(argv[4], &end, 10);
535 ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->skip_len, argv[4], end);
536 }
537 }
538 }
539 }
540 }
541
542 static int esp32_apptrace_core_id_get(struct target *target, uint8_t *hdr_buf)
543 {
544 return ESP32_APPTRACE_USER_BLOCK_CORE(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET));
545 }
546
547 static uint32_t esp32_apptrace_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len)
548 {
549 *wr_len = ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_WR_SIZE_OFFSET));
550 return ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET));
551 }
552
553 static int esp32_apptrace_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
554 struct command_invocation *cmd,
555 int mode,
556 const char **argv,
557 int argc)
558 {
559 struct esp32_apptrace_cmd_data *cmd_data;
560
561 if (argc < 1) {
562 command_print(cmd, "Not enough args! Need trace data destination!");
563 return ERROR_FAIL;
564 }
565
566 int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode);
567 if (res != ERROR_OK)
568 return res;
569
570 cmd_data = calloc(1, sizeof(*cmd_data));
571 assert(cmd_data && "No memory for command data!");
572 cmd_ctx->cmd_priv = cmd_data;
573
574 /*outfile1 [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */
575 res = esp32_apptrace_dest_init(&cmd_data->data_dest, argv, 1);
576 if (res != 1) { /* only one destination needs to be initialized */
577 command_print(cmd, "Wrong args! Needs a trace data destination!");
578 free(cmd_data);
579 goto on_error;
580 }
581 cmd_ctx->stop_tmo = -1.0; /* infinite */
582 cmd_data->max_len = UINT32_MAX;
583 cmd_data->poll_period = 0 /*ms*/;
584 if (argc > 1)
585 /* parse remaining args */
586 esp32_apptrace_cmd_args_parse(cmd_ctx, cmd_data, &argv[1], argc - 1);
587
588 LOG_USER("App trace params: from %d cores, size %" PRId32 " bytes, stop_tmo %g s, poll period %" PRId32
589 " ms, wait_rst %d, skip %" PRId32 " bytes", cmd_ctx->cores_num,
590 cmd_data->max_len,
591 cmd_ctx->stop_tmo,
592 cmd_data->poll_period,
593 cmd_data->wait4halt,
594 cmd_data->skip_len);
595
596 cmd_ctx->trace_format.hdr_sz = ESP32_APPTRACE_USER_BLOCK_HDR_SZ;
597 cmd_ctx->trace_format.core_id_get = esp32_apptrace_core_id_get;
598 cmd_ctx->trace_format.usr_block_len_get = esp32_apptrace_usr_block_len_get;
599 return ERROR_OK;
600 on_error:
601 command_print(cmd, "Not enough args! Need %d trace data destinations!", cmd_ctx->cores_num);
602 cmd_ctx->running = 0;
603 esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
604 return res;
605 }
606
607 static int esp32_apptrace_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx)
608 {
609 struct esp32_apptrace_cmd_data *cmd_data = cmd_ctx->cmd_priv;
610
611 esp32_apptrace_dest_cleanup(&cmd_data->data_dest, 1);
612 free(cmd_data);
613 cmd_ctx->cmd_priv = NULL;
614 esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
615 return ERROR_OK;
616 }
617
618 static void esp32_apptrace_print_stats(struct esp32_apptrace_cmd_ctx *ctx)
619 {
620 struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv;
621 uint32_t trace_sz = 0;
622
623 if (cmd_data)
624 trace_sz = ctx->tot_len > cmd_data->skip_len ? ctx->tot_len - cmd_data->skip_len : 0;
625 LOG_USER("Tracing is %s. Size is %" PRId32 " of %" PRId32 " @ %f (%f) KiB/s",
626 !ctx->running ? "STOPPED" : "RUNNING",
627 trace_sz,
628 cmd_data ? cmd_data->max_len : 0,
629 duration_kbps(&ctx->read_time, ctx->tot_len),
630 duration_kbps(&ctx->read_time, ctx->raw_tot_len));
631 LOG_USER("Data: blocks incomplete %" PRId32 ", lost bytes: %" PRId32,
632 ctx->stats.incompl_blocks,
633 ctx->stats.lost_bytes);
634 if (s_time_stats_enable) {
635 LOG_USER("Block read time [%f..%f] ms",
636 1000 * ctx->stats.min_blk_read_time,
637 1000 * ctx->stats.max_blk_read_time);
638 LOG_USER("Block proc time [%f..%f] ms",
639 1000 * ctx->stats.min_blk_proc_time,
640 1000 * ctx->stats.max_blk_proc_time);
641 }
642 }
643
644 static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx *ctx, struct target *target)
645 {
646 LOG_USER("Wait for halt...");
647 while (!openocd_is_shutdown_pending()) {
648 int res = target_poll(target);
649 if (res != ERROR_OK)
650 return res;
651 if (target->state == TARGET_HALTED) {
652 LOG_USER("%s: HALTED", target->cmd_name);
653 break;
654 }
655 alive_sleep(500);
656 }
657 return ERROR_OK;
658 }
659
660 int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx,
661 struct esp32_apptrace_target_state *targets)
662 {
663 int res = ERROR_OK;
664
665 memset(targets, 0, ctx->cores_num * sizeof(struct esp32_apptrace_target_state));
666 /* halt all CPUs */
667 LOG_DEBUG("Halt all targets!");
668 for (unsigned int k = 0; k < ctx->cores_num; k++) {
669 if (!target_was_examined(ctx->cpus[k]))
670 continue;
671 if (ctx->cpus[k]->state == TARGET_HALTED)
672 continue;
673 res = target_halt(ctx->cpus[k]);
674 if (res != ERROR_OK) {
675 LOG_ERROR("Failed to halt target (%d)!", res);
676 return res;
677 }
678 res = target_wait_state(ctx->cpus[k], TARGET_HALTED, ESP32_APPTRACE_TGT_STATE_TMO);
679 if (res != ERROR_OK) {
680 LOG_ERROR("Failed to wait halt target %s / %d (%d)!",
681 target_name(ctx->cpus[k]),
682 ctx->cpus[k]->state,
683 res);
684 return res;
685 }
686 }
687 /* read current block statuses from CPUs */
688 LOG_DEBUG("Read current block statuses");
689 for (unsigned int k = 0; k < ctx->cores_num; k++) {
690 uint32_t stat;
691 res = ctx->hw->status_reg_read(ctx->cpus[k], &stat);
692 if (res != ERROR_OK) {
693 LOG_ERROR("Failed to read trace status (%d)!", res);
694 return res;
695 }
696 /* check if some CPU stopped inside tracing regs update critical section */
697 if (stat) {
698 if (ctx->hw->leave_trace_crit_section_start) {
699 res = ctx->hw->leave_trace_crit_section_start(ctx->cpus[k]);
700 if (res != ERROR_OK)
701 return res;
702 }
703 uint32_t bp_addr = stat;
704 res = breakpoint_add(ctx->cpus[k], bp_addr, 1, BKPT_HARD);
705 if (res != ERROR_OK) {
706 LOG_ERROR("Failed to set breakpoint (%d)!", res);
707 return res;
708 }
709 while (stat) {
710 /* allow this CPU to leave ERI write critical section */
711 res = target_resume(ctx->cpus[k], 1, 0, 1, 0);
712 if (res != ERROR_OK) {
713 LOG_ERROR("Failed to resume target (%d)!", res);
714 breakpoint_remove(ctx->cpus[k], bp_addr);
715 return res;
716 }
717 /* wait for CPU to be halted on BP */
718 enum target_debug_reason debug_reason = DBG_REASON_UNDEFINED;
719 while (debug_reason != DBG_REASON_BREAKPOINT) {
720 res = target_wait_state(ctx->cpus[k], TARGET_HALTED,
721 ESP32_APPTRACE_TGT_STATE_TMO);
722 if (res != ERROR_OK) {
723 LOG_ERROR("Failed to wait halt on bp (%d)!", res);
724 breakpoint_remove(ctx->cpus[k], bp_addr);
725 return res;
726 }
727 debug_reason = ctx->cpus[k]->debug_reason;
728 }
729 res = ctx->hw->status_reg_read(ctx->cpus[k], &stat);
730 if (res != ERROR_OK) {
731 LOG_ERROR("Failed to read trace status (%d)!", res);
732 breakpoint_remove(ctx->cpus[k], bp_addr);
733 return res;
734 }
735 }
736 breakpoint_remove(ctx->cpus[k], bp_addr);
737 if (ctx->hw->leave_trace_crit_section_stop) {
738 res = ctx->hw->leave_trace_crit_section_stop(ctx->cpus[k]);
739 if (res != ERROR_OK)
740 return res;
741 }
742 }
743 res = ctx->hw->data_len_read(ctx->cpus[k], &targets[k].block_id, &targets[k].data_len);
744 if (res != ERROR_OK) {
745 LOG_ERROR("Failed to read trace status (%d)!", res);
746 return res;
747 }
748 }
749
750 return ERROR_OK;
751 }
752
753 static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx *ctx,
754 bool conn,
755 bool resume_target)
756 {
757 struct esp32_apptrace_target_state target_to_connect[ESP32_APPTRACE_MAX_CORES_NUM];
758
759 if (conn)
760 LOG_USER("Connect targets...");
761 else
762 LOG_USER("Disconnect targets...");
763
764 int res = esp32_apptrace_safe_halt_targets(ctx, target_to_connect);
765 if (res != ERROR_OK) {
766 command_print(ctx->cmd, "Failed to halt targets (%d)!", res);
767 return res;
768 }
769 if (ctx->cores_num > 1) {
770 /* set block ids to the highest value */
771 uint32_t max_id = 0;
772 for (unsigned int k = 0; k < ctx->cores_num; k++) {
773 if (target_to_connect[k].block_id > max_id)
774 max_id = target_to_connect[k].block_id;
775 }
776 for (unsigned int k = 0; k < ctx->cores_num; k++)
777 target_to_connect[k].block_id = max_id;
778 }
779 for (unsigned int k = 0; k < ctx->cores_num; k++) {
780 /* update host connected status */
781 res = ctx->hw->ctrl_reg_write(ctx->cpus[k],
782 target_to_connect[k].block_id,
783 0 /*ack target data*/,
784 conn,
785 false /*no host data*/);
786 if (res != ERROR_OK) {
787 command_print(ctx->cmd, "Failed to read trace status (%d)!", res);
788 return res;
789 }
790 }
791 if (resume_target) {
792 LOG_DEBUG("Resume targets");
793 bool smp_resumed = false;
794 for (unsigned int k = 0; k < ctx->cores_num; k++) {
795 if (smp_resumed && ctx->cpus[k]->smp) {
796 /* in SMP mode we need to call target_resume for one core only */
797 continue;
798 }
799 res = target_resume(ctx->cpus[k], 1, 0, 1, 0);
800 if (res != ERROR_OK) {
801 command_print(ctx->cmd, "Failed to resume target (%d)!", res);
802 return res;
803 }
804 if (ctx->cpus[k]->smp)
805 smp_resumed = true;
806 }
807 }
808 if (conn)
809 LOG_INFO("Targets connected.");
810 else
811 LOG_INFO("Targets disconnected.");
812 return ERROR_OK;
813 }
814
815 int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target,
816 uint32_t block_id,
817 const uint8_t *data,
818 uint32_t size)
819 {
820 struct esp_apptrace_host2target_hdr hdr = { .block_sz = size };
821 uint32_t buf_sz[2] = { sizeof(hdr), size };
822 const uint8_t *bufs[2] = { (const uint8_t *)&hdr, data };
823
824 if (size > hw->usr_block_max_size_get(target)) {
825 LOG_ERROR("Too large user block %" PRId32, size);
826 return ERROR_FAIL;
827 }
828
829 return hw->buffs_write(target,
830 ARRAY_SIZE(buf_sz),
831 buf_sz,
832 bufs,
833 block_id,
834 true /*ack target data*/,
835 true /*host data*/);
836 }
837
838 static uint32_t esp32_apptrace_usr_block_check(struct esp32_apptrace_cmd_ctx *ctx, uint8_t *hdr_buf)
839 {
840 uint32_t wr_len = 0;
841 uint32_t usr_len = ctx->trace_format.usr_block_len_get(ctx->target, hdr_buf, &wr_len);
842 if (usr_len != wr_len) {
843 LOG_ERROR("Incomplete block sz %" PRId32 ", wr %" PRId32, usr_len, wr_len);
844 ctx->stats.incompl_blocks++;
845 ctx->stats.lost_bytes += usr_len - wr_len;
846 }
847 return usr_len;
848 }
849
850 int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx,
851 struct esp32_apptrace_target_state *target_state,
852 uint32_t *fired_target_num)
853 {
854 if (fired_target_num)
855 *fired_target_num = UINT32_MAX;
856
857 for (unsigned int i = 0; i < ctx->cores_num; i++) {
858 int res = ctx->hw->data_len_read(ctx->cpus[i], &target_state[i].block_id, &target_state[i].data_len);
859 if (res != ERROR_OK) {
860 LOG_ERROR("Failed to read data len on (%s)!", target_name(ctx->cpus[i]));
861 return res;
862 }
863 if (target_state[i].data_len) {
864 LOG_TARGET_DEBUG(ctx->cpus[i], "Block %" PRId32 ", len %" PRId32 " bytes on fired",
865 target_state[i].block_id, target_state[i].data_len);
866 if (fired_target_num)
867 *fired_target_num = i;
868 break;
869 }
870 }
871 return ERROR_OK;
872 }
873
874 static int esp32_apptrace_process_data(struct esp32_apptrace_cmd_ctx *ctx,
875 unsigned int core_id,
876 uint8_t *data,
877 uint32_t data_len)
878 {
879 struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv;
880
881 LOG_DEBUG("Got block %" PRId32 " bytes [%x %x...%x %x]", data_len, data[12], data[13],
882 data[data_len - 2], data[data_len - 1]);
883 if (ctx->tot_len + data_len > cmd_data->skip_len) {
884 uint32_t wr_idx = 0, wr_chunk_len = data_len;
885 if (ctx->tot_len < cmd_data->skip_len) {
886 wr_chunk_len = (ctx->tot_len + wr_chunk_len) - cmd_data->skip_len;
887 wr_idx = cmd_data->skip_len - ctx->tot_len;
888 }
889 if (ctx->tot_len + wr_chunk_len > cmd_data->max_len)
890 wr_chunk_len -= (ctx->tot_len + wr_chunk_len - cmd_data->skip_len) - cmd_data->max_len;
891 if (wr_chunk_len > 0) {
892 int res = cmd_data->data_dest.write(cmd_data->data_dest.priv, data + wr_idx, wr_chunk_len);
893 if (res != ERROR_OK) {
894 LOG_ERROR("Failed to write %" PRId32 " bytes to dest 0!", data_len);
895 return res;
896 }
897 }
898 ctx->tot_len += wr_chunk_len;
899 } else {
900 ctx->tot_len += data_len;
901 }
902
903 if (cmd_data->data_dest.log_progress)
904 LOG_USER("%" PRId32 " ", ctx->tot_len);
905 /* check for stop condition */
906 if (ctx->tot_len > cmd_data->skip_len && (ctx->tot_len - cmd_data->skip_len >= cmd_data->max_len)) {
907 ctx->running = 0;
908 if (duration_measure(&ctx->read_time) != 0) {
909 LOG_ERROR("Failed to stop trace read time measure!");
910 return ERROR_FAIL;
911 }
912 }
913 return ERROR_OK;
914 }
915
916 static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx,
917 struct esp32_apptrace_block *block)
918 {
919 uint32_t processed = 0;
920 uint32_t hdr_sz = ctx->trace_format.hdr_sz;
921
922 LOG_DEBUG("Got block %" PRId32 " bytes", block->data_len);
923 /* process user blocks one by one */
924 while (processed < block->data_len) {
925 LOG_DEBUG("Process usr block %" PRId32 "/%" PRId32, processed, block->data_len);
926 /* process user block */
927 uint32_t usr_len = esp32_apptrace_usr_block_check(ctx, block->data + processed);
928 int core_id = ctx->trace_format.core_id_get(ctx->target, block->data + processed);
929 /* process user data */
930 int res = ctx->process_data(ctx, core_id, block->data + processed + hdr_sz, usr_len);
931 if (res != ERROR_OK) {
932 LOG_ERROR("Failed to process %" PRId32 " bytes!", usr_len);
933 return res;
934 }
935 processed += usr_len + hdr_sz;
936 }
937 return ERROR_OK;
938 }
939
940 static int esp32_apptrace_data_processor(void *priv)
941 {
942 struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv;
943
944 if (!ctx->running)
945 return ERROR_OK;
946
947 struct esp32_apptrace_block *block = esp32_apptrace_ready_block_get(ctx);
948 if (!block)
949 return ERROR_OK;
950
951 int res = esp32_apptrace_handle_trace_block(ctx, block);
952 if (res != ERROR_OK) {
953 ctx->running = 0;
954 LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
955 return res;
956 }
957 res = esp32_apptrace_block_free(ctx, block);
958 if (res != ERROR_OK) {
959 ctx->running = 0;
960 LOG_ERROR("Failed to free ready block!");
961 return res;
962 }
963
964 return ERROR_OK;
965 }
966
967 static int esp32_apptrace_check_connection(struct esp32_apptrace_cmd_ctx *ctx)
968 {
969 if (!ctx)
970 return ERROR_FAIL;
971
972 unsigned int busy_target_num = 0;
973
974 for (unsigned int i = 0; i < ctx->cores_num; i++) {
975 bool conn = true;
976 int res = ctx->hw->ctrl_reg_read(ctx->cpus[i], NULL, NULL, &conn);
977 if (res != ERROR_OK) {
978 LOG_ERROR("Failed to read apptrace control reg for cpu(%d) res(%d)!", i, res);
979 return res;
980 }
981 if (!conn) {
982 uint32_t stat = 0;
983 LOG_TARGET_WARNING(ctx->cpus[i], "apptrace connection is lost. Re-connect.");
984 res = ctx->hw->status_reg_read(ctx->cpus[i], &stat);
985 if (res != ERROR_OK) {
986 LOG_ERROR("Failed to read trace status (%d)!", res);
987 return res;
988 }
989 if (stat) {
990 LOG_TARGET_WARNING(ctx->cpus[i], "in critical state. Retry in next poll");
991 if (++busy_target_num == ctx->cores_num) {
992 LOG_WARNING("No available core");
993 return ERROR_WAIT;
994 }
995 continue;
996 }
997 res = ctx->hw->ctrl_reg_write(ctx->cpus[i],
998 0,
999 0,
1000 true /*host connected*/,
1001 false /*no host data*/);
1002 if (res != ERROR_OK) {
1003 LOG_ERROR("Failed to write apptrace control reg for cpu(%d) res(%d)!", i, res);
1004 return res;
1005 }
1006 if (ctx->stop_tmo != -1.0) {
1007 /* re-start idle time measurement */
1008 if (duration_start(&ctx->idle_time) != 0) {
1009 LOG_ERROR("Failed to re-start idle time measure!");
1010 return ERROR_FAIL;
1011 }
1012 }
1013 }
1014 }
1015
1016 return ERROR_OK;
1017 }
1018
1019 static int esp32_apptrace_poll(void *priv)
1020 {
1021 struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv;
1022 int res;
1023 uint32_t fired_target_num = 0;
1024 struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
1025 struct duration blk_proc_time;
1026
1027 if (!ctx->running) {
1028 if (ctx->auto_clean)
1029 ctx->auto_clean(ctx);
1030 return ERROR_FAIL;
1031 }
1032
1033 /* Check for connection is alive.For some reason target and therefore host_connected flag
1034 * might have been reset */
1035 res = esp32_apptrace_check_connection(ctx);
1036 if (res != ERROR_OK) {
1037 if (res != ERROR_WAIT)
1038 ctx->running = 0;
1039 return res;
1040 }
1041
1042 /* check for data from target */
1043 res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
1044 if (res != ERROR_OK) {
1045 ctx->running = 0;
1046 LOG_ERROR("Failed to read data len!");
1047 return res;
1048 }
1049 /* LOG_DEBUG("Block %d (%d bytes) on target (%s)!", target_state[0].block_id,
1050 * target_state[0].data_len, target_name(ctx->cpus[0])); */
1051 if (fired_target_num == UINT32_MAX) {
1052 /* no data has been received, but block could be switched due to the data transferred
1053 * from host to target */
1054 if (ctx->cores_num > 1) {
1055 uint32_t max_block_id = 0, min_block_id = ctx->hw->max_block_id;
1056 /* find maximum block ID and set the same ID in control reg for both cores
1057 * */
1058 for (unsigned int i = 0; i < ctx->cores_num; i++) {
1059 if (max_block_id < target_state[i].block_id)
1060 max_block_id = target_state[i].block_id;
1061 if (min_block_id > target_state[i].block_id)
1062 min_block_id = target_state[i].block_id;
1063 }
1064 /* handle block ID overflow */
1065 if (max_block_id == ctx->hw->max_block_id && min_block_id == 0)
1066 max_block_id = 0;
1067 for (unsigned int i = 0; i < ctx->cores_num; i++) {
1068 if (max_block_id != target_state[i].block_id) {
1069 LOG_TARGET_DEBUG(ctx->cpus[i], "Ack empty block %" PRId32 "!", max_block_id);
1070 res = ctx->hw->ctrl_reg_write(ctx->cpus[i],
1071 max_block_id,
1072 0 /*all read*/,
1073 true /*host connected*/,
1074 false /*no host data*/);
1075 if (res != ERROR_OK) {
1076 ctx->running = 0;
1077 LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack empty data block!");
1078 return res;
1079 }
1080 }
1081 }
1082 ctx->last_blk_id = max_block_id;
1083 }
1084 if (ctx->stop_tmo != -1.0) {
1085 if (duration_measure(&ctx->idle_time) != 0) {
1086 ctx->running = 0;
1087 LOG_ERROR("Failed to measure idle time!");
1088 return ERROR_FAIL;
1089 }
1090 if (duration_elapsed(&ctx->idle_time) >= ctx->stop_tmo) {
1091 ctx->running = 0;
1092 LOG_ERROR("Data timeout!");
1093 return ERROR_FAIL;
1094 }
1095 }
1096 return ERROR_OK;/* no data */
1097 }
1098 /* sanity check */
1099 if (target_state[fired_target_num].data_len > ctx->max_trace_block_sz) {
1100 ctx->running = 0;
1101 LOG_ERROR("Too large block size %" PRId32 "!", target_state[fired_target_num].data_len);
1102 return ERROR_FAIL;
1103 }
1104 if (ctx->tot_len == 0) {
1105 if (duration_start(&ctx->read_time) != 0) {
1106 ctx->running = 0;
1107 LOG_ERROR("Failed to start trace read time measurement!");
1108 return ERROR_FAIL;
1109 }
1110 }
1111 struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx);
1112 if (!block) {
1113 ctx->running = 0;
1114 LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to get free block for data!");
1115 return ERROR_FAIL;
1116 }
1117 if (s_time_stats_enable) {
1118 /* read block */
1119 if (duration_start(&blk_proc_time) != 0) {
1120 ctx->running = 0;
1121 LOG_ERROR("Failed to start block read time measurement!");
1122 return ERROR_FAIL;
1123 }
1124 }
1125 res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
1126 target_state[fired_target_num].block_id,
1127 /* do not ack target data in sync mode,
1128 esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */
1129 ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC);
1130 if (res != ERROR_OK) {
1131 ctx->running = 0;
1132 LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to read data!");
1133 return res;
1134 }
1135 ctx->last_blk_id = target_state[fired_target_num].block_id;
1136 block->data_len = target_state[fired_target_num].data_len;
1137 ctx->raw_tot_len += block->data_len;
1138 if (s_time_stats_enable) {
1139 if (duration_measure(&blk_proc_time) != 0) {
1140 ctx->running = 0;
1141 LOG_ERROR("Failed to measure block read time!");
1142 return ERROR_FAIL;
1143 }
1144 /* update stats */
1145 float brt = duration_elapsed(&blk_proc_time);
1146 if (brt > ctx->stats.max_blk_read_time)
1147 ctx->stats.max_blk_read_time = brt;
1148 if (brt < ctx->stats.min_blk_read_time)
1149 ctx->stats.min_blk_read_time = brt;
1150
1151 if (duration_start(&blk_proc_time) != 0) {
1152 ctx->running = 0;
1153 LOG_ERROR("Failed to start block proc time measurement!");
1154 return ERROR_FAIL;
1155 }
1156 }
1157 /* in sync mode do not ack target data on other cores, esp32_apptrace_handle_trace_block() can write response
1158 * data and will do ack thereafter */
1159 if (ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) {
1160 for (unsigned int i = 0; i < ctx->cores_num; i++) {
1161 if (i == fired_target_num)
1162 continue;
1163 res = ctx->hw->ctrl_reg_write(ctx->cpus[i],
1164 ctx->last_blk_id,
1165 0 /*all read*/,
1166 true /*host connected*/,
1167 false /*no host data*/);
1168 if (res != ERROR_OK) {
1169 ctx->running = 0;
1170 LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack data!");
1171 return res;
1172 }
1173 LOG_TARGET_DEBUG(ctx->cpus[i], "Ack block %" PRId32, ctx->last_blk_id);
1174 }
1175 res = esp32_apptrace_ready_block_put(ctx, block);
1176 if (res != ERROR_OK) {
1177 ctx->running = 0;
1178 LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to put ready block of data!");
1179 return res;
1180 }
1181 } else {
1182 res = esp32_apptrace_handle_trace_block(ctx, block);
1183 if (res != ERROR_OK) {
1184 ctx->running = 0;
1185 LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
1186 return res;
1187 }
1188 res = esp32_apptrace_block_free(ctx, block);
1189 if (res != ERROR_OK) {
1190 ctx->running = 0;
1191 LOG_ERROR("Failed to free ready block!");
1192 return res;
1193 }
1194 }
1195 if (ctx->stop_tmo != -1.0) {
1196 /* start idle time measurement */
1197 if (duration_start(&ctx->idle_time) != 0) {
1198 ctx->running = 0;
1199 LOG_ERROR("Failed to start idle time measure!");
1200 return ERROR_FAIL;
1201 }
1202 }
1203 if (s_time_stats_enable) {
1204 if (duration_measure(&blk_proc_time) != 0) {
1205 ctx->running = 0;
1206 LOG_ERROR("Failed to stop block proc time measure!");
1207 return ERROR_FAIL;
1208 }
1209 /* update stats */
1210 float bt = duration_elapsed(&blk_proc_time);
1211 if (bt > ctx->stats.max_blk_proc_time)
1212 ctx->stats.max_blk_proc_time = bt;
1213 if (bt < ctx->stats.min_blk_proc_time)
1214 ctx->stats.min_blk_proc_time = bt;
1215 }
1216 return ERROR_OK;
1217 }
1218
1219 static inline bool is_sysview_mode(int mode)
1220 {
1221 return mode == ESP_APPTRACE_CMD_MODE_SYSVIEW || mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE;
1222 }
1223
1224 static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
1225 {
1226 if (duration_measure(&ctx->read_time) != 0)
1227 LOG_ERROR("Failed to stop trace read time measurement!");
1228 int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx);
1229 if (res != ERROR_OK)
1230 LOG_ERROR("Failed to unregister target timer handler (%d)!", res);
1231 if (is_sysview_mode(ctx->mode)) {
1232 /* stop tracing */
1233 res = esp32_sysview_stop(ctx);
1234 if (res != ERROR_OK)
1235 LOG_ERROR("sysview: Failed to stop tracing!");
1236 }
1237 /* data processor is alive, so wait for all received blocks to be processed */
1238 res = esp32_apptrace_wait_tracing_finished(ctx);
1239 if (res != ERROR_OK)
1240 LOG_ERROR("Failed to wait for pended blocks (%d)!", res);
1241 res = esp32_apptrace_connect_targets(ctx, false, ctx->target_state == TARGET_RUNNING);
1242 if (res != ERROR_OK)
1243 LOG_ERROR("Failed to disconnect targets (%d)!", res);
1244 esp32_apptrace_print_stats(ctx);
1245 res = esp32_apptrace_cmd_cleanup(ctx);
1246 if (res != ERROR_OK)
1247 LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res);
1248 }
1249
1250 /* this function must be called after connecting to targets */
1251 static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx)
1252 {
1253 uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_START };
1254 uint32_t fired_target_num = 0;
1255 struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM] = {{0}};
1256 struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
1257
1258 /* get current block id */
1259 int res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
1260 if (res != ERROR_OK) {
1261 LOG_ERROR("sysview: Failed to read target data info!");
1262 return res;
1263 }
1264 if (fired_target_num == UINT32_MAX) {
1265 /* it can happen that there is no pending target data, but block was switched
1266 * in this case block_ids on both CPUs are equal, so select the first one */
1267 fired_target_num = 0;
1268 }
1269 /* start tracing */
1270 res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
1271 cmds, sizeof(cmds));
1272 if (res != ERROR_OK) {
1273 LOG_ERROR("sysview: Failed to start tracing!");
1274 return res;
1275 }
1276 cmd_data->sv_trace_running = 1;
1277 return res;
1278 }
1279
1280 static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx)
1281 {
1282 uint32_t old_block_id, fired_target_num = 0, empty_target_num = 0;
1283 struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
1284 struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
1285 uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_STOP };
1286 struct duration wait_time;
1287
1288 struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx);
1289 if (!block) {
1290 LOG_ERROR("Failed to get free block for data on (%s)!", target_name(ctx->cpus[fired_target_num]));
1291 return ERROR_FAIL;
1292 }
1293
1294 /* halt all CPUs (not only one), otherwise it can happen that there is no target data and
1295 * while we are queueing commands another CPU switches tracing block */
1296 int res = esp32_apptrace_safe_halt_targets(ctx, target_state);
1297 if (res != ERROR_OK) {
1298 LOG_ERROR("sysview: Failed to halt targets (%d)!", res);
1299 return res;
1300 }
1301 /* it can happen that there is no pending target data
1302 * in this case block_ids on both CPUs are equal, so the first one will be selected */
1303 for (unsigned int k = 0; k < ctx->cores_num; k++) {
1304 if (target_state[k].data_len) {
1305 fired_target_num = k;
1306 break;
1307 }
1308 }
1309 if (target_state[fired_target_num].data_len) {
1310 /* read pending data without ack, they will be acked when stop command is queued */
1311 res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
1312 target_state[fired_target_num].block_id,
1313 false /*no ack target data*/);
1314 if (res != ERROR_OK) {
1315 LOG_ERROR("sysview: Failed to read data on (%s)!", target_name(ctx->cpus[fired_target_num]));
1316 return res;
1317 }
1318 /* process data */
1319 block->data_len = target_state[fired_target_num].data_len;
1320 res = esp32_apptrace_handle_trace_block(ctx, block);
1321 if (res != ERROR_OK) {
1322 LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
1323 return res;
1324 }
1325 }
1326 /* stop tracing and ack target data */
1327 res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
1328 cmds,
1329 sizeof(cmds));
1330 if (res != ERROR_OK) {
1331 LOG_ERROR("sysview: Failed to stop tracing!");
1332 return res;
1333 }
1334 if (ctx->cores_num > 1) {
1335 empty_target_num = fired_target_num ? 0 : 1;
1336 /* ack target data on another CPU */
1337 res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], target_state[fired_target_num].block_id,
1338 0 /*target data ack*/,
1339 true /*host connected*/,
1340 false /*no host data*/);
1341 if (res != ERROR_OK) {
1342 LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
1343 target_name(ctx->cpus[empty_target_num]), res);
1344 return res;
1345 }
1346 }
1347 /* resume targets to allow command processing */
1348 LOG_INFO("Resume targets");
1349 bool smp_resumed = false;
1350 for (unsigned int k = 0; k < ctx->cores_num; k++) {
1351 if (smp_resumed && ctx->cpus[k]->smp) {
1352 /* in SMP mode we need to call target_resume for one core only */
1353 continue;
1354 }
1355 res = target_resume(ctx->cpus[k], 1, 0, 1, 0);
1356 if (res != ERROR_OK) {
1357 LOG_ERROR("sysview: Failed to resume target '%s' (%d)!", target_name(ctx->cpus[k]), res);
1358 return res;
1359 }
1360 if (ctx->cpus[k]->smp)
1361 smp_resumed = true;
1362 }
1363 /* wait for block switch (command sent), so we can disconnect from targets */
1364 old_block_id = target_state[fired_target_num].block_id;
1365 if (duration_start(&wait_time) != 0) {
1366 LOG_ERROR("Failed to start trace stop timeout measurement!");
1367 return ERROR_FAIL;
1368 }
1369 /* we are waiting for the last data from tracing block and also there can be data in the pended
1370 * data buffer */
1371 /* so we are expecting two TRX block switches at most or stopping due to timeout */
1372 while (cmd_data->sv_trace_running) {
1373 res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
1374 if (res != ERROR_OK) {
1375 LOG_ERROR("sysview: Failed to read targets data info!");
1376 return res;
1377 }
1378 if (fired_target_num == UINT32_MAX) {
1379 /* it can happen that there is no pending (last) target data, but block was
1380 * switched */
1381 /* in this case block_ids on both CPUs are equal, so select the first one */
1382 fired_target_num = 0;
1383 }
1384 if (target_state[fired_target_num].block_id != old_block_id) {
1385 if (target_state[fired_target_num].data_len) {
1386 /* read last data and ack them */
1387 res = ctx->hw->data_read(ctx->cpus[fired_target_num],
1388 target_state[fired_target_num].data_len,
1389 block->data,
1390 target_state[fired_target_num].block_id,
1391 true /*ack target data*/);
1392 if (res != ERROR_OK) {
1393 LOG_ERROR("sysview: Failed to read last data on (%s)!", target_name(ctx->cpus[fired_target_num]));
1394 } else {
1395 if (ctx->cores_num > 1) {
1396 /* ack target data on another CPU */
1397 empty_target_num = fired_target_num ? 0 : 1;
1398 res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num],
1399 target_state[fired_target_num].block_id,
1400 0 /*all read*/,
1401 true /*host connected*/,
1402 false /*no host data*/);
1403 if (res != ERROR_OK) {
1404 LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
1405 target_name(ctx->cpus[empty_target_num]), res);
1406 return res;
1407 }
1408 }
1409 /* process data */
1410 block->data_len = target_state[fired_target_num].data_len;
1411 res = esp32_apptrace_handle_trace_block(ctx, block);
1412 if (res != ERROR_OK) {
1413 LOG_ERROR("Failed to process trace block %" PRId32 " bytes!",
1414 block->data_len);
1415 return res;
1416 }
1417 }
1418 old_block_id = target_state[fired_target_num].block_id;
1419 }
1420 }
1421 if (duration_measure(&wait_time) != 0) {
1422 LOG_ERROR("Failed to start trace stop timeout measurement!");
1423 return ERROR_FAIL;
1424 }
1425 const float stop_tmo = LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 30.0 : 0.5;
1426 if (duration_elapsed(&wait_time) >= stop_tmo) {
1427 LOG_INFO("Stop waiting for the last data due to timeout.");
1428 break;
1429 }
1430 }
1431 return res;
1432 }
1433
1434 static int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc)
1435 {
1436 static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx;
1437 struct esp32_apptrace_cmd_data *cmd_data;
1438 int res = ERROR_FAIL;
1439 enum target_state old_state;
1440 struct target *target = get_current_target(CMD_CTX);
1441
1442 if (argc < 1)
1443 return ERROR_COMMAND_SYNTAX_ERROR;
1444
1445 /* command can be invoked on unexamined core, if so find examined one */
1446 if (target->smp && !target_was_examined(target)) {
1447 struct target_list *head;
1448 struct target *curr;
1449 LOG_WARNING("Current target '%s' was not examined!", target_name(target));
1450 foreach_smp_target(head, target->smp_targets) {
1451 curr = head->target;
1452 if (target_was_examined(curr)) {
1453 target = curr;
1454 LOG_WARNING("Run command on target '%s'", target_name(target));
1455 break;
1456 }
1457 }
1458 }
1459 old_state = target->state;
1460
1461 if (strcmp(argv[0], "start") == 0) {
1462 if (is_sysview_mode(mode)) {
1463 /* init cmd context */
1464 res = esp32_sysview_cmd_init(&s_at_cmd_ctx,
1465 cmd,
1466 mode,
1467 mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE,
1468 &argv[1],
1469 argc - 1);
1470 if (res != ERROR_OK) {
1471 command_print(cmd, "Failed to init cmd ctx (%d)!", res);
1472 return res;
1473 }
1474 cmd_data = s_at_cmd_ctx.cmd_priv;
1475 if (cmd_data->skip_len != 0) {
1476 s_at_cmd_ctx.running = 0;
1477 esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
1478 command_print(cmd, "Data skipping not supported!");
1479 return ERROR_FAIL;
1480 }
1481 s_at_cmd_ctx.process_data = esp32_sysview_process_data;
1482 } else {
1483 res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
1484 cmd,
1485 mode,
1486 &argv[1],
1487 argc - 1);
1488 if (res != ERROR_OK) {
1489 command_print(cmd, "Failed to init cmd ctx (%d)!", res);
1490 return res;
1491 }
1492 cmd_data = s_at_cmd_ctx.cmd_priv;
1493 s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
1494 }
1495 s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop;
1496 if (cmd_data->wait4halt) {
1497 res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target);
1498 if (res != ERROR_OK) {
1499 command_print(cmd, "Failed to wait for halt target (%d)!", res);
1500 goto _on_start_error;
1501 }
1502 }
1503 res = esp32_apptrace_connect_targets(&s_at_cmd_ctx, true, old_state == TARGET_RUNNING);
1504 if (res != ERROR_OK) {
1505 command_print(cmd, "Failed to connect to targets (%d)!", res);
1506 goto _on_start_error;
1507 }
1508 if (is_sysview_mode(mode)) {
1509 /* start tracing */
1510 res = esp32_sysview_start(&s_at_cmd_ctx);
1511 if (res != ERROR_OK) {
1512 esp32_apptrace_connect_targets(&s_at_cmd_ctx, false, old_state == TARGET_RUNNING);
1513 s_at_cmd_ctx.running = 0;
1514 esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
1515 command_print(cmd, "sysview: Failed to start tracing!");
1516 return res;
1517 }
1518 }
1519 res = target_register_timer_callback(esp32_apptrace_poll,
1520 cmd_data->poll_period,
1521 TARGET_TIMER_TYPE_PERIODIC,
1522 &s_at_cmd_ctx);
1523 if (res != ERROR_OK) {
1524 command_print(cmd, "Failed to register target timer handler (%d)!", res);
1525 goto _on_start_error;
1526 }
1527 } else if (strcmp(argv[0], "stop") == 0) {
1528 if (!s_at_cmd_ctx.running) {
1529 command_print(cmd, "Tracing is not running!");
1530 return ERROR_FAIL;
1531 }
1532 esp32_apptrace_cmd_stop(&s_at_cmd_ctx);
1533 return ERROR_OK;
1534 } else if (strcmp(argv[0], "status") == 0) {
1535 if (s_at_cmd_ctx.running && duration_measure(&s_at_cmd_ctx.read_time) != 0)
1536 LOG_ERROR("Failed to measure trace read time!");
1537 esp32_apptrace_print_stats(&s_at_cmd_ctx);
1538 return ERROR_OK;
1539 } else if (strcmp(argv[0], "dump") == 0) {
1540 if (is_sysview_mode(mode)) {
1541 command_print(cmd, "Not supported!");
1542 return ERROR_FAIL;
1543 }
1544 /* [dump outfile] - post-mortem dump without connection to targets */
1545 res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
1546 cmd,
1547 mode,
1548 &argv[1],
1549 argc - 1);
1550 if (res != ERROR_OK) {
1551 command_print(cmd, "Failed to init cmd ctx (%d)!", res);
1552 return res;
1553 }
1554 s_at_cmd_ctx.stop_tmo = 0.01; /* use small stop tmo */
1555 s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
1556 /* check for exit signal and command completion */
1557 while (!openocd_is_shutdown_pending() && s_at_cmd_ctx.running) {
1558 res = esp32_apptrace_poll(&s_at_cmd_ctx);
1559 if (res != ERROR_OK) {
1560 LOG_ERROR("Failed to poll target for trace data (%d)!", res);
1561 break;
1562 }
1563 /* let registered timer callbacks to run */
1564 target_call_timer_callbacks();
1565 }
1566 if (s_at_cmd_ctx.running) {
1567 /* data processor is alive, so wait for all received blocks to be processed */
1568 res = esp32_apptrace_wait_tracing_finished(&s_at_cmd_ctx);
1569 if (res != ERROR_OK)
1570 LOG_ERROR("Failed to wait for pended blocks (%d)!", res);
1571 }
1572 esp32_apptrace_print_stats(&s_at_cmd_ctx);
1573 res = esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
1574 if (res != ERROR_OK)
1575 command_print(cmd, "Failed to cleanup cmd ctx (%d)!", res);
1576 } else {
1577 command_print(cmd, "Invalid action '%s'!", argv[0]);
1578 }
1579
1580 return res;
1581
1582 _on_start_error:
1583 s_at_cmd_ctx.running = 0;
1584 if (is_sysview_mode(mode))
1585 esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
1586 else
1587 esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
1588 return res;
1589 }
1590
1591 COMMAND_HANDLER(esp32_cmd_apptrace)
1592 {
1593 return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC);
1594 }
1595
1596 COMMAND_HANDLER(esp32_cmd_sysview)
1597 {
1598 return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW, CMD_ARGV, CMD_ARGC);
1599 }
1600
1601 COMMAND_HANDLER(esp32_cmd_sysview_mcore)
1602 {
1603 return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, CMD_ARGV, CMD_ARGC);
1604 }
1605
1606 const struct command_registration esp32_apptrace_command_handlers[] = {
1607 {
1608 .name = "apptrace",
1609 .handler = esp32_cmd_apptrace,
1610 .mode = COMMAND_EXEC,
1611 .help =
1612 "App Tracing: application level trace control. Starts, stops or queries tracing process status.",
1613 .usage =
1614 "(start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status) | (dump <destination>)",
1615 },
1616 {
1617 .name = "sysview",
1618 .handler = esp32_cmd_sysview,
1619 .mode = COMMAND_EXEC,
1620 .help =
1621 "App Tracing: SEGGER SystemView compatible trace control. Starts, stops or queries tracing process status.",
1622 .usage =
1623 "(start file://<outfile1> [file://<outfile2>] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
1624 },
1625 {
1626 .name = "sysview_mcore",
1627 .handler = esp32_cmd_sysview_mcore,
1628 .mode = COMMAND_EXEC,
1629 .help =
1630 "App Tracing: Espressif multi-core SystemView trace control. Starts, stops or queries tracing process status.",
1631 .usage =
1632 "(start file://<outfile> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
1633 },
1634 COMMAND_REGISTRATION_DONE
1635 };

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)