Merge pull request #1519 from antonio-nino-diaz-arm/an/xlat-el2

xlat v2: Support EL2 translation regime
diff --git a/bl1/aarch32/bl1_exceptions.S b/bl1/aarch32/bl1_exceptions.S
index 1540542..9b001a9 100644
--- a/bl1/aarch32/bl1_exceptions.S
+++ b/bl1/aarch32/bl1_exceptions.S
@@ -116,7 +116,7 @@
 
 	/* Turn on the MMU */
 	mov	r0, #DISABLE_DCACHE
-	bl	enable_mmu_secure
+	bl	enable_mmu_svc_mon
 
 	/* Enable the data cache. */
 	ldcopr	r9, SCTLR
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index a536649..6f0949b 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -313,6 +313,28 @@
 #define TTBCR_T0SZ_SHIFT	U(0)
 #define TTBCR_T0SZ_MASK		U(0x7)
 
+/*
+ * HTCR definitions
+ */
+#define HTCR_RES1			((U(1) << 31) | (U(1) << 23))
+
+#define HTCR_SH0_NON_SHAREABLE		(U(0x0) << 12)
+#define HTCR_SH0_OUTER_SHAREABLE	(U(0x2) << 12)
+#define HTCR_SH0_INNER_SHAREABLE	(U(0x3) << 12)
+
+#define HTCR_RGN0_OUTER_NC	(U(0x0) << 10)
+#define HTCR_RGN0_OUTER_WBA	(U(0x1) << 10)
+#define HTCR_RGN0_OUTER_WT	(U(0x2) << 10)
+#define HTCR_RGN0_OUTER_WBNA	(U(0x3) << 10)
+
+#define HTCR_RGN0_INNER_NC	(U(0x0) << 8)
+#define HTCR_RGN0_INNER_WBA	(U(0x1) << 8)
+#define HTCR_RGN0_INNER_WT	(U(0x2) << 8)
+#define HTCR_RGN0_INNER_WBNA	(U(0x3) << 8)
+
+#define HTCR_T0SZ_SHIFT		U(0)
+#define HTCR_T0SZ_MASK		U(0x7)
+
 #define MODE_RW_SHIFT		U(0x4)
 #define MODE_RW_MASK		U(0x1)
 #define MODE_RW_32		U(0x1)
@@ -433,6 +455,7 @@
 #define TLBIMVA		p15, 0, c8, c7, 1
 #define TLBIMVAA	p15, 0, c8, c7, 3
 #define TLBIMVAAIS	p15, 0, c8, c3, 3
+#define TLBIMVAHIS	p15, 4, c8, c3, 1
 #define BPIALLIS	p15, 0, c7, c1, 6
 #define BPIALL		p15, 0, c7, c5, 6
 #define ICIALLU		p15, 0, c7, c5, 0
@@ -448,6 +471,8 @@
 #define CLIDR		p15, 1, c0, c0, 1
 #define CSSELR		p15, 2, c0, c0, 0
 #define CCSIDR		p15, 1, c0, c0, 0
+#define HTCR		p15, 4, c2, c0, 2
+#define HMAIR0		p15, 4, c10, c2, 0
 #define DBGOSDLR	p14, 0, c1, c3, 4
 
 /* Debug register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
@@ -487,6 +512,7 @@
 #define CNTVOFF_64	p15, 4, c14
 #define VTTBR_64	p15, 6, c2
 #define CNTPCT_64	p15, 0, c14
+#define HTTBR_64	p15, 4, c2
 
 /* 64 bit GICv3 CPU Interface system register defines. The format is: coproc, opt1, CRm */
 #define ICC_SGI1R_EL1_64	p15, 0, c12
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index beae5d0..aa68bcb 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -300,6 +300,7 @@
 DEFINE_TLBIOP_PARAM_FUNC(mva, TLBIMVA)
 DEFINE_TLBIOP_PARAM_FUNC(mvaa, TLBIMVAA)
 DEFINE_TLBIOP_PARAM_FUNC(mvaais, TLBIMVAAIS)
