From 5096aeb2ba646548a7a6ab59e975b996e6c9026a Mon Sep 17 00:00:00 2001 From: Marc Bonnici Date: Wed, 1 Dec 2021 17:57:04 +0000 Subject: [PATCH] feat(spmc): add FF-A secure partition manager core This patch introduces the core support for enabling an SPMC in EL3 as per the FF-A spec. The current implemented functionality is targeted to enable initialization of the SPMC itself and initial support for bringing up a single S-EL1 SP. This includes initialization of the SPMC's internal state, parsing of an SP's manifest, preparing the cpu contexts and appropriate system registers for the Secure Partition. The spmc_smc_handler is the main handler for all incoming SMCs to the SPMC, FF-A ABI handlers and functionality will be implemented in subsequent patches. Signed-off-by: Marc Bonnici Change-Id: Ib33c240b91e54cbd018a69fec880d02adfbe12b9 --- include/services/ffa_svc.h | 33 +- include/services/spmc_svc.h | 38 ++ services/std_svc/spm/el3_spmc/spmc.h | 185 +++++++++ services/std_svc/spm/el3_spmc/spmc.mk | 17 + services/std_svc/spm/el3_spmc/spmc_main.c | 438 +++++++++++++++++++++ services/std_svc/spm/el3_spmc/spmc_setup.c | 112 ++++++ services/std_svc/spmd/spmd_private.h | 6 - 7 files changed, 822 insertions(+), 7 deletions(-) create mode 100644 include/services/spmc_svc.h create mode 100644 services/std_svc/spm/el3_spmc/spmc.h create mode 100644 services/std_svc/spm/el3_spmc/spmc.mk create mode 100644 services/std_svc/spm/el3_spmc/spmc_main.c create mode 100644 services/std_svc/spm/el3_spmc/spmc_setup.c diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h index 9a7c48989..ff1e04a91 100644 --- a/include/services/ffa_svc.h +++ b/include/services/ffa_svc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2021, Arm Limited. All rights reserved. + * Copyright (c) 2020-2022, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,6 +7,8 @@ #ifndef FFA_SVC_H #define FFA_SVC_H +#include + #include #include #include @@ -175,6 +177,15 @@ */ #define FFA_ENDPOINT_ID_MAX U(1 << 16) +/* + * Reserve endpoint id for the SPMD. + */ +#define SPMD_DIRECT_MSG_ENDPOINT_ID U(FFA_ENDPOINT_ID_MAX - 1) + +/* Mask and shift to check valid secure FF-A Endpoint ID. */ +#define SPMC_SECURE_ID_MASK U(1) +#define SPMC_SECURE_ID_SHIFT U(15) + /* * Mask for source and destination endpoint id in * a direct message request/response. @@ -209,4 +220,24 @@ static inline uint16_t ffa_endpoint_source(unsigned int ep) FFA_DIRECT_MSG_ENDPOINT_ID_MASK; } +/****************************************************************************** + * FF-A helper functions to determine partition ID world. + *****************************************************************************/ + +/* + * Determine if provided ID is in the secure world. + */ +static inline bool ffa_is_secure_world_id(uint16_t id) +{ + return ((id >> SPMC_SECURE_ID_SHIFT) & SPMC_SECURE_ID_MASK) == 1; +} + +/* + * Determine if provided ID is in the normal world. + */ +static inline bool ffa_is_normal_world_id(uint16_t id) +{ + return !ffa_is_secure_world_id(id); +} + #endif /* FFA_SVC_H */ diff --git a/include/services/spmc_svc.h b/include/services/spmc_svc.h new file mode 100644 index 000000000..9dbe04589 --- /dev/null +++ b/include/services/spmc_svc.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SPMC_SVC_H +#define SPMC_SVC_H + +#ifndef __ASSEMBLER__ +#include + +#include +#include + +int spmc_setup(void); +void *spmc_get_config_addr(void); + +void spmc_set_config_addr(uintptr_t soc_fw_config); + +uint64_t spmc_smc_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags); + +static inline bool is_spmc_at_el3(void) +{ + return SPMC_AT_EL3 == 1; +} + +#endif /* __ASSEMBLER__ */ + +#endif /* SPMC_SVC_H */ diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h new file mode 100644 index 000000000..e89151673 --- /dev/null +++ b/services/std_svc/spm/el3_spmc/spmc.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SPMC_H +#define SPMC_H + +#include + +#include +#include +#include "spm_common.h" + +/* + * Ranges of FF-A IDs for Normal world and Secure world components. The + * convention matches that used by other SPMCs i.e. Hafnium and OP-TEE. + */ +#define FFA_NWD_ID_BASE 0x0 +#define FFA_NWD_ID_LIMIT 0x7FFF +#define FFA_SWD_ID_BASE 0x8000 +#define FFA_SWD_ID_LIMIT SPMD_DIRECT_MSG_ENDPOINT_ID - 1 +#define FFA_SWD_ID_MASK 0x8000 + +/* First ID is reserved for the SPMC */ +#define FFA_SPMC_ID U(FFA_SWD_ID_BASE) +/* SP IDs are allocated after the SPMC ID */ +#define FFA_SP_ID_BASE (FFA_SPMC_ID + 1) +/* Align with Hafnium implementation */ +#define INV_SP_ID 0x7FFF + +/* FF-A warm boot types. */ +#define FFA_WB_TYPE_S2RAM 0 +#define FFA_WB_TYPE_NOTS2RAM 1 + +/* + * Runtime states of an execution context as per the FF-A v1.1 specification. + */ +enum sp_runtime_states { + RT_STATE_WAITING, + RT_STATE_RUNNING, + RT_STATE_PREEMPTED, + RT_STATE_BLOCKED +}; + +/* + * Runtime model of an execution context as per the FF-A v1.1 specification. Its + * value is valid only if the execution context is not in the waiting state. + */ +enum sp_runtime_model { + RT_MODEL_DIR_REQ, + RT_MODEL_RUN, + RT_MODEL_INIT, + RT_MODEL_INTR +}; + +enum sp_runtime_el { + EL1 = 0, + S_EL0, + S_EL1 +}; + +enum sp_execution_state { + SP_STATE_AARCH64 = 0, + SP_STATE_AARCH32 +}; + +/* + * Execution context members for an SP. This is a bit like struct + * vcpu in a hypervisor. + */ +struct sp_exec_ctx { + /* + * Store the stack address to restore C runtime context from after + * returning from a synchronous entry into the SP. + */ + uint64_t c_rt_ctx; + + /* Space to maintain the architectural state of an SP. */ + cpu_context_t cpu_ctx; + + /* Track the current runtime state of the SP. */ + enum sp_runtime_states rt_state; + + /* Track the current runtime model of the SP. */ + enum sp_runtime_model rt_model; +}; + +/* + * Structure to describe the cumulative properties of an SP. + */ +struct secure_partition_desc { + /* + * Execution contexts allocated to this endpoint. Ideally, + * we need as many contexts as there are physical cpus only + * for a S-EL1 SP which is MP-pinned. + */ + struct sp_exec_ctx ec[PLATFORM_CORE_COUNT]; + + /* ID of the Secure Partition. */ + uint16_t sp_id; + + /* Runtime EL. */ + enum sp_runtime_el runtime_el; + + /* Partition UUID. */ + uint32_t uuid[4]; + + /* Partition Properties. */ + uint32_t properties; + + /* Supported FF-A Version. */ + uint32_t ffa_version; + + /* Execution State. */ + enum sp_execution_state execution_state; + + /* Secondary entrypoint. Only valid for a S-EL1 SP. */ + uintptr_t secondary_ep; +}; + +/* + * This define identifies the only SP that will be initialised and participate + * in FF-A communication. The implementation leaves the door open for more SPs + * to be managed in future but for now it is reasonable to assume that either a + * single S-EL0 or a single S-EL1 SP will be supported. This define will be used + * to identify which SP descriptor to initialise and manage during SP runtime. + */ +#define ACTIVE_SP_DESC_INDEX 0 + +/* + * Structure to describe the cumulative properties of the Hypervisor and + * NS-Endpoints. + */ +struct ns_endpoint_desc { + /* + * ID of the NS-Endpoint or Hypervisor. + */ + uint16_t ns_ep_id; + + /* + * Supported FF-A Version. + */ + uint32_t ffa_version; +}; + +/* Setup Function for different SP types. */ +void spmc_sp_common_setup(struct secure_partition_desc *sp, + entry_point_info_t *ep_info); +void spmc_el1_sp_setup(struct secure_partition_desc *sp, + entry_point_info_t *ep_info); +void spmc_sp_common_ep_commit(struct secure_partition_desc *sp, + entry_point_info_t *ep_info); + +/* + * Helper function to perform a synchronous entry into a SP. + */ +uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec); + +/* + * Helper function to obtain the descriptor of the current SP on a physical cpu. + */ +struct secure_partition_desc *spmc_get_current_sp_ctx(void); + +/* + * Helper function to obtain the execution context of an SP on a + * physical cpu. + */ +struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp); + +/* + * Helper function to obtain the index of the execution context of an SP on a + * physical cpu. + */ +unsigned int get_ec_index(struct secure_partition_desc *sp); + +uint64_t spmc_ffa_error_return(void *handle, int error_code); + +/* + * Ensure a partition ID does not clash and follows the secure world convention. + */ +bool is_ffa_secure_id_valid(uint16_t partition_id); + +#endif /* SPMC_H */ diff --git a/services/std_svc/spm/el3_spmc/spmc.mk b/services/std_svc/spm/el3_spmc/spmc.mk new file mode 100644 index 000000000..2b154dd7d --- /dev/null +++ b/services/std_svc/spm/el3_spmc/spmc.mk @@ -0,0 +1,17 @@ +# +# Copyright (c) 2022, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ifneq (${ARCH},aarch64) + $(error "Error: SPMC is only supported on aarch64.") +endif + +SPMC_SOURCES := $(addprefix services/std_svc/spm/el3_spmc/, \ + spmc_main.c \ + spmc_setup.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/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c new file mode 100644 index 000000000..80d7a4c72 --- /dev/null +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2022, 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 "spmc.h" + +#include + +/* + * Allocate a secure partition descriptor to describe each SP in the system that + * does not reside at EL3. + */ +static struct secure_partition_desc sp_desc[SECURE_PARTITION_COUNT]; + +/* + * Allocate an NS endpoint descriptor to describe each VM and the Hypervisor in + * the system that interacts with a SP. It is used to track the Hypervisor + * buffer pair, version and ID for now. It could be extended to track VM + * properties when the SPMC supports indirect messaging. + */ +static struct ns_endpoint_desc ns_ep_desc[NS_PARTITION_COUNT]; + +/* + * Helper function to obtain the descriptor of the last SP to whom control was + * handed to on this physical cpu. Currently, we assume there is only one SP. + * TODO: Expand to track multiple partitions when required. + */ +struct secure_partition_desc *spmc_get_current_sp_ctx(void) +{ + return &(sp_desc[ACTIVE_SP_DESC_INDEX]); +} + +/* + * Helper function to obtain the execution context of an SP on the + * current physical cpu. + */ +struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp) +{ + return &(sp->ec[get_ec_index(sp)]); +} + +/* Helper function to get pointer to SP context from its ID. */ +struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id) +{ + /* Check for SWd Partitions. */ + for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) { + if (sp_desc[i].sp_id == id) { + return &(sp_desc[i]); + } + } + return NULL; +} + +/****************************************************************************** + * This function returns to the place where spmc_sp_synchronous_entry() was + * called originally. + ******************************************************************************/ +__dead2 void spmc_sp_synchronous_exit(struct sp_exec_ctx *ec, uint64_t rc) +{ + /* + * 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(ec->c_rt_ctx, rc); + + panic(); +} + +/******************************************************************************* + * Return FFA_ERROR with specified error code. + ******************************************************************************/ +uint64_t spmc_ffa_error_return(void *handle, int error_code) +{ + SMC_RET8(handle, FFA_ERROR, + FFA_TARGET_INFO_MBZ, error_code, + FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, + FFA_PARAM_MBZ, FFA_PARAM_MBZ); +} + +/****************************************************************************** + * Helper function to validate a secure partition ID to ensure it does not + * conflict with any other FF-A component and follows the convention to + * indicate it resides within the secure world. + ******************************************************************************/ +bool is_ffa_secure_id_valid(uint16_t partition_id) +{ + /* Ensure the ID is not the invalid partition ID. */ + if (partition_id == INV_SP_ID) { + return false; + } + + /* Ensure the ID is not the SPMD ID. */ + if (partition_id == SPMD_DIRECT_MSG_ENDPOINT_ID) { + return false; + } + + /* + * Ensure the ID follows the convention to indicate it resides + * in the secure world. + */ + if (!ffa_is_secure_world_id(partition_id)) { + return false; + } + + /* Ensure we don't conflict with the SPMC partition ID. */ + if (partition_id == FFA_SPMC_ID) { + return false; + } + + /* Ensure we do not already have an SP context with this ID. */ + if (spmc_get_sp_ctx(partition_id)) { + return false; + } + + return true; +} + +/******************************************************************************* + * This function will parse the Secure Partition Manifest. From manifest, it + * will fetch details for preparing Secure partition image context and secure + * partition image boot arguments if any. + ******************************************************************************/ +static int sp_manifest_parse(void *sp_manifest, int offset, + struct secure_partition_desc *sp, + entry_point_info_t *ep_info) +{ + int32_t ret, node; + uint32_t config_32; + + /* + * Look for the mandatory fields that are expected to be present in + * the SP manifests. + */ + node = fdt_path_offset(sp_manifest, "/"); + if (node < 0) { + ERROR("Did not find root node.\n"); + return node; + } + + ret = fdt_read_uint32(sp_manifest, node, "exception-level", &config_32); + if (ret != 0) { + ERROR("Missing SP Exception Level information.\n"); + return ret; + } + + sp->runtime_el = config_32; + + ret = fdt_read_uint32(sp_manifest, node, "ffa-version", &config_32); + if (ret != 0) { + ERROR("Missing Secure Partition FF-A Version.\n"); + return ret; + } + + sp->ffa_version = config_32; + + ret = fdt_read_uint32(sp_manifest, node, "execution-state", &config_32); + if (ret != 0) { + ERROR("Missing Secure Partition Execution State.\n"); + return ret; + } + + sp->execution_state = config_32; + + /* + * Look for the optional fields that are expected to be present in + * an SP manifest. + */ + ret = fdt_read_uint32(sp_manifest, node, "id", &config_32); + if (ret != 0) { + WARN("Missing Secure Partition ID.\n"); + } else { + if (!is_ffa_secure_id_valid(config_32)) { + ERROR("Invalid Secure Partition ID (0x%x).\n", + config_32); + return -EINVAL; + } + sp->sp_id = config_32; + } + + return 0; +} + +/******************************************************************************* + * This function gets the Secure Partition Manifest base and maps the manifest + * region. + * Currently only one Secure Partition manifest is considered which is used to + * prepare the context for the single Secure Partition. + ******************************************************************************/ +static int find_and_prepare_sp_context(void) +{ + void *sp_manifest; + uintptr_t manifest_base; + uintptr_t manifest_base_align; + entry_point_info_t *next_image_ep_info; + int32_t ret; + struct secure_partition_desc *sp; + + next_image_ep_info = bl31_plat_get_next_image_ep_info(SECURE); + if (next_image_ep_info == NULL) { + WARN("No Secure Partition image provided by BL2.\n"); + return -ENOENT; + } + + sp_manifest = (void *)next_image_ep_info->args.arg0; + if (sp_manifest == NULL) { + WARN("Secure Partition manifest absent.\n"); + return -ENOENT; + } + + manifest_base = (uintptr_t)sp_manifest; + manifest_base_align = page_align(manifest_base, DOWN); + + /* + * Map the secure partition manifest region in the EL3 translation + * regime. + * Map an area equal to (2 * PAGE_SIZE) for now. During manifest base + * alignment the region of 1 PAGE_SIZE from manifest align base may + * not completely accommodate the secure partition manifest region. + */ + ret = mmap_add_dynamic_region((unsigned long long)manifest_base_align, + manifest_base_align, + PAGE_SIZE * 2, + MT_RO_DATA); + if (ret != 0) { + ERROR("Error while mapping SP manifest (%d).\n", ret); + return ret; + } + + ret = fdt_node_offset_by_compatible(sp_manifest, -1, + "arm,ffa-manifest-1.0"); + if (ret < 0) { + ERROR("Error happened in SP manifest reading.\n"); + return -EINVAL; + } + + /* + * Store the size of the manifest so that it can be used later to pass + * the manifest as boot information later. + */ + next_image_ep_info->args.arg1 = fdt_totalsize(sp_manifest); + INFO("Manifest size = %lu bytes.\n", next_image_ep_info->args.arg1); + + /* + * Select an SP descriptor for initialising the partition's execution + * context on the primary CPU. + */ + sp = spmc_get_current_sp_ctx(); + + /* Initialize entry point information for the SP */ + SET_PARAM_HEAD(next_image_ep_info, PARAM_EP, VERSION_1, + SECURE | EP_ST_ENABLE); + + /* Parse the SP manifest. */ + ret = sp_manifest_parse(sp_manifest, ret, sp, next_image_ep_info); + if (ret != 0) { + ERROR("Error in Secure Partition manifest parsing.\n"); + return ret; + } + + /* Check that the runtime EL in the manifest was correct. */ + if (sp->runtime_el != S_EL1) { + ERROR("Unexpected runtime EL: %d\n", sp->runtime_el); + return -EINVAL; + } + + /* Perform any common initialisation. */ + spmc_sp_common_setup(sp, next_image_ep_info); + + /* Perform any initialisation specific to S-EL1 SPs. */ + spmc_el1_sp_setup(sp, next_image_ep_info); + + /* Initialize the SP context with the required ep info. */ + spmc_sp_common_ep_commit(sp, next_image_ep_info); + + return 0; +} + +/******************************************************************************* + * This function takes an SP context pointer and performs a synchronous entry + * into it. + ******************************************************************************/ +uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec) +{ + uint64_t rc; + + assert(ec != NULL); + + /* Assign the context of the SP to this CPU */ + cm_set_context(&(ec->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(&ec->c_rt_ctx); + + /* Save secure state */ + cm_el1_sysregs_context_save(SECURE); + + return rc; +} + +/******************************************************************************* + * SPMC Helper Functions. + ******************************************************************************/ +static int32_t sp_init(void) +{ + uint64_t rc; + struct secure_partition_desc *sp; + struct sp_exec_ctx *ec; + + sp = spmc_get_current_sp_ctx(); + ec = spmc_get_sp_ec(sp); + ec->rt_model = RT_MODEL_INIT; + ec->rt_state = RT_STATE_RUNNING; + + INFO("Secure Partition (0x%x) init start.\n", sp->sp_id); + + rc = spmc_sp_synchronous_entry(ec); + if (rc != 0) { + /* Indicate SP init was not successful. */ + ERROR("SP (0x%x) failed to initialize (%lu).\n", + sp->sp_id, rc); + return 0; + } + + ec->rt_state = RT_STATE_WAITING; + INFO("Secure Partition initialized.\n"); + + return 1; +} + +static void initalize_sp_descs(void) +{ + struct secure_partition_desc *sp; + + for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) { + sp = &sp_desc[i]; + sp->sp_id = INV_SP_ID; + sp->secondary_ep = 0; + } +} + +static void initalize_ns_ep_descs(void) +{ + struct ns_endpoint_desc *ns_ep; + + for (unsigned int i = 0U; i < NS_PARTITION_COUNT; i++) { + ns_ep = &ns_ep_desc[i]; + /* + * Clashes with the Hypervisor ID but will not be a + * problem in practice. + */ + ns_ep->ns_ep_id = 0; + ns_ep->ffa_version = 0; + } +} + +/******************************************************************************* + * Initialize contexts of all Secure Partitions. + ******************************************************************************/ +int32_t spmc_setup(void) +{ + int32_t ret; + + /* Initialize endpoint descriptors */ + initalize_sp_descs(); + initalize_ns_ep_descs(); + + /* Perform physical SP setup. */ + + /* Disable MMU at EL1 (initialized by BL2) */ + disable_mmu_icache_el1(); + + /* Initialize context of the SP */ + INFO("Secure Partition context setup start.\n"); + + ret = find_and_prepare_sp_context(); + if (ret != 0) { + ERROR("Error in SP finding and context preparation.\n"); + return ret; + } + + /* Register init function for deferred init. */ + bl31_register_bl32_init(&sp_init); + + INFO("Secure Partition setup done.\n"); + + return 0; +} + +/******************************************************************************* + * Secure Partition Manager SMC handler. + ******************************************************************************/ +uint64_t spmc_smc_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + switch (smc_fid) { + + default: + WARN("Unsupported FF-A call 0x%08x.\n", smc_fid); + break; + } + return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); +} diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c new file mode 100644 index 000000000..7b23c9e3b --- /dev/null +++ b/services/std_svc/spm/el3_spmc/spmc_setup.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2022, 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_common.h" +#include "spmc.h" + +#include + +/* + * We are assuming that the index of the execution + * context used is the linear index of the current physical cpu. + */ +unsigned int get_ec_index(struct secure_partition_desc *sp) +{ + return plat_my_core_pos(); +} + +/* S-EL1 partition specific initialisation. */ +void spmc_el1_sp_setup(struct secure_partition_desc *sp, + entry_point_info_t *ep_info) +{ + /* Sanity check input arguments. */ + assert(sp != NULL); + assert(ep_info != NULL); + + /* Initialise the SPSR for S-EL1 SPs. */ + ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + + /* + * Check whether setup is being performed for the primary or a secondary + * execution context. In the latter case, indicate to the SP that this + * is a warm boot. + * TODO: This check would need to be reworked if the same entry point is + * used for both primary and secondary initialisation. + */ + if (sp->secondary_ep != 0U) { + /* + * Sanity check that the secondary entry point is still what was + * originally set. + */ + assert(sp->secondary_ep == ep_info->pc); + ep_info->args.arg0 = FFA_WB_TYPE_S2RAM; + } +} + +/* Common initialisation for all SPs. */ +void spmc_sp_common_setup(struct secure_partition_desc *sp, + entry_point_info_t *ep_info) +{ + uint16_t sp_id; + + /* Assign FF-A Partition ID if not already assigned. */ + if (sp->sp_id == INV_SP_ID) { + sp_id = FFA_SP_ID_BASE + ACTIVE_SP_DESC_INDEX; + /* + * Ensure we don't clash with previously assigned partition + * IDs. + */ + while (!is_ffa_secure_id_valid(sp_id)) { + sp_id++; + + if (sp_id == FFA_SWD_ID_LIMIT) { + ERROR("Unable to determine valid SP ID.\n"); + panic(); + } + } + sp->sp_id = sp_id; + } + + /* + * We currently only support S-EL1 partitions so ensure this is the + * case. + */ + assert(sp->runtime_el == S_EL1); + + /* + * Clear the general purpose registers. These should be populated as + * required. + */ + zeromem(&ep_info->args, sizeof(ep_info->args)); +} + +/* + * Initialise the SP context now we have populated the common and EL specific + * entrypoint information. + */ +void spmc_sp_common_ep_commit(struct secure_partition_desc *sp, + entry_point_info_t *ep_info) +{ + cpu_context_t *cpu_ctx; + + cpu_ctx = &(spmc_get_sp_ec(sp)->cpu_ctx); + print_entry_point_info(ep_info); + cm_setup_context(cpu_ctx, ep_info); +} diff --git a/services/std_svc/spmd/spmd_private.h b/services/std_svc/spmd/spmd_private.h index 4cd6a744b..4c298c9e8 100644 --- a/services/std_svc/spmd/spmd_private.h +++ b/services/std_svc/spmd/spmd_private.h @@ -58,12 +58,6 @@ typedef struct spmd_spm_core_context { */ #define FFA_NS_ENDPOINT_ID U(0) -/* Mask and shift to check valid secure FF-A Endpoint ID. */ -#define SPMC_SECURE_ID_MASK U(1) -#define SPMC_SECURE_ID_SHIFT U(15) - -#define SPMD_DIRECT_MSG_ENDPOINT_ID U(FFA_ENDPOINT_ID_MAX - 1) - /* Define SPMD target function IDs for framework messages to the SPMC */ #define SPMD_FWK_MSG_BIT BIT(31) #define SPMD_FWK_MSG_PSCI U(0)