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_i_cache_inval_all(struct target
*target
)
228 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
229 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
232 retval
= armv7a_l1_i_cache_sanity_check(target
);
233 if (retval
!= ERROR_OK
)
236 retval
= dpm
->prepare(dpm
);
237 if (retval
!= ERROR_OK
)
242 retval
= dpm
->instr_write_data_r0(dpm
,
243 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
246 retval
= dpm
->instr_write_data_r0(dpm
,
247 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
250 if (retval
!= ERROR_OK
)
257 LOG_ERROR("i-cache invalidate failed");
263 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
266 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
267 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
268 struct armv7a_cache_common
*armv7a_cache
=
269 &armv7a
->armv7a_mmu
.armv7a_cache
;
270 uint32_t linelen
= armv7a_cache
->iminline
;
271 uint32_t va_line
, va_end
;
274 retval
= armv7a_l1_i_cache_sanity_check(target
);
275 if (retval
!= ERROR_OK
)
278 retval
= dpm
->prepare(dpm
);
279 if (retval
!= ERROR_OK
)
282 va_line
= virt
& (-linelen
);
283 va_end
= virt
+ size
;
285 while (va_line
< va_end
) {
286 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
287 retval
= dpm
->instr_write_data_r0(dpm
,
288 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
289 if (retval
!= ERROR_OK
)
292 retval
= dpm
->instr_write_data_r0(dpm
,
293 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
294 if (retval
!= ERROR_OK
)
301 LOG_ERROR("i-cache invalidate failed");
309 * We assume that target core was chosen correctly. It means if same data
310 * was handled by two cores, other core will loose the changes. Since it
311 * is impossible to know (FIXME) which core has correct data, keep in mind
312 * that some kind of data lost or korruption is possible.
314 * - core1 loaded and changed data on 0x12345678
315 * - we halted target and modified same data on core0
316 * - data on core1 will be lost.
318 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
321 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
322 int retval
= ERROR_OK
;
324 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
327 armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
328 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
331 struct target_list
*head
;
334 while (head
!= (struct target_list
*)NULL
) {
336 if (curr
->state
== TARGET_HALTED
) {
337 retval
= armv7a_l1_i_cache_inval_all(curr
);
338 if (retval
!= ERROR_OK
)
340 retval
= armv7a_l1_d_cache_inval_virt(target
,
342 if (retval
!= ERROR_OK
)
348 retval
= armv7a_l1_i_cache_inval_all(target
);
349 if (retval
!= ERROR_OK
)
351 retval
= armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
352 if (retval
!= ERROR_OK
)
359 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
361 struct target
*target
= get_current_target(CMD_CTX
);
362 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
364 return armv7a_handle_cache_info_command(CMD_CTX
,
365 &armv7a
->armv7a_mmu
.armv7a_cache
);
368 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
370 struct target
*target
= get_current_target(CMD_CTX
);
372 armv7a_l1_d_cache_clean_inval_all(target
);
377 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
379 struct target
*target
= get_current_target(CMD_CTX
);
382 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
383 return ERROR_COMMAND_SYNTAX_ERROR
;
386 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
390 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
392 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
395 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
397 struct target
*target
= get_current_target(CMD_CTX
);
400 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
401 return ERROR_COMMAND_SYNTAX_ERROR
;
404 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
408 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
410 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
413 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
415 struct target
*target
= get_current_target(CMD_CTX
);
417 armv7a_l1_i_cache_inval_all(target
);
422 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
424 struct target
*target
= get_current_target(CMD_CTX
);
427 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
428 return ERROR_COMMAND_SYNTAX_ERROR
;
431 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
435 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
437 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
440 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
442 struct target
*target
= get_current_target(CMD_CTX
);
443 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
446 command_print(CMD_CTX
, "auto cache is %s",
447 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
454 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
455 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
459 return ERROR_COMMAND_SYNTAX_ERROR
;
462 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
465 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
467 .help
= "flush (clean and invalidate) complete l1 d-cache",
472 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
474 .help
= "invalidate l1 d-cache by virtual address offset and range size",
475 .usage
= "<virt_addr> [size]",
479 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
481 .help
= "clean l1 d-cache by virtual address address offset and range size",
482 .usage
= "<virt_addr> [size]",
484 COMMAND_REGISTRATION_DONE
487 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
490 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
492 .help
= "invalidate complete l1 i-cache",
497 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
499 .help
= "invalidate l1 i-cache by virtual address offset and range size",
500 .usage
= "<virt_addr> [size]",
502 COMMAND_REGISTRATION_DONE
505 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
508 .handler
= arm7a_l1_cache_info_cmd
,
510 .help
= "print cache realted information",
516 .help
= "l1 d-cache command group",
518 .chain
= arm7a_l1_d_cache_commands
,
523 .help
= "l1 i-cache command group",
525 .chain
= arm7a_l1_i_cache_commands
,
527 COMMAND_REGISTRATION_DONE
530 const struct command_registration arm7a_cache_group_handlers
[] = {
533 .handler
= arm7a_cache_disable_auto_cmd
,
535 .help
= "disable or enable automatic cache handling.",
541 .help
= "l1 cache command group",
543 .chain
= arm7a_l1_di_cache_group_handlers
,
546 .chain
= arm7a_l2x_cache_command_handler
,
548 COMMAND_REGISTRATION_DONE
551 const struct command_registration arm7a_cache_command_handlers
[] = {
555 .help
= "cache command group",
557 .chain
= arm7a_cache_group_handlers
,
559 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)