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 <marc.bonnici@arm.com>
Change-Id: I84fee8390023295b9689067e14cd25cba23ca39b
This commit is contained in:
Marc Bonnici 2021-11-29 18:02:45 +00:00
parent 6da76075bf
commit bb01a67306
3 changed files with 102 additions and 20 deletions

View File

@ -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 <stdint.h>
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 */

View File

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

View File

@ -17,6 +17,7 @@
#include <services/rmmd_svc.h>
#include <services/sdei.h>
#include <services/spm_mm_svc.h>
#include <services/spmc_svc.h>
#include <services/spmd_svc.h>
#include <services/std_svc.h>
#include <services/trng_svc.h>
@ -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