1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 /***************************************************************************
4 * Copyright (C) 2009 by David Brownell *
6 * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
7 ***************************************************************************/
13 #include <helper/replacements.h>
16 #include "armv7a_mmu.h"
17 #include "arm_disassembler.h"
20 #include <helper/binarybuffer.h>
21 #include <helper/command.h>
27 #include "arm_opcodes.h"
29 #include "target_type.h"
32 static void armv7a_show_fault_registers(struct target
*target
)
34 uint32_t dfsr
, ifsr
, dfar
, ifar
;
35 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
36 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
39 retval
= dpm
->prepare(dpm
);
40 if (retval
!= ERROR_OK
)
43 /* ARMV4_5_MRC(cpnum, op1, r0, crn, crm, op2) */
45 /* c5/c0 - {data, instruction} fault status registers */
46 retval
= dpm
->instr_read_data_r0(dpm
,
47 ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
49 if (retval
!= ERROR_OK
)
52 retval
= dpm
->instr_read_data_r0(dpm
,
53 ARMV4_5_MRC(15, 0, 0, 5, 0, 1),
55 if (retval
!= ERROR_OK
)
58 /* c6/c0 - {data, instruction} fault address registers */
59 retval
= dpm
->instr_read_data_r0(dpm
,
60 ARMV4_5_MRC(15, 0, 0, 6, 0, 0),
62 if (retval
!= ERROR_OK
)
65 retval
= dpm
->instr_read_data_r0(dpm
,
66 ARMV4_5_MRC(15, 0, 0, 6, 0, 2),
68 if (retval
!= ERROR_OK
)
71 LOG_USER("Data fault registers DFSR: %8.8" PRIx32
72 ", DFAR: %8.8" PRIx32
, dfsr
, dfar
);
73 LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
74 ", IFAR: %8.8" PRIx32
, ifsr
, ifar
);
77 /* (void) */ dpm
->finish(dpm
);
81 /* retrieve main id register */
82 static int armv7a_read_midr(struct target
*target
)
84 int retval
= ERROR_FAIL
;
85 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
86 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
88 retval
= dpm
->prepare(dpm
);
89 if (retval
!= ERROR_OK
)
91 /* MRC p15,0,<Rd>,c0,c0,0; read main id register*/
93 retval
= dpm
->instr_read_data_r0(dpm
,
94 ARMV4_5_MRC(15, 0, 0, 0, 0, 0),
96 if (retval
!= ERROR_OK
)
99 armv7a
->rev
= (midr
& 0xf);
100 armv7a
->partnum
= (midr
>> 4) & 0xfff;
101 armv7a
->arch
= (midr
>> 16) & 0xf;
102 armv7a
->variant
= (midr
>> 20) & 0xf;
103 armv7a
->implementor
= (midr
>> 24) & 0xff;
104 LOG_DEBUG("%s rev %" PRIx32
", partnum %" PRIx32
", arch %" PRIx32
105 ", variant %" PRIx32
", implementor %" PRIx32
,
111 armv7a
->implementor
);
118 int armv7a_read_ttbcr(struct target
*target
)
120 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
121 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
122 uint32_t ttbcr
, ttbcr_n
;
126 retval
= dpm
->prepare(dpm
);
127 if (retval
!= ERROR_OK
)
130 /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
131 retval
= dpm
->instr_read_data_r0(dpm
,
132 ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
134 if (retval
!= ERROR_OK
)
137 LOG_DEBUG("ttbcr %" PRIx32
, ttbcr
);
139 ttbcr_n
= ttbcr
& 0x7;
140 armv7a
->armv7a_mmu
.ttbcr
= ttbcr
;
141 armv7a
->armv7a_mmu
.cached
= 1;
143 for (ttbidx
= 0; ttbidx
< 2; ttbidx
++) {
144 /* MRC p15,0,<Rt>,c2,c0,ttbidx */
145 retval
= dpm
->instr_read_data_r0(dpm
,
146 ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx
),
147 &armv7a
->armv7a_mmu
.ttbr
[ttbidx
]);
148 if (retval
!= ERROR_OK
)
153 * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition),
154 * document # ARM DDI 0406C
156 armv7a
->armv7a_mmu
.ttbr_range
[0] = 0xffffffff >> ttbcr_n
;
157 armv7a
->armv7a_mmu
.ttbr_range
[1] = 0xffffffff;
158 armv7a
->armv7a_mmu
.ttbr_mask
[0] = 0xffffffff << (14 - ttbcr_n
);
159 armv7a
->armv7a_mmu
.ttbr_mask
[1] = 0xffffffff << 14;
160 armv7a
->armv7a_mmu
.cached
= 1;
162 retval
= armv7a_read_midr(target
);
163 if (retval
!= ERROR_OK
)
166 /* FIXME: why this special case based on part number? */
167 if ((armv7a
->partnum
& 0xf) == 0) {
168 /* ARM DDI 0344H , ARM DDI 0407F */
169 armv7a
->armv7a_mmu
.ttbr_mask
[0] = 7 << (32 - ttbcr_n
);
172 LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32
" ttbr1_mask %" PRIx32
,
173 (ttbcr_n
!= 0) ? "used" : "not used",
174 armv7a
->armv7a_mmu
.ttbr_mask
[0],
175 armv7a
->armv7a_mmu
.ttbr_mask
[1]);
182 /* FIXME: remove it */
183 static int armv7a_l2x_cache_init(struct target
*target
, uint32_t base
, uint32_t way
)
185 struct armv7a_l2x_cache
*l2x_cache
;
186 struct target_list
*head
;
188 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
189 l2x_cache
= calloc(1, sizeof(struct armv7a_l2x_cache
));
190 l2x_cache
->base
= base
;
191 l2x_cache
->way
= way
;
192 /*LOG_INFO("cache l2 initialized base %x way %d",
193 l2x_cache->base,l2x_cache->way);*/
194 if (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
)
195 LOG_INFO("outer cache already initialized\n");
196 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= l2x_cache
;
197 /* initialize all target in this cluster (smp target)
198 * l2 cache must be configured after smp declaration */
199 foreach_smp_target(head
, target
->smp_targets
) {
200 struct target
*curr
= head
->target
;
201 if (curr
!= target
) {
202 armv7a
= target_to_armv7a(curr
);
203 if (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
)
204 LOG_ERROR("smp target : outer cache already initialized\n");
205 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= l2x_cache
;
211 /* FIXME: remove it */
212 COMMAND_HANDLER(handle_cache_l2x
)
214 struct target
*target
= get_current_target(CMD_CTX
);
218 return ERROR_COMMAND_SYNTAX_ERROR
;
220 /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
221 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], base
);
222 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], way
);
224 /* AP address is in bits 31:24 of DP_SELECT */
225 armv7a_l2x_cache_init(target
, base
, way
);
230 int armv7a_handle_cache_info_command(struct command_invocation
*cmd
,
231 struct armv7a_cache_common
*armv7a_cache
)
233 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
234 (armv7a_cache
->outer_cache
);
238 if (armv7a_cache
->info
== -1) {
239 command_print(cmd
, "cache not yet identified");
243 for (cl
= 0; cl
< armv7a_cache
->loc
; cl
++) {
244 struct armv7a_arch_cache
*arch
= &(armv7a_cache
->arch
[cl
]);
246 if (arch
->ctype
& 1) {
248 "L%d I-Cache: linelen %" PRIu32
249 ", associativity %" PRIu32
251 ", cachesize %" PRIu32
" KBytes",
253 arch
->i_size
.linelen
,
254 arch
->i_size
.associativity
,
256 arch
->i_size
.cachesize
);
259 if (arch
->ctype
>= 2) {
261 "L%d D-Cache: linelen %" PRIu32
262 ", associativity %" PRIu32
264 ", cachesize %" PRIu32
" KBytes",
266 arch
->d_u_size
.linelen
,
267 arch
->d_u_size
.associativity
,
268 arch
->d_u_size
.nsets
,
269 arch
->d_u_size
.cachesize
);
274 command_print(cmd
, "Outer unified cache Base Address 0x%" PRIx32
", %" PRIu32
" ways",
275 l2x_cache
->base
, l2x_cache
->way
);
280 /* retrieve core id cluster id */
281 static int armv7a_read_mpidr(struct target
*target
)
283 int retval
= ERROR_FAIL
;
284 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
285 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
287 retval
= dpm
->prepare(dpm
);
288 if (retval
!= ERROR_OK
)
290 /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
292 retval
= dpm
->instr_read_data_r0(dpm
,
293 ARMV4_5_MRC(15, 0, 0, 0, 0, 5),
295 if (retval
!= ERROR_OK
)
298 /* Is register in Multiprocessing Extensions register format? */
299 if (mpidr
& MPIDR_MP_EXT
) {
300 LOG_DEBUG("%s: MPIDR 0x%" PRIx32
, target_name(target
), mpidr
);
301 armv7a
->multi_processor_system
= (mpidr
>> 30) & 1;
302 armv7a
->multi_threading_processor
= (mpidr
>> 24) & 1;
303 armv7a
->level2_id
= (mpidr
>> 16) & 0xf;
304 armv7a
->cluster_id
= (mpidr
>> 8) & 0xf;
305 armv7a
->cpu_id
= mpidr
& 0xf;
306 LOG_INFO("%s: MPIDR level2 %x, cluster %x, core %x, %s, %s",
311 armv7a
->multi_processor_system
== 0 ? "multi core" : "mono core",
312 armv7a
->multi_threading_processor
== 1 ? "SMT" : "no SMT");
315 LOG_ERROR("MPIDR not in multiprocessor format");
324 static int get_cache_info(struct arm_dpm
*dpm
, int cl
, int ct
, uint32_t *cache_reg
)
326 int retval
= ERROR_OK
;
328 /* select cache level */
329 retval
= dpm
->instr_write_data_r0(dpm
,
330 ARMV4_5_MCR(15, 2, 0, 0, 0, 0),
331 (cl
<< 1) | (ct
== 1 ? 1 : 0));
332 if (retval
!= ERROR_OK
)
335 retval
= dpm
->instr_read_data_r0(dpm
,
336 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
342 static struct armv7a_cachesize
decode_cache_reg(uint32_t cache_reg
)
344 struct armv7a_cachesize size
;
347 size
.linelen
= 16 << (cache_reg
& 0x7);
348 size
.associativity
= ((cache_reg
>> 3) & 0x3ff) + 1;
349 size
.nsets
= ((cache_reg
>> 13) & 0x7fff) + 1;
350 size
.cachesize
= size
.linelen
* size
.associativity
* size
.nsets
/ 1024;
352 /* compute info for set way operation on cache */
353 size
.index_shift
= (cache_reg
& 0x7) + 4;
354 size
.index
= (cache_reg
>> 13) & 0x7fff;
355 size
.way
= ((cache_reg
>> 3) & 0x3ff);
357 while (((size
.way
<< i
) & 0x80000000) == 0)
364 int armv7a_identify_cache(struct target
*target
)
366 /* read cache descriptor */
367 int retval
= ERROR_FAIL
;
368 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
369 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
370 uint32_t csselr
, clidr
, ctr
;
373 struct armv7a_cache_common
*cache
=
374 &(armv7a
->armv7a_mmu
.armv7a_cache
);
376 retval
= dpm
->prepare(dpm
);
377 if (retval
!= ERROR_OK
)
381 * mrc p15, 0, r0, c0, c0, 1 @ read ctr */
382 retval
= dpm
->instr_read_data_r0(dpm
,
383 ARMV4_5_MRC(15, 0, 0, 0, 0, 1),
385 if (retval
!= ERROR_OK
)
388 cache
->iminline
= 4UL << (ctr
& 0xf);
389 cache
->dminline
= 4UL << ((ctr
& 0xf0000) >> 16);
390 LOG_DEBUG("ctr %" PRIx32
" ctr.iminline %" PRIu32
" ctr.dminline %" PRIu32
,
391 ctr
, cache
->iminline
, cache
->dminline
);
394 * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
395 retval
= dpm
->instr_read_data_r0(dpm
,
396 ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
398 if (retval
!= ERROR_OK
)
401 cache
->loc
= (clidr
& 0x7000000) >> 24;
402 LOG_DEBUG("Number of cache levels to PoC %" PRId32
, cache
->loc
);
404 /* retrieve selected cache for later restore
405 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
406 retval
= dpm
->instr_read_data_r0(dpm
,
407 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
409 if (retval
!= ERROR_OK
)
412 /* retrieve all available inner caches */
413 for (cl
= 0; cl
< cache
->loc
; clidr
>>= 3, cl
++) {
415 /* isolate cache type at current level */
418 /* skip reserved values */
419 if (ctype
> CACHE_LEVEL_HAS_UNIFIED_CACHE
)
422 /* separate d or unified d/i cache at this level ? */
423 if (ctype
& (CACHE_LEVEL_HAS_UNIFIED_CACHE
| CACHE_LEVEL_HAS_D_CACHE
)) {
424 /* retrieve d-cache info */
425 retval
= get_cache_info(dpm
, cl
, 0, &cache_reg
);
426 if (retval
!= ERROR_OK
)
428 cache
->arch
[cl
].d_u_size
= decode_cache_reg(cache_reg
);
430 LOG_DEBUG("data/unified cache index %" PRIu32
" << %" PRIu32
", way %" PRIu32
" << %" PRIu32
,
431 cache
->arch
[cl
].d_u_size
.index
,
432 cache
->arch
[cl
].d_u_size
.index_shift
,
433 cache
->arch
[cl
].d_u_size
.way
,
434 cache
->arch
[cl
].d_u_size
.way_shift
);
436 LOG_DEBUG("cacheline %" PRIu32
" bytes %" PRIu32
" KBytes asso %" PRIu32
" ways",
437 cache
->arch
[cl
].d_u_size
.linelen
,
438 cache
->arch
[cl
].d_u_size
.cachesize
,
439 cache
->arch
[cl
].d_u_size
.associativity
);
442 /* separate i-cache at this level ? */
443 if (ctype
& CACHE_LEVEL_HAS_I_CACHE
) {
444 /* retrieve i-cache info */
445 retval
= get_cache_info(dpm
, cl
, 1, &cache_reg
);
446 if (retval
!= ERROR_OK
)
448 cache
->arch
[cl
].i_size
= decode_cache_reg(cache_reg
);
450 LOG_DEBUG("instruction cache index %" PRIu32
" << %" PRIu32
", way %" PRIu32
" << %" PRIu32
,
451 cache
->arch
[cl
].i_size
.index
,
452 cache
->arch
[cl
].i_size
.index_shift
,
453 cache
->arch
[cl
].i_size
.way
,
454 cache
->arch
[cl
].i_size
.way_shift
);
456 LOG_DEBUG("cacheline %" PRIu32
" bytes %" PRIu32
" KBytes asso %" PRIu32
" ways",
457 cache
->arch
[cl
].i_size
.linelen
,
458 cache
->arch
[cl
].i_size
.cachesize
,
459 cache
->arch
[cl
].i_size
.associativity
);
462 cache
->arch
[cl
].ctype
= ctype
;
465 /* restore selected cache */
466 dpm
->instr_write_data_r0(dpm
,
467 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
470 if (retval
!= ERROR_OK
)
473 /* if no l2 cache initialize l1 data cache flush function function */
474 if (!armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
) {
475 armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
=
476 armv7a_cache_auto_flush_all_data
;
479 armv7a
->armv7a_mmu
.armv7a_cache
.info
= 1;
482 armv7a_read_mpidr(target
);
487 static int armv7a_setup_semihosting(struct target
*target
, int enable
)
489 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
493 ret
= mem_ap_read_atomic_u32(armv7a
->debug_ap
,
494 armv7a
->debug_base
+ CPUDBG_VCR
,
497 LOG_ERROR("Failed to read VCR register\n");
502 vcr
|= DBG_VCR_SVC_MASK
;
504 vcr
&= ~DBG_VCR_SVC_MASK
;
506 ret
= mem_ap_write_atomic_u32(armv7a
->debug_ap
,
507 armv7a
->debug_base
+ CPUDBG_VCR
,
510 LOG_ERROR("Failed to write VCR register\n");
515 int armv7a_init_arch_info(struct target
*target
, struct armv7a_common
*armv7a
)
517 struct arm
*arm
= &armv7a
->arm
;
518 arm
->arch_info
= armv7a
;
519 target
->arch_info
= &armv7a
->arm
;
520 arm
->setup_semihosting
= armv7a_setup_semihosting
;
521 /* target is useful in all function arm v4 5 compatible */
522 armv7a
->arm
.target
= target
;
523 armv7a
->arm
.common_magic
= ARM_COMMON_MAGIC
;
524 armv7a
->common_magic
= ARMV7_COMMON_MAGIC
;
525 armv7a
->armv7a_mmu
.armv7a_cache
.info
= -1;
526 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= NULL
;
527 armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
= NULL
;
528 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= 1;
532 int armv7a_arch_state(struct target
*target
)
534 static const char *state
[] = {
535 "disabled", "enabled"
538 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
539 struct arm
*arm
= &armv7a
->arm
;
541 if (armv7a
->common_magic
!= ARMV7_COMMON_MAGIC
) {
542 LOG_ERROR("BUG: called for a non-ARMv7A target");
543 return ERROR_COMMAND_SYNTAX_ERROR
;
546 arm_arch_state(target
);
548 if (armv7a
->is_armv7r
) {
549 LOG_USER("D-Cache: %s, I-Cache: %s",
550 state
[armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
],
551 state
[armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
]);
553 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
554 state
[armv7a
->armv7a_mmu
.mmu_enabled
],
555 state
[armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
],
556 state
[armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
]);
559 if (arm
->core_mode
== ARM_MODE_ABT
)
560 armv7a_show_fault_registers(target
);
565 static const struct command_registration l2_cache_commands
[] = {
568 .handler
= handle_cache_l2x
,
569 .mode
= COMMAND_EXEC
,
570 .help
= "configure l2x cache",
571 .usage
= "[base_addr] [number_of_way]",
573 COMMAND_REGISTRATION_DONE
577 static const struct command_registration l2x_cache_command_handlers
[] = {
579 .name
= "cache_config",
580 .mode
= COMMAND_EXEC
,
581 .help
= "cache configuration for a target",
583 .chain
= l2_cache_commands
,
585 COMMAND_REGISTRATION_DONE
588 const struct command_registration armv7a_command_handlers
[] = {
590 .chain
= l2x_cache_command_handlers
,
593 .chain
= arm7a_cache_command_handlers
,
595 COMMAND_REGISTRATION_DONE
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)