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_WARNING("virt = phys : MMU disable !!");
158 LOG_INFO("%" PRIx32
" : %" PRIx32
" %s outer shareable %s secured",
160 NOS
== 1 ? "not" : " ",
161 NS
== 1 ? "not" : "");
164 LOG_INFO("outer: Non-Cacheable");
167 LOG_INFO("outer: Write-Back, Write-Allocate");
170 LOG_INFO("outer: Write-Through, No Write-Allocate");
173 LOG_INFO("outer: Write-Back, no Write-Allocate");
178 LOG_INFO("inner: Non-Cacheable");
181 LOG_INFO("inner: Strongly-ordered");
184 LOG_INFO("inner: Device");
187 LOG_INFO("inner: Write-Back, Write-Allocate");
190 LOG_INFO("inner: Write-Through");
193 LOG_INFO("inner: Write-Back, no Write-Allocate");
196 LOG_INFO("inner: %" PRIx32
" ???", INNER
);
206 static const char *desc_bits_to_string(bool c_bit
, bool b_bit
, bool s_bit
, bool ap2
, int ap10
, bool afe
)
208 static char bits_string
[64];
214 bool priv
= !(ap10
& 2);
215 len
= snprintf(bits_string
, sizeof(bits_string
), "%s%s%s access%s: %s%s",
216 s_bit
? "S " : "", c_bit
? "C " : "", b_bit
? "B " : "",
217 priv
? "(priv)" : "", acc_r
? "R" : "N", acc_w
? "W " : "O ");
219 bool priv_acc_w
= !ap2
;
220 bool priv_acc_r
= true;
221 bool unpriv_acc_w
= priv_acc_w
;
222 bool unpriv_acc_r
= priv_acc_r
;
226 priv_acc_r
= priv_acc_w
= false;
227 unpriv_acc_r
= unpriv_acc_w
= false;
230 unpriv_acc_r
= unpriv_acc_w
= false;
233 unpriv_acc_w
= false;
239 len
= snprintf(bits_string
, sizeof(bits_string
), "%s%s%s access(priv): %s%s access(unpriv): %s%s",
240 s_bit
? "S " : "", c_bit
? "C " : "", b_bit
? "B " : "", priv_acc_r
? "R" : "N", priv_acc_w
? "W" : "O",
241 unpriv_acc_r
? "R" : "N", unpriv_acc_w
? "W" : "O");
244 if (len
>= sizeof(bits_string
))
250 static const char *l2_desc_bits_to_string(uint32_t l2_desc
, bool afe
)
252 bool c_bit
= !!(l2_desc
& (1 << 3));
253 bool b_bit
= !!(l2_desc
& (1 << 2));
254 bool s_bit
= !!(l2_desc
& (1 << 10));
255 bool ap2
= !!(l2_desc
& (1 << 9));
256 int ap10
= (l2_desc
>> 4) & 3;
258 return desc_bits_to_string(c_bit
, b_bit
, s_bit
, ap2
, ap10
, afe
);
261 static const char *l1_desc_bits_to_string(uint32_t l1_desc
, bool afe
)
263 bool c_bit
= !!(l1_desc
& (1 << 3));
264 bool b_bit
= !!(l1_desc
& (1 << 2));
265 bool s_bit
= !!(l1_desc
& (1 << 16));
266 bool ap2
= !!(l1_desc
& (1 << 15));
267 int ap10
= (l1_desc
>> 10) & 3;
269 return desc_bits_to_string(c_bit
, b_bit
, s_bit
, ap2
, ap10
, afe
);
272 COMMAND_HANDLER(armv7a_mmu_dump_table
)
274 struct target
*target
= get_current_target(CMD_CTX
);
275 struct cortex_a_common
*cortex_a
= target_to_cortex_a(target
);
276 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
277 struct armv7a_mmu_common
*mmu
= &armv7a
->armv7a_mmu
;
278 struct armv7a_cache_common
*cache
= &mmu
->armv7a_cache
;
279 uint32_t *first_lvl_ptbl
;
284 int max_pt_idx
= 4095;
288 return ERROR_COMMAND_SYNTAX_ERROR
;
290 if (!strcmp(CMD_ARGV
[0], "addr")) {
292 return ERROR_COMMAND_SYNTAX_ERROR
;
294 COMMAND_PARSE_NUMBER(target_addr
, CMD_ARGV
[1], ttb
);
297 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[2], max_pt_idx
);
299 if (max_pt_idx
< 1 || max_pt_idx
> 4096)
300 return ERROR_COMMAND_ARGUMENT_INVALID
;
304 if (mmu
->cached
!= 1) {
305 LOG_ERROR("TTB not cached!");
309 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], ttbidx
);
310 if (ttbidx
< 0 || ttbidx
> 1)
311 return ERROR_COMMAND_ARGUMENT_INVALID
;
313 ttb
= mmu
->ttbr
[ttbidx
] & mmu
->ttbr_mask
[ttbidx
];
316 int ttbcr_n
= mmu
->ttbcr
& 0x7;
317 max_pt_idx
= 0x0fff >> ttbcr_n
;
321 LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR
, ttb
);
323 first_lvl_ptbl
= malloc(sizeof(uint32_t)*(max_pt_idx
+1));
324 if (first_lvl_ptbl
== NULL
)
328 * this may or may not be necessary depending on whether
329 * the table walker is configured to use the cache or not.
331 cache
->flush_all_data_cache(target
);
333 retval
= mmu
->read_physical_memory(target
, ttb
, 4, max_pt_idx
+1, (uint8_t *)first_lvl_ptbl
);
334 if (retval
!= ERROR_OK
) {
335 LOG_ERROR("Failed to read first-level page table!");
339 afe
= !!(cortex_a
->cp15_control_reg
& SCTLR_BIT_AFE
);
341 for (pt_idx
= 0; pt_idx
<= max_pt_idx
;) {
342 uint32_t first_lvl_descriptor
= target_buffer_get_u32(target
,
343 (uint8_t *)&first_lvl_ptbl
[pt_idx
]);
345 LOG_DEBUG("L1 desc[%8.8"PRIx32
"]: %8.8"PRIx32
, pt_idx
<< 20, first_lvl_descriptor
);
347 /* skip empty entries in the first level table */
348 if ((first_lvl_descriptor
& 3) == 0) {
351 if ((first_lvl_descriptor
& 0x40002) == 2) {
352 /* section descriptor */
353 uint32_t va_range
= 1024*1024-1; /* 1MB range */
354 uint32_t va_start
= pt_idx
<< 20;
355 uint32_t va_end
= va_start
+ va_range
;
357 uint32_t pa_start
= (first_lvl_descriptor
& 0xfff00000);
358 uint32_t pa_end
= pa_start
+ va_range
;
360 LOG_USER("SECT: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
361 va_start
, va_end
, pa_start
, pa_end
, l1_desc_bits_to_string(first_lvl_descriptor
, afe
));
364 if ((first_lvl_descriptor
& 0x40002) == 0x40002) {
365 /* supersection descriptor */
366 uint32_t va_range
= 16*1024*1024-1; /* 16MB range */
367 uint32_t va_start
= pt_idx
<< 20;
368 uint32_t va_end
= va_start
+ va_range
;
370 uint32_t pa_start
= (first_lvl_descriptor
& 0xff000000);
371 uint32_t pa_end
= pa_start
+ va_range
;
373 LOG_USER("SSCT: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
374 va_start
, va_end
, pa_start
, pa_end
, l1_desc_bits_to_string(first_lvl_descriptor
, afe
));
376 /* skip next 15 entries, they're duplicating the first entry */
379 target_addr_t second_lvl_ptbl
= first_lvl_descriptor
& 0xfffffc00;
380 uint32_t second_lvl_descriptor
;
384 /* page table, always 1KB long */
386 retval
= mmu
->read_physical_memory(target
, second_lvl_ptbl
,
387 4, 256, (uint8_t *)pt2
);
388 if (retval
!= ERROR_OK
) {
389 LOG_ERROR("Failed to read second-level page table!");
393 for (pt2_idx
= 0; pt2_idx
< 256; ) {
394 second_lvl_descriptor
= target_buffer_get_u32(target
,
395 (uint8_t *)&pt2
[pt2_idx
]);
397 if ((second_lvl_descriptor
& 3) == 0) {
401 if ((second_lvl_descriptor
& 3) == 1) {
403 uint32_t va_range
= 64*1024-1; /* 64KB range */
404 uint32_t va_start
= (pt_idx
<< 20) + (pt2_idx
<< 12);
405 uint32_t va_end
= va_start
+ va_range
;
407 uint32_t pa_start
= (second_lvl_descriptor
& 0xffff0000);
408 uint32_t pa_end
= pa_start
+ va_range
;
410 LOG_USER("LPGE: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
411 va_start
, va_end
, pa_start
, pa_end
, l2_desc_bits_to_string(second_lvl_descriptor
, afe
));
416 uint32_t va_range
= 4*1024-1; /* 4KB range */
417 uint32_t va_start
= (pt_idx
<< 20) + (pt2_idx
<< 12);
418 uint32_t va_end
= va_start
+ va_range
;
420 uint32_t pa_start
= (second_lvl_descriptor
& 0xfffff000);
421 uint32_t pa_end
= pa_start
+ va_range
;
423 LOG_USER("SPGE: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
424 va_start
, va_end
, pa_start
, pa_end
, l2_desc_bits_to_string(second_lvl_descriptor
, afe
));
434 free(first_lvl_ptbl
);
438 static const struct command_registration armv7a_mmu_group_handlers
[] = {
441 .handler
= armv7a_mmu_dump_table
,
443 .help
= "dump translation table 0, 1 or from <address>",
444 .usage
= "(0|1|addr <address> [num_entries])",
446 COMMAND_REGISTRATION_DONE
449 const struct command_registration armv7a_mmu_command_handlers
[] = {
453 .help
= "mmu command group",
455 .chain
= armv7a_mmu_group_handlers
,
457 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)