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

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)