Merge pull request #1109 from robertovargas-arm/mem_protect

Mem protect
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index 0ed39c9..0b44ab2 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -65,6 +65,9 @@
 #define PSCI_STAT_RESIDENCY_AARCH64	U(0xc4000010)
 #define PSCI_STAT_COUNT_AARCH32		U(0x84000011)
 #define PSCI_STAT_COUNT_AARCH64		U(0xc4000011)
+#define PSCI_MEM_PROTECT		U(0x84000013)
+#define PSCI_MEM_CHK_RANGE_AARCH32	U(0x84000014)
+#define PSCI_MEM_CHK_RANGE_AARCH64	U(0xc4000014)
 
 /* Macro to help build the psci capabilities bitfield */
 #define define_psci_cap(x)		(U(1) << (x & U(0x1f)))
@@ -288,6 +291,9 @@
 				    unsigned int power_state,
 				    psci_power_state_t *output_state);
 	int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
+	int (*mem_protect_chk)(uintptr_t base, u_register_t length);
+	int (*read_mem_protect)(int *val);
+	int (*write_mem_protect)(int val);
 } plat_psci_ops_t;
 
 /*******************************************************************************
diff --git a/include/lib/utils.h b/include/lib/utils.h
index b75813f..cfc8302 100644
--- a/include/lib/utils.h
+++ b/include/lib/utils.h
@@ -19,6 +19,25 @@
 
 #include <types.h>
 
+typedef struct mem_region_t {
+	uintptr_t base;
+	size_t nbytes;
+} mem_region_t;
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions);
+
+
+/*
+ * checks that a region (addr + nbytes-1) of memory is totally covered by
+ * one of the regions defined in tbl. Caller must ensure that (addr+nbytes-1)
+ * doesn't overflow.
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+			    uintptr_t addr, size_t nbytes);
+
 /*
  * Fill a region of normal memory of size "length" in bytes with zero bytes.
  *
diff --git a/include/plat/arm/board/common/board_arm_def.h b/include/plat/arm/board/common/board_arm_def.h
index 4d14500..ae0f956 100644
--- a/include/plat/arm/board/common/board_arm_def.h
+++ b/include/plat/arm/board/common/board_arm_def.h
@@ -89,11 +89,26 @@
 
 #define PLAT_ARM_TRUSTED_SRAM_SIZE	0x00040000	/* 256 KB */
 
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
 #define PLAT_ARM_FIP_BASE		V2M_FLASH0_BASE
-#define PLAT_ARM_FIP_MAX_SIZE		V2M_FLASH0_SIZE
+#define PLAT_ARM_FIP_MAX_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
 
 #define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
-#define PLAT_ARM_NVM_SIZE		V2M_FLASH0_SIZE
+#define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR		(V2M_FLASH0_BASE + \
+					 V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
 
+/*
+ * Map mem_protect flash region with read and write permissions
+ */
+#define ARM_V2M_MAP_MEM_PROTECT		MAP_REGION_FLAT(PLAT_ARM_MEM_PROT_ADDR,	\
+						V2M_FLASH_BLOCK_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
 
 #endif /* __BOARD_ARM_DEF_H__ */
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
index 2ad513a..364b780 100644
--- a/include/plat/arm/board/common/v2m_def.h
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -69,6 +69,7 @@
 /* NOR Flash */
 #define V2M_FLASH0_BASE			0x08000000
 #define V2M_FLASH0_SIZE			0x04000000
+#define V2M_FLASH_BLOCK_SIZE		0x00040000	/* 256 KB */
 
 #define V2M_IOFPGA_BASE			0x1c000000
 #define V2M_IOFPGA_SIZE			0x03000000
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 787ccb0..dbf102b 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -177,7 +177,12 @@
 						ARM_NS_DRAM1_SIZE,	\
 						MT_MEMORY | MT_RW | MT_NS)
 
+#define ARM_MAP_DRAM2			MAP_REGION_FLAT(		\
+						ARM_DRAM2_BASE,		\
+						ARM_DRAM2_SIZE,		\
+						MT_MEMORY | MT_RW | MT_NS)
 #ifdef SPD_tspd
