23d201f7bc0f5945a1cfb41691c5dade1ec3009c
[fw/openocd] / 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 };