armv7a_mmu: s/LOG_ERROR/LOG_WARNING/ on address translation failure
[openocd.git] / src / target / armv7m_trace.c
1 /***************************************************************************
2 * Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <target/target.h>
23 #include <target/armv7m.h>
24 #include <target/cortex_m.h>
25 #include <target/armv7m_trace.h>
26 #include <jtag/interface.h>
27
28 #define TRACE_BUF_SIZE 4096
29
30 static int armv7m_poll_trace(void *target)
31 {
32 struct armv7m_common *armv7m = target_to_armv7m(target);
33 uint8_t buf[TRACE_BUF_SIZE];
34 size_t size = sizeof(buf);
35 int retval;
36
37 retval = adapter_poll_trace(buf, &size);
38 if (retval != ERROR_OK || !size)
39 return retval;
40
41 target_call_trace_callbacks(target, size, buf);
42
43 if (armv7m->trace_config.trace_file != NULL) {
44 if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size)
45 fflush(armv7m->trace_config.trace_file);
46 else {
47 LOG_ERROR("Error writing to the trace destination file");
48 return ERROR_FAIL;
49 }
50 }
51
52 return ERROR_OK;
53 }
54
55 int armv7m_trace_tpiu_config(struct target *target)
56 {
57 struct armv7m_common *armv7m = target_to_armv7m(target);
58 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
59 int prescaler;
60 int retval;
61
62 target_unregister_timer_callback(armv7m_poll_trace, target);
63
64
65 retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
66 trace_config->pin_protocol,
67 trace_config->port_size,
68 &trace_config->trace_freq);
69 if (retval != ERROR_OK)
70 return retval;
71
72 if (!trace_config->trace_freq) {
73 LOG_ERROR("Trace port frequency is 0, can't enable TPIU");
74 return ERROR_FAIL;
75 }
76
77 prescaler = trace_config->traceclkin_freq / trace_config->trace_freq;
78
79 if (trace_config->traceclkin_freq % trace_config->trace_freq) {
80 prescaler++;
81 int trace_freq = trace_config->traceclkin_freq / prescaler;
82 LOG_INFO("Can not obtain %u trace port frequency from %u TRACECLKIN frequency, using %u instead",
83 trace_config->trace_freq, trace_config->traceclkin_freq,
84 trace_freq);
85 trace_config->trace_freq = trace_freq;
86 retval = adapter_config_trace(trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL,
87 trace_config->pin_protocol,
88 trace_config->port_size,
89 &trace_config->trace_freq);
90 if (retval != ERROR_OK)
91 return retval;
92 }
93
94 retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size);
95 if (retval != ERROR_OK)
96 return retval;
97
98 retval = target_write_u32(target, TPIU_ACPR, prescaler - 1);
99 if (retval != ERROR_OK)
100 return retval;
101
102 retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol);
103 if (retval != ERROR_OK)
104 return retval;
105
106 uint32_t ffcr;
107 retval = target_read_u32(target, TPIU_FFCR, &ffcr);
108 if (retval != ERROR_OK)
109 return retval;
110 if (trace_config->formatter)
111 ffcr |= (1 << 1);
112 else
113 ffcr &= ~(1 << 1);
114 retval = target_write_u32(target, TPIU_FFCR, ffcr);
115 if (retval != ERROR_OK)
116 return retval;
117
118 if (trace_config->config_type == TRACE_CONFIG_TYPE_INTERNAL)
119 target_register_timer_callback(armv7m_poll_trace, 1, 1, target);
120
121 target_call_event_callbacks(target, TARGET_EVENT_TRACE_CONFIG);
122
123 return ERROR_OK;
124 }
125
126 int armv7m_trace_itm_config(struct target *target)
127 {
128 struct armv7m_common *armv7m = target_to_armv7m(target);
129 struct armv7m_trace_config *trace_config = &armv7m->trace_config;
130 int retval;
131
132 retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY);
133 if (retval != ERROR_OK)
134 return retval;
135
136 /* Enable ITM, TXENA, set TraceBusID and other parameters */
137 retval = target_write_u32(target, ITM_TCR, (1 << 0) | (1 << 3) |
138 (trace_config->itm_diff_timestamps << 1) |
139 (trace_config->itm_synchro_packets << 2) |
140 (trace_config->itm_async_timestamps << 4) |
141 (trace_config->itm_ts_prescale << 8) |
142 (trace_config->trace_bus_id << 16));
143 if (retval != ERROR_OK)
144 return retval;
145
146 for (unsigned int i = 0; i < 8; i++) {
147 retval = target_write_u32(target, ITM_TER0 + i * 4,
148 trace_config->itm_ter[i]);
149 if (retval != ERROR_OK)
150 return retval;
151 }
152
153 return ERROR_OK;
154 }
155
156 static void close_trace_file(struct armv7m_common *armv7m)
157 {
158 if (armv7m->trace_config.trace_file)
159 fclose(armv7m->trace_config.trace_file);
160 armv7m->trace_config.trace_file = NULL;
161 }
162
163 COMMAND_HANDLER(handle_tpiu_config_command)
164 {
165 struct target *target = get_current_target(CMD_CTX);
166 struct armv7m_common *armv7m = target_to_armv7m(target);
167
168 unsigned int cmd_idx = 0;
169
170 if (CMD_ARGC == cmd_idx)
171 return ERROR_COMMAND_SYNTAX_ERROR;
172 if (!strcmp(CMD_ARGV[cmd_idx], "disable")) {
173 if (CMD_ARGC == cmd_idx + 1) {
174 close_trace_file(armv7m);
175
176 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED;
177 if (CMD_CTX->mode == COMMAND_EXEC)
178 return armv7m_trace_tpiu_config(target);
179 else
180 return ERROR_OK;
181 }
182 } else if (!strcmp(CMD_ARGV[cmd_idx], "external") ||
183 !strcmp(CMD_ARGV[cmd_idx], "internal")) {
184 close_trace_file(armv7m);
185
186 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL;
187 if (!strcmp(CMD_ARGV[cmd_idx], "internal")) {
188 cmd_idx++;
189 if (CMD_ARGC == cmd_idx)
190 return ERROR_COMMAND_SYNTAX_ERROR;
191
192 armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL;
193
194 if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) {
195 armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab");
196 if (!armv7m->trace_config.trace_file) {
197 LOG_ERROR("Can't open trace destination file");
198 return ERROR_FAIL;
199 }
200 }
201 }
202 cmd_idx++;
203 if (CMD_ARGC == cmd_idx)
204 return ERROR_COMMAND_SYNTAX_ERROR;
205
206 if (!strcmp(CMD_ARGV[cmd_idx], "sync")) {
207 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_SYNC;
208
209 cmd_idx++;
210 if (CMD_ARGC == cmd_idx)
211 return ERROR_COMMAND_SYNTAX_ERROR;
212
213 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx], armv7m->trace_config.port_size);
214 } else {
215 if (!strcmp(CMD_ARGV[cmd_idx], "manchester"))
216 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER;
217 else if (!strcmp(CMD_ARGV[cmd_idx], "uart"))
218 armv7m->trace_config.pin_protocol = TPIU_PIN_PROTOCOL_ASYNC_UART;
219 else
220 return ERROR_COMMAND_SYNTAX_ERROR;
221
222 cmd_idx++;
223 if (CMD_ARGC == cmd_idx)
224 return ERROR_COMMAND_SYNTAX_ERROR;
225
226 COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx], armv7m->trace_config.formatter);
227 }
228
229 cmd_idx++;
230 if (CMD_ARGC == cmd_idx)
231 return ERROR_COMMAND_SYNTAX_ERROR;
232
233 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.traceclkin_freq);
234
235 cmd_idx++;
236 if (CMD_ARGC != cmd_idx) {
237 COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq);
238 cmd_idx++;
239 } else {
240 if (armv7m->trace_config.config_type != TRACE_CONFIG_TYPE_INTERNAL) {
241 LOG_ERROR("Trace port frequency can't be omitted in external capture mode");
242 return ERROR_COMMAND_SYNTAX_ERROR;
243 }
244 armv7m->trace_config.trace_freq = 0;
245 }
246
247 if (CMD_ARGC == cmd_idx) {
248 if (CMD_CTX->mode == COMMAND_EXEC)
249 return armv7m_trace_tpiu_config(target);
250 else
251 return ERROR_OK;
252 }
253 }
254
255 return ERROR_COMMAND_SYNTAX_ERROR;
256 }
257
258 COMMAND_HANDLER(handle_itm_port_command)
259 {
260 struct target *target = get_current_target(CMD_CTX);
261 struct armv7m_common *armv7m = target_to_armv7m(target);
262 unsigned int reg_idx;
263 uint8_t port;
264 bool enable;
265
266 if (CMD_ARGC != 2)
267 return ERROR_COMMAND_SYNTAX_ERROR;
268
269 COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port);
270 COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
271 reg_idx = port / 32;
272 port = port % 32;
273 if (enable)
274 armv7m->trace_config.itm_ter[reg_idx] |= (1 << port);
275 else
276 armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port);
277
278 if (CMD_CTX->mode == COMMAND_EXEC)
279 return armv7m_trace_itm_config(target);
280 else
281 return ERROR_OK;
282 }
283
284 COMMAND_HANDLER(handle_itm_ports_command)
285 {
286 struct target *target = get_current_target(CMD_CTX);
287 struct armv7m_common *armv7m = target_to_armv7m(target);
288 bool enable;
289
290 if (CMD_ARGC != 1)
291 return ERROR_COMMAND_SYNTAX_ERROR;
292
293 COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
294 memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0,
295 sizeof(armv7m->trace_config.itm_ter));
296
297 if (CMD_CTX->mode == COMMAND_EXEC)
298 return armv7m_trace_itm_config(target);
299 else
300 return ERROR_OK;
301 }
302
303 static const struct command_registration tpiu_command_handlers[] = {
304 {
305 .name = "config",
306 .handler = handle_tpiu_config_command,
307 .mode = COMMAND_ANY,
308 .help = "Configure TPIU features",
309 .usage = "(disable | "
310 "((external | internal <filename>) "
311 "(sync <port width> | ((manchester | uart) <formatter enable>)) "
312 "<TRACECLKIN freq> [<trace freq>]))",
313 },
314 COMMAND_REGISTRATION_DONE
315 };
316
317 static const struct command_registration itm_command_handlers[] = {
318 {
319 .name = "port",
320 .handler = handle_itm_port_command,
321 .mode = COMMAND_ANY,
322 .help = "Enable or disable ITM stimulus port",
323 .usage = "<port> (0|1|on|off)",
324 },
325 {
326 .name = "ports",
327 .handler = handle_itm_ports_command,
328 .mode = COMMAND_ANY,
329 .help = "Enable or disable all ITM stimulus ports",
330 .usage = "(0|1|on|off)",
331 },
332 COMMAND_REGISTRATION_DONE
333 };
334
335 const struct command_registration armv7m_trace_command_handlers[] = {
336 {
337 .name = "tpiu",
338 .mode = COMMAND_ANY,
339 .help = "tpiu command group",
340 .usage = "",
341 .chain = tpiu_command_handlers,
342 },
343 {
344 .name = "itm",
345 .mode = COMMAND_ANY,
346 .help = "itm command group",
347 .usage = "",
348 .chain = itm_command_handlers,
349 },
350 COMMAND_REGISTRATION_DONE
351 };

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)