+DEFINE_TLBIOP_PARAM_FUNC(mvahis, TLBIMVAHIS)
 
 /*
  * BPI operation prototypes.
@@ -320,6 +321,10 @@
 #define IS_IN_SECURE() \
 	(GET_NS_BIT(read_scr()) == 0)
 
+#define IS_IN_HYP()	(GET_M32(read_cpsr()) == MODE32_hyp)
+#define IS_IN_SVC()	(GET_M32(read_cpsr()) == MODE32_svc)
+#define IS_IN_MON()	(GET_M32(read_cpsr()) == MODE32_mon)
+#define IS_IN_EL2()	IS_IN_HYP()
  /*
   * If EL3 is AArch32, then secure PL1 and monitor mode correspond to EL3
   */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 397013e..c9619f6 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -364,7 +364,9 @@
  * TCR defintions
  */
 #define TCR_EL3_RES1		((U(1) << 31) | (U(1) << 23))
+#define TCR_EL2_RES1		((ULL(1) << 31) | (ULL(1) << 23))
 #define TCR_EL1_IPS_SHIFT	U(32)
+#define TCR_EL2_PS_SHIFT	U(16)
 #define TCR_EL3_PS_SHIFT	U(16)
 
 #define TCR_TxSZ_MIN		ULL(16)
diff --git a/include/lib/xlat_tables/xlat_mmu_helpers.h b/include/lib/xlat_tables/xlat_mmu_helpers.h
index cd42c33..e1d0227 100644
--- a/include/lib/xlat_tables/xlat_mmu_helpers.h
+++ b/include/lib/xlat_tables/xlat_mmu_helpers.h
@@ -67,15 +67,24 @@
 
 #ifdef AARCH32
 /* AArch32 specific translation table API */
+#if !ERROR_DEPRECATED
 void enable_mmu_secure(unsigned int flags);
-
 void enable_mmu_direct(unsigned int flags);
+#endif
+
+void enable_mmu_svc_mon(unsigned int flags);
+void enable_mmu_hyp(unsigned int flags);
+
+void enable_mmu_direct_svc_mon(unsigned int flags);
+void enable_mmu_direct_hyp(unsigned int flags);
 #else
 /* AArch64 specific translation table APIs */
 void enable_mmu_el1(unsigned int flags);
+void enable_mmu_el2(unsigned int flags);
 void enable_mmu_el3(unsigned int flags);
 
 void enable_mmu_direct_el1(unsigned int flags);
+void enable_mmu_direct_el2(unsigned int flags);
 void enable_mmu_direct_el3(unsigned int flags);
 #endif /* AARCH32 */
 
diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h
index 022acce..52c4dc6 100644
--- a/include/lib/xlat_tables/xlat_tables_v2.h
+++ b/include/lib/xlat_tables/xlat_tables_v2.h
@@ -125,6 +125,7 @@
  * library to detect it at runtime.
  */
 #define EL1_EL0_REGIME		1
+#define EL2_REGIME		2
 #define EL3_REGIME		3
 #define EL_REGIME_INVALID	-1
 
diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c
index 87b15b8..033e237 100644
--- a/lib/xlat_tables/aarch32/xlat_tables.c
+++ b/lib/xlat_tables/aarch32/xlat_tables.c
@@ -65,8 +65,20 @@
  * Function for enabling the MMU in Secure PL1, assuming that the
  * page-tables have already been created.
  ******************************************************************************/
+#if !ERROR_DEPRECATED
 void enable_mmu_secure(unsigned int flags)
 {
+	enable_mmu_svc_mon(flags);
+}
+
+void enable_mmu_direct(unsigned int flags)
+{
+	enable_mmu_direct_svc_mon(flags);
+}
+#endif
+
+void enable_mmu_svc_mon(unsigned int flags)
+{
 	unsigned int mair0, ttbcr, sctlr;
 	uint64_t ttbr0;
 
@@ -131,7 +143,7 @@
 	isb();
 }
 
-void enable_mmu_direct(unsigned int flags)
+void enable_mmu_direct_svc_mon(unsigned int flags)
 {
-	enable_mmu_secure(flags);
+	enable_mmu_svc_mon(flags);
 }
