xlat lib v2: Refactor the functions enabling the MMU

This patch refactors both the AArch32 and AArch64 versions of the
function enable_mmu_arch().

In both versions, the code now computes the VMSA-related system
registers upfront then program them in one go (rather than interleaving
the 2).

In the AArch64 version, this allows to reduce the amount of code
generated by the C preprocessor and limits it to the actual differences
between EL1 and EL3.

In the AArch32 version, this patch also removes the function
enable_mmu_internal_secure() and moves its code directly inside
enable_mmu_arch(), as it was its only caller.

Change-Id: I35c09b6db4404916cbb2e2fd3fda2ad59f935954
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index 84f1a7d..78aae2b 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -82,16 +82,20 @@
 }
 
 /*******************************************************************************
- * Function for enabling the MMU in Secure PL1, assuming that the
- * page-tables have already been created.
+ * Function for enabling the MMU in Secure PL1, assuming that the page tables
+ * have already been created.
  ******************************************************************************/
-void enable_mmu_internal_secure(unsigned int flags, uint64_t *base_table)
+void enable_mmu_arch(unsigned int flags,
+		uint64_t *base_table,
+		unsigned long long max_pa)
 {
 	u_register_t mair0, ttbcr, sctlr;
 	uint64_t ttbr0;
 
 	assert(IS_IN_SECURE());
-	assert((read_sctlr() & SCTLR_M_BIT) == 0);
+
+	sctlr = read_sctlr();
+	assert((sctlr & SCTLR_M_BIT) == 0);
 
 	/* Invalidate TLBs at the current exception level */
 	tlbiall();
@@ -102,29 +106,47 @@
 			ATTR_IWBWA_OWBWA_NTR_INDEX);
 	mair0 |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE,
 			ATTR_NON_CACHEABLE_INDEX);
-	write_mair0(mair0);
 
 	/*
-	 * Set TTBCR bits as well. Set TTBR0 table properties. Disable TTBR1.
+	 * Configure the control register for stage 1 of the PL1&0 translation
+	 * regime.
+	 */
+
+	/* Use the Long-descriptor translation table format. */
+	ttbcr = TTBCR_EAE_BIT;
+
+	/*
+	 * Disable translation table walk for addresses that are translated
+	 * using TTBR1. Therefore, only TTBR0 is used.
+	 */
+	ttbcr |= TTBCR_EPD1_BIT;
+
+	/*
+	 * Limit the input address ranges and memory region sizes translated
+	 * using TTBR0 to the given virtual address space size.
+	 */
+	ttbcr |= 32 - __builtin_ctzl((uintptr_t) PLAT_VIRT_ADDR_SPACE_SIZE);
+
+	/*
+	 * Set the cacheability and shareability attributes for memory
+	 * associated with translation table walks using TTBR0.
 	 */
 	if (flags & XLAT_TABLE_NC) {
 		/* Inner & outer non-cacheable non-shareable. */
-		ttbcr = TTBCR_EAE_BIT |
-			TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC |
-			TTBCR_RGN0_INNER_NC |
-			(32 - __builtin_ctzl((uintptr_t)PLAT_VIRT_ADDR_SPACE_SIZE));
+		ttbcr |= TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC |
+			TTBCR_RGN0_INNER_NC;
 	} else {
 		/* Inner & outer WBWA & shareable. */
-		ttbcr = TTBCR_EAE_BIT |
-			TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA |
-			TTBCR_RGN0_INNER_WBA |
-			(32 - __builtin_ctzl((uintptr_t)PLAT_VIRT_ADDR_SPACE_SIZE));
+		ttbcr |= TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA |
+			TTBCR_RGN0_INNER_WBA;
 	}
-	ttbcr |= TTBCR_EPD1_BIT;
-	write_ttbcr(ttbcr);
 
 	/* Set TTBR0 bits as well */
 	ttbr0 = (uint64_t)(uintptr_t) base_table;
+
+	/* Now program the relevant system registers */
+	write_mair0(mair0);
+	write_ttbcr(ttbcr);
 	write64_ttbr0(ttbr0);
 	write64_ttbr1(0);
 
@@ -137,7 +159,6 @@
 	dsbish();
 	isb();
 
-	sctlr = read_sctlr();
 	sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT;
 
 	if (flags & DISABLE_DCACHE)
@@ -150,10 +171,3 @@
 	/* Ensure the MMU enable takes effect immediately */
 	isb();
 }
-
-void enable_mmu_arch(unsigned int flags,
-		uint64_t *base_table,
-		unsigned long long max_pa)
-{
-	enable_mmu_internal_secure(flags, base_table);
-}
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index ba1ab73..49b0605 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -22,8 +22,6 @@
 # define IMAGE_EL	1
 #endif
 
