diff options
-rw-r--r-- | tftf/tests/runtime_services/generic/generic_smc.c | 227 | ||||
-rw-r--r-- | tftf/tests/tests-smc.mk | 7 | ||||
-rw-r--r-- | tftf/tests/tests-smc.xml | 19 | ||||
-rw-r--r-- | tftf/tests/tests-standard.mk | 1 | ||||
-rw-r--r-- | tftf/tests/tests-standard.xml | 2 |
5 files changed, 256 insertions, 0 deletions
diff --git a/tftf/tests/runtime_services/generic/generic_smc.c b/tftf/tests/runtime_services/generic/generic_smc.c new file mode 100644 index 000000000..901b44812 --- /dev/null +++ b/tftf/tests/runtime_services/generic/generic_smc.c @@ -0,0 +1,227 @@ +/* + * 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; +} + diff --git a/tftf/tests/tests-smc.mk b/tftf/tests/tests-smc.mk new file mode 100644 index 000000000..8496cd1de --- /dev/null +++ b/tftf/tests/tests-smc.mk @@ -0,0 +1,7 @@ +# +# Copyright (c) 2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +TESTS_SOURCES += tftf/tests/runtime_services/generic/generic_smc.c diff --git a/tftf/tests/tests-smc.xml b/tftf/tests/tests-smc.xml new file mode 100644 index 000000000..56f987dd9 --- /dev/null +++ b/tftf/tests/tests-smc.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Copyright (c) 2018, Arm Limited. All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause +--> + +<testsuites> + + <testsuite name="SMC calling convention" + description="Test different flavours of the SMC calling convention"> + <testcase name="Fast SMC32" function="smc32_fast" /> + <testcase name="Fast SMC64" function="smc64_fast" /> + <testcase name="Yielding SMC32" function="smc32_yielding" /> + <testcase name="Yielding SMC64" function="smc64_yielding" /> + </testsuite> + +</testsuites> diff --git a/tftf/tests/tests-standard.mk b/tftf/tests/tests-standard.mk index c4d35c609..72c2ec0d0 100644 --- a/tftf/tests/tests-standard.mk +++ b/tftf/tests/tests-standard.mk @@ -16,6 +16,7 @@ TESTS_MAKEFILE := $(addprefix tftf/tests/, \ tests-runtime-instrumentation.mk \ tests-sdei.mk \ tests-single-fault.mk \ + tests-smc.mk \ tests-spm.mk \ tests-template.mk \ tests-tftf-validation.mk \ diff --git a/tftf/tests/tests-standard.xml b/tftf/tests/tests-standard.xml index e2a1a2bd8..a1323d555 100644 --- a/tftf/tests/tests-standard.xml +++ b/tftf/tests/tests-standard.xml @@ -19,6 +19,7 @@ <!ENTITY tests-state-switch SYSTEM "tests-arm-state-switch.xml"> <!ENTITY tests-cpu-extensions SYSTEM "tests-cpu-extensions.xml"> <!ENTITY tests-performance SYSTEM "tests-performance.xml"> + <!ENTITY tests-smc SYSTEM "tests-smc.xml"> ]> <testsuites> @@ -33,5 +34,6 @@ &tests-state-switch; &tests-cpu-extensions; &tests-performance; + &tests-smc; </testsuites> |