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;
+}
+
diff --git a/tftf/tests/tests-smc.mk b/tftf/tests/tests-smc.mk
new file mode 100644
index 0000000..8496cd1
--- /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 0000000..56f987d
--- /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 c4d35c6..72c2ec0 100644
--- a/tftf/tests/tests-standard.mk
+++ b/tftf/tests/tests-standard.mk
@@ -16,6 +16,7 @@
 	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 e2a1a2b..a1323d5 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>