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-Redition),
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_CTX, "%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_context
*cmd_ctx
,
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_ctx
, "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) {
259 command_print(cmd_ctx
,
260 "L%d I-Cache: linelen %" PRIi32
261 ", associativity %" PRIi32
263 ", cachesize %" PRId32
" KBytes",
265 arch
->i_size
.linelen
,
266 arch
->i_size
.associativity
,
268 arch
->i_size
.cachesize
);
271 if (arch
->ctype
>= 2) {
272 command_print(cmd_ctx
,
273 "L%d D-Cache: linelen %" PRIi32
274 ", associativity %" PRIi32
276 ", cachesize %" PRId32
" 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_ctx
, "Outer unified cache Base Address 0x%" PRIx32
", %" PRId32
" 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 /* ARMv7R uses a different format for MPIDR.
311 * When configured uniprocessor (most R cores) it reads as 0.
312 * This will need to be implemented for multiprocessor ARMv7R cores. */
313 if (armv7a
->is_armv7r
) {
315 LOG_ERROR("MPIDR nonzero in ARMv7-R target");
320 armv7a
->multi_processor_system
= (mpidr
>> 30) & 1;
321 armv7a
->cluster_id
= (mpidr
>> 8) & 0xf;
322 armv7a
->cpu_id
= mpidr
& 0x3;
323 LOG_INFO("%s cluster %x core %x %s", target_name(target
),
326 armv7a
->multi_processor_system
== 0 ? "multi core" : "mono core");
329 LOG_ERROR("MPIDR not in multiprocessor format");
338 static int get_cache_info(struct arm_dpm
*dpm
, int cl
, int ct
, uint32_t *cache_reg
)
340 int retval
= ERROR_OK
;
342 /* select cache level */
343 retval
= dpm
->instr_write_data_r0(dpm
,
344 ARMV4_5_MCR(15, 2, 0, 0, 0, 0),
345 (cl
<< 1) | (ct
== 1 ? 1 : 0));
346 if (retval
!= ERROR_OK
)
349 retval
= dpm
->instr_read_data_r0(dpm
,
350 ARMV4_5_MRC(15, 1, 0, 0, 0, 0),
356 static struct armv7a_cachesize
decode_cache_reg(uint32_t cache_reg
)
358 struct armv7a_cachesize size
;
361 size
.linelen
= 16 << (cache_reg
& 0x7);
362 size
.associativity
= ((cache_reg
>> 3) & 0x3ff) + 1;
363 size
.nsets
= ((cache_reg
>> 13) & 0x7fff) + 1;
364 size
.cachesize
= size
.linelen
* size
.associativity
* size
.nsets
/ 1024;
366 /* compute info for set way operation on cache */
367 size
.index_shift
= (cache_reg
& 0x7) + 4;
368 size
.index
= (cache_reg
>> 13) & 0x7fff;
369 size
.way
= ((cache_reg
>> 3) & 0x3ff);
371 while (((size
.way
<< i
) & 0x80000000) == 0)
378 int armv7a_identify_cache(struct target
*target
)
380 /* read cache descriptor */
381 int retval
= ERROR_FAIL
;
382 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
383 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
384 uint32_t csselr
, clidr
, ctr
;
387 struct armv7a_cache_common
*cache
=
388 &(armv7a
->armv7a_mmu
.armv7a_cache
);
390 retval
= dpm
->prepare(dpm
);
391 if (retval
!= ERROR_OK
)
395 * mrc p15, 0, r0, c0, c0, 1 @ read ctr */
396 retval
= dpm
->instr_read_data_r0(dpm
,
397 ARMV4_5_MRC(15, 0, 0, 0, 0, 1),
399 if (retval
!= ERROR_OK
)
402 cache
->iminline
= 4UL << (ctr
& 0xf);
403 cache
->dminline
= 4UL << ((ctr
& 0xf0000) >> 16);
404 LOG_DEBUG("ctr %" PRIx32
" ctr.iminline %" PRId32
" ctr.dminline %" PRId32
,
405 ctr
, cache
->iminline
, cache
->dminline
);
408 * mrc p15, 1, r0, c0, c0, 1 @ read clidr */
409 retval
= dpm
->instr_read_data_r0(dpm
,
410 ARMV4_5_MRC(15, 1, 0, 0, 0, 1),
412 if (retval
!= ERROR_OK
)
415 cache
->loc
= (clidr
& 0x7000000) >> 24;
416 LOG_DEBUG("Number of cache levels to PoC %" PRId32
, cache
->loc
);
418 /* retrieve selected cache for later restore
419 * MRC p15, 2,<Rd>, c0, c0, 0; Read CSSELR */
420 retval
= dpm
->instr_read_data_r0(dpm
,
421 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
423 if (retval
!= ERROR_OK
)
426 /* retrieve all available inner caches */
427 for (cl
= 0; cl
< cache
->loc
; clidr
>>= 3, cl
++) {
429 /* isolate cache type at current level */
432 /* skip reserved values */
433 if (ctype
> CACHE_LEVEL_HAS_UNIFIED_CACHE
)
436 /* separate d or unified d/i cache at this level ? */
437 if (ctype
& (CACHE_LEVEL_HAS_UNIFIED_CACHE
| CACHE_LEVEL_HAS_D_CACHE
)) {
438 /* retrieve d-cache info */
439 retval
= get_cache_info(dpm
, cl
, 0, &cache_reg
);
440 if (retval
!= ERROR_OK
)
442 cache
->arch
[cl
].d_u_size
= decode_cache_reg(cache_reg
);
444 LOG_DEBUG("data/unified cache index %d << %d, way %d << %d",
445 cache
->arch
[cl
].d_u_size
.index
,
446 cache
->arch
[cl
].d_u_size
.index_shift
,
447 cache
->arch
[cl
].d_u_size
.way
,
448 cache
->arch
[cl
].d_u_size
.way_shift
);
450 LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
451 cache
->arch
[cl
].d_u_size
.linelen
,
452 cache
->arch
[cl
].d_u_size
.cachesize
,
453 cache
->arch
[cl
].d_u_size
.associativity
);
456 /* separate i-cache at this level ? */
457 if (ctype
& CACHE_LEVEL_HAS_I_CACHE
) {
458 /* retrieve i-cache info */
459 retval
= get_cache_info(dpm
, cl
, 1, &cache_reg
);
460 if (retval
!= ERROR_OK
)
462 cache
->arch
[cl
].i_size
= decode_cache_reg(cache_reg
);
464 LOG_DEBUG("instruction cache index %d << %d, way %d << %d",
465 cache
->arch
[cl
].i_size
.index
,
466 cache
->arch
[cl
].i_size
.index_shift
,
467 cache
->arch
[cl
].i_size
.way
,
468 cache
->arch
[cl
].i_size
.way_shift
);
470 LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways",
471 cache
->arch
[cl
].i_size
.linelen
,
472 cache
->arch
[cl
].i_size
.cachesize
,
473 cache
->arch
[cl
].i_size
.associativity
);
476 cache
->arch
[cl
].ctype
= ctype
;
479 /* restore selected cache */
480 dpm
->instr_write_data_r0(dpm
,
481 ARMV4_5_MRC(15, 2, 0, 0, 0, 0),
484 if (retval
!= ERROR_OK
)
487 /* if no l2 cache initialize l1 data cache flush function function */
488 if (armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
== NULL
) {
489 armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
=
490 armv7a_cache_auto_flush_all_data
;
493 armv7a
->armv7a_mmu
.armv7a_cache
.info
= 1;
496 armv7a_read_mpidr(target
);
501 static int armv7a_setup_semihosting(struct target
*target
, int enable
)
503 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
507 ret
= mem_ap_read_atomic_u32(armv7a
->debug_ap
,
508 armv7a
->debug_base
+ CPUDBG_VCR
,
511 LOG_ERROR("Failed to read VCR register\n");
516 vcr
|= DBG_VCR_SVC_MASK
;
518 vcr
&= ~DBG_VCR_SVC_MASK
;
520 ret
= mem_ap_write_atomic_u32(armv7a
->debug_ap
,
521 armv7a
->debug_base
+ CPUDBG_VCR
,
524 LOG_ERROR("Failed to write VCR register\n");
529 int armv7a_init_arch_info(struct target
*target
, struct armv7a_common
*armv7a
)
531 struct arm
*arm
= &armv7a
->arm
;
532 arm
->arch_info
= armv7a
;
533 target
->arch_info
= &armv7a
->arm
;
534 arm
->setup_semihosting
= armv7a_setup_semihosting
;
535 /* target is useful in all function arm v4 5 compatible */
536 armv7a
->arm
.target
= target
;
537 armv7a
->arm
.common_magic
= ARM_COMMON_MAGIC
;
538 armv7a
->common_magic
= ARMV7_COMMON_MAGIC
;
539 armv7a
->armv7a_mmu
.armv7a_cache
.info
= -1;
540 armv7a
->armv7a_mmu
.armv7a_cache
.outer_cache
= NULL
;
541 armv7a
->armv7a_mmu
.armv7a_cache
.flush_all_data_cache
= NULL
;
542 armv7a
->armv7a_mmu
.armv7a_cache
.auto_cache_enabled
= 1;
546 int armv7a_arch_state(struct target
*target
)
548 static const char *state
[] = {
549 "disabled", "enabled"
552 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
553 struct arm
*arm
= &armv7a
->arm
;
555 if (armv7a
->common_magic
!= ARMV7_COMMON_MAGIC
) {
556 LOG_ERROR("BUG: called for a non-ARMv7A target");
557 return ERROR_COMMAND_SYNTAX_ERROR
;
560 arm_arch_state(target
);
562 if (armv7a
->is_armv7r
) {
563 LOG_USER("D-Cache: %s, I-Cache: %s",
564 state
[armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
],
565 state
[armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
]);
567 LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s",
568 state
[armv7a
->armv7a_mmu
.mmu_enabled
],
569 state
[armv7a
->armv7a_mmu
.armv7a_cache
.d_u_cache_enabled
],
570 state
[armv7a
->armv7a_mmu
.armv7a_cache
.i_cache_enabled
]);
573 if (arm
->core_mode
== ARM_MODE_ABT
)
574 armv7a_show_fault_registers(target
);
575 if (target
->debug_reason
== DBG_REASON_WATCHPOINT
)
576 LOG_USER("Watchpoint triggered at PC %#08x",
577 (unsigned) armv7a
->dpm
.wp_pc
);
582 static const struct command_registration l2_cache_commands
[] = {
585 .handler
= handle_cache_l2x
,
586 .mode
= COMMAND_EXEC
,
587 .help
= "configure l2x cache "
589 .usage
= "[base_addr] [number_of_way]",
591 COMMAND_REGISTRATION_DONE
595 const struct command_registration l2x_cache_command_handlers
[] = {
597 .name
= "cache_config",
598 .mode
= COMMAND_EXEC
,
599 .help
= "cache configuration for a target",
601 .chain
= l2_cache_commands
,
603 COMMAND_REGISTRATION_DONE
606 const struct command_registration armv7a_command_handlers
[] = {
608 .chain
= l2x_cache_command_handlers
,
611 .chain
= arm7a_cache_command_handlers
,
613 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)