1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
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. *
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. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 ***************************************************************************/
25 #include "oocd_trace.h"
28 * This is "proof of concept" code, for prototype hardware:
29 * https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html
32 static int oocd_trace_read_reg(struct oocd_trace
*oocd_trace
, int reg
, uint32_t *value
)
34 size_t bytes_written
, bytes_read
, bytes_to_read
;
37 cmd
= 0x10 | (reg
& 0x7);
38 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
39 if (bytes_written
< 1)
43 while (bytes_to_read
> 0) {
44 bytes_read
= read(oocd_trace
->tty_fd
, ((uint8_t *)value
) + 4 - bytes_to_read
, bytes_to_read
);
45 bytes_to_read
-= bytes_read
;
48 LOG_DEBUG("reg #%i: 0x%8.8x", reg
, *value
);
53 static int oocd_trace_write_reg(struct oocd_trace
*oocd_trace
, int reg
, uint32_t value
)
58 data
[0] = 0x18 | (reg
& 0x7);
59 data
[1] = value
& 0xff;
60 data
[2] = (value
& 0xff00) >> 8;
61 data
[3] = (value
& 0xff0000) >> 16;
62 data
[4] = (value
& 0xff000000) >> 24;
64 bytes_written
= write(oocd_trace
->tty_fd
, data
, 5);
65 if (bytes_written
< 5)
68 LOG_DEBUG("reg #%i: 0x%8.8x", reg
, value
);
73 static int oocd_trace_read_memory(struct oocd_trace
*oocd_trace
, uint8_t *data
, uint32_t address
, uint32_t size
)
75 size_t bytes_written
, bytes_to_read
;
79 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, address
);
80 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_SDRAM_COUNTER
, size
);
83 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
84 if (bytes_written
< 1)
87 bytes_to_read
= size
* 16;
88 while (bytes_to_read
> 0) {
89 bytes_read
= read(oocd_trace
->tty_fd
,
90 ((uint8_t *)data
) + (size
* 16) - bytes_to_read
, bytes_to_read
);
92 LOG_DEBUG("read() returned %zi (%s)", bytes_read
, strerror(errno
));
94 bytes_to_read
-= bytes_read
;
100 static int oocd_trace_init(struct etm_context
*etm_ctx
)
103 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
106 oocd_trace
->tty_fd
= open(oocd_trace
->tty
, O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
108 if (oocd_trace
->tty_fd
< 0) {
109 LOG_ERROR("can't open tty");
110 return ERROR_ETM_CAPTURE_INIT_FAILED
;
113 /* clear input & output buffers, then switch to "blocking mode" */
114 tcflush(oocd_trace
->tty_fd
, TCOFLUSH
);
115 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
116 fcntl(oocd_trace
->tty_fd
, F_SETFL
, fcntl(oocd_trace
->tty_fd
, F_GETFL
) & ~O_NONBLOCK
);
118 tcgetattr(oocd_trace
->tty_fd
, &oocd_trace
->oldtio
); /* save current port settings */
120 bzero(&oocd_trace
->newtio
, sizeof(oocd_trace
->newtio
));
121 oocd_trace
->newtio
.c_cflag
= CS8
| CLOCAL
| CREAD
| B2500000
;
123 oocd_trace
->newtio
.c_iflag
= IGNPAR
| IGNBRK
| IXON
| IXOFF
;
124 oocd_trace
->newtio
.c_oflag
= 0;
126 /* set input mode (non-canonical, no echo,...) */
127 oocd_trace
->newtio
.c_lflag
= 0;
129 cfmakeraw(&oocd_trace
->newtio
);
130 oocd_trace
->newtio
.c_cc
[VTIME
] = 1; /* inter-character timer used */
131 oocd_trace
->newtio
.c_cc
[VMIN
] = 0; /* blocking read until 0 chars received */
133 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
134 tcsetattr(oocd_trace
->tty_fd
, TCSANOW
, &oocd_trace
->newtio
);
136 /* occasionally one bogus character is left in the input buffer
137 * read up any leftover characters to ensure communication is in sync */
139 bytes_read
= read(oocd_trace
->tty_fd
, trash
, sizeof(trash
));
141 LOG_DEBUG("%zi bytes read", bytes_read
);
142 } while (bytes_read
> 0);
147 static trace_status_t
oocd_trace_status(struct etm_context
*etm_ctx
)
149 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
152 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
154 /* if tracing is currently idle, return this information */
155 if (etm_ctx
->capture_status
== TRACE_IDLE
)
156 return etm_ctx
->capture_status
;
157 else if (etm_ctx
->capture_status
& TRACE_RUNNING
) {
158 /* check Full bit to identify an overflow */
160 etm_ctx
->capture_status
|= TRACE_OVERFLOWED
;
162 /* check Triggered bit to identify trigger condition */
164 etm_ctx
->capture_status
|= TRACE_TRIGGERED
;
167 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
168 etm_ctx
->capture_status
|= TRACE_COMPLETED
;
172 return etm_ctx
->capture_status
;
175 static int oocd_trace_read_trace(struct etm_context
*etm_ctx
)
177 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
178 uint32_t status
, address
;
179 uint32_t first_frame
= 0x0;
180 uint32_t num_frames
= 1048576;
184 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
185 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, &address
);
187 /* check if we overflowed, and adjust first frame of the trace accordingly
188 * if we didn't overflow, read only up to the frame that would be written next,
189 * i.e. don't read invalid entries
192 first_frame
= address
;
194 num_frames
= address
;
196 /* read data into temporary array for unpacking
197 * one frame from OpenOCD + trace corresponds to 16 trace cycles
199 trace_data
= malloc(sizeof(uint8_t) * num_frames
* 16);
200 oocd_trace_read_memory(oocd_trace
, trace_data
, first_frame
, num_frames
);
202 if (etm_ctx
->trace_depth
> 0)
203 free(etm_ctx
->trace_data
);
205 etm_ctx
->trace_depth
= num_frames
* 16;
206 etm_ctx
->trace_data
= malloc(sizeof(struct etmv1_trace_data
) * etm_ctx
->trace_depth
);
208 for (i
= 0; i
< num_frames
* 16; i
++) {
209 etm_ctx
->trace_data
[i
].pipestat
= (trace_data
[i
] & 0x7);
210 etm_ctx
->trace_data
[i
].packet
= (trace_data
[i
] & 0x78) >> 3;
211 etm_ctx
->trace_data
[i
].flags
= 0;
213 if ((trace_data
[i
] & 0x80) >> 7)
214 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRACESYNC_CYCLE
;
216 if (etm_ctx
->trace_data
[i
].pipestat
== STAT_TR
) {
217 etm_ctx
->trace_data
[i
].pipestat
= etm_ctx
->trace_data
[i
].packet
& 0x7;
218 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRIGGER_CYCLE
;
227 static int oocd_trace_start_capture(struct etm_context
*etm_ctx
)
229 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
230 uint32_t control
= 0x1; /* 0x1: enabled */
231 uint32_t trigger_count
;
233 if (((etm_ctx
->control
& ETM_PORT_MODE_MASK
) != ETM_PORT_NORMAL
)
234 || ((etm_ctx
->control
& ETM_PORT_WIDTH_MASK
) != ETM_PORT_4BIT
)) {
235 LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode");
236 return ERROR_ETM_PORTMODE_NOT_SUPPORTED
;
239 if ((etm_ctx
->control
& ETM_PORT_CLOCK_MASK
) == ETM_PORT_HALF_CLOCK
)
240 control
|= 0x2; /* half rate clock, capture at twice the clock rate */
242 /* OpenOCD + trace holds up to 16 million samples,
243 * but trigger counts is set in multiples of 16 */
244 trigger_count
= (1048576 * /* trigger_percent */ 50) / 100;
246 /* capturing always starts at address zero */
247 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, 0x0);
248 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_TRIGGER_COUNTER
, trigger_count
);
249 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, control
);
251 /* we're starting a new trace, initialize capture status */
252 etm_ctx
->capture_status
= TRACE_RUNNING
;
257 static int oocd_trace_stop_capture(struct etm_context
*etm_ctx
)
259 struct oocd_trace
*oocd_trace
= etm_ctx
->capture_driver_priv
;
261 /* trace stopped, just clear running flag, but preserve others */
262 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
264 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, 0x0);
269 COMMAND_HANDLER(handle_oocd_trace_config_command
)
271 struct target
*target
;
275 return ERROR_COMMAND_SYNTAX_ERROR
;
277 target
= get_current_target(CMD_CTX
);
278 arm
= target_to_arm(target
);
280 command_print(CMD_CTX
, "current target isn't an ARM");
285 struct oocd_trace
*oocd_trace
= malloc(sizeof(struct oocd_trace
));
287 arm
->etm
->capture_driver_priv
= oocd_trace
;
288 oocd_trace
->etm_ctx
= arm
->etm
;
290 /* copy name of TTY device used to communicate with OpenOCD + trace */
291 oocd_trace
->tty
= strndup(CMD_ARGV
[1], 256);
293 LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured");
298 COMMAND_HANDLER(handle_oocd_trace_status_command
)
300 struct target
*target
;
302 struct oocd_trace
*oocd_trace
;
305 target
= get_current_target(CMD_CTX
);
307 arm
= target_to_arm(target
);
309 command_print(CMD_CTX
, "current target isn't an ARM");
314 command_print(CMD_CTX
, "current target doesn't have an ETM configured");
318 if (strcmp(arm
->etm
->capture_driver
->name
, "oocd_trace") != 0) {
319 command_print(CMD_CTX
, "current target's ETM capture driver isn't 'oocd_trace'");
323 oocd_trace
= (struct oocd_trace
*)arm
->etm
->capture_driver_priv
;
325 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
328 command_print(CMD_CTX
, "trace clock locked");
330 command_print(CMD_CTX
, "no trace clock");
335 COMMAND_HANDLER(handle_oocd_trace_resync_command
)
337 struct target
*target
;
339 struct oocd_trace
*oocd_trace
;
340 size_t bytes_written
;
341 uint8_t cmd_array
[1];
343 target
= get_current_target(CMD_CTX
);
345 arm
= target_to_arm(target
);
347 command_print(CMD_CTX
, "current target isn't an ARM");
352 command_print(CMD_CTX
, "current target doesn't have an ETM configured");
356 if (strcmp(arm
->etm
->capture_driver
->name
, "oocd_trace") != 0) {
357 command_print(CMD_CTX
, "current target's ETM capture driver isn't 'oocd_trace'");
361 oocd_trace
= (struct oocd_trace
*)arm
->etm
->capture_driver_priv
;
365 bytes_written
= write(oocd_trace
->tty_fd
, cmd_array
, 1);
366 if (bytes_written
< 1)
369 command_print(CMD_CTX
, "requesting traceclock resync");
370 LOG_DEBUG("resyncing traceclk pll");
375 static const struct command_registration oocd_trace_all_command_handlers
[] = {
378 .handler
= handle_oocd_trace_config_command
,
379 .mode
= COMMAND_CONFIG
,
380 .usage
= "<target> <tty>",
384 .handler
= handle_oocd_trace_status_command
,
385 .mode
= COMMAND_EXEC
,
387 .help
= "display OpenOCD + trace status",
391 .handler
= handle_oocd_trace_resync_command
,
392 .mode
= COMMAND_EXEC
,
394 .help
= "resync OpenOCD + trace capture clock",
396 COMMAND_REGISTRATION_DONE
398 static const struct command_registration oocd_trace_command_handlers
[] = {
400 .name
= "oocd_trace",
402 .help
= "OpenOCD trace capture driver command group",
404 .chain
= oocd_trace_all_command_handlers
,
406 COMMAND_REGISTRATION_DONE
409 struct etm_capture_driver oocd_trace_capture_driver
= {
410 .name
= "oocd_trace",
411 .commands
= oocd_trace_command_handlers
,
412 .init
= oocd_trace_init
,
413 .status
= oocd_trace_status
,
414 .start_capture
= oocd_trace_start_capture
,
415 .stop_capture
= oocd_trace_stop_capture
,
416 .read_trace
= oocd_trace_read_trace
,
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)