Merge pull request #1792 from satheesbalya-arm/sb1/sb1_2159_v84_xlat

lib/xlat_tables: Add support for ARMv8.4-TTST
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 9e2bffa..76c3e27 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -204,6 +204,10 @@
 
 /* ID_AA64MMFR2_EL1 definitions */
 #define ID_AA64MMFR2_EL1		S3_0_C0_C7_2
+
+#define ID_AA64MMFR2_EL1_ST_SHIFT	U(28)
+#define ID_AA64MMFR2_EL1_ST_MASK	ULL(0xf)
+
 #define ID_AA64MMFR2_EL1_CNP_SHIFT	U(0)
 #define ID_AA64MMFR2_EL1_CNP_MASK	ULL(0xf)
 
@@ -427,6 +431,7 @@
 
 #define TCR_TxSZ_MIN		ULL(16)
 #define TCR_TxSZ_MAX		ULL(39)
+#define TCR_TxSZ_MAX_TTST	ULL(48)
 
 /* (internal) physical address size bits in EL3/EL1 */
 #define TCR_PS_BITS_4GB		ULL(0x0)
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 2b09ba0..9bf43bf 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -17,4 +17,10 @@
 		ID_AA64MMFR2_EL1_CNP_MASK) != 0U;
 }
 
+static inline bool is_armv8_4_ttst_present(void)
+{
+	return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_ST_SHIFT) &
+		ID_AA64MMFR2_EL1_ST_MASK) == 1U;
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h
index a333d1e..30eb5e9 100644
--- a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h
+++ b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h
@@ -63,8 +63,7 @@
  * is 1.
  *
  * Note that this macro assumes that the given virtual address space size is
- * valid. Therefore, the caller is expected to check it is the case using the
- * CHECK_VIRT_ADDR_SPACE_SIZE() macro first.
+ * valid.
  */
 #define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz)			\
 	(((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) ?	\
diff --git a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
index cc5624c..3014c8f 100644
--- a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
+++ b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
@@ -43,14 +43,22 @@
  * state.
  *
  * TCR.TxSZ is calculated as 64 minus the width of said address space.
- * The value of TCR.TxSZ must be in the range 16 to 39 [1], which means that
- * the virtual address space width must be in the range 48 to 25 bits.
+ * The value of TCR.TxSZ must be in the range 16 to 39 [1] or 48 [2],
+ * depending on Small Translation Table Support which means that
+ * the virtual address space width must be in the range 48 to 25 or 16 bits.
  *
  * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more
  * information:
  * Page 1730: 'Input address size', 'For all translation stages'.
+ * [2] See section 12.2.55 in the ARMv8-A Architecture Reference Manual
+ * (DDI 0487D.a)
  */
+/* Maximum value of TCR_ELx.T(0,1)SZ is 39 */
 #define MIN_VIRT_ADDR_SPACE_SIZE	(ULL(1) << (U(64) - TCR_TxSZ_MAX))
+
+/* Maximum value of TCR_ELx.T(0,1)SZ is 48 */
+#define MIN_VIRT_ADDR_SPACE_SIZE_TTST	\
+				(ULL(1) << (U(64) - TCR_TxSZ_MAX_TTST))
 #define MAX_VIRT_ADDR_SPACE_SIZE	(ULL(1) << (U(64) - TCR_TxSZ_MIN))
 
 /*
@@ -58,9 +66,13 @@
  * virtual address space size. For a 4 KB page size,
  * - level 0 supports virtual address spaces of widths 48 to 40 bits;
  * - level 1 from 39 to 31;
- * - level 2 from 30 to 25.
+ * - level 2 from 30 to 22.
+ * - level 3 from 21 to 16.
  *
- * Wider or narrower address spaces are not supported. As a result, level 3
+ * Small Translation Table (Armv8.4-TTST) support allows the starting level
+ * of the translation table from 3 for 4KB granularity. See section 12.2.55 in
+ * the ARMv8-A Architecture Reference Manual (DDI 0487D.a). In Armv8.3 and below
+ * wider or narrower address spaces are not supported. As a result, level 3
  * cannot be used as initial lookup level with 4 KB granularity. See section
  * D4.2.5 in the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more
  * information.
@@ -71,13 +83,14 @@
  * is 1.
  *
  * Note that this macro assumes that the given virtual address space size is
- * valid. Therefore, the caller is expected to check it is the case using the
- * CHECK_VIRT_ADDR_SPACE_SIZE() macro first.
+ * valid.
  */
 #define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz)		\
 	(((_virt_addr_space_sz) > (ULL(1) << L0_XLAT_ADDRESS_SHIFT))	\
 	? 0U								\
-	 : (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT))	\
-	 ? 1U : 2U))
+	: (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT))	\
+	? 1U								\
+	: (((_virt_addr_space_sz) > (ULL(1) << L2_XLAT_ADDRESS_SHIFT))	\
+	? 2U : 3U)))
 
 #endif /* XLAT_TABLES_AARCH64_H */
