OpenOCD
esp_xtensa_apptrace.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Xtensa application tracing module for OpenOCD *
5  * Copyright (C) 2017 Espressif Systems Ltd. *
6  ***************************************************************************/
7 
8 /*
9  How it works?
10  https://github.com/espressif/esp-idf/blob/master/components/app_trace/port/xtensa/port.c#L8
11 */
12 
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16 
17 #include <helper/align.h>
18 #include <target/xtensa/xtensa.h>
20 #include "esp_xtensa_apptrace.h"
21 
22 /* TRAX is disabled, so we use its registers for our own purposes
23  * | 31..XXXXXX..24 | 23 .(host_connect). 23 | 22 .(host_data). 22| 21..(block_id)..15 | 14..(block_len)..0 |
24  */
25 #define XTENSA_APPTRACE_CTRL_REG XDMREG_DELAYCNT
26 #define XTENSA_APPTRACE_BLOCK_ID_MSK 0x7FUL
27 #define XTENSA_APPTRACE_BLOCK_ID_MAX XTENSA_APPTRACE_BLOCK_ID_MSK
28 /* if non-zero then apptrace code entered the critical section and the value is an address of the
29  * critical section's exit point */
30 #define XTENSA_APPTRACE_STAT_REG XDMREG_TRIGGERPC
31 
32 #define XTENSA_APPTRACE_BLOCK_LEN_MSK 0x7FFFUL
33 #define XTENSA_APPTRACE_BLOCK_LEN(_l_) ((_l_) & XTENSA_APPTRACE_BLOCK_LEN_MSK)
34 #define XTENSA_APPTRACE_BLOCK_LEN_GET(_v_) ((_v_) & XTENSA_APPTRACE_BLOCK_LEN_MSK)
35 #define XTENSA_APPTRACE_BLOCK_ID(_id_) (((_id_) & XTENSA_APPTRACE_BLOCK_ID_MSK) << 15)
36 #define XTENSA_APPTRACE_BLOCK_ID_GET(_v_) (((_v_) >> 15) & XTENSA_APPTRACE_BLOCK_ID_MSK)
37 #define XTENSA_APPTRACE_HOST_DATA BIT(22)
38 #define XTENSA_APPTRACE_HOST_CONNECT BIT(23)
39 
43  uint32_t bufs_num,
44  uint32_t buf_sz[],
45  const uint8_t *bufs[],
46  uint32_t block_id,
47  bool ack,
48  bool data);
49 
52  .max_block_size_get = esp_xtensa_apptrace_block_max_size_get,
53  .status_reg_read = esp_xtensa_apptrace_status_reg_read,
54  .ctrl_reg_write = esp_xtensa_apptrace_ctrl_reg_write,
55  .ctrl_reg_read = esp_xtensa_apptrace_ctrl_reg_read,
56  .data_len_read = esp_xtensa_apptrace_data_len_read,
57  .data_read = esp_xtensa_apptrace_data_read,
58  .usr_block_max_size_get = esp_xtensa_apptrace_usr_block_max_size_get,
59  .buffs_write = esp_xtensa_apptrace_buffs_write,
60  .leave_trace_crit_section_start = esp_xtensa_apptrace_leave_crit_section_start,
61  .leave_trace_crit_section_stop = esp_xtensa_apptrace_leave_crit_section_stop,
62 };
63 
65 {
68  struct xtensa_trace_config trace_config;
69  uint32_t max_trace_block_sz;
70 
72  if (res != ERROR_OK) {
73  LOG_ERROR("Failed to read TRAX status (%d)!", res);
74  return 0;
75  }
76 
77  max_trace_block_sz = BIT(((trace_status.stat >> 8) & 0x1f) - 2) * 4;
78  res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config);
79  if (res != ERROR_OK) {
80  LOG_ERROR("Failed to read TRAX config (%d)!", res);
81  return 0;
82  }
83  LOG_DEBUG("ctrl=0x%" PRIx32 " memadrstart=0x%" PRIx32 " memadrend=0x%" PRIx32 " traxadr=0x%" PRIx32,
84  trace_config.ctrl,
85  trace_config.memaddr_start,
86  trace_config.memaddr_end,
87  trace_config.addr);
88 
89  return max_trace_block_sz;
90 }
91 
93 {
95 }
96 
98  uint32_t *block_id,
99  uint32_t *len)
100 {
101  return esp_xtensa_apptrace_ctrl_reg_read(target, block_id, len, NULL);
102 }
103 
105  uint32_t block_id,
106  const uint8_t *data,
107  uint32_t size)
108 {
110 }
111 
113  uint32_t size,
114  uint8_t *buffer,
115  uint8_t *unal_bytes)
116 {
117  int res = 0;
118  uint32_t rd_sz = ALIGN_UP(size, 4);
119 
121  if (res != ERROR_OK)
122  return res;
123  if (!IS_ALIGNED(size, 4)) {
125  if (res != ERROR_OK)
126  return res;
127  }
128  for (unsigned int i = size / 4; i != 0; i--) {
130  if (res != ERROR_OK)
131  return res;
132  }
133  return ERROR_OK;
134 }
135 
137  uint32_t size,
138  uint8_t *buffer,
139  uint8_t *unal_bytes)
140 {
142  if (res != ERROR_OK)
143  return res;
144  for (unsigned int i = 0; i < size / 4; i++) {
146  if (res != ERROR_OK)
147  return res;
148  }
149  if (!IS_ALIGNED(size, 4)) {
151  if (res != ERROR_OK)
152  return res;
153  }
154  return ERROR_OK;
155 }
156 
158  uint32_t size,
159  uint8_t *buffer,
160  uint32_t block_id,
161  bool ack)
162 {
164  int res;
165  uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | XTENSA_APPTRACE_BLOCK_ID(block_id) |
167  uint8_t unal_bytes[4];
168 
169  LOG_DEBUG("Read data on target (%s)", target_name(target));
172  else
174  if (res != ERROR_OK)
175  return res;
176  if (ack) {
177  LOG_DEBUG("Ack block %" PRIu32 " target (%s)!", block_id, target_name(target));
179  if (res != ERROR_OK)
180  return res;
181  }
184  if (res != ERROR_OK) {
185  LOG_ERROR("Failed to exec JTAG queue!");
186  return res;
187  }
188  if (!IS_ALIGNED(size, 4)) {
189  /* copy the last unaligned bytes */
190  memcpy(buffer + ALIGN_DOWN(size, 4), unal_bytes, size & 0x3UL);
191  }
192  return ERROR_OK;
193 }
194 
196  uint32_t block_id,
197  uint32_t len,
198  bool conn,
199  bool data)
200 {
202  uint32_t tmp = (conn ? XTENSA_APPTRACE_HOST_CONNECT : 0) |
203  (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) |
205 
209  if (res != ERROR_OK) {
210  LOG_ERROR("Failed to exec JTAG queue!");
211  return res;
212  }
213 
214  return ERROR_OK;
215 }
216 
218  uint32_t *block_id,
219  uint32_t *len,
220  bool *conn)
221 {
223  uint8_t tmp[4];
224 
228  if (res != ERROR_OK)
229  return res;
230  uint32_t val = target_buffer_get_u32(target, tmp);
231  if (block_id)
232  *block_id = XTENSA_APPTRACE_BLOCK_ID_GET(val);
233  if (len)
234  *len = XTENSA_APPTRACE_BLOCK_LEN_GET(val);
235  if (conn)
237  return ERROR_OK;
238 }
239 
241 {
243  uint8_t tmp[4];
244 
246  if (res != ERROR_OK)
247  return res;
250  if (res != ERROR_OK) {
251  LOG_ERROR("Failed to exec JTAG queue!");
252  return res;
253  }
254  *stat = buf_get_u32(tmp, 0, 32);
255  return ERROR_OK;
256 }
257 
259 {
261 
265  if (res != ERROR_OK) {
266  LOG_ERROR("Failed to exec JTAG queue!");
267  return res;
268  }
269  return ERROR_OK;
270 }
271 
272 static int esp_xtensa_swdbg_activate(struct target *target, int enab)
273 {
275 
279  if (res != ERROR_OK) {
280  LOG_ERROR("%s: writing DCR failed!", target->cmd_name);
281  return res;
282  }
283 
284  return ERROR_OK;
285 }
286 
288 {
289  /* TODO: not sure that we need this, but it seems that we fail to leave tracing critical
290  *section w/o this */
291  int res = esp_xtensa_swdbg_activate(target, 1 /*enable*/);
292  if (res != ERROR_OK) {
293  LOG_ERROR("Failed to activate SW debug (%d)!", res);
294  return res;
295  }
296  return ERROR_OK;
297 }
298 
300 {
301  int res = esp_xtensa_swdbg_activate(target, 0 /*disable*/);
302  if (res != ERROR_OK) {
303  LOG_ERROR("Failed to activate SW debug (%d)!", res);
304  return res;
305  }
306  return ERROR_OK;
307 }
308 
309 static int esp_xtensa_apptrace_queue_reverse_write(struct target *target, uint32_t bufs_num,
310  uint32_t buf_sz[], const uint8_t *bufs[])
311 {
312  int res = ERROR_OK;
313  uint32_t cached_bytes = 0, total_sz = 0;
314  uint8_t cached_data8[sizeof(uint32_t)] = { 0 };
315  uint32_t cached_data32 = 0;
316 
318 
319  for (uint32_t i = 0; i < bufs_num; i++)
320  total_sz += buf_sz[i];
321  if (!IS_ALIGNED(total_sz, 4)) {
322  cached_bytes = sizeof(uint32_t) - (total_sz & 0x3UL);
323  total_sz = ALIGN_UP(total_sz, 4);
324  }
326  for (uint32_t i = bufs_num; i > 0; i--) {
327  uint32_t bsz = buf_sz[i - 1];
328  const uint8_t *cur_buf = &bufs[i - 1][bsz];
329  uint32_t bytes_to_cache;
330  /* if there are cached bytes from the previous buffer, combine them with the last
331  * from the current buffer */
332  if (cached_bytes) {
333  if ((cached_bytes + bsz) < sizeof(uint32_t))
334  bytes_to_cache = bsz;
335  else
336  bytes_to_cache = sizeof(uint32_t) - cached_bytes;
337  memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache],
338  cur_buf - bytes_to_cache,
339  bytes_to_cache);
340  cached_data32 = target_buffer_get_u32(target, cached_data8);
341  cached_bytes += bytes_to_cache;
342  if (cached_bytes < sizeof(uint32_t))
343  continue;
344  res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
345  if (res != ERROR_OK)
346  return res;
347  bsz -= bytes_to_cache;
348  cur_buf -= bytes_to_cache;
349  memset(cached_data8, 0x00, sizeof(cached_data8));
350  cached_bytes = 0;
351  }
352  /* write full dwords */
353  for (unsigned int k = bsz; k >= sizeof(uint32_t); k -= sizeof(uint32_t)) {
354  uint32_t temp = target_buffer_get_u32(target, cur_buf - sizeof(uint32_t));
356  if (res != ERROR_OK)
357  return res;
358  cur_buf -= sizeof(uint32_t);
359  }
360  /* if there are bytes to be cached (1..3) */
361  bytes_to_cache = bsz & 0x3UL;
362  if (bytes_to_cache > 0) {
363  if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) {
364  /* filling the cache buffer from the end to beginning */
365  uint32_t to_copy = sizeof(uint32_t) - cached_bytes;
366  memcpy(&cached_data8[0], cur_buf - to_copy, to_copy);
367  cached_data32 = target_buffer_get_u32(target, cached_data8);
368  /* write full word of cached bytes */
369  res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
370  if (res != ERROR_OK)
371  return res;
372  /* cache remaining bytes */
373  memset(cached_data8, 0x00, sizeof(cached_data8));
374  cur_buf -= to_copy;
375  to_copy = bytes_to_cache + cached_bytes - sizeof(uint32_t);
376  memcpy(&cached_data8[sizeof(uint32_t) - to_copy], cur_buf - to_copy, to_copy);
377  cached_bytes = to_copy;
378  } else {
379  /* filling the cache buffer from the end to beginning */
380  memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache],
381  cur_buf - bytes_to_cache,
382  bytes_to_cache);
383  cached_bytes += bytes_to_cache;
384  }
385  }
386  }
387  return ERROR_OK;
388 }
389 
390 static int esp_xtensa_apptrace_queue_normal_write(struct target *target, uint32_t bufs_num,
391  uint32_t buf_sz[], const uint8_t *bufs[])
392 {
393  int res = ERROR_OK;
394  uint32_t cached_bytes = 0;
395  uint8_t cached_data8[4] = { 0 };
396  uint32_t cached_data32 = 0;
397 
399 
400  /* | 1 | 2 | 1 | 2 | 4 |.......|
401  * | 4 | 4 | 4 | */
403  for (unsigned int i = 0; i < bufs_num; i++) {
404  uint32_t bsz = buf_sz[i];
405  const uint8_t *cur_buf = bufs[i];
406  uint32_t bytes_to_cache;
407  /* if there are cached bytes from the previous buffer, combine them with the last
408  * from the current buffer */
409  if (cached_bytes) {
410  if ((cached_bytes + bsz) < sizeof(uint32_t))
411  bytes_to_cache = bsz;
412  else
413  bytes_to_cache = sizeof(uint32_t) - cached_bytes;
414  memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache);
415  cached_bytes += bytes_to_cache;
416  if (cached_bytes < sizeof(uint32_t))
417  continue;
418  cached_data32 = target_buffer_get_u32(target, cached_data8);
419  res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
420  if (res != ERROR_OK)
421  return res;
422  bsz -= bytes_to_cache;
423  cur_buf += bytes_to_cache;
424  memset(cached_data8, 0x00, sizeof(cached_data8));
425  cached_bytes = 0;
426  }
427  /* write full dwords */
428  for (unsigned int k = 0; (k + sizeof(uint32_t)) <= bsz; k += sizeof(uint32_t)) {
429  uint32_t temp = target_buffer_get_u32(target, cur_buf);
431  if (res != ERROR_OK)
432  return res;
433  cur_buf += sizeof(uint32_t);
434  }
435  /* if there are bytes to be cached (1..3) */
436  bytes_to_cache = bsz & 0x3UL;
437  if (bytes_to_cache > 0) {
438  if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) {
439  memcpy(&cached_data8[0], cur_buf, sizeof(uint32_t) - cached_bytes);
440  cached_data32 = target_buffer_get_u32(target, cached_data8);
441  /* write full word of cached bytes */
442  res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
443  if (res != ERROR_OK)
444  return res;
445  /* cache remaining bytes */
446  memset(cached_data8, 0x00, sizeof(cached_data8));
447  cur_buf += sizeof(uint32_t) - cached_bytes;
448  cached_bytes = bytes_to_cache + cached_bytes - sizeof(uint32_t);
449  memcpy(&cached_data8[0], cur_buf, cached_bytes);
450  } else {
451  memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache);
452  cached_bytes += bytes_to_cache;
453  }
454  }
455  }
456  if (cached_bytes) {
457  /* write remaining cached bytes */
458  cached_data32 = target_buffer_get_u32(target, cached_data8);
459  res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
460  if (res != ERROR_OK)
461  return res;
462  }
463  return ERROR_OK;
464 }
465 
467  uint32_t bufs_num,
468  uint32_t buf_sz[],
469  const uint8_t *bufs[],
470  uint32_t block_id,
471  bool ack,
472  bool data)
473 {
475  int res = ERROR_OK;
476  uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT |
477  (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) |
479 
481  res = esp_xtensa_apptrace_queue_reverse_write(target, bufs_num, buf_sz, bufs);
482  else
483  res = esp_xtensa_apptrace_queue_normal_write(target, bufs_num, buf_sz, bufs);
484  if (res != ERROR_OK)
485  return res;
486  if (ack) {
487  LOG_DEBUG("Ack block %" PRId32 " on target (%s)!", block_id, target_name(target));
489  if (res != ERROR_OK)
490  return res;
491  }
494  if (res != ERROR_OK) {
495  LOG_ERROR("Failed to exec JTAG queue!");
496  return res;
497  }
498  return ERROR_OK;
499 }
#define IS_ALIGNED(x, a)
Definition: align.h:22
#define ALIGN_DOWN(x, a)
Definition: align.h:21
#define ALIGN_UP(x, a)
Definition: align.h:20
static uint32_t buf_get_u32(const uint8_t *_buffer, unsigned int first, unsigned int num)
Retrieves num bits from _buffer, starting at the first bit, returning the bits in a 32-bit word.
Definition: binarybuffer.h:104
int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size)
#define XTENSA_APPTRACE_STAT_REG
#define XTENSA_APPTRACE_BLOCK_LEN(_l_)
int esp_xtensa_apptrace_data_read(struct target *target, uint32_t size, uint8_t *buffer, uint32_t block_id, bool ack)
static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target)
int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat)
int esp_xtensa_apptrace_data_len_read(struct target *target, uint32_t *block_id, uint32_t *len)
#define XTENSA_APPTRACE_HOST_DATA
int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat)
static int esp_xtensa_apptrace_queue_reverse_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[])
uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target)
#define XTENSA_APPTRACE_HOST_CONNECT
#define XTENSA_APPTRACE_BLOCK_LEN_GET(_v_)
struct esp32_apptrace_hw esp_xtensa_apptrace_hw
static int esp_xtensa_apptrace_buffs_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[], uint32_t block_id, bool ack, bool data)
static int esp_xtensa_apptrace_data_reverse_read(struct xtensa *xtensa, uint32_t size, uint8_t *buffer, uint8_t *unal_bytes)
#define XTENSA_APPTRACE_BLOCK_ID_GET(_v_)
static int esp_xtensa_apptrace_queue_normal_write(struct target *target, uint32_t bufs_num, uint32_t buf_sz[], const uint8_t *bufs[])
int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn)
int esp_xtensa_apptrace_ctrl_reg_write(struct target *target, uint32_t block_id, uint32_t len, bool conn, bool data)
static int esp_xtensa_swdbg_activate(struct target *target, int enab)
#define XTENSA_APPTRACE_BLOCK_ID_MAX
uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target)
int esp_xtensa_apptrace_usr_block_write(struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size)
#define XTENSA_APPTRACE_CTRL_REG
static int esp_xtensa_apptrace_data_normal_read(struct xtensa *xtensa, uint32_t size, uint8_t *buffer, uint8_t *unal_bytes)
static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target)
#define XTENSA_APPTRACE_BLOCK_ID(_id_)
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
#define BIT(nr)
Definition: stm32l4x.h:18
Definition: target.h:116
char * cmd_name
Definition: target.h:118
struct xtensa_tracing_config trace
Definition: xtensa.h:180
bool reversed_mem_access
Definition: xtensa.h:166
Represents a generic Xtensa core.
Definition: xtensa.h:242
struct xtensa_debug_module dbg_mod
Definition: xtensa.h:246
struct xtensa_config * core_config
Definition: xtensa.h:245
uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
Definition: target.c:316
static const char * target_name(const struct target *target)
Returns the instance-specific name of the specified target.
Definition: target.h:233
trace_status
Definition: trace.h:36
#define NULL
Definition: usb.h:16
Holds the interface to Xtensa cores.
static struct xtensa * target_to_xtensa(struct target *target)
Definition: xtensa.h:291
static int xtensa_queue_dbg_reg_write(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint32_t data)
Definition: xtensa.h:340
static int xtensa_queue_dbg_reg_read(struct xtensa *xtensa, enum xtensa_dm_reg reg, uint8_t *data)
Definition: xtensa.h:328
int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
static void xtensa_dm_queue_tdi_idle(struct xtensa_debug_module *dm)
#define OCDDCR_DEBUGSWACTIVE
static int xtensa_dm_queue_execute(struct xtensa_debug_module *dm)
@ XDMREG_DCRSET
@ XDMREG_TRAXDATA
@ XDMREG_TRAXADDR
@ XDMREG_DCRCLR