armv7a: ARMv7-A MMU tools 27/4327/19
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>
Thu, 14 Jul 2016 19:00:59 +0000 (21:00 +0200)
committerMatthias Welwarsky <matthias@welwarsky.de>
Thu, 8 Nov 2018 09:10:09 +0000 (09:10 +0000)
factor out mmu-related code from armv7a.c, add a 'dump' command for
page tables.

Change-Id: Ic1ac3c645d7fd097e9d625c7c8302e7065875dd4
Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com>
Reviewed-on: http://openocd.zylin.com/4327
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
doc/openocd.texi
src/target/Makefile.am
src/target/armv7a.c
src/target/armv7a.h
src/target/armv7a_mmu.c [new file with mode: 0644]
src/target/armv7a_mmu.h [new file with mode: 0644]
src/target/cortex_a.c

index ac81b35ed3949d4960a92729c4b9becad57dea7d..e7d0c67c56fec1d3cf95718ec671efaaa11ffc33 100644 (file)
@@ -8766,6 +8766,12 @@ Selects whether interrupts will be processed when single stepping
 configure l2x cache
 @end deffn
 
+@deffn Command {cortex_a mmu dump} [@option{0}|@option{1}|@option{addr} address [@option{num_entries}]]
+Dump the MMU translation table from TTB0 or TTB1 register, or from physical
+memory location @var{address}. When dumping the table from @var{address}, print at most
+@var{num_entries} page table entries. @var{num_entries} is optional, if omitted, the maximum
+possible (4096) entries are printed.
+@end deffn
 
 @subsection ARMv7-R specific commands
 @cindex Cortex-R
index 05f174870015938ee355d0c94ccf83c1f2d20c87..8e9fcb27e81da7b40239bdeccfc975603cf6d59d 100644 (file)
@@ -75,6 +75,7 @@ ARMV7_SRC = \
        %D%/armv7m_trace.c \
        %D%/cortex_m.c \
        %D%/armv7a.c \
+       %D%/armv7a_mmu.c \
        %D%/cortex_a.c \
        %D%/ls1_sap.c \
        %D%/mem_ap.c
@@ -152,6 +153,7 @@ ESIRISC_SRC = \
        %D%/arm_adi_v5.h \
        %D%/armv7a_cache.h \
        %D%/armv7a_cache_l2x.h \
+       %D%/armv7a_mmu.h \
        %D%/arm_disassembler.h \
        %D%/arm_opcodes.h \
        %D%/arm_simulator.h \
index eecfa70976af0ed0ff3ca50788965701c6af0796..f9594c9c3706c30e1102b54a3e567d167bbc72b8 100644 (file)
@@ -24,6 +24,7 @@
 #include <helper/replacements.h>
 
 #include "armv7a.h"
+#include "armv7a_mmu.h"
 #include "arm_disassembler.h"
 
 #include "register.h"
@@ -188,174 +189,6 @@ done:
        return retval;
 }
 
