SPM: FVP: Introduce port of SPM

This initial port of the Secure Partitions Manager to FVP supports BL31
in both SRAM and Trusted DRAM.

A document with instructions to build the SPM has been added.

Change-Id: I4ea83ff0a659be77f2cd72eaf2302cdf8ba98b32
Co-authored-by: Douglas Raillard <douglas.raillard@arm.com>
Co-authored-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
Co-authored-by: Achin Gupta <achin.gupta@arm.com>
Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
diff --git a/docs/spm-user-guide.rst b/docs/spm-user-guide.rst
new file mode 100644
index 0000000..a3b64d9
--- /dev/null
+++ b/docs/spm-user-guide.rst
@@ -0,0 +1,59 @@
+ARM Trusted Firmware - SPM User Guide
+=====================================
+
+.. section-numbering::
+    :suffix: .
+
+.. contents::
+
+
+This document briefly presents the Secure Partition Management (SPM) support in
+the Arm Trusted Firmware (TF), specifically focusing on how to build Arm TF with
+SPM support.
+
+Overview of the SPM software stack
+----------------------------------
+
+SPM is supported on the Arm FVP exclusively at the moment.
+
+It is not currently possible for BL31 to integrate SPM support and a Secure
+Payload Dispatcher (SPD) at the same time; they are mutually exclusive. In the
+SPM bootflow, a Secure Partition (SP) image executing at Secure-EL0 replaces the
+Secure Payload image executing at Secure-EL1 (e.g. a Trusted OS). Both are
+referred to as BL32.
+
+A working prototype of a SP has been implemented by repurposing the EDK2 code
+and tools, leveraging the concept of the *Standalone Management Mode (MM)* in
+the UEFI specification (see the PI v1.6 Volume 4: Management Mode Core
+Interface). This will be referred to as the *Standalone MM Secure Partition* in
+the rest of this document.
+
+
+Building TF with SPM support
+----------------------------
+
+To enable SPM support in the TF, the source code must be compiled with the build
+flag ``ENABLE_SPM=1``. On Arm platforms the build option ``ARM_BL31_IN_DRAM``
+can be used to select the location of BL31, both SRAM and DRAM are supported.
+
+
+Using the Standalone MM SP
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+First, build the Standalone MM Secure Partition. To build it, refer to the
+`instructions in the EDK2 repository`_.
+
+Then build TF with SPM support and include the Standalone MM Secure Partition
+image in the FIP:
+
+::
+
+    BL32=path/to/standalone/mm/sp BL33=path/to/bl33.bin \
+    make PLAT=fvp ENABLE_SPM=1 fip all
+
+
+--------------
+
+*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
+
+.. _instructions in the EDK2 repository: https://github.com/tianocore/edk2-staging/blob/AArch64StandaloneMm/HowtoBuild.MD
diff --git a/include/plat/arm/board/common/board_arm_def.h b/include/plat/arm/board/common/board_arm_def.h
index 7a4594c..97a1af4 100644
--- a/include/plat/arm/board/common/board_arm_def.h
+++ b/include/plat/arm/board/common/board_arm_def.h
@@ -52,7 +52,17 @@
  * They are also used for the dynamically mapped regions in the images that
  * enable dynamic memory mapping.
  */
-#if defined(IMAGE_BL31) || defined(IMAGE_BL32)
+#if defined(IMAGE_BL31)
+# if ENABLE_SPM
+#  define PLAT_ARM_MMAP_ENTRIES		9
+#  define MAX_XLAT_TABLES		7
+#  define PLAT_SP_IMAGE_MMAP_REGIONS	7
+#  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	10
+# else
+#  define PLAT_ARM_MMAP_ENTRIES		7
+#  define MAX_XLAT_TABLES		5
+# endif
+#elif defined(IMAGE_BL32)
 # define PLAT_ARM_MMAP_ENTRIES		7
 # define MAX_XLAT_TABLES		5
 #else
@@ -80,7 +90,11 @@
  * PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a
  * little space for growth.
  */
+#if ENABLE_SPM
+#define PLAT_ARM_MAX_BL31_SIZE		0x28000
+#else
 #define PLAT_ARM_MAX_BL31_SIZE		0x1D000
+#endif
 
 #endif /* ARM_BOARD_OPTIMISE_MEM */
 
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
index 364b780..e5f5373 100644
--- a/include/plat/arm/board/common/v2m_def.h
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -121,6 +121,11 @@
 						V2M_IOFPGA_SIZE,		\
 						MT_DEVICE | MT_RW | MT_SECURE)
 
