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

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)