jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / target / armv7a_mmu.c
1 /***************************************************************************
2 * Copyright (C) 2016 by Matthias Welwarsky *
3 * matthias.welwarsky@sysgo.com *
4 * *
5 * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
6 * *
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. *
11 * *
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. *
16 * *
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 ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <helper/binarybuffer.h>
26 #include <helper/command.h>
27
28 #include "jtag/interface.h"
29 #include "arm.h"
30 #include "armv7a.h"
31 #include "armv7a_mmu.h"
32 #include "arm_opcodes.h"
33 #include "cortex_a.h"
34
35 #define SCTLR_BIT_AFE (1 << 29)
36
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)
40 {
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;
46 *val = 0xdeadbeef;
47 retval = dpm->prepare(dpm);
48 if (retval != ERROR_OK)
49 goto done;
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),
54 virt);
55 if (retval != ERROR_OK)
56 goto done;
57 retval = dpm->instr_read_data_r0(dpm,
58 ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
59 &value);
60 if (retval != ERROR_OK)
61 goto done;
62
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;
69
70 if (SS) {
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);
77 } else {
78 *val = (value & ~0xfff) + (va & 0xfff);
79 }
80 if (meminfo) {
81 LOG_INFO("%" PRIx32 " : %" TARGET_PRIxADDR " %s outer shareable %s secured %s super section",
82 va, *val,
83 NOS == 1 ? "not" : " ",
84 NS == 1 ? "not" : "",
85 SS == 0 ? "not" : "");
86 switch (OUTER) {
87 case 0:
88 LOG_INFO("outer: Non-Cacheable");
89 break;
90 case 1:
91 LOG_INFO("outer: Write-Back, Write-Allocate");
92 break;
93 case 2:
94 LOG_INFO("outer: Write-Through, No Write-Allocate");
95 break;
96 case 3:
97 LOG_INFO("outer: Write-Back, no Write-Allocate");
98 break;
99 }
100 switch (INNER) {
101 case 0:
102 LOG_INFO("inner: Non-Cacheable");
103 break;
104 case 1:
105 LOG_INFO("inner: Strongly-ordered");
106 break;
107 case 3:
108 LOG_INFO("inner: Device");
109 break;
110 case 5:
111 LOG_INFO("inner: Write-Back, Write-Allocate");
112 break;
113 case 6:
114 LOG_INFO("inner: Write-Through");
115 break;
116 case 7:
117 LOG_INFO("inner: Write-Back, no Write-Allocate");
118 break;
119 default:
120 LOG_INFO("inner: %" PRIx32 " ???", INNER);
121 }
122 }
123
124 done:
125 dpm->finish(dpm);
126
127 return retval;
128 }
129
130 static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe)
131 {
132 static char bits_string[64];
133 unsigned int len;
134
135 if (afe) {
136 bool acc_r = true;
137 bool acc_w = !ap2;
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 ");
142 } else {
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;
147
148 switch (ap10) {
149 case 0:
150 priv_acc_r = priv_acc_w = false;
151 unpriv_acc_r = unpriv_acc_w = false;
152 break;
153 case 1:
154 unpriv_acc_r = unpriv_acc_w = false;
155 break;
156 case 2:
157 unpriv_acc_w = false;
158 break;
159 default:
160 break;
161 }
162
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");
166 }
167
168 if (len >= sizeof(bits_string))
169 bits_string[63] = 0;
170
171 return bits_string;
172 }
173
174 static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe)
175 {
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;
181
182 return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
183 }
184
185 static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe)
186 {
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;
192
193 return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
194 }
195
196 COMMAND_HANDLER(armv7a_mmu_dump_table)
197 {
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;
204 target_addr_t ttb;
205 int ttbidx = 0;
206 int retval;
207 int pt_idx;
208 int max_pt_idx = 4095;
209 bool afe;
210
211 if (CMD_ARGC < 1)
212 return ERROR_COMMAND_SYNTAX_ERROR;
213
214 if (!strcmp(CMD_ARGV[0], "addr")) {
215 if (CMD_ARGC < 2)
216 return ERROR_COMMAND_SYNTAX_ERROR;
217
218 COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb);
219
220 if (CMD_ARGC > 2) {
221 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx);
222
223 if (max_pt_idx < 1 || max_pt_idx > 4096)
224 return ERROR_COMMAND_ARGUMENT_INVALID;
225 max_pt_idx -= 1;
226 }
227 } else {
228 if (mmu->cached != 1) {
229 LOG_ERROR("TTB not cached!");
230 return ERROR_FAIL;
231 }
232
233 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx);
234 if (ttbidx < 0 || ttbidx > 1)
235 return ERROR_COMMAND_ARGUMENT_INVALID;
236
237 ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx];
238
239 if (ttbidx == 0) {
240 int ttbcr_n = mmu->ttbcr & 0x7;
241 max_pt_idx = 0x0fff >> ttbcr_n;
242 }
243 }
244
245 LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb);
246
247 first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1));
248 if (first_lvl_ptbl == NULL)
249 return ERROR_FAIL;
250
251 /*
252 * this may or may not be necessary depending on whether
253 * the table walker is configured to use the cache or not.
254 */
255 cache->flush_all_data_cache(target);
256
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!");
260 return retval;
261 }
262
263 afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE);
264
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]);
268
269 LOG_DEBUG("L1 desc[%8.8x]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor);
270
271 /* skip empty entries in the first level table */
272 if ((first_lvl_descriptor & 3) == 0) {
273 pt_idx++;
274 } else
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;
280
281 uint32_t pa_start = (first_lvl_descriptor & 0xfff00000);
282 uint32_t pa_end = pa_start + va_range;
283
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));
286 pt_idx++;
287 } else
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;
293
294 uint32_t pa_start = (first_lvl_descriptor & 0xff000000);
295 uint32_t pa_end = pa_start + va_range;
296
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));
299
300 /* skip next 15 entries, they're duplicating the first entry */
301 pt_idx += 16;
302 } else {
303 target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00;
304 uint32_t second_lvl_descriptor;
305 uint32_t *pt2;
306 int pt2_idx;
307
308 /* page table, always 1KB long */
309 pt2 = malloc(1024);
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!");
314 return ERROR_FAIL;
315 }
316
317 for (pt2_idx = 0; pt2_idx < 256; ) {
318 second_lvl_descriptor = target_buffer_get_u32(target,
319 (uint8_t *)&pt2[pt2_idx]);
320
321 if ((second_lvl_descriptor & 3) == 0) {
322 /* skip entry */
323 pt2_idx++;
324 } else
325 if ((second_lvl_descriptor & 3) == 1) {
326 /* large page */
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;
330
331 uint32_t pa_start = (second_lvl_descriptor & 0xffff0000);
332 uint32_t pa_end = pa_start + va_range;
333
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));
336
337 pt2_idx += 16;
338 } else {
339 /* small page */
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;
343
344 uint32_t pa_start = (second_lvl_descriptor & 0xfffff000);
345 uint32_t pa_end = pa_start + va_range;
346
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));
349
350 pt2_idx++;
351 }
352 }
353 free(pt2);
354 pt_idx++;
355 }
356 }
357
358 free(first_lvl_ptbl);
359 return ERROR_OK;
360 }
361
362 static const struct command_registration armv7a_mmu_group_handlers[] = {
363 {
364 .name = "dump",
365 .handler = armv7a_mmu_dump_table,
366 .mode = COMMAND_ANY,
367 .help = "dump translation table 0, 1 or from <address>",
368 .usage = "(0|1|addr <address> [num_entries])",
369 },
370 COMMAND_REGISTRATION_DONE
371 };
372
373 const struct command_registration armv7a_mmu_command_handlers[] = {
374 {
375 .name = "mmu",
376 .mode = COMMAND_ANY,
377 .help = "mmu command group",
378 .usage = "",
379 .chain = armv7a_mmu_group_handlers,
380 },
381 COMMAND_REGISTRATION_DONE
382 };

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)