Add some tests for all types of SMCs

Exercise all combinations of SMCs: fast or yielding, SMC32 or SMC64
calling convention, from a 32-bit caller or a 64-bit one.

Change-Id: I6d23549818db7f1b3fd0cb4b46e5a592b04b5289
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
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 0000000..901b448
--- /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;
+}
+