armv7a_mmu: Add support for decoding Super Sections
[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 #if !BUILD_TARGET64
66 if (SS) {
67 LOG_ERROR("Super section found with no-64 bit address support");
68 return ERROR_FAIL;
69 }
70 #endif
71 NOS = (value >> 10) & 1; /* Not Outer shareable */
72 NS = (value >> 9) & 1; /* Non secure */
73 INNER = (value >> 4) & 0x7;
74 OUTER = (value >> 2) & 0x3;
75
76 if (SS) {
77 /* PAR[31:24] contains PA[31:24] */
78 *val = value & 0xff000000;
79 /* PAR [23:16] contains PA[39:32] */
80 *val |= (target_addr_t)(value & 0x00ff0000) << 16;
81 /* PA[23:12] is the same as VA[23:12] */
82 *val |= (va & 0xffffff);
83 } else {
84 *val = (value & ~0xfff) + (va & 0xfff);
85 }
86 if (meminfo) {
87 LOG_INFO("%" PRIx32 " : %" TARGET_PRIxADDR " %s outer shareable %s secured %s super section",
88 va, *val,
89 NOS == 1 ? "not" : " ",
90 NS == 1 ? "not" : "",
91 SS == 0 ? "not" : "");
92 switch (OUTER) {
93 case 0:
94 LOG_INFO("outer: Non-Cacheable");
95 break;
96 case 1:
97 LOG_INFO("outer: Write-Back, Write-Allocate");
98 break;
99 case 2:
100 LOG_INFO("outer: Write-Through, No Write-Allocate");
101 break;
102 case 3:
103 LOG_INFO("outer: Write-Back, no Write-Allocate");
104 break;
105 }
106 switch (INNER) {
107 case 0:
108 LOG_INFO("inner: Non-Cacheable");
109 break;
110 case 1:
111 LOG_INFO("inner: Strongly-ordered");
112 break;
113 case 3:
114 LOG_INFO("inner: Device");
115 break;
116 case 5:
117 LOG_INFO("inner: Write-Back, Write-Allocate");
118 break;
119 case 6:
120 LOG_INFO("inner: Write-Through");
121 break;
122 case 7:
123 LOG_INFO("inner: Write-Back, no Write-Allocate");
124 break;
125 default:
126 LOG_INFO("inner: %" PRIx32 " ???", INNER);
127 }
128 }
129
130 done:
131 dpm->finish(dpm);
132
133 return retval;
134 }
135
136 static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe)
137 {
138 static char bits_string[64];
139 unsigned int len;
140
141 if (afe) {
142 bool acc_r = true;
143 bool acc_w = !ap2;
144 bool priv = !(ap10 & 2);
145 len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access%s: %s%s",
146 s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "",
147 priv ? "(priv)" : "", acc_r ? "R" : "N", acc_w ? "W " : "O ");
148 } else {
149 bool priv_acc_w = !ap2;
150 bool priv_acc_r = true;
151 bool unpriv_acc_w = priv_acc_w;
152 bool unpriv_acc_r = priv_acc_r;
153
154 switch (ap10) {
155 case 0:
156 priv_acc_r = priv_acc_w = false;
157 unpriv_acc_r = unpriv_acc_w = false;
158 break;
159 case 1:
160 unpriv_acc_r = unpriv_acc_w = false;
161 break;
162 case 2:
163 unpriv_acc_w = false;
164 break;
165 default:
166 break;
167 }
168
169 len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access(priv): %s%s access(unpriv): %s%s",
170 s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", priv_acc_r ? "R" : "N", priv_acc_w ? "W" : "O",
171 unpriv_acc_r ? "R" : "N", unpriv_acc_w ? "W" : "O");
172 }
173
174 if (len >= sizeof(bits_string))
175 bits_string[63] = 0;
176
177 return bits_string;
178 }
179
180 static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe)
181 {
182 bool c_bit = !!(l2_desc & (1 << 3));
183 bool b_bit = !!(l2_desc & (1 << 2));
184 bool s_bit = !!(l2_desc & (1 << 10));
185 bool ap2 = !!(l2_desc & (1 << 9));
186 int ap10 = (l2_desc >> 4) & 3;
187
188 return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
189 }
190
191 static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe)
192 {
193 bool c_bit = !!(l1_desc & (1 << 3));
194 bool b_bit = !!(l1_desc & (1 << 2));
195 bool s_bit = !!(l1_desc & (1 << 16));
196 bool ap2 = !!(l1_desc & (1 << 15));
197 int ap10 = (l1_desc >> 10) & 3;
198
199 return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
200 }
201
202 COMMAND_HANDLER(armv7a_mmu_dump_table)
203 {
204 struct target *target = get_current_target(CMD_CTX);
205 struct cortex_a_common *cortex_a = target_to_cortex_a(target);
206 struct armv7a_common *armv7a = target_to_armv7a(target);
207 struct armv7a_mmu_common *mmu = &armv7a->armv7a_mmu;
208 struct armv7a_cache_common *cache = &mmu->armv7a_cache;
209 uint32_t *first_lvl_ptbl;
210 target_addr_t ttb;
211 int ttbidx = 0;
212 int retval;
213 int pt_idx;
214 int max_pt_idx = 4095;
215 bool afe;
216
217 if (CMD_ARGC < 1)
218 return ERROR_COMMAND_SYNTAX_ERROR;
219
220 if (!strcmp(CMD_ARGV[0], "addr")) {
221 if (CMD_ARGC < 2)
222 return ERROR_COMMAND_SYNTAX_ERROR;
223
224 COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb);
225
226 if (CMD_ARGC > 2) {
227 COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx);
228
229 if (max_pt_idx < 1 || max_pt_idx > 4096)
230 return ERROR_COMMAND_ARGUMENT_INVALID;
231 max_pt_idx -= 1;
232 }
233 } else {
234 if (mmu->cached != 1) {
235 LOG_ERROR("TTB not cached!");
236 return ERROR_FAIL;
237 }
238
239 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx);
240 if (ttbidx < 0 || ttbidx > 1)
241 return ERROR_COMMAND_ARGUMENT_INVALID;
242
243 ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx];
244
245 if (ttbidx == 0) {
246 int ttbcr_n = mmu->ttbcr & 0x7;
247 max_pt_idx = 0x0fff >> ttbcr_n;
248 }
249 }
250
251 LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb);
252
253 first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1));
254 if (first_lvl_ptbl == NULL)
255 return ERROR_FAIL;
256
257 /*
258 * this may or may not be necessary depending on whether
259 * the table walker is configured to use the cache or not.
260 */
261 cache->flush_all_data_cache(target);
262
263 retval = mmu->read_physical_memory(target, ttb, 4, max_pt_idx+1, (uint8_t *)first_lvl_ptbl);
264 if (retval != ERROR_OK) {
265 LOG_ERROR("Failed to read first-level page table!");
266 return retval;
267 }
268
269 afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE);
270
271 for (pt_idx = 0; pt_idx <= max_pt_idx;) {
272 uint32_t first_lvl_descriptor = target_buffer_get_u32(target,
273 (uint8_t *)&first_lvl_ptbl[pt_idx]);
274
275 LOG_DEBUG("L1 desc[%8.8"PRIx32"]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor);
276
277 /* skip empty entries in the first level table */
278 if ((first_lvl_descriptor & 3) == 0) {
279 pt_idx++;
280 } else
281 if ((first_lvl_descriptor & 0x40002) == 2) {
282 /* section descriptor */
283 uint32_t va_range = 1024*1024-1; /* 1MB range */
284 uint32_t va_start = pt_idx << 20;
285 uint32_t va_end = va_start + va_range;
286
287 uint32_t pa_start = (first_lvl_descriptor & 0xfff00000);
288 uint32_t pa_end = pa_start + va_range;
289
290 LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
291 va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
292 pt_idx++;
293 } else
294 if ((first_lvl_descriptor & 0x40002) == 0x40002) {
295 /* supersection descriptor */
296 uint32_t va_range = 16*1024*1024-1; /* 16MB range */
297 uint32_t va_start = pt_idx << 20;
298 uint32_t va_end = va_start + va_range;
299
300 uint32_t pa_start = (first_lvl_descriptor & 0xff000000);
301 uint32_t pa_end = pa_start + va_range;
302
303 LOG_USER("SSCT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
304 va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
305
306 /* skip next 15 entries, they're duplicating the first entry */
307 pt_idx += 16;
308 } else {
309 target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00;
310 uint32_t second_lvl_descriptor;
311 uint32_t *pt2;
312 int pt2_idx;
313
314 /* page table, always 1KB long */
315 pt2 = malloc(1024);
316 retval = mmu->read_physical_memory(target, second_lvl_ptbl,
317 4, 256, (uint8_t *)pt2);
318 if (retval != ERROR_OK) {
319 LOG_ERROR("Failed to read second-level page table!");
320 return ERROR_FAIL;
321 }
322
323 for (pt2_idx = 0; pt2_idx < 256; ) {
324 second_lvl_descriptor = target_buffer_get_u32(target,
325 (uint8_t *)&pt2[pt2_idx]);
326
327 if ((second_lvl_descriptor & 3) == 0) {
328 /* skip entry */
329 pt2_idx++;
330 } else
331 if ((second_lvl_descriptor & 3) == 1) {
332 /* large page */
333 uint32_t va_range = 64*1024-1; /* 64KB range */
334 uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
335 uint32_t va_end = va_start + va_range;
336
337 uint32_t pa_start = (second_lvl_descriptor & 0xffff0000);
338 uint32_t pa_end = pa_start + va_range;
339
340 LOG_USER("LPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
341 va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
342
343 pt2_idx += 16;
344 } else {
345 /* small page */
346 uint32_t va_range = 4*1024-1; /* 4KB range */
347 uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
348 uint32_t va_end = va_start + va_range;
349
350 uint32_t pa_start = (second_lvl_descriptor & 0xfffff000);
351 uint32_t pa_end = pa_start + va_range;
352
353 LOG_USER("SPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
354 va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
355
356 pt2_idx++;
357 }
358 }
359 free(pt2);
360 pt_idx++;
361 }
362 }
363
364 free(first_lvl_ptbl);
365 return ERROR_OK;
366 }
367
368 static const struct command_registration armv7a_mmu_group_handlers[] = {
369 {
370 .name = "dump",
371 .handler = armv7a_mmu_dump_table,
372 .mode = COMMAND_ANY,
373 .help = "dump translation table 0, 1 or from <address>",
374 .usage = "(0|1|addr <address> [num_entries])",
375 },
376 COMMAND_REGISTRATION_DONE
377 };
378
379 const struct command_registration armv7a_mmu_command_handlers[] = {
380 {
381 .name = "mmu",
382 .mode = COMMAND_ANY,
383 .help = "mmu command group",
384 .usage = "",
385 .chain = armv7a_mmu_group_handlers,
386 },
387 COMMAND_REGISTRATION_DONE
388 };