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 static int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
);
46 static int oocd_trace_read_reg(oocd_trace_t
*oocd_trace
, int reg
, u32
*value
)
48 size_t bytes_written
, bytes_read
, bytes_to_read
;
51 cmd
= 0x10 | (reg
& 0x7);
52 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
55 while (bytes_to_read
> 0)
57 bytes_read
= read(oocd_trace
->tty_fd
, ((u8
*)value
) + 4 - bytes_to_read
, bytes_to_read
);
58 bytes_to_read
-= bytes_read
;
61 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, *value
);
66 static int oocd_trace_write_reg(oocd_trace_t
*oocd_trace
, int reg
, u32 value
)
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;
77 bytes_written
= write(oocd_trace
->tty_fd
, data
, 5);
78 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, value
);
83 static int oocd_trace_read_memory(oocd_trace_t
*oocd_trace
, u8
*data
, u32 address
, u32 size
)
85 size_t bytes_written
, bytes_to_read
;
89 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, address
);
90 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_SDRAM_COUNTER
, size
);
93 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
95 bytes_to_read
= size
* 16;
96 while (bytes_to_read
> 0)
98 if ((bytes_read
= read(oocd_trace
->tty_fd
,
99 ((u8
*)data
) + (size
* 16) - bytes_to_read
, bytes_to_read
)) < 0)
101 LOG_DEBUG("read() returned %zi (%s)", bytes_read
, strerror(errno
));
104 bytes_to_read
-= bytes_read
;
110 static int oocd_trace_init(etm_context_t
*etm_ctx
)
113 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
116 oocd_trace
->tty_fd
= open(oocd_trace
->tty
, O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
118 if(oocd_trace
->tty_fd
< 0)
120 LOG_ERROR("can't open tty");
121 return ERROR_ETM_CAPTURE_INIT_FAILED
;
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
);
129 tcgetattr(oocd_trace
->tty_fd
, &oocd_trace
->oldtio
); /* save current port settings */
131 bzero(&oocd_trace
->newtio
, sizeof(oocd_trace
->newtio
));
132 oocd_trace
->newtio
.c_cflag
= CS8
| CLOCAL
| CREAD
| B2500000
;
134 oocd_trace
->newtio
.c_iflag
= IGNPAR
| IGNBRK
| IXON
| IXOFF
;
135 oocd_trace
->newtio
.c_oflag
= 0;
137 /* set input mode (non-canonical, no echo,...) */
138 oocd_trace
->newtio
.c_lflag
= 0;
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 */
144 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
145 tcsetattr(oocd_trace
->tty_fd
, TCSANOW
, &oocd_trace
->newtio
);
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)
151 LOG_DEBUG("%zi bytes read\n", bytes_read
);
157 static trace_status_t
oocd_trace_status(etm_context_t
*etm_ctx
)
159 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
162 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
164 /* if tracing is currently idle, return this information */
165 if (etm_ctx
->capture_status
== TRACE_IDLE
)
167 return etm_ctx
->capture_status
;
169 else if (etm_ctx
->capture_status
& TRACE_RUNNING
)
171 /* check Full bit to identify an overflow */
173 etm_ctx
->capture_status
|= TRACE_OVERFLOWED
;
175 /* check Triggered bit to identify trigger condition */
177 etm_ctx
->capture_status
|= TRACE_TRIGGERED
;
181 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
182 etm_ctx
->capture_status
|= TRACE_COMPLETED
;
186 return etm_ctx
->capture_status
;
189 static int oocd_trace_read_trace(etm_context_t
*etm_ctx
)
191 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
193 u32 first_frame
= 0x0;
194 u32 num_frames
= 1048576;
198 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
199 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, &address
);
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
206 first_frame
= address
;
208 num_frames
= address
;
210 /* read data into temporary array for unpacking
211 * one frame from OpenOCD+trace corresponds to 16 trace cycles
213 trace_data
= malloc(sizeof(u8
) * num_frames
* 16);
214 oocd_trace_read_memory(oocd_trace
, trace_data
, first_frame
, num_frames
);
216 if (etm_ctx
->trace_depth
> 0)
218 free(etm_ctx
->trace_data
);
221 etm_ctx
->trace_depth
= num_frames
* 16;
222 etm_ctx
->trace_data
= malloc(sizeof(etmv1_trace_data_t
) * etm_ctx
->trace_depth
);
224 for (i
= 0; i
< num_frames
* 16; i
++)
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;
230 if ((trace_data
[i
] & 0x80) >> 7)
232 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRACESYNC_CYCLE
;
235 if (etm_ctx
->trace_data
[i
].pipestat
== STAT_TR
)
237 etm_ctx
->trace_data
[i
].pipestat
= etm_ctx
->trace_data
[i
].packet
& 0x7;
238 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRIGGER_CYCLE
;
247 static int oocd_trace_start_capture(etm_context_t
*etm_ctx
)
249 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
250 u32 control
= 0x1; /* 0x1: enabled */
253 if (((etm_ctx
->portmode
& ETM_PORT_MODE_MASK
) != ETM_PORT_NORMAL
)
254 || ((etm_ctx
->portmode
& ETM_PORT_WIDTH_MASK
) != ETM_PORT_4BIT
))
256 LOG_DEBUG("OpenOCD+trace only supports normal 4-bit ETM mode");
257 return ERROR_ETM_PORTMODE_NOT_SUPPORTED
;
260 if ((etm_ctx
->portmode
& ETM_PORT_CLOCK_MASK
) == ETM_PORT_HALF_CLOCK
)
262 control
|= 0x2; /* half rate clock, capture at twice the clock rate */
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;
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
);
274 /* we're starting a new trace, initialize capture status */
275 etm_ctx
->capture_status
= TRACE_RUNNING
;
280 static int oocd_trace_stop_capture(etm_context_t
*etm_ctx
)
282 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
284 /* trace stopped, just clear running flag, but preserve others */
285 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
287 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, 0x0);
292 etm_capture_driver_t oocd_trace_capture_driver
=
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
,
303 static int handle_oocd_trace_config_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
306 armv4_5_common_t
*armv4_5
;
307 arm7_9_common_t
*arm7_9
;
311 LOG_ERROR("incomplete 'oocd_trace config <target> <tty>' command");
315 target
= get_current_target(cmd_ctx
);
317 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
319 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
325 oocd_trace_t
*oocd_trace
= malloc(sizeof(oocd_trace_t
));
327 arm7_9
->etm_ctx
->capture_driver_priv
= oocd_trace
;
328 oocd_trace
->etm_ctx
= arm7_9
->etm_ctx
;
330 /* copy name of TTY device used to communicate with OpenOCD+trace */
331 oocd_trace
->tty
= strndup(args
[1], 256);
335 LOG_ERROR("target has no ETM defined, OpenOCD+trace left unconfigured");
341 static int handle_oocd_trace_status_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
344 armv4_5_common_t
*armv4_5
;
345 arm7_9_common_t
*arm7_9
;
346 oocd_trace_t
*oocd_trace
;
349 target
= get_current_target(cmd_ctx
);
351 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
353 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
357 if (!arm7_9
->etm_ctx
)
359 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
363 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
365 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
369 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
371 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
374 command_print(cmd_ctx
, "trace clock locked");
376 command_print(cmd_ctx
, "no trace clock");
381 static int handle_oocd_trace_resync_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
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
;
390 target
= get_current_target(cmd_ctx
);
392 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
394 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
398 if (!arm7_9
->etm_ctx
)
400 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
404 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
406 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
410 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
414 bytes_written
= write(oocd_trace
->tty_fd
, cmd_array
, 1);
416 command_print(cmd_ctx
, "requesting traceclock resync");
417 LOG_DEBUG("resyncing traceclk pll");
422 int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
)
424 command_t
*oocd_trace_cmd
;
426 oocd_trace_cmd
= register_command(cmd_ctx
, NULL
, "oocd_trace", NULL
, COMMAND_ANY
, "OpenOCD+trace");
428 register_command(cmd_ctx
, oocd_trace_cmd
, "config", handle_oocd_trace_config_command
, COMMAND_CONFIG
, NULL
);
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");
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)