fix(trp): preserve RMI SMC X4 when not used as return

This patch adds X2-X6 and 'smc_ret' parameters to trp_rmi_handler().
The last 'smc_ret' parameter passed in X7 contains address of
'trp_smc_result' structure on stack to return result of RMI SMC call.

This allows to preserve X4 if not used as a return argument as per
SMCCCv1.2. The patch also removes use of trp_args_t in RMI handling.

Signed-off-by: AlexeiFedorov <Alexei.Fedorov@arm.com>
Change-Id: I9e3387a7380b37863eeccc53d13e92e0ac5cffbd
This commit is contained in:
AlexeiFedorov 2022-11-24 13:42:44 +00:00 committed by Soby Mathew
parent 0125e86b3b
commit b96253db08
3 changed files with 73 additions and 34 deletions

View file

@ -39,5 +39,12 @@ trp_args_t *set_smc_args(uint64_t arg0,
__dead2 void trp_boot_abort(uint64_t err);
/* TRP SMC result registers X0-X4 */
#define TRP_SMC_RESULT_REGS 5
struct trp_smc_result {
unsigned long long x[TRP_SMC_RESULT_REGS];
};
#endif /* __ASSEMBLER __ */
#endif /* TRP_HELPERS_H */

View file

@ -115,7 +115,29 @@ endfunc trp_smc
* ---------------------------------------------
*/
func trp_handler
/*
* Save Link Register and X4, as per SMCCC v1.2 its value
* must be preserved unless it contains result, as specified
* in the function definition.
*/
stp x4, lr, [sp, #-16]!
/*
* Zero the space for X0-X3 in trp_smc_result structure
* and pass its address as the last argument.
*/
stp xzr, xzr, [sp, #-16]!
stp xzr, xzr, [sp, #-16]!
mov x7, sp
bl trp_rmi_handler
restore_args_call_smc
ldp x1, x2, [sp], #16
ldp x3, x4, [sp], #16
ldp x5, lr, [sp], #16
ldr x0, =RMM_RMI_REQ_COMPLETE
smc #0
b trp_handler
endfunc trp_handler

View file

@ -4,7 +4,6 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <plat/common/platform.h>
#include <services/rmm_core_manifest.h>
@ -31,11 +30,11 @@ void trp_setup(uint64_t x0,
uint64_t x3)
{
/*
* Validate boot parameters.
* Validate boot parameters
*
* According to the Boot Interface ABI v.0.1, the
* parameters recived from EL3 are:
* x0: CPUID (verified earlier so not used)
* According to the Boot Interface ABI v.0.1,
* the parameters received from EL3 are:
* x0: CPUID (verified earlier, so not used)
* x1: Boot Interface version
* x2: PLATFORM_CORE_COUNT
* x3: Pointer to the shared memory area.
@ -73,14 +72,14 @@ void trp_main(void)
NOTICE("TRP: %s\n", build_message);
NOTICE("TRP: Supported RMM-EL3 Interface ABI: v.%u.%u\n",
TRP_RMM_EL3_ABI_VERS_MAJOR, TRP_RMM_EL3_ABI_VERS_MINOR);
NOTICE("TRP: Boot Manifest Version : v.%u.%u\n",
NOTICE("TRP: Boot Manifest Version: v.%u.%u\n",
RMMD_GET_MANIFEST_VERSION_MAJOR(trp_boot_manifest_version),
RMMD_GET_MANIFEST_VERSION_MINOR(trp_boot_manifest_version));
INFO("TRP: Memory base : 0x%lx\n", (unsigned long)RMM_BASE);
INFO("TRP: Base address for the shared region : 0x%lx\n",
INFO("TRP: Memory base: 0x%lx\n", (unsigned long)RMM_BASE);
INFO("TRP: Shared region base address: 0x%lx\n",
(unsigned long)trp_shared_region_start);
INFO("TRP: Total size : 0x%lx bytes\n", (unsigned long)(RMM_END
- RMM_BASE));
INFO("TRP: Total size: 0x%lx bytes\n",
(unsigned long)(RMM_END - RMM_BASE));
INFO("TRP: RMM-EL3 Interface ABI reported by EL3: v.%u.%u\n",
TRP_RMM_EL3_VERSION_GET_MAJOR(trp_boot_abi_version),
TRP_RMM_EL3_VERSION_GET_MINOR(trp_boot_abi_version));
@ -89,62 +88,73 @@ void trp_main(void)
/*******************************************************************************
* Returning RMI version back to Normal World
******************************************************************************/
static trp_args_t *trp_ret_rmi_version(void)
static void trp_ret_rmi_version(struct trp_smc_result *smc_ret)
{
VERBOSE("RMM version is %u.%u\n", RMI_ABI_VERSION_MAJOR,
RMI_ABI_VERSION_MINOR);
return set_smc_args(RMM_RMI_REQ_COMPLETE, RMI_ABI_VERSION,
0, 0, 0, 0, 0, 0);
smc_ret->x[0] = RMI_ABI_VERSION;
}
/*******************************************************************************
* Transitioning granule of NON-SECURE type to REALM type
******************************************************************************/
static trp_args_t *trp_asc_mark_realm(unsigned long long x1)
static void trp_asc_mark_realm(unsigned long long x1,
struct trp_smc_result *smc_ret)
{
unsigned long long ret;
VERBOSE("Delegating granule 0x%llx\n", x1);
ret = trp_smc(set_smc_args(RMM_GTSI_DELEGATE, x1, 0, 0, 0, 0, 0, 0));
smc_ret->x[0] = trp_smc(set_smc_args(RMM_GTSI_DELEGATE, x1,
0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
if (ret != 0ULL) {
if (smc_ret->x[0] != 0ULL) {
ERROR("Granule transition from NON-SECURE type to REALM type "
"failed 0x%llx\n", ret);
"failed 0x%llx\n", smc_ret->x[0]);
}
return set_smc_args(RMM_RMI_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0);
}
/*******************************************************************************
* Transitioning granule of REALM type to NON-SECURE type
******************************************************************************/
static trp_args_t *trp_asc_mark_nonsecure(unsigned long long x1)
static void trp_asc_mark_nonsecure(unsigned long long x1,
struct trp_smc_result *smc_ret)
{
unsigned long long ret;
VERBOSE("Undelegating granule 0x%llx\n", x1);
ret = trp_smc(set_smc_args(RMM_GTSI_UNDELEGATE, x1, 0, 0, 0, 0, 0, 0));
smc_ret->x[0] = trp_smc(set_smc_args(RMM_GTSI_UNDELEGATE, x1,
0UL, 0UL, 0UL, 0UL, 0UL, 0UL));
if (ret != 0ULL) {
if (smc_ret->x[0] != 0ULL) {
ERROR("Granule transition from REALM type to NON-SECURE type "
"failed 0x%llx\n", ret);
"failed 0x%llx\n", smc_ret->x[0]);
}
return set_smc_args(RMM_RMI_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0);
}
/*******************************************************************************
* Main RMI SMC handler function
******************************************************************************/
trp_args_t *trp_rmi_handler(unsigned long fid, unsigned long long x1)
void trp_rmi_handler(unsigned long fid,
unsigned long long x1, unsigned long long x2,
unsigned long long x3, unsigned long long x4,
unsigned long long x5, unsigned long long x6,
struct trp_smc_result *smc_ret)
{
/* Not used in the current implementation */
(void)x2;
(void)x3;
(void)x4;
(void)x5;
(void)x6;
switch (fid) {
case RMI_RMM_REQ_VERSION:
return trp_ret_rmi_version();
trp_ret_rmi_version(smc_ret);
break;
case RMI_RMM_GRANULE_DELEGATE:
return trp_asc_mark_realm(x1);
trp_asc_mark_realm(x1, smc_ret);
break;
case RMI_RMM_GRANULE_UNDELEGATE:
return trp_asc_mark_nonsecure(x1);
trp_asc_mark_nonsecure(x1, smc_ret);
break;
default:
ERROR("Invalid SMC code to %s, FID %lu\n", __func__, fid);
ERROR("Invalid SMC code to %s, FID %lx\n", __func__, fid);
smc_ret->x[0] = SMC_UNK;
}
return set_smc_args(SMC_UNK, 0, 0, 0, 0, 0, 0, 0);
}