diff --git a/lib/xlat_tables_v2/aarch32/enable_mmu.S b/lib/xlat_tables_v2/aarch32/enable_mmu.S
index 99cf088..4a4ac30 100644
--- a/lib/xlat_tables_v2/aarch32/enable_mmu.S
+++ b/lib/xlat_tables_v2/aarch32/enable_mmu.S
@@ -8,9 +8,11 @@
 #include <assert_macros.S>
 #include <xlat_tables_v2.h>
 
-	.global	enable_mmu_direct
+	.global	enable_mmu_direct_svc_mon
+	.global	enable_mmu_direct_hyp
 
-func enable_mmu_direct
+	/* void enable_mmu_direct_svc_mon(unsigned int flags) */
+func enable_mmu_direct_svc_mon
 	/* Assert that MMU is turned off */
 #if ENABLE_ASSERTIONS
 	ldcopr  r1, SCTLR
@@ -63,4 +65,56 @@
 	isb
 
 	bx	lr
-endfunc enable_mmu_direct
+endfunc enable_mmu_direct_svc_mon
+
+
+	/* void enable_mmu_direct_hyp(unsigned int flags) */
+func enable_mmu_direct_hyp
+	/* Assert that MMU is turned off */
+#if ENABLE_ASSERTIONS
+	ldcopr  r1, HSCTLR
+	tst	r1, #HSCTLR_M_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* Invalidate TLB entries */
+	TLB_INVALIDATE(r0, TLBIALL)
+
+	mov	r3, r0
+	ldr	r0, =mmu_cfg_params
+
+	/* HMAIR0 */
+	ldr	r1, [r0, #(MMU_CFG_MAIR << 3)]
+	stcopr	r1, HMAIR0
+
+	/* HTCR */
+	ldr	r2, [r0, #(MMU_CFG_TCR << 3)]
+	stcopr	r2, HTCR
+
+	/* HTTBR */
+	ldr	r1, [r0, #(MMU_CFG_TTBR0 << 3)]
+	ldr	r2, [r0, #((MMU_CFG_TTBR0 << 3) + 4)]
+	stcopr16	r1, r2, HTTBR_64
+
+	/*
+	 * Ensure all translation table writes have drained into memory, the TLB
+	 * invalidation is complete, and translation register writes are
+	 * committed before enabling the MMU
+	 */
+	dsb	ish
+	isb
+
+	/* Enable enable MMU by honoring flags */
+	ldcopr  r1, HSCTLR
+	ldr	r2, =(HSCTLR_WXN_BIT | HSCTLR_C_BIT | HSCTLR_M_BIT)
+	orr	r1, r1, r2
+
+	/* Clear C bit if requested */
+	tst	r3, #DISABLE_DCACHE
+	bicne	r1, r1, #HSCTLR_C_BIT
+
+	stcopr	r1, HSCTLR
+	isb
+
+	bx	lr
+endfunc enable_mmu_direct_hyp
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index 2482840..66938e5 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -43,22 +43,38 @@
 }
 #endif /* ENABLE_ASSERTIONS*/
 
-bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx __unused)
+bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx)
 {
-	return (read_sctlr() & SCTLR_M_BIT) != 0;
+	if (ctx->xlat_regime == EL1_EL0_REGIME) {
+		assert(xlat_arch_current_el() == 1U);
+		return (read_sctlr() & SCTLR_M_BIT) != 0U;
+	} else {
+		assert(ctx->xlat_regime == EL2_REGIME);
+		assert(xlat_arch_current_el() == 2U);
+		return (read_hsctlr() & HSCTLR_M_BIT) != 0U;
+	}
 }
 
 bool is_dcache_enabled(void)
 {
-	return (read_sctlr() & SCTLR_C_BIT) != 0;
+	if (IS_IN_EL2()) {
+		return (read_hsctlr() & HSCTLR_C_BIT) != 0U;
+	} else {
+		return (read_sctlr() & SCTLR_C_BIT) != 0U;
+	}
 }
 
-uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime __unused)
+uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime)
 {
-	return UPPER_ATTRS(XN);
+	if (xlat_regime == EL1_EL0_REGIME) {
+		return UPPER_ATTRS(XN) | UPPER_ATTRS(PXN);
+	} else {
+		assert(xlat_regime == EL2_REGIME);
+		return UPPER_ATTRS(XN);
+	}
 }
 
