OpenOCD
armv7a_mmu.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2016 by Matthias Welwarsky *
5  * matthias.welwarsky@sysgo.com *
6  * *
7  * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
8  ***************************************************************************/
9 
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13 
14 #include <helper/binarybuffer.h>
15 #include <helper/command.h>
16 
17 #include "jtag/interface.h"
18 #include "arm.h"
19 #include "armv7a.h"
20 #include "armv7a_mmu.h"
21 #include "arm_opcodes.h"
22 #include "cortex_a.h"
23 
24 #define SCTLR_BIT_AFE (1 << 29)
25 
26 /* V7 method VA TO PA */
27 int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
28  target_addr_t *val, int meminfo)
29 {
30  int retval = ERROR_FAIL;
31  struct armv7a_common *armv7a = target_to_armv7a(target);
32  struct arm_dpm *dpm = armv7a->arm.dpm;
33  uint32_t virt = va & ~0xfff, value;
34  uint32_t NOS, NS, INNER, OUTER, SS;
35  *val = 0xdeadbeef;
36  retval = dpm->prepare(dpm);
37  if (retval != ERROR_OK)
38  goto done;
39  /* mmu must be enable in order to get a correct translation
40  * use VA to PA CP15 register for conversion */
41  retval = dpm->instr_write_data_r0(dpm,
42  ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
43  virt);
44  if (retval != ERROR_OK)
45  goto done;
46  retval = dpm->instr_read_data_r0(dpm,
47  ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
48  &value);
49  if (retval != ERROR_OK)
50  goto done;
51 
52  /* decode memory attribute */
53  SS = (value >> 1) & 1;
54  NOS = (value >> 10) & 1; /* Not Outer shareable */
55  NS = (value >> 9) & 1; /* Non secure */
56  INNER = (value >> 4) & 0x7;
57  OUTER = (value >> 2) & 0x3;
58 
59  if (SS) {
60  /* PAR[31:24] contains PA[31:24] */
61  *val = value & 0xff000000;
62  /* PAR [23:16] contains PA[39:32] */
63  *val |= (target_addr_t)(value & 0x00ff0000) << 16;
64  /* PA[23:12] is the same as VA[23:12] */
65  *val |= (va & 0xffffff);
66  } else {
67  *val = (value & ~0xfff) + (va & 0xfff);
68  }
69  if (meminfo) {
70  LOG_INFO("%" PRIx32 " : %" TARGET_PRIxADDR " %s outer shareable %s secured %s super section",
71  va, *val,
72  NOS == 1 ? "not" : " ",
73  NS == 1 ? "not" : "",
74  SS == 0 ? "not" : "");
75  switch (OUTER) {
76  case 0:
77  LOG_INFO("outer: Non-Cacheable");
78  break;
79  case 1:
80  LOG_INFO("outer: Write-Back, Write-Allocate");
81  break;
82  case 2:
83  LOG_INFO("outer: Write-Through, No Write-Allocate");
84  break;
85  case 3:
86  LOG_INFO("outer: Write-Back, no Write-Allocate");
87  break;
88  }
89  switch (INNER) {
90  case 0:
91  LOG_INFO("inner: Non-Cacheable");
92  break;
93  case 1:
94  LOG_INFO("inner: Strongly-ordered");
95  break;
96  case 3:
97  LOG_INFO("inner: Device");
98  break;
99  case 5:
100  LOG_INFO("inner: Write-Back, Write-Allocate");
101  break;
102  case 6:
103  LOG_INFO("inner: Write-Through");
104  break;
105  case 7:
106  LOG_INFO("inner: Write-Back, no Write-Allocate");
107  break;
108  default:
109  LOG_INFO("inner: %" PRIx32 " ???", INNER);
110  }
111  }
112 
113 done:
114  dpm->finish(dpm);
115 
116  return retval;
117 }
118 
119 static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe)
120 {
121  static char bits_string[64];
122  unsigned int len;
123 
124  if (afe) {
125  bool acc_r = true;
126  bool acc_w = !ap2;
127  bool priv = !(ap10 & 2);
128  len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access%s: %s%s",
129  s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "",
130  priv ? "(priv)" : "", acc_r ? "R" : "N", acc_w ? "W " : "O ");
131  } else {
132  bool priv_acc_w = !ap2;
133  bool priv_acc_r = true;
134  bool unpriv_acc_w = priv_acc_w;
135  bool unpriv_acc_r = priv_acc_r;
136 
137  switch (ap10) {
138  case 0:
139  priv_acc_r = priv_acc_w = false;
140  unpriv_acc_r = unpriv_acc_w = false;
141  break;
142  case 1:
143  unpriv_acc_r = unpriv_acc_w = false;
144  break;
145  case 2:
146  unpriv_acc_w = false;
147  break;
148  default:
149  break;
150  }
151 
152  len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access(priv): %s%s access(unpriv): %s%s",
153  s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", priv_acc_r ? "R" : "N", priv_acc_w ? "W" : "O",
154  unpriv_acc_r ? "R" : "N", unpriv_acc_w ? "W" : "O");
155  }
156 
157  if (len >= sizeof(bits_string))
158  bits_string[63] = 0;
159 
160  return bits_string;
161 }
162 
163 static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe)
164 {
165  bool c_bit = !!(l2_desc & (1 << 3));
166  bool b_bit = !!(l2_desc & (1 << 2));
167  bool s_bit = !!(l2_desc & (1 << 10));
168  bool ap2 = !!(l2_desc & (1 << 9));
169  int ap10 = (l2_desc >> 4) & 3;
170 
171  return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
172 }
173 
174 static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe)
175 {
176  bool c_bit = !!(l1_desc & (1 << 3));
177  bool b_bit = !!(l1_desc & (1 << 2));
178  bool s_bit = !!(l1_desc & (1 << 16));
179  bool ap2 = !!(l1_desc & (1 << 15));
180  int ap10 = (l1_desc >> 10) & 3;
181 
182  return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
183 }
184 
185 COMMAND_HANDLER(armv7a_mmu_dump_table)
186 {
188  struct cortex_a_common *cortex_a = target_to_cortex_a(target);
189  struct armv7a_common *armv7a = target_to_armv7a(target);
190  struct armv7a_mmu_common *mmu = &armv7a->armv7a_mmu;
191  struct armv7a_cache_common *cache = &mmu->armv7a_cache;
192  uint32_t *first_lvl_ptbl;
193  target_addr_t ttb;
194  int ttbidx = 0;
195  int retval;
196  int pt_idx;
197  int max_pt_idx = 4095;
198  bool afe;
199 
200  if (CMD_ARGC < 1)
202 
203  if (!strcmp(CMD_ARGV[0], "addr")) {
204  if (CMD_ARGC < 2)
206 
207  COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb);
208 
209  if (CMD_ARGC > 2) {
210  COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx);
211 
212  if (max_pt_idx < 1 || max_pt_idx > 4096)
214  max_pt_idx -= 1;
215  }
216  } else {
217  if (mmu->cached != 1) {
218  LOG_ERROR("TTB not cached!");
219  return ERROR_FAIL;
220  }
221 
222  COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx);
223  if (ttbidx < 0 || ttbidx > 1)
225 
226  ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx];
227 
228  if (ttbidx == 0) {
229  int ttbcr_n = mmu->ttbcr & 0x7;
230  max_pt_idx = 0x0fff >> ttbcr_n;
231  }
232  }
233 
234  LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb);
235 
236  first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1));
237  if (!first_lvl_ptbl)
238  return ERROR_FAIL;
239 
240  /*
241  * this may or may not be necessary depending on whether
242  * the table walker is configured to use the cache or not.
243  */
245 
246  retval = mmu->read_physical_memory(target, ttb, 4, max_pt_idx+1, (uint8_t *)first_lvl_ptbl);
247  if (retval != ERROR_OK) {
248  LOG_ERROR("Failed to read first-level page table!");
249  return retval;
250  }
251 
252  afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE);
253 
254  for (pt_idx = 0; pt_idx <= max_pt_idx;) {
255  uint32_t first_lvl_descriptor = target_buffer_get_u32(target,
256  (uint8_t *)&first_lvl_ptbl[pt_idx]);
257 
258  LOG_DEBUG("L1 desc[%8.8x]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor);
259 
260  /* skip empty entries in the first level table */
261  if ((first_lvl_descriptor & 3) == 0) {
262  pt_idx++;
263  } else
264  if ((first_lvl_descriptor & 0x40002) == 2) {
265  /* section descriptor */
266  uint32_t va_range = 1024*1024-1; /* 1MB range */
267  uint32_t va_start = pt_idx << 20;
268  uint32_t va_end = va_start + va_range;
269 
270  uint32_t pa_start = (first_lvl_descriptor & 0xfff00000);
271  uint32_t pa_end = pa_start + va_range;
272 
273  LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
274  va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
275  pt_idx++;
276  } else
277  if ((first_lvl_descriptor & 0x40002) == 0x40002) {
278  /* supersection descriptor */
279  uint32_t va_range = 16*1024*1024-1; /* 16MB range */
280  uint32_t va_start = pt_idx << 20;
281  uint32_t va_end = va_start + va_range;
282 
283  uint32_t pa_start = (first_lvl_descriptor & 0xff000000);
284  uint32_t pa_end = pa_start + va_range;
285 
286  LOG_USER("SSCT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
287  va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
288 
289  /* skip next 15 entries, they're duplicating the first entry */
290  pt_idx += 16;
291  } else {
292  target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00;
293  uint32_t second_lvl_descriptor;
294  uint32_t *pt2;
295  int pt2_idx;
296 
297  /* page table, always 1KB long */
298  pt2 = malloc(1024);
299  retval = mmu->read_physical_memory(target, second_lvl_ptbl,
300  4, 256, (uint8_t *)pt2);
301  if (retval != ERROR_OK) {
302  LOG_ERROR("Failed to read second-level page table!");
303  return ERROR_FAIL;
304  }
305 
306  for (pt2_idx = 0; pt2_idx < 256; ) {
307  second_lvl_descriptor = target_buffer_get_u32(target,
308  (uint8_t *)&pt2[pt2_idx]);
309 
310  if ((second_lvl_descriptor & 3) == 0) {
311  /* skip entry */
312  pt2_idx++;
313  } else
314  if ((second_lvl_descriptor & 3) == 1) {
315  /* large page */
316  uint32_t va_range = 64*1024-1; /* 64KB range */
317  uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
318  uint32_t va_end = va_start + va_range;
319 
320  uint32_t pa_start = (second_lvl_descriptor & 0xffff0000);
321  uint32_t pa_end = pa_start + va_range;
322 
323  LOG_USER("LPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
324  va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
325 
326  pt2_idx += 16;
327  } else {
328  /* small page */
329  uint32_t va_range = 4*1024-1; /* 4KB range */
330  uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
331  uint32_t va_end = va_start + va_range;
332 
333  uint32_t pa_start = (second_lvl_descriptor & 0xfffff000);
334  uint32_t pa_end = pa_start + va_range;
335 
336  LOG_USER("SPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
337  va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
338 
339  pt2_idx++;
340  }
341  }
342  free(pt2);
343  pt_idx++;
344  }
345  }
346 
347  free(first_lvl_ptbl);
348  return ERROR_OK;
349 }
350 
351 static const struct command_registration armv7a_mmu_group_handlers[] = {
352  {
353  .name = "dump",
354  .handler = armv7a_mmu_dump_table,
355  .mode = COMMAND_ANY,
356  .help = "dump translation table 0, 1 or from <address>",
357  .usage = "(0|1|addr <address> [num_entries])",
358  },
360 };
361 
363  {
364  .name = "mmu",
365  .mode = COMMAND_ANY,
366  .help = "mmu command group",
367  .usage = "",
368  .chain = armv7a_mmu_group_handlers,
369  },
371 };
Holds the interface to ARM cores.
Macros used to generate various ARM or Thumb opcodes.
#define ARMV4_5_MRC(cp, op1, rd, crn, crm, op2)
Definition: arm_opcodes.h:186
#define ARMV4_5_MCR(cp, op1, rd, crn, crm, op2)
Definition: arm_opcodes.h:209
static struct armv7a_common * target_to_armv7a(struct target *target)
Definition: armv7a.h:122
COMMAND_HANDLER(armv7a_mmu_dump_table)
Definition: armv7a_mmu.c:185
#define SCTLR_BIT_AFE
Definition: armv7a_mmu.c:24
const struct command_registration armv7a_mmu_command_handlers[]
Definition: armv7a_mmu.c:362
static const char * l1_desc_bits_to_string(uint32_t l1_desc, bool afe)
Definition: armv7a_mmu.c:174
int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, target_addr_t *val, int meminfo)
Definition: armv7a_mmu.c:27
static const struct command_registration armv7a_mmu_group_handlers[]
Definition: armv7a_mmu.c:351
static const char * desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe)
Definition: armv7a_mmu.c:119
static const char * l2_desc_bits_to_string(uint32_t l2_desc, bool afe)
Definition: armv7a_mmu.c:163
Support functions to access arbitrary bits in a byte array.
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define COMMAND_PARSE_NUMBER(type, in, out)
parses the string in into out as a type, or prints a command error and passes the error code to the c...
Definition: command.h:442
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
Definition: command.h:146
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:253
#define ERROR_COMMAND_ARGUMENT_INVALID
Definition: command.h:404
@ COMMAND_ANY
Definition: command.h:42
static struct cortex_a_common * target_to_cortex_a(struct target *target)
Definition: cortex_a.h:104
static struct esp_usb_jtag * priv
Definition: esp_usb_jtag.c:219
#define LOG_USER(expr ...)
Definition: log.h:135
#define ERROR_FAIL
Definition: log.h:170
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_INFO(expr ...)
Definition: log.h:126
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
This wraps an implementation of DPM primitives.
Definition: arm_dpm.h:47
int(* instr_write_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data)
Runs one instruction, writing data to R0 before execution.
Definition: arm_dpm.h:72
int(* finish)(struct arm_dpm *dpm)
Invoke after a series of instruction operations.
Definition: arm_dpm.h:57
int(* prepare)(struct arm_dpm *dpm)
Invoke before a series of instruction operations.
Definition: arm_dpm.h:54
int(* instr_read_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data)
Runs one instruction, reading data from r0 after execution.
Definition: arm_dpm.h:98
struct arm_dpm * dpm
Handle for the debug module, if one is present.
Definition: arm.h:212
int(* flush_all_data_cache)(struct target *target)
Definition: armv7a.h:72
struct arm arm
Definition: armv7a.h:92
struct armv7a_mmu_common armv7a_mmu
Definition: armv7a.h:113
struct armv7a_cache_common armv7a_cache
Definition: armv7a.h:85
int32_t cached
Definition: armv7a.h:77
int(* read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
Definition: armv7a.h:83
uint32_t ttbr[2]
Definition: armv7a.h:79
uint32_t ttbr_mask[2]
Definition: armv7a.h:80
uint32_t ttbcr
Definition: armv7a.h:78
const char * name
Definition: command.h:235
uint32_t cp15_control_reg
Definition: cortex_a.h:78
Definition: target.h:116
struct target * get_current_target(struct command_context *cmd_ctx)
Definition: target.c:458
uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
Definition: target.c:316
uint64_t target_addr_t
Definition: types.h:335
#define TARGET_PRIxADDR
Definition: types.h:340
@ SS
Definition: x86_32_common.h:73