diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h index 2b4a37741..08365796c 100644 --- a/include/services/ffa_svc.h +++ b/include/services/ffa_svc.h @@ -38,6 +38,7 @@ #define FFA_VERSION_MINOR_SHIFT 0 #define FFA_VERSION_MINOR_MASK U(0xFFFF) #define FFA_VERSION_BIT31_MASK U(0x1u << 31) +#define FFA_VERSION_MASK U(0xFFFFFFFF) #define MAKE_FFA_VERSION(major, minor) \ diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h index 0915d0b4c..faa604f53 100644 --- a/services/std_svc/spm/el3_spmc/spmc.h +++ b/services/std_svc/spm/el3_spmc/spmc.h @@ -221,4 +221,10 @@ bool is_ffa_secure_id_valid(uint16_t partition_id); */ struct el3_lp_desc *get_el3_lp_array(void); +/* + * Helper function to obtain the RX/TX buffer pair descriptor of the Hypervisor + * or OS kernel in the normal world or the last SP that was run. + */ +struct mailbox *spmc_get_mbox_desc(bool secure_origin); + #endif /* SPMC_H */ diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index 35def25af..33a25a262 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -72,7 +72,7 @@ struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *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. */ + /* Check for Secure World Partitions. */ for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) { if (sp_desc[i].sp_id == id) { return &(sp_desc[i]); @@ -81,6 +81,29 @@ struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id) return NULL; } +/* + * Helper function to obtain the descriptor of the Hypervisor or OS kernel. + * We assume that the first descriptor is reserved for this entity. + */ +struct ns_endpoint_desc *spmc_get_hyp_ctx(void) +{ + return &(ns_ep_desc[0]); +} + +/* + * Helper function to obtain the RX/TX buffer pair descriptor of the Hypervisor + * or OS kernel in the normal world or the last SP that was run. + */ +struct mailbox *spmc_get_mbox_desc(bool secure_origin) +{ + /* Obtain the RX/TX buffer pair descriptor. */ + if (secure_origin) { + return &(spmc_get_current_sp_ctx()->mailbox); + } else { + return &(spmc_get_hyp_ctx()->mailbox); + } +} + /****************************************************************************** * This function returns to the place where spmc_sp_synchronous_entry() was * called originally. @@ -491,6 +514,59 @@ static uint64_t ffa_error_handler(uint32_t smc_fid, return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); } +static uint64_t ffa_version_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) +{ + uint32_t requested_version = x1 & FFA_VERSION_MASK; + + if (requested_version & FFA_VERSION_BIT31_MASK) { + /* Invalid encoding, return an error. */ + SMC_RET1(handle, FFA_ERROR_NOT_SUPPORTED); + /* Execution stops here. */ + } + + /* Determine the caller to store the requested version. */ + if (secure_origin) { + /* + * Ensure that the SP is reporting the same version as + * specified in its manifest. If these do not match there is + * something wrong with the SP. + * TODO: Should we abort the SP? For now assert this is not + * case. + */ + assert(requested_version == + spmc_get_current_sp_ctx()->ffa_version); + } else { + /* + * If this is called by the normal world, record this + * information in its descriptor. + */ + spmc_get_hyp_ctx()->ffa_version = requested_version; + } + + SMC_RET1(handle, MAKE_FFA_VERSION(FFA_VERSION_MAJOR, + FFA_VERSION_MINOR)); +} + +/******************************************************************************* + * Helper function to obtain the FF-A version of the calling partition. + ******************************************************************************/ +uint32_t get_partition_ffa_version(bool secure_origin) +{ + if (secure_origin) { + return spmc_get_current_sp_ctx()->ffa_version; + } else { + return spmc_get_hyp_ctx()->ffa_version; + } +} + /******************************************************************************* * This function will parse the Secure Partition Manifest. From manifest, it * will fetch details for preparing Secure partition image context and secure @@ -544,6 +620,23 @@ static int sp_manifest_parse(void *sp_manifest, int offset, sp->execution_state = config_32; + ret = fdt_read_uint32(sp_manifest, node, + "messaging-method", &config_32); + if (ret != 0) { + ERROR("Missing Secure Partition messaging method.\n"); + return ret; + } + + /* Validate this entry, we currently only support direct messaging. */ + if ((config_32 & ~(FFA_PARTITION_DIRECT_REQ_RECV | + FFA_PARTITION_DIRECT_REQ_SEND)) != 0U) { + WARN("Invalid Secure Partition messaging method (0x%x)\n", + config_32); + return -EINVAL; + } + + sp->properties = config_32; + ret = fdt_read_uint32(sp_manifest, node, "execution-ctx-count", &config_32); @@ -866,6 +959,10 @@ uint64_t spmc_smc_handler(uint32_t smc_fid, { switch (smc_fid) { + case FFA_VERSION: + return ffa_version_handler(smc_fid, secure_origin, x1, x2, x3, + x4, cookie, handle, flags); + case FFA_MSG_SEND_DIRECT_REQ_SMC32: case FFA_MSG_SEND_DIRECT_REQ_SMC64: return direct_req_smc_handler(smc_fid, secure_origin, x1, x2, diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c index 5b131cd5e..777a96203 100644 --- a/services/std_svc/spmd/spmd_main.c +++ b/services/std_svc/spmd/spmd_main.c @@ -626,7 +626,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, * If caller is secure and SPMC was initialized, * return FFA_VERSION of SPMD. * If caller is non secure and SPMC was initialized, - * return SPMC's version. + * forward to the EL3 SPMC if enabled, otherwise return + * the SPMC version if implemented at a lower EL. * Sanity check to "input_version". * If the EL3 SPMC is enabled, ignore the SPMC state as * this is not used. @@ -635,6 +636,17 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, (!is_spmc_at_el3() && (ctx->state == SPMC_STATE_RESET))) { ret = FFA_ERROR_NOT_SUPPORTED; } else if (!secure_origin) { + if (is_spmc_at_el3()) { + /* + * Forward the call directly to the EL3 SPMC, if + * enabled, as we don't need to wrap the call in + * a direct request. + */ + return spmd_smc_forward(smc_fid, secure_origin, + x1, x2, x3, x4, cookie, + handle, flags); + } + gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); uint64_t rc;