14197beceeaff6ab2f22d0b69a14d89056a5d35d
[openocd.git] / src / target / oocd_trace.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE
26 #endif
27 #include <string.h>
28 #include <errno.h>
29
30 #include "oocd_trace.h"
31 #include "etm.h"
32
33 #include "log.h"
34 #include "types.h"
35 #include "binarybuffer.h"
36 #include "target.h"
37 #include "register.h"
38 #include "jtag.h"
39 #include "arm7_9_common.h"
40 #include "replacements.h"
41
42 #include <stdlib.h>
43
44 static int oocd_trace_register_commands(struct command_context_s *cmd_ctx);
45
46 static int oocd_trace_read_reg(oocd_trace_t *oocd_trace, int reg, u32 *value)
47 {
48 size_t bytes_written, bytes_read, bytes_to_read;
49 u8 cmd;
50
51 cmd = 0x10 | (reg & 0x7);
52 bytes_written = write(oocd_trace->tty_fd, &cmd, 1);
53
54 bytes_to_read = 4;
55 while (bytes_to_read > 0)
56 {
57 bytes_read = read(oocd_trace->tty_fd, ((u8*)value) + 4 - bytes_to_read, bytes_to_read);
58 bytes_to_read -= bytes_read;
59 }
60
61 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg, *value);
62
63 return ERROR_OK;
64 }
65
66 static int oocd_trace_write_reg(oocd_trace_t *oocd_trace, int reg, u32 value)
67 {
68 size_t bytes_written;
69 u8 data[5];
70
71 data[0] = 0x18 | (reg & 0x7);
72 data[1] = value & 0xff;
73 data[2] = (value & 0xff00) >> 8;
74 data[3] = (value & 0xff0000) >> 16;
75 data[4] = (value & 0xff000000) >> 24;
76
77 bytes_written = write(oocd_trace->tty_fd, data, 5);
78 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg, value);
79
80 return ERROR_OK;
81 }
82
83 static int oocd_trace_read_memory(oocd_trace_t *oocd_trace, u8 *data, u32 address, u32 size)
84 {
85 size_t bytes_written, bytes_to_read;
86 ssize_t bytes_read;
87 u8 cmd;
88
89 oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, address);
90 oocd_trace_write_reg(oocd_trace, OOCD_TRACE_SDRAM_COUNTER, size);
91
92 cmd = 0x20;
93 bytes_written = write(oocd_trace->tty_fd, &cmd, 1);
94
95 bytes_to_read = size * 16;
96 while (bytes_to_read > 0)
97 {
98 if ((bytes_read = read(oocd_trace->tty_fd,
99 ((u8*)data) + (size * 16) - bytes_to_read, bytes_to_read)) < 0)
100 {
101 LOG_DEBUG("read() returned %zi (%s)", bytes_read, strerror(errno));
102 }
103 else
104 bytes_to_read -= bytes_read;
105 }
106
107 return ERROR_OK;
108 }
109
110 static int oocd_trace_init(etm_context_t *etm_ctx)
111 {
112 u8 trash[256];
113 oocd_trace_t *oocd_trace = etm_ctx->capture_driver_priv;
114 size_t bytes_read;
115
116 oocd_trace->tty_fd = open(oocd_trace->tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
117
118 if(oocd_trace->tty_fd < 0)
119 {
120 LOG_ERROR("can't open tty");
121 return ERROR_ETM_CAPTURE_INIT_FAILED;
122 }
123
124 /* clear input & output buffers, then switch to "blocking mode" */
125 tcflush(oocd_trace->tty_fd, TCOFLUSH);
126 tcflush(oocd_trace->tty_fd, TCIFLUSH);
127 fcntl(oocd_trace->tty_fd, F_SETFL, fcntl(oocd_trace->tty_fd, F_GETFL) & ~O_NONBLOCK);
128
129 tcgetattr(oocd_trace->tty_fd, &oocd_trace->oldtio); /* save current port settings */
130
131 bzero(&oocd_trace->newtio, sizeof(oocd_trace->newtio));
132 oocd_trace->newtio.c_cflag = CS8 | CLOCAL | CREAD | B2500000;
133
134 oocd_trace->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF;
135 oocd_trace->newtio.c_oflag = 0;
136
137 /* set input mode (non-canonical, no echo,...) */
138 oocd_trace->newtio.c_lflag = 0;
139
140 cfmakeraw(&oocd_trace->newtio);
141 oocd_trace->newtio.c_cc[VTIME] = 1; /* inter-character timer used */
142 oocd_trace->newtio.c_cc[VMIN] = 0; /* blocking read until 0 chars received */
143
144 tcflush(oocd_trace->tty_fd, TCIFLUSH);
145 tcsetattr(oocd_trace->tty_fd, TCSANOW, &oocd_trace->newtio);
146
147 /* occasionally one bogus character is left in the input buffer
148 * read up any leftover characters to ensure communication is in sync */
149 while ((bytes_read = read(oocd_trace->tty_fd, trash, sizeof(trash))) > 0)
150 {
151 LOG_DEBUG("%zi bytes read\n", bytes_read);
152 };
153
154 return ERROR_OK;
155 }
156
157 static trace_status_t oocd_trace_status(etm_context_t *etm_ctx)
158 {
159 oocd_trace_t *oocd_trace = etm_ctx->capture_driver_priv;
160 u32 status;
161
162 oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
163
164 /* if tracing is currently idle, return this information */
165 if (etm_ctx->capture_status == TRACE_IDLE)
166 {
167 return etm_ctx->capture_status;
168 }
169 else if (etm_ctx->capture_status & TRACE_RUNNING)
170 {
171 /* check Full bit to identify an overflow */
172 if (status & 0x4)
173 etm_ctx->capture_status |= TRACE_OVERFLOWED;
174
175 /* check Triggered bit to identify trigger condition */
176 if (status & 0x2)
177 etm_ctx->capture_status |= TRACE_TRIGGERED;
178
179 if (status & 0x1)
180 {
181 etm_ctx->capture_status &= ~TRACE_RUNNING;
182 etm_ctx->capture_status |= TRACE_COMPLETED;
183 }
184 }
185
186 return etm_ctx->capture_status;
187 }
188
189 static int oocd_trace_read_trace(etm_context_t *etm_ctx)
190 {
191 oocd_trace_t *oocd_trace = etm_ctx->capture_driver_priv;
192 u32 status, address;
193 u32 first_frame = 0x0;
194 u32 num_frames = 1048576;
195 u8 *trace_data;
196 u32 i;
197
198 oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
199 oocd_trace_read_reg(oocd_trace, OOCD_TRACE_ADDRESS, &address);
200
201 /* check if we overflowed, and adjust first frame of the trace accordingly
202 * if we didn't overflow, read only up to the frame that would be written next,
203 * i.e. don't read invalid entries
204 */
205 if (status & 0x4)
206 first_frame = address;
207 else
208 num_frames = address;
209
210 /* read data into temporary array for unpacking
211 * one frame from OpenOCD+trace corresponds to 16 trace cycles
212 */
213 trace_data = malloc(sizeof(u8) * num_frames * 16);
214 oocd_trace_read_memory(oocd_trace, trace_data, first_frame, num_frames);
215
216 if (etm_ctx->trace_depth > 0)
217 {
218 free(etm_ctx->trace_data);
219 }
220
221 etm_ctx->trace_depth = num_frames * 16;
222 etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth);
223
224 for (i = 0; i < num_frames * 16; i++)
225 {
226 etm_ctx->trace_data[i].pipestat = (trace_data[i] & 0x7);
227 etm_ctx->trace_data[i].packet = (trace_data[i] & 0x78) >> 3;
228 etm_ctx->trace_data[i].flags = 0;
229
230 if ((trace_data[i] & 0x80) >> 7)
231 {
232 etm_ctx->trace_data[i].flags |= ETMV1_TRACESYNC_CYCLE;
233 }
234
235 if (etm_ctx->trace_data[i].pipestat == STAT_TR)
236 {
237 etm_ctx->trace_data[i].pipestat = etm_ctx->trace_data[i].packet & 0x7;
238 etm_ctx->trace_data[i].flags |= ETMV1_TRIGGER_CYCLE;
239 }
240 }
241
242 free(trace_data);
243
244 return ERROR_OK;
245 }
246
247 static int oocd_trace_start_capture(etm_context_t *etm_ctx)
248 {
249 oocd_trace_t *oocd_trace = etm_ctx->capture_driver_priv;
250 u32 control = 0x1; /* 0x1: enabled */
251 u32 trigger_count;
252
253 if (((etm_ctx->portmode & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL)
254 || ((etm_ctx->portmode & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT))
255 {
256 LOG_DEBUG("OpenOCD+trace only supports normal 4-bit ETM mode");
257 return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
258 }
259
260 if ((etm_ctx->portmode & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK)
261 {
262 control |= 0x2; /* half rate clock, capture at twice the clock rate */
263 }
264
265 /* OpenOCD+trace holds up to 16 million samples,
266 * but trigger counts is set in multiples of 16 */
267 trigger_count = (1048576 * etm_ctx->trigger_percent) / 100;
268
269 /* capturing always starts at address zero */
270 oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, 0x0);
271 oocd_trace_write_reg(oocd_trace, OOCD_TRACE_TRIGGER_COUNTER, trigger_count);
272 oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, control);
273
274 /* we're starting a new trace, initialize capture status */
275 etm_ctx->capture_status = TRACE_RUNNING;
276
277 return ERROR_OK;
278 }
279
280 static int oocd_trace_stop_capture(etm_context_t *etm_ctx)
281 {
282 oocd_trace_t *oocd_trace = etm_ctx->capture_driver_priv;
283
284 /* trace stopped, just clear running flag, but preserve others */
285 etm_ctx->capture_status &= ~TRACE_RUNNING;
286
287 oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, 0x0);
288
289 return ERROR_OK;
290 }
291
292 etm_capture_driver_t oocd_trace_capture_driver =
293 {
294 .name = "oocd_trace",
295 .register_commands = oocd_trace_register_commands,
296 .init = oocd_trace_init,
297 .status = oocd_trace_status,
298 .start_capture = oocd_trace_start_capture,
299 .stop_capture = oocd_trace_stop_capture,
300 .read_trace = oocd_trace_read_trace,
301 };
302
303 static int handle_oocd_trace_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
304 {
305 target_t *target;
306 armv4_5_common_t *armv4_5;
307 arm7_9_common_t *arm7_9;
308
309 if (argc != 2)
310 {
311 LOG_ERROR("incomplete 'oocd_trace config <target> <tty>' command");
312 exit(-1);
313 }
314
315 target = get_current_target(cmd_ctx);
316
317 if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
318 {
319 command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
320 return ERROR_OK;
321 }
322
323 if (arm7_9->etm_ctx)
324 {
325 oocd_trace_t *oocd_trace = malloc(sizeof(oocd_trace_t));
326
327 arm7_9->etm_ctx->capture_driver_priv = oocd_trace;
328 oocd_trace->etm_ctx = arm7_9->etm_ctx;
329
330 /* copy name of TTY device used to communicate with OpenOCD+trace */
331 oocd_trace->tty = strndup(args[1], 256);
332 }
333 else
334 {
335 LOG_ERROR("target has no ETM defined, OpenOCD+trace left unconfigured");
336 }
337
338 return ERROR_OK;
339 }
340
341 static int handle_oocd_trace_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
342 {
343 target_t *target;
344 armv4_5_common_t *armv4_5;
345 arm7_9_common_t *arm7_9;
346 oocd_trace_t *oocd_trace;
347 u32 status;
348
349 target = get_current_target(cmd_ctx);
350
351 if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
352 {
353 command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
354 return ERROR_OK;
355 }
356
357 if (!arm7_9->etm_ctx)
358 {
359 command_print(cmd_ctx, "current target doesn't have an ETM configured");
360 return ERROR_OK;
361 }
362
363 if (strcmp(arm7_9->etm_ctx->capture_driver->name, "oocd_trace") != 0)
364 {
365 command_print(cmd_ctx, "current target's ETM capture driver isn't 'oocd_trace'");
366 return ERROR_OK;
367 }
368
369 oocd_trace = (oocd_trace_t*)arm7_9->etm_ctx->capture_driver_priv;
370
371 oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status);
372
373 if (status & 0x8)
374 command_print(cmd_ctx, "trace clock locked");
375 else
376 command_print(cmd_ctx, "no trace clock");
377
378 return ERROR_OK;
379 }
380
381 static int handle_oocd_trace_resync_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
382 {
383 target_t *target;
384 armv4_5_common_t *armv4_5;
385 arm7_9_common_t *arm7_9;
386 oocd_trace_t *oocd_trace;
387 size_t bytes_written;
388 u8 cmd_array[1];
389
390 target = get_current_target(cmd_ctx);
391
392 if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
393 {
394 command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
395 return ERROR_OK;
396 }
397
398 if (!arm7_9->etm_ctx)
399 {
400 command_print(cmd_ctx, "current target doesn't have an ETM configured");
401 return ERROR_OK;
402 }
403
404 if (strcmp(arm7_9->etm_ctx->capture_driver->name, "oocd_trace") != 0)
405 {
406 command_print(cmd_ctx, "current target's ETM capture driver isn't 'oocd_trace'");
407 return ERROR_OK;
408 }
409
410 oocd_trace = (oocd_trace_t*)arm7_9->etm_ctx->capture_driver_priv;
411
412 cmd_array[0] = 0xf0;
413
414 bytes_written = write(oocd_trace->tty_fd, cmd_array, 1);
415
416 command_print(cmd_ctx, "requesting traceclock resync");
417 LOG_DEBUG("resyncing traceclk pll");
418
419 return ERROR_OK;
420 }
421
422 int oocd_trace_register_commands(struct command_context_s *cmd_ctx)
423 {
424 command_t *oocd_trace_cmd;
425
426 oocd_trace_cmd = register_command(cmd_ctx, NULL, "oocd_trace", NULL, COMMAND_ANY, "OpenOCD+trace");
427
428 register_command(cmd_ctx, oocd_trace_cmd, "config", handle_oocd_trace_config_command, COMMAND_CONFIG, NULL);
429
430 register_command(cmd_ctx, oocd_trace_cmd, "status", handle_oocd_trace_status_command, COMMAND_EXEC, "display OpenOCD+trace status");
431 register_command(cmd_ctx, oocd_trace_cmd, "resync", handle_oocd_trace_resync_command, COMMAND_EXEC, "resync OpenOCD+trace capture clock");
432
433 return ERROR_OK;
434 }

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)