+/* Region equivalent to V2M_MAP_IOFPGA suitable for mapping at EL0 */
+#define V2M_MAP_IOFPGA_EL0		MAP_REGION_FLAT(		\
+						V2M_IOFPGA_BASE,	\
+						V2M_IOFPGA_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
 
 
 #endif /* __V2M_DEF_H__ */
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 6cab91f..9e82e29 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -378,7 +378,13 @@
  * Trusted DRAM (if available) or the DRAM region secured by the TrustZone
  * controller.
  */
-#if ARM_BL31_IN_DRAM
+#if ENABLE_SPM
+# define TSP_SEC_MEM_BASE		(ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
+# define TSP_SEC_MEM_SIZE		(ARM_AP_TZC_DRAM1_SIZE - ULL(0x200000))
+# define BL32_BASE			(ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
+# define BL32_LIMIT			(ARM_AP_TZC_DRAM1_BASE +	\
+						ARM_AP_TZC_DRAM1_SIZE)
+#elif ARM_BL31_IN_DRAM
 # define TSP_SEC_MEM_BASE		(ARM_AP_TZC_DRAM1_BASE +	\
 						PLAT_ARM_MAX_BL31_SIZE)
 # define TSP_SEC_MEM_SIZE		(ARM_AP_TZC_DRAM1_SIZE -	\
@@ -409,11 +415,14 @@
 # error "Unsupported ARM_TSP_RAM_LOCATION_ID value"
 #endif
 
-/* BL32 is mandatory in AArch32 */
+/*
+ * BL32 is mandatory in AArch32. In AArch64, undefine BL32_BASE if there is no
+ * SPD and no SPM, as they are the only ones that can be used as BL32.
+ */
 #ifndef AARCH32
-#ifdef SPD_none
-#undef BL32_BASE
-#endif /* SPD_none */
+# if defined(SPD_none) && !ENABLE_SPM
+#  undef BL32_BASE
+# endif
 #endif
 
 /*******************************************************************************
diff --git a/include/plat/arm/common/arm_spm_def.h b/include/plat/arm/common/arm_spm_def.h
new file mode 100644
index 0000000..83277a6
--- /dev/null
+++ b/include/plat/arm/common/arm_spm_def.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __ARM_SPM_DEF_H__
+#define __ARM_SPM_DEF_H__
+
+#include <arm_def.h>
+#include <platform_def.h>
+#include <utils_def.h>
+#include <xlat_tables_defs.h>
+
+/*
+ * If BL31 is placed in DRAM, place the Secure Partition in DRAM right after the
+ * region used by BL31. If BL31 it is placed in SRAM, put the Secure Partition
+ * at the base of DRAM.
+ */
+#define ARM_SP_IMAGE_BASE		BL32_BASE
+#define ARM_SP_IMAGE_LIMIT		BL32_LIMIT
+/* The maximum size of the S-EL0 payload can be 3MB */
+#define ARM_SP_IMAGE_SIZE		ULL(0x300000)
+
+#ifdef IMAGE_BL2
+/* SPM Payload memory. Mapped as RW in BL2. */
+#define ARM_SP_IMAGE_MMAP		MAP_REGION_FLAT(			\
+						ARM_SP_IMAGE_BASE,		\
+						ARM_SP_IMAGE_SIZE,		\
+						MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+#ifdef IMAGE_BL31
+/* SPM Payload memory. Mapped as code in S-EL1 */
+#define ARM_SP_IMAGE_MMAP		MAP_REGION2(				\
+						ARM_SP_IMAGE_BASE,		\
+						ARM_SP_IMAGE_BASE,		\
+						ARM_SP_IMAGE_SIZE,		\
+						MT_CODE | MT_SECURE | MT_USER,	\
+						PAGE_SIZE)
+#endif
+
+/*
+ * Memory shared between EL3 and S-EL0. It is used by EL3 to push data into
+ * S-EL0, so it is mapped with RW permission from EL3 and with RO permission
+ * from S-EL0. Placed after SPM Payload memory.
+ */
+#define PLAT_SPM_BUF_BASE		(ARM_SP_IMAGE_BASE + ARM_SP_IMAGE_SIZE)
+#define PLAT_SPM_BUF_SIZE		ULL(0x100000)
+
+#define ARM_SPM_BUF_EL3_MMAP		MAP_REGION_FLAT(			\
+						PLAT_SPM_BUF_BASE,		\
+						PLAT_SPM_BUF_SIZE,		\
+						MT_RW_DATA | MT_SECURE)
+#define ARM_SPM_BUF_EL0_MMAP		MAP_REGION2(			\
+						PLAT_SPM_BUF_BASE,		\
+						PLAT_SPM_BUF_BASE,		\
+						PLAT_SPM_BUF_SIZE,		\
+						MT_RO_DATA | MT_SECURE | MT_USER,\
+						PAGE_SIZE)
+
+/*
+ * Memory shared between Normal world and S-EL0 for passing data during service
+ * requests. Mapped as RW and NS. Placed after the shared memory between EL3 and
+ * S-EL0.
+ */
+#define ARM_SP_IMAGE_NS_BUF_BASE	(PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE)
+#define ARM_SP_IMAGE_NS_BUF_SIZE	ULL(0x10000)
+#define ARM_SP_IMAGE_NS_BUF_MMAP	MAP_REGION2(				\
+						ARM_SP_IMAGE_NS_BUF_BASE,	\
+						ARM_SP_IMAGE_NS_BUF_BASE,	\
+						ARM_SP_IMAGE_NS_BUF_SIZE,	\
+						MT_RW_DATA | MT_NS | MT_USER,	\
+						PAGE_SIZE)
+
+/*
+ * RW memory, which uses the remaining Trusted DRAM. Placed after the memory
+ * shared between Secure and Non-secure worlds. First there is the stack memory
+ * for all CPUs and then there is the common heap memory. Both are mapped with
+ * RW permissions.
+ */
+#define PLAT_SP_IMAGE_STACK_BASE	(ARM_SP_IMAGE_NS_BUF_BASE +		\
+						ARM_SP_IMAGE_NS_BUF_SIZE)
+#define PLAT_SP_IMAGE_STACK_PCPU_SIZE	ULL(0x2000)
+#define ARM_SP_IMAGE_STACK_TOTAL_SIZE	(PLATFORM_CORE_COUNT *			\
+					 PLAT_SP_IMAGE_STACK_PCPU_SIZE)
+
+#define ARM_SP_IMAGE_HEAP_BASE		(PLAT_SP_IMAGE_STACK_BASE +		\
+					 ARM_SP_IMAGE_STACK_TOTAL_SIZE)
+#define ARM_SP_IMAGE_HEAP_SIZE		(ARM_SP_IMAGE_LIMIT - ARM_SP_IMAGE_HEAP_BASE)
+
+#define ARM_SP_IMAGE_RW_MMAP		MAP_REGION2(				\
+						PLAT_SP_IMAGE_STACK_BASE,	\
+						PLAT_SP_IMAGE_STACK_BASE,	\
+						(ARM_SP_IMAGE_LIMIT -		\
+						 PLAT_SP_IMAGE_STACK_BASE),	\
+						MT_RW_DATA | MT_SECURE | MT_USER,\
+						PAGE_SIZE)
+
+/* Total number of memory regions with distinct properties */
+#define ARM_SP_IMAGE_NUM_MEM_REGIONS	6
+
+/* Cookies passed to the Secure Partition at boot. Not used by ARM platforms. */
+#define PLAT_SPM_COOKIE_0		ULL(0)
+#define PLAT_SPM_COOKIE_1		ULL(0)
+
+#endif /* __ARM_SPM_DEF_H__ */
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 57cc3d5..6729863 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -6,6 +6,7 @@
 
 #include <arm_config.h>
 #include <arm_def.h>
