Merge pull request #1148 from antonio-nino-diaz-arm/an/spm

Introduce Secure Partition Manager
This commit is contained in:
davidcunado-arm 2017-11-09 22:38:37 +00:00 committed by GitHub
commit 9500d5a438
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1658 additions and 28 deletions

View File

@ -500,6 +500,7 @@ $(eval $(call add_define,PROGRAMMABLE_RESET_ADDRESS))
$(eval $(call add_define,PSCI_EXTENDED_STATE_ID))
$(eval $(call add_define,RESET_TO_BL31))
$(eval $(call add_define,SEPARATE_CODE_AND_RODATA))
$(eval $(call add_define,ENABLE_SPM))
$(eval $(call add_define,SPD_${SPD}))
$(eval $(call add_define,SPIN_ON_BL1_EXIT))
$(eval $(call add_define,TRUSTED_BOARD_BOOT))

View File

@ -118,6 +118,23 @@ SECTIONS
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
#if ENABLE_SPM
/*
* Exception vectors of the SPM shim layer. They must be aligned to a 2K
* address, but we need to place them in a separate page so that we can set
* individual permissions to them, so the actual alignment needed is 4K.
*
* There's no need to include this into the RO section of BL31 because it
* doesn't need to be accessed by BL31.
*/
spm_shim_exceptions : ALIGN(4096) {
__SPM_SHIM_EXCEPTIONS_START__ = .;
*(.spm_shim_exceptions)
. = NEXT(4096);
__SPM_SHIM_EXCEPTIONS_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
@ -202,6 +219,13 @@ SECTIONS
* the .bss section and eliminates the unecessary zero init
*/
xlat_table (NOLOAD) : {
#if ENABLE_SPM
__SP_IMAGE_XLAT_TABLES_START__ = .;
*secure_partition*.o(xlat_table)
/* Make sure that the rest of the page is empty. */
. = NEXT(4096);
__SP_IMAGE_XLAT_TABLES_END__ = .;
#endif
*(xlat_table)
} >RAM

View File

@ -4,6 +4,15 @@
# SPDX-License-Identifier: BSD-3-Clause
#
################################################################################
# Include SPM Makefile
################################################################################
ifeq (${ENABLE_SPM},1)
$(info Including SPM makefile)
include services/std_svc/spm/spm.mk
endif
include lib/psci/psci_lib.mk
BL31_SOURCES += bl31/bl31_main.c \
@ -15,7 +24,9 @@ BL31_SOURCES += bl31/bl31_main.c \
common/runtime_svc.c \
plat/common/aarch64/platform_mp_stack.S \
services/std_svc/std_svc_setup.c \
${PSCI_LIB_SOURCES}
${PSCI_LIB_SOURCES} \
${SPM_SOURCES} \
ifeq (${ENABLE_PMF}, 1)
BL31_SOURCES += lib/pmf/pmf_main.c

59
docs/spm-user-guide.rst Normal file
View File

@ -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

View File

@ -51,8 +51,8 @@
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_base label
.section .vectors, "ax"
.macro vector_base label, section_name=.vectors
.section \section_name, "ax"
.align 11, 0
\label:
.endm
@ -64,9 +64,9 @@
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_entry label
.macro vector_entry label, section_name=.vectors
.cfi_sections .debug_frame
.section .vectors, "ax"
.section \section_name, "ax"
.align 7, 0
.type \label, %function
.func \label

View File

@ -8,12 +8,13 @@
#define __PARAM_HEADER_H__
/* Param header types */
#define PARAM_EP 0x01
#define PARAM_IMAGE_BINARY 0x02
#define PARAM_BL31 0x03
#define PARAM_BL_LOAD_INFO 0x04
#define PARAM_BL_PARAMS 0x05
#define PARAM_PSCI_LIB_ARGS 0x06
#define PARAM_EP 0x01
#define PARAM_IMAGE_BINARY 0x02
#define PARAM_BL31 0x03
#define PARAM_BL_LOAD_INFO 0x04
#define PARAM_BL_PARAMS 0x05
#define PARAM_PSCI_LIB_ARGS 0x06
#define PARAM_SP_IMAGE_BOOT_INFO 0x07
/* Param header version */
#define VERSION_1 0x01

View File

@ -126,6 +126,7 @@
#define ID_AA64PFR0_GIC_MASK ((U(1) << ID_AA64PFR0_GIC_WIDTH) - 1)
/* ID_AA64MMFR0_EL1 definitions */
#define ID_AA64MMFR0_EL1_PARANGE_SHIFT U(0)
#define ID_AA64MMFR0_EL1_PARANGE_MASK U(0xf)
#define PARANGE_0000 U(32)
@ -135,6 +136,21 @@
#define PARANGE_0100 U(44)
#define PARANGE_0101 U(48)
#define ID_AA64MMFR0_EL1_TGRAN4_SHIFT U(28)
#define ID_AA64MMFR0_EL1_TGRAN4_MASK U(0xf)
#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED U(0x0)
#define ID_AA64MMFR0_EL1_TGRAN4_NOT_SUPPORTED U(0xf)
#define ID_AA64MMFR0_EL1_TGRAN64_SHIFT U(24)
#define ID_AA64MMFR0_EL1_TGRAN64_MASK U(0xf)
#define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED U(0x0)
#define ID_AA64MMFR0_EL1_TGRAN64_NOT_SUPPORTED U(0xf)
#define ID_AA64MMFR0_EL1_TGRAN16_SHIFT U(20)
#define ID_AA64MMFR0_EL1_TGRAN16_MASK U(0xf)
#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED U(0x1)
#define ID_AA64MMFR0_EL1_TGRAN16_NOT_SUPPORTED U(0x0)
/* ID_PFR1_EL1 definitions */
#define ID_PFR1_VIRTEXT_SHIFT U(12)
#define ID_PFR1_VIRTEXT_MASK U(0xf)
@ -160,12 +176,25 @@
#define SCTLR_A_BIT (U(1) << 1)
#define SCTLR_C_BIT (U(1) << 2)
#define SCTLR_SA_BIT (U(1) << 3)
#define SCTLR_SA0_BIT (U(1) << 4)
#define SCTLR_CP15BEN_BIT (U(1) << 5)
#define SCTLR_ITD_BIT (U(1) << 7)
#define SCTLR_SED_BIT (U(1) << 8)
#define SCTLR_UMA_BIT (U(1) << 9)
#define SCTLR_I_BIT (U(1) << 12)
#define SCTLR_V_BIT (U(1) << 13)
#define SCTLR_DZE_BIT (U(1) << 14)
#define SCTLR_UCT_BIT (U(1) << 15)
#define SCTLR_NTWI_BIT (U(1) << 16)
#define SCTLR_NTWE_BIT (U(1) << 18)
#define SCTLR_WXN_BIT (U(1) << 19)
#define SCTLR_UWXN_BIT (U(1) << 20)
#define SCTLR_E0E_BIT (U(1) << 24)
#define SCTLR_EE_BIT (U(1) << 25)
#define SCTLR_UCI_BIT (U(1) << 26)
#define SCTLR_TRE_BIT (U(1) << 28)
#define SCTLR_AFE_BIT (U(1) << 29)
#define SCTLR_TE_BIT (U(1) << 30)
#define SCTLR_RESET_VAL SCTLR_EL3_RES1
/* CPACR_El1 definitions */
@ -350,6 +379,13 @@
#define TCR_SH_OUTER_SHAREABLE (U(0x2) << 12)
#define TCR_SH_INNER_SHAREABLE (U(0x3) << 12)
#define TCR_TG0_SHIFT U(14)
#define TCR_TG0_MASK U(3)
#define TCR_TG0_4K (ULL(0) << TCR_TG0_SHIFT)
#define TCR_TG0_64K (ULL(1) << TCR_TG0_SHIFT)
#define TCR_TG0_16K (ULL(2) << TCR_TG0_SHIFT)
#define TCR_EPD0_BIT (U(1) << 7)
#define TCR_EPD1_BIT (U(1) << 23)
#define MODE_SP_SHIFT U(0x0)

View File

@ -15,6 +15,11 @@
#error "PAGE_SIZE is not defined."
#endif
/*
* Encode a Physical Address Space size for its use in TCR_ELx.
*/
unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr);
/*
* In AArch64 state, the MMU may support 4 KB, 16 KB and 64 KB page
* granularity. For 4KB granularity, a level 0 table descriptor doesn't support

View File

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

View File

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

View File

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

View File

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

View File

@ -23,6 +23,8 @@ struct bl31_params;
struct image_desc;
struct bl_load_info;
struct bl_params;
struct mmap_region;
struct secure_partition_boot_info;
/*******************************************************************************
* plat_get_rotpk_info() flags
@ -293,6 +295,13 @@ int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr);
int plat_set_nv_ctr2(void *cookie, const struct auth_img_desc_s *img_desc,
unsigned int nv_ctr);
/*******************************************************************************
* Secure Partitions functions
******************************************************************************/
const struct mmap_region *plat_get_secure_partition_mmap(void *cookie);
const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
void *cookie);
#if LOAD_IMAGE_V2
/*******************************************************************************
* Mandatory BL image load functions(may be overridden).

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SECURE_PARTITION_H__
#define __SECURE_PARTITION_H__
#include <bl_common.h>
#include <types.h>
#include <utils_def.h>
/* Linker symbols */
extern uintptr_t __SP_IMAGE_XLAT_TABLES_START__;
extern uintptr_t __SP_IMAGE_XLAT_TABLES_END__;
/* Definitions */
#define SP_IMAGE_XLAT_TABLES_START \
(uintptr_t)(&__SP_IMAGE_XLAT_TABLES_START__)
#define SP_IMAGE_XLAT_TABLES_END \
(uintptr_t)(&__SP_IMAGE_XLAT_TABLES_END__)
#define SP_IMAGE_XLAT_TABLES_SIZE \
(SP_IMAGE_XLAT_TABLES_END - SP_IMAGE_XLAT_TABLES_START)
/*
* Flags used by the secure_partition_mp_info structure to describe the
* characteristics of a cpu. Only a single flag is defined at the moment to
* indicate the primary cpu.
*/
#define MP_INFO_FLAG_PRIMARY_CPU U(0x00000001)
/*
* This structure is used to provide information required to initialise a S-EL0
* partition.
*/
typedef struct secure_partition_mp_info {
u_register_t mpidr;
unsigned int linear_id;
unsigned int flags;
} secure_partition_mp_info_t;
typedef struct secure_partition_boot_info {
param_header_t h;
uintptr_t sp_mem_base;
uintptr_t sp_mem_limit;
uintptr_t sp_image_base;
uintptr_t sp_stack_base;
uintptr_t sp_heap_base;
uintptr_t sp_ns_comm_buf_base;
uintptr_t sp_shared_buf_base;
size_t sp_image_size;
size_t sp_pcpu_stack_size;
size_t sp_heap_size;
size_t sp_ns_comm_buf_size;
size_t sp_shared_buf_size;
unsigned int num_sp_mem_regions;
unsigned int num_cpus;
secure_partition_mp_info_t *mp_info;
} secure_partition_boot_info_t;
/* Setup function for secure partitions context. */
void secure_partition_setup(void);
#endif /* __SECURE_PARTITION_H__ */

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SPM_SVC_H__
#define __SPM_SVC_H__
#include <utils_def.h>
#define SPM_VERSION_MAJOR U(0)
#define SPM_VERSION_MINOR U(1)
#define SPM_VERSION_FORM(major, minor) ((major << 16) | (minor))
#define SPM_VERSION_COMPILED SPM_VERSION_FORM(SPM_VERSION_MAJOR, SPM_VERSION_MINOR)
#define SP_VERSION_MAJOR U(1)
#define SP_VERSION_MINOR U(0)
#define SP_VERSION_FORM(major, minor) ((major << 16) | (minor))
#define SP_VERSION_COMPILED SP_VERSION_FORM(SP_VERSION_MAJOR, SP_VERSION_MINOR)
/* The macros below are used to identify SPM calls from the SMC function ID */
#define SPM_FID_MASK U(0xffff)
#define SPM_FID_MIN_VALUE U(0x40)
#define SPM_FID_MAX_VALUE U(0x7f)
#define is_spm_fid(_fid) \
((((_fid) & SPM_FID_MASK) >= SPM_FID_MIN_VALUE) && \
(((_fid) & SPM_FID_MASK) <= SPM_FID_MAX_VALUE))
/*
* SMC IDs defined for accessing services implemented by the Secure Partition
* Manager from the Secure Partition(s). These services enable a partition to
* handle delegated events and request privileged operations from the manager.
*/
#define SPM_VERSION_AARCH32 U(0x84000060)
#define SP_EVENT_COMPLETE_AARCH64 U(0xC4000061)
#define SP_MEM_ATTRIBUTES_GET_AARCH64 U(0xC4000064)
#define SP_MEM_ATTRIBUTES_SET_AARCH64 U(0xC4000065)
/*
* Macros used by SP_MEM_ATTRIBUTES_SET_AARCH64.
*/
#define SP_MEM_ATTR_ACCESS_NOACCESS U(0)
#define SP_MEM_ATTR_ACCESS_RW U(1)
/* Value U(2) is reserved. */
#define SP_MEM_ATTR_ACCESS_RO U(3)
#define SP_MEM_ATTR_ACCESS_MASK U(3)
#define SP_MEM_ATTR_ACCESS_SHIFT 0
#define SP_MEM_ATTR_EXEC (U(0) << 2)
#define SP_MEM_ATTR_NON_EXEC (U(1) << 2)
/*
* SMC IDs defined in [1] for accessing secure partition services from the
* Non-secure world. These FIDs occupy the range 0x40 - 0x5f
* [1] DEN0060A_ARM_MM_Interface_Specification.pdf
*/
#define SP_VERSION_AARCH64 U(0xC4000040)
#define SP_VERSION_AARCH32 U(0x84000040)
#define SP_COMMUNICATE_AARCH64 U(0xC4000041)
#define SP_COMMUNICATE_AARCH32 U(0x84000041)
/* SPM error codes. */
#define SPM_SUCCESS 0
#define SPM_NOT_SUPPORTED -1
#define SPM_INVALID_PARAMETER -2
#define SPM_DENIED -3
#define SPM_NO_MEMORY -5
#ifndef __ASSEMBLY__
#include <stdint.h>
int32_t spm_setup(void);
uint64_t spm_smc_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
uint64_t x3,
uint64_t x4,
void *cookie,
void *handle,
uint64_t flags);
#endif /* __ASSEMBLY__ */
#endif /* __SPM_SVC_H__ */

