1 /***************************************************************************
2 * Copyright (C) 2016 by Matthias Welwarsky *
3 * matthias.welwarsky@sysgo.com *
5 * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 ***************************************************************************/
25 #include <helper/binarybuffer.h>
26 #include <helper/command.h>
28 #include "jtag/interface.h"
31 #include "armv7a_mmu.h"
32 #include "arm_opcodes.h"
35 #define SCTLR_BIT_AFE (1 << 29)
37 /* method adapted to Cortex-A : reused ARM v4 v5 method */
38 int armv7a_mmu_translate_va(struct target
*target
, uint32_t va
, uint32_t *val
)
40 uint32_t first_lvl_descriptor
= 0x0;
41 uint32_t second_lvl_descriptor
= 0x0;
43 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
44 uint32_t ttbidx
= 0; /* default to ttbr0 */
49 if (target
->state
!= TARGET_HALTED
)
50 LOG_INFO("target not halted, using cached values for translation table!");
52 /* if va is above the range handled by ttbr0, select ttbr1 */
53 if (va
> armv7a
->armv7a_mmu
.ttbr_range
[0]) {
58 ttb
= armv7a
->armv7a_mmu
.ttbr
[ttbidx
];
59 ttb_mask
= armv7a
->armv7a_mmu
.ttbr_mask
[ttbidx
];
60 va_mask
= 0xfff00000 & armv7a
->armv7a_mmu
.ttbr_range
[ttbidx
];
62 LOG_DEBUG("ttb_mask %" PRIx32
" va_mask %" PRIx32
" ttbidx %i",
63 ttb_mask
, va_mask
, ttbidx
);
64 retval
= armv7a
->armv7a_mmu
.read_physical_memory(target
,
65 (ttb
& ttb_mask
) | ((va
& va_mask
) >> 18),
66 4, 1, (uint8_t *)&first_lvl_descriptor
);
67 if (retval
!= ERROR_OK
)
69 first_lvl_descriptor
= target_buffer_get_u32(target
, (uint8_t *)
70 &first_lvl_descriptor
);
71 /* reuse armv4_5 piece of code, specific armv7a changes may come later */
72 LOG_DEBUG("1st lvl desc: %8.8" PRIx32
"", first_lvl_descriptor
);
74 if ((first_lvl_descriptor
& 0x3) == 0) {
75 /* Avoid LOG_ERROR, probably GDB is guessing the stack frame */
76 LOG_WARNING("Address translation failure [1]: va %8.8" PRIx32
"", va
);
77 return ERROR_TARGET_TRANSLATION_FAULT
;
80 if ((first_lvl_descriptor
& 0x40002) == 2) {
81 /* section descriptor */
82 *val
= (first_lvl_descriptor
& 0xfff00000) | (va
& 0x000fffff);
84 } else if ((first_lvl_descriptor
& 0x40002) == 0x40002) {
85 /* supersection descriptor */
86 if (first_lvl_descriptor
& 0x00f001e0) {
87 LOG_ERROR("Physical address does not fit into 32 bits");
88 return ERROR_TARGET_TRANSLATION_FAULT
;
90 *val
= (first_lvl_descriptor
& 0xff000000) | (va
& 0x00ffffff);
95 retval
= armv7a
->armv7a_mmu
.read_physical_memory(target
,
96 (first_lvl_descriptor
& 0xfffffc00) | ((va
& 0x000ff000) >> 10),
97 4, 1, (uint8_t *)&second_lvl_descriptor
);
98 if (retval
!= ERROR_OK
)
101 second_lvl_descriptor
= target_buffer_get_u32(target
, (uint8_t *)
102 &second_lvl_descriptor
);
104 LOG_DEBUG("2nd lvl desc: %8.8" PRIx32
"", second_lvl_descriptor
);
106 if ((second_lvl_descriptor
& 0x3) == 0) {
107 /* Avoid LOG_ERROR, probably GDB is guessing the stack frame */
108 LOG_WARNING("Address translation failure [2]: va %8.8" PRIx32
"", va
);
109 return ERROR_TARGET_TRANSLATION_FAULT
;
112 if ((second_lvl_descriptor
& 0x3) == 1) {
113 /* large page descriptor */
114 *val
= (second_lvl_descriptor
& 0xffff0000) | (va
& 0x0000ffff);
116 /* small page descriptor */
117 *val
= (second_lvl_descriptor
& 0xfffff000) | (va
& 0x00000fff);
123 /* V7 method VA TO PA */
124 int armv7a_mmu_translate_va_pa(struct target
*target
, uint32_t va
,
125 uint32_t *val
, int meminfo
)
127 int retval
= ERROR_FAIL
;
128 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
129 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
130 uint32_t virt
= va
& ~0xfff;
131 uint32_t NOS
, NS
, INNER
, OUTER
;
133 retval
= dpm
->prepare(dpm
);
134 if (retval
!= ERROR_OK
)
136 /* mmu must be enable in order to get a correct translation
137 * use VA to PA CP15 register for conversion */
138 retval
= dpm
->instr_write_data_r0(dpm
,
139 ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
141 if (retval
!= ERROR_OK
)
143 retval
= dpm
->instr_read_data_r0(dpm
,
144 ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
146 /* decode memory attribute */
147 NOS
= (*val
>> 10) & 1; /* Not Outer shareable */
148 NS
= (*val
>> 9) & 1; /* Non secure */
149 INNER
= (*val
>> 4) & 0x7;
150 OUTER
= (*val
>> 2) & 0x3;
152 if (retval
!= ERROR_OK
)
154 *val
= (*val
& ~0xfff) + (va
& 0xfff);
156 LOG_INFO("%" PRIx32
" : %" PRIx32
" %s outer shareable %s secured",
158 NOS
== 1 ? "not" : " ",
159 NS
== 1 ? "not" : "");
162 LOG_INFO("outer: Non-Cacheable");
165 LOG_INFO("outer: Write-Back, Write-Allocate");
168 LOG_INFO("outer: Write-Through, No Write-Allocate");
171 LOG_INFO("outer: Write-Back, no Write-Allocate");
176 LOG_INFO("inner: Non-Cacheable");
179 LOG_INFO("inner: Strongly-ordered");
182 LOG_INFO("inner: Device");
185 LOG_INFO("inner: Write-Back, Write-Allocate");
188 LOG_INFO("inner: Write-Through");
191 LOG_INFO("inner: Write-Back, no Write-Allocate");
194 LOG_INFO("inner: %" PRIx32
" ???", INNER
);
204 static const char *desc_bits_to_string(bool c_bit
, bool b_bit
, bool s_bit
, bool ap2
, int ap10
, bool afe
)
206 static char bits_string
[64];
212 bool priv
= !(ap10
& 2);
213 len
= snprintf(bits_string
, sizeof(bits_string
), "%s%s%s access%s: %s%s",
214 s_bit
? "S " : "", c_bit
? "C " : "", b_bit
? "B " : "",
215 priv
? "(priv)" : "", acc_r
? "R" : "N", acc_w
? "W " : "O ");
217 bool priv_acc_w
= !ap2
;
218 bool priv_acc_r
= true;
219 bool unpriv_acc_w
= priv_acc_w
;
220 bool unpriv_acc_r
= priv_acc_r
;
224 priv_acc_r
= priv_acc_w
= false;
225 unpriv_acc_r
= unpriv_acc_w
= false;
228 unpriv_acc_r
= unpriv_acc_w
= false;
231 unpriv_acc_w
= false;
237 len
= snprintf(bits_string
, sizeof(bits_string
), "%s%s%s access(priv): %s%s access(unpriv): %s%s",
238 s_bit
? "S " : "", c_bit
? "C " : "", b_bit
? "B " : "", priv_acc_r
? "R" : "N", priv_acc_w
? "W" : "O",
239 unpriv_acc_r
? "R" : "N", unpriv_acc_w
? "W" : "O");
242 if (len
>= sizeof(bits_string
))
248 static const char *l2_desc_bits_to_string(uint32_t l2_desc
, bool afe
)
250 bool c_bit
= !!(l2_desc
& (1 << 3));
251 bool b_bit
= !!(l2_desc
& (1 << 2));
252 bool s_bit
= !!(l2_desc
& (1 << 10));
253 bool ap2
= !!(l2_desc
& (1 << 9));
254 int ap10
= (l2_desc
>> 4) & 3;
256 return desc_bits_to_string(c_bit
, b_bit
, s_bit
, ap2
, ap10
, afe
);
259 static const char *l1_desc_bits_to_string(uint32_t l1_desc
, bool afe
)
261 bool c_bit
= !!(l1_desc
& (1 << 3));
262 bool b_bit
= !!(l1_desc
& (1 << 2));
263 bool s_bit
= !!(l1_desc
& (1 << 16));
264 bool ap2
= !!(l1_desc
& (1 << 15));
265 int ap10
= (l1_desc
>> 10) & 3;
267 return desc_bits_to_string(c_bit
, b_bit
, s_bit
, ap2
, ap10
, afe
);
270 COMMAND_HANDLER(armv7a_mmu_dump_table
)
272 struct target
*target
= get_current_target(CMD_CTX
);
273 struct cortex_a_common
*cortex_a
= target_to_cortex_a(target
);
274 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
275 struct armv7a_mmu_common
*mmu
= &armv7a
->armv7a_mmu
;
276 struct armv7a_cache_common
*cache
= &mmu
->armv7a_cache
;
277 uint32_t *first_lvl_ptbl
;
282 int max_pt_idx
= 4095;
286 return ERROR_COMMAND_SYNTAX_ERROR
;
288 if (!strcmp(CMD_ARGV
[0], "addr")) {
290 return ERROR_COMMAND_SYNTAX_ERROR
;
292 COMMAND_PARSE_NUMBER(target_addr
, CMD_ARGV
[1], ttb
);
295 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[2], max_pt_idx
);
297 if (max_pt_idx
< 1 || max_pt_idx
> 4096)
298 return ERROR_COMMAND_ARGUMENT_INVALID
;
302 if (mmu
->cached
!= 1) {
303 LOG_ERROR("TTB not cached!");
307 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], ttbidx
);
308 if (ttbidx
< 0 || ttbidx
> 1)
309 return ERROR_COMMAND_ARGUMENT_INVALID
;
311 ttb
= mmu
->ttbr
[ttbidx
] & mmu
->ttbr_mask
[ttbidx
];
314 int ttbcr_n
= mmu
->ttbcr
& 0x7;
315 max_pt_idx
= 0x0fff >> ttbcr_n
;
319 LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR
, ttb
);
321 first_lvl_ptbl
= malloc(sizeof(uint32_t)*(max_pt_idx
+1));
322 if (first_lvl_ptbl
== NULL
)
326 * this may or may not be necessary depending on whether
327 * the table walker is configured to use the cache or not.
329 cache
->flush_all_data_cache(target
);
331 retval
= mmu
->read_physical_memory(target
, ttb
, 4, max_pt_idx
+1, (uint8_t *)first_lvl_ptbl
);
332 if (retval
!= ERROR_OK
) {
333 LOG_ERROR("Failed to read first-level page table!");
337 afe
= !!(cortex_a
->cp15_control_reg
& SCTLR_BIT_AFE
);
339 for (pt_idx
= 0; pt_idx
<= max_pt_idx
;) {
340 uint32_t first_lvl_descriptor
= target_buffer_get_u32(target
,
341 (uint8_t *)&first_lvl_ptbl
[pt_idx
]);
343 LOG_DEBUG("L1 desc[%8.8"PRIx32
"]: %8.8"PRIx32
, pt_idx
<< 20, first_lvl_descriptor
);
345 /* skip empty entries in the first level table */
346 if ((first_lvl_descriptor
& 3) == 0) {
349 if ((first_lvl_descriptor
& 0x40002) == 2) {
350 /* section descriptor */
351 uint32_t va_range
= 1024*1024-1; /* 1MB range */
352 uint32_t va_start
= pt_idx
<< 20;
353 uint32_t va_end
= va_start
+ va_range
;
355 uint32_t pa_start
= (first_lvl_descriptor
& 0xfff00000);
356 uint32_t pa_end
= pa_start
+ va_range
;
358 LOG_USER("SECT: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
359 va_start
, va_end
, pa_start
, pa_end
, l1_desc_bits_to_string(first_lvl_descriptor
, afe
));
362 if ((first_lvl_descriptor
& 0x40002) == 0x40002) {
363 /* supersection descriptor */
364 uint32_t va_range
= 16*1024*1024-1; /* 16MB range */
365 uint32_t va_start
= pt_idx
<< 20;
366 uint32_t va_end
= va_start
+ va_range
;
368 uint32_t pa_start
= (first_lvl_descriptor
& 0xff000000);
369 uint32_t pa_end
= pa_start
+ va_range
;
371 LOG_USER("SSCT: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
372 va_start
, va_end
, pa_start
, pa_end
, l1_desc_bits_to_string(first_lvl_descriptor
, afe
));
374 /* skip next 15 entries, they're duplicating the first entry */
377 target_addr_t second_lvl_ptbl
= first_lvl_descriptor
& 0xfffffc00;
378 uint32_t second_lvl_descriptor
;
382 /* page table, always 1KB long */
384 retval
= mmu
->read_physical_memory(target
, second_lvl_ptbl
,
385 4, 256, (uint8_t *)pt2
);
386 if (retval
!= ERROR_OK
) {
387 LOG_ERROR("Failed to read second-level page table!");
391 for (pt2_idx
= 0; pt2_idx
< 256; ) {
392 second_lvl_descriptor
= target_buffer_get_u32(target
,
393 (uint8_t *)&pt2
[pt2_idx
]);
395 if ((second_lvl_descriptor
& 3) == 0) {
399 if ((second_lvl_descriptor
& 3) == 1) {
401 uint32_t va_range
= 64*1024-1; /* 64KB range */
402 uint32_t va_start
= (pt_idx
<< 20) + (pt2_idx
<< 12);
403 uint32_t va_end
= va_start
+ va_range
;
405 uint32_t pa_start
= (second_lvl_descriptor
& 0xffff0000);
406 uint32_t pa_end
= pa_start
+ va_range
;
408 LOG_USER("LPGE: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
409 va_start
, va_end
, pa_start
, pa_end
, l2_desc_bits_to_string(second_lvl_descriptor
, afe
));
414 uint32_t va_range
= 4*1024-1; /* 4KB range */
415 uint32_t va_start
= (pt_idx
<< 20) + (pt2_idx
<< 12);
416 uint32_t va_end
= va_start
+ va_range
;
418 uint32_t pa_start
= (second_lvl_descriptor
& 0xfffff000);
419 uint32_t pa_end
= pa_start
+ va_range
;
421 LOG_USER("SPGE: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
422 va_start
, va_end
, pa_start
, pa_end
, l2_desc_bits_to_string(second_lvl_descriptor
, afe
));
432 free(first_lvl_ptbl
);
436 static const struct command_registration armv7a_mmu_group_handlers
[] = {
439 .handler
= armv7a_mmu_dump_table
,
441 .help
= "dump translation table 0, 1 or from <address>",
442 .usage
= "(0|1|addr <address> [num_entries])",
444 COMMAND_REGISTRATION_DONE
447 const struct command_registration armv7a_mmu_command_handlers
[] = {
451 .help
= "mmu command group",
453 .chain
= armv7a_mmu_group_handlers
,
455 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)