Merge pull request #1513 from antonio-nino-diaz-arm/an/xlat-caches

xlat v2: Cleanup and dcache coherency bug fix
diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h
index fd61fc4..022acce 100644
--- a/include/lib/xlat_tables/xlat_tables_v2.h
+++ b/include/lib/xlat_tables/xlat_tables_v2.h
@@ -296,14 +296,15 @@
  * translation tables are not modified by any other code while this function is
  * executing.
  */
-int change_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va, size_t size,
-			  uint32_t attr);
+int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				   size_t size, uint32_t attr);
+int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr);
 
 /*
  * Query the memory attributes of a memory page in a set of translation tables.
  *
  * Return 0 on success, a negative error code on error.
- * On success, the attributes are stored into *attributes.
+ * On success, the attributes are stored into *attr.
  *
  * ctx
  *   Translation context to work on.
@@ -311,11 +312,12 @@
  *   Virtual address of the page to get the attributes of.
  *   There are no alignment restrictions on this address. The attributes of the
  *   memory page it lies within are returned.
- * attributes
+ * attr
  *   Output parameter where to store the attributes of the targeted memory page.
  */
-int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
-		       uint32_t *attributes);
+int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				uint32_t *attr);
+int xlat_get_mem_attributes(uintptr_t base_va, uint32_t *attr);
 
 #endif /*__ASSEMBLY__*/
 #endif /* XLAT_TABLES_V2_H */
diff --git a/lib/psci/aarch32/psci_helpers.S b/lib/psci/aarch32/psci_helpers.S
index a29a29c..63d7e70 100644
--- a/lib/psci/aarch32/psci_helpers.S
+++ b/lib/psci/aarch32/psci_helpers.S
@@ -91,28 +91,6 @@
 	stcopr	r0, SCTLR
 	isb
 
-#if PLAT_XLAT_TABLES_DYNAMIC
-	/* ---------------------------------------------
-	 * During warm boot the MMU is enabled with data
-	 * cache disabled, then the interconnect is set
-	 * up and finally the data cache is enabled.
-	 *
-	 * During this period, if another CPU modifies
-	 * the translation tables, the MMU table walker
-	 * may read the old entries. This is only a
-	 * problem for dynamic regions, the warm boot
-	 * code isn't affected because it is static.
-	 *
-	 * Invalidate all TLB entries loaded while the
-	 * CPU wasn't coherent with the rest of the
-	 * system.
-	 * ---------------------------------------------
-	 */
-	stcopr	r0, TLBIALL
-	dsb	ish
-	isb
-#endif
-
 	pop	{r12, pc}
 endfunc psci_do_pwrup_cache_maintenance
 
diff --git a/lib/psci/aarch64/psci_helpers.S b/lib/psci/aarch64/psci_helpers.S
index d37ca76..06d6636 100644
--- a/lib/psci/aarch64/psci_helpers.S
+++ b/lib/psci/aarch64/psci_helpers.S
@@ -115,28 +115,6 @@
 	msr	sctlr_el3, x0
 	isb
 
-#if PLAT_XLAT_TABLES_DYNAMIC
-	/* ---------------------------------------------
-	 * During warm boot the MMU is enabled with data
-	 * cache disabled, then the interconnect is set
-	 * up and finally the data cache is enabled.
-	 *
-	 * During this period, if another CPU modifies
-	 * the translation tables, the MMU table walker
-	 * may read the old entries. This is only a
-	 * problem for dynamic regions, the warm boot
-	 * code isn't affected because it is static.
-	 *
-	 * Invalidate all TLB entries loaded while the
-	 * CPU wasn't coherent with the rest of the
-	 * system.
-	 * ---------------------------------------------
-	 */
-	tlbi	alle3
-	dsb	ish
-	isb
-#endif
-
 	ldp	x29, x30, [sp], #16
 	ret
 endfunc psci_do_pwrup_cache_maintenance
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index c09fb59..2482840 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -48,6 +48,11 @@
 	return (read_sctlr() & SCTLR_M_BIT) != 0;
 }
 
+bool is_dcache_enabled(void)
+{
+	return (read_sctlr() & SCTLR_C_BIT) != 0;
+}
+
 uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime __unused)
 {
 	return UPPER_ATTRS(XN);
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index 4e4292f..cf8070a 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -112,6 +112,17 @@
 	}
 }
 
