target algo: do not write reg_param if direction is PARAM_IN
[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 /* 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)
39 {
40 uint32_t first_lvl_descriptor = 0x0;
41 uint32_t second_lvl_descriptor = 0x0;
42 int retval;
43 struct armv7a_common *armv7a = target_to_armv7a(target);
44 uint32_t ttbidx = 0; /* default to ttbr0 */
45 uint32_t ttb_mask;
46 uint32_t va_mask;
47 uint32_t ttb;
48
49 if (target->state != TARGET_HALTED)
50 LOG_INFO("target not halted, using cached values for translation table!");
51
52 /* if va is above the range handled by ttbr0, select ttbr1 */
53 if (va > armv7a->armv7a_mmu.ttbr_range[0]) {
54 /* select ttb 1 */
55 ttbidx = 1;
56 }
57
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];
61
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)
68 return retval;
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);
73
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;
78 }
79
80 if ((first_lvl_descriptor & 0x40002) == 2) {
81 /* section descriptor */
82 *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
83 return ERROR_OK;
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;
89 }
90 *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff);
91 return ERROR_OK;
92 }
93
94 /* page table */
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)
99 return retval;
100
101 second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
102 &second_lvl_descriptor);
103
104 LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
105
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;
110 }
111
112 if ((second_lvl_descriptor & 0x3) == 1) {
113 /* large page descriptor */
114 *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
115 } else {
116 /* small page descriptor */
117 *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
118 }
119
120 return ERROR_OK;
121 }
122
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)
126 {
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;
132 *val = 0xdeadbeef;
133 retval = dpm->prepare(dpm);
134 if (retval != ERROR_OK)
135 goto done;
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),
140 virt);
141 if (retval != ERROR_OK)
142 goto done;
143 retval = dpm->instr_read_data_r0(dpm,
144 ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
145 val);
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;
151
152 if (retval != ERROR_OK)
153 goto done;
154 *val = (*val & ~0xfff) + (va & 0xfff);
155 if (*val == va)
156 LOG_WARNING("virt = phys : MMU disable !!");
157 if (meminfo) {
158 LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured",
159 va, *val,
160 NOS == 1 ? "not" : " ",
161 NS == 1 ? "not" : "");
162 switch (OUTER) {
163 case 0:
164 LOG_INFO("outer: Non-Cacheable");
165 break;
166 case 1:
167 LOG_INFO("outer: Write-Back, Write-Allocate");
168 break;
169 case 2:
170 LOG_INFO("outer: Write-Through, No Write-Allocate");
171 break;
172 case 3:
173 LOG_INFO("outer: Write-Back, no Write-Allocate");
174 break;
175 }
176 switch (INNER) {
177 case 0:
178 LOG_INFO("inner: Non-Cacheable");
179 break;
180 case 1:
181 LOG_INFO("inner: Strongly-ordered");
182 break;
183 case 3:
184 LOG_INFO("inner: Device");
185 break;
186 case 5:
187 LOG_INFO("inner: Write-Back, Write-Allocate");
188 break;
189 case 6:
190 LOG_INFO("inner: Write-Through");
191 break;
192 case 7:
193 LOG_INFO("inner: Write-Back, no Write-Allocate");
194 break;
195 default:
196 LOG_INFO("inner: %" PRIx32 " ???", INNER);
197 }
198 }
199
200 done:
201 dpm->finish(dpm);
202
203 return retval;
204 }
205
206 static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe)
207 {
208 static char bits_string[64];
209 unsigned int len;
210
211 if (afe) {
212 bool acc_r = true;
213 bool acc_w = !ap2;
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 ");
218 } else {
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;
223
224 switch (ap10) {
225 case 0:
226 priv_acc_r = priv_acc_w = false;
227 unpriv_acc_r = unpriv_acc_w = false;
228 break;
229 case 1:
230 unpriv_acc_r = unpriv_acc_w = false;
231 break;
232 case 2:
233 unpriv_acc_w = false;
234 break;
235 default:
236 break;
237 }
238
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");
242 }
243
244 if (len >= sizeof(bits_string))
245 bits_string[63] = 0;
246
247 return bits_string;
248 }
249
250 static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe)
251 {
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;
257
258 return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
259 }
260
261 static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe)
262 {
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;
268
269 return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
270 }
271
272 COMMAND_HANDLER(armv7a_mmu_dump_table)
273 {
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;
280 target_addr_t ttb;
281 int ttbidx = 0;
282 int retval;
283 int pt_idx;
284 int max_pt_idx = 4095;
285 bool afe;
286
287 if (CMD_ARGC < 1)
288 return ERROR_COMMAND_SYNTAX_ERROR;
289
290 if (!strcmp(CMD_ARGV[0], "addr")) {
291 if (CMD_ARGC < 2)
292 return ERROR_COMMAND_SYNTAX_ERROR;
293
294 COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb);
295
296 if (CMD_ARGC > 2) {
297 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx);
298
299 if (max_pt_idx < 1 || max_pt_idx > 4096)
300 return ERROR_COMMAND_ARGUMENT_INVALID;
301 max_pt_idx -= 1;
302 }
303 } else {
304 if (mmu->cached != 1) {
305 LOG_ERROR("TTB not cached!");
306 return ERROR_FAIL;
307 }
308
309 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx);
310 if (ttbidx < 0 || ttbidx > 1)
311 return ERROR_COMMAND_ARGUMENT_INVALID;
312
313 ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx];
314
315 if (ttbidx == 0) {
316 int ttbcr_n = mmu->ttbcr & 0x7;
317 max_pt_idx = 0x0fff >> ttbcr_n;
318 }
319 }
320
321 LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb);
322
323 first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1));
324 if (first_lvl_ptbl == NULL)
325 return ERROR_FAIL;
326
327 /*
328 * this may or may not be necessary depending on whether
329 * the table walker is configured to use the cache or not.
330 */
331 cache->flush_all_data_cache(target);
332
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!");
336 return retval;
337 }
338
339 afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE);
340
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]);
344
345 LOG_DEBUG("L1 desc[%8.8"PRIx32"]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor);
346
347 /* skip empty entries in the first level table */
348 if ((first_lvl_descriptor & 3) == 0) {
349 pt_idx++;
350 } else
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;
356
357 uint32_t pa_start = (first_lvl_descriptor & 0xfff00000);
358 uint32_t pa_end = pa_start + va_range;
359
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));
362 pt_idx++;
363 } else
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;
369
370 uint32_t pa_start = (first_lvl_descriptor & 0xff000000);
371 uint32_t pa_end = pa_start + va_range;
372
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));
375
376 /* skip next 15 entries, they're duplicating the first entry */
377 pt_idx += 16;
378 } else {
379 target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00;
380 uint32_t second_lvl_descriptor;
381 uint32_t *pt2;
382 int pt2_idx;
383
384 /* page table, always 1KB long */
385 pt2 = malloc(1024);
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!");
390 return ERROR_FAIL;
391 }
392
393 for (pt2_idx = 0; pt2_idx < 256; ) {
394 second_lvl_descriptor = target_buffer_get_u32(target,
395 (uint8_t *)&pt2[pt2_idx]);
396
397 if ((second_lvl_descriptor & 3) == 0) {
398 /* skip entry */
399 pt2_idx++;
400 } else
401 if ((second_lvl_descriptor & 3) == 1) {
402 /* large page */
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;
406
407 uint32_t pa_start = (second_lvl_descriptor & 0xffff0000);
408 uint32_t pa_end = pa_start + va_range;
409
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));
412
413 pt2_idx += 16;
414 } else {
415 /* small page */
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;
419
420 uint32_t pa_start = (second_lvl_descriptor & 0xfffff000);
421 uint32_t pa_end = pa_start + va_range;
422
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));
425
426 pt2_idx++;
427 }
428 }
429 free(pt2);
430 pt_idx++;
431 }
432 }
433
434 free(first_lvl_ptbl);
435 return ERROR_OK;
436 }
437
438 static const struct command_registration armv7a_mmu_group_handlers[] = {
439 {
440 .name = "dump",
441 .handler = armv7a_mmu_dump_table,
442 .mode = COMMAND_ANY,
443 .help = "dump translation table 0, 1 or from <address>",
444 .usage = "(0|1|addr <address> [num_entries])",
445 },
446 COMMAND_REGISTRATION_DONE
447 };
448
449 const struct command_registration armv7a_mmu_command_handlers[] = {
450 {
451 .name = "mmu",
452 .mode = COMMAND_ANY,
453 .help = "mmu command group",
454 .usage = "",
455 .chain = armv7a_mmu_group_handlers,
456 },
457 COMMAND_REGISTRATION_DONE
458 };

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)