-void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime __unused)
+void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime)
 {
 	/*
 	 * Ensure the translation table write has drained into memory before
@@ -66,7 +82,12 @@
 	 */
 	dsbishst();
 
-	tlbimvaais(TLBI_ADDR(va));
+	if (xlat_regime == EL1_EL0_REGIME) {
+		tlbimvaais(TLBI_ADDR(va));
+	} else {
+		assert(xlat_regime == EL2_REGIME);
+		tlbimvahis(TLBI_ADDR(va));
+	}
 }
 
 void xlat_arch_tlbi_va_sync(void)
@@ -97,19 +118,25 @@
 
 unsigned int xlat_arch_current_el(void)
 {
-	/*
-	 * If EL3 is in AArch32 mode, all secure PL1 modes (Monitor, System,
-	 * SVC, Abort, UND, IRQ and FIQ modes) execute at EL3.
-	 *
-	 * The PL1&0 translation regime in AArch32 behaves like the EL1&0 regime
-	 * in AArch64 except for the XN bits, but we set and unset them at the
-	 * same time, so there's no difference in practice.
-	 */
-	return 1U;
+	if (IS_IN_HYP()) {
+		return 2U;
+	} else {
+		assert(IS_IN_SVC() || IS_IN_MON());
+		/*
+		 * If EL3 is in AArch32 mode, all secure PL1 modes (Monitor,
+		 * System, SVC, Abort, UND, IRQ and FIQ modes) execute at EL3.
+		 *
+		 * The PL1&0 translation regime in AArch32 behaves like the
+		 * EL1&0 regime in AArch64 except for the XN bits, but we set
+		 * and unset them at the same time, so there's no difference in
+		 * practice.
+		 */
+		return 1U;
+	}
 }
 
 /*******************************************************************************
- * Function for enabling the MMU in Secure PL1, assuming that the page tables
+ * Function for enabling the MMU in PL1 or PL2, assuming that the page tables
  * have already been created.
  ******************************************************************************/
 void setup_mmu_cfg(uint64_t *params, unsigned int flags,
@@ -119,8 +146,6 @@
 	uint64_t mair, ttbr0;
 	uint32_t ttbcr;
 
-	assert(IS_IN_SECURE());
-
 	/* Set attributes in the right indices of the MAIR */
 	mair = MAIR0_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
 	mair |= MAIR0_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,
@@ -129,18 +154,32 @@
 			ATTR_NON_CACHEABLE_INDEX);
 
 	/*
-	 * Configure the control register for stage 1 of the PL1&0 translation
-	 * regime.
+	 * Configure the control register for stage 1 of the PL1&0 or EL2
+	 * translation regimes.
 	 */
 
 	/* 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;
+	if (xlat_regime == EL1_EL0_REGIME) {
+		assert(IS_IN_SVC() || IS_IN_MON());
+		/*
+		 * Disable translation table walk for addresses that are
+		 * translated using TTBR1. Therefore, only TTBR0 is used.
+		 */
+		ttbcr |= TTBCR_EPD1_BIT;
+	} else {
+		assert(xlat_regime == EL2_REGIME);
+		assert(IS_IN_HYP());
+
+		/*
+		 * Set HTCR bits as well. Set HTTBR table properties
+		 * as Inner & outer WBWA & shareable.
+		 */
+		ttbcr |= HTCR_RES1 |
+			 HTCR_SH0_INNER_SHAREABLE | HTCR_RGN0_OUTER_WBA |
+			 HTCR_RGN0_INNER_WBA;
+	}
 
 	/*
 	 * Limit the input address ranges and memory region sizes translated
diff --git a/lib/xlat_tables_v2/aarch64/enable_mmu.S b/lib/xlat_tables_v2/aarch64/enable_mmu.S
index 5c5a2a9..21717d2 100644
--- a/lib/xlat_tables_v2/aarch64/enable_mmu.S
+++ b/lib/xlat_tables_v2/aarch64/enable_mmu.S
@@ -9,6 +9,7 @@
 #include <xlat_tables_v2.h>
 
 	.global	enable_mmu_direct_el1
+	.global	enable_mmu_direct_el2
 	.global	enable_mmu_direct_el3
 
 	/* Macros to read and write to system register for a given EL. */
