ARM platforms: Demonstrate mem_protect from el3_runtime

Previously mem_protect used to be only supported from BL2. This is not
helpful in the case when ARM TF-A BL2 is not used. This patch demonstrates
mem_protect from el3_runtime firmware on ARM Platforms specifically
when RESET_TO_BL31 or RESET_TO_SP_MIN flag is set as BL2 may be absent
in these cases. The Non secure DRAM is dynamically mapped into EL3 mmap
tables temporarily and then the protected regions are then cleared. This
avoids the need to map the non secure DRAM permanently to BL31/sp_min.

The stack size is also increased, because DYNAMIC_XLAT_TABLES require
a bigger stack.

Change-Id: Ia44c594192ed5c5adc596c0cff2c7cc18c001fde
Signed-off-by: Roberto Vargas <roberto.vargas@arm.com>
diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c
index c1c3e66..c4e83a4 100644
--- a/plat/arm/board/common/board_css_common.c
+++ b/plat/arm/board/common/board_css_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -73,6 +73,9 @@
 const mmap_region_t plat_arm_mmap[] = {
 #ifdef AARCH32
 	ARM_MAP_SHARED_RAM,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
 #endif
 	V2M_MAP_IOFPGA,
 	CSS_MAP_DEVICE,
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 0fa83a5..065ecc1 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -412,13 +412,7 @@
 	 */
 	.get_sys_suspend_power_state = fvp_get_sys_suspend_power_state,
 #endif
-#if !RESET_TO_BL31 && !RESET_TO_SP_MIN
-	/*
-	 * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
-	 * as that would require mapping in all of NS DRAM into BL31 or BL32.
-	 */
 	.mem_protect_chk	= arm_psci_mem_protect_chk,
 	.read_mem_protect	= arm_psci_read_mem_protect,
 	.write_mem_protect	= arm_nor_psci_write_mem_protect,
-#endif
 };
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 2d01490..b1adbee 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -7,6 +7,17 @@
 #ifndef __PLATFORM_DEF_H__
 #define __PLATFORM_DEF_H__
 
+/* Enable the dynamic translation tables library. */
+#ifdef AARCH32
+# if defined(IMAGE_BL32) && RESET_TO_SP_MIN
+#  define PLAT_XLAT_TABLES_DYNAMIC     1
+# endif
+#else
+# if defined(IMAGE_BL31) && RESET_TO_BL31
+#  define PLAT_XLAT_TABLES_DYNAMIC     1
+# endif
+#endif /* AARCH32 */
+
 #include <arm_def.h>
 #include <arm_spm_def.h>
 #include <board_arm_def.h>
@@ -40,6 +51,9 @@
 #define PLAT_ARM_TRUSTED_DRAM_BASE	0x06000000
 #define PLAT_ARM_TRUSTED_DRAM_SIZE	0x02000000	/* 32 MB */
 
+/* virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME	0xc0000000
+
 /* No SCP in FVP */
 #define PLAT_ARM_SCP_TZC_DRAM1_SIZE	ULL(0x0)
 
@@ -48,7 +62,7 @@
 /*
  * Load address of BL33 for this platform port
  */
-#define PLAT_ARM_NS_IMAGE_OFFSET	(ARM_DRAM1_BASE + 0x8000000)
+#define PLAT_ARM_NS_IMAGE_OFFSET	(ARM_DRAM1_BASE + U(0x8000000))
 
 
 /*
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index b422398..c834941 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -7,6 +7,18 @@
 #ifndef __PLATFORM_DEF_H__
 #define __PLATFORM_DEF_H__
 
+/* Enable the dynamic translation tables library. */
+#ifdef AARCH32
+# if defined(IMAGE_BL32) && RESET_TO_SP_MIN
+#  define PLAT_XLAT_TABLES_DYNAMIC     1
+# endif
+#else
+# if defined(IMAGE_BL31) && RESET_TO_BL31
+#  define PLAT_XLAT_TABLES_DYNAMIC     1
+# endif
+#endif /* AARCH32 */
+
+
 #include <arm_def.h>
 #include <board_arm_def.h>
 #include <board_css_def.h>
@@ -44,6 +56,9 @@
 /* Use the bypass address */
 #define PLAT_ARM_TRUSTED_ROM_BASE	V2M_FLASH0_BASE + BL1_ROM_BYPASS_OFFSET
 
+/* virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME	0xc0000000
+
 /*
  * Actual ROM size on Juno is 64 KB, but TBB currently requires at least 80 KB
  * in debug mode. We can test TBB on Juno bypassing the ROM and using 128 KB of
@@ -90,7 +105,7 @@
 #endif
 
 #ifdef IMAGE_BL32
-# define PLAT_ARM_MMAP_ENTRIES		5
+# define PLAT_ARM_MMAP_ENTRIES		6
 # define MAX_XLAT_TABLES		4
 #endif
 
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 8a6c768..dc7cd68 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -219,7 +219,7 @@
 	plat_arm_security_setup();
 
 #if defined(PLAT_ARM_MEM_PROT_ADDR)
-	arm_nor_psci_do_mem_protect();
+	arm_nor_psci_do_static_mem_protect();
 #endif
 }
 
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 963c4d2..3c70f9d 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -206,6 +206,10 @@
 	 */
 	plat_arm_security_setup();
 
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	arm_nor_psci_do_dyn_mem_protect();
+#endif /* PLAT_ARM_MEM_PROT_ADDR */
+
 #endif /* RESET_TO_BL31 */
 
 	/* Enable and initialize the System level generic timer */
