1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2015 by Oleksij Rempel *
5 * linux@rempel-privat.de *
6 ***************************************************************************/
12 #include "jtag/interface.h"
15 #include "armv7a_cache.h"
16 #include <helper/time_support.h>
17 #include "arm_opcodes.h"
20 static int armv7a_l1_d_cache_sanity_check(struct target
*target
)
22 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
24 if (target
->state
!= TARGET_HALTED
) {
25 LOG_ERROR("%s: target not halted", __func__
);
26 return ERROR_TARGET_NOT_HALTED
;
29 /* check that cache data is on at target halt */
30 if (!armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
) {
31 LOG_DEBUG("data cache is not enabled");
32 return ERROR_TARGET_INVALID
;
38 static int armv7a_l1_i_cache_sanity_check(struct target
*target
)
40 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
42 if (target
->state
!= TARGET_HALTED
) {
43 LOG_ERROR("%s: target not halted", __func__
);
44 return ERROR_TARGET_NOT_HALTED
;
47 /* check that cache data is on at target halt */
48 if (!armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
) {
49 LOG_DEBUG("instruction cache is not enabled");
50 return ERROR_TARGET_INVALID
;
56 static int armv7a_l1_d_cache_flush_level(struct arm_dpm
*dpm
, struct armv7a_cachesize
*size
, int cl
)
58 int retval
= ERROR_OK
;
59 int32_t c_way
, c_index
= size
->index
;
61 LOG_DEBUG("cl %" PRId32
, cl
);
66 uint32_t value
= (c_index
<< size
->index_shift
)
67 | (c_way
<< size
->way_shift
) | (cl
<< 1);
69 * DCCISW - Clean and invalidate data cache
72 retval
= dpm
->instr_write_data_r0(dpm
,
73 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
75 if (retval
!= ERROR_OK
)
80 } while (c_index
>= 0);
87 static int armv7a_l1_d_cache_clean_inval_all(struct target
*target
)
89 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
90 struct armv7a_cache_common
*cache
= &(armv7a
->armv7a_mmu
.armv7a_cache
);
91 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
95 retval
= armv7a_l1_d_cache_sanity_check(target
);
96 if (retval
!= ERROR_OK
)
99 retval
= dpm
->prepare(dpm
);
100 if (retval
!= ERROR_OK
)
103 for (cl
= 0; cl
< cache
->loc
; cl
++) {
104 /* skip i-only caches */
105 if (cache
->arch
[cl
].ctype
< CACHE_LEVEL_HAS_D_CACHE
)
108 armv7a_l1_d_cache_flush_level(dpm
, &cache
->arch
[cl
].d_u_size
, cl
);
111 retval
= dpm
->finish(dpm
);
115 LOG_ERROR("clean invalidate failed");
121 int armv7a_cache_auto_flush_all_data(struct target
*target
)
123 int retval
= ERROR_FAIL
;
124 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
126 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
130 struct target_list
*head
;
131 foreach_smp_target(head
, target
->smp_targets
) {
132 struct target
*curr
= head
->target
;
133 if (curr
->state
== TARGET_HALTED
)
134 retval
= armv7a_l1_d_cache_clean_inval_all(curr
);
137 retval
= armv7a_l1_d_cache_clean_inval_all(target
);
139 if (retval
!= ERROR_OK
)
142 /* do outer cache flushing after inner caches have been flushed */
143 return arm7a_l2x_flush_all_data(target
);
147 int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
150 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
151 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
152 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
153 uint32_t linelen
= armv7a_cache
->dminline
;
154 uint32_t va_line
, va_end
;
157 retval
= armv7a_l1_d_cache_sanity_check(target
);
158 if (retval
!= ERROR_OK
)
161 retval
= dpm
->prepare(dpm
);
162 if (retval
!= ERROR_OK
)
165 va_line
= virt
& (-linelen
);
166 va_end
= virt
+ size
;
168 /* handle unaligned start */
169 if (virt
!= va_line
) {
171 retval
= dpm
->instr_write_data_r0(dpm
,
172 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
173 if (retval
!= ERROR_OK
)
178 /* handle unaligned end */
179 if ((va_end
& (linelen
-1)) != 0) {
180 va_end
&= (-linelen
);
182 retval
= dpm
->instr_write_data_r0(dpm
,
183 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end
);
184 if (retval
!= ERROR_OK
)
188 while (va_line
< va_end
) {
189 if ((i
++ & 0x3f) == 0)
191 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
192 retval
= dpm
->instr_write_data_r0(dpm
,
193 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line
);
194 if (retval
!= ERROR_OK
)
204 LOG_ERROR("d-cache invalidate failed");
211 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
214 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
215 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
216 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
217 uint32_t linelen
= armv7a_cache
->dminline
;
218 uint32_t va_line
, va_end
;
221 retval
= armv7a_l1_d_cache_sanity_check(target
);
222 if (retval
!= ERROR_OK
)
225 retval
= dpm
->prepare(dpm
);
226 if (retval
!= ERROR_OK
)
229 va_line
= virt
& (-linelen
);
230 va_end
= virt
+ size
;
232 while (va_line
< va_end
) {
233 if ((i
++ & 0x3f) == 0)
235 /* DCCMVAC - Data Cache Clean by MVA to PoC */
236 retval
= dpm
->instr_write_data_r0(dpm
,
237 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line
);
238 if (retval
!= ERROR_OK
)
248 LOG_ERROR("d-cache invalidate failed");
255 int armv7a_l1_d_cache_flush_virt(struct target
*target
, uint32_t virt
,
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
;
265 retval
= armv7a_l1_d_cache_sanity_check(target
);
266 if (retval
!= ERROR_OK
)
269 retval
= dpm
->prepare(dpm
);
270 if (retval
!= ERROR_OK
)
273 va_line
= virt
& (-linelen
);
274 va_end
= virt
+ size
;
276 while (va_line
< va_end
) {
277 if ((i
++ & 0x3f) == 0)
280 retval
= dpm
->instr_write_data_r0(dpm
,
281 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
282 if (retval
!= ERROR_OK
)
292 LOG_ERROR("d-cache invalidate failed");
299 int armv7a_l1_i_cache_inval_all(struct target
*target
)
301 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
302 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
305 retval
= armv7a_l1_i_cache_sanity_check(target
);
306 if (retval
!= ERROR_OK
)
309 retval
= dpm
->prepare(dpm
);
310 if (retval
!= ERROR_OK
)
315 retval
= dpm
->instr_write_data_r0(dpm
,
316 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
319 retval
= dpm
->instr_write_data_r0(dpm
,
320 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
323 if (retval
!= ERROR_OK
)
330 LOG_ERROR("i-cache invalidate failed");
336 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
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
;
347 retval
= armv7a_l1_i_cache_sanity_check(target
);
348 if (retval
!= ERROR_OK
)
351 retval
= dpm
->prepare(dpm
);
352 if (retval
!= ERROR_OK
)
355 va_line
= virt
& (-linelen
);
356 va_end
= virt
+ size
;
358 while (va_line
< va_end
) {
359 if ((i
++ & 0x3f) == 0)
361 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
362 retval
= dpm
->instr_write_data_r0(dpm
,
363 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
364 if (retval
!= ERROR_OK
)
367 retval
= dpm
->instr_write_data_r0(dpm
,
368 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
369 if (retval
!= ERROR_OK
)
378 LOG_ERROR("i-cache invalidate failed");
385 int armv7a_cache_flush_virt(struct target
*target
, uint32_t virt
,
388 armv7a_l1_d_cache_flush_virt(target
, virt
, size
);
389 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
395 * We assume that target core was chosen correctly. It means if same data
396 * was handled by two cores, other core will loose the changes. Since it
397 * is impossible to know (FIXME) which core has correct data, keep in mind
398 * that some kind of data lost or corruption is possible.
400 * - core1 loaded and changed data on 0x12345678
401 * - we halted target and modified same data on core0
402 * - data on core1 will be lost.
404 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
407 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
409 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
412 return armv7a_cache_flush_virt(target
, virt
, size
);
415 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
417 struct target
*target
= get_current_target(CMD_CTX
);
418 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
420 return armv7a_handle_cache_info_command(CMD
,
421 &armv7a
->armv7a_mmu
.armv7a_cache
);
424 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
426 struct target
*target
= get_current_target(CMD_CTX
);
428 armv7a_l1_d_cache_clean_inval_all(target
);
433 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
435 struct target
*target
= get_current_target(CMD_CTX
);
438 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
439 return ERROR_COMMAND_SYNTAX_ERROR
;
442 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
446 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
448 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
451 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
453 struct target
*target
= get_current_target(CMD_CTX
);
456 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
457 return ERROR_COMMAND_SYNTAX_ERROR
;
460 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
464 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
466 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
469 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
471 struct target
*target
= get_current_target(CMD_CTX
);
473 armv7a_l1_i_cache_inval_all(target
);
478 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
480 struct target
*target
= get_current_target(CMD_CTX
);
483 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
484 return ERROR_COMMAND_SYNTAX_ERROR
;
487 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
491 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
493 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
496 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
498 struct target
*target
= get_current_target(CMD_CTX
);
499 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
502 command_print(CMD
, "auto cache is %s",
503 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
510 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
511 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
515 return ERROR_COMMAND_SYNTAX_ERROR
;
518 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
521 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
523 .help
= "flush (clean and invalidate) complete l1 d-cache",
528 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
530 .help
= "invalidate l1 d-cache by virtual address offset and range size",
531 .usage
= "<virt_addr> [size]",
535 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
537 .help
= "clean l1 d-cache by virtual address address offset and range size",
538 .usage
= "<virt_addr> [size]",
540 COMMAND_REGISTRATION_DONE
543 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
546 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
548 .help
= "invalidate complete l1 i-cache",
553 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
555 .help
= "invalidate l1 i-cache by virtual address offset and range size",
556 .usage
= "<virt_addr> [size]",
558 COMMAND_REGISTRATION_DONE
561 static const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
564 .handler
= arm7a_l1_cache_info_cmd
,
566 .help
= "print cache related information",
572 .help
= "l1 d-cache command group",
574 .chain
= arm7a_l1_d_cache_commands
,
579 .help
= "l1 i-cache command group",
581 .chain
= arm7a_l1_i_cache_commands
,
583 COMMAND_REGISTRATION_DONE
586 static const struct command_registration arm7a_cache_group_handlers
[] = {
589 .handler
= arm7a_cache_disable_auto_cmd
,
591 .help
= "disable or enable automatic cache handling.",
597 .help
= "l1 cache command group",
599 .chain
= arm7a_l1_di_cache_group_handlers
,
602 .chain
= arm7a_l2x_cache_command_handler
,
604 COMMAND_REGISTRATION_DONE
607 const struct command_registration arm7a_cache_command_handlers
[] = {
611 .help
= "cache command group",
613 .chain
= arm7a_cache_group_handlers
,
615 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)