-static unsigned long long tcr_ps_bits;
-
 static unsigned long long calc_physical_addr_size_bits(
 					unsigned long long max_addr)
 {
@@ -151,50 +149,23 @@
  * exception level, assuming that the pagetables have already been created.
  *
  *   _el:		Exception level at which the function will run
- *   _tcr_extra:	Extra bits to set in the TCR register. This mask will
- *			be OR'ed with the default TCR value.
  *   _tlbi_fct:		Function to invalidate the TLBs at the current
  *			exception level
  ******************************************************************************/
-#define DEFINE_ENABLE_MMU_EL(_el, _tcr_extra, _tlbi_fct)		\
-	void enable_mmu_internal_el##_el(unsigned int flags,		\
-					 uint64_t *base_table)		\
+#define DEFINE_ENABLE_MMU_EL(_el, _tlbi_fct)				\
+	static void enable_mmu_internal_el##_el(int flags,		\
+						uint64_t mair,		\
+						uint64_t tcr,		\
+						uint64_t ttbr)		\
 	{								\
-		uint64_t mair, tcr, ttbr;				\
-		uint32_t sctlr;						\
-									\
-		assert(IS_IN_EL(_el));					\
-		assert((read_sctlr_el##_el() & SCTLR_M_BIT) == 0);	\
+		uint32_t sctlr = read_sctlr_el##_el();			\
+		assert((sctlr & SCTLR_M_BIT) == 0);			\
 									\
 		/* Invalidate TLBs at the current exception level */	\
 		_tlbi_fct();						\
 									\
-		/* Set attributes in the right indices of the MAIR */	\
-		mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);	\
-		mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,		\
-				ATTR_IWBWA_OWBWA_NTR_INDEX);		\
-		mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE,		\
-				ATTR_NON_CACHEABLE_INDEX);		\
 		write_mair_el##_el(mair);				\
-									\
-		/* Set TCR bits as well. */				\
-		/* Set T0SZ to (64 - width of virtual address space) */	\
-		if (flags & XLAT_TABLE_NC) {				\
-			/* Inner & outer non-cacheable non-shareable. */\
-			tcr = TCR_SH_NON_SHAREABLE |			\
-				TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC |	\
-				(64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE));\
-		} else {						\
-			/* Inner & outer WBWA & shareable. */		\
-			tcr = TCR_SH_INNER_SHAREABLE |			\
-				TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA |	\
-				(64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE));\
-		}							\
-		tcr |= _tcr_extra;					\
 		write_tcr_el##_el(tcr);					\
-									\
-		/* Set TTBR bits as well */				\
-		ttbr = (uint64_t) base_table;				\
 		write_ttbr0_el##_el(ttbr);				\
 									\
 		/* Ensure all translation table writes have drained */	\
@@ -204,9 +175,7 @@
 		dsbish();						\
 		isb();							\
 									\
-		sctlr = read_sctlr_el##_el();				\
 		sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT;			\
-									\
 		if (flags & DISABLE_DCACHE)				\
 			sctlr &= ~SCTLR_C_BIT;				\
 		else							\
@@ -220,30 +189,61 @@
 
 /* Define EL1 and EL3 variants of the function enabling the MMU */
 #if IMAGE_EL == 1
-DEFINE_ENABLE_MMU_EL(1,
-		(tcr_ps_bits << TCR_EL1_IPS_SHIFT),
-		tlbivmalle1)
+DEFINE_ENABLE_MMU_EL(1, tlbivmalle1)
 #elif IMAGE_EL == 3
-DEFINE_ENABLE_MMU_EL(3,
-		TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT),
-		tlbialle3)
+DEFINE_ENABLE_MMU_EL(3, tlbialle3)
 #endif
 
 void enable_mmu_arch(unsigned int flags,
 		uint64_t *base_table,
 		unsigned long long max_pa)
 {
+	uint64_t mair, ttbr, tcr;
+
+	/* Set attributes in the right indices of the MAIR. */
+	mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
+	mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX);
+	mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX);
+
+	ttbr = (uint64_t) base_table;
+
+	/*
+	 * Set TCR bits as well.
+	 */
+
+	/*
+	 * Limit the input address ranges and memory region sizes translated
+	 * using TTBR0 to the given virtual address space size.
+	 */
+	tcr = 64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE);
+
+	/*
+	 * Set the cacheability and shareability attributes for memory
+	 * associated with translation table walks.
+	 */
+	if (flags & XLAT_TABLE_NC) {
+		/* Inner & outer non-cacheable non-shareable. */
+		tcr |= TCR_SH_NON_SHAREABLE |
+			TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC;
+	} else {
+		/* Inner & outer WBWA & shareable. */
+		tcr |= TCR_SH_INNER_SHAREABLE |
+			TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA;
+	}
+
 	/*
 	 * It is safer to restrict the max physical address accessible by the
 	 * hardware as much as possible.
 	 */
-	tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
+	unsigned long long tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
 
 #if IMAGE_EL == 1
 	assert(IS_IN_EL(1));
-	enable_mmu_internal_el1(flags, base_table);
+	tcr |= tcr_ps_bits << TCR_EL1_IPS_SHIFT;
+	enable_mmu_internal_el1(flags, mair, tcr, ttbr);
 #elif IMAGE_EL == 3
 	assert(IS_IN_EL(3));
-	enable_mmu_internal_el3(flags, base_table);
+	tcr |= TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT);
+	enable_mmu_internal_el3(flags, mair, tcr, ttbr);
 #endif
 }