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