@@ -20,6 +21,19 @@
 	mrs	\gp_reg, \reg_name\()_el\()\el
 	.endm
 
+	.macro tlbi_invalidate_all el
+	.if \el == 1
+		TLB_INVALIDATE(vmalle1)
+	.elseif \el == 2
+		TLB_INVALIDATE(alle2)
+	.elseif \el == 3
+		TLB_INVALIDATE(alle3)
+	.else
+		.error "EL must be 1, 2 or 3"
+	.endif
+	.endm
+
+	/* void enable_mmu_direct_el<x>(unsigned int flags) */
 	.macro define_mmu_enable_func el
 	func enable_mmu_direct_\()el\el
 #if ENABLE_ASSERTIONS
@@ -27,17 +41,8 @@
 		tst	x1, #SCTLR_M_BIT
 		ASM_ASSERT(eq)
 #endif
-
-		/* Invalidate TLB entries */
-		.if \el == 1
-		TLB_INVALIDATE(vmalle1)
-		.else
-		.if \el == 3
-		TLB_INVALIDATE(alle3)
-		.else
-		.error "EL must be 1 or 3"
-		.endif
-		.endif
+		/* Invalidate all TLB entries */
+		tlbi_invalidate_all \el
 
 		mov	x7, x0
 		ldr	x0, =mmu_cfg_params
@@ -86,4 +91,5 @@
 	 *  enable_mmu_direct_el3
 	 */
 	define_mmu_enable_func 1
+	define_mmu_enable_func 2
 	define_mmu_enable_func 3
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index cf8070a..d1555bf 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -105,6 +105,9 @@
 	if (ctx->xlat_regime == EL1_EL0_REGIME) {
 		assert(xlat_arch_current_el() >= 1U);
 		return (read_sctlr_el1() & SCTLR_M_BIT) != 0U;
+	} else if (ctx->xlat_regime == EL2_REGIME) {
+		assert(xlat_arch_current_el() >= 2U);
+		return (read_sctlr_el2() & SCTLR_M_BIT) != 0U;
 	} else {
 		assert(ctx->xlat_regime == EL3_REGIME);
 		assert(xlat_arch_current_el() >= 3U);
@@ -118,6 +121,8 @@
 
 	if (el == 1U) {
 		return (read_sctlr_el1() & SCTLR_C_BIT) != 0U;
+	} else if (el == 2U) {
+		return (read_sctlr_el2() & SCTLR_C_BIT) != 0U;
 	} else {
 		return (read_sctlr_el3() & SCTLR_C_BIT) != 0U;
 	}
@@ -128,7 +133,8 @@
 	if (xlat_regime == EL1_EL0_REGIME) {
 		return UPPER_ATTRS(UXN) | UPPER_ATTRS(PXN);
 	} else {
-		assert(xlat_regime == EL3_REGIME);
+		assert((xlat_regime == EL2_REGIME) ||
+		       (xlat_regime == EL3_REGIME));
 		return UPPER_ATTRS(XN);
 	}
 }
@@ -151,6 +157,9 @@
 	if (xlat_regime == EL1_EL0_REGIME) {
 		assert(xlat_arch_current_el() >= 1U);
 		tlbivaae1is(TLBI_ADDR(va));
+	} else if (xlat_regime == EL2_REGIME) {
+		assert(xlat_arch_current_el() >= 2U);
+		tlbivae2is(TLBI_ADDR(va));
 	} else {
 		assert(xlat_regime == EL3_REGIME);
 		assert(xlat_arch_current_el() >= 3U);
@@ -245,6 +254,8 @@
 		 * that are translated using TTBR1_EL1.
 		 */
 		tcr |= TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT);
+	} else if (xlat_regime == EL2_REGIME) {
+		tcr |= TCR_EL2_RES1 | (tcr_ps_bits << TCR_EL2_PS_SHIFT);
 	} else {
 		assert(xlat_regime == EL3_REGIME);
 		tcr |= TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT);
