target: clarify usage of `coreid`
[openocd.git] / src / target / armv8_cache.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2016 by Matthias Welwarsky *
5 * matthias.welwarsky@sysgo.com *
6 ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "armv8_cache.h"
13 #include "armv8_dpm.h"
14 #include "armv8_opcodes.h"
15 #include "smp.h"
16
17 /* CLIDR cache types */
18 #define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4
19 #define CACHE_LEVEL_HAS_D_CACHE 0x2
20 #define CACHE_LEVEL_HAS_I_CACHE 0x1
21
22 static int armv8_d_cache_sanity_check(struct armv8_common *armv8)
23 {
24 struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
25
26 if (armv8_cache->d_u_cache_enabled)
27 return ERROR_OK;
28
29 return ERROR_TARGET_INVALID;
30 }
31
32 static int armv8_i_cache_sanity_check(struct armv8_common *armv8)
33 {
34 struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
35
36 if (armv8_cache->i_cache_enabled)
37 return ERROR_OK;
38
39 return ERROR_TARGET_INVALID;
40 }
41
42 static int armv8_cache_d_inner_flush_level(struct armv8_common *armv8, struct armv8_cachesize *size, int cl)
43 {
44 struct arm_dpm *dpm = armv8->arm.dpm;
45 int retval = ERROR_OK;
46 int32_t c_way, c_index = size->index;
47
48 LOG_DEBUG("cl %" PRId32, cl);
49 do {
50 c_way = size->way;
51 do {
52 uint32_t value = (c_index << size->index_shift)
53 | (c_way << size->way_shift) | (cl << 1);
54 /*
55 * DC CISW - Clean and invalidate data cache
56 * line by Set/Way.
57 */
58 retval = dpm->instr_write_data_r0(dpm,
59 armv8_opcode(armv8, ARMV8_OPC_DCCISW), value);
60 if (retval != ERROR_OK)
61 goto done;
62 c_way -= 1;
63 } while (c_way >= 0);
64 c_index -= 1;
65 } while (c_index >= 0);
66
67 done:
68 return retval;
69 }
70
71 static int armv8_cache_d_inner_clean_inval_all(struct armv8_common *armv8)
72 {
73 struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache);
74 struct arm_dpm *dpm = armv8->arm.dpm;
75 int cl;
76 int retval;
77
78 retval = armv8_d_cache_sanity_check(armv8);
79 if (retval != ERROR_OK)
80 return retval;
81
82 retval = dpm->prepare(dpm);
83 if (retval != ERROR_OK)
84 goto done;
85
86 for (cl = 0; cl < cache->loc; cl++) {
87 /* skip i-only caches */
88 if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE)
89 continue;
90
91 armv8_cache_d_inner_flush_level(armv8, &cache->arch[cl].d_u_size, cl);
92 }
93
94 retval = dpm->finish(dpm);
95 return retval;
96
97 done:
98 LOG_ERROR("clean invalidate failed");
99 dpm->finish(dpm);
100
101 return retval;
102 }
103
104 int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size)
105 {
106 struct arm_dpm *dpm = armv8->arm.dpm;
107 struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
108 uint64_t linelen = armv8_cache->dminline;
109 target_addr_t va_line, va_end;
110 int retval;
111
112 retval = armv8_d_cache_sanity_check(armv8);
113 if (retval != ERROR_OK)
114 return retval;
115
116 retval = dpm->prepare(dpm);
117 if (retval != ERROR_OK)
118 goto done;
119
120 va_line = va & (-linelen);
121 va_end = va + size;
122
123 while (va_line < va_end) {
124 /* DC CIVAC */
125 /* Aarch32: DCCIMVAC: ARMV4_5_MCR(15, 0, 0, 7, 14, 1) */
126 retval = dpm->instr_write_data_r0_64(dpm,
127 armv8_opcode(armv8, ARMV8_OPC_DCCIVAC), va_line);
128 if (retval != ERROR_OK)
129 goto done;
130 va_line += linelen;
131 }
132
133 dpm->finish(dpm);
134 return retval;
135
136 done:
137 LOG_ERROR("d-cache invalidate failed");
138 dpm->finish(dpm);
139
140 return retval;
141 }
142
143 int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size)
144 {
145 struct arm_dpm *dpm = armv8->arm.dpm;
146 struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache;
147 uint64_t linelen = armv8_cache->iminline;
148 target_addr_t va_line, va_end;
149 int retval;
150
151 retval = armv8_i_cache_sanity_check(armv8);
152 if (retval != ERROR_OK)
153 return retval;
154
155 retval = dpm->prepare(dpm);
156 if (retval != ERROR_OK)
157 goto done;
158
159 va_line = va & (-linelen);
160 va_end = va + size;
161
162 while (va_line < va_end) {
163 /* IC IVAU - Invalidate instruction cache by VA to PoU. */
164 retval = dpm->instr_write_data_r0_64(dpm,
165 armv8_opcode(armv8, ARMV8_OPC_ICIVAU), va_line);
166 if (retval != ERROR_OK)
167 goto done;
168 va_line += linelen;
169 }
170
171 dpm->finish(dpm);
172 return retval;
173
174 done:
175 LOG_ERROR("d-cache invalidate failed");
176 dpm->finish(dpm);
177
178 return retval;
179 }
180
181 static int armv8_handle_inner_cache_info_command(struct command_invocation *cmd,
182 struct armv8_cache_common *armv8_cache)
183 {
184 int cl;
185
186 if (armv8_cache->info == -1) {
187 command_print(cmd, "cache not yet identified");
188 return ERROR_OK;
189 }
190
191 for (cl = 0; cl < armv8_cache->loc; cl++) {
192 struct armv8_arch_cache *arch = &(armv8_cache->arch[cl]);
193
194 if (arch->ctype & 1) {
195 command_print(cmd,
196 "L%d I-Cache: linelen %" PRIu32
197 ", associativity %" PRIu32
198 ", nsets %" PRIu32
199 ", cachesize %" PRIu32 " KBytes",
200 cl+1,
201 arch->i_size.linelen,
202 arch->i_size.associativity,
203 arch->i_size.nsets,
204 arch->i_size.cachesize);
205 }
206
207 if (arch->ctype >= 2) {
208 command_print(cmd,
209 "L%d D-Cache: linelen %" PRIu32
210 ", associativity %" PRIu32
211 ", nsets %" PRIu32
212 ", cachesize %" PRIu32 " KBytes",
213 cl+1,
214 arch->d_u_size.linelen,
215 arch->d_u_size.associativity,
216 arch->d_u_size.nsets,
217 arch->d_u_size.cachesize);
218 }
219 }
220
221 return ERROR_OK;
222 }
223
224 static int _armv8_flush_all_data(struct target *target)
225 {
226 return armv8_cache_d_inner_clean_inval_all(target_to_armv8(target));
227 }
228
229 static int armv8_flush_all_data(struct target *target)
230 {
231 int retval = ERROR_FAIL;
232 /* check that armv8_cache is correctly identify */
233 struct armv8_common *armv8 = target_to_armv8(target);
234 if (armv8->armv8_mmu.armv8_cache.info == -1) {
235 LOG_ERROR("trying to flush un-identified cache");
236 return retval;
237 }
238
239 if (target->smp) {
240 /* look if all the other target have been flushed in order to flush level
241 * 2 */
242 struct target_list *head;
243 foreach_smp_target(head, target->smp_targets) {
244 struct target *curr = head->target;
245 if (curr->state == TARGET_HALTED) {
246 LOG_TARGET_INFO(curr, "Wait flushing data l1.");
247 retval = _armv8_flush_all_data(curr);
248 }
249 }
250 } else
251 retval = _armv8_flush_all_data(target);
252 return retval;
253 }
254
255 static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg)
256 {
257 struct armv8_common *armv8 = dpm->arm->arch_info;
258 int retval = ERROR_OK;
259
260 /* select cache level */
261 retval = dpm->instr_write_data_r0(dpm,
262 armv8_opcode(armv8, WRITE_REG_CSSELR),
263 (cl << 1) | (ct == 1 ? 1 : 0));
264 if (retval != ERROR_OK)
265 goto done;
266
267 retval = dpm->instr_read_data_r0(dpm,
268 armv8_opcode(armv8, READ_REG_CCSIDR),
269 cache_reg);
270 done:
271 return retval;
272 }
273
274 static struct armv8_cachesize decode_cache_reg(uint32_t cache_reg)
275 {
276 struct armv8_cachesize size;
277 int i = 0;
278
279 size.linelen = 16 << (cache_reg & 0x7);
280 size.associativity = ((cache_reg >> 3) & 0x3ff) + 1;
281 size.nsets = ((cache_reg >> 13) & 0x7fff) + 1;
282 size.cachesize = size.linelen * size.associativity * size.nsets / 1024;
283
284 /* compute info for set way operation on cache */
285 size.index_shift = (cache_reg & 0x7) + 4;
286 size.index = (cache_reg >> 13) & 0x7fff;
287 size.way = ((cache_reg >> 3) & 0x3ff);
288
289 if (size.way != 0)
290 while (((size.way << i) & 0x80000000) == 0)
291 i++;
292 size.way_shift = i;
293
294 return size;
295 }
296
297 int armv8_identify_cache(struct armv8_common *armv8)
298 {
299 /* read cache descriptor */
300 int retval = ERROR_FAIL;
301 struct arm *arm = &armv8->arm;
302 struct arm_dpm *dpm = armv8->arm.dpm;
303 uint32_t csselr, clidr, ctr;
304 uint32_t cache_reg;
305 int cl, ctype;
306 struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache);
307
308 retval = dpm->prepare(dpm);
309 if (retval != ERROR_OK)
310 goto done;
311
312 /* check if we're in an unprivileged mode */
313 if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) {
314 retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
315 if (retval != ERROR_OK)
316 return retval;
317 }
318
319 /* retrieve CTR */
320 retval = dpm->instr_read_data_r0(dpm,
321 armv8_opcode(armv8, READ_REG_CTR), &ctr);
322 if (retval != ERROR_OK)
323 goto done;
324
325 cache->iminline = 4UL << (ctr & 0xf);
326 cache->dminline = 4UL << ((ctr & 0xf0000) >> 16);
327 LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32,
328 ctr, cache->iminline, cache->dminline);
329
330 /* retrieve CLIDR */
331 retval = dpm->instr_read_data_r0(dpm,
332 armv8_opcode(armv8, READ_REG_CLIDR), &clidr);
333 if (retval != ERROR_OK)
334 goto done;
335
336 cache->loc = (clidr & 0x7000000) >> 24;
337 LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc);
338
339 /* retrieve selected cache for later restore
340 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
341 retval = dpm->instr_read_data_r0(dpm,
342 armv8_opcode(armv8, READ_REG_CSSELR), &csselr);
343 if (retval != ERROR_OK)
344 goto done;
345
346 /* retrieve all available inner caches */
347 for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) {
348
349 /* isolate cache type at current level */
350 ctype = clidr & 7;
351
352 /* skip reserved values */
353 if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE)
354 continue;
355
356 /* separate d or unified d/i cache at this level ? */
357 if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) {
358 /* retrieve d-cache info */
359 retval = get_cache_info(dpm, cl, 0, &cache_reg);
360 if (retval != ERROR_OK)
361 goto done;
362 cache->arch[cl].d_u_size = decode_cache_reg(cache_reg);
363
364 LOG_DEBUG("data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
365 cache->arch[cl].d_u_size.index,
366 cache->arch[cl].d_u_size.index_shift,
367 cache->arch[cl].d_u_size.way,
368 cache->arch[cl].d_u_size.way_shift);
369
370 LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
371 cache->arch[cl].d_u_size.linelen,
372 cache->arch[cl].d_u_size.cachesize,
373 cache->arch[cl].d_u_size.associativity);
374 }
375
376 /* separate i-cache at this level ? */
377 if (ctype & CACHE_LEVEL_HAS_I_CACHE) {
378 /* retrieve i-cache info */
379 retval = get_cache_info(dpm, cl, 1, &cache_reg);
380 if (retval != ERROR_OK)
381 goto done;
382 cache->arch[cl].i_size = decode_cache_reg(cache_reg);
383
384 LOG_DEBUG("instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
385 cache->arch[cl].i_size.index,
386 cache->arch[cl].i_size.index_shift,
387 cache->arch[cl].i_size.way,
388 cache->arch[cl].i_size.way_shift);
389
390 LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
391 cache->arch[cl].i_size.linelen,
392 cache->arch[cl].i_size.cachesize,
393 cache->arch[cl].i_size.associativity);
394 }
395
396 cache->arch[cl].ctype = ctype;
397 }
398
399 /* restore selected cache */
400 dpm->instr_write_data_r0(dpm,
401 armv8_opcode(armv8, WRITE_REG_CSSELR), csselr);
402 if (retval != ERROR_OK)
403 goto done;
404
405 armv8->armv8_mmu.armv8_cache.info = 1;
406
407 /* if no l2 cache initialize l1 data cache flush function function */
408 if (!armv8->armv8_mmu.armv8_cache.flush_all_data_cache) {
409 armv8->armv8_mmu.armv8_cache.display_cache_info =
410 armv8_handle_inner_cache_info_command;
411 armv8->armv8_mmu.armv8_cache.flush_all_data_cache =
412 armv8_flush_all_data;
413 }
414
415 done:
416 armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
417 dpm->finish(dpm);
418 return retval;
419
420 }

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)