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 ***************************************************************************/
24 #include "oocd_trace.h"
25 #include "arm7_9_common.h"
28 static int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
);
30 static int oocd_trace_read_reg(oocd_trace_t
*oocd_trace
, int reg
, u32
*value
)
32 size_t bytes_written
, bytes_read
, bytes_to_read
;
35 cmd
= 0x10 | (reg
& 0x7);
36 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
39 while (bytes_to_read
> 0)
41 bytes_read
= read(oocd_trace
->tty_fd
, ((u8
*)value
) + 4 - bytes_to_read
, bytes_to_read
);
42 bytes_to_read
-= bytes_read
;
45 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, *value
);
50 static int oocd_trace_write_reg(oocd_trace_t
*oocd_trace
, int reg
, u32 value
)
55 data
[0] = 0x18 | (reg
& 0x7);
56 data
[1] = value
& 0xff;
57 data
[2] = (value
& 0xff00) >> 8;
58 data
[3] = (value
& 0xff0000) >> 16;
59 data
[4] = (value
& 0xff000000) >> 24;
61 bytes_written
= write(oocd_trace
->tty_fd
, data
, 5);
62 LOG_DEBUG("reg #%i: 0x%8.8x\n", reg
, value
);
67 static int oocd_trace_read_memory(oocd_trace_t
*oocd_trace
, u8
*data
, u32 address
, u32 size
)
69 size_t bytes_written
, bytes_to_read
;
73 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, address
);
74 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_SDRAM_COUNTER
, size
);
77 bytes_written
= write(oocd_trace
->tty_fd
, &cmd
, 1);
79 bytes_to_read
= size
* 16;
80 while (bytes_to_read
> 0)
82 if ((bytes_read
= read(oocd_trace
->tty_fd
,
83 ((u8
*)data
) + (size
* 16) - bytes_to_read
, bytes_to_read
)) < 0)
85 LOG_DEBUG("read() returned %zi (%s)", bytes_read
, strerror(errno
));
88 bytes_to_read
-= bytes_read
;
94 static int oocd_trace_init(etm_context_t
*etm_ctx
)
97 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
100 oocd_trace
->tty_fd
= open(oocd_trace
->tty
, O_RDWR
| O_NOCTTY
| O_NONBLOCK
);
102 if(oocd_trace
->tty_fd
< 0)
104 LOG_ERROR("can't open tty");
105 return ERROR_ETM_CAPTURE_INIT_FAILED
;
108 /* clear input & output buffers, then switch to "blocking mode" */
109 tcflush(oocd_trace
->tty_fd
, TCOFLUSH
);
110 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
111 fcntl(oocd_trace
->tty_fd
, F_SETFL
, fcntl(oocd_trace
->tty_fd
, F_GETFL
) & ~O_NONBLOCK
);
113 tcgetattr(oocd_trace
->tty_fd
, &oocd_trace
->oldtio
); /* save current port settings */
115 bzero(&oocd_trace
->newtio
, sizeof(oocd_trace
->newtio
));
116 oocd_trace
->newtio
.c_cflag
= CS8
| CLOCAL
| CREAD
| B2500000
;
118 oocd_trace
->newtio
.c_iflag
= IGNPAR
| IGNBRK
| IXON
| IXOFF
;
119 oocd_trace
->newtio
.c_oflag
= 0;
121 /* set input mode (non-canonical, no echo,...) */
122 oocd_trace
->newtio
.c_lflag
= 0;
124 cfmakeraw(&oocd_trace
->newtio
);
125 oocd_trace
->newtio
.c_cc
[VTIME
] = 1; /* inter-character timer used */
126 oocd_trace
->newtio
.c_cc
[VMIN
] = 0; /* blocking read until 0 chars received */
128 tcflush(oocd_trace
->tty_fd
, TCIFLUSH
);
129 tcsetattr(oocd_trace
->tty_fd
, TCSANOW
, &oocd_trace
->newtio
);
131 /* occasionally one bogus character is left in the input buffer
132 * read up any leftover characters to ensure communication is in sync */
133 while ((bytes_read
= read(oocd_trace
->tty_fd
, trash
, sizeof(trash
))) > 0)
135 LOG_DEBUG("%zi bytes read\n", bytes_read
);
141 static trace_status_t
oocd_trace_status(etm_context_t
*etm_ctx
)
143 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
146 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
148 /* if tracing is currently idle, return this information */
149 if (etm_ctx
->capture_status
== TRACE_IDLE
)
151 return etm_ctx
->capture_status
;
153 else if (etm_ctx
->capture_status
& TRACE_RUNNING
)
155 /* check Full bit to identify an overflow */
157 etm_ctx
->capture_status
|= TRACE_OVERFLOWED
;
159 /* check Triggered bit to identify trigger condition */
161 etm_ctx
->capture_status
|= TRACE_TRIGGERED
;
165 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
166 etm_ctx
->capture_status
|= TRACE_COMPLETED
;
170 return etm_ctx
->capture_status
;
173 static int oocd_trace_read_trace(etm_context_t
*etm_ctx
)
175 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
177 u32 first_frame
= 0x0;
178 u32 num_frames
= 1048576;
182 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
183 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, &address
);
185 /* check if we overflowed, and adjust first frame of the trace accordingly
186 * if we didn't overflow, read only up to the frame that would be written next,
187 * i.e. don't read invalid entries
190 first_frame
= address
;
192 num_frames
= address
;
194 /* read data into temporary array for unpacking
195 * one frame from OpenOCD+trace corresponds to 16 trace cycles
197 trace_data
= malloc(sizeof(u8
) * num_frames
* 16);
198 oocd_trace_read_memory(oocd_trace
, trace_data
, first_frame
, num_frames
);
200 if (etm_ctx
->trace_depth
> 0)
202 free(etm_ctx
->trace_data
);
205 etm_ctx
->trace_depth
= num_frames
* 16;
206 etm_ctx
->trace_data
= malloc(sizeof(etmv1_trace_data_t
) * etm_ctx
->trace_depth
);
208 for (i
= 0; i
< num_frames
* 16; i
++)
210 etm_ctx
->trace_data
[i
].pipestat
= (trace_data
[i
] & 0x7);
211 etm_ctx
->trace_data
[i
].packet
= (trace_data
[i
] & 0x78) >> 3;
212 etm_ctx
->trace_data
[i
].flags
= 0;
214 if ((trace_data
[i
] & 0x80) >> 7)
216 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRACESYNC_CYCLE
;
219 if (etm_ctx
->trace_data
[i
].pipestat
== STAT_TR
)
221 etm_ctx
->trace_data
[i
].pipestat
= etm_ctx
->trace_data
[i
].packet
& 0x7;
222 etm_ctx
->trace_data
[i
].flags
|= ETMV1_TRIGGER_CYCLE
;
231 static int oocd_trace_start_capture(etm_context_t
*etm_ctx
)
233 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
234 u32 control
= 0x1; /* 0x1: enabled */
237 if (((etm_ctx
->portmode
& ETM_PORT_MODE_MASK
) != ETM_PORT_NORMAL
)
238 || ((etm_ctx
->portmode
& ETM_PORT_WIDTH_MASK
) != ETM_PORT_4BIT
))
240 LOG_DEBUG("OpenOCD+trace only supports normal 4-bit ETM mode");
241 return ERROR_ETM_PORTMODE_NOT_SUPPORTED
;
244 if ((etm_ctx
->portmode
& ETM_PORT_CLOCK_MASK
) == ETM_PORT_HALF_CLOCK
)
246 control
|= 0x2; /* half rate clock, capture at twice the clock rate */
249 /* OpenOCD+trace holds up to 16 million samples,
250 * but trigger counts is set in multiples of 16 */
251 trigger_count
= (1048576 * etm_ctx
->trigger_percent
) / 100;
253 /* capturing always starts at address zero */
254 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_ADDRESS
, 0x0);
255 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_TRIGGER_COUNTER
, trigger_count
);
256 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, control
);
258 /* we're starting a new trace, initialize capture status */
259 etm_ctx
->capture_status
= TRACE_RUNNING
;
264 static int oocd_trace_stop_capture(etm_context_t
*etm_ctx
)
266 oocd_trace_t
*oocd_trace
= etm_ctx
->capture_driver_priv
;
268 /* trace stopped, just clear running flag, but preserve others */
269 etm_ctx
->capture_status
&= ~TRACE_RUNNING
;
271 oocd_trace_write_reg(oocd_trace
, OOCD_TRACE_CONTROL
, 0x0);
276 etm_capture_driver_t oocd_trace_capture_driver
=
278 .name
= "oocd_trace",
279 .register_commands
= oocd_trace_register_commands
,
280 .init
= oocd_trace_init
,
281 .status
= oocd_trace_status
,
282 .start_capture
= oocd_trace_start_capture
,
283 .stop_capture
= oocd_trace_stop_capture
,
284 .read_trace
= oocd_trace_read_trace
,
287 static int handle_oocd_trace_config_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
290 armv4_5_common_t
*armv4_5
;
291 arm7_9_common_t
*arm7_9
;
295 LOG_ERROR("incomplete 'oocd_trace config <target> <tty>' command");
299 target
= get_current_target(cmd_ctx
);
301 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
303 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
309 oocd_trace_t
*oocd_trace
= malloc(sizeof(oocd_trace_t
));
311 arm7_9
->etm_ctx
->capture_driver_priv
= oocd_trace
;
312 oocd_trace
->etm_ctx
= arm7_9
->etm_ctx
;
314 /* copy name of TTY device used to communicate with OpenOCD+trace */
315 oocd_trace
->tty
= strndup(args
[1], 256);
319 LOG_ERROR("target has no ETM defined, OpenOCD+trace left unconfigured");
325 static int handle_oocd_trace_status_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
328 armv4_5_common_t
*armv4_5
;
329 arm7_9_common_t
*arm7_9
;
330 oocd_trace_t
*oocd_trace
;
333 target
= get_current_target(cmd_ctx
);
335 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
337 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
341 if (!arm7_9
->etm_ctx
)
343 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
347 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
349 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
353 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
355 oocd_trace_read_reg(oocd_trace
, OOCD_TRACE_STATUS
, &status
);
358 command_print(cmd_ctx
, "trace clock locked");
360 command_print(cmd_ctx
, "no trace clock");
365 static int handle_oocd_trace_resync_command(struct command_context_s
*cmd_ctx
, char *cmd
, char **args
, int argc
)
368 armv4_5_common_t
*armv4_5
;
369 arm7_9_common_t
*arm7_9
;
370 oocd_trace_t
*oocd_trace
;
371 size_t bytes_written
;
374 target
= get_current_target(cmd_ctx
);
376 if (arm7_9_get_arch_pointers(target
, &armv4_5
, &arm7_9
) != ERROR_OK
)
378 command_print(cmd_ctx
, "current target isn't an ARM7/ARM9 target");
382 if (!arm7_9
->etm_ctx
)
384 command_print(cmd_ctx
, "current target doesn't have an ETM configured");
388 if (strcmp(arm7_9
->etm_ctx
->capture_driver
->name
, "oocd_trace") != 0)
390 command_print(cmd_ctx
, "current target's ETM capture driver isn't 'oocd_trace'");
394 oocd_trace
= (oocd_trace_t
*)arm7_9
->etm_ctx
->capture_driver_priv
;
398 bytes_written
= write(oocd_trace
->tty_fd
, cmd_array
, 1);
400 command_print(cmd_ctx
, "requesting traceclock resync");
401 LOG_DEBUG("resyncing traceclk pll");
406 int oocd_trace_register_commands(struct command_context_s
*cmd_ctx
)
408 command_t
*oocd_trace_cmd
;
410 oocd_trace_cmd
= register_command(cmd_ctx
, NULL
, "oocd_trace", NULL
, COMMAND_ANY
, "OpenOCD+trace");
412 register_command(cmd_ctx
, oocd_trace_cmd
, "config", handle_oocd_trace_config_command
, COMMAND_CONFIG
, NULL
);
414 register_command(cmd_ctx
, oocd_trace_cmd
, "status", handle_oocd_trace_status_command
, COMMAND_EXEC
, "display OpenOCD+trace status");
415 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)