diff --git a/lib/xlat_tables_v2/xlat_tables_context.c b/lib/xlat_tables_v2/xlat_tables_context.c
index 143f08a..bf0cc9f 100644
--- a/lib/xlat_tables_v2/xlat_tables_context.c
+++ b/lib/xlat_tables_v2/xlat_tables_context.c
@@ -82,6 +82,8 @@
 
 	if (current_el == 1U) {
 		tf_xlat_ctx.xlat_regime = EL1_EL0_REGIME;
+	} else if (current_el == 2U) {
+		tf_xlat_ctx.xlat_regime = EL2_REGIME;
 	} else {
 		assert(current_el == 3U);
 		tf_xlat_ctx.xlat_regime = EL3_REGIME;
@@ -119,14 +121,34 @@
 
 #ifdef AARCH32
 
+#if !ERROR_DEPRECATED
 void enable_mmu_secure(unsigned int flags)
 {
+	enable_mmu_svc_mon(flags);
+}
+
+void enable_mmu_direct(unsigned int flags)
+{
+	enable_mmu_direct_svc_mon(flags);
+}
+#endif
+
+void enable_mmu_svc_mon(unsigned int flags)
+{
 	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
 		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
 		      tf_xlat_ctx.va_max_address, EL1_EL0_REGIME);
-	enable_mmu_direct(flags);
+	enable_mmu_direct_svc_mon(flags);
 }
 
+void enable_mmu_hyp(unsigned int flags)
+{
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
+		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
+		      tf_xlat_ctx.va_max_address, EL2_REGIME);
+	enable_mmu_direct_hyp(flags);
+}
+
 #else
 
 void enable_mmu_el1(unsigned int flags)
@@ -137,6 +159,14 @@
 	enable_mmu_direct_el1(flags);
 }
 
+void enable_mmu_el2(unsigned int flags)
+{
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
+		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
+		      tf_xlat_ctx.va_max_address, EL2_REGIME);
+	enable_mmu_direct_el2(flags);
+}
+
 void enable_mmu_el3(unsigned int flags)
 {
 	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
index 56b9514..0340bf6 100644
--- a/lib/xlat_tables_v2/xlat_tables_core.c
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -142,7 +142,8 @@
 			desc |= LOWER_ATTRS(AP_NO_ACCESS_UNPRIVILEGED);
 		}
 	} else {
-		assert(ctx->xlat_regime == EL3_REGIME);
+		assert((ctx->xlat_regime == EL2_REGIME) ||
+		       (ctx->xlat_regime == EL3_REGIME));
 		desc |= LOWER_ATTRS(AP_ONE_VA_RANGE_RES1);
 	}
 
@@ -1016,6 +1017,7 @@
 	assert(ctx != NULL);
 	assert(!ctx->initialized);
 	assert((ctx->xlat_regime == EL3_REGIME) ||
+	       (ctx->xlat_regime == EL2_REGIME) ||
 	       (ctx->xlat_regime == EL1_EL0_REGIME));
 	assert(!is_mmu_enabled_ctx(ctx));
 
diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c
index 8cad348..05533c6 100644
--- a/lib/xlat_tables_v2/xlat_tables_utils.c
+++ b/lib/xlat_tables_v2/xlat_tables_utils.c
@@ -60,8 +60,8 @@
 		tf_printf("DEV");
 	}
 