diff --git a/plat/arm/common/arm_nor_psci_mem_protect.c b/plat/arm/common/arm_nor_psci_mem_protect.c
index 3167a42..c01e4ed 100644
--- a/plat/arm/common/arm_nor_psci_mem_protect.c
+++ b/plat/arm/common/arm_nor_psci_mem_protect.c
@@ -12,10 +12,22 @@
 #include <psci.h>
 #include <utils.h>
 
+
+/*
+ * DRAM1 is used also to load the NS boot loader. For this reason we
+ * cannot clear the full DRAM1, because in that case we would clear
+ * the NS images (especially for RESET_TO_BL31 and RESET_TO_SPMIN cases).
+ * For this reason we reserve 64 MB for the NS images and protect the RAM
+ * until the end of DRAM1.
+ * We limit the size of DRAM2 to 1 GB to avoid big delays while booting
+ */
+#define DRAM1_NS_IMAGE_LIMIT  (PLAT_ARM_NS_IMAGE_OFFSET + (32 << TWO_MB_SHIFT))
+#define DRAM1_PROTECTED_SIZE  (ARM_NS_DRAM1_END+1u - DRAM1_NS_IMAGE_LIMIT)
+
 static mem_region_t arm_ram_ranges[] = {
-	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_SIZE},
+	{DRAM1_NS_IMAGE_LIMIT, DRAM1_PROTECTED_SIZE},
 #ifdef AARCH64
-	{ARM_DRAM2_BASE, ARM_DRAM2_SIZE},
+	{ARM_DRAM2_BASE, 1u << ONE_GB_SHIFT},
 #endif
 };
 
@@ -29,7 +41,7 @@
 	int tmp;
 
 	tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR;
-	*enabled = (tmp == 1);
+	*enabled = (tmp == 1) ? 1 : 0;
 	return 0;
 }
 
@@ -46,7 +58,7 @@
 		return -1;
 	}
 
-	if (enable) {
+	if (enable != 0) {
 		/*
 		 * If we want to write a value different than 0
 		 * then we have to erase the full block because
@@ -71,15 +83,47 @@
  * Function used for required psci operations performed when
  * system boots
  ******************************************************************************/
-void arm_nor_psci_do_mem_protect(void)
+/*
+ * PLAT_MEM_PROTECT_VA_FRAME is a address specifically
+ * selected in a way that is not needed an additional
+ * translation table for memprotect. It happens because
+ * we use a chunk of size 2MB and it means that it can
+ * be mapped in a level 2 table and the level 2 table
+ * for 0xc0000000 is already used and the entry for
+ * 0xc0000000 is not used.
+ */
+#if defined(PLAT_XLAT_TABLES_DYNAMIC)
+void arm_nor_psci_do_dyn_mem_protect(void)
 {
 	int enable;
 
 	arm_psci_read_mem_protect(&enable);
-	if (!enable)
+	if (enable == 0)
 		return;
-	INFO("PSCI: Overwritting non secure memory\n");
-	clear_mem_regions(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges));
+
+	INFO("PSCI: Overwriting non secure memory\n");
+	clear_map_dyn_mem_regions(arm_ram_ranges,
+				  ARRAY_SIZE(arm_ram_ranges),
+				  PLAT_ARM_MEM_PROTEC_VA_FRAME,
+				  1 << TWO_MB_SHIFT);
+}
+#endif
+
+/*******************************************************************************
+ * Function used for required psci operations performed when
+ * system boots and dynamic memory is not used.
+ ******************************************************************************/
+void arm_nor_psci_do_static_mem_protect(void)
+{
+	int enable;
+
+	arm_psci_read_mem_protect(&enable);
+	if (enable == 0)
+		return;
+
+	INFO("PSCI: Overwriting non secure memory\n");
+	clear_mem_regions(arm_ram_ranges,
+			  ARRAY_SIZE(arm_ram_ranges));
 	arm_nor_psci_write_mem_protect(0);
 }
 
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 7b5477e..9a6c074 100644
--- a/plat/arm/common/sp_min/arm_sp_min_setup.c
+++ b/plat/arm/common/sp_min/arm_sp_min_setup.c
@@ -162,6 +162,11 @@
 	 */
 #if RESET_TO_SP_MIN
 	plat_arm_security_setup();
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	arm_nor_psci_do_dyn_mem_protect();
+#endif /* PLAT_ARM_MEM_PROT_ADDR */
+
 #endif
 
 	/* Enable and initialize the System level generic timer */
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index 4a615e1..3df5b78 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -303,11 +303,8 @@
 	.translate_power_state_by_mpidr = css_translate_power_state_by_mpidr,
 	.get_node_hw_state	= css_node_hw_state,
 	.get_sys_suspend_power_state = css_get_sys_suspend_power_state,
-/*
- * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
- * as that would require mapping in all of NS DRAM into BL31 or BL32.
- */
-#if defined(PLAT_ARM_MEM_PROT_ADDR) && !RESET_TO_BL31 && !RESET_TO_SP_MIN
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
 	.mem_protect_chk	= arm_psci_mem_protect_chk,
 	.read_mem_protect	= arm_psci_read_mem_protect,
 	.write_mem_protect	= arm_nor_psci_write_mem_protect,