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 */
/*