+bool is_dcache_enabled(void)
+{
+	unsigned int el = (unsigned int)GET_EL(read_CurrentEl());
+
+	if (el == 1U) {
+		return (read_sctlr_el1() & SCTLR_C_BIT) != 0U;
+	} else {
+		return (read_sctlr_el3() & SCTLR_C_BIT) != 0U;
+	}
+}
+
 uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime)
 {
 	if (xlat_regime == EL1_EL0_REGIME) {
diff --git a/lib/xlat_tables_v2/xlat_tables_context.c b/lib/xlat_tables_v2/xlat_tables_context.c
index d7b2ebf..143f08a 100644
--- a/lib/xlat_tables_v2/xlat_tables_context.c
+++ b/lib/xlat_tables_v2/xlat_tables_context.c
@@ -90,6 +90,16 @@
 	init_xlat_tables_ctx(&tf_xlat_ctx);
 }
 
+int xlat_get_mem_attributes(uintptr_t base_va, uint32_t *attr)
+{
+	return xlat_get_mem_attributes_ctx(&tf_xlat_ctx, base_va, attr);
+}
+
+int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr)
+{
+	return xlat_change_mem_attributes_ctx(&tf_xlat_ctx, base_va, size, attr);
+}
+
 /*
  * If dynamic allocation of new regions is disabled then by the time we call the
  * function enabling the MMU, we'll have registered all the memory regions to
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
index 54e5834..56b9514 100644
--- a/lib/xlat_tables_v2/xlat_tables_core.c
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -18,6 +18,13 @@
 
 #include "xlat_tables_private.h"
 
+/* Helper function that cleans the data cache only if it is enabled. */
+static inline void xlat_clean_dcache_range(uintptr_t addr, size_t size)
+{
+	if (is_dcache_enabled())
+		clean_dcache_range(addr, size);
+}
+
 #if PLAT_XLAT_TABLES_DYNAMIC
 
 /*
@@ -329,7 +336,10 @@
 			xlat_tables_unmap_region(ctx, mm, table_idx_va,
 						 subtable, XLAT_TABLE_ENTRIES,
 						 level + 1U);
-
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)subtable,
+				XLAT_TABLE_ENTRIES * sizeof(uint64_t));
+#endif
 			/*
 			 * If the subtable is now empty, remove its reference.
 			 */
@@ -563,6 +573,10 @@
 			end_va = xlat_tables_map_region(ctx, mm, table_idx_va,
 					       subtable, XLAT_TABLE_ENTRIES,
 					       level + 1U);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)subtable,
+				XLAT_TABLE_ENTRIES * sizeof(uint64_t));
+#endif
 			if (end_va !=
 				(table_idx_va + XLAT_BLOCK_SIZE(level) - 1U))
 				return end_va;
@@ -575,6 +589,10 @@
 			end_va = xlat_tables_map_region(ctx, mm, table_idx_va,
 					       subtable, XLAT_TABLE_ENTRIES,
 					       level + 1U);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)subtable,
+				XLAT_TABLE_ENTRIES * sizeof(uint64_t));
+#endif
 			if (end_va !=
 				(table_idx_va + XLAT_BLOCK_SIZE(level) - 1U))
 				return end_va;
@@ -859,7 +877,10 @@
 		end_va = xlat_tables_map_region(ctx, mm_cursor,
 				0U, ctx->base_table, ctx->base_table_entries,
 				ctx->base_level);
-
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+				   ctx->base_table_entries * sizeof(uint64_t));
+#endif
 		/* Failed to map, remove mmap entry, unmap and return error. */
 		if (end_va != (mm_cursor->base_va + mm_cursor->size - 1U)) {
 			(void)memmove(mm_cursor, mm_cursor + 1U,
@@ -885,7 +906,10 @@
 			xlat_tables_unmap_region(ctx, &unmap_mm, 0U,
 				ctx->base_table, ctx->base_table_entries,
 				ctx->base_level);
-
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+				ctx->base_table_entries * sizeof(uint64_t));
+#endif
 			return -ENOMEM;
 		}
 
@@ -951,6 +975,10 @@
 		xlat_tables_unmap_region(ctx, mm, 0U, ctx->base_table,
 					 ctx->base_table_entries,
 					 ctx->base_level);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+			ctx->base_table_entries * sizeof(uint64_t));
+#endif
 		xlat_arch_tlbi_va_sync();
 	}
 
@@ -1012,7 +1040,10 @@
 		uintptr_t end_va = xlat_tables_map_region(ctx, mm, 0U,
 				ctx->base_table, ctx->base_table_entries,
 				ctx->base_level);
