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"
30 static int armv7a_l1_d_cache_sanity_check(struct target
*target
)
32 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
34 if (target
->state
!= TARGET_HALTED
) {
35 LOG_ERROR("%s: target not halted", __func__
);
36 return ERROR_TARGET_NOT_HALTED
;
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
;
48 static int armv7a_l1_i_cache_sanity_check(struct target
*target
)
50 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
52 if (target
->state
!= TARGET_HALTED
) {
53 LOG_ERROR("%s: target not halted", __func__
);
54 return ERROR_TARGET_NOT_HALTED
;
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
;
66 static int armv7a_l1_d_cache_flush_level(struct arm_dpm
*dpm
, struct armv7a_cachesize
*size
, int cl
)
68 int retval
= ERROR_OK
;
69 int32_t c_way
, c_index
= size
->index
;
71 LOG_DEBUG("cl %" PRId32
, cl
);
76 uint32_t value
= (c_index
<< size
->index_shift
)
77 | (c_way
<< size
->way_shift
) | (cl
<< 1);
79 * DCCISW - Clean and invalidate data cache
82 retval
= dpm
->instr_write_data_r0(dpm
,
83 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
85 if (retval
!= ERROR_OK
)
90 } while (c_index
>= 0);
97 static int armv7a_l1_d_cache_clean_inval_all(struct target
*target
)
99 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
100 struct armv7a_cache_common
*cache
= &(armv7a
->armv7a_mmu
.armv7a_cache
);
101 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
105 retval
= armv7a_l1_d_cache_sanity_check(target
);
106 if (retval
!= ERROR_OK
)
109 retval
= dpm
->prepare(dpm
);
110 if (retval
!= ERROR_OK
)
113 for (cl
= 0; cl
< cache
->loc
; cl
++) {
114 /* skip i-only caches */
115 if (cache
->arch
[cl
].ctype
< CACHE_LEVEL_HAS_D_CACHE
)
118 armv7a_l1_d_cache_flush_level(dpm
, &cache
->arch
[cl
].d_u_size
, cl
);
121 retval
= dpm
->finish(dpm
);
125 LOG_ERROR("clean invalidate failed");
131 int armv7a_cache_auto_flush_all_data(struct target
*target
)
133 int retval
= ERROR_FAIL
;
134 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
136 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
140 struct target_list
*head
;
143 while (head
!= (struct target_list
*)NULL
) {
145 if (curr
->state
== TARGET_HALTED
)
146 retval
= armv7a_l1_d_cache_clean_inval_all(curr
);
151 retval
= armv7a_l1_d_cache_clean_inval_all(target
);
153 if (retval
!= ERROR_OK
)
156 /* do outer cache flushing after inner caches have been flushed */
157 return arm7a_l2x_flush_all_data(target
);
161 int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
164 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
165 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
166 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
167 uint32_t linelen
= armv7a_cache
->dminline
;
168 uint32_t va_line
, va_end
;
171 retval
= armv7a_l1_d_cache_sanity_check(target
);
172 if (retval
!= ERROR_OK
)
175 retval
= dpm
->prepare(dpm
);
176 if (retval
!= ERROR_OK
)
179 va_line
= virt
& (-linelen
);
180 va_end
= virt
+ size
;
182 /* handle unaligned start */
183 if (virt
!= va_line
) {
185 retval
= dpm
->instr_write_data_r0(dpm
,
186 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
187 if (retval
!= ERROR_OK
)
192 /* handle unaligned end */
193 if ((va_end
& (linelen
-1)) != 0) {
194 va_end
&= (-linelen
);
196 retval
= dpm
->instr_write_data_r0(dpm
,
197 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end
);
198 if (retval
!= ERROR_OK
)
202 while (va_line
< va_end
) {
203 if ((i
++ & 0x3f) == 0)
205 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
206 retval
= dpm
->instr_write_data_r0(dpm
,
207 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line
);
208 if (retval
!= ERROR_OK
)
218 LOG_ERROR("d-cache invalidate failed");
225 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
228 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
229 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
230 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
231 uint32_t linelen
= armv7a_cache
->dminline
;
232 uint32_t va_line
, va_end
;
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 va_line
= virt
& (-linelen
);
244 va_end
= virt
+ size
;
246 while (va_line
< va_end
) {
247 if ((i
++ & 0x3f) == 0)
249 /* DCCMVAC - Data Cache Clean by MVA to PoC */
250 retval
= dpm
->instr_write_data_r0(dpm
,
251 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line
);
252 if (retval
!= ERROR_OK
)
262 LOG_ERROR("d-cache invalidate failed");
269 int armv7a_l1_d_cache_flush_virt(struct target
*target
, uint32_t virt
,
272 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
273 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
274 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
275 uint32_t linelen
= armv7a_cache
->dminline
;
276 uint32_t va_line
, va_end
;
279 retval
= armv7a_l1_d_cache_sanity_check(target
);
280 if (retval
!= ERROR_OK
)
283 retval
= dpm
->prepare(dpm
);
284 if (retval
!= ERROR_OK
)
287 va_line
= virt
& (-linelen
);
288 va_end
= virt
+ size
;
290 while (va_line
< va_end
) {
291 if ((i
++ & 0x3f) == 0)
294 retval
= dpm
->instr_write_data_r0(dpm
,
295 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
296 if (retval
!= ERROR_OK
)
306 LOG_ERROR("d-cache invalidate failed");
313 int armv7a_l1_i_cache_inval_all(struct target
*target
)
315 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
316 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
319 retval
= armv7a_l1_i_cache_sanity_check(target
);
320 if (retval
!= ERROR_OK
)
323 retval
= dpm
->prepare(dpm
);
324 if (retval
!= ERROR_OK
)
329 retval
= dpm
->instr_write_data_r0(dpm
,
330 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
333 retval
= dpm
->instr_write_data_r0(dpm
,
334 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
337 if (retval
!= ERROR_OK
)
344 LOG_ERROR("i-cache invalidate failed");
350 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
353 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
354 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
355 struct armv7a_cache_common
*armv7a_cache
=
356 &armv7a
->armv7a_mmu
.armv7a_cache
;
357 uint32_t linelen
= armv7a_cache
->iminline
;
358 uint32_t va_line
, va_end
;
361 retval
= armv7a_l1_i_cache_sanity_check(target
);
362 if (retval
!= ERROR_OK
)
365 retval
= dpm
->prepare(dpm
);
366 if (retval
!= ERROR_OK
)
369 va_line
= virt
& (-linelen
);
370 va_end
= virt
+ size
;
372 while (va_line
< va_end
) {
373 if ((i
++ & 0x3f) == 0)
375 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
376 retval
= dpm
->instr_write_data_r0(dpm
,
377 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
378 if (retval
!= ERROR_OK
)
381 retval
= dpm
->instr_write_data_r0(dpm
,
382 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
383 if (retval
!= ERROR_OK
)
392 LOG_ERROR("i-cache invalidate failed");
399 int armv7a_cache_flush_virt(struct target
*target
, uint32_t virt
,
402 armv7a_l1_d_cache_flush_virt(target
, virt
, size
);
403 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
409 * We assume that target core was chosen correctly. It means if same data
410 * was handled by two cores, other core will loose the changes. Since it
411 * is impossible to know (FIXME) which core has correct data, keep in mind
412 * that some kind of data lost or korruption is possible.
414 * - core1 loaded and changed data on 0x12345678
415 * - we halted target and modified same data on core0
416 * - data on core1 will be lost.
418 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
421 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
423 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
426 return armv7a_cache_flush_virt(target
, virt
, size
);
429 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
431 struct target
*target
= get_current_target(CMD_CTX
);
432 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
434 return armv7a_handle_cache_info_command(CMD_CTX
,
435 &armv7a
->armv7a_mmu
.armv7a_cache
);
438 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
440 struct target
*target
= get_current_target(CMD_CTX
);
442 armv7a_l1_d_cache_clean_inval_all(target
);
447 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
449 struct target
*target
= get_current_target(CMD_CTX
);
452 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
453 return ERROR_COMMAND_SYNTAX_ERROR
;
456 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
460 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
462 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
465 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
467 struct target
*target
= get_current_target(CMD_CTX
);
470 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
471 return ERROR_COMMAND_SYNTAX_ERROR
;
474 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
478 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
480 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
483 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
485 struct target
*target
= get_current_target(CMD_CTX
);
487 armv7a_l1_i_cache_inval_all(target
);
492 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
494 struct target
*target
= get_current_target(CMD_CTX
);
497 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
498 return ERROR_COMMAND_SYNTAX_ERROR
;
501 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
505 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
507 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
510 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
512 struct target
*target
= get_current_target(CMD_CTX
);
513 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
516 command_print(CMD_CTX
, "auto cache is %s",
517 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
524 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
525 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
529 return ERROR_COMMAND_SYNTAX_ERROR
;
532 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
535 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
537 .help
= "flush (clean and invalidate) complete l1 d-cache",
542 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
544 .help
= "invalidate l1 d-cache by virtual address offset and range size",
545 .usage
= "<virt_addr> [size]",
549 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
551 .help
= "clean l1 d-cache by virtual address address offset and range size",
552 .usage
= "<virt_addr> [size]",
554 COMMAND_REGISTRATION_DONE
557 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
560 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
562 .help
= "invalidate complete l1 i-cache",
567 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
569 .help
= "invalidate l1 i-cache by virtual address offset and range size",
570 .usage
= "<virt_addr> [size]",
572 COMMAND_REGISTRATION_DONE
575 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
578 .handler
= arm7a_l1_cache_info_cmd
,
580 .help
= "print cache realted information",
586 .help
= "l1 d-cache command group",
588 .chain
= arm7a_l1_d_cache_commands
,
593 .help
= "l1 i-cache command group",
595 .chain
= arm7a_l1_i_cache_commands
,
597 COMMAND_REGISTRATION_DONE
600 const struct command_registration arm7a_cache_group_handlers
[] = {
603 .handler
= arm7a_cache_disable_auto_cmd
,
605 .help
= "disable or enable automatic cache handling.",
611 .help
= "l1 cache command group",
613 .chain
= arm7a_l1_di_cache_group_handlers
,
616 .chain
= arm7a_l2x_cache_command_handler
,
618 COMMAND_REGISTRATION_DONE
621 const struct command_registration arm7a_cache_command_handlers
[] = {
625 .help
= "cache command group",
627 .chain
= arm7a_cache_group_handlers
,
629 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)