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_clean_inval_all(struct target
*target
)
65 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
66 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
67 struct armv7a_cachesize
*d_u_size
=
68 &(armv7a
->armv7a_mmu
.armv7a_cache
.d_u_size
);
69 int32_t c_way
, c_index
= d_u_size
->index
;
72 retval
= armv7a_l1_d_cache_sanity_check(target
);
73 if (retval
!= ERROR_OK
)
76 retval
= dpm
->prepare(dpm
);
77 if (retval
!= ERROR_OK
)
81 c_way
= d_u_size
->way
;
83 uint32_t value
= (c_index
<< d_u_size
->index_shift
)
84 | (c_way
<< d_u_size
->way_shift
);
86 * DCCISW - Clean and invalidate data cache
89 retval
= dpm
->instr_write_data_r0(dpm
,
90 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
92 if (retval
!= ERROR_OK
)
97 } while (c_index
>= 0);
102 LOG_ERROR("clean invalidate failed");
108 int armv7a_cache_auto_flush_all_data(struct target
*target
)
110 int retval
= ERROR_FAIL
;
111 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
113 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
117 struct target_list
*head
;
120 while (head
!= (struct target_list
*)NULL
) {
122 if (curr
->state
== TARGET_HALTED
)
123 retval
= armv7a_l1_d_cache_clean_inval_all(curr
);
128 retval
= armv7a_l1_d_cache_clean_inval_all(target
);
130 /* do outer cache flushing after inner caches have been flushed */
131 retval
= arm7a_l2x_flush_all_data(target
);
137 static int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
140 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
141 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
142 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
143 uint32_t i
, linelen
= armv7a_cache
->dminline
;
146 retval
= armv7a_l1_d_cache_sanity_check(target
);
147 if (retval
!= ERROR_OK
)
150 retval
= dpm
->prepare(dpm
);
151 if (retval
!= ERROR_OK
)
154 for (i
= 0; i
< size
; i
+= linelen
) {
155 uint32_t offs
= virt
+ i
;
157 /* DCIMVAC - Clean and invalidate data cache line by VA to PoC. */
158 retval
= dpm
->instr_write_data_r0(dpm
,
159 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), offs
);
160 if (retval
!= ERROR_OK
)
166 LOG_ERROR("d-cache invalidate failed");
172 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
175 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
176 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
177 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
178 uint32_t i
, linelen
= armv7a_cache
->dminline
;
181 retval
= armv7a_l1_d_cache_sanity_check(target
);
182 if (retval
!= ERROR_OK
)
185 retval
= dpm
->prepare(dpm
);
186 if (retval
!= ERROR_OK
)
189 for (i
= 0; i
< size
; i
+= linelen
) {
190 uint32_t offs
= virt
+ i
;
192 /* FIXME: do we need DCCVAC or DCCVAU */
193 /* FIXME: in both cases it is not enough for i-cache */
194 retval
= dpm
->instr_write_data_r0(dpm
,
195 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), offs
);
196 if (retval
!= ERROR_OK
)
202 LOG_ERROR("d-cache invalidate failed");
208 int armv7a_l1_i_cache_inval_all(struct target
*target
)
210 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
211 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
214 retval
= armv7a_l1_i_cache_sanity_check(target
);
215 if (retval
!= ERROR_OK
)
218 retval
= dpm
->prepare(dpm
);
219 if (retval
!= ERROR_OK
)
224 retval
= dpm
->instr_write_data_r0(dpm
,
225 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
228 retval
= dpm
->instr_write_data_r0(dpm
,
229 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
232 if (retval
!= ERROR_OK
)
239 LOG_ERROR("i-cache invalidate failed");
245 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
248 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
249 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
250 struct armv7a_cache_common
*armv7a_cache
=
251 &armv7a
->armv7a_mmu
.armv7a_cache
;
252 uint32_t linelen
= armv7a_cache
->iminline
;
253 uint32_t va_line
, va_end
;
256 retval
= armv7a_l1_i_cache_sanity_check(target
);
257 if (retval
!= ERROR_OK
)
260 retval
= dpm
->prepare(dpm
);
261 if (retval
!= ERROR_OK
)
264 va_line
= virt
& (-linelen
);
265 va_end
= virt
+ size
;
267 while (va_line
< va_end
) {
268 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
269 retval
= dpm
->instr_write_data_r0(dpm
,
270 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
271 if (retval
!= ERROR_OK
)
274 retval
= dpm
->instr_write_data_r0(dpm
,
275 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
276 if (retval
!= ERROR_OK
)
283 LOG_ERROR("i-cache invalidate failed");
291 * We assume that target core was chosen correctly. It means if same data
292 * was handled by two cores, other core will loose the changes. Since it
293 * is impossible to know (FIXME) which core has correct data, keep in mind
294 * that some kind of data lost or korruption is possible.
296 * - core1 loaded and changed data on 0x12345678
297 * - we halted target and modified same data on core0
298 * - data on core1 will be lost.
300 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
303 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
304 int retval
= ERROR_OK
;
306 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
309 armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
310 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
313 struct target_list
*head
;
316 while (head
!= (struct target_list
*)NULL
) {
318 if (curr
->state
== TARGET_HALTED
) {
319 retval
= armv7a_l1_i_cache_inval_all(curr
);
320 if (retval
!= ERROR_OK
)
322 retval
= armv7a_l1_d_cache_inval_virt(target
,
324 if (retval
!= ERROR_OK
)
330 retval
= armv7a_l1_i_cache_inval_all(target
);
331 if (retval
!= ERROR_OK
)
333 retval
= armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
334 if (retval
!= ERROR_OK
)
341 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
343 struct target
*target
= get_current_target(CMD_CTX
);
344 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
346 return armv7a_handle_cache_info_command(CMD_CTX
,
347 &armv7a
->armv7a_mmu
.armv7a_cache
);
350 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
352 struct target
*target
= get_current_target(CMD_CTX
);
354 armv7a_l1_d_cache_clean_inval_all(target
);
359 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
361 struct target
*target
= get_current_target(CMD_CTX
);
364 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
365 return ERROR_COMMAND_SYNTAX_ERROR
;
368 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
372 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
374 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
377 COMMAND_HANDLER(arm7a_l1_d_cache_clean_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_clean_virt(target
, virt
, size
);
395 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
397 struct target
*target
= get_current_target(CMD_CTX
);
399 armv7a_l1_i_cache_inval_all(target
);
404 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
406 struct target
*target
= get_current_target(CMD_CTX
);
409 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
410 return ERROR_COMMAND_SYNTAX_ERROR
;
413 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
417 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
419 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
422 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
424 struct target
*target
= get_current_target(CMD_CTX
);
425 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
428 command_print(CMD_CTX
, "auto cache is %s",
429 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
436 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
437 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
441 return ERROR_COMMAND_SYNTAX_ERROR
;
444 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
447 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
449 .help
= "flush (clean and invalidate) complete l1 d-cache",
454 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
456 .help
= "invalidate l1 d-cache by virtual address offset and range size",
457 .usage
= "<virt_addr> [size]",
461 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
463 .help
= "clean l1 d-cache by virtual address address offset and range size",
464 .usage
= "<virt_addr> [size]",
466 COMMAND_REGISTRATION_DONE
469 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
472 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
474 .help
= "invalidate complete l1 i-cache",
479 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
481 .help
= "invalidate l1 i-cache by virtual address offset and range size",
482 .usage
= "<virt_addr> [size]",
484 COMMAND_REGISTRATION_DONE
487 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
490 .handler
= arm7a_l1_cache_info_cmd
,
492 .help
= "print cache realted information",
498 .help
= "l1 d-cache command group",
500 .chain
= arm7a_l1_d_cache_commands
,
505 .help
= "l1 i-cache command group",
507 .chain
= arm7a_l1_i_cache_commands
,
509 COMMAND_REGISTRATION_DONE
512 const struct command_registration arm7a_cache_group_handlers
[] = {
515 .handler
= arm7a_cache_disable_auto_cmd
,
517 .help
= "disable or enable automatic cache handling.",
523 .help
= "l1 cache command group",
525 .chain
= arm7a_l1_di_cache_group_handlers
,
528 .chain
= arm7a_l2x_cache_command_handler
,
530 COMMAND_REGISTRATION_DONE
533 const struct command_registration arm7a_cache_command_handlers
[] = {
537 .help
= "cache command group",
539 .chain
= arm7a_cache_group_handlers
,
541 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)