+
 #define ARM_MAP_TSP_SEC_MEM		MAP_REGION_FLAT(		\
 						TSP_SEC_MEM_BASE,	\
 						TSP_SEC_MEM_SIZE,	\
@@ -224,8 +229,18 @@
  * Required platform porting definitions common to all ARM standard platforms
  *****************************************************************************/
 
+/*
+ * We need to access DRAM2 from BL2 for PSCI_MEM_PROTECT for
+ * AArch64 builds
+ */
+#ifdef AARCH64
+#define PLAT_PHY_ADDR_SPACE_SIZE			(1ull << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE			(1ull << 36)
+#else
 #define PLAT_PHY_ADDR_SPACE_SIZE			(1ull << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE			(1ull << 32)
+#endif
+
 
 /*
  * This macro defines the deepest retention state possible. A higher state
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index f0e9767..4e589c0 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -122,6 +122,10 @@
 int arm_validate_ns_entrypoint(uintptr_t entrypoint);
 void arm_system_pwr_domain_resume(void);
 void arm_program_trusted_mailbox(uintptr_t address);
+int arm_psci_read_mem_protect(int *val);
+int arm_nor_psci_write_mem_protect(int val);
+void arm_nor_psci_do_mem_protect(void);
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length);
 
 /* Topology utility function */
 int arm_check_mpidr(u_register_t mpidr);
diff --git a/lib/psci/psci_lib.mk b/lib/psci/psci_lib.mk
index 29080db..1d4aac4 100644
--- a/lib/psci/psci_lib.mk
+++ b/lib/psci/psci_lib.mk
@@ -17,6 +17,7 @@
 				lib/psci/psci_main.c			\
 				lib/psci/psci_setup.c			\
 				lib/psci/psci_system_off.c		\
+				lib/psci/psci_mem_protect.c		\
 				lib/psci/${ARCH}/psci_helpers.S
 
 ifeq (${ARCH}, aarch64)
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 257479a..a5d707e 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -408,6 +408,11 @@
 		case PSCI_STAT_COUNT_AARCH32:
 			return psci_stat_count(x1, x2);
 #endif
+		case PSCI_MEM_PROTECT:
+			return psci_mem_protect(x1);
+
+		case PSCI_MEM_CHK_RANGE_AARCH32:
+			return psci_mem_chk_range(x1, x2);
 
 		default:
 			break;
@@ -445,6 +450,10 @@
 			return psci_stat_count(x1, x2);
 #endif
 
+		case PSCI_MEM_CHK_RANGE_AARCH64:
+			return psci_mem_chk_range(x1, x2);
+
+
 		default:
 			break;
 		}
diff --git a/lib/psci/psci_mem_protect.c b/lib/psci/psci_mem_protect.c
new file mode 100644
index 0000000..fca84e9
--- /dev/null
+++ b/lib/psci/psci_mem_protect.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <utils.h>
+#include "psci_private.h"
+
+int psci_mem_protect(unsigned int enable)
+{
+	int val;
+
+	assert(psci_plat_pm_ops->read_mem_protect);
+	assert(psci_plat_pm_ops->write_mem_protect);
+
+	if (psci_plat_pm_ops->read_mem_protect(&val) < 0)
+		return PSCI_E_NOT_SUPPORTED;
+	if (psci_plat_pm_ops->write_mem_protect(enable) < 0)
+		return PSCI_E_NOT_SUPPORTED;
+
+	return val != 0;
+}
+
+int psci_mem_chk_range(uintptr_t base, u_register_t length)
+{
+	int ret;
+
+	assert(psci_plat_pm_ops->mem_protect_chk);
+
+	if (length == 0 || check_uptr_overflow(base, length-1))
+		return PSCI_E_DENIED;
+
+	ret = psci_plat_pm_ops->mem_protect_chk(base, length);
+	return (ret < 0) ? PSCI_E_DENIED : PSCI_E_SUCCESS;
+}
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index da6a20f..facfacb 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -269,4 +269,8 @@
 u_register_t psci_stat_count(u_register_t target_cpu,
 			unsigned int power_state);
 