-/*  method adapted to Cortex-A : reused ARM v4 v5 method */
-int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val)
-{
-       uint32_t first_lvl_descriptor = 0x0;
-       uint32_t second_lvl_descriptor = 0x0;
-       int retval;
-       struct armv7a_common *armv7a = target_to_armv7a(target);
-       uint32_t ttbidx = 0;    /*  default to ttbr0 */
-       uint32_t ttb_mask;
-       uint32_t va_mask;
-       uint32_t ttb;
-
-       if (target->state != TARGET_HALTED)
-               LOG_INFO("target not halted, using cached values for translation table!");
-
-       /* if va is above the range handled by ttbr0, select ttbr1 */
-       if (va > armv7a->armv7a_mmu.ttbr_range[0]) {
-               /*  select ttb 1 */
-               ttbidx = 1;
-       }
-
-       ttb = armv7a->armv7a_mmu.ttbr[ttbidx];
-       ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx];
-       va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx];
-
-       LOG_DEBUG("ttb_mask %" PRIx32 " va_mask %" PRIx32 " ttbidx %i",
-                 ttb_mask, va_mask, ttbidx);
-       retval = armv7a->armv7a_mmu.read_physical_memory(target,
-                       (ttb & ttb_mask) | ((va & va_mask) >> 18),
-                       4, 1, (uint8_t *)&first_lvl_descriptor);
-       if (retval != ERROR_OK)
-               return retval;
-       first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
-                       &first_lvl_descriptor);
-       /*  reuse armv4_5 piece of code, specific armv7a changes may come later */
-       LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
-
-       if ((first_lvl_descriptor & 0x3) == 0) {
-               LOG_ERROR("Address translation failure");
-               return ERROR_TARGET_TRANSLATION_FAULT;
-       }
-
-
-       if ((first_lvl_descriptor & 0x40002) == 2) {
-               /* section descriptor */
-               *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
-               return ERROR_OK;
-       } else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
-               /* supersection descriptor */
-               if (first_lvl_descriptor & 0x00f001e0) {
-                       LOG_ERROR("Physical address does not fit into 32 bits");
-                       return ERROR_TARGET_TRANSLATION_FAULT;
-               }
-               *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff);
-               return ERROR_OK;
-       }
-
-       /* page table */
-       retval = armv7a->armv7a_mmu.read_physical_memory(target,
-                       (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
-                       4, 1, (uint8_t *)&second_lvl_descriptor);
-       if (retval != ERROR_OK)
-               return retval;
-
-       second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
-                       &second_lvl_descriptor);
-
-       LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
-
-       if ((second_lvl_descriptor & 0x3) == 0) {
-               LOG_ERROR("Address translation failure");
-               return ERROR_TARGET_TRANSLATION_FAULT;
-       }
-
-       if ((second_lvl_descriptor & 0x3) == 1) {
-               /* large page descriptor */
-               *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
-       } else {
-               /* small page descriptor */
-               *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
-       }
-
-       return ERROR_OK;
-}
-
-/*  V7 method VA TO PA  */
-int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
-       uint32_t *val, int meminfo)
-{
-       int retval = ERROR_FAIL;
-       struct armv7a_common *armv7a = target_to_armv7a(target);
-       struct arm_dpm *dpm = armv7a->arm.dpm;
-       uint32_t virt = va & ~0xfff;
-       uint32_t NOS, NS, INNER, OUTER;
-       *val = 0xdeadbeef;
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-       /*  mmu must be enable in order to get a correct translation
-        *  use VA to PA CP15 register for conversion */
-       retval = dpm->instr_write_data_r0(dpm,
-                       ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
-                       virt);
-       if (retval != ERROR_OK)
-               goto done;
-       retval = dpm->instr_read_data_r0(dpm,
-                       ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
-                       val);
-       /* decode memory attribute */
-       NOS = (*val >> 10) & 1; /*  Not Outer shareable */
-       NS = (*val >> 9) & 1;   /* Non secure */
-       INNER = (*val >> 4) &  0x7;
-       OUTER = (*val >> 2) & 0x3;
-
-       if (retval != ERROR_OK)
-               goto done;
-       *val = (*val & ~0xfff)  +  (va & 0xfff);
-       if (*val == va)
-               LOG_WARNING("virt = phys  : MMU disable !!");
-       if (meminfo) {
-               LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured",
-                       va, *val,
-                       NOS == 1 ? "not" : " ",
-                       NS == 1 ? "not" : "");
-               switch (OUTER) {
-                       case 0:
-                               LOG_INFO("outer: Non-Cacheable");
-                               break;
-                       case 1:
-                               LOG_INFO("outer: Write-Back, Write-Allocate");
-                               break;
-                       case 2:
-                               LOG_INFO("outer: Write-Through, No Write-Allocate");
-                               break;
-                       case 3:
-                               LOG_INFO("outer: Write-Back, no Write-Allocate");
-                               break;
-               }
-               switch (INNER) {
-                       case 0:
-                               LOG_INFO("inner: Non-Cacheable");
-                               break;
-                       case 1:
-                               LOG_INFO("inner: Strongly-ordered");
-                               break;
-                       case 3:
-                               LOG_INFO("inner: Device");
-                               break;
-                       case 5:
-                               LOG_INFO("inner: Write-Back, Write-Allocate");
-                               break;
-                       case 6:
-                               LOG_INFO("inner:  Write-Through");
-                               break;
-                       case 7:
-                               LOG_INFO("inner: Write-Back, no Write-Allocate");
-                               break;
-                       default:
-                               LOG_INFO("inner: %" PRIx32 " ???", INNER);
-               }
-       }
-
-done:
-       dpm->finish(dpm);
-
-       return retval;
-}
-
 /* FIXME: remove it */
 static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
 {
index cf938809a221781a986bf4d004a78532d64c0032..1e88c98cf774e631d081e42855d2d96d7a446803 100644 (file)
@@ -186,9 +186,6 @@ static inline bool is_armv7a(struct armv7a_common *armv7a)
 int armv7a_arch_state(struct target *target);
 int armv7a_identify_cache(struct target *target);
 int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a);
