Add wrapper for AT instruction

In case of AT speculative workaround applied, page table walk
is disabled for lower ELs (EL1 and EL0) in EL3.
Hence added a wrapper function which temporarily enables page
table walk to execute AT instruction for lower ELs and then
disables page table walk.

Execute AT instructions directly for lower ELs (EL1 and EL0)
assuming page table walk is enabled always when AT speculative
workaround is not applied.

Change-Id: I4ad4c0bcbb761448af257e9f72ae979473c0dde8
Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
diff --git a/common/backtrace/backtrace.c b/common/backtrace/backtrace.c
index ef57500..a07c066 100644
--- a/common/backtrace/backtrace.c
+++ b/common/backtrace/backtrace.c
@@ -70,7 +70,7 @@
 	} else if (el == 2U) {
 		ats1e2r(addr);
 	} else {
-		ats1e1r(addr);
+		AT(ats1e1r, addr);
 	}
 
 	isb();
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 4bff0f6..1f2f4a9 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -590,4 +590,24 @@
 #define read_clusterpwrdn()	read_clusterpwrdn_el1()
 #define write_clusterpwrdn(_v)	write_clusterpwrdn_el1(_v)
 
+#if ERRATA_SPECULATIVE_AT
+/*
+ * Assuming SCTLR.M bit is already enabled
+ * 1. Enable page table walk by clearing TCR_EL1.EPDx bits
+ * 2. Execute AT instruction for lower EL1/0
+ * 3. Disable page table walk by setting TCR_EL1.EPDx bits
+ */
+#define AT(_at_inst, _va)	\
+{	\
+	assert((read_sctlr_el1() & SCTLR_M_BIT) != 0ULL);	\
+	write_tcr_el1(read_tcr_el1() & ~(TCR_EPD0_BIT | TCR_EPD1_BIT));	\
+	isb();	\
+	_at_inst(_va);	\
+	write_tcr_el1(read_tcr_el1() | (TCR_EPD0_BIT | TCR_EPD1_BIT));	\
+	isb();	\
+}
+#else
+#define AT(_at_inst, _va)	_at_inst(_va);
+#endif
+
 #endif /* ARCH_HELPERS_H */
diff --git a/plat/arm/common/arm_common.c b/plat/arm/common/arm_common.c
index e2b99a3..e55ea90 100644
--- a/plat/arm/common/arm_common.c
+++ b/plat/arm/common/arm_common.c
@@ -216,7 +216,7 @@
 		 * Translate entry point to Physical Address using the EL1&0
 		 * translation regime, including stage 2.
 		 */
-		ats12e1r(ep);
+		AT(ats12e1r, ep);
 	}
 	isb();
 	par = read_par_el1();
diff --git a/services/spd/tlkd/tlkd_common.c b/services/spd/tlkd/tlkd_common.c
index dbe6c2e..820bd8a 100644
--- a/services/spd/tlkd/tlkd_common.c
+++ b/services/spd/tlkd/tlkd_common.c
@@ -38,16 +38,16 @@
 	int at = type & AT_MASK;
 	switch (at) {
 	case 0:
-		ats12e1r(va);
+		AT(ats12e1r, va);
 		break;
 	case 1:
-		ats12e1w(va);
+		AT(ats12e1w, va);
 		break;
 	case 2:
-		ats12e0r(va);
+		AT(ats12e0r, va);
 		break;
 	case 3:
-		ats12e0w(va);
+		AT(ats12e0w, va);
 		break;
 	default:
 		assert(0); /* Unreachable */