+/* Private exported functions from psci_mem_protect.c */
+int psci_mem_protect(unsigned int enable);
+int psci_mem_chk_range(uintptr_t base, u_register_t length);
+
 #endif /* __PSCI_PRIVATE_H__ */
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index f70e34d..5ef49ac 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -243,6 +243,11 @@
 		psci_caps |=  define_psci_cap(PSCI_SYSTEM_RESET);
 	if (psci_plat_pm_ops->get_node_hw_state)
 		psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
+	if (psci_plat_pm_ops->read_mem_protect &&
+			psci_plat_pm_ops->write_mem_protect)
+		psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
+	if (psci_plat_pm_ops->mem_protect_chk)
+		psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
 
 #if ENABLE_PSCI_STAT
 	psci_caps |=  define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
diff --git a/lib/utils/mem_region.c b/lib/utils/mem_region.c
new file mode 100644
index 0000000..31c6231
--- /dev/null
+++ b/lib/utils/mem_region.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <utils.h>
+
+/*
+ * All the regions defined in mem_region_t must have the following properties
+ *
+ * - Any contiguous regions must be merged into a single entry.
+ * - The number of bytes of each region must be greater than zero.
+ * - The calculation of the highest address within the region (base + nbytes-1)
+ *   doesn't produce an overflow.
+ *
+ * These conditions must be fulfilled by the caller and they aren't checked
+ * at runtime.
+ */
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ * It assumes that MMU is enabled and the memory is Normal memory.
+ * tbl must be a valid pointer to a memory mem_region_t array,
+ * nregions is the size of the array.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions)
+{
+	size_t i;
+
+	assert(tbl);
+	assert(nregions > 0);
+
+	for (i = 0; i < nregions; i++) {
+		assert(tbl->nbytes > 0);
+		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+		zero_normalmem((void *) (tbl->base), tbl->nbytes);
+		tbl++;
+	}
+}
+
+/*
+ * This function checks that a region (addr + nbytes-1) of memory is totally
+ * covered by one of the regions defined in tbl.
+ * tbl must be a valid pointer to a memory mem_region_t array, nregions
+ * is the size of the array and the region described by addr and nbytes must
+ * not generate an overflow.
+ * Returns:
+ *  -1 means that the region is not covered by any of the regions
+ *     described in tbl.
+ *   0 the region (addr + nbytes-1) is covered by one of the regions described
+ *     in tbl
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+			    uintptr_t addr, size_t nbytes)
+{
+	uintptr_t region_start, region_end, start, end;
+	size_t i;
+
+	assert(tbl);
+	assert(nbytes > 0);
+	assert(!check_uptr_overflow(addr, nbytes-1));
+
+	region_start = addr;
+	region_end = addr + (nbytes - 1);
+	for (i = 0; i < nregions; i++) {
+		assert(tbl->nbytes > 0);
+		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+		start = tbl->base;
+		end = start + (tbl->nbytes - 1);
+		if (region_start >= start && region_end <= end)
+			return 0;
+		tbl++;
+	}
+
+	return -1;
+}
diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk
index 643047c..d63ae9a 100644
--- a/plat/arm/board/common/board_common.mk
+++ b/plat/arm/board/common/board_common.mk
@@ -12,9 +12,13 @@
 
 BL1_SOURCES		+=	plat/arm/board/common/drivers/norflash/norflash.c
 
-BL2_SOURCES		+=	plat/arm/board/common/drivers/norflash/norflash.c
+BL2_SOURCES		+=	lib/utils/mem_region.c					\
+				plat/arm/common/arm_nor_psci_mem_protect.c		\
+				plat/arm/board/common/drivers/norflash/norflash.c
 
-#BL31_SOURCES		+=
+BL31_SOURCES		+=	lib/utils/mem_region.c					\
+				plat/arm/board/common/drivers/norflash/norflash.c	\
+				plat/arm/common/arm_nor_psci_mem_protect.c
 
 ifneq (${TRUSTED_BOARD_BOOT},0)
   ifneq (${ARM_CRYPTOCELL_INTEG}, 1)
diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c
index 159bf86..032ebdf 100644
--- a/plat/arm/board/common/board_css_common.c
+++ b/plat/arm/board/common/board_css_common.c
@@ -29,10 +29,16 @@
 const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_SHARED_RAM,
 	V2M_MAP_FLASH0_RO,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
 	V2M_MAP_IOFPGA,
 	CSS_MAP_DEVICE,
 	SOC_CSS_MAP_DEVICE,
 	ARM_MAP_NS_DRAM1,
+#ifdef AARCH64
+	ARM_MAP_DRAM2,
+#endif
 #ifdef SPD_tspd
 	ARM_MAP_TSP_SEC_MEM,
 #endif
@@ -56,6 +62,9 @@
 	ARM_MAP_SHARED_RAM,
 	V2M_MAP_IOFPGA,
 	CSS_MAP_DEVICE,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
 	SOC_CSS_MAP_DEVICE,
 	{0}
 };
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index e869f5b..7015ac0 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -79,6 +79,9 @@
 	MAP_DEVICE0,
 	MAP_DEVICE1,
 	ARM_MAP_NS_DRAM1,
+#ifdef AARCH64
+	ARM_MAP_DRAM2,
+#endif
 #ifdef SPD_tspd
 	ARM_MAP_TSP_SEC_MEM,
 #endif
@@ -109,6 +112,7 @@
 	V2M_MAP_IOFPGA,
 	MAP_DEVICE0,
 	MAP_DEVICE1,
+	ARM_V2M_MAP_MEM_PROTECT,
 	{0}
 };
 #endif
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 9a02089..dad3a79 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -324,5 +324,14 @@
 	.system_reset = fvp_system_reset,
 	.validate_power_state = arm_validate_power_state,
 	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
-	.get_node_hw_state = fvp_node_hw_state
+	.get_node_hw_state = fvp_node_hw_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 !RESET_TO_BL31 && !RESET_TO_SP_MIN
+	.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/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
index 864df1b..b370fd5 100644
--- a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
+++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
@@ -5,11 +5,14 @@
 #
 
 # SP_MIN source files specific to FVP platform
-BL32_SOURCES		+=	plat/arm/board/fvp/aarch32/fvp_helpers.S	\
+BL32_SOURCES		+=	lib/utils/mem_region.c				\
+				plat/arm/board/fvp/aarch32/fvp_helpers.S	\
 				plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c	\
 				plat/arm/board/fvp/fvp_pm.c			\
 				plat/arm/board/fvp/fvp_topology.c		\
 				plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c	\
+				plat/arm/board/common/drivers/norflash/norflash.c	\
+				plat/arm/common/arm_nor_psci_mem_protect.c	\
 				${FVP_CPU_LIBS}					\
 				${FVP_GIC_SOURCES}				\
 				${FVP_INTERCONNECT_SOURCES}			\
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index 7794af5..3c44a1e 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -68,11 +68,11 @@
 
 #ifdef IMAGE_BL2
 #ifdef SPD_opteed
-# define PLAT_ARM_MMAP_ENTRIES		9
-# define MAX_XLAT_TABLES		4
+# define PLAT_ARM_MMAP_ENTRIES		11
+# define MAX_XLAT_TABLES		5
 #else
-# define PLAT_ARM_MMAP_ENTRIES		8
-# define MAX_XLAT_TABLES		3
+# define PLAT_ARM_MMAP_ENTRIES		10
+# define MAX_XLAT_TABLES		4
 #endif
 #endif
 
@@ -82,8 +82,8 @@
 #endif
 
 #ifdef IMAGE_BL31
-#  define PLAT_ARM_MMAP_ENTRIES		5
-#  define MAX_XLAT_TABLES		2
+#  define PLAT_ARM_MMAP_ENTRIES		7
+#  define MAX_XLAT_TABLES		3
 #endif
 
 #ifdef IMAGE_BL32
diff --git a/plat/arm/board/juno/sp_min/sp_min-juno.mk b/plat/arm/board/juno/sp_min/sp_min-juno.mk
index 336c4e7..cd1f497 100644
--- a/plat/arm/board/juno/sp_min/sp_min-juno.mk
+++ b/plat/arm/board/juno/sp_min/sp_min-juno.mk
@@ -8,7 +8,10 @@
 BL32_SOURCES	+=	lib/cpus/aarch32/cortex_a53.S		\
 			lib/cpus/aarch32/cortex_a57.S		\
 			lib/cpus/aarch32/cortex_a72.S		\
+			lib/utils/mem_region.c			\
+			plat/arm/board/common/drivers/norflash/norflash.c	\
 			plat/arm/board/juno/juno_topology.c	\
+			plat/arm/common/arm_nor_psci_mem_protect.c	\
 			plat/arm/soc/common/soc_css_security.c	\
 			${JUNO_GIC_SOURCES}			\
 			${JUNO_INTERCONNECT_SOURCES}		\
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index cab6113..5d83118 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -193,6 +193,10 @@
 {
 	/* Initialize the secure environment */
 	plat_arm_security_setup();
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	arm_nor_psci_do_mem_protect();
+#endif
 }
 
 void bl2_platform_setup(void)
