From bb01a67306f47271adde051e541c760028c1a0f1 Mon Sep 17 00:00:00 2001 From: Marc Bonnici Date: Mon, 29 Nov 2021 18:02:45 +0000 Subject: [PATCH] feat(spmd): enable handling of FF-A SMCs with the SPMC at EL3 Any FF-A SMC that arrives from the normal world is handled by the SPMD before being forwarded to the SPMC. Similarly any SMC arriving from the secure world will hit the SPMC first and be forwarded to the SPMD if required, otherwise the SPMC will respond directly. This allows for the existing flow of handling FF-A ABI's when the SPMC resides at a lower EL to be preserved. In order to facilitate this flow the spmd_smc_forward function has been split and control is either passed to the SPMC or it is forwarded as before. To allow this the flags and cookie parameters must now also be passed into this method as the SPMC must be able to provide these when calling back into the SPMD handler as appropriate. Signed-off-by: Marc Bonnici Change-Id: I84fee8390023295b9689067e14cd25cba23ca39b --- include/services/spmd_svc.h | 17 ++++- services/std_svc/spmd/spmd_main.c | 100 +++++++++++++++++++++++++----- services/std_svc/std_svc_setup.c | 5 +- 3 files changed, 102 insertions(+), 20 deletions(-) diff --git a/include/services/spmd_svc.h b/include/services/spmd_svc.h index 1e7e6aa87..29dfdad34 100644 --- a/include/services/spmd_svc.h +++ b/include/services/spmd_svc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -12,6 +12,14 @@ #include int spmd_setup(void); +uint64_t spmd_ffa_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); uint64_t spmd_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, @@ -20,6 +28,13 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, void *cookie, void *handle, uint64_t flags); +uint64_t spmd_smc_switch_state(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *handle); #endif /* __ASSEMBLER__ */ #endif /* SPMD_SVC_H */ diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c index 448e12d40..ca441afe7 100644 --- a/services/std_svc/spmd/spmd_main.c +++ b/services/std_svc/spmd/spmd_main.c @@ -90,7 +90,9 @@ static uint64_t spmd_smc_forward(uint32_t smc_fid, uint64_t x2, uint64_t x3, uint64_t x4, - void *handle); + void *cookie, + void *handle, + uint64_t flags); /****************************************************************************** * Builds an SPMD to SPMC direct message request. @@ -434,15 +436,15 @@ int spmd_setup(void) } /******************************************************************************* - * Forward SMC to the other security state + * Forward FF-A SMCs to the other security state. ******************************************************************************/ -static uint64_t spmd_smc_forward(uint32_t smc_fid, - bool secure_origin, - uint64_t x1, - uint64_t x2, - uint64_t x3, - uint64_t x4, - void *handle) +uint64_t spmd_smc_switch_state(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *handle) { unsigned int secure_state_in = (secure_origin) ? SECURE : NON_SECURE; unsigned int secure_state_out = (!secure_origin) ? SECURE : NON_SECURE; @@ -474,6 +476,28 @@ static uint64_t spmd_smc_forward(uint32_t smc_fid, SMC_GET_GP(handle, CTX_GPREG_X7)); } +/******************************************************************************* + * Forward SMCs to the other security state. + ******************************************************************************/ +static uint64_t spmd_smc_forward(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) +{ + if (is_spmc_at_el3() && !secure_origin) { + return spmc_smc_handler(smc_fid, secure_origin, x1, x2, x3, x4, + cookie, handle, flags); + } + return spmd_smc_switch_state(smc_fid, secure_origin, x1, x2, x3, x4, + handle); + +} + /******************************************************************************* * Return FFA_ERROR with specified error code ******************************************************************************/ @@ -501,6 +525,10 @@ bool spmd_check_address_in_binary_image(uint64_t address) *****************************************************************************/ static bool spmd_is_spmc_message(unsigned int ep) { + if (is_spmc_at_el3()) { + return false; + } + return ((ffa_endpoint_destination(ep) == SPMD_DIRECT_MSG_ENDPOINT_ID) && (ffa_endpoint_source(ep) == spmc_attrs.spmc_id)); } @@ -518,6 +546,35 @@ static int spmd_handle_spmc_message(unsigned long long msg, return -EINVAL; } +/******************************************************************************* + * This function forwards FF-A SMCs to either the main SPMD handler or the + * SPMC at EL3, depending on the origin security state, if enabled. + ******************************************************************************/ +uint64_t spmd_ffa_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) +{ + if (is_spmc_at_el3()) { + /* + * If we have an SPMC at EL3 allow handling of the SMC first. + * The SPMC will call back through to SPMD handler if required. + */ + if (is_caller_secure(flags)) { + return spmc_smc_handler(smc_fid, + is_caller_secure(flags), + x1, x2, x3, x4, cookie, + handle, flags); + } + } + return spmd_smc_handler(smc_fid, x1, x2, x3, x4, cookie, + handle, flags); +} + /******************************************************************************* * This function handles all SMCs in the range reserved for FFA. Each call is * either forwarded to the other security state or handled by the SPM dispatcher @@ -559,7 +616,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, } return spmd_smc_forward(smc_fid, secure_origin, - x1, x2, x3, x4, handle); + x1, x2, x3, x4, cookie, + handle, flags); break; /* not reached */ case FFA_VERSION: @@ -570,9 +628,11 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, * If caller is non secure and SPMC was initialized, * return SPMC's version. * Sanity check to "input_version". + * If the EL3 SPMC is enabled, ignore the SPMC state as + * this is not used. */ if ((input_version & FFA_VERSION_BIT31_MASK) || - (ctx->state == SPMC_STATE_RESET)) { + (!is_spmc_at_el3() && (ctx->state == SPMC_STATE_RESET))) { ret = FFA_ERROR_NOT_SUPPORTED; } else if (!secure_origin) { gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); @@ -627,7 +687,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, */ return spmd_smc_forward(ret, true, FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ, - FFA_PARAM_MBZ, gpregs); + FFA_PARAM_MBZ, cookie, gpregs, + flags); } else { ret = MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR); @@ -647,7 +708,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, /* Forward SMC from Normal world to the SPM Core */ if (!secure_origin) { return spmd_smc_forward(smc_fid, secure_origin, - x1, x2, x3, x4, handle); + x1, x2, x3, x4, cookie, + handle, flags); } /* @@ -743,7 +805,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, } else { /* Forward direct message to the other world */ return spmd_smc_forward(smc_fid, secure_origin, - x1, x2, x3, x4, handle); + x1, x2, x3, x4, cookie, + handle, flags); } break; /* Not reached */ @@ -753,7 +816,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, } else { /* Forward direct message to the other world */ return spmd_smc_forward(smc_fid, secure_origin, - x1, x2, x3, x4, handle); + x1, x2, x3, x4, cookie, + handle, flags); } break; /* Not reached */ @@ -808,7 +872,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, */ return spmd_smc_forward(smc_fid, secure_origin, - x1, x2, x3, x4, handle); + x1, x2, x3, x4, cookie, + handle, flags); break; /* not reached */ case FFA_MSG_WAIT: @@ -831,7 +896,8 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, } return spmd_smc_forward(smc_fid, secure_origin, - x1, x2, x3, x4, handle); + x1, x2, x3, x4, cookie, + handle, flags); break; /* not reached */ case FFA_NORMAL_WORLD_RESUME: diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c index bfe26cab1..b1e3db977 100644 --- a/services/std_svc/std_svc_setup.c +++ b/services/std_svc/std_svc_setup.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -147,8 +148,8 @@ static uintptr_t std_svc_smc_handler(uint32_t smc_fid, * dispatcher and return its return value */ if (is_ffa_fid(smc_fid)) { - return spmd_smc_handler(smc_fid, x1, x2, x3, x4, cookie, - handle, flags); + return spmd_ffa_smc_handler(smc_fid, x1, x2, x3, x4, cookie, + handle, flags); } #endif