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
);
75 uint32_t value
= (c_index
<< size
->index_shift
)
76 | (c_way
<< size
->way_shift
) | (cl
<< 1);
78 * DCCISW - Clean and invalidate data cache
81 retval
= dpm
->instr_write_data_r0(dpm
,
82 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
84 if (retval
!= ERROR_OK
)
89 } while (c_index
>= 0);
95 static int armv7a_l1_d_cache_clean_inval_all(struct target
*target
)
97 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
98 struct armv7a_cache_common
*cache
= &(armv7a
->armv7a_mmu
.armv7a_cache
);
99 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
103 retval
= armv7a_l1_d_cache_sanity_check(target
);
104 if (retval
!= ERROR_OK
)
107 retval
= dpm
->prepare(dpm
);
108 if (retval
!= ERROR_OK
)
111 for (cl
= 0; cl
< cache
->loc
; cl
++) {
112 /* skip i-only caches */
113 if (cache
->arch
[cl
].ctype
< CACHE_LEVEL_HAS_D_CACHE
)
116 armv7a_l1_d_cache_flush_level(dpm
, &cache
->arch
[cl
].d_u_size
, cl
);
119 retval
= dpm
->finish(dpm
);
123 LOG_ERROR("clean invalidate failed");
129 int armv7a_cache_auto_flush_all_data(struct target
*target
)
131 int retval
= ERROR_FAIL
;
132 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
134 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
138 struct target_list
*head
;
141 while (head
!= (struct target_list
*)NULL
) {
143 if (curr
->state
== TARGET_HALTED
)
144 retval
= armv7a_l1_d_cache_clean_inval_all(curr
);
149 retval
= armv7a_l1_d_cache_clean_inval_all(target
);
151 /* do outer cache flushing after inner caches have been flushed */
152 retval
= 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 /* DCIMVAC - Invalidate data cache line by VA to PoC. */
201 retval
= dpm
->instr_write_data_r0(dpm
,
202 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line
);
203 if (retval
!= ERROR_OK
)
212 LOG_ERROR("d-cache invalidate failed");
218 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
221 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
222 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
223 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
224 uint32_t linelen
= armv7a_cache
->dminline
;
225 uint32_t va_line
, va_end
;
228 retval
= armv7a_l1_d_cache_sanity_check(target
);
229 if (retval
!= ERROR_OK
)
232 retval
= dpm
->prepare(dpm
);
233 if (retval
!= ERROR_OK
)
236 va_line
= virt
& (-linelen
);
237 va_end
= virt
+ size
;
239 while (va_line
< va_end
) {
240 /* DCCMVAC - Data Cache Clean by MVA to PoC */
241 retval
= dpm
->instr_write_data_r0(dpm
,
242 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line
);
243 if (retval
!= ERROR_OK
)
252 LOG_ERROR("d-cache invalidate failed");
258 int armv7a_l1_d_cache_flush_virt(struct target
*target
, uint32_t virt
,
261 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
262 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
263 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
264 uint32_t linelen
= armv7a_cache
->dminline
;
265 uint32_t va_line
, va_end
;
268 retval
= armv7a_l1_d_cache_sanity_check(target
);
269 if (retval
!= ERROR_OK
)
272 retval
= dpm
->prepare(dpm
);
273 if (retval
!= ERROR_OK
)
276 va_line
= virt
& (-linelen
);
277 va_end
= virt
+ size
;
279 while (va_line
< va_end
) {
281 retval
= dpm
->instr_write_data_r0(dpm
,
282 ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line
);
283 if (retval
!= ERROR_OK
)
292 LOG_ERROR("d-cache invalidate failed");
298 int armv7a_l1_i_cache_inval_all(struct target
*target
)
300 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
301 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
304 retval
= armv7a_l1_i_cache_sanity_check(target
);
305 if (retval
!= ERROR_OK
)
308 retval
= dpm
->prepare(dpm
);
309 if (retval
!= ERROR_OK
)
314 retval
= dpm
->instr_write_data_r0(dpm
,
315 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
318 retval
= dpm
->instr_write_data_r0(dpm
,
319 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
322 if (retval
!= ERROR_OK
)
329 LOG_ERROR("i-cache invalidate failed");
335 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
338 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
339 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
340 struct armv7a_cache_common
*armv7a_cache
=
341 &armv7a
->armv7a_mmu
.armv7a_cache
;
342 uint32_t linelen
= armv7a_cache
->iminline
;
343 uint32_t va_line
, va_end
;
346 retval
= armv7a_l1_i_cache_sanity_check(target
);
347 if (retval
!= ERROR_OK
)
350 retval
= dpm
->prepare(dpm
);
351 if (retval
!= ERROR_OK
)
354 va_line
= virt
& (-linelen
);
355 va_end
= virt
+ size
;
357 while (va_line
< va_end
) {
358 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
359 retval
= dpm
->instr_write_data_r0(dpm
,
360 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
361 if (retval
!= ERROR_OK
)
364 retval
= dpm
->instr_write_data_r0(dpm
,
365 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
366 if (retval
!= ERROR_OK
)
373 LOG_ERROR("i-cache invalidate failed");
379 int armv7a_cache_flush_virt(struct target
*target
, uint32_t virt
,
382 armv7a_l1_d_cache_flush_virt(target
, virt
, size
);
383 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
389 * We assume that target core was chosen correctly. It means if same data
390 * was handled by two cores, other core will loose the changes. Since it
391 * is impossible to know (FIXME) which core has correct data, keep in mind
392 * that some kind of data lost or korruption is possible.
394 * - core1 loaded and changed data on 0x12345678
395 * - we halted target and modified same data on core0
396 * - data on core1 will be lost.
398 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
401 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
403 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
406 return armv7a_cache_flush_virt(target
, virt
, size
);
409 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
411 struct target
*target
= get_current_target(CMD_CTX
);
412 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
414 return armv7a_handle_cache_info_command(CMD_CTX
,
415 &armv7a
->armv7a_mmu
.armv7a_cache
);
418 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
420 struct target
*target
= get_current_target(CMD_CTX
);
422 armv7a_l1_d_cache_clean_inval_all(target
);
427 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
429 struct target
*target
= get_current_target(CMD_CTX
);
432 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
433 return ERROR_COMMAND_SYNTAX_ERROR
;
436 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
440 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
442 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
445 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
447 struct target
*target
= get_current_target(CMD_CTX
);
450 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
451 return ERROR_COMMAND_SYNTAX_ERROR
;
454 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
458 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
460 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
463 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
465 struct target
*target
= get_current_target(CMD_CTX
);
467 armv7a_l1_i_cache_inval_all(target
);
472 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
474 struct target
*target
= get_current_target(CMD_CTX
);
477 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
478 return ERROR_COMMAND_SYNTAX_ERROR
;
481 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
485 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
487 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
490 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
492 struct target
*target
= get_current_target(CMD_CTX
);
493 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
496 command_print(CMD_CTX
, "auto cache is %s",
497 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
504 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
505 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
509 return ERROR_COMMAND_SYNTAX_ERROR
;
512 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
515 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
517 .help
= "flush (clean and invalidate) complete l1 d-cache",
522 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
524 .help
= "invalidate l1 d-cache by virtual address offset and range size",
525 .usage
= "<virt_addr> [size]",
529 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
531 .help
= "clean l1 d-cache by virtual address address offset and range size",
532 .usage
= "<virt_addr> [size]",
534 COMMAND_REGISTRATION_DONE
537 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
540 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
542 .help
= "invalidate complete l1 i-cache",
547 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
549 .help
= "invalidate l1 i-cache by virtual address offset and range size",
550 .usage
= "<virt_addr> [size]",
552 COMMAND_REGISTRATION_DONE
555 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
558 .handler
= arm7a_l1_cache_info_cmd
,
560 .help
= "print cache realted information",
566 .help
= "l1 d-cache command group",
568 .chain
= arm7a_l1_d_cache_commands
,
573 .help
= "l1 i-cache command group",
575 .chain
= arm7a_l1_i_cache_commands
,
577 COMMAND_REGISTRATION_DONE
580 const struct command_registration arm7a_cache_group_handlers
[] = {
583 .handler
= arm7a_cache_disable_auto_cmd
,
585 .help
= "disable or enable automatic cache handling.",
591 .help
= "l1 cache command group",
593 .chain
= arm7a_l1_di_cache_group_handlers
,
596 .chain
= arm7a_l2x_cache_command_handler
,
598 COMMAND_REGISTRATION_DONE
601 const struct command_registration arm7a_cache_command_handlers
[] = {
605 .help
= "cache command group",
607 .chain
= arm7a_cache_group_handlers
,
609 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)