diff --git a/plat/arm/common/arm_nor_psci_mem_protect.c b/plat/arm/common/arm_nor_psci_mem_protect.c
new file mode 100644
index 0000000..c5263fd
--- /dev/null
+++ b/plat/arm/common/arm_nor_psci_mem_protect.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <mmio.h>
+#include <norflash.h>
+#include <plat_arm.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <utils.h>
+
+mem_region_t arm_ram_ranges[] = {
+	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_SIZE},
+#ifdef AARCH64
+	{ARM_DRAM2_BASE, ARM_DRAM2_SIZE},
+#endif
+};
+
+/*******************************************************************************
+ * Function that reads the content of the memory protect variable that
+ * enables clearing of non secure memory when system boots. This variable
+ * should be stored in a secure NVRAM.
+ ******************************************************************************/
+int arm_psci_read_mem_protect(int *enabled)
+{
+	int tmp;
+
+	tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR;
+	*enabled = (tmp == 1);
+	return 0;
+}
+
+/*******************************************************************************
+ * Function that writes the content of the memory protect variable that
+ * enables overwritten of non secure memory when system boots.
+ ******************************************************************************/
+int arm_nor_psci_write_mem_protect(int val)
+{
+	int enable = (val != 0);
+
+	if (nor_unlock(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+		ERROR("unlocking memory protect variable\n");
+		return -1;
+	}
+
+	if (enable) {
+		/*
+		 * If we want to write a value different than 0
+		 * then we have to erase the full block because
+		 * otherwise we cannot ensure that the value programmed
+		 * into the flash is going to be the same than the value
+		 * requested by the caller
+		 */
+		if (nor_erase(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+			ERROR("erasing block containing memory protect variable\n");
+			return -1;
+		}
+	}
+
+	if (nor_word_program(PLAT_ARM_MEM_PROT_ADDR, enable) != 0) {
+		ERROR("programming memory protection variable\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*******************************************************************************
+ * Function used for required psci operations performed when
+ * system boots
+ ******************************************************************************/
+void arm_nor_psci_do_mem_protect(void)
+{
+	int enable;
+
+	arm_psci_read_mem_protect(&enable);
+	if (!enable)
+		return;
+	INFO("PSCI: Overwritting non secure memory\n");
+	clear_mem_regions(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges));
+	arm_nor_psci_write_mem_protect(0);
+}
+
+/*******************************************************************************
+ * Function that checks if a region is protected by the memory protect
+ * mechanism
+ ******************************************************************************/
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length)
+{
+	return mem_region_in_array_chk(arm_ram_ranges,
+				       ARRAY_SIZE(arm_ram_ranges),
+				       base, length);
+}
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index e0e5200..93d51fe 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -290,5 +290,14 @@
 	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
 	.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
+	.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
+	.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
 };