View File

@ -16,8 +16,7 @@
#include <xlat_tables_v2.h>
#include "../xlat_tables_private.h"
static unsigned long long calc_physical_addr_size_bits(
unsigned long long max_addr)
unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr)
{
/* Physical address can't exceed 48 bits */
assert((max_addr & ADDR_MASK_48_TO_63) == 0);
@ -252,7 +251,7 @@ void enable_mmu_arch(unsigned int flags,
* It is safer to restrict the max physical address accessible by the
* hardware as much as possible.
*/
unsigned long long tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
unsigned long long tcr_ps_bits = tcr_physical_addr_size_bits(max_pa);
#if IMAGE_EL == 1
assert(IS_IN_EL(1));

View File

@ -118,6 +118,9 @@ SEPARATE_CODE_AND_RODATA := 0
# SPD choice
SPD := none
# For including the Secure Partition Manager
ENABLE_SPM := 0
# Flag to introduce an infinite loop in BL1 just before it exits into the next
# image. This is meant to help debugging the post-BL2 phase.
SPIN_ON_BL1_EXIT := 0

View File

@ -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 @@ const mmap_region_t plat_arm_mmap[] = {
/* 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 @@ const mmap_region_t plat_arm_mmap[] = {
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 @@ static unsigned int get_interconnect_master(void)
}
#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

View File

@ -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 @@ void arm_setup_page_tables(uintptr_t total_base,
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());

View File

@ -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 @@ void arm_tzc400_setup(void)
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 */
/*

View File

@ -78,7 +78,7 @@ uint64_t opteed_synchronous_sp_entry(optee_context_t *optee_ctx)
cm_set_next_eret_context(SECURE);
rc = opteed_enter_sp(&optee_ctx->c_rt_ctx);
#if DEBUG
#if ENABLE_ASSERTIONS
optee_ctx->c_rt_ctx = 0;
#endif

View File

@ -131,7 +131,7 @@ uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx)
cm_set_next_eret_context(SECURE);
rc = tlkd_enter_sp(&tlk_ctx->c_rt_ctx);
#if DEBUG
#if ENABLE_ASSERTIONS
tlk_ctx->c_rt_ctx = 0;
#endif

View File

@ -79,7 +79,7 @@ uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx)
cm_set_next_eret_context(SECURE);
rc = tspd_enter_sp(&tsp_ctx->c_rt_ctx);
#if DEBUG
#if ENABLE_ASSERTIONS
tsp_ctx->c_rt_ctx = 0;
#endif

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include "../spm_private.h"
.global spm_secure_partition_enter
.global spm_secure_partition_exit
/* ---------------------------------------------------------------------
* This function is called with SP_EL0 as stack. Here we stash our EL3
* callee-saved registers on to the stack as a part of saving the C
* runtime and enter the secure payload.
* 'x0' contains a pointer to the memory where the address of the C
* runtime context is to be saved.
* ---------------------------------------------------------------------
*/
func spm_secure_partition_enter
/* Make space for the registers that we're going to save */
mov x3, sp
str x3, [x0, #0]
sub sp, sp, #SP_C_RT_CTX_SIZE
/* Save callee-saved registers on to the stack */
stp x19, x20, [sp, #SP_C_RT_CTX_X19]
stp x21, x22, [sp, #SP_C_RT_CTX_X21]
stp x23, x24, [sp, #SP_C_RT_CTX_X23]
stp x25, x26, [sp, #SP_C_RT_CTX_X25]
stp x27, x28, [sp, #SP_C_RT_CTX_X27]
stp x29, x30, [sp, #SP_C_RT_CTX_X29]
/* ---------------------------------------------------------------------
* Everything is setup now. el3_exit() will use the secure context to
* restore to the general purpose and EL3 system registers to ERET
* into the secure payload.
* ---------------------------------------------------------------------
*/
b el3_exit
endfunc spm_secure_partition_enter
/* ---------------------------------------------------------------------
* This function is called with 'x0' pointing to a C runtime context
* saved in spm_secure_partition_enter().
* It restores the saved registers and jumps to that runtime with 'x0'
* as the new SP register. This destroys the C runtime context that had
* been built on the stack below the saved context by the caller. Later
* the second parameter 'x1' is passed as a return value to the caller.
* ---------------------------------------------------------------------
*/
func spm_secure_partition_exit
/* Restore the previous stack */
mov sp, x0
/* Restore callee-saved registers on to the stack */
ldp x19, x20, [x0, #(SP_C_RT_CTX_X19 - SP_C_RT_CTX_SIZE)]
ldp x21, x22, [x0, #(SP_C_RT_CTX_X21 - SP_C_RT_CTX_SIZE)]
ldp x23, x24, [x0, #(SP_C_RT_CTX_X23 - SP_C_RT_CTX_SIZE)]
ldp x25, x26, [x0, #(SP_C_RT_CTX_X25 - SP_C_RT_CTX_SIZE)]
ldp x27, x28, [x0, #(SP_C_RT_CTX_X27 - SP_C_RT_CTX_SIZE)]
ldp x29, x30, [x0, #(SP_C_RT_CTX_X29 - SP_C_RT_CTX_SIZE)]
/* ---------------------------------------------------------------------
* This should take us back to the instruction after the call to the
* last spm_secure_partition_enter().* Place the second parameter to x0
* so that the caller will see it as a return value from the original
* entry call.
* ---------------------------------------------------------------------
*/
mov x0, x1
ret
endfunc spm_secure_partition_exit

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <bl_common.h>
#include <context.h>
/* -----------------------------------------------------------------------------
* Very simple stackless exception handlers used by the spm shim layer.
* -----------------------------------------------------------------------------
*/
.globl spm_shim_exceptions_ptr
vector_base spm_shim_exceptions_ptr, .spm_shim_exceptions
/* -----------------------------------------------------
* Current EL with SP0 : 0x0 - 0x200
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionSP0, .spm_shim_exceptions
b .
check_vector_size SynchronousExceptionSP0
vector_entry IrqSP0, .spm_shim_exceptions
b .
check_vector_size IrqSP0
vector_entry FiqSP0, .spm_shim_exceptions
b .
check_vector_size FiqSP0
vector_entry SErrorSP0, .spm_shim_exceptions
b .
check_vector_size SErrorSP0
/* -----------------------------------------------------
* Current EL with SPx: 0x200 - 0x400
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionSPx, .spm_shim_exceptions
b .
check_vector_size SynchronousExceptionSPx
vector_entry IrqSPx, .spm_shim_exceptions
b .
check_vector_size IrqSPx
vector_entry FiqSPx, .spm_shim_exceptions
b .
check_vector_size FiqSPx
vector_entry SErrorSPx, .spm_shim_exceptions
b .
check_vector_size SErrorSPx
/* -----------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x600. No exceptions
* are handled since secure_partition does not implement
* a lower EL
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionA64, .spm_shim_exceptions
msr tpidr_el1, x30
mrs x30, esr_el1
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
cmp x30, #EC_AARCH64_SVC
b.eq do_smc
cmp x30, #EC_AARCH32_SVC
b.eq do_smc
cmp x30, #EC_AARCH64_SYS
b.eq handle_sys_trap
/* Fail in all the other cases */
b panic
/* ---------------------------------------------
* Tell SPM that we are done initialising
* ---------------------------------------------
*/
do_smc:
mrs x30, tpidr_el1
smc #0
eret
/* AArch64 system instructions trap are handled as a panic for now */
handle_sys_trap:
panic:
b panic
check_vector_size SynchronousExceptionA64
vector_entry IrqA64, .spm_shim_exceptions
b .
check_vector_size IrqA64
vector_entry FiqA64, .spm_shim_exceptions
b .
check_vector_size FiqA64
vector_entry SErrorA64, .spm_shim_exceptions
b .
check_vector_size SErrorA64
/* -----------------------------------------------------
* Lower EL using AArch32 : 0x600 - 0x800
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionA32, .spm_shim_exceptions
b .
check_vector_size SynchronousExceptionA32
vector_entry IrqA32, .spm_shim_exceptions
b .
check_vector_size IrqA32
vector_entry FiqA32, .spm_shim_exceptions
b .
check_vector_size FiqA32
vector_entry SErrorA32, .spm_shim_exceptions
b .
check_vector_size SErrorA32

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <arm_spm_def.h>
#include <assert.h>
#include <common_def.h>
#include <context.h>
#include <context_mgmt.h>
#include <debug.h>
#include <platform_def.h>
#include <platform.h>
#include <secure_partition.h>
#include <string.h>
#include <types.h>
#include <xlat_tables_v2.h>
#include "spm_private.h"
#include "spm_shim_private.h"
/* Allocate and initialise the translation context for the secure partition. */
REGISTER_XLAT_CONTEXT2(secure_partition,
PLAT_SP_IMAGE_MMAP_REGIONS,
PLAT_SP_IMAGE_MAX_XLAT_TABLES,
PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE,
EL1_EL0_REGIME);
/* Export a handle on the secure partition translation context */
xlat_ctx_t *secure_partition_xlat_ctx_handle = &secure_partition_xlat_ctx;
/* Setup context of the Secure Partition */
void secure_partition_setup(void)
{
VERBOSE("S-EL1/S-EL0 context setup start...\n");
cpu_context_t *ctx = cm_get_context(SECURE);
/* Make sure that we got a Secure context. */
assert(ctx != NULL);
/* Assert we are in Secure state. */
assert((read_scr_el3() & SCR_NS_BIT) == 0);
/* Disable MMU at EL1. */
disable_mmu_icache_el1();
/* Invalidate TLBs at EL1. */
tlbivmalle1();
/*
* General-Purpose registers
* -------------------------
*/
/*
* X0: Virtual address of a buffer shared between EL3 and Secure EL0.
* The buffer will be mapped in the Secure EL1 translation regime
* with Normal IS WBWA attributes and RO data and Execute Never
* instruction access permissions.
*
* X1: Size of the buffer in bytes
*
* X2: cookie value (Implementation Defined)
*
* X3: cookie value (Implementation Defined)
*
* X4 to X30 = 0 (already done by cm_init_my_context())
*/
write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0, PLAT_SPM_BUF_BASE);
write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1, PLAT_SPM_BUF_SIZE);
write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2, PLAT_SPM_COOKIE_0);
write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3, PLAT_SPM_COOKIE_1);
/*
* SP_EL0: A non-zero value will indicate to the SP that the SPM has
* initialized the stack pointer for the current CPU through
* implementation defined means. The value will be 0 otherwise.
*/
write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0,
PLAT_SP_IMAGE_STACK_BASE + PLAT_SP_IMAGE_STACK_PCPU_SIZE);
/*
* Setup translation tables
* ------------------------
*/
#if ENABLE_ASSERTIONS
/* Get max granularity supported by the platform. */
u_register_t id_aa64prf0_el1 = read_id_aa64pfr0_el1();
int tgran64_supported =
((id_aa64prf0_el1 >> ID_AA64MMFR0_EL1_TGRAN64_SHIFT) &
ID_AA64MMFR0_EL1_TGRAN64_MASK) ==
ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED;
int tgran16_supported =
((id_aa64prf0_el1 >> ID_AA64MMFR0_EL1_TGRAN16_SHIFT) &
ID_AA64MMFR0_EL1_TGRAN16_MASK) ==
ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED;
int tgran4_supported =
((id_aa64prf0_el1 >> ID_AA64MMFR0_EL1_TGRAN4_SHIFT) &
ID_AA64MMFR0_EL1_TGRAN4_MASK) ==
ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED;
uintptr_t max_granule_size;
if (tgran64_supported) {
max_granule_size = 64 * 1024;
} else if (tgran16_supported) {
max_granule_size = 16 * 1024;
} else {
assert(tgran4_supported);
max_granule_size = 4 * 1024;
}
VERBOSE("Max translation granule supported: %lu KiB\n",
max_granule_size);
uintptr_t max_granule_size_mask = max_granule_size - 1;
/* Base must be aligned to the max granularity */
assert((ARM_SP_IMAGE_NS_BUF_BASE & max_granule_size_mask) == 0);
/* Size must be a multiple of the max granularity */
assert((ARM_SP_IMAGE_NS_BUF_SIZE & max_granule_size_mask) == 0);
#endif /* ENABLE_ASSERTIONS */
/* This region contains the exception vectors used at S-EL1. */
const mmap_region_t sel1_exception_vectors =
MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START,
SPM_SHIM_EXCEPTIONS_SIZE,
MT_CODE | MT_SECURE | MT_PRIVILEGED);
mmap_add_region_ctx(&secure_partition_xlat_ctx,
&sel1_exception_vectors);
mmap_add_ctx(&secure_partition_xlat_ctx,
plat_get_secure_partition_mmap(NULL));
init_xlat_tables_ctx(&secure_partition_xlat_ctx);
/*
* MMU-related registers
* ---------------------
*/
/* Set attributes in the right indices of the MAIR */
u_register_t mair_el1 =
MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX) |
MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX) |
MAIR_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX);
write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1, mair_el1);
/* Setup TCR_EL1. */
u_register_t tcr_ps_bits = tcr_physical_addr_size_bits(PLAT_PHY_ADDR_SPACE_SIZE);
u_register_t tcr_el1 =
/* Size of region addressed by TTBR0_EL1 = 2^(64-T0SZ) bytes. */
(64 - __builtin_ctzl(PLAT_VIRT_ADDR_SPACE_SIZE)) |
/* Inner and outer WBWA, shareable. */
TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA |
/* Set the granularity to 4KB. */
TCR_TG0_4K |
/* Limit Intermediate Physical Address Size. */
tcr_ps_bits << TCR_EL1_IPS_SHIFT |
/* Disable translations using TBBR1_EL1. */
TCR_EPD1_BIT
/* The remaining fields related to TBBR1_EL1 are left as zero. */
;
tcr_el1 &= ~(
/* Enable translations using TBBR0_EL1 */
TCR_EPD0_BIT
);
write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1, tcr_el1);
/* Setup SCTLR_EL1 */
u_register_t sctlr_el1 = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1);
sctlr_el1 |=
/*SCTLR_EL1_RES1 |*/
/* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
SCTLR_UCI_BIT |
/* RW regions at xlat regime EL1&0 are forced to be XN. */
SCTLR_WXN_BIT |
/* Don't trap to EL1 execution of WFI or WFE at EL0. */
SCTLR_NTWI_BIT | SCTLR_NTWE_BIT |
/* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
SCTLR_UCT_BIT |
/* Don't trap to EL1 execution of DZ ZVA at EL0. */
SCTLR_DZE_BIT |
/* Enable SP Alignment check for EL0 */
SCTLR_SA0_BIT |
/* Allow cacheable data and instr. accesses to normal memory. */
SCTLR_C_BIT | SCTLR_I_BIT |
/* Alignment fault checking enabled when at EL1 and EL0. */
SCTLR_A_BIT |
/* Enable MMU. */
SCTLR_M_BIT
;
sctlr_el1 &= ~(
/* Explicit data accesses at EL0 are little-endian. */
SCTLR_E0E_BIT |
/* Accesses to DAIF from EL0 are trapped to EL1. */
SCTLR_UMA_BIT
);
write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
/* Point TTBR0_EL1 at the tables of the context created for the SP. */
write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1,
(u_register_t)secure_partition_base_xlat_table);
/*
* Setup other system registers
* ----------------------------
*/
/* Shim Exception Vector Base Address */
write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1,
SPM_SHIM_EXCEPTIONS_PTR);
/*
* FPEN: Forbid the Secure Partition to access FP/SIMD registers.
* TTA: Enable access to trace registers.
* ZEN (v8.2): Trap SVE instructions and access to SVE registers.
*/
write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1,
CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_ALL));
/*
* Prepare information in buffer shared between EL3 and S-EL0
* ----------------------------------------------------------
*/
void *shared_buf_ptr = (void *) PLAT_SPM_BUF_BASE;
/* Copy the boot information into the shared buffer with the SP. */
assert((uintptr_t)shared_buf_ptr + sizeof(secure_partition_boot_info_t)
<= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE));
assert(PLAT_SPM_BUF_BASE <= (UINTPTR_MAX - PLAT_SPM_BUF_SIZE + 1));
const secure_partition_boot_info_t *sp_boot_info =
plat_get_secure_partition_boot_info(NULL);
assert(sp_boot_info != NULL);
memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info,
sizeof(secure_partition_boot_info_t));
/* Pointer to the MP information from the platform port. */
secure_partition_mp_info_t *sp_mp_info =
((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info;
assert(sp_mp_info != NULL);
/*
* Point the shared buffer MP information pointer to where the info will
* be populated, just after the boot info.
*/
((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info =
((secure_partition_mp_info_t *) shared_buf_ptr) +
sizeof(secure_partition_boot_info_t);
/*
* Update the shared buffer pointer to where the MP information for the
* payload will be populated
*/
shared_buf_ptr = ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info;
/*
* Copy the cpu information into the shared buffer area after the boot
* information.
*/
assert(sp_boot_info->num_cpus <= PLATFORM_CORE_COUNT);
assert((uintptr_t)shared_buf_ptr
<= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE -
(sp_boot_info->num_cpus * sizeof(*sp_mp_info))));
memcpy(shared_buf_ptr, (const void *) sp_mp_info,
sp_boot_info->num_cpus * sizeof(*sp_mp_info));
/*
* Calculate the linear indices of cores in boot information for the
* secure partition and flag the primary CPU
*/
sp_mp_info = (secure_partition_mp_info_t *) shared_buf_ptr;
for (unsigned int index = 0; index < sp_boot_info->num_cpus; index++) {
u_register_t mpidr = sp_mp_info[index].mpidr;
sp_mp_info[index].linear_id = plat_core_pos_by_mpidr(mpidr);
if (plat_my_core_pos() == sp_mp_info[index].linear_id)
sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU;
}
VERBOSE("S-EL1/S-EL0 context setup end.\n");
}

View File

@ -0,0 +1,25 @@
#
# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
ifneq (${SPD},none)
$(error "Error: SPD and SPM are incompatible build options.")
endif
ifneq (${ARCH},aarch64)
$(error "Error: SPM is only supported on aarch64.")
endif
# SPM sources
SPM_SOURCES := $(addprefix services/std_svc/spm/, \
spm_main.c \
${ARCH}/spm_helpers.S \
secure_partition_setup.c \
${ARCH}/spm_shim_exceptions.S)
# Let the top-level Makefile know that we intend to include a BL32 image
NEED_BL32 := yes

View File

@ -0,0 +1,452 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl31.h>
#include <context_mgmt.h>
#include <debug.h>
#include <errno.h>
#include <platform.h>
#include <runtime_svc.h>
#include <secure_partition.h>
#include <smcc.h>
#include <smcc_helpers.h>
#include <spinlock.h>
#include <spm_svc.h>
#include <utils.h>
#include <xlat_tables_v2.h>
#include "spm_private.h"
/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */
static spinlock_t mem_attr_smc_lock;
/*******************************************************************************
* Secure Partition context information.
******************************************************************************/
static secure_partition_context_t sp_ctx;
unsigned int sp_init_in_progress;
/*******************************************************************************
* Replace the S-EL1 re-entry information with S-EL0 re-entry
* information
******************************************************************************/
void spm_setup_next_eret_into_sel0(cpu_context_t *secure_context)
{
assert(secure_context == cm_get_context(SECURE));
cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
}
/*******************************************************************************
* This function takes an SP context pointer and:
* 1. Applies the S-EL1 system register context from sp_ctx->cpu_ctx.
* 2. Saves the current C runtime state (callee-saved registers) on the stack
* frame and saves a reference to this state.
* 3. Calls el3_exit() so that the EL3 system and general purpose registers
* from the sp_ctx->cpu_ctx are used to enter the secure payload image.
******************************************************************************/
static uint64_t spm_synchronous_sp_entry(secure_partition_context_t *sp_ctx_ptr)
{
uint64_t rc;
assert(sp_ctx_ptr != NULL);
assert(sp_ctx_ptr->c_rt_ctx == 0);
assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
/* Apply the Secure EL1 system register context and switch to it */
cm_el1_sysregs_context_restore(SECURE);
cm_set_next_eret_context(SECURE);
VERBOSE("%s: We're about to enter the Secure partition...\n", __func__);
rc = spm_secure_partition_enter(&sp_ctx_ptr->c_rt_ctx);
#if ENABLE_ASSERTIONS
sp_ctx_ptr->c_rt_ctx = 0;
#endif
return rc;
}
/*******************************************************************************
* This function takes a Secure partition context pointer and:
* 1. Saves the S-EL1 system register context tp sp_ctx->cpu_ctx.
* 2. Restores the current C runtime state (callee saved registers) from the
* stack frame using the reference to this state saved in
* spm_secure_partition_enter().
* 3. It does not need to save any general purpose or EL3 system register state
* as the generic smc entry routine should have saved those.
******************************************************************************/
static void __dead2 spm_synchronous_sp_exit(
secure_partition_context_t *sp_ctx_ptr, uint64_t ret)
{
assert(sp_ctx_ptr != NULL);
/* Save the Secure EL1 system register context */
assert(cm_get_context(SECURE) == &sp_ctx_ptr->cpu_ctx);
cm_el1_sysregs_context_save(SECURE);
assert(sp_ctx_ptr->c_rt_ctx != 0);
spm_secure_partition_exit(sp_ctx_ptr->c_rt_ctx, ret);
/* Should never reach here */
assert(0);
}
/*******************************************************************************
* This function passes control to the Secure Partition image (BL32) for the
* first time on the primary cpu after a cold boot. It assumes that a valid
* secure context has already been created by spm_setup() which can be directly
* used. This function performs a synchronous entry into the Secure payload.
* The SP passes control back to this routine through a SMC.
******************************************************************************/
int32_t spm_init(void)
{
entry_point_info_t *secure_partition_ep_info;
uint64_t rc;
VERBOSE("%s entry\n", __func__);
/*
* Get information about the Secure Partition (BL32) image. Its
* absence is a critical failure.
*/
secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
assert(secure_partition_ep_info);
/*
* Initialise the common context and then overlay the S-EL0 specific
* context on top of it.
*/
cm_init_my_context(secure_partition_ep_info);
secure_partition_setup();
/*
* Arrange for an entry into the secure payload.
*/
sp_init_in_progress = 1;
rc = spm_synchronous_sp_entry(&sp_ctx);
assert(rc == 0);
sp_init_in_progress = 0;
VERBOSE("SP_MEM_ATTRIBUTES_SET_AARCH64 availability has been revoked\n");
return rc;
}
/*******************************************************************************
* Given a secure payload entrypoint info pointer, entry point PC & pointer to
* a context data structure, this function will initialize the SPM context and
* entry point info for the secure payload
******************************************************************************/
void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
uint64_t pc,
secure_partition_context_t *sp_ctx_ptr)
{
uint32_t ep_attr;
assert(sp_ep_info);
assert(pc);
assert(sp_ctx_ptr);
cm_set_context(&sp_ctx_ptr->cpu_ctx, SECURE);
/* initialise an entrypoint to set up the CPU context */
ep_attr = SECURE | EP_ST_ENABLE;
if (read_sctlr_el3() & SCTLR_EE_BIT)
ep_attr |= EP_EE_BIG;
SET_PARAM_HEAD(sp_ep_info, PARAM_EP, VERSION_1, ep_attr);
sp_ep_info->pc = pc;
/* The SPM payload runs in S-EL0 */
sp_ep_info->spsr = SPSR_64(MODE_EL0,
MODE_SP_EL0,
DISABLE_ALL_EXCEPTIONS);
zeromem(&sp_ep_info->args, sizeof(sp_ep_info->args));
}
/*******************************************************************************
* Secure Partition Manager setup. The SPM finds out the SP entrypoint if not
* already known and initialises the context for entry into the SP for its
* initialisation.
******************************************************************************/
int32_t spm_setup(void)
{
entry_point_info_t *secure_partition_ep_info;
VERBOSE("%s entry\n", __func__);
/*
* Get information about the Secure Partition (BL32) image. Its
* absence is a critical failure.
*/
secure_partition_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
if (!secure_partition_ep_info) {
WARN("No SPM provided by BL2 boot loader, Booting device"
" without SPM initialization. SMCs destined for SPM"
" will return SMC_UNK\n");
return 1;
}
/*
* If there's no valid entry point for SP, we return a non-zero value
* signalling failure initializing the service. We bail out without
* registering any handlers
*/
if (!secure_partition_ep_info->pc) {
return 1;
}
spm_init_sp_ep_state(secure_partition_ep_info,
secure_partition_ep_info->pc,
&sp_ctx);
/*
* All SPM initialization done. Now register our init function with
* BL31 for deferred invocation
*/
bl31_register_bl32_init(&spm_init);
VERBOSE("%s exit\n", __func__);
return 0;
}
/*
* Attributes are encoded using a different format in the SMC interface than in
* the Trusted Firmware, where the mmap_attr_t enum type is used. This function
* 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().
*/
static mmap_attr_t smc_attr_to_mmap_attr(unsigned int attributes)
{
mmap_attr_t tf_attr = 0;
unsigned int access = (attributes & SP_MEM_ATTR_ACCESS_MASK)
>> SP_MEM_ATTR_ACCESS_SHIFT;
if (access == SP_MEM_ATTR_ACCESS_RW) {
tf_attr |= MT_RW | MT_USER;
} else if (access == SP_MEM_ATTR_ACCESS_RO) {
tf_attr |= MT_RO | MT_USER;
} else {
/* Other values are reserved. */
assert(access == SP_MEM_ATTR_ACCESS_NOACCESS);
/* The only requirement is that there's no access from EL0 */
tf_attr |= MT_RO | MT_PRIVILEGED;
}
if ((attributes & SP_MEM_ATTR_NON_EXEC) == 0) {
tf_attr |= MT_EXECUTE;
} else {
tf_attr |= MT_EXECUTE_NEVER;
}
return tf_attr;
}
/*
* This function converts attributes from the Trusted Firmware format into the
* SMC interface format.
*/
static int smc_mmap_to_smc_attr(mmap_attr_t attr)
{
int smc_attr = 0;
int data_access;
if ((attr & MT_USER) == 0) {
/* No access from EL0. */
data_access = SP_MEM_ATTR_ACCESS_NOACCESS;
} else {
if ((attr & MT_RW) != 0) {
assert(MT_TYPE(attr) != MT_DEVICE);
data_access = SP_MEM_ATTR_ACCESS_RW;
} else {
data_access = SP_MEM_ATTR_ACCESS_RO;
}
}
smc_attr |= (data_access & SP_MEM_ATTR_ACCESS_MASK) << SP_MEM_ATTR_ACCESS_SHIFT;
if (attr & MT_EXECUTE_NEVER) {
smc_attr |= SP_MEM_ATTR_NON_EXEC;
}
return smc_attr;
}
static int spm_memory_attributes_get_smc_handler(uintptr_t base_va)
{
spin_lock(&mem_attr_smc_lock);
mmap_attr_t attributes;
int rc = get_mem_attributes(secure_partition_xlat_ctx_handle,
base_va, &attributes);
spin_unlock(&mem_attr_smc_lock);
/* Convert error codes of get_mem_attributes() into SPM ones. */
assert(rc == 0 || rc == -EINVAL);
if (rc == 0) {
return smc_mmap_to_smc_attr(attributes);
} else {
return SPM_INVALID_PARAMETER;
}
}
static int spm_memory_attributes_set_smc_handler(u_register_t page_address,
u_register_t pages_count,
u_register_t smc_attributes)
{
uintptr_t base_va = (uintptr_t) page_address;
size_t size = (size_t) (pages_count * PAGE_SIZE);
unsigned int attributes = (unsigned int) smc_attributes;
INFO(" Start address : 0x%lx\n", base_va);
INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
INFO(" Attributes : 0x%x\n", attributes);
spin_lock(&mem_attr_smc_lock);
int ret = change_mem_attributes(secure_partition_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. */
assert(ret == 0 || ret == -EINVAL);
return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;
}
uint64_t spm_smc_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
uint64_t x3,
uint64_t x4,
void *cookie,
void *handle,
uint64_t flags)
{
cpu_context_t *ns_cpu_context;
unsigned int ns;
/* Determine which security state this SMC originated from */
ns = is_caller_non_secure(flags);
if (ns == SMC_FROM_SECURE) {
/* Handle SMCs from Secure world. */
switch (smc_fid) {
case SPM_VERSION_AARCH32:
SMC_RET1(handle, SPM_VERSION_COMPILED);
case SP_EVENT_COMPLETE_AARCH64:
assert(handle == cm_get_context(SECURE));
cm_el1_sysregs_context_save(SECURE);
spm_setup_next_eret_into_sel0(handle);
if (sp_init_in_progress) {
/*
* SPM reports completion. The SPM must have
* initiated the original request through a
* synchronous entry into the secure
* partition. Jump back to the original C
* runtime context.
*/
spm_synchronous_sp_exit(&sp_ctx, x1);
assert(0);
}
/*
* This is the result from the Secure partition of an
* earlier request. Copy the result into the non-secure
* context, save the secure state and return to the
* non-secure state.
*/
/* Get a reference to the non-secure context */
ns_cpu_context = cm_get_context(NON_SECURE);
assert(ns_cpu_context);
/* Restore non-secure state */
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
/* Return to normal world */
SMC_RET1(ns_cpu_context, x1);
case SP_MEM_ATTRIBUTES_GET_AARCH64:
INFO("Received SP_MEM_ATTRIBUTES_GET_AARCH64 SMC\n");
if (!sp_init_in_progress) {
WARN("SP_MEM_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
SMC_RET1(handle, SPM_NOT_SUPPORTED);
}
SMC_RET1(handle, spm_memory_attributes_get_smc_handler(x1));
case SP_MEM_ATTRIBUTES_SET_AARCH64:
INFO("Received SP_MEM_ATTRIBUTES_SET_AARCH64 SMC\n");
if (!sp_init_in_progress) {
WARN("SP_MEM_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
SMC_RET1(handle, SPM_NOT_SUPPORTED);
}
SMC_RET1(handle, spm_memory_attributes_set_smc_handler(x1, x2, x3));
default:
break;
}
} else {
/* Handle SMCs from Non-secure world. */
switch (smc_fid) {
case SP_VERSION_AARCH64:
case SP_VERSION_AARCH32:
SMC_RET1(handle, SP_VERSION_COMPILED);
case SP_COMMUNICATE_AARCH32:
case SP_COMMUNICATE_AARCH64:
/* Save the Normal world context */
cm_el1_sysregs_context_save(NON_SECURE);
/*
* Restore the secure world context and prepare for
* entry in S-EL0
*/
assert(&sp_ctx.cpu_ctx == cm_get_context(SECURE));
cm_el1_sysregs_context_restore(SECURE);
cm_set_next_eret_context(SECURE);
if (x2 != 0) {
VERBOSE("SP_COMMUNICATE_AARCH32/64: X2 is not 0 as recommended.");
}
SMC_RET4(&sp_ctx.cpu_ctx,
smc_fid, x2, x3, plat_my_core_pos());
case SP_MEM_ATTRIBUTES_GET_AARCH64:
case SP_MEM_ATTRIBUTES_SET_AARCH64:
/* SMC interfaces reserved for secure callers. */
SMC_RET1(handle, SPM_NOT_SUPPORTED);
default:
break;
}
}
SMC_RET1(handle, SMC_UNK);
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SPM_PRIVATE_H__
#define __SPM_PRIVATE_H__
#include <context.h>
/*******************************************************************************
* Constants that allow assembler code to preserve callee-saved registers of the
* C runtime context while performing a security state switch.
******************************************************************************/
#define SP_C_RT_CTX_X19 0x0
#define SP_C_RT_CTX_X20 0x8
#define SP_C_RT_CTX_X21 0x10
#define SP_C_RT_CTX_X22 0x18
#define SP_C_RT_CTX_X23 0x20
#define SP_C_RT_CTX_X24 0x28
#define SP_C_RT_CTX_X25 0x30
#define SP_C_RT_CTX_X26 0x38
#define SP_C_RT_CTX_X27 0x40
#define SP_C_RT_CTX_X28 0x48
#define SP_C_RT_CTX_X29 0x50
#define SP_C_RT_CTX_X30 0x58
#define SP_C_RT_CTX_SIZE 0x60
#define SP_C_RT_CTX_ENTRIES (SP_C_RT_CTX_SIZE >> DWORD_SHIFT)
#ifndef __ASSEMBLY__
#include <stdint.h>
#include <xlat_tables_v2.h>
/* Handle on the Secure partition translation context */
extern xlat_ctx_t *secure_partition_xlat_ctx_handle;
struct entry_point_info;
typedef struct secure_partition_context {
uint64_t c_rt_ctx;
cpu_context_t cpu_ctx;
} secure_partition_context_t;
uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx);
void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret);
void spm_init_sp_ep_state(struct entry_point_info *sp_ep_info,
uint64_t pc,
secure_partition_context_t *sp_ctx_ptr);
#endif /* __ASSEMBLY__ */
#endif /* __SPM_PRIVATE_H__ */

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SPM_SHIM_PRIVATE__
#define __SPM_SHIM_PRIVATE__
#include <types.h>
/* Assembly source */
extern uintptr_t spm_shim_exceptions_ptr;
/* Linker symbols */
extern uintptr_t __SPM_SHIM_EXCEPTIONS_START__;
extern uintptr_t __SPM_SHIM_EXCEPTIONS_END__;
/* Definitions */
#define SPM_SHIM_EXCEPTIONS_PTR (uintptr_t)(&spm_shim_exceptions_ptr)
#define SPM_SHIM_EXCEPTIONS_START \
(uintptr_t)(&__SPM_SHIM_EXCEPTIONS_START__)
#define SPM_SHIM_EXCEPTIONS_END \
(uintptr_t)(&__SPM_SHIM_EXCEPTIONS_END__)
#define SPM_SHIM_EXCEPTIONS_SIZE \
(SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START)
#endif /* __SPM_SHIM_PRIVATE__ */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -12,6 +12,7 @@
#include <runtime_instr.h>
#include <runtime_svc.h>
#include <smcc_helpers.h>
#include <spm_svc.h>
#include <std_svc.h>
#include <stdint.h>
#include <uuid.h>
@ -25,15 +26,26 @@ DEFINE_SVC_UUID(arm_svc_uid,
static int32_t std_svc_setup(void)
{
uintptr_t svc_arg;
int ret = 0;
svc_arg = get_arm_std_svc_args(PSCI_FID_MASK);
assert(svc_arg);
/*
* PSCI is the only specification implemented as a Standard Service.
* PSCI is one of the specifications implemented as a Standard Service.
* The `psci_setup()` also does EL3 architectural setup.
*/
return psci_setup((const psci_lib_args_t *)svc_arg);
if (psci_setup((const psci_lib_args_t *)svc_arg) != PSCI_E_SUCCESS) {
ret = 1;
}
#if ENABLE_SPM
if (spm_setup() != 0) {
ret = 1;
}
#endif
return ret;
}
/*
@ -80,6 +92,18 @@ uintptr_t std_svc_smc_handler(uint32_t smc_fid,
SMC_RET1(handle, ret);
}
#if ENABLE_SPM
/*
* Dispatch SPM calls to SPM SMC handler and return its return
* value
*/
if (is_spm_fid(smc_fid)) {
return spm_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
handle, flags);
}
#endif
switch (smc_fid) {
case ARM_STD_SVC_CALL_COUNT:
/*