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 
125  if (target->smp) {
126  struct target_list *head;
128  struct target *curr = head->target;
129  if (curr->state == TARGET_HALTED) {
130  int retval1 = armv7a_l1_d_cache_clean_inval_all(curr);
131  if (retval1 != ERROR_OK)
132  retval = retval1;
133  }
134  }
135  } else
137 
138  if (retval != ERROR_OK)
139  return retval;
140 
141  /* do outer cache flushing after inner caches have been flushed */
143 }
144 
145 
146 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
147  uint32_t size)
148 {
149  struct armv7a_common *armv7a = target_to_armv7a(target);
150  struct arm_dpm *dpm = armv7a->arm.dpm;
151  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
152  uint32_t linelen = armv7a_cache->dminline;
153  uint32_t va_line, va_end;
154  int retval, i = 0;
155 
157  if (retval != ERROR_OK)
158  return retval;
159 
160  retval = dpm->prepare(dpm);
161  if (retval != ERROR_OK)
162  goto done;
163 
164  va_line = virt & (-linelen);
165  va_end = virt + size;
166 
167  /* handle unaligned start */
168  if (virt != va_line) {
169  /* DCCIMVAC */
170  retval = dpm->instr_write_data_r0(dpm,
171  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
172  if (retval != ERROR_OK)
173  goto done;
174  va_line += linelen;
175  }
176 
177  /* handle unaligned end */
178  if ((va_end & (linelen-1)) != 0) {
179  va_end &= (-linelen);
180  /* DCCIMVAC */
181  retval = dpm->instr_write_data_r0(dpm,
182  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
183  if (retval != ERROR_OK)
184  goto done;
185  }
186 
187  while (va_line < va_end) {
188  if ((i++ & 0x3f) == 0)
189  keep_alive();
190  /* DCIMVAC - Invalidate data cache line by VA to PoC. */
191  retval = dpm->instr_write_data_r0(dpm,
192  ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
193  if (retval != ERROR_OK)
194  goto done;
195  va_line += linelen;
196  }
197 
198  keep_alive();
199  dpm->finish(dpm);
200  return retval;
201 
202 done:
203  LOG_ERROR("d-cache invalidate failed");
204  keep_alive();
205  dpm->finish(dpm);
206 
207  return retval;
208 }
209 
210 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
211  unsigned int size)
212 {
213  struct armv7a_common *armv7a = target_to_armv7a(target);
214  struct arm_dpm *dpm = armv7a->arm.dpm;
215  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
216  uint32_t linelen = armv7a_cache->dminline;
217  uint32_t va_line, va_end;
218  int retval, i = 0;
219 
221  if (retval != ERROR_OK)
222  return retval;
223 
224  retval = dpm->prepare(dpm);
225  if (retval != ERROR_OK)
226  goto done;
227 
228  va_line = virt & (-linelen);
229  va_end = virt + size;
230 
231  while (va_line < va_end) {
232  if ((i++ & 0x3f) == 0)
233  keep_alive();
234  /* DCCMVAC - Data Cache Clean by MVA to PoC */
235  retval = dpm->instr_write_data_r0(dpm,
236  ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
237  if (retval != ERROR_OK)
238  goto done;
239  va_line += linelen;
240  }
241 
242  keep_alive();
243  dpm->finish(dpm);
244  return retval;
245 
246 done:
247  LOG_ERROR("d-cache invalidate failed");
248  keep_alive();
249  dpm->finish(dpm);
250 
251  return retval;
252 }
253 
254 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
255  unsigned int size)
256 {
257  struct armv7a_common *armv7a = target_to_armv7a(target);
258  struct arm_dpm *dpm = armv7a->arm.dpm;
259  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
260  uint32_t linelen = armv7a_cache->dminline;
261  uint32_t va_line, va_end;
262  int retval, i = 0;
263 
265  if (retval != ERROR_OK)
266  return retval;
267 
268  retval = dpm->prepare(dpm);
269  if (retval != ERROR_OK)
270  goto done;
271 
272  va_line = virt & (-linelen);
273  va_end = virt + size;
274 
275  while (va_line < va_end) {
276  if ((i++ & 0x3f) == 0)
277  keep_alive();
278  /* DCCIMVAC */
279  retval = dpm->instr_write_data_r0(dpm,
280  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
281  if (retval != ERROR_OK)
282  goto done;
283  va_line += linelen;
284  }
285 
286  keep_alive();
287  dpm->finish(dpm);
288  return retval;
289 
290 done:
291  LOG_ERROR("d-cache invalidate failed");
292  keep_alive();
293  dpm->finish(dpm);
294 
295  return retval;
296 }
297 
299 {
300  struct armv7a_common *armv7a = target_to_armv7a(target);
301  struct arm_dpm *dpm = armv7a->arm.dpm;
302  int retval;
303 
305  if (retval != ERROR_OK)
306  return retval;
307 
308  retval = dpm->prepare(dpm);
309  if (retval != ERROR_OK)
310  goto done;
311 
312  if (target->smp) {
313  /* ICIALLUIS */
314  retval = dpm->instr_write_data_r0(dpm,
315  ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
316  } else {
317  /* ICIALLU */
318  retval = dpm->instr_write_data_r0(dpm,
319  ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
320  }
321 
322  if (retval != ERROR_OK)
323  goto done;
324 
325  dpm->finish(dpm);
326  return retval;
327 
328 done:
329  LOG_ERROR("i-cache invalidate failed");
330  dpm->finish(dpm);
331 
332  return retval;
333 }
334 
335 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
336  uint32_t size)
337 {
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;
344  int retval, i = 0;
345 
347  if (retval != ERROR_OK)
348  return retval;
349 
350  retval = dpm->prepare(dpm);
351  if (retval != ERROR_OK)
352  goto done;
353 
354  va_line = virt & (-linelen);
355  va_end = virt + size;
356 
357  while (va_line < va_end) {
358  if ((i++ & 0x3f) == 0)
359  keep_alive();
360  /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
361  retval = dpm->instr_write_data_r0(dpm,
362  ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
363  if (retval != ERROR_OK)
364  goto done;
365  /* BPIMVA */
366  retval = dpm->instr_write_data_r0(dpm,
367  ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
368  if (retval != ERROR_OK)
369  goto done;
370  va_line += linelen;
371  }
372  keep_alive();
373  dpm->finish(dpm);
374  return retval;
375 
376 done:
377  LOG_ERROR("i-cache invalidate failed");
378  keep_alive();
379  dpm->finish(dpm);
380 
381  return retval;
382 }
383 
384 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
385  uint32_t size)
386 {
389 
390  return ERROR_OK;
391 }
392 
393 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
394 {
396  struct armv7a_common *armv7a = target_to_armv7a(target);
397 
399  &armv7a->armv7a_mmu.armv7a_cache);
400 }
401 
402 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
403 {
405 
407 
408  return 0;
409 }
410 
411 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
412 {
414  uint32_t virt, size;
415 
416  if (CMD_ARGC == 0 || CMD_ARGC > 2)
418 
419  if (CMD_ARGC == 2)
421  else
422  size = 1;
423 
424  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
425 
427 }
428 
429 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
430 {
432  uint32_t virt, size;
433 
434  if (CMD_ARGC == 0 || CMD_ARGC > 2)
436 
437  if (CMD_ARGC == 2)
439  else
440  size = 1;
441 
442  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
443 
445 }
446 
447 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
448 {
450 
452 
453  return 0;
454 }
455 
456 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
457 {
459  uint32_t virt, size;
460 
461  if (CMD_ARGC == 0 || CMD_ARGC > 2)
463 
464  if (CMD_ARGC == 2)
466  else
467  size = 1;
468 
469  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
470 
472 }
473 
474 static const struct command_registration arm7a_l1_d_cache_commands[] = {
475  {
476  .name = "flush_all",
477  .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
478  .mode = COMMAND_ANY,
479  .help = "flush (clean and invalidate) complete l1 d-cache",
480  .usage = "",
481  },
482  {
483  .name = "inval",
484  .handler = arm7a_l1_d_cache_inval_virt_cmd,
485  .mode = COMMAND_ANY,
486  .help = "invalidate l1 d-cache by virtual address offset and range size",
487  .usage = "<virt_addr> [size]",
488  },
489  {
490  .name = "clean",
491  .handler = arm7a_l1_d_cache_clean_virt_cmd,
492  .mode = COMMAND_ANY,
493  .help = "clean l1 d-cache by virtual address address offset and range size",
494  .usage = "<virt_addr> [size]",
495  },
497 };
498 
499 static const struct command_registration arm7a_l1_i_cache_commands[] = {
500  {
501  .name = "inval_all",
502  .handler = armv7a_i_cache_clean_inval_all_cmd,
503  .mode = COMMAND_ANY,
504  .help = "invalidate complete l1 i-cache",
505  .usage = "",
506  },
507  {
508  .name = "inval",
509  .handler = arm7a_l1_i_cache_inval_virt_cmd,
510  .mode = COMMAND_ANY,
511  .help = "invalidate l1 i-cache by virtual address offset and range size",
512  .usage = "<virt_addr> [size]",
513  },
515 };
516 
518  {
519  .name = "info",
520  .handler = arm7a_l1_cache_info_cmd,
521  .mode = COMMAND_ANY,
522  .help = "print cache related information",
523  .usage = "",
524  },
525  {
526  .name = "d",
527  .mode = COMMAND_ANY,
528  .help = "l1 d-cache command group",
529  .usage = "",
530  .chain = arm7a_l1_d_cache_commands,
531  },
532  {
533  .name = "i",
534  .mode = COMMAND_ANY,
535  .help = "l1 i-cache command group",
536  .usage = "",
537  .chain = arm7a_l1_i_cache_commands,
538  },
540 };
541 
542 static const struct command_registration arm7a_cache_group_handlers[] = {
543  {
544  .name = "l1",
545  .mode = COMMAND_ANY,
546  .help = "l1 cache command group",
547  .usage = "",
549  },
550  {
552  },
554 };
555 
557  {
558  .name = "cache",
559  .mode = COMMAND_ANY,
560  .help = "cache command group",
561  .usage = "",
563  },
565 };
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:120
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:254
int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:335
int armv7a_l1_i_cache_inval_all(struct target *target)
Definition: armv7a_cache.c:298
static const struct command_registration arm7a_l1_i_cache_commands[]
Definition: armv7a_cache.c:499
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
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_cache_flush_all_data(struct target *target)
Definition: armv7a_cache.c:121
int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, unsigned int size)
Definition: armv7a_cache.c:210
static const struct command_registration arm7a_l1_di_cache_group_handlers[]
Definition: armv7a_cache.c:517
int armv7a_cache_flush_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:384
static const struct command_registration arm7a_cache_group_handlers[]
Definition: armv7a_cache.c:542
const struct command_registration arm7a_cache_command_handlers[]
Definition: armv7a_cache.c:556
COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
Definition: armv7a_cache.c:393
static const struct command_registration arm7a_l1_d_cache_commands[]
Definition: armv7a_cache.c:474
int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:146
#define CACHE_LEVEL_HAS_D_CACHE
Definition: armv7a_cache.h:30
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[]
#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_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:213
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 d_u_cache_enabled
Definition: armv7a.h:67
struct arm arm
Definition: armv7a.h:90
struct armv7a_mmu_common armv7a_mmu
Definition: armv7a.h:111
struct arm_dpm dpm
Definition: armv7a.h:94
struct armv7a_cache_common armv7a_cache
Definition: armv7a.h:83
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
enum target_state state
Definition: target.h:157
struct list_head * smp_targets
Definition: target.h:188
unsigned int smp
Definition: target.h:187
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