diff --git a/include/lib/xlat_tables/xlat_tables_arch.h b/include/lib/xlat_tables/xlat_tables_arch.h
index 251b020..7237534 100644
--- a/include/lib/xlat_tables/xlat_tables_arch.h
+++ b/include/lib/xlat_tables/xlat_tables_arch.h
@@ -14,18 +14,6 @@
 #endif
 
 /*
- * Evaluates to 1 if the given virtual address space size is valid, or 0 if it's
- * not.
- *
- * A valid size is one that is a power of 2 and is within the architectural
- * limits. Not that these limits are different for AArch32 and AArch64.
- */
-#define CHECK_VIRT_ADDR_SPACE_SIZE(size)			\
-	(((unsigned long long)(size) >= MIN_VIRT_ADDR_SPACE_SIZE) &&	\
-	((unsigned long long)(size) <= MAX_VIRT_ADDR_SPACE_SIZE) &&	\
-	IS_POWER_OF_TWO(size))
-
-/*
  * Evaluates to 1 if the given physical address space size is a power of 2,
  * or 0 if it's not.
  */
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
index ce5cf82..6a1be32 100644
--- a/include/lib/xlat_tables/xlat_tables_v2_helpers.h
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
@@ -125,9 +125,6 @@
 #define REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count,		\
 			_xlat_tables_count, _virt_addr_space_size,	\
 			_phy_addr_space_size, _xlat_regime, _section_name)\
-	CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(_virt_addr_space_size),	\
-		assert_invalid_virtual_addr_space_size_for_##_ctx_name);\
-									\
 	CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(_phy_addr_space_size),	\
 		assert_invalid_physical_addr_space_sizefor_##_ctx_name);\
 									\
diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c
index 468a9e7..4b01b9b 100644
--- a/lib/xlat_tables/aarch32/xlat_tables.c
+++ b/lib/xlat_tables/aarch32/xlat_tables.c
@@ -55,6 +55,11 @@
 {
 	unsigned long long max_pa;
 	uintptr_t max_va;
+
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE >= MIN_VIRT_ADDR_SPACE_SIZE);
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE);
+	assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE));
+
 	print_mmap();
 	init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE,
 						&max_va, &max_pa);
diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c
index 71f491a..e64fd3e 100644
--- a/lib/xlat_tables/aarch64/xlat_tables.c
+++ b/lib/xlat_tables/aarch64/xlat_tables.c
@@ -10,7 +10,7 @@
 #include <platform_def.h>
 
 #include <arch.h>
-#include <arch_helpers.h>
+#include <arch_features.h>
 #include <common/bl_common.h>
 #include <lib/utils.h>
 #include <lib/xlat_tables/xlat_tables.h>
@@ -79,6 +79,21 @@
 
 	return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL;
 }
+
+/*
+ * Return minimum virtual address space size supported by the architecture
+ */
+static uintptr_t xlat_get_min_virt_addr_space_size(void)
+{
+	uintptr_t ret;
+
+	if (is_armv8_4_ttst_present())
+		ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST;
+	else
+		ret = MIN_VIRT_ADDR_SPACE_SIZE;
+
+	return ret;
+}
 #endif /* ENABLE_ASSERTIONS */
 
 unsigned int xlat_arch_current_el(void)
