armv7a: remove special l2x flush-all and cache-info handlers
[openocd.git] / src / target / armv7a_cache.c
1 /***************************************************************************
2 * Copyright (C) 2015 by Oleksij Rempel *
3 * linux@rempel-privat.de *
4 * *
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. *
9 * *
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. *
14 ***************************************************************************/
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #include "jtag/interface.h"
21 #include "arm.h"
22 #include "armv7a.h"
23 #include "armv7a_cache.h"
24 #include <helper/time_support.h>
25 #include "arm_opcodes.h"
26
27 static int armv7a_l1_d_cache_sanity_check(struct target *target)
28 {
29 struct armv7a_common *armv7a = target_to_armv7a(target);
30
31 if (target->state != TARGET_HALTED) {
32 LOG_ERROR("%s: target not halted", __func__);
33 return ERROR_TARGET_NOT_HALTED;
34 }
35
36 /* check that cache data is on at target halt */
37 if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
38 LOG_DEBUG("l1 data cache is not enabled");
39 return ERROR_TARGET_INVALID;
40 }
41
42 return ERROR_OK;
43 }
44
45 static int armv7a_l1_i_cache_sanity_check(struct target *target)
46 {
47 struct armv7a_common *armv7a = target_to_armv7a(target);
48
49 if (target->state != TARGET_HALTED) {
50 LOG_ERROR("%s: target not halted", __func__);
51 return ERROR_TARGET_NOT_HALTED;
52 }
53
54 /* check that cache data is on at target halt */
55 if (!armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) {
56 LOG_DEBUG("l1 data cache is not enabled");
57 return ERROR_TARGET_INVALID;
58 }
59
60 return ERROR_OK;
61 }
62
63 static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
64 {
65 struct armv7a_common *armv7a = target_to_armv7a(target);
66 struct arm_dpm *dpm = armv7a->arm.dpm;
67 struct armv7a_cachesize *d_u_size =
68 &(armv7a->armv7a_mmu.armv7a_cache.d_u_size);
69 int32_t c_way, c_index = d_u_size->index;
70 int retval;
71
72 retval = armv7a_l1_d_cache_sanity_check(target);
73 if (retval != ERROR_OK)
74 return retval;
75
76 retval = dpm->prepare(dpm);
77 if (retval != ERROR_OK)
78 goto done;
79
80 do {
81 c_way = d_u_size->way;
82 do {
83 uint32_t value = (c_index << d_u_size->index_shift)
84 | (c_way << d_u_size->way_shift);
85 /*
86 * DCCISW - Clean and invalidate data cache
87 * line by Set/Way.
88 */
89 retval = dpm->instr_write_data_r0(dpm,
90 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
91 value);
92 if (retval != ERROR_OK)
93 goto done;
94 c_way -= 1;
95 } while (c_way >= 0);
96 c_index -= 1;
97 } while (c_index >= 0);
98
99 return retval;
100
101 done:
102 LOG_ERROR("clean invalidate failed");
103 dpm->finish(dpm);
104
105 return retval;
106 }
107
108 int armv7a_cache_auto_flush_all_data(struct target *target)
109 {
110 int retval = ERROR_FAIL;
111 struct armv7a_common *armv7a = target_to_armv7a(target);
112
113 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
114 return ERROR_OK;
115
116 if (target->smp) {
117 struct target_list *head;
118 struct target *curr;
119 head = target->head;
120 while (head != (struct target_list *)NULL) {
121 curr = head->target;
122 if (curr->state == TARGET_HALTED)
123 retval = armv7a_l1_d_cache_clean_inval_all(curr);
124
125 head = head->next;
126 }
127 } else
128 retval = armv7a_l1_d_cache_clean_inval_all(target);
129
130 /* do outer cache flushing after inner caches have been flushed */
131 retval = arm7a_l2x_flush_all_data(target);
132
133 return retval;
134 }
135
136
137 static int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
138 uint32_t size)
139 {
140 struct armv7a_common *armv7a = target_to_armv7a(target);
141 struct arm_dpm *dpm = armv7a->arm.dpm;
142 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
143 uint32_t i, linelen = armv7a_cache->dminline;
144 int retval;
145
146 retval = armv7a_l1_d_cache_sanity_check(target);
147 if (retval != ERROR_OK)
148 return retval;
149
150 retval = dpm->prepare(dpm);
151 if (retval != ERROR_OK)
152 goto done;
153
154 for (i = 0; i < size; i += linelen) {
155 uint32_t offs = virt + i;
156
157 /* DCIMVAC - Clean and invalidate data cache line by VA to PoC. */
158 retval = dpm->instr_write_data_r0(dpm,
159 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), offs);
160 if (retval != ERROR_OK)
161 goto done;
162 }
163 return retval;
164
165 done:
166 LOG_ERROR("d-cache invalidate failed");
167 dpm->finish(dpm);
168
169 return retval;
170 }
171
172 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
173 unsigned int size)
174 {
175 struct armv7a_common *armv7a = target_to_armv7a(target);
176 struct arm_dpm *dpm = armv7a->arm.dpm;
177 struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
178 uint32_t i, linelen = armv7a_cache->dminline;
179 int retval;
180
181 retval = armv7a_l1_d_cache_sanity_check(target);
182 if (retval != ERROR_OK)
183 return retval;
184
185 retval = dpm->prepare(dpm);
186 if (retval != ERROR_OK)
187 goto done;
188
189 for (i = 0; i < size; i += linelen) {
190 uint32_t offs = virt + i;
191
192 /* FIXME: do we need DCCVAC or DCCVAU */
193 /* FIXME: in both cases it is not enough for i-cache */
194 retval = dpm->instr_write_data_r0(dpm,
195 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), offs);
196 if (retval != ERROR_OK)
197 goto done;
198 }
199 return retval;
200
201 done:
202 LOG_ERROR("d-cache invalidate failed");
203 dpm->finish(dpm);
204
205 return retval;
206 }
207
208 int armv7a_l1_i_cache_inval_all(struct target *target)
209 {
210 struct armv7a_common *armv7a = target_to_armv7a(target);
211 struct arm_dpm *dpm = armv7a->arm.dpm;
212 int retval;
213
214 retval = armv7a_l1_i_cache_sanity_check(target);
215 if (retval != ERROR_OK)
216 return retval;
217
218 retval = dpm->prepare(dpm);
219 if (retval != ERROR_OK)
220 goto done;
221
222 if (target->smp) {
223 /* ICIALLUIS */
224 retval = dpm->instr_write_data_r0(dpm,
225 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
226 } else {
227 /* ICIALLU */
228 retval = dpm->instr_write_data_r0(dpm,
229 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
230 }
231
232 if (retval != ERROR_OK)
233 goto done;
234
235 dpm->finish(dpm);
236 return retval;
237
238 done:
239 LOG_ERROR("i-cache invalidate failed");
240 dpm->finish(dpm);
241
242 return retval;
243 }
244
245 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
246 uint32_t size)
247 {
248 struct armv7a_common *armv7a = target_to_armv7a(target);
249 struct arm_dpm *dpm = armv7a->arm.dpm;
250 struct armv7a_cache_common *armv7a_cache =
251 &armv7a->armv7a_mmu.armv7a_cache;
252 uint32_t linelen = armv7a_cache->iminline;
253 uint32_t va_line, va_end;
254 int retval;
255
256 retval = armv7a_l1_i_cache_sanity_check(target);
257 if (retval != ERROR_OK)
258 return retval;
259
260 retval = dpm->prepare(dpm);
261 if (retval != ERROR_OK)
262 goto done;
263
264 va_line = virt & (-linelen);
265 va_end = virt + size;
266
267 while (va_line < va_end) {
268 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
269 retval = dpm->instr_write_data_r0(dpm,
270 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
271 if (retval != ERROR_OK)
272 goto done;
273 /* BPIMVA */
274 retval = dpm->instr_write_data_r0(dpm,
275 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
276 if (retval != ERROR_OK)
277 goto done;
278 va_line += linelen;
279 }
280 return retval;
281
282 done:
283 LOG_ERROR("i-cache invalidate failed");
284 dpm->finish(dpm);
285
286 return retval;
287 }
288
289
290 /*
291 * We assume that target core was chosen correctly. It means if same data
292 * was handled by two cores, other core will loose the changes. Since it
293 * is impossible to know (FIXME) which core has correct data, keep in mind
294 * that some kind of data lost or korruption is possible.
295 * Possible scenario:
296 * - core1 loaded and changed data on 0x12345678
297 * - we halted target and modified same data on core0
298 * - data on core1 will be lost.
299 */
300 int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt,
301 uint32_t size)
302 {
303 struct armv7a_common *armv7a = target_to_armv7a(target);
304 int retval = ERROR_OK;
305
306 if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled)
307 return ERROR_OK;
308
309 armv7a_l1_d_cache_clean_virt(target, virt, size);
310 armv7a_l2x_cache_flush_virt(target, virt, size);
311
312 if (target->smp) {
313 struct target_list *head;
314 struct target *curr;
315 head = target->head;
316 while (head != (struct target_list *)NULL) {
317 curr = head->target;
318 if (curr->state == TARGET_HALTED) {
319 retval = armv7a_l1_i_cache_inval_all(curr);
320 if (retval != ERROR_OK)
321 return retval;
322 retval = armv7a_l1_d_cache_inval_virt(target,
323 virt, size);
324 if (retval != ERROR_OK)
325 return retval;
326 }
327 head = head->next;
328 }
329 } else {
330 retval = armv7a_l1_i_cache_inval_all(target);
331 if (retval != ERROR_OK)
332 return retval;
333 retval = armv7a_l1_d_cache_inval_virt(target, virt, size);
334 if (retval != ERROR_OK)
335 return retval;
336 }
337
338 return retval;
339 }
340
341 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
342 {
343 struct target *target = get_current_target(CMD_CTX);
344 struct armv7a_common *armv7a = target_to_armv7a(target);
345
346 return armv7a_handle_cache_info_command(CMD_CTX,
347 &armv7a->armv7a_mmu.armv7a_cache);
348 }
349
350 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
351 {
352 struct target *target = get_current_target(CMD_CTX);
353
354 armv7a_l1_d_cache_clean_inval_all(target);
355
356 return 0;
357 }
358
359 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
360 {
361 struct target *target = get_current_target(CMD_CTX);
362 uint32_t virt, size;
363
364 if (CMD_ARGC == 0 || CMD_ARGC > 2)
365 return ERROR_COMMAND_SYNTAX_ERROR;
366
367 if (CMD_ARGC == 2)
368 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
369 else
370 size = 1;
371
372 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
373
374 return armv7a_l1_d_cache_inval_virt(target, virt, size);
375 }
376
377 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
378 {
379 struct target *target = get_current_target(CMD_CTX);
380 uint32_t virt, size;
381
382 if (CMD_ARGC == 0 || CMD_ARGC > 2)
383 return ERROR_COMMAND_SYNTAX_ERROR;
384
385 if (CMD_ARGC == 2)
386 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
387 else
388 size = 1;
389
390 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
391
392 return armv7a_l1_d_cache_clean_virt(target, virt, size);
393 }
394
395 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
396 {
397 struct target *target = get_current_target(CMD_CTX);
398
399 armv7a_l1_i_cache_inval_all(target);
400
401 return 0;
402 }
403
404 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
405 {
406 struct target *target = get_current_target(CMD_CTX);
407 uint32_t virt, size;
408
409 if (CMD_ARGC == 0 || CMD_ARGC > 2)
410 return ERROR_COMMAND_SYNTAX_ERROR;
411
412 if (CMD_ARGC == 2)
413 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size);
414 else
415 size = 1;
416
417 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
418
419 return armv7a_l1_i_cache_inval_virt(target, virt, size);
420 }
421
422 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
423 {
424 struct target *target = get_current_target(CMD_CTX);
425 struct armv7a_common *armv7a = target_to_armv7a(target);
426
427 if (CMD_ARGC == 0) {
428 command_print(CMD_CTX, "auto cache is %s",
429 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
430 return ERROR_OK;
431 }
432
433 if (CMD_ARGC == 1) {
434 uint32_t set;
435
436 COMMAND_PARSE_ENABLE(CMD_ARGV[0], set);
437 armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled = !!set;
438 return ERROR_OK;
439 }
440
441 return ERROR_COMMAND_SYNTAX_ERROR;
442 }
443
444 static const struct command_registration arm7a_l1_d_cache_commands[] = {
445 {
446 .name = "flush_all",
447 .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
448 .mode = COMMAND_ANY,
449 .help = "flush (clean and invalidate) complete l1 d-cache",
450 .usage = "",
451 },
452 {
453 .name = "inval",
454 .handler = arm7a_l1_d_cache_inval_virt_cmd,
455 .mode = COMMAND_ANY,
456 .help = "invalidate l1 d-cache by virtual address offset and range size",
457 .usage = "<virt_addr> [size]",
458 },
459 {
460 .name = "clean",
461 .handler = arm7a_l1_d_cache_clean_virt_cmd,
462 .mode = COMMAND_ANY,
463 .help = "clean l1 d-cache by virtual address address offset and range size",
464 .usage = "<virt_addr> [size]",
465 },
466 COMMAND_REGISTRATION_DONE
467 };
468
469 static const struct command_registration arm7a_l1_i_cache_commands[] = {
470 {
471 .name = "inval_all",
472 .handler = armv7a_i_cache_clean_inval_all_cmd,
473 .mode = COMMAND_ANY,
474 .help = "invalidate complete l1 i-cache",
475 .usage = "",
476 },
477 {
478 .name = "inval",
479 .handler = arm7a_l1_i_cache_inval_virt_cmd,
480 .mode = COMMAND_ANY,
481 .help = "invalidate l1 i-cache by virtual address offset and range size",
482 .usage = "<virt_addr> [size]",
483 },
484 COMMAND_REGISTRATION_DONE
485 };
486
487 const struct command_registration arm7a_l1_di_cache_group_handlers[] = {
488 {
489 .name = "info",
490 .handler = arm7a_l1_cache_info_cmd,
491 .mode = COMMAND_ANY,
492 .help = "print cache realted information",
493 .usage = "",
494 },
495 {
496 .name = "d",
497 .mode = COMMAND_ANY,
498 .help = "l1 d-cache command group",
499 .usage = "",
500 .chain = arm7a_l1_d_cache_commands,
501 },
502 {
503 .name = "i",
504 .mode = COMMAND_ANY,
505 .help = "l1 i-cache command group",
506 .usage = "",
507 .chain = arm7a_l1_i_cache_commands,
508 },
509 COMMAND_REGISTRATION_DONE
510 };
511
512 const struct command_registration arm7a_cache_group_handlers[] = {
513 {
514 .name = "auto",
515 .handler = arm7a_cache_disable_auto_cmd,
516 .mode = COMMAND_ANY,
517 .help = "disable or enable automatic cache handling.",
518 .usage = "(1|0)",
519 },
520 {
521 .name = "l1",
522 .mode = COMMAND_ANY,
523 .help = "l1 cache command group",
524 .usage = "",
525 .chain = arm7a_l1_di_cache_group_handlers,
526 },
527 {
528 .chain = arm7a_l2x_cache_command_handler,
529 },
530 COMMAND_REGISTRATION_DONE
531 };
532
533 const struct command_registration arm7a_cache_command_handlers[] = {
534 {
535 .name = "cache",
536 .mode = COMMAND_ANY,
537 .help = "cache command group",
538 .usage = "",
539 .chain = arm7a_cache_group_handlers,
540 },
541 COMMAND_REGISTRATION_DONE
542 };

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)