OpenOCD
armv7a_cache.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2015 by Oleksij Rempel *
5  * linux@rempel-privat.de *
6  ***************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11 
12 #include "jtag/interface.h"
13 #include "arm.h"
14 #include "armv7a.h"
15 #include "armv7a_cache.h"
16 #include <helper/time_support.h>
17 #include "arm_opcodes.h"
18 #include "smp.h"
19 
21 {
22  struct armv7a_common *armv7a = target_to_armv7a(target);
23 
24  if (target->state != TARGET_HALTED) {
25  LOG_TARGET_ERROR(target, "not halted");
27  }
28 
29  /* check that cache data is on at target halt */
31  LOG_DEBUG("data cache is not enabled");
32  return ERROR_TARGET_INVALID;
33  }
34 
35  return ERROR_OK;
36 }
37 
39 {
40  struct armv7a_common *armv7a = target_to_armv7a(target);
41 
42  if (target->state != TARGET_HALTED) {
43  LOG_TARGET_ERROR(target, "not halted");
45  }
46 
47  /* check that cache data is on at target halt */
49  LOG_DEBUG("instruction cache is not enabled");
50  return ERROR_TARGET_INVALID;
51  }
52 
53  return ERROR_OK;
54 }
55 
56 static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
57 {
58  int retval = ERROR_OK;
59  int32_t c_way, c_index = size->index;
60 
61  LOG_DEBUG("cl %" PRId32, cl);
62  do {
63  keep_alive();
64  c_way = size->way;
65  do {
66  uint32_t value = (c_index << size->index_shift)
67  | (c_way << size->way_shift) | (cl << 1);
68  /*
69  * DCCISW - Clean and invalidate data cache
70  * line by Set/Way.
71  */
72  retval = dpm->instr_write_data_r0(dpm,
73  ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
74  value);
75  if (retval != ERROR_OK)
76  goto done;
77  c_way -= 1;
78  } while (c_way >= 0);
79  c_index -= 1;
80  } while (c_index >= 0);
81 
82  done:
83  keep_alive();
84  return retval;
85 }
86 
88 {
89  struct armv7a_common *armv7a = target_to_armv7a(target);
90  struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
91  struct arm_dpm *dpm = armv7a->arm.dpm;
92  int cl;
93  int retval;
94 
96  if (retval != ERROR_OK)
97  return retval;
98 
99  retval = dpm->prepare(dpm);
100  if (retval != ERROR_OK)
101  goto done;
102 
103  for (cl = 0; cl < cache->loc; cl++) {
104  /* skip i-only caches */
105  if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
106  continue;
107 
108  armv7a_l1_d_cache_flush_level(dpm, &cache->arch[cl].d_u_size, cl);
109  }
110 
111  retval = dpm->finish(dpm);
112  return retval;
113 
114 done:
115  LOG_ERROR("clean invalidate failed");
116  dpm->finish(dpm);
117 
118  return retval;
119 }
120 
122 {
123  int retval = ERROR_FAIL;
124  struct armv7a_common *armv7a = target_to_armv7a(target);
125 
127  return ERROR_OK;
128 
129  if (target->smp) {
130  struct target_list *head;
132  struct target *curr = head->target;
133  if (curr->state == TARGET_HALTED)
134  retval = armv7a_l1_d_cache_clean_inval_all(curr);
135  }
136  } else
138 
139  if (retval != ERROR_OK)
140  return retval;
141 
142  /* do outer cache flushing after inner caches have been flushed */
144 }
145 
146 
147 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
148  uint32_t size)
149 {
150  struct armv7a_common *armv7a = target_to_armv7a(target);
151  struct arm_dpm *dpm = armv7a->arm.dpm;
152  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
153  uint32_t linelen = armv7a_cache->dminline;
154  uint32_t va_line, va_end;
155  int retval, i = 0;
156 
158  if (retval != ERROR_OK)
159  return retval;
160 
161  retval = dpm->prepare(dpm);
162  if (retval != ERROR_OK)
163  goto done;
164 
165  va_line = virt & (-linelen);
166  va_end = virt + size;
167 
168  /* handle unaligned start */
169  if (virt != va_line) {
170  /* DCCIMVAC */
171  retval = dpm->instr_write_data_r0(dpm,
172  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
173  if (retval != ERROR_OK)
174  goto done;
175  va_line += linelen;
176  }
177 
178  /* handle unaligned end */
179  if ((va_end & (linelen-1)) != 0) {
180  va_end &= (-linelen);
181  /* DCCIMVAC */
182  retval = dpm->instr_write_data_r0(dpm,
183  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
184  if (retval != ERROR_OK)
185  goto done;
186  }
187 
188  while (va_line < va_end) {
189  if ((i++ & 0x3f) == 0)
190  keep_alive();
191  /* DCIMVAC - Invalidate data cache line by VA to PoC. */
192  retval = dpm->instr_write_data_r0(dpm,
193  ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
194  if (retval != ERROR_OK)
195  goto done;
196  va_line += linelen;
197  }
198 
199  keep_alive();
200  dpm->finish(dpm);
201  return retval;
202 
203 done:
204  LOG_ERROR("d-cache invalidate failed");
205  keep_alive();
206  dpm->finish(dpm);
207 
208  return retval;
209 }
210 
211 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
212  unsigned int size)
213 {
214  struct armv7a_common *armv7a = target_to_armv7a(target);
215  struct arm_dpm *dpm = armv7a->arm.dpm;
216  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
217  uint32_t linelen = armv7a_cache->dminline;
218  uint32_t va_line, va_end;
219  int retval, i = 0;
220 
222  if (retval != ERROR_OK)
223  return retval;
224 
225  retval = dpm->prepare(dpm);
226  if (retval != ERROR_OK)
227  goto done;
228 
229  va_line = virt & (-linelen);
230  va_end = virt + size;
231 
232  while (va_line < va_end) {
233  if ((i++ & 0x3f) == 0)
234  keep_alive();
235  /* DCCMVAC - Data Cache Clean by MVA to PoC */
236  retval = dpm->instr_write_data_r0(dpm,
237  ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
238  if (retval != ERROR_OK)
239  goto done;
240  va_line += linelen;
241  }
242 
243  keep_alive();
244  dpm->finish(dpm);
245  return retval;
246 
247 done:
248  LOG_ERROR("d-cache invalidate failed");
249  keep_alive();
250  dpm->finish(dpm);
251 
252  return retval;
253 }
254 
255 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
256  unsigned int size)
257 {
258  struct armv7a_common *armv7a = target_to_armv7a(target);
259  struct arm_dpm *dpm = armv7a->arm.dpm;
260  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
261  uint32_t linelen = armv7a_cache->dminline;
262  uint32_t va_line, va_end;
263  int retval, i = 0;
264 
266  if (retval != ERROR_OK)
267  return retval;
268 
269  retval = dpm->prepare(dpm);
270  if (retval != ERROR_OK)
271  goto done;
272 
273  va_line = virt & (-linelen);
274  va_end = virt + size;
275 
276  while (va_line < va_end) {
277  if ((i++ & 0x3f) == 0)
278  keep_alive();
279  /* DCCIMVAC */
280  retval = dpm->instr_write_data_r0(dpm,
281  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
282  if (retval != ERROR_OK)
283  goto done;
284  va_line += linelen;
285  }
286 
287  keep_alive();
288  dpm->finish(dpm);
289  return retval;
290 
291 done:
292  LOG_ERROR("d-cache invalidate failed");
293  keep_alive();
294  dpm->finish(dpm);
295 
296  return retval;
297 }
298 
300 {
301  struct armv7a_common *armv7a = target_to_armv7a(target);
302  struct arm_dpm *dpm = armv7a->arm.dpm;
303  int retval;
304 
306  if (retval != ERROR_OK)
307  return retval;
308 
309  retval = dpm->prepare(dpm);
310  if (retval != ERROR_OK)
311  goto done;
312 
313  if (target->smp) {
314  /* ICIALLUIS */
315  retval = dpm->instr_write_data_r0(dpm,
316  ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
317  } else {
318  /* ICIALLU */
319  retval = dpm->instr_write_data_r0(dpm,
320  ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
321  }
322 
323  if (retval != ERROR_OK)
324  goto done;
325 
326  dpm->finish(dpm);
327  return retval;
328 
329 done:
330  LOG_ERROR("i-cache invalidate failed");
331  dpm->finish(dpm);
332 
333  return retval;
334 }
335 
336 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
337  uint32_t size)
338 {
339  struct armv7a_common *armv7a = target_to_armv7a(target);
340  struct arm_dpm *dpm = armv7a->arm.dpm;
341  struct armv7a_cache_common *armv7a_cache =
342  &armv7a->armv7a_mmu.armv7a_cache;
343  uint32_t linelen = armv7a_cache->iminline;
344  uint32_t va_line, va_end;
345  int retval, i = 0;
346 
348  if (retval != ERROR_OK)
349  return retval;
350 
351  retval = dpm->prepare(dpm);
352  if (retval != ERROR_OK)
353  goto done;
354 
355  va_line = virt & (-linelen);
356  va_end = virt + size;
357 
358  while (va_line < va_end) {
359  if ((i++ & 0x3f) == 0)
360  keep_alive();
361  /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
362  retval = dpm->instr_write_data_r0(dpm,
363  ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
364  if (retval != ERROR_OK)
365  goto done;
366  /* BPIMVA */
367  retval = dpm->instr_write_data_r0(dpm,
368  ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
369  if (retval != ERROR_OK)
370  goto done;
371  va_line += linelen;
372  }
373  keep_alive();
374  dpm->finish(dpm);
375  return retval;
376 
377 done:
378  LOG_ERROR("i-cache invalidate failed");
379  keep_alive();
380  dpm->finish(dpm);
381 
382  return retval;
383 }
384 
385 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
386  uint32_t size)
387 {
390 
391  return ERROR_OK;
392 }
393 
394 /*
395  * We assume that target core was chosen correctly. It means if same data
396  * was handled by two cores, other core will loose the changes. Since it
397  * is impossible to know (FIXME) which core has correct data, keep in mind
398  * that some kind of data lost or corruption is possible.
399  * Possible scenario:
400  * - core1 loaded and changed data on 0x12345678
401  * - we halted target and modified same data on core0
402  * - data on core1 will be lost.
403  */
404 int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt,
405  uint32_t size)
406 {
407  struct armv7a_common *armv7a = target_to_armv7a(target);
408 
410  return ERROR_OK;
411 
412  return armv7a_cache_flush_virt(target, virt, size);
413 }
414 
415 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
416 {
418  struct armv7a_common *armv7a = target_to_armv7a(target);
419 
421  &armv7a->armv7a_mmu.armv7a_cache);
422 }
423 
424 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
425 {
427 
429 
430  return 0;
431 }
432 
433 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
434 {
436  uint32_t virt, size;
437 
438  if (CMD_ARGC == 0 || CMD_ARGC > 2)
440 
441  if (CMD_ARGC == 2)
443  else
444  size = 1;
445 
446  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
447 
449 }
450 
451 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
452 {
454  uint32_t virt, size;
455 
456  if (CMD_ARGC == 0 || CMD_ARGC > 2)
458 
459  if (CMD_ARGC == 2)
461  else
462  size = 1;
463 
464  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
465 
467 }
468 
469 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
470 {
472 
474 
475  return 0;
476 }
477 
478 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
479 {
481  uint32_t virt, size;
482 
483  if (CMD_ARGC == 0 || CMD_ARGC > 2)
485 
486  if (CMD_ARGC == 2)
488  else
489  size = 1;
490 
491  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
492 
494 }
495 
496 COMMAND_HANDLER(arm7a_cache_disable_auto_cmd)
497 {
499  struct armv7a_common *armv7a = target_to_armv7a(target);
500 
501  if (CMD_ARGC == 0) {
502  command_print(CMD, "auto cache is %s",
503  armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled ? "enabled" : "disabled");
504  return ERROR_OK;
505  }
506 
507  if (CMD_ARGC == 1) {
508  uint32_t set;
509 
512  return ERROR_OK;
513  }
514 
516 }
517 
518 static const struct command_registration arm7a_l1_d_cache_commands[] = {
519  {
520  .name = "flush_all",
521  .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
522  .mode = COMMAND_ANY,
523  .help = "flush (clean and invalidate) complete l1 d-cache",
524  .usage = "",
525  },
526  {
527  .name = "inval",
528  .handler = arm7a_l1_d_cache_inval_virt_cmd,
529  .mode = COMMAND_ANY,
530  .help = "invalidate l1 d-cache by virtual address offset and range size",
531  .usage = "<virt_addr> [size]",
532  },
533  {
534  .name = "clean",
535  .handler = arm7a_l1_d_cache_clean_virt_cmd,
536  .mode = COMMAND_ANY,
537  .help = "clean l1 d-cache by virtual address address offset and range size",
538  .usage = "<virt_addr> [size]",
539  },
541 };
542 
543 static const struct command_registration arm7a_l1_i_cache_commands[] = {
544  {
545  .name = "inval_all",
546  .handler = armv7a_i_cache_clean_inval_all_cmd,
547  .mode = COMMAND_ANY,
548  .help = "invalidate complete l1 i-cache",
549  .usage = "",
550  },
551  {
552  .name = "inval",
553  .handler = arm7a_l1_i_cache_inval_virt_cmd,
554  .mode = COMMAND_ANY,
555  .help = "invalidate l1 i-cache by virtual address offset and range size",
556  .usage = "<virt_addr> [size]",
557  },
559 };
560 
562  {
563  .name = "info",
564  .handler = arm7a_l1_cache_info_cmd,
565  .mode = COMMAND_ANY,
566  .help = "print cache related information",
567  .usage = "",
568  },
569  {
570  .name = "d",
571  .mode = COMMAND_ANY,
572  .help = "l1 d-cache command group",
573  .usage = "",
574  .chain = arm7a_l1_d_cache_commands,
575  },
576  {
577  .name = "i",
578  .mode = COMMAND_ANY,
579  .help = "l1 i-cache command group",
580  .usage = "",
581  .chain = arm7a_l1_i_cache_commands,
582  },
584 };
585 
586 static const struct command_registration arm7a_cache_group_handlers[] = {
587  {
588  .name = "auto",
589  .handler = arm7a_cache_disable_auto_cmd,
590  .mode = COMMAND_ANY,
591  .help = "disable or enable automatic cache handling.",
592  .usage = "(1|0)",
593  },
594  {
595  .name = "l1",
596  .mode = COMMAND_ANY,
597  .help = "l1 cache command group",
598  .usage = "",
600  },
601  {
603  },
605 };
606 
608  {
609  .name = "cache",
610  .mode = COMMAND_ANY,
611  .help = "cache command group",
612  .usage = "",
614  },
616 };
Holds the interface to ARM cores.
Macros used to generate various ARM or Thumb opcodes.
#define ARMV4_5_MCR(cp, op1, rd, crn, crm, op2)
Definition: arm_opcodes.h:209
int armv7a_handle_cache_info_command(struct command_invocation *cmd, struct armv7a_cache_common *armv7a_cache)
Definition: armv7a.c:230
static struct armv7a_common * target_to_armv7a(struct target *target)
Definition: armv7a.h:122
static int armv7a_l1_d_cache_sanity_check(struct target *target)
Definition: armv7a_cache.c:20
int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, unsigned int size)
Definition: armv7a_cache.c:255
int armv7a_cache_auto_flush_all_data(struct target *target)
Definition: armv7a_cache.c:121
int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:336
int armv7a_l1_i_cache_inval_all(struct target *target)
Definition: armv7a_cache.c:299
static const struct command_registration arm7a_l1_i_cache_commands[]
Definition: armv7a_cache.c:543
static int armv7a_l1_i_cache_sanity_check(struct target *target)
Definition: armv7a_cache.c:38
static int armv7a_l1_d_cache_clean_inval_all(struct target *target)
Definition: armv7a_cache.c:87
int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:404
static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl)
Definition: armv7a_cache.c:56
int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, unsigned int size)
Definition: armv7a_cache.c:211
static const struct command_registration arm7a_l1_di_cache_group_handlers[]
Definition: armv7a_cache.c:561
int armv7a_cache_flush_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:385
static const struct command_registration arm7a_cache_group_handlers[]
Definition: armv7a_cache.c:586
const struct command_registration arm7a_cache_command_handlers[]
Definition: armv7a_cache.c:607
COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
Definition: armv7a_cache.c:415
static const struct command_registration arm7a_l1_d_cache_commands[]
Definition: armv7a_cache.c:518
int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:147
#define CACHE_LEVEL_HAS_D_CACHE
Definition: armv7a_cache.h:32
int arm7a_l2x_flush_all_data(struct target *target)
int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt, uint32_t size)
const struct command_registration arm7a_l2x_cache_command_handler[]
void command_print(struct command_invocation *cmd, const char *format,...)
Definition: command.c:443
#define CMD
Use this macro to access the command being handled, rather than accessing the variable directly.
Definition: command.h:141
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define COMMAND_PARSE_ENABLE(in, out)
parses an enable/disable command argument
Definition: command.h:524
#define COMMAND_PARSE_NUMBER(type, in, out)
parses the string in into out as a type, or prints a command error and passes the error code to the c...
Definition: command.h:442
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:146
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:253
@ COMMAND_ANY
Definition: command.h:42
void keep_alive(void)
Definition: log.c:415
#define ERROR_FAIL
Definition: log.h:170
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:158
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
#define foreach_smp_target(pos, head)
Definition: smp.h:15
This wraps an implementation of DPM primitives.
Definition: arm_dpm.h:47
int(* instr_write_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data)
Runs one instruction, writing data to R0 before execution.
Definition: arm_dpm.h:72
int(* finish)(struct arm_dpm *dpm)
Invoke after a series of instruction operations.
Definition: arm_dpm.h:57
int(* prepare)(struct arm_dpm *dpm)
Invoke before a series of instruction operations.
Definition: arm_dpm.h:54
struct arm_dpm * dpm
Handle for the debug module, if one is present.
Definition: arm.h:212
struct armv7a_cachesize d_u_size
Definition: armv7a.h:55
uint32_t dminline
Definition: armv7a.h:63
struct armv7a_arch_cache arch[6]
Definition: armv7a.h:65
uint32_t iminline
Definition: armv7a.h:64
int auto_cache_enabled
Definition: armv7a.h:68
int d_u_cache_enabled
Definition: armv7a.h:67
struct arm arm
Definition: armv7a.h:92
struct armv7a_mmu_common armv7a_mmu
Definition: armv7a.h:113
struct arm_dpm dpm
Definition: armv7a.h:96
struct armv7a_cache_common armv7a_cache
Definition: armv7a.h:85
const char * name
Definition: command.h:235
const struct command_registration * chain
If non-NULL, the commands in chain will be registered in the same context and scope of this registrat...
Definition: command.h:249
struct target * target
Definition: target.h:214
Definition: target.h:116
int smp
Definition: target.h:187
enum target_state state
Definition: target.h:157
struct list_head * smp_targets
Definition: target.h:188
struct target * get_current_target(struct command_context *cmd_ctx)
Definition: target.c:458
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:790
#define ERROR_TARGET_INVALID
Definition: target.h:787
@ TARGET_HALTED
Definition: target.h:56