diff mbox

[U-Boot,8/9] armv8: mmu: Add a function to change mapping attributes

Message ID 1487043936-10112-9-git-send-email-york.sun@nxp.com
State Accepted
Commit 7f9b9f318ff152bd8d2e8b573708e2bdc088c1b1
Delegated to: York Sun
Headers show

Commit Message

York Sun Feb. 14, 2017, 3:45 a.m. UTC
Function mmu_change_region_attr() is added to change existing mapping
with updated PXN, UXN and memory type. This is a break-before-make
process during which the mapping becomes fault (invalid) before final
attributres are set.

Signed-off-by: York Sun <york.sun@nxp.com>
---

 arch/arm/cpu/armv8/cache_v8.c    | 72 +++++++++++++++++++++++++++++++++++++---
 arch/arm/include/asm/armv8/mmu.h |  5 +++
 arch/arm/include/asm/system.h    |  1 +
 3 files changed, 74 insertions(+), 4 deletions(-)

Comments

Alexander Graf Feb. 14, 2017, 3:39 p.m. UTC | #1
On 14/02/2017 04:45, York Sun wrote:
> Function mmu_change_region_attr() is added to change existing mapping
> with updated PXN, UXN and memory type. This is a break-before-make
> process during which the mapping becomes fault (invalid) before final
> attributres are set.

This is what we have the emergency tables for, no? Just switch to those, 
modify anything you like in the original tables, then switch back.


Alex
York Sun Feb. 14, 2017, 4:44 p.m. UTC | #2
On 02/14/2017 07:39 AM, Alexander Graf wrote:
>
>
> On 14/02/2017 04:45, York Sun wrote:
>> Function mmu_change_region_attr() is added to change existing mapping
>> with updated PXN, UXN and memory type. This is a break-before-make
>> process during which the mapping becomes fault (invalid) before final
>> attributres are set.
>
> This is what we have the emergency tables for, no? Just switch to those,
> modify anything you like in the original tables, then switch back.
>

It is the emergency table for. However, I don't have the luxury to use 
another table for the early MMU due to very limited SRAM available.

York
diff mbox

Patch

diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index 6c5630c..bd1c3e0 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -501,7 +501,8 @@  static bool is_aligned(u64 addr, u64 size, u64 align)
 	return !(addr & (align - 1)) && !(size & (align - 1));
 }
 
-static u64 set_one_region(u64 start, u64 size, u64 attrs, int level)
+/* Use flag to indicate if attrs has more than d-cache attributes */
+static u64 set_one_region(u64 start, u64 size, u64 attrs, bool flag, int level)
 {
 	int levelshift = level2shift(level);
 	u64 levelsize = 1ULL << levelshift;
@@ -509,8 +510,13 @@  static u64 set_one_region(u64 start, u64 size, u64 attrs, int level)
 
 	/* Can we can just modify the current level block PTE? */
 	if (is_aligned(start, size, levelsize)) {
-		*pte &= ~PMD_ATTRINDX_MASK;
-		*pte |= attrs;
+		if (flag) {
+			*pte &= ~PMD_ATTRMASK;
+			*pte |= attrs & PMD_ATTRMASK;
+		} else {
+			*pte &= ~PMD_ATTRINDX_MASK;
+			*pte |= attrs & PMD_ATTRINDX_MASK;
+		}
 		debug("Set attrs=%llx pte=%p level=%d\n", attrs, pte, level);
 
 		return levelsize;
@@ -560,7 +566,8 @@  void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
 		u64 r;
 
 		for (level = 1; level < 4; level++) {
-			r = set_one_region(start, size, attrs, level);
+			/* Set d-cache attributes only */
+			r = set_one_region(start, size, attrs, false, level);
 			if (r) {
 				/* PTE successfully replaced */
 				size -= r;
@@ -581,6 +588,63 @@  void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
 	flush_dcache_range(real_start, real_start + real_size);
 }
 
+/*
+ * Modify MMU table for a region with updated PXN/UXN/Memory type/valid bits.
+ * The procecess is break-before-make. The target region will be marked as
+ * invalid during the process of changing.
+ */
+void mmu_change_region_attr(phys_addr_t addr, size_t siz, u64 attrs)
+{
+	int level;
+	u64 r, size, start;
+
+	start = addr;
+	size = siz;
+	/*
+	 * Loop through the address range until we find a page granule that fits
+	 * our alignment constraints, then set it to "invalid".
+	 */
+	while (size > 0) {
+		for (level = 1; level < 4; level++) {
+			/* Set PTE to fault */
+			r = set_one_region(start, size, PTE_TYPE_FAULT, true,
+					   level);
+			if (r) {
+				/* PTE successfully invalidated */
+				size -= r;
+				start += r;
+				break;
+			}
+		}
+	}
+
+	flush_dcache_range(gd->arch.tlb_addr,
+			   gd->arch.tlb_addr + gd->arch.tlb_size);
+	__asm_invalidate_tlb_all();
+
+	/*
+	 * Loop through the address range until we find a page granule that fits
+	 * our alignment constraints, then set it to the new cache attributes
+	 */
+	start = addr;
+	size = siz;
+	while (size > 0) {
+		for (level = 1; level < 4; level++) {
+			/* Set PTE to new attributes */
+			r = set_one_region(start, size, attrs, true, level);
+			if (r) {
+				/* PTE successfully updated */
+				size -= r;
+				start += r;
+				break;
+			}
+		}
+	}
+	flush_dcache_range(gd->arch.tlb_addr,
+			   gd->arch.tlb_addr + gd->arch.tlb_size);
+	__asm_invalidate_tlb_all();
+}
+
 #else	/* CONFIG_SYS_DCACHE_OFF */
 
 /*
diff --git a/arch/arm/include/asm/armv8/mmu.h b/arch/arm/include/asm/armv8/mmu.h
index e9b4cdb..a349903 100644
--- a/arch/arm/include/asm/armv8/mmu.h
+++ b/arch/arm/include/asm/armv8/mmu.h
@@ -53,6 +53,7 @@ 
 #define PTE_TYPE_FAULT		(0 << 0)
 #define PTE_TYPE_TABLE		(3 << 0)
 #define PTE_TYPE_BLOCK		(1 << 0)
+#define PTE_TYPE_VALID		(1 << 0)
 
 #define PTE_TABLE_PXN		(1UL << 59)
 #define PTE_TABLE_XN		(1UL << 60)
@@ -77,6 +78,10 @@ 
  */
 #define PMD_ATTRINDX(t)		((t) << 2)
 #define PMD_ATTRINDX_MASK	(7 << 2)
+#define PMD_ATTRMASK		(PTE_BLOCK_PXN		| \
+				 PTE_BLOCK_UXN		| \
+				 PMD_ATTRINDX_MASK	| \
+				 PTE_TYPE_VALID)
 
 /*
  * TCR flags.
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 766e929..9c3261c 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -226,6 +226,7 @@  void protect_secure_region(void);
 void smp_kick_all_cpus(void);
 
 void flush_l3_cache(void);
+void mmu_change_region_attr(phys_addr_t start, size_t size, u64 attrs);
 
 /*
  *Issue a secure monitor call in accordance with ARM "SMC Calling convention",