blob: 901b4481211bfce99f1c59eb5c2b2e46f165c49d [file] [log] [blame]
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <psci.h>
#include <smccc.h>
#include <std_svc.h>
#include <string.h>
#include <tftf_lib.h>
#include <tsp.h>
#include <utils_def.h>
/* An invalid SMC function number. */
#define INVALID_FN 0x666
/* PSCI version returned by TF-A. */
static const uint32_t psci_version = PSCI_VERSION(PSCI_MAJOR_VER,
PSCI_MINOR_VER);
/* UUID of the standard service in TF-A. */
static const smc_ret_values std_svc_uuid = {
0x108d905b, 0x47e8f863, 0xfbc02dae, 0xe2f64156
};
/*
* Build an SMC function ID given its type (fast/yielding), calling convention,
* owning entity number and function number.
*/
static inline uint32_t make_smc_fid(unsigned int type, unsigned int cc,
unsigned int oen, unsigned int func_num)
{
return (type << FUNCID_TYPE_SHIFT) | (cc << FUNCID_CC_SHIFT)
| (oen << FUNCID_OEN_SHIFT) | (func_num << FUNCID_NUM_SHIFT);
}
/* Exit the test if the specified condition holds true. */
#define FAIL_IF(_cond) \
do { \
if ((_cond)) { \
return TEST_RESULT_FAIL; \
} \
} while (0)
/*
* Send an SMC with the specified arguments.
* Check that the values it returns match the expected ones. If not, write an
* error message in the test report.
*/
static bool smc_check_eq(const smc_args *args, const smc_ret_values *expect)
{
smc_ret_values ret = tftf_smc(args);
if (memcmp(&ret, expect, sizeof(smc_ret_values)) == 0) {
return true;
} else {
tftf_testcase_printf(
"Got {0x%lx,0x%lx,0x%lx,0x%lx}, expected {0x%lx,0x%lx,0x%lx,0x%lx}.\n",
ret.ret0, ret.ret1, ret.ret2, ret.ret3,
expect->ret0, expect->ret1, expect->ret2, expect->ret3);
return false;
}
}
/* Exercise SMC32 calling convention with fast SMC calls. */
test_result_t smc32_fast(void)
{
/* Valid Fast SMC32 using all 4 return values. */
const smc_args args1 = { .fid = SMC_STD_SVC_UID };
FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
/* Invalid Fast SMC32. */
const smc_args args2 = {
make_smc_fid(SMC_TYPE_FAST, SMC_32, OEN_ARM_START, INVALID_FN),
0x11111111, 0x22222222, 0x33333333 };
const smc_ret_values ret2
= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
FAIL_IF(!smc_check_eq(&args2, &ret2));
/* Valid Fast SMC32 using 1 return value. */
const smc_args args3
= { SMC_PSCI_VERSION, 0x44444444, 0x55555555, 0x66666666 };
const smc_ret_values ret3
= { psci_version, 0x44444444, 0x55555555, 0x66666666 };
FAIL_IF(!smc_check_eq(&args3, &ret3));
return TEST_RESULT_SUCCESS;
}
/* Exercise SMC64 calling convention with yielding SMC calls. */
test_result_t smc64_yielding(void)
{
/* Valid Fast SMC32 using all 4 return values. */
const smc_args args1 = { .fid = SMC_STD_SVC_UID };
FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
/* Invalid function number, SMC64 Yielding. */
const smc_args args2 = {
make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_ARM_START, INVALID_FN),
0x11111111, 0x22222222, 0x33333333 };
const smc_ret_values ret2
= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
FAIL_IF(!smc_check_eq(&args2, &ret2));
/*
* Valid[1] yielding SMC64 using 1 return value.
*
* [1] Valid from the point of view of the generic SMC handler if the
* TSPd is present. In this case, the SMC request gets passed to the
* TSPd handler code. The fact that it then gets rejected by the TSPd is
* irrelevant here, as we are not trying to test the TSPd nor the TSP.
*
* In other cases (i.e. AArch64 BL31 with no TSPd support or AArch32
* SP_MIN) this test should still fail in the same way, although it
* doesn't exercise the same code path in TF-A.
*/
const smc_args args3 = {
make_smc_fid(SMC_TYPE_STD, SMC_64, OEN_TOS_START, INVALID_FN),
0x44444444, 0x55555555, 0x66666666 };
const smc_ret_values ret3
= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
FAIL_IF(!smc_check_eq(&args3, &ret3));
return TEST_RESULT_SUCCESS;
}
#ifdef AARCH32
static test_result_t smc64_fast_caller32(void)
{
/* Valid Fast SMC32 using all 4 return values. */
smc_args args1 = { .fid = SMC_STD_SVC_UID };
FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
/* Invalid SMC function number, Fast SMC64. */
const smc_args args2 = {
make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
0x11111111, 0x22222222, 0x33333333 };
const smc_ret_values ret2
= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
FAIL_IF(!smc_check_eq(&args2, &ret2));
/*
* Valid SMC function number, Fast SMC64. However, 32-bit callers are
* forbidden to use the SMC64 calling convention.
*/
const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
0x44444444, 0x55555555, 0x66666666 };
const smc_ret_values ret3
= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
FAIL_IF(!smc_check_eq(&args3, &ret3));
return TEST_RESULT_SUCCESS;
}
#else
static test_result_t smc64_fast_caller64(void)
{
/* Valid Fast SMC32 using all 4 return values. */
smc_args args1 = { .fid = SMC_STD_SVC_UID };
FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
/* Invalid function number, Fast SMC64. */
const smc_args args2 = {
make_smc_fid(SMC_TYPE_FAST, SMC_64, OEN_ARM_START, INVALID_FN),
0x11111111, 0x22222222, 0x33333333 };
const smc_ret_values ret2
= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
FAIL_IF(!smc_check_eq(&args2, &ret2));
/* Valid Fast SMC64 using 1 return value. */
const smc_args args3 = { SMC_PSCI_AFFINITY_INFO_AARCH64,
0x44444444, 0x55555555, 0x66666666 };
const smc_ret_values ret3
= { PSCI_E_INVALID_PARAMS, 0x44444444, 0x55555555, 0x66666666 };
FAIL_IF(!smc_check_eq(&args3, &ret3));
return TEST_RESULT_SUCCESS;
}
#endif /* AARCH32 */
/* Exercise SMC64 calling convention with fast SMC calls. */
test_result_t smc64_fast(void)
{
#ifdef AARCH32
return smc64_fast_caller32();
#else
return smc64_fast_caller64();
#endif
}
/* Exercise SMC32 calling convention with yielding SMC calls. */
test_result_t smc32_yielding(void)
{
/* Valid Fast SMC32 using all 4 return values. */
const smc_args args1 = { .fid = SMC_STD_SVC_UID };
FAIL_IF(!smc_check_eq(&args1, &std_svc_uuid));
/* Invalid function number, SMC32 Yielding. */
const smc_args args2 = {
make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_ARM_START, INVALID_FN),
0x11111111, 0x22222222, 0x33333333 };
const smc_ret_values ret2
= { SMC_UNKNOWN, 0x11111111, 0x22222222, 0x33333333 };
FAIL_IF(!smc_check_eq(&args2, &ret2));
/*
* Valid[1] yielding SMC32 using 1 return value.
*
* [1] Valid from the point of view of the generic SMC handler if a
* secure payload dispatcher handling this SMC range is present. In this
* case, the SMC request gets passed to the dispatcher handler code. The
* fact that it then gets rejected by the dispatcher is irrelevant here,
* as we are not trying to test the dispatcher nor the secure payload.
*
* In BL31 has no SPD support, this test should still fail in the same
* way, although it doesn't exercise the same code path in TF-A.
*/
const smc_args args3 = {
make_smc_fid(SMC_TYPE_STD, SMC_32, OEN_TOS_START, INVALID_FN),
0x44444444, 0x55555555, 0x66666666 };
const smc_ret_values ret3
= { SMC_UNKNOWN, 0x44444444, 0x55555555, 0x66666666 };
FAIL_IF(!smc_check_eq(&args3, &ret3));
return TEST_RESULT_SUCCESS;
}