1 /***************************************************************************
2 * Copyright (C) 2009 by David Brownell *
4 * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
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. *
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. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
24 #include <helper/replacements.h>
27 #include "armv7a_mmu.h"
28 #include "arm_disassembler.h"
31 #include <helper/binarybuffer.h>
32 #include <helper/command.h>
38 #include "arm_opcodes.h"
40 #include "target_type.h"
42 static void armv7a_show_fault_registers(struct target
*target
)
44 uint32_t dfsr
, ifsr
, dfar
, ifar
;
45 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
46 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
49 retval
= dpm
->prepare(dpm
);
50 if (retval
!= ERROR_OK
)
53 /* ARMV4_5_MRC(cpnum, op1, r0, crn, crm, op2) */
55 /* c5/c0 - {data, instruction} fault status registers */
56 retval
= dpm
->instr_read_data_r0(dpm
,
57 ARMV4_5_MRC(15, 0, 0, 5, 0, 0),
59 if (retval
!= ERROR_OK
)
62 retval
= dpm
->instr_read_data_r0(dpm
,
63 ARMV4_5_MRC(15, 0, 0, 5, 0, 1),
65 if (retval
!= ERROR_OK
)
68 /* c6/c0 - {data, instruction} fault address registers */
69 retval
= dpm
->instr_read_data_r0(dpm
,
70 ARMV4_5_MRC(15, 0, 0, 6, 0, 0),
72 if (retval
!= ERROR_OK
)
75 retval
= dpm
->instr_read_data_r0(dpm
,
76 ARMV4_5_MRC(15, 0, 0, 6, 0, 2),
78 if (retval
!= ERROR_OK
)
81 LOG_USER("Data fault registers DFSR: %8.8" PRIx32
82 ", DFAR: %8.8" PRIx32
, dfsr
, dfar
);
83 LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32
84 ", IFAR: %8.8" PRIx32
, ifsr
, ifar
);
87 /* (void) */ dpm
->finish(dpm
);
91 /* retrieve main id register */
92 static int armv7a_read_midr(struct target
*target
)
94 int retval
= ERROR_FAIL
;
95 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
96 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
98 retval
= dpm
->prepare(dpm
);
99 if (retval
!= ERROR_OK
)
101 /* MRC p15,0,<Rd>,c0,c0,0; read main id register*/
103 retval
= dpm
->instr_read_data_r0(dpm
,
104 ARMV4_5_MRC(15, 0, 0, 0, 0, 0),
106 if (retval
!= ERROR_OK
)
109 armv7a
->rev
= (midr
& 0xf);
110 armv7a
->partnum
= (midr
>> 4) & 0xfff;
111 armv7a
->arch
= (midr
>> 16) & 0xf;
112 armv7a
->variant
= (midr
>> 20) & 0xf;
113 armv7a
->implementor
= (midr
>> 24) & 0xff;
114 LOG_INFO("%s rev %" PRIx32
", partnum %" PRIx32
", arch %" PRIx32
115 ", variant %" PRIx32
", implementor %" PRIx32
,
121 armv7a
->implementor
);
128 int armv7a_read_ttbcr(struct target
*target
)
130 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
131 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
132 uint32_t ttbcr
, ttbcr_n
;
136 retval
= dpm
->prepare(dpm
);
137 if (retval
!= ERROR_OK
)
140 /* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
141 retval
= dpm
->instr_read_data_r0(dpm
,
142 ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
144 if (retval
!= ERROR_OK
)
147 LOG_DEBUG("ttbcr %" PRIx32
, ttbcr
);
149 ttbcr_n
= ttbcr
& 0x7;
150 armv7a
->armv7a_mmu
.ttbcr
= ttbcr
;
151 armv7a
->armv7a_mmu
.cached
= 1;
153 for (ttbidx
= 0; ttbidx
< 2; ttbidx
++) {
154 /* MRC p15,0,<Rt>,c2,c0,ttbidx */
155 retval
= dpm
->instr_read_data_r0(dpm
,
156 ARMV4_5_MRC(15, 0, 0, 2, 0, ttbidx
),
157 &armv7a
->armv7a_mmu
.ttbr
[ttbidx
]);
158 if (retval
!= ERROR_OK
)
163 * ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition),
164 * document # ARM DDI 0406C
166 armv7a
->armv7a_mmu
.ttbr_range
[0] = 0xffffffff >> ttbcr_n
;
167 armv7a
->armv7a_mmu
.ttbr_range
[1] = 0xffffffff;
168 armv7a
->armv7a_mmu
.ttbr_mask
[0] = 0xffffffff << (14 - ttbcr_n
);
169 armv7a
->armv7a_mmu
.ttbr_mask
[1] = 0xffffffff << 14;
170 armv7a
->armv7a_mmu
.cached
= 1;
172 retval
= armv7a_read_midr(target
);
173 if (retval
!= ERROR_OK
)
176 /* FIXME: why this special case based on part number? */
177 if ((armv7a
->partnum
& 0xf) == 0) {
178 /* ARM DDI 0344H , ARM DDI 0407F */
179 armv7a
->armv7a_mmu
.ttbr_mask
[0] = 7 << (32 - ttbcr_n
);
182 LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32
" ttbr1_mask %" PRIx32
,
183 (ttbcr_n
!= 0) ? "used" : "not used",
184 armv7a
->armv7a_mmu
.ttbr_mask
[0],
185 armv7a
->armv7a_mmu
.ttbr_mask
[1]);
192 /* FIXME: remove it */
193 static int armv7a_l2x_cache_init(struct target
*target
, uint32_t base
, uint32_t way
)
195 struct armv7a_l2x_cache
*l2x_cache
;
196 struct target_list
*head
= target
->head
;
199 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
200 l2x_cache
= calloc(1, sizeof(struct armv7a_l2x_cache
));
201 l2x_cache
->base
= base
;
202 l2x_cache
->way
= way
;
203 /*LOG_INFO("cache l2 initialized base %x way %d",
204 l2x_cache->base,l2x_cache->way);*/
205 if (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
)
206 LOG_INFO("outer cache already initialized\n");
207 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= l2x_cache
;
208 /* initialize all target in this cluster (smp target)
209 * l2 cache must be configured after smp declaration */
210 while (head
!= (struct target_list
*)NULL
) {
212 if (curr
!= target
) {
213 armv7a
= target_to_armv7a(curr
);
214 if (armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
)
215 LOG_ERROR("smp target : outer cache already initialized\n");
216 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= l2x_cache
;
223 /* FIXME: remove it */
224 COMMAND_HANDLER(handle_cache_l2x
)
226 struct target
*target
= get_current_target(CMD_CTX
);
230 return ERROR_COMMAND_SYNTAX_ERROR
;
232 /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */
233 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[0], base
);
234 COMMAND_PARSE_NUMBER(u32
, CMD_ARGV
[1], way
);
236 /* AP address is in bits 31:24 of DP_SELECT */
237 armv7a_l2x_cache_init(target
, base
, way
);
242 int armv7a_handle_cache_info_command(struct command_invocation
*cmd
,
243 struct armv7a_cache_common
*armv7a_cache
)
245 struct armv7a_l2x_cache
*l2x_cache
= (struct armv7a_l2x_cache
*)
246 (armv7a_cache
->outer_cache
);
250 if (armv7a_cache
->info
== -1) {
251 command_print(cmd
, "cache not yet identified");
255 for (cl
= 0; cl
< armv7a_cache
->loc
; cl
++) {
256 struct armv7a_arch_cache
*arch
= &(armv7a_cache
->arch
[cl
]);
258 if (arch
->ctype
& 1) {
260 "L%d I-Cache: linelen %" PRIu32
261 ", associativity %" PRIu32
263 ", cachesize %" PRIu32
" KBytes",
265 arch
->i_size
.linelen
,
266 arch
->i_size
.associativity
,
268 arch
->i_size
.cachesize
);
271 if (arch
->ctype
>= 2) {
273 "L%d D-Cache: linelen %" PRIu32
274 ", associativity %" PRIu32
276 ", cachesize %" PRIu32
" KBytes",
278 arch
->d_u_size
.linelen
,
279 arch
->d_u_size
.associativity
,
280 arch
->d_u_size
.nsets
,
281 arch
->d_u_size
.cachesize
);
285 if (l2x_cache
!= NULL
)
286 command_print(cmd
, "Outer unified cache Base Address 0x%" PRIx32
", %" PRIu32
" ways",
287 l2x_cache
->base
, l2x_cache
->way
);
292 /* retrieve core id cluster id */
293 static int armv7a_read_mpidr(struct target
*target
)
295 int retval
= ERROR_FAIL
;
296 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
297 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
299 retval
= dpm
->prepare(dpm
);
300 if (retval
!= ERROR_OK
)
302 /* MRC p15,0,<Rd>,c0,c0,5; read Multiprocessor ID register*/
304 retval
= dpm
->instr_read_data_r0(dpm
,
305 ARMV4_5_MRC(15, 0, 0, 0, 0, 5),
307 if (retval
!= ERROR_OK
)
310 /* Is register in Multiprocessing Extensions register format? */
311 if (mpidr
& MPIDR_MP_EXT
) {
312 LOG_DEBUG("%s: MPIDR 0x%" PRIx32
, target_name(target
), mpidr
);
313 armv7a
->multi_processor_system
= (mpidr
>> 30) & 1;
314 armv7a
->multi_threading_processor
= (mpidr
>> 24) & 1;
315 armv7a
->level2_id
= (mpidr
>> 16) & 0xf;
316 armv7a
->cluster_id
= (mpidr
>> 8) & 0xf;
317 armv7a
->cpu_id
= mpidr
& 0xf;
318 LOG_INFO("%s: MPIDR level2 %x, cluster %x, core %x, %s, %s",
323 armv7a
->multi_processor_system
== 0 ? "multi core" : "mono core",
324 armv7a
->multi_threading_processor
== 1 ? "SMT" : "no SMT");
327 LOG_ERROR("MPIDR not in multiprocessor format");
336 static int get_cache_info(struct arm_dpm
*dpm
, int cl
, int ct
, uint32_t *cache_reg
)
338 int retval
= ERROR_OK
;
340 /* select cache level */
341 retval
= dpm
->instr_write_data_r0(dpm
,
342 ARMV4_5_MCR(15, 2, 0, 0, 0, 0),
343 (cl
<< 1) | (ct
== 1 ? 1 : 0));
344 if (retval
!= ERROR_OK
)
347 retval
= dpm
->instr_read_data_r0(dpm
,
348 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
354 static struct armv7a_cachesize
decode_cache_reg(uint32_t cache_reg
)
356 struct armv7a_cachesize size
;
359 size
.linelen
= 16 << (cache_reg
& 0x7);
360 size
.associativity
= ((cache_reg
>> 3) & 0x3ff) + 1;
361 size
.nsets
= ((cache_reg
>> 13) & 0x7fff) + 1;
362 size
.cachesize
= size
.linelen
* size
.associativity
* size
.nsets
/ 1024;
364 /* compute info for set way operation on cache */
365 size
.index_shift
= (cache_reg
& 0x7) + 4;
366 size
.index
= (cache_reg
>> 13) & 0x7fff;
367 size
.way
= ((cache_reg
>> 3) & 0x3ff);
369 while (((size
.way
<< i
) & 0x80000000) == 0)
376 int armv7a_identify_cache(struct target
*target
)
378 /* read cache descriptor */
379 int retval
= ERROR_FAIL
;
380 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
381 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
382 uint32_t csselr
, clidr
, ctr
;
385 struct armv7a_cache_common
*cache
=
386 &(armv7a
->armv7a_mmu
.armv7a_cache
);
388 retval
= dpm
->prepare(dpm
);
389 if (retval
!= ERROR_OK
)
393 * mrc p15, 0, r0, c0, c0, 1 @ read ctr */
394 retval
= dpm
->instr_read_data_r0(dpm
,
395 ARMV4_5_MRC(15, 0, 0, 0, 0, 1),
397 if (retval
!= ERROR_OK
)
400 cache
->iminline
= 4UL << (ctr
& 0xf);
401 cache
->dminline
= 4UL << ((ctr
& 0xf0000) >> 16);
402 LOG_DEBUG("ctr %" PRIx32
" ctr.iminline %" PRIu32
" ctr.dminline %" PRIu32
,
403 ctr
, cache
->iminline
, cache
->dminline
);
406 * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
407 retval
= dpm
->instr_read_data_r0(dpm
,
408 ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
410 if (retval
!= ERROR_OK
)
413 cache
->loc
= (clidr
& 0x7000000) >> 24;
414 LOG_DEBUG("Number of cache levels to PoC %" PRId32
, cache
->loc
);
416 /* retrieve selected cache for later restore
417 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
418 retval
= dpm
->instr_read_data_r0(dpm
,
419 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
421 if (retval
!= ERROR_OK
)
424 /* retrieve all available inner caches */
425 for (cl
= 0; cl
< cache
->loc
; clidr
>>= 3, cl
++) {
427 /* isolate cache type at current level */
430 /* skip reserved values */
431 if (ctype
> CACHE_LEVEL_HAS_UNIFIED_CACHE
)
434 /* separate d or unified d/i cache at this level ? */
435 if (ctype
& (CACHE_LEVEL_HAS_UNIFIED_CACHE
| CACHE_LEVEL_HAS_D_CACHE
)) {
436 /* retrieve d-cache info */
437 retval
= get_cache_info(dpm
, cl
, 0, &cache_reg
);
438 if (retval
!= ERROR_OK
)
440 cache
->arch
[cl
].d_u_size
= decode_cache_reg(cache_reg
);
442 LOG_DEBUG("data/unified cache index %" PRIu32
" << %" PRIu32
", way %" PRIu32
" << %" PRIu32
,
443 cache
->arch
[cl
].d_u_size
.index
,
444 cache
->arch
[cl
].d_u_size
.index_shift
,
445 cache
->arch
[cl
].d_u_size
.way
,
446 cache
->arch
[cl
].d_u_size
.way_shift
);
448 LOG_DEBUG("cacheline %" PRIu32
" bytes %" PRIu32
" KBytes asso %" PRIu32
" ways",
449 cache
->arch
[cl
].d_u_size
.linelen
,
450 cache
->arch
[cl
].d_u_size
.cachesize
,
451 cache
->arch
[cl
].d_u_size
.associativity
);
454 /* separate i-cache at this level ? */
455 if (ctype
& CACHE_LEVEL_HAS_I_CACHE
) {
456 /* retrieve i-cache info */
457 retval
= get_cache_info(dpm
, cl
, 1, &cache_reg
);
458 if (retval
!= ERROR_OK
)
460 cache
->arch
[cl
].i_size
= decode_cache_reg(cache_reg
);
462 LOG_DEBUG("instruction cache index %" PRIu32
" << %" PRIu32
", way %" PRIu32
" << %" PRIu32
,
463 cache
->arch
[cl
].i_size
.index
,
464 cache
->arch
[cl
].i_size
.index_shift
,
465 cache
->arch
[cl
].i_size
.way
,
466 cache
->arch
[cl
].i_size
.way_shift
);
468 LOG_DEBUG("cacheline %" PRIu32
" bytes %" PRIu32
" KBytes asso %" PRIu32
" ways",
469 cache
->arch
[cl
].i_size
.linelen
,
470 cache
->arch
[cl
].i_size
.cachesize
,
471 cache
->arch
[cl
].i_size
.associativity
);
474 cache
->arch
[cl
].ctype
= ctype
;
477 /* restore selected cache */
478 dpm
->instr_write_data_r0(dpm
,
479 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
482 if (retval
!= ERROR_OK
)
485 /* if no l2 cache initialize l1 data cache flush function function */
486 if (armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
== NULL
) {
487 armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
=
488 armv7a_cache_auto_flush_all_data
;
491 armv7a
->armv7a_mmu
.armv7a_cache
.info
= 1;
494 armv7a_read_mpidr(target
);
499 static int armv7a_setup_semihosting(struct target
*target
, int enable
)
501 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
505 ret
= mem_ap_read_atomic_u32(armv7a
->debug_ap
,
506 armv7a
->debug_base
+ CPUDBG_VCR
,
509 LOG_ERROR("Failed to read VCR register\n");
514 vcr
|= DBG_VCR_SVC_MASK
;
516 vcr
&= ~DBG_VCR_SVC_MASK
;
518 ret
= mem_ap_write_atomic_u32(armv7a
->debug_ap
,
519 armv7a
->debug_base
+ CPUDBG_VCR
,
522 LOG_ERROR("Failed to write VCR register\n");
527 int armv7a_init_arch_info(struct target
*target
, struct armv7a_common
*armv7a
)
529 struct arm
*arm
= &armv7a
->arm
;
530 arm
->arch_info
= armv7a
;
531 target
->arch_info
= &armv7a
->arm
;
532 arm
->setup_semihosting
= armv7a_setup_semihosting
;
533 /* target is useful in all function arm v4 5 compatible */
534 armv7a
->arm
.target
= target
;
535 armv7a
->arm
.common_magic
= ARM_COMMON_MAGIC
;
536 armv7a
->common_magic
= ARMV7_COMMON_MAGIC
;
537 armv7a
->armv7a_mmu
.armv7a_cache
.info
= -1;
538 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= NULL
;
539 armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
= NULL
;
540 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= 1;
544 int armv7a_arch_state(struct target
*target
)
546 static const char *state
[] = {
547 "disabled", "enabled"
550 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
551 struct arm
*arm
= &armv7a
->arm
;
553 if (armv7a
->common_magic
!= ARMV7_COMMON_MAGIC
) {
554 LOG_ERROR("BUG: called for a non-ARMv7A target");
555 return ERROR_COMMAND_SYNTAX_ERROR
;
558 arm_arch_state(target
);
560 if (armv7a
->is_armv7r
) {
561 LOG_USER("D-Cache: %s, I-Cache: %s",
562 state
[armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
],
563 state
[armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
]);
565 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
566 state
[armv7a
->armv7a_mmu
.mmu_enabled
],
567 state
[armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
],
568 state
[armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
]);
571 if (arm
->core_mode
== ARM_MODE_ABT
)
572 armv7a_show_fault_registers(target
);
577 static const struct command_registration l2_cache_commands
[] = {
580 .handler
= handle_cache_l2x
,
581 .mode
= COMMAND_EXEC
,
582 .help
= "configure l2x cache",
583 .usage
= "[base_addr] [number_of_way]",
585 COMMAND_REGISTRATION_DONE
589 static const struct command_registration l2x_cache_command_handlers
[] = {
591 .name
= "cache_config",
592 .mode
= COMMAND_EXEC
,
593 .help
= "cache configuration for a target",
595 .chain
= l2_cache_commands
,
597 COMMAND_REGISTRATION_DONE
600 const struct command_registration armv7a_command_handlers
[] = {
602 .chain
= l2x_cache_command_handlers
,
605 .chain
= arm7a_cache_command_handlers
,
607 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)