1 /***************************************************************************
2 * Copyright (C) 2015 by Oleksij Rempel *
3 * linux@rempel-privat.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. *
14 ***************************************************************************/
20 #include "jtag/interface.h"
23 #include "armv7a_cache.h"
24 #include <helper/time_support.h>
25 #include "arm_opcodes.h"
27 static int armv7a_l1_d_cache_sanity_check(struct target
*target
)
29 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
31 if (target
->state
!= TARGET_HALTED
) {
32 LOG_ERROR("%s: target not halted", __func__
);
33 return ERROR_TARGET_NOT_HALTED
;
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
;
45 static int armv7a_l1_i_cache_sanity_check(struct target
*target
)
47 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
49 if (target
->state
!= TARGET_HALTED
) {
50 LOG_ERROR("%s: target not halted", __func__
);
51 return ERROR_TARGET_NOT_HALTED
;
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
;
63 static int armv7a_l1_d_cache_flush_level(struct arm_dpm
*dpm
, struct armv7a_cachesize
*size
, int cl
)
65 int retval
= ERROR_OK
;
66 int32_t c_way
, c_index
= size
->index
;
68 LOG_DEBUG("cl %" PRId32
, cl
);
72 uint32_t value
= (c_index
<< size
->index_shift
)
73 | (c_way
<< size
->way_shift
) | (cl
<< 1);
75 * DCCISW - Clean and invalidate data cache
78 retval
= dpm
->instr_write_data_r0(dpm
,
79 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
81 if (retval
!= ERROR_OK
)
86 } while (c_index
>= 0);
92 static int armv7a_l1_d_cache_clean_inval_all(struct target
*target
)
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
;
100 retval
= armv7a_l1_d_cache_sanity_check(target
);
101 if (retval
!= ERROR_OK
)
104 retval
= dpm
->prepare(dpm
);
105 if (retval
!= ERROR_OK
)
108 for (cl
= 0; cl
< cache
->loc
; cl
++) {
109 /* skip i-only caches */
110 if (cache
->arch
[cl
].ctype
< CACHE_LEVEL_HAS_D_CACHE
)
113 armv7a_l1_d_cache_flush_level(dpm
, &cache
->arch
[cl
].d_u_size
, cl
);
116 retval
= dpm
->finish(dpm
);
120 LOG_ERROR("clean invalidate failed");
126 int armv7a_cache_auto_flush_all_data(struct target
*target
)
128 int retval
= ERROR_FAIL
;
129 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
131 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
135 struct target_list
*head
;
138 while (head
!= (struct target_list
*)NULL
) {
140 if (curr
->state
== TARGET_HALTED
)
141 retval
= armv7a_l1_d_cache_clean_inval_all(curr
);
146 retval
= armv7a_l1_d_cache_clean_inval_all(target
);
148 /* do outer cache flushing after inner caches have been flushed */
149 retval
= arm7a_l2x_flush_all_data(target
);
155 static int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
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 i
, linelen
= armv7a_cache
->dminline
;
164 retval
= armv7a_l1_d_cache_sanity_check(target
);
165 if (retval
!= ERROR_OK
)
168 retval
= dpm
->prepare(dpm
);
169 if (retval
!= ERROR_OK
)
172 for (i
= 0; i
< size
; i
+= linelen
) {
173 uint32_t offs
= virt
+ i
;
175 /* DCIMVAC - Clean and invalidate data cache line by VA to PoC. */
176 retval
= dpm
->instr_write_data_r0(dpm
,
177 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), offs
);
178 if (retval
!= ERROR_OK
)
184 LOG_ERROR("d-cache invalidate failed");
190 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
193 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
194 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
195 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
196 uint32_t i
, linelen
= armv7a_cache
->dminline
;
199 retval
= armv7a_l1_d_cache_sanity_check(target
);
200 if (retval
!= ERROR_OK
)
203 retval
= dpm
->prepare(dpm
);
204 if (retval
!= ERROR_OK
)
207 for (i
= 0; i
< size
; i
+= linelen
) {
208 uint32_t offs
= virt
+ i
;
210 /* FIXME: do we need DCCVAC or DCCVAU */
211 /* FIXME: in both cases it is not enough for i-cache */
212 retval
= dpm
->instr_write_data_r0(dpm
,
213 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), offs
);
214 if (retval
!= ERROR_OK
)
220 LOG_ERROR("d-cache invalidate failed");
226 int armv7a_l1_d_cache_flush_virt(struct target
*target
, uint32_t virt
,
229 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
230 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
231 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
232 uint32_t i
, linelen
= armv7a_cache
->dminline
;
235 retval
= armv7a_l1_d_cache_sanity_check(target
);
236 if (retval
!= ERROR_OK
)
239 retval
= dpm
->prepare(dpm
);
240 if (retval
!= ERROR_OK
)
243 for (i
= 0; i
< size
; i
+= linelen
) {
244 uint32_t offs
= virt
+ i
;
247 retval
= dpm
->instr_write_data_r0(dpm
,
248 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), offs
);
249 if (retval
!= ERROR_OK
)
255 LOG_ERROR("d-cache invalidate failed");
261 int armv7a_l1_i_cache_inval_all(struct target
*target
)
263 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
264 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
267 retval
= armv7a_l1_i_cache_sanity_check(target
);
268 if (retval
!= ERROR_OK
)
271 retval
= dpm
->prepare(dpm
);
272 if (retval
!= ERROR_OK
)
277 retval
= dpm
->instr_write_data_r0(dpm
,
278 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
281 retval
= dpm
->instr_write_data_r0(dpm
,
282 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
285 if (retval
!= ERROR_OK
)
292 LOG_ERROR("i-cache invalidate failed");
298 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
301 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
302 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
303 struct armv7a_cache_common
*armv7a_cache
=
304 &armv7a
->armv7a_mmu
.armv7a_cache
;
305 uint32_t linelen
= armv7a_cache
->iminline
;
306 uint32_t va_line
, va_end
;
309 retval
= armv7a_l1_i_cache_sanity_check(target
);
310 if (retval
!= ERROR_OK
)
313 retval
= dpm
->prepare(dpm
);
314 if (retval
!= ERROR_OK
)
317 va_line
= virt
& (-linelen
);
318 va_end
= virt
+ size
;
320 while (va_line
< va_end
) {
321 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
322 retval
= dpm
->instr_write_data_r0(dpm
,
323 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
324 if (retval
!= ERROR_OK
)
327 retval
= dpm
->instr_write_data_r0(dpm
,
328 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
329 if (retval
!= ERROR_OK
)
336 LOG_ERROR("i-cache invalidate failed");
344 * We assume that target core was chosen correctly. It means if same data
345 * was handled by two cores, other core will loose the changes. Since it
346 * is impossible to know (FIXME) which core has correct data, keep in mind
347 * that some kind of data lost or korruption is possible.
349 * - core1 loaded and changed data on 0x12345678
350 * - we halted target and modified same data on core0
351 * - data on core1 will be lost.
353 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
356 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
357 int retval
= ERROR_OK
;
359 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
362 armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
363 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
366 struct target_list
*head
;
369 while (head
!= (struct target_list
*)NULL
) {
371 if (curr
->state
== TARGET_HALTED
) {
372 retval
= armv7a_l1_i_cache_inval_all(curr
);
373 if (retval
!= ERROR_OK
)
375 retval
= armv7a_l1_d_cache_inval_virt(target
,
377 if (retval
!= ERROR_OK
)
383 retval
= armv7a_l1_i_cache_inval_all(target
);
384 if (retval
!= ERROR_OK
)
386 retval
= armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
387 if (retval
!= ERROR_OK
)
394 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
396 struct target
*target
= get_current_target(CMD_CTX
);
397 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
399 return armv7a_handle_cache_info_command(CMD_CTX
,
400 &armv7a
->armv7a_mmu
.armv7a_cache
);
403 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
405 struct target
*target
= get_current_target(CMD_CTX
);
407 armv7a_l1_d_cache_clean_inval_all(target
);
412 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
414 struct target
*target
= get_current_target(CMD_CTX
);
417 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
418 return ERROR_COMMAND_SYNTAX_ERROR
;
421 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
425 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
427 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
430 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
432 struct target
*target
= get_current_target(CMD_CTX
);
435 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
436 return ERROR_COMMAND_SYNTAX_ERROR
;
439 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
443 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
445 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
448 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
450 struct target
*target
= get_current_target(CMD_CTX
);
452 armv7a_l1_i_cache_inval_all(target
);
457 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
459 struct target
*target
= get_current_target(CMD_CTX
);
462 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
463 return ERROR_COMMAND_SYNTAX_ERROR
;
466 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
470 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
472 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
475 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
477 struct target
*target
= get_current_target(CMD_CTX
);
478 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
481 command_print(CMD_CTX
, "auto cache is %s",
482 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
489 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
490 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
494 return ERROR_COMMAND_SYNTAX_ERROR
;
497 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
500 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
502 .help
= "flush (clean and invalidate) complete l1 d-cache",
507 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
509 .help
= "invalidate l1 d-cache by virtual address offset and range size",
510 .usage
= "<virt_addr> [size]",
514 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
516 .help
= "clean l1 d-cache by virtual address address offset and range size",
517 .usage
= "<virt_addr> [size]",
519 COMMAND_REGISTRATION_DONE
522 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
525 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
527 .help
= "invalidate complete l1 i-cache",
532 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
534 .help
= "invalidate l1 i-cache by virtual address offset and range size",
535 .usage
= "<virt_addr> [size]",
537 COMMAND_REGISTRATION_DONE
540 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
543 .handler
= arm7a_l1_cache_info_cmd
,
545 .help
= "print cache realted information",
551 .help
= "l1 d-cache command group",
553 .chain
= arm7a_l1_d_cache_commands
,
558 .help
= "l1 i-cache command group",
560 .chain
= arm7a_l1_i_cache_commands
,
562 COMMAND_REGISTRATION_DONE
565 const struct command_registration arm7a_cache_group_handlers
[] = {
568 .handler
= arm7a_cache_disable_auto_cmd
,
570 .help
= "disable or enable automatic cache handling.",
576 .help
= "l1 cache command group",
578 .chain
= arm7a_l1_di_cache_group_handlers
,
581 .chain
= arm7a_l2x_cache_command_handler
,
583 COMMAND_REGISTRATION_DONE
586 const struct command_registration arm7a_cache_command_handlers
[] = {
590 .help
= "cache command group",
592 .chain
= arm7a_cache_group_handlers
,
594 COMMAND_REGISTRATION_DONE
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)