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, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
30 #include "oocd_trace.h"
35 #include "binarybuffer.h"
39 #include "arm7_9_common.h"
40 #include "replacements.h"
44 int oocd_trace_read_reg(oocd_trace_t
*oocd_trace
, int reg
, u32
*value
)
46 size_t bytes_written
, bytes_read
, bytes_to_read
;
49 cmd
= 0x10 | (reg
& 0x7);
50 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
53 while (bytes_to_read
> 0)
55 bytes_read
= read(oocd_trace
->tty_fd
, ((u8
*)value
) + 4 - bytes_to_read
, bytes_to_read
);
56 bytes_to_read
-= bytes_read
;
59 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, *value
);
64 int oocd_trace_write_reg(oocd_trace_t
*oocd_trace
, int reg
, u32 value
)
69 data
[0] = 0x18 | (reg
& 0x7);
70 data
[1] = value
& 0xff;
71 data
[2] = (value
& 0xff00) >> 8;
72 data
[3] = (value
& 0xff0000) >> 16;
73 data
[4] = (value
& 0xff000000) >> 24;
75 bytes_written
= write(oocd_trace
->tty_fd
, data
, 5);
76 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, value
);
81 int oocd_trace_read_memory(oocd_trace_t
*oocd_trace
, u8
*data
, u32 address
, u32 size
)
83 size_t bytes_written
, bytes_to_read
;
87 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, address
);
88 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_SDRAM_COUNTER
, size
);
91 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
93 bytes_to_read
= size
* 16;
94 while (bytes_to_read
> 0)
96 if ((bytes_read
= read(oocd_trace
->tty_fd
,
97 ((u8
*)data
) + (size
* 16) - bytes_to_read
, bytes_to_read
)) < 0)
99 LOG_DEBUG("read() returned %i (%s)", bytes_read
, strerror(errno
));
102 bytes_to_read
-= bytes_read
;
108 int oocd_trace_init(etm_context_t
*etm_ctx
)
111 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
114 oocd_trace
->tty_fd
= open(oocd_trace
->tty
, O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
116 if(oocd_trace
->tty_fd
< 0)
118 LOG_ERROR("can't open tty");
119 return ERROR_ETM_CAPTURE_INIT_FAILED
;
122 /* clear input & output buffers, then switch to "blocking mode" */
123 tcflush(oocd_trace
->tty_fd
, TCOFLUSH
);
124 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
125 fcntl(oocd_trace
->tty_fd
, F_SETFL
, fcntl(oocd_trace
->tty_fd
, F_GETFL
) & ~O_NONBLOCK
);
127 tcgetattr(oocd_trace
->tty_fd
, &oocd_trace
->oldtio
); /* save current port settings */
129 bzero(&oocd_trace
->newtio
, sizeof(oocd_trace
->newtio
));
130 oocd_trace
->newtio
.c_cflag
= CS8
| CLOCAL
| CREAD
| B2500000
;
132 oocd_trace
->newtio
.c_iflag
= IGNPAR
| IGNBRK
| IXON
| IXOFF
;
133 oocd_trace
->newtio
.c_oflag
= 0;
135 /* set input mode (non-canonical, no echo,...) */
136 oocd_trace
->newtio
.c_lflag
= 0;
138 cfmakeraw(&oocd_trace
->newtio
);
139 oocd_trace
->newtio
.c_cc
[VTIME
] = 1; /* inter-character timer used */
140 oocd_trace
->newtio
.c_cc
[VMIN
] = 0; /* blocking read until 0 chars received */
142 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
143 tcsetattr(oocd_trace
->tty_fd
, TCSANOW
, &oocd_trace
->newtio
);
145 /* occasionally one bogus character is left in the input buffer
146 * read up any leftover characters to ensure communication is in sync */
147 while ((bytes_read
= read(oocd_trace
->tty_fd
, trash
, sizeof(trash
))) > 0)
149 LOG_DEBUG("%i bytes read\n", bytes_read
);
155 trace_status_t
oocd_trace_status(etm_context_t
*etm_ctx
)
157 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
160 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
162 /* if tracing is currently idle, return this information */
163 if (etm_ctx
->capture_status
== TRACE_IDLE
)
165 return etm_ctx
->capture_status
;
167 else if (etm_ctx
->capture_status
& TRACE_RUNNING
)
169 /* check Full bit to identify an overflow */
171 etm_ctx
->capture_status
|= TRACE_OVERFLOWED
;
173 /* check Triggered bit to identify trigger condition */
175 etm_ctx
->capture_status
|= TRACE_TRIGGERED
;
179 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
180 etm_ctx
->capture_status
|= TRACE_COMPLETED
;
184 return etm_ctx
->capture_status
;
187 int oocd_trace_read_trace(etm_context_t
*etm_ctx
)
189 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
191 u32 first_frame
= 0x0;
192 u32 num_frames
= 1048576;
196 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
197 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, &address
);
199 /* check if we overflowed, and adjust first frame of the trace accordingly
200 * if we didn't overflow, read only up to the frame that would be written next,
201 * i.e. don't read invalid entries
204 first_frame
= address
;
206 num_frames
= address
;
208 /* read data into temporary array for unpacking
209 * one frame from OpenOCD+trace corresponds to 16 trace cycles
211 trace_data
= malloc(sizeof(u8
) * num_frames
* 16);
212 oocd_trace_read_memory(oocd_trace
, trace_data
, first_frame
, num_frames
);
214 if (etm_ctx
->trace_depth
> 0)
216 free(etm_ctx
->trace_data
);
219 etm_ctx
->trace_depth
= num_frames
* 16;
220 etm_ctx
->trace_data
= malloc(sizeof(etmv1_trace_data_t
) * etm_ctx
->trace_depth
);
222 for (i
= 0; i
< num_frames
* 16; i
++)
224 etm_ctx
->trace_data
[i
].pipestat
= (trace_data
[i
] & 0x7);
225 etm_ctx
->trace_data
[i
].packet
= (trace_data
[i
] & 0x78) >> 3;
226 etm_ctx
->trace_data
[i
].flags
= 0;
228 if ((trace_data
[i
] & 0x80) >> 7)
230 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRACESYNC_CYCLE
;
233 if (etm_ctx
->trace_data
[i
].pipestat
== STAT_TR
)
235 etm_ctx
->trace_data
[i
].pipestat
= etm_ctx
->trace_data
[i
].packet
& 0x7;
236 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRIGGER_CYCLE
;
245 int oocd_trace_start_capture(etm_context_t
*etm_ctx
)
247 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
248 u32 control
= 0x1; /* 0x1: enabled */
251 if (((etm_ctx
->portmode
& ETM_PORT_MODE_MASK
) != ETM_PORT_NORMAL
)
252 || ((etm_ctx
->portmode
& ETM_PORT_WIDTH_MASK
) != ETM_PORT_4BIT
))
254 LOG_DEBUG("OpenOCD+trace only supports normal 4-bit ETM mode");
255 return ERROR_ETM_PORTMODE_NOT_SUPPORTED
;
258 if ((etm_ctx
->portmode
& ETM_PORT_CLOCK_MASK
) == ETM_PORT_HALF_CLOCK
)
260 control
|= 0x2; /* half rate clock, capture at twice the clock rate */
263 /* OpenOCD+trace holds up to 16 million samples,
264 * but trigger counts is set in multiples of 16 */
265 trigger_count
= (1048576 * etm_ctx
->trigger_percent
) / 100;
267 /* capturing always starts at address zero */
268 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, 0x0);
269 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_TRIGGER_COUNTER
, trigger_count
);
270 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, control
);
272 /* we're starting a new trace, initialize capture status */
273 etm_ctx
->capture_status
= TRACE_RUNNING
;
278 int oocd_trace_stop_capture(etm_context_t
*etm_ctx
)
280 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
282 /* trace stopped, just clear running flag, but preserve others */
283 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
285 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, 0x0);
290 etm_capture_driver_t oocd_trace_capture_driver
=
292 .name
= "oocd_trace",
293 .register_commands
= oocd_trace_register_commands
,
294 .init
= oocd_trace_init
,
295 .status
= oocd_trace_status
,
296 .start_capture
= oocd_trace_start_capture
,
297 .stop_capture
= oocd_trace_stop_capture
,
298 .read_trace
= oocd_trace_read_trace
,
301 int handle_oocd_trace_config_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
304 armv4_5_common_t
*armv4_5
;
305 arm7_9_common_t
*arm7_9
;
309 LOG_ERROR("incomplete 'oocd_trace config <target> <tty>' command");
313 target
= get_current_target(cmd_ctx
);
315 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
317 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
323 oocd_trace_t
*oocd_trace
= malloc(sizeof(oocd_trace_t
));
325 arm7_9
->etm_ctx
->capture_driver_priv
= oocd_trace
;
326 oocd_trace
->etm_ctx
= arm7_9
->etm_ctx
;
328 /* copy name of TTY device used to communicate with OpenOCD+trace */
329 oocd_trace
->tty
= strndup(args
[1], 256);
333 LOG_ERROR("target has no ETM defined, OpenOCD+trace left unconfigured");
339 int handle_oocd_trace_status_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
342 armv4_5_common_t
*armv4_5
;
343 arm7_9_common_t
*arm7_9
;
344 oocd_trace_t
*oocd_trace
;
347 target
= get_current_target(cmd_ctx
);
349 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
351 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
355 if (!arm7_9
->etm_ctx
)
357 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
361 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
363 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
367 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
369 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
372 command_print(cmd_ctx
, "trace clock locked");
374 command_print(cmd_ctx
, "no trace clock");
379 int handle_oocd_trace_resync_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
382 armv4_5_common_t
*armv4_5
;
383 arm7_9_common_t
*arm7_9
;
384 oocd_trace_t
*oocd_trace
;
385 size_t bytes_written
;
388 target
= get_current_target(cmd_ctx
);
390 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
392 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
396 if (!arm7_9
->etm_ctx
)
398 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
402 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
404 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
408 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
412 bytes_written
= write(oocd_trace
->tty_fd
, cmd_array
, 1);
414 command_print(cmd_ctx
, "requesting traceclock resync");
415 LOG_DEBUG("resyncing traceclk pll");
420 int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
)
422 command_t
*oocd_trace_cmd
;
424 oocd_trace_cmd
= register_command(cmd_ctx
, NULL
, "oocd_trace", NULL
, COMMAND_ANY
, "OpenOCD+trace");
426 register_command(cmd_ctx
, oocd_trace_cmd
, "config", handle_oocd_trace_config_command
, COMMAND_CONFIG
, NULL
);
428 register_command(cmd_ctx
, oocd_trace_cmd
, "status", handle_oocd_trace_status_command
, COMMAND_EXEC
, "display OpenOCD+trace status");
429 register_command(cmd_ctx
, oocd_trace_cmd
, "resync", handle_oocd_trace_resync_command
, COMMAND_EXEC
, "resync OpenOCD+trace capture clock");
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)