From b2dc1af59a4cead2bd9446256ef31658b2a5de61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Gl=C3=B6ckner?= <daniel-gl@gmx.net>
Date: Thu, 20 Nov 2014 23:57:26 +0100
Subject: [PATCH] armv7a: fix interpretation of MMU table
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

On armv7 there no longer are 1kB pages. Instead the bit that in
older architectures distinguished 1kB pages from 4kB pages is on
armv7 used for as execute-never marker. There may now also be 16MB
supersections with 40 bit physical address.

Change-Id: I959bdb8012782a9d07d968907a21f50e3d9b356a
Signed-off-by: Daniel Glöckner <daniel-gl@gmx.net>
Reviewed-on: http://openocd.zylin.com/2386
Tested-by: jenkins
Reviewed-by: Vladimir Svoboda <ze.vlad@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
---
 src/target/armv7a.c | 46 +++++++++++++++++----------------------------
 1 file changed, 17 insertions(+), 29 deletions(-)

diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index ca599eb68..170cfcc28 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -232,27 +232,26 @@ int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val)
 	}
 
 
-	if ((first_lvl_descriptor & 0x3) == 2) {
+	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;
 	}
 
-	if ((first_lvl_descriptor & 0x3) == 1) {
-		/* coarse 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;
-	} else if ((first_lvl_descriptor & 0x3) == 3)   {
-		/* fine page table */
-		retval = armv7a->armv7a_mmu.read_physical_memory(target,
-				(first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
-				4, 1, (uint8_t *)&second_lvl_descriptor);
-		if (retval != ERROR_OK)
-			return retval;
-	}
+	/* 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);
@@ -267,23 +266,12 @@ int armv7a_mmu_translate_va(struct target *target,  uint32_t va, uint32_t *val)
 	if ((second_lvl_descriptor & 0x3) == 1) {
 		/* large page descriptor */
 		*val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
-		return ERROR_OK;
-	}
-
-	if ((second_lvl_descriptor & 0x3) == 2) {
+	} else {
 		/* small page descriptor */
 		*val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
-		return ERROR_OK;
 	}
 
-	if ((second_lvl_descriptor & 0x3) == 3) {
-		*val = (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
-		return ERROR_OK;
-	}
-
-	/* should not happen */
-	LOG_ERROR("Address translation failure");
-	return ERROR_TARGET_TRANSLATION_FAULT;
+	return ERROR_OK;
 
 done:
 	return retval;