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  return dpm->finish(dpm);
112 
113 done:
114  LOG_ERROR("clean invalidate failed");
115  dpm->finish(dpm);
116 
117  return retval;
118 }
119 
121 {
122  int retval = ERROR_FAIL;
123 
124  if (target->smp) {
125  struct target_list *head;
127  struct target *curr = head->target;
128  if (curr->state == TARGET_HALTED) {
129  int retval1 = armv7a_l1_d_cache_clean_inval_all(curr);
130  if (retval1 != ERROR_OK)
131  retval = retval1;
132  }
133  }
134  } else
136 
137  if (retval != ERROR_OK)
138  return retval;
139 
140  /* do outer cache flushing after inner caches have been flushed */
142 }
143 
144 
145 int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
146  uint32_t size)
147 {
148  struct armv7a_common *armv7a = target_to_armv7a(target);
149  struct arm_dpm *dpm = armv7a->arm.dpm;
150  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
151  uint32_t linelen = armv7a_cache->dminline;
152  uint32_t va_line, va_end;
153 
155  if (retval != ERROR_OK)
156  return retval;
157 
158  retval = dpm->prepare(dpm);
159  if (retval != ERROR_OK)
160  goto done;
161 
162  va_line = virt & (-linelen);
163  va_end = virt + size;
164 
165  /* handle unaligned start */
166  if (virt != va_line) {
167  /* DCCIMVAC */
168  retval = dpm->instr_write_data_r0(dpm,
169  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
170  if (retval != ERROR_OK)
171  goto done;
172  va_line += linelen;
173  }
174 
175  /* handle unaligned end */
176  if ((va_end & (linelen-1)) != 0) {
177  va_end &= (-linelen);
178  /* DCCIMVAC */
179  retval = dpm->instr_write_data_r0(dpm,
180  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
181  if (retval != ERROR_OK)
182  goto done;
183  }
184 
185  while (va_line < va_end) {
186  keep_alive();
187  /* DCIMVAC - Invalidate data cache line by VA to PoC. */
188  retval = dpm->instr_write_data_r0(dpm,
189  ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
190  if (retval != ERROR_OK)
191  goto done;
192  va_line += linelen;
193  }
194 
195  keep_alive();
196  dpm->finish(dpm);
197  return retval;
198 
199 done:
200  LOG_ERROR("d-cache invalidate failed");
201  keep_alive();
202  dpm->finish(dpm);
203 
204  return retval;
205 }
206 
207 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
208  unsigned int size)
209 {
210  struct armv7a_common *armv7a = target_to_armv7a(target);
211  struct arm_dpm *dpm = armv7a->arm.dpm;
212  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
213  uint32_t linelen = armv7a_cache->dminline;
214  uint32_t va_line, va_end;
215 
217  if (retval != ERROR_OK)
218  return retval;
219 
220  retval = dpm->prepare(dpm);
221  if (retval != ERROR_OK)
222  goto done;
223 
224  va_line = virt & (-linelen);
225  va_end = virt + size;
226 
227  while (va_line < va_end) {
228  keep_alive();
229  /* DCCMVAC - Data Cache Clean by MVA to PoC */
230  retval = dpm->instr_write_data_r0(dpm,
231  ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
232  if (retval != ERROR_OK)
233  goto done;
234  va_line += linelen;
235  }
236 
237  keep_alive();
238  dpm->finish(dpm);
239  return retval;
240 
241 done:
242  LOG_ERROR("d-cache invalidate failed");
243  keep_alive();
244  dpm->finish(dpm);
245 
246  return retval;
247 }
248 
249 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
250  unsigned int size)
251 {
252  struct armv7a_common *armv7a = target_to_armv7a(target);
253  struct arm_dpm *dpm = armv7a->arm.dpm;
254  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
255  uint32_t linelen = armv7a_cache->dminline;
256  uint32_t va_line, va_end;
257 
259  if (retval != ERROR_OK)
260  return retval;
261 
262  retval = dpm->prepare(dpm);
263  if (retval != ERROR_OK)
264  goto done;
265 
266  va_line = virt & (-linelen);
267  va_end = virt + size;
268 
269  while (va_line < va_end) {
270  keep_alive();
271  /* DCCIMVAC */
272  retval = dpm->instr_write_data_r0(dpm,
273  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
274  if (retval != ERROR_OK)
275  goto done;
276  va_line += linelen;
277  }
278 
279  keep_alive();
280  dpm->finish(dpm);
281  return retval;
282 
283 done:
284  LOG_ERROR("d-cache invalidate failed");
285  keep_alive();
286  dpm->finish(dpm);
287 
288  return retval;
289 }
290 
292 {
293  struct armv7a_common *armv7a = target_to_armv7a(target);
294  struct arm_dpm *dpm = armv7a->arm.dpm;
295  int retval;
296 
298  if (retval != ERROR_OK)
299  return retval;
300 
301  retval = dpm->prepare(dpm);
302  if (retval != ERROR_OK)
303  goto done;
304 
305  if (target->smp) {
306  /* ICIALLUIS */
307  retval = dpm->instr_write_data_r0(dpm,
308  ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
309  } else {
310  /* ICIALLU */
311  retval = dpm->instr_write_data_r0(dpm,
312  ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
313  }
314 
315  if (retval != ERROR_OK)
316  goto done;
317 
318  dpm->finish(dpm);
319  return retval;
320 
321 done:
322  LOG_ERROR("i-cache invalidate failed");
323  dpm->finish(dpm);
324 
325  return retval;
326 }
327 
328 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
329  uint32_t size)
330 {
331  struct armv7a_common *armv7a = target_to_armv7a(target);
332  struct arm_dpm *dpm = armv7a->arm.dpm;
333  struct armv7a_cache_common *armv7a_cache =
334  &armv7a->armv7a_mmu.armv7a_cache;
335  uint32_t linelen = armv7a_cache->iminline;
336  uint32_t va_line, va_end;
337 
339  if (retval != ERROR_OK)
340  return retval;
341 
342  retval = dpm->prepare(dpm);
343  if (retval != ERROR_OK)
344  goto done;
345 
346  va_line = virt & (-linelen);
347  va_end = virt + size;
348 
349  while (va_line < va_end) {
350  keep_alive();
351  /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
352  retval = dpm->instr_write_data_r0(dpm,
353  ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
354  if (retval != ERROR_OK)
355  goto done;
356  /* BPIMVA */
357  retval = dpm->instr_write_data_r0(dpm,
358  ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
359  if (retval != ERROR_OK)
360  goto done;
361  va_line += linelen;
362  }
363  keep_alive();
364  dpm->finish(dpm);
365  return retval;
366 
367 done:
368  LOG_ERROR("i-cache invalidate failed");
369  keep_alive();
370  dpm->finish(dpm);
371 
372  return retval;
373 }
374 
375 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
376  uint32_t size)
377 {
380 
381  return ERROR_OK;
382 }
383 
384 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
385 {
387  struct armv7a_common *armv7a = target_to_armv7a(target);
388 
390  &armv7a->armv7a_mmu.armv7a_cache);
391 }
392 
393 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
394 {
396 
398 
399  return 0;
400 }
401 
402 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
403 {
405  uint32_t virt, size;
406 
407  if (CMD_ARGC == 0 || CMD_ARGC > 2)
409 
410  if (CMD_ARGC == 2)
412  else
413  size = 1;
414 
415  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
416 
418 }
419 
420 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
421 {
423  uint32_t virt, size;
424 
425  if (CMD_ARGC == 0 || CMD_ARGC > 2)
427 
428  if (CMD_ARGC == 2)
430  else
431  size = 1;
432 
433  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
434 
436 }
437 
438 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
439 {
441 
443 
444  return 0;
445 }
446 
447 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
448 {
450  uint32_t virt, size;
451 
452  if (CMD_ARGC == 0 || CMD_ARGC > 2)
454 
455  if (CMD_ARGC == 2)
457  else
458  size = 1;
459 
460  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
461 
463 }
464 
465 static const struct command_registration arm7a_l1_d_cache_commands[] = {
466  {
467  .name = "flush_all",
468  .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
469  .mode = COMMAND_ANY,
470  .help = "flush (clean and invalidate) complete l1 d-cache",
471  .usage = "",
472  },
473  {
474  .name = "inval",
475  .handler = arm7a_l1_d_cache_inval_virt_cmd,
476  .mode = COMMAND_ANY,
477  .help = "invalidate l1 d-cache by virtual address offset and range size",
478  .usage = "<virt_addr> [size]",
479  },
480  {
481  .name = "clean",
482  .handler = arm7a_l1_d_cache_clean_virt_cmd,
483  .mode = COMMAND_ANY,
484  .help = "clean l1 d-cache by virtual address address offset and range size",
485  .usage = "<virt_addr> [size]",
486  },
488 };
489 
490 static const struct command_registration arm7a_l1_i_cache_commands[] = {
491  {
492  .name = "inval_all",
493  .handler = armv7a_i_cache_clean_inval_all_cmd,
494  .mode = COMMAND_ANY,
495  .help = "invalidate complete l1 i-cache",
496  .usage = "",
497  },
498  {
499  .name = "inval",
500  .handler = arm7a_l1_i_cache_inval_virt_cmd,
501  .mode = COMMAND_ANY,
502  .help = "invalidate l1 i-cache by virtual address offset and range size",
503  .usage = "<virt_addr> [size]",
504  },
506 };
507 
509  {
510  .name = "info",
511  .handler = arm7a_l1_cache_info_cmd,
512  .mode = COMMAND_ANY,
513  .help = "print cache related information",
514  .usage = "",
515  },
516  {
517  .name = "d",
518  .mode = COMMAND_ANY,
519  .help = "l1 d-cache command group",
520  .usage = "",
521  .chain = arm7a_l1_d_cache_commands,
522  },
523  {
524  .name = "i",
525  .mode = COMMAND_ANY,
526  .help = "l1 i-cache command group",
527  .usage = "",
528  .chain = arm7a_l1_i_cache_commands,
529  },
531 };
532 
533 static const struct command_registration arm7a_cache_group_handlers[] = {
534  {
535  .name = "l1",
536  .mode = COMMAND_ANY,
537  .help = "l1 cache command group",
538  .usage = "",
540  },
541  {
543  },
545 };
546 
548  {
549  .name = "cache",
550  .mode = COMMAND_ANY,
551  .help = "cache command group",
552  .usage = "",
554  },
556 };
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:183
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:249
int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:328
int armv7a_l1_i_cache_inval_all(struct target *target)
Definition: armv7a_cache.c:291
static const struct command_registration arm7a_l1_i_cache_commands[]
Definition: armv7a_cache.c:490
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:120
int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, unsigned int size)
Definition: armv7a_cache.c:207
static const struct command_registration arm7a_l1_di_cache_group_handlers[]
Definition: armv7a_cache.c:508
int armv7a_cache_flush_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:375
static const struct command_registration arm7a_cache_group_handlers[]
Definition: armv7a_cache.c:533
const struct command_registration arm7a_cache_command_handlers[]
Definition: armv7a_cache.c:547
COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
Definition: armv7a_cache.c:384
static const struct command_registration arm7a_l1_d_cache_commands[]
Definition: armv7a_cache.c:465
int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:145
#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:146
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:161
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:405
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:156
#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:445
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:151
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:256
@ COMMAND_ANY
Definition: command.h:42
uint32_t size
Size of dw_spi_transaction::buffer.
Definition: dw-spi-helper.h:4
void keep_alive(void)
Definition: log.c:437
#define ERROR_FAIL
Definition: log.h:188
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:176
#define LOG_ERROR(expr ...)
Definition: log.h:147
#define LOG_DEBUG(expr ...)
Definition: log.h:124
#define ERROR_OK
Definition: log.h:182
#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:214
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
bool i_cache_enabled
Definition: armv7a.h:66
bool d_u_cache_enabled
Definition: armv7a.h:67
uint32_t iminline
Definition: armv7a.h:64
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:239
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:252
struct target * target
Definition: target.h:227
Definition: target.h:119
enum target_state state
Definition: target.h:167
struct list_head * smp_targets
Definition: target.h:201
unsigned int smp
Definition: target.h:200
struct target * get_current_target(struct command_context *cmd_ctx)
Definition: target.c:468
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:817
#define ERROR_TARGET_INVALID
Definition: target.h:814
@ TARGET_HALTED
Definition: target.h:58