-int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
-               uint32_t *val, int meminfo);
-int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val);
 
 int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
                struct armv7a_cache_common *armv7a_cache);
diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c
new file mode 100644 (file)
index 0000000..eed73ee
--- /dev/null
@@ -0,0 +1,456 @@
+/***************************************************************************
+ *   Copyright (C) 2016 by Matthias Welwarsky                              *
+ *   matthias.welwarsky@sysgo.com                                          *
+ *                                                                         *
+ *   Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com        *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/binarybuffer.h>
+#include <helper/command.h>
+
+#include "jtag/interface.h"
+#include "arm.h"
+#include "armv7a.h"
+#include "armv7a_mmu.h"
+#include "arm_opcodes.h"
+#include "cortex_a.h"
+
+#define SCTLR_BIT_AFE (1 << 29)
+
+/*  method adapted to Cortex-A : reused ARM v4 v5 method */
+int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val)
+{
+       uint32_t first_lvl_descriptor = 0x0;
+       uint32_t second_lvl_descriptor = 0x0;
+       int retval;
+       struct armv7a_common *armv7a = target_to_armv7a(target);
+       uint32_t ttbidx = 0;    /*  default to ttbr0 */
+       uint32_t ttb_mask;
+       uint32_t va_mask;
+       uint32_t ttb;
+
+       if (target->state != TARGET_HALTED)
+               LOG_INFO("target not halted, using cached values for translation table!");
+
+       /* if va is above the range handled by ttbr0, select ttbr1 */
+       if (va > armv7a->armv7a_mmu.ttbr_range[0]) {
+               /*  select ttb 1 */
+               ttbidx = 1;
+       }
+
+       ttb = armv7a->armv7a_mmu.ttbr[ttbidx];
+       ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx];
+       va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx];
+
+       LOG_DEBUG("ttb_mask %" PRIx32 " va_mask %" PRIx32 " ttbidx %i",
+                 ttb_mask, va_mask, ttbidx);
+       retval = armv7a->armv7a_mmu.read_physical_memory(target,
+                       (ttb & ttb_mask) | ((va & va_mask) >> 18),
+                       4, 1, (uint8_t *)&first_lvl_descriptor);
+       if (retval != ERROR_OK)
+               return retval;
+       first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
+                       &first_lvl_descriptor);
+       /*  reuse armv4_5 piece of code, specific armv7a changes may come later */
+       LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
+
+       if ((first_lvl_descriptor & 0x3) == 0) {
+               LOG_ERROR("Address translation failure");
+               return ERROR_TARGET_TRANSLATION_FAULT;
+       }
+
+       if ((first_lvl_descriptor & 0x40002) == 2) {
+               /* section descriptor */
+               *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
+               return ERROR_OK;
+       } else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
+               /* supersection descriptor */
+               if (first_lvl_descriptor & 0x00f001e0) {
+                       LOG_ERROR("Physical address does not fit into 32 bits");
+                       return ERROR_TARGET_TRANSLATION_FAULT;
+               }
+               *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff);
+               return ERROR_OK;
+       }
+
+       /* page table */
+       retval = armv7a->armv7a_mmu.read_physical_memory(target,
+                       (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
+                       4, 1, (uint8_t *)&second_lvl_descriptor);
+       if (retval != ERROR_OK)
+               return retval;
+
+       second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
+                       &second_lvl_descriptor);
+
+       LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
+
+       if ((second_lvl_descriptor & 0x3) == 0) {
+               LOG_ERROR("Address translation failure");
+               return ERROR_TARGET_TRANSLATION_FAULT;
+       }
+
+       if ((second_lvl_descriptor & 0x3) == 1) {
+               /* large page descriptor */
+               *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
+       } else {
+               /* small page descriptor */
+               *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
+       }
+
+       return ERROR_OK;
+}
+
+/*  V7 method VA TO PA  */
+int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
+       uint32_t *val, int meminfo)
+{
+       int retval = ERROR_FAIL;
+       struct armv7a_common *armv7a = target_to_armv7a(target);
+       struct arm_dpm *dpm = armv7a->arm.dpm;
+       uint32_t virt = va & ~0xfff;
+       uint32_t NOS, NS, INNER, OUTER;
+       *val = 0xdeadbeef;
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+       /*  mmu must be enable in order to get a correct translation
+        *  use VA to PA CP15 register for conversion */
+       retval = dpm->instr_write_data_r0(dpm,
+                       ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
+                       virt);
+       if (retval != ERROR_OK)
+               goto done;
+       retval = dpm->instr_read_data_r0(dpm,
+                       ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
+                       val);
+       /* decode memory attribute */
+       NOS = (*val >> 10) & 1; /*  Not Outer shareable */
+       NS = (*val >> 9) & 1;   /* Non secure */
+       INNER = (*val >> 4) &  0x7;
+       OUTER = (*val >> 2) & 0x3;
+
+       if (retval != ERROR_OK)
+               goto done;
+       *val = (*val & ~0xfff)  +  (va & 0xfff);
+       if (*val == va)
+               LOG_WARNING("virt = phys  : MMU disable !!");
+       if (meminfo) {
+               LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured",
+                       va, *val,
+                       NOS == 1 ? "not" : " ",
+                       NS == 1 ? "not" : "");
+               switch (OUTER) {
+                       case 0:
+                               LOG_INFO("outer: Non-Cacheable");
+                               break;
+                       case 1:
+                               LOG_INFO("outer: Write-Back, Write-Allocate");
+                               break;
+                       case 2:
+                               LOG_INFO("outer: Write-Through, No Write-Allocate");
+                               break;
+                       case 3:
+                               LOG_INFO("outer: Write-Back, no Write-Allocate");
+                               break;
+               }
+               switch (INNER) {
+                       case 0:
+                               LOG_INFO("inner: Non-Cacheable");
+                               break;
+                       case 1:
+                               LOG_INFO("inner: Strongly-ordered");
+                               break;
+                       case 3:
+                               LOG_INFO("inner: Device");
+                               break;
+                       case 5:
+                               LOG_INFO("inner: Write-Back, Write-Allocate");
+                               break;
+                       case 6:
+                               LOG_INFO("inner:  Write-Through");
+                               break;
+                       case 7:
+                               LOG_INFO("inner: Write-Back, no Write-Allocate");
+                               break;
+                       default:
+                               LOG_INFO("inner: %" PRIx32 " ???", INNER);
+               }
+       }
+
+done:
+       dpm->finish(dpm);
+
+       return retval;
+}
+
+static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe)
+{
+       static char bits_string[64];
+       unsigned int len;
+
+       if (afe) {
+               bool acc_r = true;
+               bool acc_w = !ap2;
+               bool priv = !(ap10 & 2);
+               len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access%s: %s%s",
+                                          s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "",
+                                priv ? "(priv)" : "", acc_r ? "R" : "N", acc_w ? "W " : "O ");
+       } else {
+               bool priv_acc_w = !ap2;
+               bool priv_acc_r = true;
+               bool unpriv_acc_w = priv_acc_w;
+               bool unpriv_acc_r = priv_acc_r;
+
+               switch (ap10) {
+               case 0:
+                       priv_acc_r = priv_acc_w = false;
+                       unpriv_acc_r = unpriv_acc_w = false;
+                       break;
+               case 1:
+                       unpriv_acc_r = unpriv_acc_w = false;
+                       break;
+               case 2:
+                       unpriv_acc_w = false;
+                       break;
+               default:
+                       break;
+               }
+
+               len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access(priv): %s%s access(unpriv): %s%s",
+                               s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", priv_acc_r ? "R" : "N", priv_acc_w ? "W" : "O",
+                               unpriv_acc_r ? "R" : "N", unpriv_acc_w ? "W" : "O");
+       }
+
+       if (len >= sizeof(bits_string))
+               bits_string[63] = 0;
+
+       return bits_string;
+}
+
+static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe)
+{
+       bool c_bit = !!(l2_desc & (1 << 3));
+       bool b_bit = !!(l2_desc & (1 << 2));
+       bool s_bit = !!(l2_desc & (1 << 10));
+       bool ap2 = !!(l2_desc & (1 << 9));
+       int ap10 = (l2_desc >> 4) & 3;
+
+       return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
+}
+
+static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe)
+{
+       bool c_bit = !!(l1_desc & (1 << 3));
+       bool b_bit = !!(l1_desc & (1 << 2));
+       bool s_bit = !!(l1_desc & (1 << 16));
+       bool ap2 = !!(l1_desc & (1 << 15));
+       int ap10 = (l1_desc >> 10) & 3;
+
+       return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
+}
+
+COMMAND_HANDLER(armv7a_mmu_dump_table)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+       struct armv7a_common *armv7a = target_to_armv7a(target);
+       struct armv7a_mmu_common *mmu = &armv7a->armv7a_mmu;
+       struct armv7a_cache_common *cache = &mmu->armv7a_cache;
+       uint32_t *first_lvl_ptbl;
+       target_addr_t ttb;
+       int ttbidx = 0;
+       int retval;
+       int pt_idx;
+       int max_pt_idx = 4095;
+       bool afe;
+
+       if (CMD_ARGC < 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (!strcmp(CMD_ARGV[0], "addr")) {
+               if (CMD_ARGC < 2)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+
+               COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb);
+
+               if (CMD_ARGC > 2) {
+                       COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx);
+
+                       if (max_pt_idx < 1 || max_pt_idx > 4096)
+                               return ERROR_COMMAND_ARGUMENT_INVALID;
+                       max_pt_idx -= 1;
+               }
+       } else {
+               if (mmu->cached != 1) {
+                       LOG_ERROR("TTB not cached!");
+                       return ERROR_FAIL;
+               }
+
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx);
+               if (ttbidx < 0 || ttbidx > 1)
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+
+               ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx];
+
+               if (ttbidx == 0) {
+                       int ttbcr_n = mmu->ttbcr & 0x7;
+                       max_pt_idx = 0x0fff >> ttbcr_n;
+               }
+       }
+
+       LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb);
+
+       first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1));
+       if (first_lvl_ptbl == NULL)
+               return ERROR_FAIL;
+
+       /*
+        * this may or may not be necessary depending on whether
+        * the table walker is configured to use the cache or not.
+        */
+       cache->flush_all_data_cache(target);
+
+       retval = mmu->read_physical_memory(target, ttb, 4, max_pt_idx+1, (uint8_t *)first_lvl_ptbl);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Failed to read first-level page table!");
+               return retval;
+       }
+
+       afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE);
+
+       for (pt_idx = 0; pt_idx <= max_pt_idx;) {
+               uint32_t first_lvl_descriptor = target_buffer_get_u32(target,
+                                               (uint8_t *)&first_lvl_ptbl[pt_idx]);
+
+               LOG_DEBUG("L1 desc[%8.8"PRIx32"]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor);
+
+               /* skip empty entries in the first level table */
+               if ((first_lvl_descriptor & 3) == 0) {
+                       pt_idx++;
+               } else
+               if ((first_lvl_descriptor & 0x40002) == 2) {
+                       /* section descriptor */
+                       uint32_t va_range = 1024*1024-1; /* 1MB range */
+                       uint32_t va_start = pt_idx << 20;
+                       uint32_t va_end = va_start + va_range;
+
+                       uint32_t pa_start = (first_lvl_descriptor & 0xfff00000);
+                       uint32_t pa_end = pa_start + va_range;
+
+                       LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+                               va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
+                       pt_idx++;
+               } else
+               if ((first_lvl_descriptor & 0x40002) == 0x40002) {
+                       /* supersection descriptor */
+                       uint32_t va_range = 16*1024*1024-1; /* 16MB range */
+                       uint32_t va_start = pt_idx << 20;
+                       uint32_t va_end = va_start + va_range;
+
+                       uint32_t pa_start = (first_lvl_descriptor & 0xff000000);
+                       uint32_t pa_end = pa_start + va_range;
+
+                       LOG_USER("SSCT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+                               va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
+
+                       /* skip next 15 entries, they're duplicating the first entry */
+                       pt_idx += 16;
+               } else {
+                       target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00;
+                       uint32_t second_lvl_descriptor;
+                       uint32_t *pt2;
+                       int pt2_idx;
+
+                       /* page table, always 1KB long */
+                       pt2 = malloc(1024);
+                       retval = mmu->read_physical_memory(target, second_lvl_ptbl,
+                                                 4, 256, (uint8_t *)pt2);
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Failed to read second-level page table!");
+                               return ERROR_FAIL;
+                       }
+
+                       for (pt2_idx = 0; pt2_idx < 256; ) {
+                               second_lvl_descriptor = target_buffer_get_u32(target,
+                                               (uint8_t *)&pt2[pt2_idx]);
+
+                               if ((second_lvl_descriptor & 3) == 0) {
+                                       /* skip entry */
+                                       pt2_idx++;
+                               } else
+                               if ((second_lvl_descriptor & 3) == 1) {
+                                       /* large page */
+                                       uint32_t va_range = 64*1024-1; /* 64KB range */
+                                       uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
+                                       uint32_t va_end = va_start + va_range;
+
+                                       uint32_t pa_start = (second_lvl_descriptor & 0xffff0000);
+                                       uint32_t pa_end = pa_start + va_range;
+
+                                       LOG_USER("LPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+                                               va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
+
+                                       pt2_idx += 16;
+                               } else {
+                                       /* small page */
+                                       uint32_t va_range = 4*1024-1; /* 4KB range */
+                                       uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
+                                       uint32_t va_end = va_start + va_range;
+
+                                       uint32_t pa_start = (second_lvl_descriptor & 0xfffff000);
+                                       uint32_t pa_end = pa_start + va_range;
+
+                                       LOG_USER("SPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+                                               va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
+
+                                       pt2_idx++;
+                               }
+                       }
+                       free(pt2);
+                       pt_idx++;
+               }
+       }
+
+       free(first_lvl_ptbl);
+       return ERROR_OK;
+}
+
+static const struct command_registration armv7a_mmu_group_handlers[] = {
+       {
+               .name = "dump",
+               .handler = armv7a_mmu_dump_table,
+               .mode = COMMAND_ANY,
+               .help = "dump translation table 0, 1 or from <address>",
+               .usage = "(0|1|addr <address> [num_entries])",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration armv7a_mmu_command_handlers[] = {
+       {
+               .name = "mmu",
+               .mode = COMMAND_ANY,
+               .help = "mmu command group",
+               .usage = "",
+               .chain = armv7a_mmu_group_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
diff --git a/src/target/armv7a_mmu.h b/src/target/armv7a_mmu.h
new file mode 100644 (file)
index 0000000..4372aa8
--- /dev/null
@@ -0,0 +1,28 @@
+/***************************************************************************
+ *   Copyright (C) 2016 by Matthias Welwarsky                              *
+ *   matthias.welwarsky@sysgo.com                                          *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARMV7A_MMU_H
+#define OPENOCD_TARGET_ARMV7A_MMU_H
+
+extern int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val);
+extern int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
+       uint32_t *val, int meminfo);
+
+extern const struct command_registration armv7a_mmu_command_handlers[];
+
+#endif /* OPENOCD_TARGET_ARMV7A_MMU_H */
index 73fb8e0f57ebb1ea34147702f995e13d8607347f..92ba54789dbb326d1f99fc709f7a31303c3f1d3c 100644 (file)
@@ -50,6 +50,7 @@
 #include "breakpoints.h"
 #include "cortex_a.h"
 #include "register.h"
+#include "armv7a_mmu.h"
 #include "target_request.h"
 #include "target_type.h"
 #include "arm_opcodes.h"
@@ -3121,6 +3122,9 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
                        "on memory access",
                .usage = "['on'|'off']",
        },
+       {
+               .chain = armv7a_mmu_command_handlers,
+       },
 
        COMMAND_REGISTRATION_DONE
 };

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)