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