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