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 
156  if (retval != ERROR_OK)
157  return retval;
158 
159  retval = dpm->prepare(dpm);
160  if (retval != ERROR_OK)
161  goto done;
162 
163  va_line = virt & (-linelen);
164  va_end = virt + size;
165 
166  /* handle unaligned start */
167  if (virt != va_line) {
168  /* DCCIMVAC */
169  retval = dpm->instr_write_data_r0(dpm,
170  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
171  if (retval != ERROR_OK)
172  goto done;
173  va_line += linelen;
174  }
175 
176  /* handle unaligned end */
177  if ((va_end & (linelen-1)) != 0) {
178  va_end &= (-linelen);
179  /* DCCIMVAC */
180  retval = dpm->instr_write_data_r0(dpm,
181  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end);
182  if (retval != ERROR_OK)
183  goto done;
184  }
185 
186  while (va_line < va_end) {
187  keep_alive();
188  /* DCIMVAC - Invalidate data cache line by VA to PoC. */
189  retval = dpm->instr_write_data_r0(dpm,
190  ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line);
191  if (retval != ERROR_OK)
192  goto done;
193  va_line += linelen;
194  }
195 
196  keep_alive();
197  dpm->finish(dpm);
198  return retval;
199 
200 done:
201  LOG_ERROR("d-cache invalidate failed");
202  keep_alive();
203  dpm->finish(dpm);
204 
205  return retval;
206 }
207 
208 int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
209  unsigned int size)
210 {
211  struct armv7a_common *armv7a = target_to_armv7a(target);
212  struct arm_dpm *dpm = armv7a->arm.dpm;
213  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
214  uint32_t linelen = armv7a_cache->dminline;
215  uint32_t va_line, va_end;
216 
218  if (retval != ERROR_OK)
219  return retval;
220 
221  retval = dpm->prepare(dpm);
222  if (retval != ERROR_OK)
223  goto done;
224 
225  va_line = virt & (-linelen);
226  va_end = virt + size;
227 
228  while (va_line < va_end) {
229  keep_alive();
230  /* DCCMVAC - Data Cache Clean by MVA to PoC */
231  retval = dpm->instr_write_data_r0(dpm,
232  ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line);
233  if (retval != ERROR_OK)
234  goto done;
235  va_line += linelen;
236  }
237 
238  keep_alive();
239  dpm->finish(dpm);
240  return retval;
241 
242 done:
243  LOG_ERROR("d-cache invalidate failed");
244  keep_alive();
245  dpm->finish(dpm);
246 
247  return retval;
248 }
249 
250 int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
251  unsigned int size)
252 {
253  struct armv7a_common *armv7a = target_to_armv7a(target);
254  struct arm_dpm *dpm = armv7a->arm.dpm;
255  struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache;
256  uint32_t linelen = armv7a_cache->dminline;
257  uint32_t va_line, va_end;
258 
260  if (retval != ERROR_OK)
261  return retval;
262 
263  retval = dpm->prepare(dpm);
264  if (retval != ERROR_OK)
265  goto done;
266 
267  va_line = virt & (-linelen);
268  va_end = virt + size;
269 
270  while (va_line < va_end) {
271  keep_alive();
272  /* DCCIMVAC */
273  retval = dpm->instr_write_data_r0(dpm,
274  ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line);
275  if (retval != ERROR_OK)
276  goto done;
277  va_line += linelen;
278  }
279 
280  keep_alive();
281  dpm->finish(dpm);
282  return retval;
283 
284 done:
285  LOG_ERROR("d-cache invalidate failed");
286  keep_alive();
287  dpm->finish(dpm);
288 
289  return retval;
290 }
291 
293 {
294  struct armv7a_common *armv7a = target_to_armv7a(target);
295  struct arm_dpm *dpm = armv7a->arm.dpm;
296  int retval;
297 
299  if (retval != ERROR_OK)
300  return retval;
301 
302  retval = dpm->prepare(dpm);
303  if (retval != ERROR_OK)
304  goto done;
305 
306  if (target->smp) {
307  /* ICIALLUIS */
308  retval = dpm->instr_write_data_r0(dpm,
309  ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0);
310  } else {
311  /* ICIALLU */
312  retval = dpm->instr_write_data_r0(dpm,
313  ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0);
314  }
315 
316  if (retval != ERROR_OK)
317  goto done;
318 
319  dpm->finish(dpm);
320  return retval;
321 
322 done:
323  LOG_ERROR("i-cache invalidate failed");
324  dpm->finish(dpm);
325 
326  return retval;
327 }
328 
329 int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt,
330  uint32_t size)
331 {
332  struct armv7a_common *armv7a = target_to_armv7a(target);
333  struct arm_dpm *dpm = armv7a->arm.dpm;
334  struct armv7a_cache_common *armv7a_cache =
335  &armv7a->armv7a_mmu.armv7a_cache;
336  uint32_t linelen = armv7a_cache->iminline;
337  uint32_t va_line, va_end;
338 
340  if (retval != ERROR_OK)
341  return retval;
342 
343  retval = dpm->prepare(dpm);
344  if (retval != ERROR_OK)
345  goto done;
346 
347  va_line = virt & (-linelen);
348  va_end = virt + size;
349 
350  while (va_line < va_end) {
351  keep_alive();
352  /* ICIMVAU - Invalidate instruction cache by VA to PoU. */
353  retval = dpm->instr_write_data_r0(dpm,
354  ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line);
355  if (retval != ERROR_OK)
356  goto done;
357  /* BPIMVA */
358  retval = dpm->instr_write_data_r0(dpm,
359  ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line);
360  if (retval != ERROR_OK)
361  goto done;
362  va_line += linelen;
363  }
364  keep_alive();
365  dpm->finish(dpm);
366  return retval;
367 
368 done:
369  LOG_ERROR("i-cache invalidate failed");
370  keep_alive();
371  dpm->finish(dpm);
372 
373  return retval;
374 }
375 
376 int armv7a_cache_flush_virt(struct target *target, uint32_t virt,
377  uint32_t size)
378 {
381 
382  return ERROR_OK;
383 }
384 
385 COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
386 {
388  struct armv7a_common *armv7a = target_to_armv7a(target);
389 
391  &armv7a->armv7a_mmu.armv7a_cache);
392 }
393 
394 COMMAND_HANDLER(armv7a_l1_d_cache_clean_inval_all_cmd)
395 {
397 
399 
400  return 0;
401 }
402 
403 COMMAND_HANDLER(arm7a_l1_d_cache_inval_virt_cmd)
404 {
406  uint32_t virt, size;
407 
408  if (CMD_ARGC == 0 || CMD_ARGC > 2)
410 
411  if (CMD_ARGC == 2)
413  else
414  size = 1;
415 
416  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
417 
419 }
420 
421 COMMAND_HANDLER(arm7a_l1_d_cache_clean_virt_cmd)
422 {
424  uint32_t virt, size;
425 
426  if (CMD_ARGC == 0 || CMD_ARGC > 2)
428 
429  if (CMD_ARGC == 2)
431  else
432  size = 1;
433 
434  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
435 
437 }
438 
439 COMMAND_HANDLER(armv7a_i_cache_clean_inval_all_cmd)
440 {
442 
444 
445  return 0;
446 }
447 
448 COMMAND_HANDLER(arm7a_l1_i_cache_inval_virt_cmd)
449 {
451  uint32_t virt, size;
452 
453  if (CMD_ARGC == 0 || CMD_ARGC > 2)
455 
456  if (CMD_ARGC == 2)
458  else
459  size = 1;
460 
461  COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], virt);
462 
464 }
465 
466 static const struct command_registration arm7a_l1_d_cache_commands[] = {
467  {
468  .name = "flush_all",
469  .handler = armv7a_l1_d_cache_clean_inval_all_cmd,
470  .mode = COMMAND_ANY,
471  .help = "flush (clean and invalidate) complete l1 d-cache",
472  .usage = "",
473  },
474  {
475  .name = "inval",
476  .handler = arm7a_l1_d_cache_inval_virt_cmd,
477  .mode = COMMAND_ANY,
478  .help = "invalidate l1 d-cache by virtual address offset and range size",
479  .usage = "<virt_addr> [size]",
480  },
481  {
482  .name = "clean",
483  .handler = arm7a_l1_d_cache_clean_virt_cmd,
484  .mode = COMMAND_ANY,
485  .help = "clean l1 d-cache by virtual address address offset and range size",
486  .usage = "<virt_addr> [size]",
487  },
489 };
490 
491 static const struct command_registration arm7a_l1_i_cache_commands[] = {
492  {
493  .name = "inval_all",
494  .handler = armv7a_i_cache_clean_inval_all_cmd,
495  .mode = COMMAND_ANY,
496  .help = "invalidate complete l1 i-cache",
497  .usage = "",
498  },
499  {
500  .name = "inval",
501  .handler = arm7a_l1_i_cache_inval_virt_cmd,
502  .mode = COMMAND_ANY,
503  .help = "invalidate l1 i-cache by virtual address offset and range size",
504  .usage = "<virt_addr> [size]",
505  },
507 };
508 
510  {
511  .name = "info",
512  .handler = arm7a_l1_cache_info_cmd,
513  .mode = COMMAND_ANY,
514  .help = "print cache related information",
515  .usage = "",
516  },
517  {
518  .name = "d",
519  .mode = COMMAND_ANY,
520  .help = "l1 d-cache command group",
521  .usage = "",
522  .chain = arm7a_l1_d_cache_commands,
523  },
524  {
525  .name = "i",
526  .mode = COMMAND_ANY,
527  .help = "l1 i-cache command group",
528  .usage = "",
529  .chain = arm7a_l1_i_cache_commands,
530  },
532 };
533 
534 static const struct command_registration arm7a_cache_group_handlers[] = {
535  {
536  .name = "l1",
537  .mode = COMMAND_ANY,
538  .help = "l1 cache command group",
539  .usage = "",
541  },
542  {
544  },
546 };
547 
549  {
550  .name = "cache",
551  .mode = COMMAND_ANY,
552  .help = "cache command group",
553  .usage = "",
555  },
557 };
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:250
int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:329
int armv7a_l1_i_cache_inval_all(struct target *target)
Definition: armv7a_cache.c:292
static const struct command_registration arm7a_l1_i_cache_commands[]
Definition: armv7a_cache.c:491
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:208
static const struct command_registration arm7a_l1_di_cache_group_handlers[]
Definition: armv7a_cache.c:509
int armv7a_cache_flush_virt(struct target *target, uint32_t virt, uint32_t size)
Definition: armv7a_cache.c:376
static const struct command_registration arm7a_cache_group_handlers[]
Definition: armv7a_cache.c:534
const struct command_registration arm7a_cache_command_handlers[]
Definition: armv7a_cache.c:548
COMMAND_HANDLER(arm7a_l1_cache_info_cmd)
Definition: armv7a_cache.c:385
static const struct command_registration arm7a_l1_d_cache_commands[]
Definition: armv7a_cache.c:466
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:400
#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:440
#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:251
@ 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:427
#define ERROR_FAIL
Definition: log.h:174
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:162
#define LOG_ERROR(expr ...)
Definition: log.h:133
#define LOG_DEBUG(expr ...)
Definition: log.h:110
#define ERROR_OK
Definition: log.h:168
#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
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:234
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:247
struct target * target
Definition: target.h:217
Definition: target.h:119
enum target_state state
Definition: target.h:160
struct list_head * smp_targets
Definition: target.h:191
unsigned int smp
Definition: target.h:190
struct target * get_current_target(struct command_context *cmd_ctx)
Definition: target.c:467
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:786
#define ERROR_TARGET_INVALID
Definition: target.h:783
@ TARGET_HALTED
Definition: target.h:58