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. *
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 ***************************************************************************/
23 #include "jtag/interface.h"
26 #include "armv7a_cache.h"
27 #include <helper/time_support.h>
28 #include "arm_opcodes.h"
31 static int armv7a_l1_d_cache_sanity_check(struct target
*target
)
33 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
35 if (target
->state
!= TARGET_HALTED
) {
36 LOG_ERROR("%s: target not halted", __func__
);
37 return ERROR_TARGET_NOT_HALTED
;
40 /* check that cache data is on at target halt */
41 if (!armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
) {
42 LOG_DEBUG("data cache is not enabled");
43 return ERROR_TARGET_INVALID
;
49 static int armv7a_l1_i_cache_sanity_check(struct target
*target
)
51 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
53 if (target
->state
!= TARGET_HALTED
) {
54 LOG_ERROR("%s: target not halted", __func__
);
55 return ERROR_TARGET_NOT_HALTED
;
58 /* check that cache data is on at target halt */
59 if (!armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
) {
60 LOG_DEBUG("instruction cache is not enabled");
61 return ERROR_TARGET_INVALID
;
67 static int armv7a_l1_d_cache_flush_level(struct arm_dpm
*dpm
, struct armv7a_cachesize
*size
, int cl
)
69 int retval
= ERROR_OK
;
70 int32_t c_way
, c_index
= size
->index
;
72 LOG_DEBUG("cl %" PRId32
, cl
);
77 uint32_t value
= (c_index
<< size
->index_shift
)
78 | (c_way
<< size
->way_shift
) | (cl
<< 1);
80 * DCCISW - Clean and invalidate data cache
83 retval
= dpm
->instr_write_data_r0(dpm
,
84 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
86 if (retval
!= ERROR_OK
)
91 } while (c_index
>= 0);
98 static int armv7a_l1_d_cache_clean_inval_all(struct target
*target
)
100 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
101 struct armv7a_cache_common
*cache
= &(armv7a
->armv7a_mmu
.armv7a_cache
);
102 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
106 retval
= armv7a_l1_d_cache_sanity_check(target
);
107 if (retval
!= ERROR_OK
)
110 retval
= dpm
->prepare(dpm
);
111 if (retval
!= ERROR_OK
)
114 for (cl
= 0; cl
< cache
->loc
; cl
++) {
115 /* skip i-only caches */
116 if (cache
->arch
[cl
].ctype
< CACHE_LEVEL_HAS_D_CACHE
)
119 armv7a_l1_d_cache_flush_level(dpm
, &cache
->arch
[cl
].d_u_size
, cl
);
122 retval
= dpm
->finish(dpm
);
126 LOG_ERROR("clean invalidate failed");
132 int armv7a_cache_auto_flush_all_data(struct target
*target
)
134 int retval
= ERROR_FAIL
;
135 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
137 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
141 struct target_list
*head
;
142 foreach_smp_target(head
, target
->smp_targets
) {
143 struct target
*curr
= head
->target
;
144 if (curr
->state
== TARGET_HALTED
)
145 retval
= armv7a_l1_d_cache_clean_inval_all(curr
);
148 retval
= armv7a_l1_d_cache_clean_inval_all(target
);
150 if (retval
!= ERROR_OK
)
153 /* do outer cache flushing after inner caches have been flushed */
154 return arm7a_l2x_flush_all_data(target
);
158 int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
161 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
162 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
163 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
164 uint32_t linelen
= armv7a_cache
->dminline
;
165 uint32_t va_line
, va_end
;
168 retval
= armv7a_l1_d_cache_sanity_check(target
);
169 if (retval
!= ERROR_OK
)
172 retval
= dpm
->prepare(dpm
);
173 if (retval
!= ERROR_OK
)
176 va_line
= virt
& (-linelen
);
177 va_end
= virt
+ size
;
179 /* handle unaligned start */
180 if (virt
!= va_line
) {
182 retval
= dpm
->instr_write_data_r0(dpm
,
183 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
184 if (retval
!= ERROR_OK
)
189 /* handle unaligned end */
190 if ((va_end
& (linelen
-1)) != 0) {
191 va_end
&= (-linelen
);
193 retval
= dpm
->instr_write_data_r0(dpm
,
194 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end
);
195 if (retval
!= ERROR_OK
)
199 while (va_line
< va_end
) {
200 if ((i
++ & 0x3f) == 0)
202 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
203 retval
= dpm
->instr_write_data_r0(dpm
,
204 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line
);
205 if (retval
!= ERROR_OK
)
215 LOG_ERROR("d-cache invalidate failed");
222 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
225 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
226 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
227 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
228 uint32_t linelen
= armv7a_cache
->dminline
;
229 uint32_t va_line
, va_end
;
232 retval
= armv7a_l1_d_cache_sanity_check(target
);
233 if (retval
!= ERROR_OK
)
236 retval
= dpm
->prepare(dpm
);
237 if (retval
!= ERROR_OK
)
240 va_line
= virt
& (-linelen
);
241 va_end
= virt
+ size
;
243 while (va_line
< va_end
) {
244 if ((i
++ & 0x3f) == 0)
246 /* DCCMVAC - Data Cache Clean by MVA to PoC */
247 retval
= dpm
->instr_write_data_r0(dpm
,
248 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line
);
249 if (retval
!= ERROR_OK
)
259 LOG_ERROR("d-cache invalidate failed");
266 int armv7a_l1_d_cache_flush_virt(struct target
*target
, uint32_t virt
,
269 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
270 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
271 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
272 uint32_t linelen
= armv7a_cache
->dminline
;
273 uint32_t va_line
, va_end
;
276 retval
= armv7a_l1_d_cache_sanity_check(target
);
277 if (retval
!= ERROR_OK
)
280 retval
= dpm
->prepare(dpm
);
281 if (retval
!= ERROR_OK
)
284 va_line
= virt
& (-linelen
);
285 va_end
= virt
+ size
;
287 while (va_line
< va_end
) {
288 if ((i
++ & 0x3f) == 0)
291 retval
= dpm
->instr_write_data_r0(dpm
,
292 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
293 if (retval
!= ERROR_OK
)
303 LOG_ERROR("d-cache invalidate failed");
310 int armv7a_l1_i_cache_inval_all(struct target
*target
)
312 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
313 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
316 retval
= armv7a_l1_i_cache_sanity_check(target
);
317 if (retval
!= ERROR_OK
)
320 retval
= dpm
->prepare(dpm
);
321 if (retval
!= ERROR_OK
)
326 retval
= dpm
->instr_write_data_r0(dpm
,
327 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
330 retval
= dpm
->instr_write_data_r0(dpm
,
331 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
334 if (retval
!= ERROR_OK
)
341 LOG_ERROR("i-cache invalidate failed");
347 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
350 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
351 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
352 struct armv7a_cache_common
*armv7a_cache
=
353 &armv7a
->armv7a_mmu
.armv7a_cache
;
354 uint32_t linelen
= armv7a_cache
->iminline
;
355 uint32_t va_line
, va_end
;
358 retval
= armv7a_l1_i_cache_sanity_check(target
);
359 if (retval
!= ERROR_OK
)
362 retval
= dpm
->prepare(dpm
);
363 if (retval
!= ERROR_OK
)
366 va_line
= virt
& (-linelen
);
367 va_end
= virt
+ size
;
369 while (va_line
< va_end
) {
370 if ((i
++ & 0x3f) == 0)
372 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
373 retval
= dpm
->instr_write_data_r0(dpm
,
374 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
375 if (retval
!= ERROR_OK
)
378 retval
= dpm
->instr_write_data_r0(dpm
,
379 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
380 if (retval
!= ERROR_OK
)
389 LOG_ERROR("i-cache invalidate failed");
396 int armv7a_cache_flush_virt(struct target
*target
, uint32_t virt
,
399 armv7a_l1_d_cache_flush_virt(target
, virt
, size
);
400 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
406 * We assume that target core was chosen correctly. It means if same data
407 * was handled by two cores, other core will loose the changes. Since it
408 * is impossible to know (FIXME) which core has correct data, keep in mind
409 * that some kind of data lost or corruption is possible.
411 * - core1 loaded and changed data on 0x12345678
412 * - we halted target and modified same data on core0
413 * - data on core1 will be lost.
415 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
418 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
420 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
423 return armv7a_cache_flush_virt(target
, virt
, size
);
426 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
428 struct target
*target
= get_current_target(CMD_CTX
);
429 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
431 return armv7a_handle_cache_info_command(CMD
,
432 &armv7a
->armv7a_mmu
.armv7a_cache
);
435 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
437 struct target
*target
= get_current_target(CMD_CTX
);
439 armv7a_l1_d_cache_clean_inval_all(target
);
444 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
446 struct target
*target
= get_current_target(CMD_CTX
);
449 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
450 return ERROR_COMMAND_SYNTAX_ERROR
;
453 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
457 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
459 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
462 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
464 struct target
*target
= get_current_target(CMD_CTX
);
467 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
468 return ERROR_COMMAND_SYNTAX_ERROR
;
471 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
475 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
477 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
480 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
482 struct target
*target
= get_current_target(CMD_CTX
);
484 armv7a_l1_i_cache_inval_all(target
);
489 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
491 struct target
*target
= get_current_target(CMD_CTX
);
494 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
495 return ERROR_COMMAND_SYNTAX_ERROR
;
498 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
502 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
504 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
507 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
509 struct target
*target
= get_current_target(CMD_CTX
);
510 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
513 command_print(CMD
, "auto cache is %s",
514 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
521 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
522 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
526 return ERROR_COMMAND_SYNTAX_ERROR
;
529 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
532 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
534 .help
= "flush (clean and invalidate) complete l1 d-cache",
539 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
541 .help
= "invalidate l1 d-cache by virtual address offset and range size",
542 .usage
= "<virt_addr> [size]",
546 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
548 .help
= "clean l1 d-cache by virtual address address offset and range size",
549 .usage
= "<virt_addr> [size]",
551 COMMAND_REGISTRATION_DONE
554 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
557 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
559 .help
= "invalidate complete l1 i-cache",
564 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
566 .help
= "invalidate l1 i-cache by virtual address offset and range size",
567 .usage
= "<virt_addr> [size]",
569 COMMAND_REGISTRATION_DONE
572 static const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
575 .handler
= arm7a_l1_cache_info_cmd
,
577 .help
= "print cache related information",
583 .help
= "l1 d-cache command group",
585 .chain
= arm7a_l1_d_cache_commands
,
590 .help
= "l1 i-cache command group",
592 .chain
= arm7a_l1_i_cache_commands
,
594 COMMAND_REGISTRATION_DONE
597 static const struct command_registration arm7a_cache_group_handlers
[] = {
600 .handler
= arm7a_cache_disable_auto_cmd
,
602 .help
= "disable or enable automatic cache handling.",
608 .help
= "l1 cache command group",
610 .chain
= arm7a_l1_di_cache_group_handlers
,
613 .chain
= arm7a_l2x_cache_command_handler
,
615 COMMAND_REGISTRATION_DONE
618 const struct command_registration arm7a_cache_command_handlers
[] = {
622 .help
= "cache command group",
624 .chain
= arm7a_cache_group_handlers
,
626 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)