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 /* V7 method VA TO PA */
38 int armv7a_mmu_translate_va_pa(struct target
*target
, uint32_t va
,
39 target_addr_t
*val
, int meminfo
)
41 int retval
= ERROR_FAIL
;
42 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
43 struct arm_dpm
*dpm
= armv7a
->arm
.dpm
;
44 uint32_t virt
= va
& ~0xfff, value
;
45 uint32_t NOS
, NS
, INNER
, OUTER
, SS
;
47 retval
= dpm
->prepare(dpm
);
48 if (retval
!= ERROR_OK
)
50 /* mmu must be enable in order to get a correct translation
51 * use VA to PA CP15 register for conversion */
52 retval
= dpm
->instr_write_data_r0(dpm
,
53 ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
55 if (retval
!= ERROR_OK
)
57 retval
= dpm
->instr_read_data_r0(dpm
,
58 ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
60 if (retval
!= ERROR_OK
)
63 /* decode memory attribute */
64 SS
= (value
>> 1) & 1;
65 NOS
= (value
>> 10) & 1; /* Not Outer shareable */
66 NS
= (value
>> 9) & 1; /* Non secure */
67 INNER
= (value
>> 4) & 0x7;
68 OUTER
= (value
>> 2) & 0x3;
71 /* PAR[31:24] contains PA[31:24] */
72 *val
= value
& 0xff000000;
73 /* PAR [23:16] contains PA[39:32] */
74 *val
|= (target_addr_t
)(value
& 0x00ff0000) << 16;
75 /* PA[23:12] is the same as VA[23:12] */
76 *val
|= (va
& 0xffffff);
78 *val
= (value
& ~0xfff) + (va
& 0xfff);
81 LOG_INFO("%" PRIx32
" : %" TARGET_PRIxADDR
" %s outer shareable %s secured %s super section",
83 NOS
== 1 ? "not" : " ",
85 SS
== 0 ? "not" : "");
88 LOG_INFO("outer: Non-Cacheable");
91 LOG_INFO("outer: Write-Back, Write-Allocate");
94 LOG_INFO("outer: Write-Through, No Write-Allocate");
97 LOG_INFO("outer: Write-Back, no Write-Allocate");
102 LOG_INFO("inner: Non-Cacheable");
105 LOG_INFO("inner: Strongly-ordered");
108 LOG_INFO("inner: Device");
111 LOG_INFO("inner: Write-Back, Write-Allocate");
114 LOG_INFO("inner: Write-Through");
117 LOG_INFO("inner: Write-Back, no Write-Allocate");
120 LOG_INFO("inner: %" PRIx32
" ???", INNER
);
130 static const char *desc_bits_to_string(bool c_bit
, bool b_bit
, bool s_bit
, bool ap2
, int ap10
, bool afe
)
132 static char bits_string
[64];
138 bool priv
= !(ap10
& 2);
139 len
= snprintf(bits_string
, sizeof(bits_string
), "%s%s%s access%s: %s%s",
140 s_bit
? "S " : "", c_bit
? "C " : "", b_bit
? "B " : "",
141 priv
? "(priv)" : "", acc_r
? "R" : "N", acc_w
? "W " : "O ");
143 bool priv_acc_w
= !ap2
;
144 bool priv_acc_r
= true;
145 bool unpriv_acc_w
= priv_acc_w
;
146 bool unpriv_acc_r
= priv_acc_r
;
150 priv_acc_r
= priv_acc_w
= false;
151 unpriv_acc_r
= unpriv_acc_w
= false;
154 unpriv_acc_r
= unpriv_acc_w
= false;
157 unpriv_acc_w
= false;
163 len
= snprintf(bits_string
, sizeof(bits_string
), "%s%s%s access(priv): %s%s access(unpriv): %s%s",
164 s_bit
? "S " : "", c_bit
? "C " : "", b_bit
? "B " : "", priv_acc_r
? "R" : "N", priv_acc_w
? "W" : "O",
165 unpriv_acc_r
? "R" : "N", unpriv_acc_w
? "W" : "O");
168 if (len
>= sizeof(bits_string
))
174 static const char *l2_desc_bits_to_string(uint32_t l2_desc
, bool afe
)
176 bool c_bit
= !!(l2_desc
& (1 << 3));
177 bool b_bit
= !!(l2_desc
& (1 << 2));
178 bool s_bit
= !!(l2_desc
& (1 << 10));
179 bool ap2
= !!(l2_desc
& (1 << 9));
180 int ap10
= (l2_desc
>> 4) & 3;
182 return desc_bits_to_string(c_bit
, b_bit
, s_bit
, ap2
, ap10
, afe
);
185 static const char *l1_desc_bits_to_string(uint32_t l1_desc
, bool afe
)
187 bool c_bit
= !!(l1_desc
& (1 << 3));
188 bool b_bit
= !!(l1_desc
& (1 << 2));
189 bool s_bit
= !!(l1_desc
& (1 << 16));
190 bool ap2
= !!(l1_desc
& (1 << 15));
191 int ap10
= (l1_desc
>> 10) & 3;
193 return desc_bits_to_string(c_bit
, b_bit
, s_bit
, ap2
, ap10
, afe
);
196 COMMAND_HANDLER(armv7a_mmu_dump_table
)
198 struct target
*target
= get_current_target(CMD_CTX
);
199 struct cortex_a_common
*cortex_a
= target_to_cortex_a(target
);
200 struct armv7a_common
*armv7a
= target_to_armv7a(target
);
201 struct armv7a_mmu_common
*mmu
= &armv7a
->armv7a_mmu
;
202 struct armv7a_cache_common
*cache
= &mmu
->armv7a_cache
;
203 uint32_t *first_lvl_ptbl
;
208 int max_pt_idx
= 4095;
212 return ERROR_COMMAND_SYNTAX_ERROR
;
214 if (!strcmp(CMD_ARGV
[0], "addr")) {
216 return ERROR_COMMAND_SYNTAX_ERROR
;
218 COMMAND_PARSE_NUMBER(target_addr
, CMD_ARGV
[1], ttb
);
221 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[2], max_pt_idx
);
223 if (max_pt_idx
< 1 || max_pt_idx
> 4096)
224 return ERROR_COMMAND_ARGUMENT_INVALID
;
228 if (mmu
->cached
!= 1) {
229 LOG_ERROR("TTB not cached!");
233 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], ttbidx
);
234 if (ttbidx
< 0 || ttbidx
> 1)
235 return ERROR_COMMAND_ARGUMENT_INVALID
;
237 ttb
= mmu
->ttbr
[ttbidx
] & mmu
->ttbr_mask
[ttbidx
];
240 int ttbcr_n
= mmu
->ttbcr
& 0x7;
241 max_pt_idx
= 0x0fff >> ttbcr_n
;
245 LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR
, ttb
);
247 first_lvl_ptbl
= malloc(sizeof(uint32_t)*(max_pt_idx
+1));
248 if (first_lvl_ptbl
== NULL
)
252 * this may or may not be necessary depending on whether
253 * the table walker is configured to use the cache or not.
255 cache
->flush_all_data_cache(target
);
257 retval
= mmu
->read_physical_memory(target
, ttb
, 4, max_pt_idx
+1, (uint8_t *)first_lvl_ptbl
);
258 if (retval
!= ERROR_OK
) {
259 LOG_ERROR("Failed to read first-level page table!");
263 afe
= !!(cortex_a
->cp15_control_reg
& SCTLR_BIT_AFE
);
265 for (pt_idx
= 0; pt_idx
<= max_pt_idx
;) {
266 uint32_t first_lvl_descriptor
= target_buffer_get_u32(target
,
267 (uint8_t *)&first_lvl_ptbl
[pt_idx
]);
269 LOG_DEBUG("L1 desc[%8.8x]: %8.8"PRIx32
, pt_idx
<< 20, first_lvl_descriptor
);
271 /* skip empty entries in the first level table */
272 if ((first_lvl_descriptor
& 3) == 0) {
275 if ((first_lvl_descriptor
& 0x40002) == 2) {
276 /* section descriptor */
277 uint32_t va_range
= 1024*1024-1; /* 1MB range */
278 uint32_t va_start
= pt_idx
<< 20;
279 uint32_t va_end
= va_start
+ va_range
;
281 uint32_t pa_start
= (first_lvl_descriptor
& 0xfff00000);
282 uint32_t pa_end
= pa_start
+ va_range
;
284 LOG_USER("SECT: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
285 va_start
, va_end
, pa_start
, pa_end
, l1_desc_bits_to_string(first_lvl_descriptor
, afe
));
288 if ((first_lvl_descriptor
& 0x40002) == 0x40002) {
289 /* supersection descriptor */
290 uint32_t va_range
= 16*1024*1024-1; /* 16MB range */
291 uint32_t va_start
= pt_idx
<< 20;
292 uint32_t va_end
= va_start
+ va_range
;
294 uint32_t pa_start
= (first_lvl_descriptor
& 0xff000000);
295 uint32_t pa_end
= pa_start
+ va_range
;
297 LOG_USER("SSCT: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
298 va_start
, va_end
, pa_start
, pa_end
, l1_desc_bits_to_string(first_lvl_descriptor
, afe
));
300 /* skip next 15 entries, they're duplicating the first entry */
303 target_addr_t second_lvl_ptbl
= first_lvl_descriptor
& 0xfffffc00;
304 uint32_t second_lvl_descriptor
;
308 /* page table, always 1KB long */
310 retval
= mmu
->read_physical_memory(target
, second_lvl_ptbl
,
311 4, 256, (uint8_t *)pt2
);
312 if (retval
!= ERROR_OK
) {
313 LOG_ERROR("Failed to read second-level page table!");
317 for (pt2_idx
= 0; pt2_idx
< 256; ) {
318 second_lvl_descriptor
= target_buffer_get_u32(target
,
319 (uint8_t *)&pt2
[pt2_idx
]);
321 if ((second_lvl_descriptor
& 3) == 0) {
325 if ((second_lvl_descriptor
& 3) == 1) {
327 uint32_t va_range
= 64*1024-1; /* 64KB range */
328 uint32_t va_start
= (pt_idx
<< 20) + (pt2_idx
<< 12);
329 uint32_t va_end
= va_start
+ va_range
;
331 uint32_t pa_start
= (second_lvl_descriptor
& 0xffff0000);
332 uint32_t pa_end
= pa_start
+ va_range
;
334 LOG_USER("LPGE: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
335 va_start
, va_end
, pa_start
, pa_end
, l2_desc_bits_to_string(second_lvl_descriptor
, afe
));
340 uint32_t va_range
= 4*1024-1; /* 4KB range */
341 uint32_t va_start
= (pt_idx
<< 20) + (pt2_idx
<< 12);
342 uint32_t va_end
= va_start
+ va_range
;
344 uint32_t pa_start
= (second_lvl_descriptor
& 0xfffff000);
345 uint32_t pa_end
= pa_start
+ va_range
;
347 LOG_USER("SPGE: VA[%8.8"PRIx32
" -- %8.8"PRIx32
"]: PA[%8.8"PRIx32
" -- %8.8"PRIx32
"] %s",
348 va_start
, va_end
, pa_start
, pa_end
, l2_desc_bits_to_string(second_lvl_descriptor
, afe
));
358 free(first_lvl_ptbl
);
362 static const struct command_registration armv7a_mmu_group_handlers
[] = {
365 .handler
= armv7a_mmu_dump_table
,
367 .help
= "dump translation table 0, 1 or from <address>",
368 .usage
= "(0|1|addr <address> [num_entries])",
370 COMMAND_REGISTRATION_DONE
373 const struct command_registration armv7a_mmu_command_handlers
[] = {
377 .help
= "mmu command group",
379 .chain
= armv7a_mmu_group_handlers
,
381 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)