@@ -104,6 +119,12 @@
 {
 	unsigned long long max_pa;
 	uintptr_t max_va;
+
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE >=
+		(xlat_get_min_virt_addr_space_size() - 1U));
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE);
+	assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE));
+
 	print_mmap();
 	init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE,
 			   &max_va, &max_pa);
diff --git a/lib/xlat_tables/xlat_tables_private.h b/lib/xlat_tables/xlat_tables_private.h
index 4390f34..82bc70c 100644
--- a/lib/xlat_tables/xlat_tables_private.h
+++ b/lib/xlat_tables/xlat_tables_private.h
@@ -16,9 +16,6 @@
 #error xlat tables v2 must be used with HW_ASSISTED_COHERENCY
 #endif
 
-CASSERT(CHECK_VIRT_ADDR_SPACE_SIZE(PLAT_VIRT_ADDR_SPACE_SIZE),
-	assert_valid_virt_addr_space_size);
-
 CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(PLAT_PHY_ADDR_SPACE_SIZE),
 	assert_valid_phy_addr_space_size);
 
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index 913c86d..b69c670 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -45,6 +45,14 @@
 	/* Physical address space size for long descriptor format. */
 	return (1ULL << 40) - 1ULL;
 }
+
+/*
+ * Return minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void)
+{
+	return MIN_VIRT_ADDR_SPACE_SIZE;
+}
 #endif /* ENABLE_ASSERTIONS*/
 
 bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx)
@@ -193,7 +201,12 @@
 	if (max_va != UINT32_MAX) {
 		uintptr_t virtual_addr_space_size = max_va + 1U;
 
-		assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size));
+		assert(virtual_addr_space_size >=
+			xlat_get_min_virt_addr_space_size());
+		assert(virtual_addr_space_size <=
+			MAX_VIRT_ADDR_SPACE_SIZE);
+		assert(IS_POWER_OF_TWO(virtual_addr_space_size));
+
 		/*
 		 * __builtin_ctzll(0) is undefined but here we are guaranteed
 		 * that virtual_addr_space_size is in the range [1, UINT32_MAX].
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index 228f751..e7593dd 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -101,6 +101,21 @@
 
 	return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL;
 }
+
+/*
+ * Return minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void)
+{
+	uintptr_t ret;
+
+	if (is_armv8_4_ttst_present())
+		ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST;
+	else
+		ret = MIN_VIRT_ADDR_SPACE_SIZE;
+
+	return ret;
+}
 #endif /* ENABLE_ASSERTIONS*/
 
 bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx)
@@ -221,7 +236,11 @@
 	assert(max_va < ((uint64_t)UINTPTR_MAX));
 
 	virtual_addr_space_size = (uintptr_t)max_va + 1U;
-	assert(CHECK_VIRT_ADDR_SPACE_SIZE(virtual_addr_space_size));
+
+	assert(virtual_addr_space_size >=
+		xlat_get_min_virt_addr_space_size());
+	assert(virtual_addr_space_size <= MAX_VIRT_ADDR_SPACE_SIZE);
+	assert(IS_POWER_OF_TWO(virtual_addr_space_size));
 
 	/*
 	 * __builtin_ctzll(0) is undefined but here we are guaranteed that
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
index c49554f..4820b4f 100644
--- a/lib/xlat_tables_v2/xlat_tables_core.c
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -1146,6 +1146,11 @@
 
 	mmap_region_t *mm = ctx->mmap;
 
+	assert(ctx->va_max_address >=
+		(xlat_get_min_virt_addr_space_size() - 1U));
+	assert(ctx->va_max_address <= (MAX_VIRT_ADDR_SPACE_SIZE - 1U));
+	assert(IS_POWER_OF_TWO(ctx->va_max_address + 1U));
+
 	xlat_mmap_print(mm);
 
 	/* All tables must be zeroed before mapping any region. */
diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h
index fc70955..70ef395 100644
--- a/lib/xlat_tables_v2/xlat_tables_private.h
+++ b/lib/xlat_tables_v2/xlat_tables_private.h
@@ -102,4 +102,9 @@
 /* Returns true if the data cache is enabled at the current EL. */
 bool is_dcache_enabled(void);
 
+/*
+ * Returns minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void);
+
 #endif /* XLAT_TABLES_PRIVATE_H */