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 /* DCCMVAC - Data Cache Clean by MVA to PoC */
211 retval
= dpm
->instr_write_data_r0(dpm
,
212 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), offs
);
213 if (retval
!= ERROR_OK
)
219 LOG_ERROR("d-cache invalidate failed");
225 int armv7a_l1_d_cache_flush_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 i
, linelen
= armv7a_cache
->dminline
;
234 retval
= armv7a_l1_d_cache_sanity_check(target
);
235 if (retval
!= ERROR_OK
)
238 retval
= dpm
->prepare(dpm
);
239 if (retval
!= ERROR_OK
)
242 for (i
= 0; i
< size
; i
+= linelen
) {
243 uint32_t offs
= virt
+ i
;
246 retval
= dpm
->instr_write_data_r0(dpm
,
247 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), offs
);
248 if (retval
!= ERROR_OK
)
254 LOG_ERROR("d-cache invalidate failed");
260 int armv7a_l1_i_cache_inval_all(struct target
*target
)
262 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
263 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
266 retval
= armv7a_l1_i_cache_sanity_check(target
);
267 if (retval
!= ERROR_OK
)
270 retval
= dpm
->prepare(dpm
);
271 if (retval
!= ERROR_OK
)
276 retval
= dpm
->instr_write_data_r0(dpm
,
277 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
280 retval
= dpm
->instr_write_data_r0(dpm
,
281 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
284 if (retval
!= ERROR_OK
)
291 LOG_ERROR("i-cache invalidate failed");
297 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
300 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
301 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
302 struct armv7a_cache_common
*armv7a_cache
=
303 &armv7a
->armv7a_mmu
.armv7a_cache
;
304 uint32_t linelen
= armv7a_cache
->iminline
;
305 uint32_t va_line
, va_end
;
308 retval
= armv7a_l1_i_cache_sanity_check(target
);
309 if (retval
!= ERROR_OK
)
312 retval
= dpm
->prepare(dpm
);
313 if (retval
!= ERROR_OK
)
316 va_line
= virt
& (-linelen
);
317 va_end
= virt
+ size
;
319 while (va_line
< va_end
) {
320 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
321 retval
= dpm
->instr_write_data_r0(dpm
,
322 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
323 if (retval
!= ERROR_OK
)
326 retval
= dpm
->instr_write_data_r0(dpm
,
327 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
328 if (retval
!= ERROR_OK
)
335 LOG_ERROR("i-cache invalidate failed");
341 int armv7a_cache_flush_virt(struct target
*target
, uint32_t virt
,
344 armv7a_l1_d_cache_flush_virt(target
, virt
, size
);
345 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
351 * We assume that target core was chosen correctly. It means if same data
352 * was handled by two cores, other core will loose the changes. Since it
353 * is impossible to know (FIXME) which core has correct data, keep in mind
354 * that some kind of data lost or korruption is possible.
356 * - core1 loaded and changed data on 0x12345678
357 * - we halted target and modified same data on core0
358 * - data on core1 will be lost.
360 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
363 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
365 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
368 return armv7a_cache_flush_virt(target
, virt
, size
);
371 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
373 struct target
*target
= get_current_target(CMD_CTX
);
374 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
376 return armv7a_handle_cache_info_command(CMD_CTX
,
377 &armv7a
->armv7a_mmu
.armv7a_cache
);
380 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
382 struct target
*target
= get_current_target(CMD_CTX
);
384 armv7a_l1_d_cache_clean_inval_all(target
);
389 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
391 struct target
*target
= get_current_target(CMD_CTX
);
394 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
395 return ERROR_COMMAND_SYNTAX_ERROR
;
398 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
402 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
404 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
407 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
409 struct target
*target
= get_current_target(CMD_CTX
);
412 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
413 return ERROR_COMMAND_SYNTAX_ERROR
;
416 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
420 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
422 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
425 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
427 struct target
*target
= get_current_target(CMD_CTX
);
429 armv7a_l1_i_cache_inval_all(target
);
434 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
436 struct target
*target
= get_current_target(CMD_CTX
);
439 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
440 return ERROR_COMMAND_SYNTAX_ERROR
;
443 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
447 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
449 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
452 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
454 struct target
*target
= get_current_target(CMD_CTX
);
455 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
458 command_print(CMD_CTX
, "auto cache is %s",
459 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
466 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
467 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
471 return ERROR_COMMAND_SYNTAX_ERROR
;
474 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
477 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
479 .help
= "flush (clean and invalidate) complete l1 d-cache",
484 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
486 .help
= "invalidate l1 d-cache by virtual address offset and range size",
487 .usage
= "<virt_addr> [size]",
491 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
493 .help
= "clean l1 d-cache by virtual address address offset and range size",
494 .usage
= "<virt_addr> [size]",
496 COMMAND_REGISTRATION_DONE
499 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
502 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
504 .help
= "invalidate complete l1 i-cache",
509 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
511 .help
= "invalidate l1 i-cache by virtual address offset and range size",
512 .usage
= "<virt_addr> [size]",
514 COMMAND_REGISTRATION_DONE
517 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
520 .handler
= arm7a_l1_cache_info_cmd
,
522 .help
= "print cache realted information",
528 .help
= "l1 d-cache command group",
530 .chain
= arm7a_l1_d_cache_commands
,
535 .help
= "l1 i-cache command group",
537 .chain
= arm7a_l1_i_cache_commands
,
539 COMMAND_REGISTRATION_DONE
542 const struct command_registration arm7a_cache_group_handlers
[] = {
545 .handler
= arm7a_cache_disable_auto_cmd
,
547 .help
= "disable or enable automatic cache handling.",
553 .help
= "l1 cache command group",
555 .chain
= arm7a_l1_di_cache_group_handlers
,
558 .chain
= arm7a_l2x_cache_command_handler
,
560 COMMAND_REGISTRATION_DONE
563 const struct command_registration arm7a_cache_command_handlers
[] = {
567 .help
= "cache command group",
569 .chain
= arm7a_cache_group_handlers
,
571 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)