From 2d7b9e5e7fde47be6e312a903f127964596bb85e Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Tue, 30 Oct 2018 11:08:08 +0000 Subject: [PATCH] SPM: Deprecate the current implementation The current SPM is a prototype that only supports one secure partition in EL0. The objective of SPM is to have multiple partitions. The current MM interface isn't adequate for this, so it is needed to modify heavily the code to add proper support for it. However, there are platforms which are already using this (like SGI) and removing the code would break it. For this reason, the current SPM code has been duplicated in order to temporarily preserve compatibility. All new improvements/changes to SPM will be done in the non-deprecated copy, that may change without notice. The new build option SPM_DEPRECATED has been introduced to select the SPM implementation. It defaults to 1, that selects the deprecated SPM. Change-Id: Ic9f80b53b450e97b4d3f47e4ef4a138ee8d87443 Signed-off-by: Antonio Nino Diaz --- Makefile | 2 + bl31/bl31.mk | 15 +- make_helpers/defaults.mk | 3 + .../spm_deprecated/aarch64/spm_helpers.S | 74 ++++ .../aarch64/spm_shim_exceptions.S | 128 +++++++ services/std_svc/spm_deprecated/sp_setup.c | 247 ++++++++++++ services/std_svc/spm_deprecated/sp_xlat.c | 155 ++++++++ services/std_svc/spm_deprecated/spm.mk | 23 ++ services/std_svc/spm_deprecated/spm_main.c | 353 ++++++++++++++++++ services/std_svc/spm_deprecated/spm_private.h | 70 ++++ .../std_svc/spm_deprecated/spm_shim_private.h | 25 ++ 11 files changed, 1090 insertions(+), 5 deletions(-) create mode 100644 services/std_svc/spm_deprecated/aarch64/spm_helpers.S create mode 100644 services/std_svc/spm_deprecated/aarch64/spm_shim_exceptions.S create mode 100644 services/std_svc/spm_deprecated/sp_setup.c create mode 100644 services/std_svc/spm_deprecated/sp_xlat.c create mode 100644 services/std_svc/spm_deprecated/spm.mk create mode 100644 services/std_svc/spm_deprecated/spm_main.c create mode 100644 services/std_svc/spm_deprecated/spm_private.h create mode 100644 services/std_svc/spm_deprecated/spm_shim_private.h diff --git a/Makefile b/Makefile index eed7c7a8..e1bbb96f 100644 --- a/Makefile +++ b/Makefile @@ -570,6 +570,7 @@ $(eval $(call assert_boolean,RESET_TO_BL31)) $(eval $(call assert_boolean,SAVE_KEYS)) $(eval $(call assert_boolean,SEPARATE_CODE_AND_RODATA)) $(eval $(call assert_boolean,SPIN_ON_BL1_EXIT)) +$(eval $(call assert_boolean,SPM_DEPRECATED)) $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT)) $(eval $(call assert_boolean,USE_COHERENT_MEM)) $(eval $(call assert_boolean,USE_ROMLIB)) @@ -623,6 +624,7 @@ $(eval $(call add_define,RECLAIM_INIT_CODE)) $(eval $(call add_define,SMCCC_MAJOR_VERSION)) $(eval $(call add_define,SPD_${SPD})) $(eval $(call add_define,SPIN_ON_BL1_EXIT)) +$(eval $(call add_define,SPM_DEPRECATED)) $(eval $(call add_define,TRUSTED_BOARD_BOOT)) $(eval $(call add_define,USE_COHERENT_MEM)) $(eval $(call add_define,USE_ROMLIB)) diff --git a/bl31/bl31.mk b/bl31/bl31.mk index 019a19ec..eddd164f 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -8,11 +8,16 @@ # Include SPM Makefile ################################################################################ ifeq (${ENABLE_SPM},1) -ifeq (${EL3_EXCEPTION_HANDLING},0) - $(error EL3_EXCEPTION_HANDLING must be 1 for SPM support) -endif -$(info Including SPM makefile) -include services/std_svc/spm/spm.mk + ifeq (${SPM_DEPRECATED},1) + ifeq (${EL3_EXCEPTION_HANDLING},0) + $(error EL3_EXCEPTION_HANDLING must be 1 for SPM support) + endif + $(info Including deprecated SPM makefile) + include services/std_svc/spm_deprecated/spm.mk + else + $(info Including SPM makefile) + include services/std_svc/spm/spm.mk + endif endif diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 4a3f5411..a55e729b 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -162,6 +162,9 @@ SPD := none # For including the Secure Partition Manager ENABLE_SPM := 0 +# Use the deprecated SPM based on MM +SPM_DEPRECATED := 1 + # 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 diff --git a/services/std_svc/spm_deprecated/aarch64/spm_helpers.S b/services/std_svc/spm_deprecated/aarch64/spm_helpers.S new file mode 100644 index 00000000..aa35811f --- /dev/null +++ b/services/std_svc/spm_deprecated/aarch64/spm_helpers.S @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#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 diff --git a/services/std_svc/spm_deprecated/aarch64/spm_shim_exceptions.S b/services/std_svc/spm_deprecated/aarch64/spm_shim_exceptions.S new file mode 100644 index 00000000..9c218dfe --- /dev/null +++ b/services/std_svc/spm_deprecated/aarch64/spm_shim_exceptions.S @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +/* ----------------------------------------------------------------------------- + * 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 . +end_vector_entry SynchronousExceptionSP0 + +vector_entry IrqSP0, .spm_shim_exceptions + b . +end_vector_entry IrqSP0 + +vector_entry FiqSP0, .spm_shim_exceptions + b . +end_vector_entry FiqSP0 + +vector_entry SErrorSP0, .spm_shim_exceptions + b . +end_vector_entry SErrorSP0 + + /* ----------------------------------------------------- + * Current EL with SPx: 0x200 - 0x400 + * ----------------------------------------------------- + */ +vector_entry SynchronousExceptionSPx, .spm_shim_exceptions + b . +end_vector_entry SynchronousExceptionSPx + +vector_entry IrqSPx, .spm_shim_exceptions + b . +end_vector_entry IrqSPx + +vector_entry FiqSPx, .spm_shim_exceptions + b . +end_vector_entry FiqSPx + +vector_entry SErrorSPx, .spm_shim_exceptions + b . +end_vector_entry 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 +end_vector_entry SynchronousExceptionA64 + +vector_entry IrqA64, .spm_shim_exceptions + b . +end_vector_entry IrqA64 + +vector_entry FiqA64, .spm_shim_exceptions + b . +end_vector_entry FiqA64 + +vector_entry SErrorA64, .spm_shim_exceptions + b . +end_vector_entry SErrorA64 + + /* ----------------------------------------------------- + * Lower EL using AArch32 : 0x600 - 0x800 + * ----------------------------------------------------- + */ +vector_entry SynchronousExceptionA32, .spm_shim_exceptions + b . +end_vector_entry SynchronousExceptionA32 + +vector_entry IrqA32, .spm_shim_exceptions + b . +end_vector_entry IrqA32 + +vector_entry FiqA32, .spm_shim_exceptions + b . +end_vector_entry FiqA32 + +vector_entry SErrorA32, .spm_shim_exceptions + b . +end_vector_entry SErrorA32 diff --git a/services/std_svc/spm_deprecated/sp_setup.c b/services/std_svc/spm_deprecated/sp_setup.c new file mode 100644 index 00000000..0d61306f --- /dev/null +++ b/services/std_svc/spm_deprecated/sp_setup.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spm_private.h" +#include "spm_shim_private.h" + +/* Setup context of the Secure Partition */ +void spm_sp_setup(sp_context_t *sp_ctx) +{ + cpu_context_t *ctx = &(sp_ctx->cpu_ctx); + + /* + * Initialize CPU context + * ---------------------- + */ + + entry_point_info_t ep_info = {0}; + + SET_PARAM_HEAD(&ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE); + + /* Setup entrypoint and SPSR */ + ep_info.pc = BL32_BASE; + ep_info.spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS); + + /* + * 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 X7 = 0 + */ + ep_info.args.arg0 = PLAT_SPM_BUF_BASE; + ep_info.args.arg1 = PLAT_SPM_BUF_SIZE; + ep_info.args.arg2 = PLAT_SPM_COOKIE_0; + ep_info.args.arg3 = PLAT_SPM_COOKIE_1; + + cm_setup_context(ctx, &ep_info); + + /* + * 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. */ + unsigned int max_granule = xlat_arch_get_max_supported_granule_size(); + + VERBOSE("Max translation granule size supported: %u KiB\n", + max_granule / 1024U); + + unsigned int max_granule_mask = max_granule - 1U; + + /* Base must be aligned to the max granularity */ + assert((ARM_SP_IMAGE_NS_BUF_BASE & max_granule_mask) == 0); + + /* Size must be a multiple of the max granularity */ + assert((ARM_SP_IMAGE_NS_BUF_SIZE & max_granule_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(sp_ctx->xlat_ctx_handle, + &sel1_exception_vectors); + + mmap_add_ctx(sp_ctx->xlat_ctx_handle, + plat_get_secure_partition_mmap(NULL)); + + init_xlat_tables_ctx(sp_ctx->xlat_ctx_handle); + + /* + * MMU-related registers + * --------------------- + */ + xlat_ctx_t *xlat_ctx = sp_ctx->xlat_ctx_handle; + + uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX]; + + setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table, + xlat_ctx->pa_max_address, xlat_ctx->va_max_address, + EL1_EL0_REGIME); + + write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1, + mmu_cfg_params[MMU_CFG_MAIR]); + + write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1, + mmu_cfg_params[MMU_CFG_TCR]); + + write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1, + mmu_cfg_params[MMU_CFG_TTBR0]); + + /* 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); + + /* + * Setup other system registers + * ---------------------------- + */ + + /* Shim Exception Vector Base Address */ + write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1, + SPM_SHIM_EXCEPTIONS_PTR); + + /* + * FPEN: Allow the Secure Partition to access FP/SIMD registers. + * Note that SPM will not do any saving/restoring of these registers on + * behalf of the SP. This falls under the SP's responsibility. + * 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_NONE)); + + /* + * 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 *) ((uintptr_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; + } +} diff --git a/services/std_svc/spm_deprecated/sp_xlat.c b/services/std_svc/spm_deprecated/sp_xlat.c new file mode 100644 index 00000000..35271386 --- /dev/null +++ b/services/std_svc/spm_deprecated/sp_xlat.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spm_private.h" +#include "spm_shim_private.h" + +/* Place translation tables by default along with the ones used by BL31. */ +#ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME +#define PLAT_SP_IMAGE_XLAT_SECTION_NAME "xlat_table" +#endif + +/* Allocate and initialise the translation context for the secure partitions. */ +REGISTER_XLAT_CONTEXT2(sp, + PLAT_SP_IMAGE_MMAP_REGIONS, + PLAT_SP_IMAGE_MAX_XLAT_TABLES, + PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE, + EL1_EL0_REGIME, PLAT_SP_IMAGE_XLAT_SECTION_NAME); + +/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */ +static spinlock_t mem_attr_smc_lock; + +/* Get handle of Secure Partition translation context */ +xlat_ctx_t *spm_get_sp_xlat_context(void) +{ + return &sp_xlat_ctx; +}; + +/* + * 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 + * xlat_change_mem_attributes_ctx(). + */ +static unsigned int smc_attr_to_mmap_attr(unsigned int attributes) +{ + unsigned int tf_attr = 0U; + + unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK) + >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT; + + if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) { + tf_attr |= MT_RW | MT_USER; + } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) { + tf_attr |= MT_RO | MT_USER; + } else { + /* Other values are reserved. */ + assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS); + /* The only requirement is that there's no access from EL0 */ + tf_attr |= MT_RO | MT_PRIVILEGED; + } + + if ((attributes & SP_MEMORY_ATTRIBUTES_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 unsigned int smc_mmap_to_smc_attr(unsigned int attr) +{ + unsigned int smc_attr = 0U; + + unsigned int data_access; + + if ((attr & MT_USER) == 0) { + /* No access from EL0. */ + data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS; + } else { + if ((attr & MT_RW) != 0) { + assert(MT_TYPE(attr) != MT_DEVICE); + data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW; + } else { + data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO; + } + } + + smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK) + << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT; + + if ((attr & MT_EXECUTE_NEVER) != 0U) { + smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC; + } + + return smc_attr; +} + +int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx, + uintptr_t base_va) +{ + uint32_t attributes; + + spin_lock(&mem_attr_smc_lock); + + int rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, + base_va, &attributes); + + spin_unlock(&mem_attr_smc_lock); + + /* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */ + assert((rc == 0) || (rc == -EINVAL)); + + if (rc == 0) { + return (int32_t) smc_mmap_to_smc_attr(attributes); + } else { + return SPM_INVALID_PARAMETER; + } +} + +int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx, + 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); + uint32_t attributes = (uint32_t) 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 = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, + base_va, size, + smc_attr_to_mmap_attr(attributes)); + + spin_unlock(&mem_attr_smc_lock); + + /* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */ + assert((ret == 0) || (ret == -EINVAL)); + + return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER; +} diff --git a/services/std_svc/spm_deprecated/spm.mk b/services/std_svc/spm_deprecated/spm.mk new file mode 100644 index 00000000..fedcaed0 --- /dev/null +++ b/services/std_svc/spm_deprecated/spm.mk @@ -0,0 +1,23 @@ +# +# Copyright (c) 2017-2018, 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 := $(addprefix services/std_svc/spm_deprecated/, \ + ${ARCH}/spm_helpers.S \ + ${ARCH}/spm_shim_exceptions.S \ + spm_main.c \ + sp_setup.c \ + sp_xlat.c) + + +# Let the top-level Makefile know that we intend to include a BL32 image +NEED_BL32 := yes diff --git a/services/std_svc/spm_deprecated/spm_main.c b/services/std_svc/spm_deprecated/spm_main.c new file mode 100644 index 00000000..880e86e4 --- /dev/null +++ b/services/std_svc/spm_deprecated/spm_main.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spm_private.h" + +/******************************************************************************* + * Secure Partition context information. + ******************************************************************************/ +static sp_context_t sp_ctx; + +/******************************************************************************* + * Set state of a Secure Partition context. + ******************************************************************************/ +void sp_state_set(sp_context_t *sp_ptr, sp_state_t state) +{ + spin_lock(&(sp_ptr->state_lock)); + sp_ptr->state = state; + spin_unlock(&(sp_ptr->state_lock)); +} + +/******************************************************************************* + * Wait until the state of a Secure Partition is the specified one and change it + * to the desired state. + ******************************************************************************/ +void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) +{ + int success = 0; + + while (success == 0) { + spin_lock(&(sp_ptr->state_lock)); + + if (sp_ptr->state == from) { + sp_ptr->state = to; + + success = 1; + } + + spin_unlock(&(sp_ptr->state_lock)); + } +} + +/******************************************************************************* + * Check if the state of a Secure Partition is the specified one and, if so, + * change it to the desired state. Returns 0 on success, -1 on error. + ******************************************************************************/ +int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) +{ + int ret = -1; + + spin_lock(&(sp_ptr->state_lock)); + + if (sp_ptr->state == from) { + sp_ptr->state = to; + + ret = 0; + } + + spin_unlock(&(sp_ptr->state_lock)); + + return ret; +} + +/******************************************************************************* + * This function takes an SP context pointer and performs a synchronous entry + * into it. + ******************************************************************************/ +static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx) +{ + uint64_t rc; + + assert(sp_ctx != NULL); + + /* Assign the context of the SP to this CPU */ + cm_set_context(&(sp_ctx->cpu_ctx), SECURE); + + /* Restore the context assigned above */ + cm_el1_sysregs_context_restore(SECURE); + cm_set_next_eret_context(SECURE); + + /* Invalidate TLBs at EL1. */ + tlbivmalle1(); + dsbish(); + + /* Enter Secure Partition */ + rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx); + + /* Save secure state */ + cm_el1_sysregs_context_save(SECURE); + + return rc; +} + +/******************************************************************************* + * This function returns to the place where spm_sp_synchronous_entry() was + * called originally. + ******************************************************************************/ +__dead2 static void spm_sp_synchronous_exit(uint64_t rc) +{ + sp_context_t *ctx = &sp_ctx; + + /* + * The SPM must have initiated the original request through a + * synchronous entry into the secure partition. Jump back to the + * original C runtime context with the value of rc in x0; + */ + spm_secure_partition_exit(ctx->c_rt_ctx, rc); + + panic(); +} + +/******************************************************************************* + * Jump to each Secure Partition for the first time. + ******************************************************************************/ +static int32_t spm_init(void) +{ + uint64_t rc; + sp_context_t *ctx; + + INFO("Secure Partition init...\n"); + + ctx = &sp_ctx; + + ctx->state = SP_STATE_RESET; + + rc = spm_sp_synchronous_entry(ctx); + assert(rc == 0); + + ctx->state = SP_STATE_IDLE; + + INFO("Secure Partition initialized.\n"); + + return rc; +} + +/******************************************************************************* + * Initialize contexts of all Secure Partitions. + ******************************************************************************/ +int32_t spm_setup(void) +{ + sp_context_t *ctx; + + /* Disable MMU at EL1 (initialized by BL2) */ + disable_mmu_icache_el1(); + + /* Initialize context of the SP */ + INFO("Secure Partition context setup start...\n"); + + ctx = &sp_ctx; + + /* Assign translation tables context. */ + ctx->xlat_ctx_handle = spm_get_sp_xlat_context(); + + spm_sp_setup(ctx); + + /* Register init function for deferred init. */ + bl31_register_bl32_init(&spm_init); + + INFO("Secure Partition setup done.\n"); + + return 0; +} + +/******************************************************************************* + * Function to perform a call to a Secure Partition. + ******************************************************************************/ +uint64_t spm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3) +{ + uint64_t rc; + sp_context_t *sp_ptr = &sp_ctx; + + /* Wait until the Secure Partition is idle and set it to busy. */ + sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY); + + /* Set values for registers on SP entry */ + cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx); + + write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid); + write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1); + write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2); + write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3); + + /* Jump to the Secure Partition. */ + rc = spm_sp_synchronous_entry(sp_ptr); + + /* Flag Secure Partition as idle. */ + assert(sp_ptr->state == SP_STATE_BUSY); + sp_state_set(sp_ptr, SP_STATE_IDLE); + + return rc; +} + +/******************************************************************************* + * MM_COMMUNICATE handler + ******************************************************************************/ +static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie, + uint64_t comm_buffer_address, + uint64_t comm_size_address, void *handle) +{ + uint64_t rc; + + /* Cookie. Reserved for future use. It must be zero. */ + if (mm_cookie != 0U) { + ERROR("MM_COMMUNICATE: cookie is not zero\n"); + SMC_RET1(handle, SPM_INVALID_PARAMETER); + } + + if (comm_buffer_address == 0U) { + ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n"); + SMC_RET1(handle, SPM_INVALID_PARAMETER); + } + + if (comm_size_address != 0U) { + VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n"); + } + + /* + * The current secure partition design mandates + * - at any point, only a single core can be + * executing in the secure partiton. + * - a core cannot be preempted by an interrupt + * while executing in secure partition. + * Raise the running priority of the core to the + * interrupt level configured for secure partition + * so as to block any interrupt from preempting this + * core. + */ + ehf_activate_priority(PLAT_SP_PRI); + + /* Save the Normal world context */ + cm_el1_sysregs_context_save(NON_SECURE); + + rc = spm_sp_call(smc_fid, comm_buffer_address, comm_size_address, + plat_my_core_pos()); + + /* Restore non-secure state */ + cm_el1_sysregs_context_restore(NON_SECURE); + cm_set_next_eret_context(NON_SECURE); + + /* + * Exited from secure partition. This core can take + * interrupts now. + */ + ehf_deactivate_priority(PLAT_SP_PRI); + + SMC_RET1(handle, rc); +} + +/******************************************************************************* + * Secure Partition Manager SMC handler. + ******************************************************************************/ +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) +{ + 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. */ + + assert(handle == cm_get_context(SECURE)); + + /* Make next ERET jump to S-EL0 instead of S-EL1. */ + cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1()); + + switch (smc_fid) { + + case SPM_VERSION_AARCH32: + SMC_RET1(handle, SPM_VERSION_COMPILED); + + case SP_EVENT_COMPLETE_AARCH64: + spm_sp_synchronous_exit(x1); + + case SP_MEMORY_ATTRIBUTES_GET_AARCH64: + INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n"); + + if (sp_ctx.state != SP_STATE_RESET) { + WARN("SP_MEMORY_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( + &sp_ctx, x1)); + + case SP_MEMORY_ATTRIBUTES_SET_AARCH64: + INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n"); + + if (sp_ctx.state != SP_STATE_RESET) { + WARN("SP_MEMORY_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( + &sp_ctx, x1, x2, x3)); + default: + break; + } + } else { + + /* Handle SMCs from Non-secure world. */ + + assert(handle == cm_get_context(NON_SECURE)); + + switch (smc_fid) { + + case MM_VERSION_AARCH32: + SMC_RET1(handle, MM_VERSION_COMPILED); + + case MM_COMMUNICATE_AARCH32: + case MM_COMMUNICATE_AARCH64: + return mm_communicate(smc_fid, x1, x2, x3, handle); + + case SP_MEMORY_ATTRIBUTES_GET_AARCH64: + case SP_MEMORY_ATTRIBUTES_SET_AARCH64: + /* SMC interfaces reserved for secure callers. */ + SMC_RET1(handle, SPM_NOT_SUPPORTED); + + default: + break; + } + } + + SMC_RET1(handle, SMC_UNK); +} diff --git a/services/std_svc/spm_deprecated/spm_private.h b/services/std_svc/spm_deprecated/spm_private.h new file mode 100644 index 00000000..ec3f48ea --- /dev/null +++ b/services/std_svc/spm_deprecated/spm_private.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SPM_PRIVATE_H +#define SPM_PRIVATE_H + +#include + +/******************************************************************************* + * 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 +#include +#include + +typedef enum sp_state { + SP_STATE_RESET = 0, + SP_STATE_IDLE, + SP_STATE_BUSY +} sp_state_t; + +typedef struct sp_context { + uint64_t c_rt_ctx; + cpu_context_t cpu_ctx; + xlat_ctx_t *xlat_ctx_handle; + + sp_state_t state; + spinlock_t state_lock; +} sp_context_t; + +/* Assembly helpers */ +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_sp_setup(sp_context_t *sp_ctx); + +xlat_ctx_t *spm_get_sp_xlat_context(void); + +int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx, + uintptr_t base_va); +int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx, + u_register_t page_address, + u_register_t pages_count, + u_register_t smc_attributes); + +#endif /* __ASSEMBLY__ */ + +#endif /* SPM_PRIVATE_H */ diff --git a/services/std_svc/spm_deprecated/spm_shim_private.h b/services/std_svc/spm_deprecated/spm_shim_private.h new file mode 100644 index 00000000..f2a7e052 --- /dev/null +++ b/services/std_svc/spm_deprecated/spm_shim_private.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SPM_SHIM_PRIVATE_H +#define SPM_SHIM_PRIVATE_H + +#include +#include + +/* Assembly source */ +IMPORT_SYM(uintptr_t, spm_shim_exceptions_ptr, SPM_SHIM_EXCEPTIONS_PTR); + +/* Linker symbols */ +IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__, SPM_SHIM_EXCEPTIONS_START); +IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__, SPM_SHIM_EXCEPTIONS_END); + +/* Definitions */ + +#define SPM_SHIM_EXCEPTIONS_SIZE \ + (SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START) + +#endif /* SPM_SHIM_PRIVATE_H */ -- 2.30.2