+#include <arm_spm_def.h>
 #include <assert.h>
 #include <cci.h>
 #include <ccn.h>
@@ -13,6 +14,7 @@
 #include <gicv2.h>
 #include <mmio.h>
 #include <plat_arm.h>
+#include <secure_partition.h>
 #include <v2m_def.h>
 #include "../fvp_def.h"
 
@@ -89,6 +91,9 @@
 	/* To access the Root of Trust Public Key registers. */
 	MAP_DEVICE2,
 #endif
+#if ENABLE_SPM
+	ARM_SP_IMAGE_MMAP,
+#endif
 #if ARM_BL31_IN_DRAM
 	ARM_MAP_BL31_SEC_DRAM,
 #endif
@@ -114,8 +119,22 @@
 	MAP_DEVICE0,
 	MAP_DEVICE1,
 	ARM_V2M_MAP_MEM_PROTECT,
+#if ENABLE_SPM
+	ARM_SPM_BUF_EL3_MMAP,
+#endif
 	{0}
 };
+
+#if ENABLE_SPM && defined(IMAGE_BL31)
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+	V2M_MAP_IOFPGA_EL0, /* for the UART */
+	ARM_SP_IMAGE_MMAP,
+	ARM_SP_IMAGE_NS_BUF_MMAP,
+	ARM_SP_IMAGE_RW_MMAP,
+	ARM_SPM_BUF_EL0_MMAP,
+	{0}
+};
+#endif
 #endif
 #ifdef IMAGE_BL32
 const mmap_region_t plat_arm_mmap[] = {
@@ -156,6 +175,57 @@
 }
 #endif
 
