ca599eb68ab01abcc4c46cea904d7faa14700ae9
[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
568 if (CMD_ARGC != 2)
569 return ERROR_COMMAND_SYNTAX_ERROR;
570
571 /* command_print(CMD_CTX, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
572 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base);
573 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way);
574
575 /* AP address is in bits 31:24 of DP_SELECT */
576 armv7a_l2x_cache_init(target, base, way);
577
578 return ERROR_OK;
579 }
580
581 int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
582 struct armv7a_cache_common *armv7a_cache)
583 {
584 if (armv7a_cache->ctype == -1) {
585 command_print(cmd_ctx, "cache not yet identified");
586 return ERROR_OK;
587 }
588
589 if (armv7a_cache->display_cache_info)
590 armv7a_cache->display_cache_info(cmd_ctx, armv7a_cache);
591 return ERROR_OK;
592 }
593
594 /* retrieve core id cluster id */
595 static int armv7a_read_mpidr(struct target *target)
596 {
597 int retval = ERROR_FAIL;
598 struct armv7a_common *armv7a = target_to_armv7a(target);
599 struct arm_dpm *dpm = armv7a->arm.dpm;
600 uint32_t mpidr;
601 retval = dpm->prepare(dpm);
602 if (retval != ERROR_OK)
603 goto done;
604 /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
605
606 retval = dpm->instr_read_data_r0(dpm,
607 ARMV4_5_MRC(15, 0, 0, 0, 0, 5),
608 &mpidr);
609 if (retval != ERROR_OK)
610 goto done;
611
612 /* ARMv7R uses a different format for MPIDR.
613 * When configured uniprocessor (most R cores) it reads as 0.
614 * This will need to be implemented for multiprocessor ARMv7R cores. */
615 if (armv7a->is_armv7r) {
616 if (mpidr)
617 LOG_ERROR("MPIDR nonzero in ARMv7-R target");
618 goto done;
619 }
620
621 if (mpidr & 1<<31) {
622 armv7a->multi_processor_system = (mpidr >> 30) & 1;
623 armv7a->cluster_id = (mpidr >> 8) & 0xf;
624 armv7a->cpu_id = mpidr & 0x3;
625 LOG_INFO("%s cluster %x core %x %s", target_name(target),
626 armv7a->cluster_id,
627 armv7a->cpu_id,
628 armv7a->multi_processor_system == 0 ? "multi core" : "mono core");
629
630 } else
631 LOG_ERROR("MPIDR not in multiprocessor format");
632
633 done:
634 dpm->finish(dpm);
635 return retval;
636
637
638 }
639
640 int armv7a_identify_cache(struct target *target)
641 {
642 /* read cache descriptor */
643 int retval = ERROR_FAIL;
644 struct armv7a_common *armv7a = target_to_armv7a(target);
645 struct arm_dpm *dpm = armv7a->arm.dpm;
646 uint32_t cache_selected, clidr;
647 uint32_t cache_i_reg, cache_d_reg;
648 struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache);
649 if (!armv7a->is_armv7r)
650 armv7a_read_ttbcr(target);
651 retval = dpm->prepare(dpm);
652
653 if (retval != ERROR_OK)
654 goto done;
655 /* retrieve CLIDR
656 * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
657 retval = dpm->instr_read_data_r0(dpm,
658 ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
659 &clidr);
660 if (retval != ERROR_OK)
661 goto done;
662 clidr = (clidr & 0x7000000) >> 23;
663 LOG_INFO("number of cache level %" PRIx32, (uint32_t)(clidr / 2));
664 if ((clidr / 2) > 1) {
665 /* FIXME not supported present in cortex A8 and later */
666 /* in cortex A7, A15 */
667 LOG_ERROR("cache l2 present :not supported");
668 }
669 /* retrieve selected cache
670 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
671 retval = dpm->instr_read_data_r0(dpm,
672 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
673 &cache_selected);
674 if (retval != ERROR_OK)
675 goto done;
676
677 retval = armv7a->arm.mrc(target, 15,
678 2, 0, /* op1, op2 */
679 0, 0, /* CRn, CRm */
680 &cache_selected);
681 if (retval != ERROR_OK)
682 goto done;
683 /* select instruction cache
684 * MCR p15, 2,<Rd>, c0, c0, 0; Write CSSELR
685 * [0] : 1 instruction cache selection , 0 data cache selection */
686 retval = dpm->instr_write_data_r0(dpm,
687 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
688 1);
689 if (retval != ERROR_OK)
690 goto done;
691
692 /* read CCSIDR
693 * MRC P15,1,<RT>,C0, C0,0 ;on cortex A9 read CCSIDR
694 * [2:0] line size 001 eight word per line
695 * [27:13] NumSet 0x7f 16KB, 0xff 32Kbytes, 0x1ff 64Kbytes */
696 retval = dpm->instr_read_data_r0(dpm,
697 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
698 &cache_i_reg);
699 if (retval != ERROR_OK)
700 goto done;
701
702 /* select data cache*/
703 retval = dpm->instr_write_data_r0(dpm,
704 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
705 0);
706 if (retval != ERROR_OK)
707 goto done;
708
709 retval = dpm->instr_read_data_r0(dpm,
710 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
711 &cache_d_reg);
712 if (retval != ERROR_OK)
713 goto done;
714
715 /* restore selected cache */
716 dpm->instr_write_data_r0(dpm,
717 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
718 cache_selected);
719
720 if (retval != ERROR_OK)
721 goto done;
722 dpm->finish(dpm);
723
724 /* put fake type */
725 cache->d_u_size.linelen = 16 << (cache_d_reg & 0x7);
726 cache->d_u_size.cachesize = (((cache_d_reg >> 13) & 0x7fff)+1)/8;
727 cache->d_u_size.nsets = (cache_d_reg >> 13) & 0x7fff;
728 cache->d_u_size.associativity = ((cache_d_reg >> 3) & 0x3ff) + 1;
729 /* compute info for set way operation on cache */
730 cache->d_u_size.index_shift = (cache_d_reg & 0x7) + 4;
731 cache->d_u_size.index = (cache_d_reg >> 13) & 0x7fff;
732 cache->d_u_size.way = ((cache_d_reg >> 3) & 0x3ff);
733 cache->d_u_size.way_shift = cache->d_u_size.way + 1;
734 {
735 int i = 0;
736 while (((cache->d_u_size.way_shift >> i) & 1) != 1)
737 i++;
738 cache->d_u_size.way_shift = 32-i;
739 }
740 #if 0
741 LOG_INFO("data cache index %d << %d, way %d << %d",
742 cache->d_u_size.index, cache->d_u_size.index_shift,
743 cache->d_u_size.way,
744 cache->d_u_size.way_shift);
745
746 LOG_INFO("data cache %d bytes %d KBytes asso %d ways",
747 cache->d_u_size.linelen,
748 cache->d_u_size.cachesize,
749 cache->d_u_size.associativity);
750 #endif
751 cache->i_size.linelen = 16 << (cache_i_reg & 0x7);
752 cache->i_size.associativity = ((cache_i_reg >> 3) & 0x3ff) + 1;
753 cache->i_size.nsets = (cache_i_reg >> 13) & 0x7fff;
754 cache->i_size.cachesize = (((cache_i_reg >> 13) & 0x7fff)+1)/8;
755 /* compute info for set way operation on cache */
756 cache->i_size.index_shift = (cache_i_reg & 0x7) + 4;
757 cache->i_size.index = (cache_i_reg >> 13) & 0x7fff;
758 cache->i_size.way = ((cache_i_reg >> 3) & 0x3ff);
759 cache->i_size.way_shift = cache->i_size.way + 1;
760 {
761 int i = 0;
762 while (((cache->i_size.way_shift >> i) & 1) != 1)
763 i++;
764 cache->i_size.way_shift = 32-i;
765 }
766 #if 0
767 LOG_INFO("instruction cache index %d << %d, way %d << %d",
768 cache->i_size.index, cache->i_size.index_shift,
769 cache->i_size.way, cache->i_size.way_shift);
770
771 LOG_INFO("instruction cache %d bytes %d KBytes asso %d ways",
772 cache->i_size.linelen,
773 cache->i_size.cachesize,
774 cache->i_size.associativity);
775 #endif
776 /* if no l2 cache initialize l1 data cache flush function function */
777 if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) {
778 armv7a->armv7a_mmu.armv7a_cache.display_cache_info =
779 armv7a_handle_inner_cache_info_command;
780 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache =
781 armv7a_flush_all_data;
782 }
783 armv7a->armv7a_mmu.armv7a_cache.ctype = 0;
784
785 done:
786 dpm->finish(dpm);
787 armv7a_read_mpidr(target);
788 return retval;
789
790 }
791
792 int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a)
793 {
794 struct arm *arm = &armv7a->arm;
795 arm->arch_info = armv7a;
796 target->arch_info = &armv7a->arm;
797 /* target is useful in all function arm v4 5 compatible */
798 armv7a->arm.target = target;
799 armv7a->arm.common_magic = ARM_COMMON_MAGIC;
800 armv7a->common_magic = ARMV7_COMMON_MAGIC;
801 armv7a->armv7a_mmu.armv7a_cache.l2_cache = NULL;
802 armv7a->armv7a_mmu.armv7a_cache.ctype = -1;
803 armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL;
804 armv7a->armv7a_mmu.armv7a_cache.display_cache_info = NULL;
805 return ERROR_OK;
806 }
807
808 int armv7a_arch_state(struct target *target)
809 {
810 static const char *state[] = {
811 "disabled", "enabled"
812 };
813
814 struct armv7a_common *armv7a = target_to_armv7a(target);
815 struct arm *arm = &armv7a->arm;
816
817 if (armv7a->common_magic != ARMV7_COMMON_MAGIC) {
818 LOG_ERROR("BUG: called for a non-ARMv7A target");
819 return ERROR_COMMAND_SYNTAX_ERROR;
820 }
821
822 arm_arch_state(target);
823
824 if (armv7a->is_armv7r) {
825 LOG_USER("D-Cache: %s, I-Cache: %s",
826 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
827 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
828 } else {
829 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
830 state[armv7a->armv7a_mmu.mmu_enabled],
831 state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled],
832 state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]);
833 }
834
835 if (arm->core_mode == ARM_MODE_ABT)
836 armv7a_show_fault_registers(target);
837 if (target->debug_reason == DBG_REASON_WATCHPOINT)
838 LOG_USER("Watchpoint triggered at PC %#08x",
839 (unsigned) armv7a->dpm.wp_pc);
840
841 return ERROR_OK;
842 }
843
844 static const struct command_registration l2_cache_commands[] = {
845 {
846 .name = "l2x",
847 .handler = handle_cache_l2x,
848 .mode = COMMAND_EXEC,
849 .help = "configure l2x cache "
850 "",
851 .usage = "[base_addr] [number_of_way]",
852 },
853 COMMAND_REGISTRATION_DONE
854
855 };
856
857 const struct command_registration l2x_cache_command_handlers[] = {
858 {
859 .name = "cache_config",
860 .mode = COMMAND_EXEC,
861 .help = "cache configuration for a target",
862 .usage = "",
863 .chain = l2_cache_commands,
864 },
865 COMMAND_REGISTRATION_DONE
866 };
867
868
869 const struct command_registration armv7a_command_handlers[] = {
870 {
871 .chain = dap_command_handlers,
872 },
873 {
874 .chain = l2x_cache_command_handlers,
875 },
876 COMMAND_REGISTRATION_DONE
877 };

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)