armv7a: re-read ttb information if ttbcr changes
[openocd.git] / src / target / armv7a.c
1 /***************************************************************************
2 * Copyright (C) 2009 by David Brownell *
3 * *
4 * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
20 ***************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <helper/replacements.h>
27
28 #include "armv7a.h"
29 #include "arm_disassembler.h"
30
31 #include "register.h"
32 #include <helper/binarybuffer.h>
33 #include <helper/command.h>
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include "arm_opcodes.h"
40 #include "target.h"
41 #include "target_type.h"
42
43 static void armv7a_show_fault_registers(struct target *target)
44 {
45 uint32_t dfsr, ifsr, dfar, ifar;
46 struct armv7a_common *armv7a = target_to_armv7a(target);
47 struct arm_dpm *dpm = armv7a->arm.dpm;
48 int retval;
49
50 retval = dpm->prepare(dpm);
51 if (retval != ERROR_OK)
52 return;
53
54 /* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */
55
56 /* c5/c0 - {data, instruction} fault status registers */
57 retval = dpm->instr_read_data_r0(dpm,
58 ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
59 &dfsr);
60 if (retval != ERROR_OK)
61 goto done;
62
63 retval = dpm->instr_read_data_r0(dpm,
64 ARMV4_5_MRC(15, 0, 0, 5, 0, 1),
65 &ifsr);
66 if (retval != ERROR_OK)
67 goto done;
68
69 /* c6/c0 - {data, instruction} fault address registers */
70 retval = dpm->instr_read_data_r0(dpm,
71 ARMV4_5_MRC(15, 0, 0, 6, 0, 0),
72 &dfar);
73 if (retval != ERROR_OK)
74 goto done;
75
76 retval = dpm->instr_read_data_r0(dpm,
77 ARMV4_5_MRC(15, 0, 0, 6, 0, 2),
78 &ifar);
79 if (retval != ERROR_OK)
80 goto done;
81
82 LOG_USER("Data fault registers DFSR: %8.8" PRIx32
83 ", DFAR: %8.8" PRIx32, dfsr, dfar);
84 LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
85 ", IFAR: %8.8" PRIx32, ifsr, ifar);
86
87 done:
88 /* (void) */ dpm->finish(dpm);
89 }
90
91
92 /* retrieve main id register */
93 static int armv7a_read_midr(struct target *target)
94 {
95 int retval = ERROR_FAIL;
96 struct armv7a_common *armv7a = target_to_armv7a(target);
97 struct arm_dpm *dpm = armv7a->arm.dpm;
98 uint32_t midr;
99 retval = dpm->prepare(dpm);
100 if (retval != ERROR_OK)
101 goto done;
102 /* MRC p15,0,<Rd>,c0,c0,0; read main id register*/
103
104 retval = dpm->instr_read_data_r0(dpm,
105 ARMV4_5_MRC(15, 0, 0, 0, 0, 0),
106 &midr);
107 if (retval != ERROR_OK)
108 goto done;
109
110 armv7a->rev = (midr & 0xf);
111 armv7a->partnum = (midr >> 4) & 0xfff;
112 armv7a->arch = (midr >> 16) & 0xf;
113 armv7a->variant = (midr >> 20) & 0xf;
114 armv7a->implementor = (midr >> 24) & 0xff;
115 LOG_INFO("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32
116 ", variant %" PRIx32 ", implementor %" PRIx32,
117 target->cmd_name,
118 armv7a->rev,
119 armv7a->partnum,
120 armv7a->arch,
121 armv7a->variant,
122 armv7a->implementor);
123
124 done:
125 dpm->finish(dpm);
126 return retval;
127 }
128
129 static int armv7a_read_ttbcr(struct target *target)
130 {
131 struct armv7a_common *armv7a = target_to_armv7a(target);
132 struct arm_dpm *dpm = armv7a->arm.dpm;
133 uint32_t ttbcr;
134 uint32_t ttbr0, ttbr1;
135 int retval = dpm->prepare(dpm);
136 if (retval != ERROR_OK)
137 goto done;
138 /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
139 retval = dpm->instr_read_data_r0(dpm,
140 ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
141 &ttbcr);
142 if (retval != ERROR_OK)
143 goto done;
144
145 retval = dpm->instr_read_data_r0(dpm,
146 ARMV4_5_MRC(15, 0, 0, 2, 0, 0),
147 &ttbr0);
148 if (retval != ERROR_OK)
149 goto done;
150
151 retval = dpm->instr_read_data_r0(dpm,
152 ARMV4_5_MRC(15, 0, 0, 2, 0, 1),
153 &ttbr1);
154 if (retval != ERROR_OK)
155 goto done;
156
157 LOG_INFO("ttbcr %" PRIx32 " ttbr0 %" PRIx32 " ttbr1 %" PRIx32, ttbcr, ttbr0, ttbr1);
158
159 armv7a->armv7a_mmu.ttbr1_used = ((ttbcr & 0x7) != 0) ? 1 : 0;
160 armv7a->armv7a_mmu.ttbr0_mask = 0;
161 armv7a->armv7a_mmu.ttbcr = ttbcr;
162
163 retval = armv7a_read_midr(target);
164 if (retval != ERROR_OK)
165 goto done;
166
167 if (armv7a->partnum & 0xf) {
168 /*
169 * ARM Architecture Reference Manual (ARMv7-A and ARMv7-Redition),
170 * document # ARM DDI 0406C
171 */
172 armv7a->armv7a_mmu.ttbr0_mask = 1 << (14 - ((ttbcr & 0x7)));
173 } else {
174 /* ARM DDI 0344H , ARM DDI 0407F */
175 armv7a->armv7a_mmu.ttbr0_mask = 7 << (32 - ((ttbcr & 0x7)));
176 /* fix me , default is hard coded LINUX border */
177 armv7a->armv7a_mmu.os_border = 0xc0000000;
178 }
179
180 LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32,
181 armv7a->armv7a_mmu.ttbr1_used ? "used" : "not used",
182 armv7a->armv7a_mmu.ttbr0_mask);
183
184 if (armv7a->armv7a_mmu.ttbr1_used == 1) {
185 LOG_INFO("SVC access above %" PRIx32,
186 (0xffffffff & armv7a->armv7a_mmu.ttbr0_mask));
187 armv7a->armv7a_mmu.os_border = 0xffffffff & armv7a->armv7a_mmu.ttbr0_mask;
188 }
189 done:
190 dpm->finish(dpm);
191 return retval;
192 }
193
194 /* method adapted to cortex A : reused arm v4 v5 method*/
195 int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
196 {
197 uint32_t first_lvl_descriptor = 0x0;
198 uint32_t second_lvl_descriptor = 0x0;
199 int retval;
200 struct armv7a_common *armv7a = target_to_armv7a(target);
201 struct arm_dpm *dpm = armv7a->arm.dpm;
202 uint32_t ttb = 0; /* default ttb0 */
203 uint32_t ttbcr;
204
205 retval = dpm->prepare(dpm);
206 if (retval != ERROR_OK)
207 goto done;
208
209 /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
210 retval = dpm->instr_read_data_r0(dpm,
211 ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
212 &ttbcr);
213 if (retval != ERROR_OK)
214 goto done;
215
216 /* if ttbcr has changed, re-read the information */
217 if (armv7a->armv7a_mmu.ttbcr != ttbcr)
218 armv7a_read_ttbcr(target);
219 if ((armv7a->armv7a_mmu.ttbr1_used) &&
220 (va > (0xffffffff & armv7a->armv7a_mmu.ttbr0_mask))) {
221 /* select ttb 1 */
222 ttb = 1;
223 }
224 /* MRC p15,0,<Rt>,c2,c0,ttb */
225 retval = dpm->instr_read_data_r0(dpm,
226 ARMV4_5_MRC(15, 0, 0, 2, 0, ttb),
227 &ttb);
228 if (retval != ERROR_OK)
229 return retval;
230 retval = armv7a->armv7a_mmu.read_physical_memory(target,
231 (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
232 4, 1, (uint8_t *)&first_lvl_descriptor);
233 if (retval != ERROR_OK)
234 return retval;
235 first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
236 &first_lvl_descriptor);
237 /* reuse armv4_5 piece of code, specific armv7a changes may come later */
238 LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
239
240 if ((first_lvl_descriptor & 0x3) == 0) {
241 LOG_ERROR("Address translation failure");
242 return ERROR_TARGET_TRANSLATION_FAULT;
243 }
244
245
246 if ((first_lvl_descriptor & 0x40002) == 2) {
247 /* section descriptor */
248 *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
249 return ERROR_OK;
250 } else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
251 /* supersection descriptor */
252 if (first_lvl_descriptor & 0x00f001e0) {
253 LOG_ERROR("Physical address does not fit into 32 bits");
254 return ERROR_TARGET_TRANSLATION_FAULT;
255 }
256 *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff);
257 return ERROR_OK;
258 }
259
260 /* page table */
261 retval = armv7a->armv7a_mmu.read_physical_memory(target,
262 (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
263 4, 1, (uint8_t *)&second_lvl_descriptor);
264 if (retval != ERROR_OK)
265 return retval;
266
267 second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
268 &second_lvl_descriptor);
269
270 LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
271
272 if ((second_lvl_descriptor & 0x3) == 0) {
273 LOG_ERROR("Address translation failure");
274 return ERROR_TARGET_TRANSLATION_FAULT;
275 }
276
277 if ((second_lvl_descriptor & 0x3) == 1) {
278 /* large page descriptor */
279 *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
280 } else {
281 /* small page descriptor */
282 *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
283 }
284
285 return ERROR_OK;
286
287 done:
288 return retval;
289 }
290
291 /* V7 method VA TO PA */
292 int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
293 uint32_t *val, int meminfo)
294 {
295 int retval = ERROR_FAIL;
296 struct armv7a_common *armv7a = target_to_armv7a(target);
297 struct arm_dpm *dpm = armv7a->arm.dpm;
298 uint32_t virt = va & ~0xfff;
299 uint32_t NOS, NS, INNER, OUTER;
300 *val = 0xdeadbeef;
301 retval = dpm->prepare(dpm);
302 if (retval != ERROR_OK)
303 goto done;
304 /* mmu must be enable in order to get a correct translation
305 * use VA to PA CP15 register for conversion */
306 retval = dpm->instr_write_data_r0(dpm,
307 ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
308 virt);
309 if (retval != ERROR_OK)
310 goto done;
311 retval = dpm->instr_read_data_r0(dpm,
312 ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
313 val);
314 /* decode memory attribute */
315 NOS = (*val >> 10) & 1; /* Not Outer shareable */
316 NS = (*val >> 9) & 1; /* Non secure */
317 INNER = (*val >> 4) & 0x7;
318 OUTER = (*val >> 2) & 0x3;
319
320 if (retval != ERROR_OK)
321 goto done;
322 *val = (*val & ~0xfff) + (va & 0xfff);
323 if (*val == va)
324 LOG_WARNING("virt = phys : MMU disable !!");
325 if (meminfo) {
326 LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured",
327 va, *val,
328 NOS == 1 ? "not" : " ",
329 NS == 1 ? "not" : "");
330 switch (OUTER) {
331 case 0:
332 LOG_INFO("outer: Non-Cacheable");
333 break;
334 case 1:
335 LOG_INFO("outer: Write-Back, Write-Allocate");
336 break;
337 case 2:
338 LOG_INFO("outer: Write-Through, No Write-Allocate");
339 break;
340 case 3:
341 LOG_INFO("outer: Write-Back, no Write-Allocate");
342 break;
343 }
344 switch (INNER) {
345 case 0:
346 LOG_INFO("inner: Non-Cacheable");
347 break;
348 case 1:
349 LOG_INFO("inner: Strongly-ordered");
350 break;
351 case 3:
352 LOG_INFO("inner: Device");
353 break;
354 case 5:
355 LOG_INFO("inner: Write-Back, Write-Allocate");
356 break;
357 case 6:
358 LOG_INFO("inner: Write-Through");
359 break;
360 case 7:
361 LOG_INFO("inner: Write-Back, no Write-Allocate");
362
363 default:
364 LOG_INFO("inner: %" PRIx32 " ???", INNER);
365 }
366 }
367
368 done:
369 dpm->finish(dpm);
370
371 return retval;
372 }
373
374 static int armv7a_handle_inner_cache_info_command(struct command_context *cmd_ctx,
375 struct armv7a_cache_common *armv7a_cache)
376 {
377 if (armv7a_cache->ctype == -1) {
378 command_print(cmd_ctx, "cache not yet identified");
379 return ERROR_OK;
380 }
381
382 command_print(cmd_ctx,
383 "D-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes",
384 armv7a_cache->d_u_size.linelen,
385 armv7a_cache->d_u_size.associativity,
386 armv7a_cache->d_u_size.nsets,
387 armv7a_cache->d_u_size.cachesize);
388
389 command_print(cmd_ctx,
390 "I-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes",
391 armv7a_cache->i_size.linelen,
392 armv7a_cache->i_size.associativity,
393 armv7a_cache->i_size.nsets,
394 armv7a_cache->i_size.cachesize);
395
396 return ERROR_OK;
397 }
398
399 static int _armv7a_flush_all_data(struct target *target)
400 {
401 struct armv7a_common *armv7a = target_to_armv7a(target);
402 struct arm_dpm *dpm = armv7a->arm.dpm;
403 struct armv7a_cachesize *d_u_size =
404 &(armv7a->armv7a_mmu.armv7a_cache.d_u_size);
405 int32_t c_way, c_index = d_u_size->index;
406 int retval;
407 /* check that cache data is on at target halt */
408 if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
409 LOG_INFO("flushed not performed :cache not on at target halt");
410 return ERROR_OK;
411 }
412 retval = dpm->prepare(dpm);
413 if (retval != ERROR_OK)
414 goto done;
415 do {
416 c_way = d_u_size->way;
417 do {
418 uint32_t value = (c_index << d_u_size->index_shift)
419 | (c_way << d_u_size->way_shift);
420 /* DCCISW */
421 /* LOG_INFO ("%d %d %x",c_way,c_index,value); */
422 retval = dpm->instr_write_data_r0(dpm,
423 ARMV4_5_MCR(15, 0, 0, 7, 14, 2),
424 value);
425 if (retval != ERROR_OK)
426 goto done;
427 c_way -= 1;
428 } while (c_way >= 0);
429 c_index -= 1;
430 } while (c_index >= 0);
431 return retval;
432 done:
433 LOG_ERROR("flushed failed");
434 dpm->finish(dpm);
435 return retval;
436 }
437
438 static int armv7a_flush_all_data(struct target *target)
439 {
440 int retval = ERROR_FAIL;
441 /* check that armv7a_cache is correctly identify */
442 struct armv7a_common *armv7a = target_to_armv7a(target);
443 if (armv7a->armv7a_mmu.armv7a_cache.ctype == -1) {
444 LOG_ERROR("trying to flush un-identified cache");
445 return retval;
446 }
447
448 if (target->smp) {
449 /* look if all the other target have been flushed in order to flush level
450 * 2 */
451 struct target_list *head;
452 struct target *curr;
453 head = target->head;
454 while (head != (struct target_list *)NULL) {
455 curr = head->target;
456 if (curr->state == TARGET_HALTED) {
457 LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid);
458 retval = _armv7a_flush_all_data(curr);
459 }
460 head = head->next;
461 }
462 } else
463 retval = _armv7a_flush_all_data(target);
464 return retval;
465 }
466
467 /* L2 is not specific to armv7a a specific file is needed */
468 static int armv7a_l2x_flush_all_data(struct target *target)
469 {
470
471 #define L2X0_CLEAN_INV_WAY 0x7FC
472 int retval = ERROR_FAIL;
473 struct armv7a_common *armv7a = target_to_armv7a(target);
474 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
475 (armv7a->armv7a_mmu.armv7a_cache.l2_cache);
476 uint32_t base = l2x_cache->base;
477 uint32_t l2_way = l2x_cache->way;
478 uint32_t l2_way_val = (1 << l2_way) - 1;
479 retval = armv7a_flush_all_data(target);
480 if (retval != ERROR_OK)
481 return retval;
482 retval = target->type->write_phys_memory(target,
483 (uint32_t)(base+(uint32_t)L2X0_CLEAN_INV_WAY),
484 (uint32_t)4,
485 (uint32_t)1,
486 (uint8_t *)&l2_way_val);
487 return retval;
488 }
489
490 static int armv7a_handle_l2x_cache_info_command(struct command_context *cmd_ctx,
491 struct armv7a_cache_common *armv7a_cache)
492 {
493
494 struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *)
495 (armv7a_cache->l2_cache);
496
497 if (armv7a_cache->ctype == -1) {
498 command_print(cmd_ctx, "cache not yet identified");
499 return ERROR_OK;
500 }
501
502 command_print(cmd_ctx,
503 "L1 D-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes",
504 armv7a_cache->d_u_size.linelen,
505 armv7a_cache->d_u_size.associativity,
506 armv7a_cache->d_u_size.nsets,
507 armv7a_cache->d_u_size.cachesize);
508
509 command_print(cmd_ctx,
510 "L1 I-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes",
511 armv7a_cache->i_size.linelen,
512 armv7a_cache->i_size.associativity,
513 armv7a_cache->i_size.nsets,
514 armv7a_cache->i_size.cachesize);
515 command_print(cmd_ctx, "L2 unified cache Base Address 0x%" PRIx32 ", %" PRId32 " ways",
516 l2x_cache->base, l2x_cache->way);
517
518
519 return ERROR_OK;
520 }
521
522
523 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
524 {
525 struct armv7a_l2x_cache *l2x_cache;
526 struct target_list *head = target->head;
527 struct target *curr;
528
529 struct armv7a_common *armv7a = target_to_armv7a(target);
530 l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache));
531 l2x_cache->base = base;
532 l2x_cache->way = way;
533 /*LOG_INFO("cache l2 initialized base %x way %d",
534 l2x_cache->base,l2x_cache->way);*/
535 if (armv7a->armv7a_mmu.armv7a_cache.l2_cache)
536 LOG_INFO("cache l2 already initialized\n");
537 armv7a->armv7a_mmu.armv7a_cache.l2_cache = l2x_cache;
538 /* initialize l1 / l2x cache function */
539 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache
540 = armv7a_l2x_flush_all_data;
541 armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
542 armv7a_handle_l2x_cache_info_command;
543 /* initialize all target in this cluster (smp target)
544 * l2 cache must be configured after smp declaration */
545 while (head != (struct target_list *)NULL) {
546 curr = head->target;
547 if (curr != target) {
548 armv7a = target_to_armv7a(curr);
549 if (armv7a->armv7a_mmu.armv7a_cache.l2_cache)
550 LOG_ERROR("smp target : cache l2 already initialized\n");
551 armv7a->armv7a_mmu.armv7a_cache.l2_cache = l2x_cache;
552 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
553 armv7a_l2x_flush_all_data;
554 armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
555 armv7a_handle_l2x_cache_info_command;
556 }
557 head = head->next;
558 }
559 return JIM_OK;
560 }
561
562 COMMAND_HANDLER(handle_cache_l2x)
563 {
564 struct target *target = get_current_target(CMD_CTX);
565 uint32_t base, way;
566
567 if (CMD_ARGC != 2)
568 return ERROR_COMMAND_SYNTAX_ERROR;
569
570 /* command_print(CMD_CTX, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
571 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
572 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
573
574 /* AP address is in bits 31:24 of DP_SELECT */
575 armv7a_l2x_cache_init(target, base, way);
576
577 return ERROR_OK;
578 }
579
580 int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
581 struct armv7a_cache_common *armv7a_cache)
582 {
583 if (armv7a_cache->ctype == -1) {
584 command_print(cmd_ctx, "cache not yet identified");
585 return ERROR_OK;
586 }
587
588 if (armv7a_cache->display_cache_info)
589 armv7a_cache->display_cache_info(cmd_ctx, armv7a_cache);
590 return ERROR_OK;
591 }
592
593 /* retrieve core id cluster id */
594 static int armv7a_read_mpidr(struct target *target)
595 {
596 int retval = ERROR_FAIL;
597 struct armv7a_common *armv7a = target_to_armv7a(target);
598 struct arm_dpm *dpm = armv7a->arm.dpm;
599 uint32_t mpidr;
600 retval = dpm->prepare(dpm);
601 if (retval != ERROR_OK)
602 goto done;
603 /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
604
605 retval = dpm->instr_read_data_r0(dpm,
606 ARMV4_5_MRC(15, 0, 0, 0, 0, 5),
607 &mpidr);
608 if (retval != ERROR_OK)
609 goto done;
610
611 /* ARMv7R uses a different format for MPIDR.
612 * When configured uniprocessor (most R cores) it reads as 0.
613 * This will need to be implemented for multiprocessor ARMv7R cores. */
614 if (armv7a->is_armv7r) {
615 if (mpidr)
616 LOG_ERROR("MPIDR nonzero in ARMv7-R target");
617 goto done;
618 }
619
620 if (mpidr & 1<<31) {
621 armv7a->multi_processor_system = (mpidr >> 30) & 1;
622 armv7a->cluster_id = (mpidr >> 8) & 0xf;
623 armv7a->cpu_id = mpidr & 0x3;
624 LOG_INFO("%s cluster %x core %x %s", target_name(target),
625 armv7a->cluster_id,
626 armv7a->cpu_id,
627 armv7a->multi_processor_system == 0 ? "multi core" : "mono core");
628
629 } else
630 LOG_ERROR("MPIDR not in multiprocessor format");
631
632 done:
633 dpm->finish(dpm);
634 return retval;
635
636
637 }
638
639 int armv7a_identify_cache(struct target *target)
640 {
641 /* read cache descriptor */
642 int retval = ERROR_FAIL;
643 struct armv7a_common *armv7a = target_to_armv7a(target);
644 struct arm_dpm *dpm = armv7a->arm.dpm;
645 uint32_t cache_selected, clidr;
646 uint32_t cache_i_reg, cache_d_reg;
647 struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
648 if (!armv7a->is_armv7r)
649 armv7a_read_ttbcr(target);
650 retval = dpm->prepare(dpm);
651
652 if (retval != ERROR_OK)
653 goto done;
654 /* retrieve CLIDR
655 * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
656 retval = dpm->instr_read_data_r0(dpm,
657 ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
658 &clidr);
659 if (retval != ERROR_OK)
660 goto done;
661 clidr = (clidr & 0x7000000) >> 23;
662 LOG_INFO("number of cache level %" PRIx32, (uint32_t)(clidr / 2));
663 if ((clidr / 2) > 1) {
664 /* FIXME not supported present in cortex A8 and later */
665 /* in cortex A7, A15 */
666 LOG_ERROR("cache l2 present :not supported");
667 }
668 /* retrieve selected cache
669 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
670 retval = dpm->instr_read_data_r0(dpm,
671 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
672 &cache_selected);
673 if (retval != ERROR_OK)
674 goto done;
675
676 retval = armv7a->arm.mrc(target, 15,
677 2, 0, /* op1, op2 */
678 0, 0, /* CRn, CRm */
679 &cache_selected);
680 if (retval != ERROR_OK)
681 goto done;
682 /* select instruction cache
683 * MCR p15, 2,<Rd>, c0, c0, 0; Write CSSELR
684 * [0] : 1 instruction cache selection , 0 data cache selection */
685 retval = dpm->instr_write_data_r0(dpm,
686 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
687 1);
688 if (retval != ERROR_OK)
689 goto done;
690
691 /* read CCSIDR
692 * MRC P15,1,<RT>,C0, C0,0 ;on cortex A9 read CCSIDR
693 * [2:0] line size 001 eight word per line
694 * [27:13] NumSet 0x7f 16KB, 0xff 32Kbytes, 0x1ff 64Kbytes */
695 retval = dpm->instr_read_data_r0(dpm,
696 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
697 &cache_i_reg);
698 if (retval != ERROR_OK)
699 goto done;
700
701 /* select data cache*/
702 retval = dpm->instr_write_data_r0(dpm,
703 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
704 0);
705 if (retval != ERROR_OK)
706 goto done;
707
708 retval = dpm->instr_read_data_r0(dpm,
709 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
710 &cache_d_reg);
711 if (retval != ERROR_OK)
712 goto done;
713
714 /* restore selected cache */
715 dpm->instr_write_data_r0(dpm,
716 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
717 cache_selected);
718
719 if (retval != ERROR_OK)
720 goto done;
721 dpm->finish(dpm);
722
723 /* put fake type */
724 cache->d_u_size.linelen = 16 << (cache_d_reg & 0x7);
725 cache->d_u_size.cachesize = (((cache_d_reg >> 13) & 0x7fff)+1)/8;
726 cache->d_u_size.nsets = (cache_d_reg >> 13) & 0x7fff;
727 cache->d_u_size.associativity = ((cache_d_reg >> 3) & 0x3ff) + 1;
728 /* compute info for set way operation on cache */
729 cache->d_u_size.index_shift = (cache_d_reg & 0x7) + 4;
730 cache->d_u_size.index = (cache_d_reg >> 13) & 0x7fff;
731 cache->d_u_size.way = ((cache_d_reg >> 3) & 0x3ff);
732 cache->d_u_size.way_shift = cache->d_u_size.way + 1;
733 {
734 int i = 0;
735 while (((cache->d_u_size.way_shift >> i) & 1) != 1)
736 i++;
737 cache->d_u_size.way_shift = 32-i;
738 }
739 #if 0
740 LOG_INFO("data cache index %d << %d, way %d << %d",
741 cache->d_u_size.index, cache->d_u_size.index_shift,
742 cache->d_u_size.way,
743 cache->d_u_size.way_shift);
744
745 LOG_INFO("data cache %d bytes %d KBytes asso %d ways",
746 cache->d_u_size.linelen,
747 cache->d_u_size.cachesize,
748 cache->d_u_size.associativity);
749 #endif
750 cache->i_size.linelen = 16 << (cache_i_reg & 0x7);
751 cache->i_size.associativity = ((cache_i_reg >> 3) & 0x3ff) + 1;
752 cache->i_size.nsets = (cache_i_reg >> 13) & 0x7fff;
753 cache->i_size.cachesize = (((cache_i_reg >> 13) & 0x7fff)+1)/8;
754 /* compute info for set way operation on cache */
755 cache->i_size.index_shift = (cache_i_reg & 0x7) + 4;
756 cache->i_size.index = (cache_i_reg >> 13) & 0x7fff;
757 cache->i_size.way = ((cache_i_reg >> 3) & 0x3ff);
758 cache->i_size.way_shift = cache->i_size.way + 1;
759 {
760 int i = 0;
761 while (((cache->i_size.way_shift >> i) & 1) != 1)
762 i++;
763 cache->i_size.way_shift = 32-i;
764 }
765 #if 0
766 LOG_INFO("instruction cache index %d << %d, way %d << %d",
767 cache->i_size.index, cache->i_size.index_shift,
768 cache->i_size.way, cache->i_size.way_shift);
769
770 LOG_INFO("instruction cache %d bytes %d KBytes asso %d ways",
771 cache->i_size.linelen,
772 cache->i_size.cachesize,
773 cache->i_size.associativity);
774 #endif
775 /* if no l2 cache initialize l1 data cache flush function function */
776 if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) {
777 armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
778 armv7a_handle_inner_cache_info_command;
779 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
780 armv7a_flush_all_data;
781 }
782 armv7a->armv7a_mmu.armv7a_cache.ctype = 0;
783
784 done:
785 dpm->finish(dpm);
786 armv7a_read_mpidr(target);
787 return retval;
788
789 }
790
791 int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a)
792 {
793 struct arm *arm = &armv7a->arm;
794 arm->arch_info = armv7a;
795 target->arch_info = &armv7a->arm;
796 /* target is useful in all function arm v4 5 compatible */
797 armv7a->arm.target = target;
798 armv7a->arm.common_magic = ARM_COMMON_MAGIC;
799 armv7a->common_magic = ARMV7_COMMON_MAGIC;
800 armv7a->armv7a_mmu.armv7a_cache.l2_cache = NULL;
801 armv7a->armv7a_mmu.armv7a_cache.ctype = -1;
802 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL;
803 armv7a->armv7a_mmu.armv7a_cache.display_cache_info = NULL;
804 return ERROR_OK;
805 }
806
807 int armv7a_arch_state(struct target *target)
808 {
809 static const char *state[] = {
810 "disabled", "enabled"
811 };
812
813 struct armv7a_common *armv7a = target_to_armv7a(target);
814 struct arm *arm = &armv7a->arm;
815
816 if (armv7a->common_magic != ARMV7_COMMON_MAGIC) {
817 LOG_ERROR("BUG: called for a non-ARMv7A target");
818 return ERROR_COMMAND_SYNTAX_ERROR;
819 }
820
821 arm_arch_state(target);
822
823 if (armv7a->is_armv7r) {
824 LOG_USER("D-Cache: %s, I-Cache: %s",
825 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
826 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
827 } else {
828 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
829 state[armv7a->armv7a_mmu.mmu_enabled],
830 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
831 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
832 }
833
834 if (arm->core_mode == ARM_MODE_ABT)
835 armv7a_show_fault_registers(target);
836 if (target->debug_reason == DBG_REASON_WATCHPOINT)
837 LOG_USER("Watchpoint triggered at PC %#08x",
838 (unsigned) armv7a->dpm.wp_pc);
839
840 return ERROR_OK;
841 }
842
843 static const struct command_registration l2_cache_commands[] = {
844 {
845 .name = "l2x",
846 .handler = handle_cache_l2x,
847 .mode = COMMAND_EXEC,
848 .help = "configure l2x cache "
849 "",
850 .usage = "[base_addr] [number_of_way]",
851 },
852 COMMAND_REGISTRATION_DONE
853
854 };
855
856 const struct command_registration l2x_cache_command_handlers[] = {
857 {
858 .name = "cache_config",
859 .mode = COMMAND_EXEC,
860 .help = "cache configuration for a target",
861 .usage = "",
862 .chain = l2_cache_commands,
863 },
864 COMMAND_REGISTRATION_DONE
865 };
866
867
868 const struct command_registration armv7a_command_handlers[] = {
869 {
870 .chain = dap_command_handlers,
871 },
872 {
873 .chain = l2x_cache_command_handlers,
874 },
875 COMMAND_REGISTRATION_DONE
876 };

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)