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 /* FIXME: do l2x flushing here */
136 static int armv7a_l1_d_cache_inval_virt(struct target
*target
, uint32_t virt
,
139 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
140 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
141 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
142 uint32_t i
, linelen
= armv7a_cache
->dminline
;
145 retval
= armv7a_l1_d_cache_sanity_check(target
);
146 if (retval
!= ERROR_OK
)
149 retval
= dpm
->prepare(dpm
);
150 if (retval
!= ERROR_OK
)
153 for (i
= 0; i
< size
; i
+= linelen
) {
154 uint32_t offs
= virt
+ i
;
156 /* DCIMVAC - Clean and invalidate data cache line by VA to PoC. */
157 retval
= dpm
->instr_write_data_r0(dpm
,
158 ARMV4_5_MCR(15, 0, 0, 7, 6, 1), offs
);
159 if (retval
!= ERROR_OK
)
165 LOG_ERROR("d-cache invalidate failed");
171 int armv7a_l1_d_cache_clean_virt(struct target
*target
, uint32_t virt
,
174 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
175 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
176 struct armv7a_cache_common
*armv7a_cache
= &armv7a
->armv7a_mmu
.armv7a_cache
;
177 uint32_t i
, linelen
= armv7a_cache
->dminline
;
180 retval
= armv7a_l1_d_cache_sanity_check(target
);
181 if (retval
!= ERROR_OK
)
184 retval
= dpm
->prepare(dpm
);
185 if (retval
!= ERROR_OK
)
188 for (i
= 0; i
< size
; i
+= linelen
) {
189 uint32_t offs
= virt
+ i
;
191 /* FIXME: do we need DCCVAC or DCCVAU */
192 /* FIXME: in both cases it is not enough for i-cache */
193 retval
= dpm
->instr_write_data_r0(dpm
,
194 ARMV4_5_MCR(15, 0, 0, 7, 10, 1), offs
);
195 if (retval
!= ERROR_OK
)
201 LOG_ERROR("d-cache invalidate failed");
207 int armv7a_l1_i_cache_inval_all(struct target
*target
)
209 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
210 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
213 retval
= armv7a_l1_i_cache_sanity_check(target
);
214 if (retval
!= ERROR_OK
)
217 retval
= dpm
->prepare(dpm
);
218 if (retval
!= ERROR_OK
)
223 retval
= dpm
->instr_write_data_r0(dpm
,
224 ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
227 retval
= dpm
->instr_write_data_r0(dpm
,
228 ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
231 if (retval
!= ERROR_OK
)
238 LOG_ERROR("i-cache invalidate failed");
244 int armv7a_l1_i_cache_inval_virt(struct target
*target
, uint32_t virt
,
247 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
248 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
249 struct armv7a_cache_common
*armv7a_cache
=
250 &armv7a
->armv7a_mmu
.armv7a_cache
;
251 uint32_t linelen
= armv7a_cache
->iminline
;
252 uint32_t va_line
, va_end
;
255 retval
= armv7a_l1_i_cache_sanity_check(target
);
256 if (retval
!= ERROR_OK
)
259 retval
= dpm
->prepare(dpm
);
260 if (retval
!= ERROR_OK
)
263 va_line
= virt
& (-linelen
);
264 va_end
= virt
+ size
;
266 while (va_line
< va_end
) {
267 /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
268 retval
= dpm
->instr_write_data_r0(dpm
,
269 ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line
);
270 if (retval
!= ERROR_OK
)
273 retval
= dpm
->instr_write_data_r0(dpm
,
274 ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line
);
275 if (retval
!= ERROR_OK
)
282 LOG_ERROR("i-cache invalidate failed");
290 * We assume that target core was chosen correctly. It means if same data
291 * was handled by two cores, other core will loose the changes. Since it
292 * is impossible to know (FIXME) which core has correct data, keep in mind
293 * that some kind of data lost or korruption is possible.
295 * - core1 loaded and changed data on 0x12345678
296 * - we halted target and modified same data on core0
297 * - data on core1 will be lost.
299 int armv7a_cache_auto_flush_on_write(struct target
*target
, uint32_t virt
,
302 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
303 int retval
= ERROR_OK
;
305 if (!armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
)
308 armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
309 armv7a_l2x_cache_flush_virt(target
, virt
, size
);
312 struct target_list
*head
;
315 while (head
!= (struct target_list
*)NULL
) {
317 if (curr
->state
== TARGET_HALTED
) {
318 retval
= armv7a_l1_i_cache_inval_all(curr
);
319 if (retval
!= ERROR_OK
)
321 retval
= armv7a_l1_d_cache_inval_virt(target
,
323 if (retval
!= ERROR_OK
)
329 retval
= armv7a_l1_i_cache_inval_all(target
);
330 if (retval
!= ERROR_OK
)
332 retval
= armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
333 if (retval
!= ERROR_OK
)
340 COMMAND_HANDLER(arm7a_l1_cache_info_cmd
)
342 struct target
*target
= get_current_target(CMD_CTX
);
343 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
345 return armv7a_handle_cache_info_command(CMD_CTX
,
346 &armv7a
->armv7a_mmu
.armv7a_cache
);
349 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd
)
351 struct target
*target
= get_current_target(CMD_CTX
);
353 armv7a_l1_d_cache_clean_inval_all(target
);
358 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd
)
360 struct target
*target
= get_current_target(CMD_CTX
);
363 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
364 return ERROR_COMMAND_SYNTAX_ERROR
;
367 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
371 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
373 return armv7a_l1_d_cache_inval_virt(target
, virt
, size
);
376 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd
)
378 struct target
*target
= get_current_target(CMD_CTX
);
381 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
382 return ERROR_COMMAND_SYNTAX_ERROR
;
385 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
389 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
391 return armv7a_l1_d_cache_clean_virt(target
, virt
, size
);
394 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd
)
396 struct target
*target
= get_current_target(CMD_CTX
);
398 armv7a_l1_i_cache_inval_all(target
);
403 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd
)
405 struct target
*target
= get_current_target(CMD_CTX
);
408 if (CMD_ARGC
== 0 || CMD_ARGC
> 2)
409 return ERROR_COMMAND_SYNTAX_ERROR
;
412 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], size
);
416 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], virt
);
418 return armv7a_l1_i_cache_inval_virt(target
, virt
, size
);
421 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd
)
423 struct target
*target
= get_current_target(CMD_CTX
);
424 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
427 command_print(CMD_CTX
, "auto cache is %s",
428 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
? "enabled" : "disabled");
435 COMMAND_PARSE_ENABLE(CMD_ARGV
[0], set
);
436 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= !!set
;
440 return ERROR_COMMAND_SYNTAX_ERROR
;
443 static const struct command_registration arm7a_l1_d_cache_commands
[] = {
446 .handler
= armv7a_l1_d_cache_clean_inval_all_cmd
,
448 .help
= "flush (clean and invalidate) complete l1 d-cache",
453 .handler
= arm7a_l1_d_cache_inval_virt_cmd
,
455 .help
= "invalidate l1 d-cache by virtual address offset and range size",
456 .usage
= "<virt_addr> [size]",
460 .handler
= arm7a_l1_d_cache_clean_virt_cmd
,
462 .help
= "clean l1 d-cache by virtual address address offset and range size",
463 .usage
= "<virt_addr> [size]",
465 COMMAND_REGISTRATION_DONE
468 static const struct command_registration arm7a_l1_i_cache_commands
[] = {
471 .handler
= armv7a_i_cache_clean_inval_all_cmd
,
473 .help
= "invalidate complete l1 i-cache",
478 .handler
= arm7a_l1_i_cache_inval_virt_cmd
,
480 .help
= "invalidate l1 i-cache by virtual address offset and range size",
481 .usage
= "<virt_addr> [size]",
483 COMMAND_REGISTRATION_DONE
486 const struct command_registration arm7a_l1_di_cache_group_handlers
[] = {
489 .handler
= arm7a_l1_cache_info_cmd
,
491 .help
= "print cache realted information",
497 .help
= "l1 d-cache command group",
499 .chain
= arm7a_l1_d_cache_commands
,
504 .help
= "l1 i-cache command group",
506 .chain
= arm7a_l1_i_cache_commands
,
508 COMMAND_REGISTRATION_DONE
511 const struct command_registration arm7a_cache_group_handlers
[] = {
514 .handler
= arm7a_cache_disable_auto_cmd
,
516 .help
= "disable or enable automatic cache handling.",
522 .help
= "l1 cache command group",
524 .chain
= arm7a_l1_di_cache_group_handlers
,
527 .chain
= arm7a_l2x_cache_command_handler
,
529 COMMAND_REGISTRATION_DONE
532 const struct command_registration arm7a_cache_command_handlers
[] = {
536 .help
= "cache command group",
538 .chain
= arm7a_cache_group_handlers
,
540 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)