+#if ENABLE_SPM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static secure_partition_mp_info_t sp_mp_info[] = {
+	[0] = {0x80000000, 0},
+	[1] = {0x80000001, 0},
+	[2] = {0x80000002, 0},
+	[3] = {0x80000003, 0},
+	[4] = {0x80000100, 0},
+	[5] = {0x80000101, 0},
+	[6] = {0x80000102, 0},
+	[7] = {0x80000103, 0},
+};
+
+const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = {
+	.h.type              = PARAM_SP_IMAGE_BOOT_INFO,
+	.h.version           = VERSION_1,
+	.h.size              = sizeof(secure_partition_boot_info_t),
+	.h.attr              = 0,
+	.sp_mem_base         = ARM_SP_IMAGE_BASE,
+	.sp_mem_limit        = ARM_SP_IMAGE_LIMIT,
+	.sp_image_base       = ARM_SP_IMAGE_BASE,
+	.sp_stack_base       = PLAT_SP_IMAGE_STACK_BASE,
+	.sp_heap_base        = ARM_SP_IMAGE_HEAP_BASE,
+	.sp_ns_comm_buf_base = ARM_SP_IMAGE_NS_BUF_BASE,
+	.sp_shared_buf_base  = PLAT_SPM_BUF_BASE,
+	.sp_image_size       = ARM_SP_IMAGE_SIZE,
+	.sp_pcpu_stack_size  = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+	.sp_heap_size        = ARM_SP_IMAGE_HEAP_SIZE,
+	.sp_ns_comm_buf_size = ARM_SP_IMAGE_NS_BUF_SIZE,
+	.sp_shared_buf_size  = PLAT_SPM_BUF_SIZE,
+	.num_sp_mem_regions  = ARM_SP_IMAGE_NUM_MEM_REGIONS,
+	.num_cpus            = PLATFORM_CORE_COUNT,
+	.mp_info             = &sp_mp_info[0],
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+	return plat_arm_secure_partition_mmap;
+}
+
+const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
+		void *cookie)
+{
+	return &plat_arm_secure_partition_boot_info;
+}
+
+#endif
+
 /*******************************************************************************
  * A single boot loader stack is expected to work on both the Foundation FVP
  * models and the two flavours of the Base FVP models (AEMv8 & Cortex). The
diff --git a/plat/arm/common/arm_common.c b/plat/arm/common/arm_common.c
index 420a386..1905c0b 100644
--- a/plat/arm/common/arm_common.c
+++ b/plat/arm/common/arm_common.c
@@ -11,6 +11,7 @@
 #include <mmio.h>
 #include <plat_arm.h>
 #include <platform_def.h>
+#include <secure_partition.h>
 
 extern const mmap_region_t plat_arm_mmap[];
 
@@ -79,6 +80,14 @@
 			MT_DEVICE | MT_RW | MT_SECURE);
 #endif
 
+#if ENABLE_SPM && defined(IMAGE_BL31)
+	/* The address of the following region is calculated by the linker. */
+	mmap_add_region(SP_IMAGE_XLAT_TABLES_START,
+			SP_IMAGE_XLAT_TABLES_START,
+			SP_IMAGE_XLAT_TABLES_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE);
+#endif
+
 	/* Now (re-)map the platform-specific memory regions */
 	mmap_add(plat_arm_get_mmap());
 
diff --git a/plat/arm/common/arm_tzc400.c b/plat/arm/common/arm_tzc400.c
index e19ca67..23c0317 100644
--- a/plat/arm/common/arm_tzc400.c
+++ b/plat/arm/common/arm_tzc400.c
@@ -1,10 +1,11 @@
 /*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <arm_def.h>
+#include <arm_spm_def.h>
 #include <debug.h>
 #include <platform_def.h>
 #include <tzc400.h>
@@ -56,9 +57,26 @@
 			ARM_DRAM2_BASE, ARM_DRAM2_END,
 			ARM_TZC_NS_DRAM_S_ACCESS,
 			PLAT_ARM_TZC_NS_DEV_ACCESS);
-#else
+
+#if ENABLE_SPM
+	/*
+	 * Region 4 set to cover Non-Secure access to the communication buffer
+	 * shared with the Secure world.
+	 */
+	tzc400_configure_region(PLAT_ARM_TZC_FILTERS,
+				4,
+				ARM_SP_IMAGE_NS_BUF_BASE,
+				(ARM_SP_IMAGE_NS_BUF_BASE +
+				 ARM_SP_IMAGE_NS_BUF_SIZE) - 1,
+				TZC_REGION_S_NONE,
+				PLAT_ARM_TZC_NS_DEV_ACCESS);
+#endif
+
+#else /* if defined(EL3_PAYLOAD_BASE) */
+
 	/* Allow secure access only to DRAM for EL3 payloads. */
 	tzc400_configure_region0(TZC_REGION_S_RDWR, 0);
+
 #endif /* EL3_PAYLOAD_BASE */
 
 	/*