-
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+				   ctx->base_table_entries * sizeof(uint64_t));
+#endif
 		if (end_va != (mm->base_va + mm->size - 1U)) {
 			ERROR("Not enough memory to map region:\n"
 			      " VA:0x%lx  PA:0x%llx  size:0x%zx  attr:0x%x\n",
diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h
index 313bd8d..528996a 100644
--- a/lib/xlat_tables_v2/xlat_tables_private.h
+++ b/lib/xlat_tables_v2/xlat_tables_private.h
@@ -97,4 +97,7 @@
  */
 bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx);
 
+/* Returns true if the data cache is enabled at the current EL. */
+bool is_dcache_enabled(void);
+
 #endif /* XLAT_TABLES_PRIVATE_H */
diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c
index 0cbd45e..8cad348 100644
--- a/lib/xlat_tables_v2/xlat_tables_utils.c
+++ b/lib/xlat_tables_v2/xlat_tables_utils.c
@@ -314,8 +314,8 @@
 }
 
 
-static int get_mem_attributes_internal(const xlat_ctx_t *ctx, uintptr_t base_va,
-		uint32_t *attributes, uint64_t **table_entry,
+static int xlat_get_mem_attributes_internal(const xlat_ctx_t *ctx,
+		uintptr_t base_va, uint32_t *attributes, uint64_t **table_entry,
 		unsigned long long *addr_pa, unsigned int *table_level)
 {
 	uint64_t *entry;
@@ -407,18 +407,16 @@
 }
 
 
-int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
-		       uint32_t *attributes)
+int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				uint32_t *attr)
 {
-	return get_mem_attributes_internal(ctx, base_va, attributes,
-					   NULL, NULL, NULL);
+	return xlat_get_mem_attributes_internal(ctx, base_va, attr,
+				NULL, NULL, NULL);
 }
 
 
-int change_mem_attributes(const xlat_ctx_t *ctx,
-			uintptr_t base_va,
-			size_t size,
-			uint32_t attr)
+int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				   size_t size, uint32_t attr)
 {
 	/* Note: This implementation isn't optimized. */
 
@@ -517,7 +515,7 @@
 		unsigned int level = 0U;
 		unsigned long long addr_pa = 0ULL;
 
-		(void) get_mem_attributes_internal(ctx, base_va, &old_attr,
+		(void) xlat_get_mem_attributes_internal(ctx, base_va, &old_attr,
 					    &entry, &addr_pa, &level);
 
 		/*
@@ -541,7 +539,9 @@
 		 * before writing the new descriptor.
 		 */
 		*entry = INVALID_DESC;
-
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		dccvac((uintptr_t)entry);
+#endif
 		/* Invalidate any cached copy of this mapping in the TLBs. */
 		xlat_arch_tlbi_va(base_va, ctx->xlat_regime);
 
@@ -550,7 +550,9 @@
 
 		/* Write new descriptor */
 		*entry = xlat_desc(ctx, new_attr, addr_pa, level);
-
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		dccvac((uintptr_t)entry);
+#endif
 		base_va += PAGE_SIZE;
 	}
 
diff --git a/services/std_svc/spm/sp_xlat.c b/services/std_svc/spm/sp_xlat.c
index 2aa2fa1..3527138 100644
--- a/services/std_svc/spm/sp_xlat.c
+++ b/services/std_svc/spm/sp_xlat.c
@@ -44,7 +44,7 @@
  * converts an attributes value from the SMC format to the mmap_attr_t format by
  * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
  * The other fields are left as 0 because they are ignored by the function
- * change_mem_attributes().
+ * xlat_change_mem_attributes_ctx().
  */
 static unsigned int smc_attr_to_mmap_attr(unsigned int attributes)
 {
@@ -112,12 +112,12 @@
 
 	spin_lock(&mem_attr_smc_lock);
 
-	int rc = get_mem_attributes(sp_ctx->xlat_ctx_handle,
+	int rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
 				     base_va, &attributes);
 
 	spin_unlock(&mem_attr_smc_lock);
 
-	/* Convert error codes of get_mem_attributes() into SPM ones. */
+	/* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */
 	assert((rc == 0) || (rc == -EINVAL));
 
 	if (rc == 0) {
@@ -142,13 +142,13 @@
 
 	spin_lock(&mem_attr_smc_lock);
 
-	int ret = change_mem_attributes(sp_ctx->xlat_ctx_handle,
+	int ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
 					base_va, size,
 					smc_attr_to_mmap_attr(attributes));
 
 	spin_unlock(&mem_attr_smc_lock);
 
-	/* Convert error codes of change_mem_attributes() into SPM ones. */
+	/* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */
 	assert((ret == 0) || (ret == -EINVAL));
 
 	return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;