-	if (xlat_regime == EL3_REGIME) {
-		/* For EL3 only check the AP[2] and XN bits. */
+	if ((xlat_regime == EL3_REGIME) || (xlat_regime == EL2_REGIME)) {
+		/* For EL3 and EL2 only check the AP[2] and XN bits. */
 		tf_printf(((desc & LOWER_ATTRS(AP_RO)) != 0ULL) ? "-RO" : "-RW");
 		tf_printf(((desc & UPPER_ATTRS(XN)) != 0ULL) ? "-XN" : "-EXEC");
 	} else {
@@ -200,6 +200,8 @@
 
 	if (ctx->xlat_regime == EL1_EL0_REGIME) {
 		xlat_regime_str = "1&0";
+	} else if (ctx->xlat_regime == EL2_REGIME) {
+		xlat_regime_str = "2";
 	} else {
 		assert(ctx->xlat_regime == EL3_REGIME);
 		xlat_regime_str = "3";
@@ -329,6 +331,7 @@
 	assert(ctx != NULL);
 	assert(ctx->initialized);
 	assert((ctx->xlat_regime == EL1_EL0_REGIME) ||
+	       (ctx->xlat_regime == EL2_REGIME) ||
 	       (ctx->xlat_regime == EL3_REGIME));
 
 	virt_addr_space_size = (unsigned long long)ctx->va_max_address + 1ULL;
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index a192a06..e8e858d 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -122,7 +122,7 @@
 
 	arm_setup_page_tables(bl_regions, plat_arm_get_mmap());
 #ifdef AARCH32
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 #else
 	enable_mmu_el3(0);
 #endif /* AARCH32 */
diff --git a/plat/arm/common/arm_bl2_el3_setup.c b/plat/arm/common/arm_bl2_el3_setup.c
index 1c93214..c67ab49 100644
--- a/plat/arm/common/arm_bl2_el3_setup.c
+++ b/plat/arm/common/arm_bl2_el3_setup.c
@@ -82,7 +82,7 @@
 	arm_setup_page_tables(bl_regions, plat_arm_get_mmap());
 
 #ifdef AARCH32
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 #else
 	enable_mmu_el3(0);
 #endif
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 39aceb3..b92e363 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -252,7 +252,7 @@
 	arm_setup_page_tables(bl_regions, plat_arm_get_mmap());
 
 #ifdef AARCH32
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 #else
 	enable_mmu_el1(0);
 #endif
diff --git a/plat/arm/common/arm_bl2u_setup.c b/plat/arm/common/arm_bl2u_setup.c
index a626830..d9a75f0 100644
--- a/plat/arm/common/arm_bl2u_setup.c
+++ b/plat/arm/common/arm_bl2u_setup.c
@@ -79,7 +79,7 @@
 	arm_setup_page_tables(bl_regions, plat_arm_get_mmap());
 
 #ifdef AARCH32
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 #else
 	enable_mmu_el1(0);
 #endif
diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c
index 935290e..5191d69 100644
--- a/plat/arm/common/sp_min/arm_sp_min_setup.c
+++ b/plat/arm/common/sp_min/arm_sp_min_setup.c
@@ -212,5 +212,5 @@
 
 	arm_setup_page_tables(bl_regions, plat_arm_get_mmap());
 
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 }
diff --git a/plat/common/aarch32/plat_common.c b/plat/common/aarch32/plat_common.c
index 4f27149..16c2b5c 100644
--- a/plat/common/aarch32/plat_common.c
+++ b/plat/common/aarch32/plat_common.c
@@ -17,5 +17,5 @@
 
 void bl32_plat_enable_mmu(uint32_t flags)
 {
-	enable_mmu_secure(flags);
+	enable_mmu_svc_mon(flags);
 }
diff --git a/plat/layerscape/common/ls_bl1_setup.c b/plat/layerscape/common/ls_bl1_setup.c
index 43f7450..0642b5e 100644
--- a/plat/layerscape/common/ls_bl1_setup.c
+++ b/plat/layerscape/common/ls_bl1_setup.c
@@ -59,7 +59,7 @@
 			     );
 	VERBOSE("After setup the page tables\n");
 #ifdef AARCH32
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 #else
 	enable_mmu_el3(0);
 #endif /* AARCH32 */
diff --git a/plat/layerscape/common/ls_bl2_setup.c b/plat/layerscape/common/ls_bl2_setup.c
index 6e6ad6e..4b2dc72 100644
--- a/plat/layerscape/common/ls_bl2_setup.c
+++ b/plat/layerscape/common/ls_bl2_setup.c
@@ -53,7 +53,7 @@
 			      );
 
 #ifdef AARCH32
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 #else
 	enable_mmu_el1(0);
 #endif
diff --git a/plat/st/stm32mp1/stm32mp1_common.c b/plat/st/stm32mp1/stm32mp1_common.c
index 68ca7db..7d84da1 100644
--- a/plat/st/stm32mp1/stm32mp1_common.c
+++ b/plat/st/stm32mp1/stm32mp1_common.c
@@ -74,7 +74,7 @@
 	mmap_add(stm32mp1_mmap);
 	init_xlat_tables();
 
-	enable_mmu_secure(0);
+	enable_mmu_svc_mon(0);
 }
 
 uintptr_t plat_get_ns_image_entrypoint(void)