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

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)