SPM: TFTF test of FFA_VERSION interface

Implemented test to FFA_VERSION interface:
- "test_ffa_version.c" contains functions to test FFA_VERSION ABI;
- Test suite for FFA_VERSION ABI in tests-spm.xml;
- Helper macros changed in "ffa_helpers.h".

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I6b0e937e30fceaa21a57c4ba0761a62049b16c0d
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 33fce53..bf14a80 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -7,15 +7,16 @@
 #ifndef __TEST_HELPERS_H__
 #define __TEST_HELPERS_H__
 
+#include <uuid.h>
 #include <arch_features.h>
-#include <plat_topology.h>
-#include <psci.h>
+#include <ffa_helpers.h>
 #include <ffa_svc.h>
+#include <psci.h>
 #include <tftf_lib.h>
 #include <trusted_os.h>
 #include <tsp.h>
-#include <uuid.h>
 #include <uuid_utils.h>
+#include <plat_topology.h>
 
 typedef struct {
 	uintptr_t addr;
@@ -148,41 +149,42 @@
 		}								\
 										\
 		if (version < MM_VERSION_FORM(major, minor)) {			\
-			tftf_testcase_printf("MM_VERSION returned %d.%d\n"	\
-					     "The required version is %d.%d\n",	\
-					     version >> MM_VERSION_MAJOR_SHIFT,	\
-					     version & MM_VERSION_MINOR_MASK,	\
-					     major, minor);			\
+			tftf_testcase_printf("MM_VERSION returned %u.%u\n"	\
+					"The required version is %u.%u\n",	\
+					version >> MM_VERSION_MAJOR_SHIFT,	\
+					version & MM_VERSION_MINOR_MASK,	\
+					major, minor);				\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
 										\
-		VERBOSE("MM_VERSION returned %d.%d\n",				\
+		VERBOSE("MM_VERSION returned %u.%u\n",				\
 			version >> MM_VERSION_MAJOR_SHIFT,			\
 			version & MM_VERSION_MINOR_MASK);			\
 	} while (0)
 
 #define SKIP_TEST_IF_FFA_VERSION_LESS_THAN(major, minor)			\
 	do {									\
-		smc_args version_smc = { FFA_VERSION };			\
-		smc_ret_values smc_ret = tftf_smc(&version_smc);		\
-		uint32_t version = smc_ret.ret2;				\
+		smc_ret_values smc_ret = ffa_version(				\
+					MAKE_FFA_VERSION(major, minor));	\
+		uint32_t version = smc_ret.ret0;				\
 										\
-		if (smc_ret.ret0 != FFA_SUCCESS_SMC32) {			\
-			tftf_testcase_printf("SPM not detected.\n");		\
+		if (version == FFA_ERROR_NOT_SUPPORTED) {			\
+			tftf_testcase_printf("FFA_VERSION not supported.\n");	\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
-                                                                                \
-		if ((version & FFA_VERSION_BIT31_MASK) != 0) {                 \
-			tftf_testcase_printf("FFA_VERSION bad response.\n");	\
-			return TEST_RESULT_SKIPPED;                             \
-		}                                                               \
 										\
-		if (version < MAKE_FFA_VERSION(major, minor)) {		\
-			tftf_testcase_printf("FFA_VERSION returned %d.%d\n"	\
-					     "The required version is %d.%d\n",	\
-					     version >> FFA_VERSION_MAJOR_SHIFT,\
-					     version & FFA_VERSION_MINOR_MASK,	\
-					     major, minor);			\
+		if ((version & FFA_VERSION_BIT31_MASK) != 0U) {				\
+			tftf_testcase_printf("FFA_VERSION bad response: %x\n",	\
+					version);				\
+			return TEST_RESULT_FAIL;				\
+		}								\
+										\
+		if (version < MAKE_FFA_VERSION(major, minor)) {			\
+			tftf_testcase_printf("FFA_VERSION returned %u.%u\n"	\
+					"The required version is %u.%u\n",	\
+					version >> FFA_VERSION_MAJOR_SHIFT,	\
+					version & FFA_VERSION_MINOR_MASK,	\
+					major, minor);				\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
 	} while (0)
@@ -202,12 +204,12 @@
 
 /* Helper macro to verify if system suspend API is supported */
 #define is_psci_sys_susp_supported()	\
-		(tftf_get_psci_feature_info(SMC_PSCI_SYSTEM_SUSPEND)	\
+		(tftf_get_psci_feature_info(SMC_PSCI_SYSTEM_SUSPEND)		\
 					== PSCI_E_SUCCESS)
 
 /* Helper macro to verify if PSCI_STAT_COUNT API is supported */
 #define is_psci_stat_count_supported()	\
-		(tftf_get_psci_feature_info(SMC_PSCI_STAT_COUNT)	\
+		(tftf_get_psci_feature_info(SMC_PSCI_STAT_COUNT)		\
 					== PSCI_E_SUCCESS)
 
 /*
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index f280c77..8ce952a 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -7,6 +7,7 @@
 #ifndef FFA_HELPERS_H
 #define FFA_HELPERS_H
 
+#include <ffa_svc.h>
 #include <tftf_lib.h>
 #include <utils_def.h>
 
@@ -20,6 +21,7 @@
 smc_ret_values ffa_msg_send_direct_req(uint32_t source_id, uint32_t dest_id, uint32_t message);
 smc_ret_values ffa_msg_send_direct_req64(uint32_t source_id, uint32_t dest_id, uint64_t message);
 smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id);
+smc_ret_values ffa_version(uint32_t input_version);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index 541a75a..f08e803 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -35,7 +35,7 @@
 #define FFA_VERSION_MINOR		U(0)
 #define FFA_VERSION_MINOR_SHIFT	0
 #define FFA_VERSION_MINOR_MASK		U(0xFFFF)
-#define FFA_VERSION_BIT31_MASK		(1 << 31)
+#define FFA_VERSION_BIT31_MASK		U(1 << 31)
 
 #define MAKE_FFA_VERSION(major, minor) \
 	((((major) & FFA_VERSION_MAJOR_MASK) <<  FFA_VERSION_MAJOR_SHIFT) | \
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 9d19fec..ba57cfe 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -106,3 +106,14 @@
 	return __ffa_msg_send_direct_req64_5(source_id, dest_id,
 					      message, 0, 0, 0, 0);
 }
+
+/* FFA Version ABI helper */
+smc_ret_values ffa_version(uint32_t input_version)
+{
+	smc_args args = {
+		.fid = FFA_VERSION,
+		.arg1 = input_version
+	};
+
+	return tftf_smc(&args);
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_version.c b/tftf/tests/runtime_services/secure_service/test_ffa_version.c
new file mode 100644
index 0000000..fae058d
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_version.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <ffa_helpers.h>
+#include <ffa_svc.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+/*
+ * Using FFA version expected for SPM.
+ */
+#define SPM_VERSION MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR)
+
+static bool should_skip_test;
+
+/*
+ * Calls FFA Version ABI, and checks if the result as expected.
+ */
+static test_result_t test_ffa_version(uint32_t input_version, uint32_t expected_return)
+{
+	if (should_skip_test) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	smc_ret_values ret_values = ffa_version(input_version);
+
+	uint32_t spm_version = (uint32_t)(0xFFFFFFFF & ret_values.ret0);
+
+	if (spm_version == expected_return) {
+		return TEST_RESULT_SUCCESS;
+	}
+
+	tftf_testcase_printf("Input Version: 0x%x\nReturn: 0x%x\nExpected: 0x%x\n",
+			      input_version, spm_version, expected_return);
+
+	return TEST_RESULT_FAIL;
+}
+
+/*
+ * @Test_Aim@ Validate what happens when using same version as SPM.
+ */
+test_result_t test_ffa_version_equal(void)
+{
+	/*
+	 * FFA_VERSION interface is used to check that SPM functionality is supported.
+	 * On FFA_VERSION invocation from TFTF, the SPMD returns either NOT_SUPPORTED or
+	 * the SPMC version value provided in the SPMC manifest. The variable "should_skip_test"
+	 * is set to true when the SPMD returns NOT_SUPPORTED or a mismatched version, which
+	 * means that a TFTF physical FF-A endpoint version (SPM_VERSION) does not match the
+	 * SPMC's physical FF-A endpoint version. This prevents running the subsequent FF-A
+	 * version tests (and break the test flow), as they're not relevant when the SPMD is
+	 * not present within BL31 (FFA_VERSION returns NOT_SUPPORTED).
+	 */
+	test_result_t ret = test_ffa_version(SPM_VERSION, SPM_VERSION);
+	if (ret != TEST_RESULT_SUCCESS) {
+		should_skip_test = true;
+		ret = TEST_RESULT_SKIPPED;
+	}
+	return ret;
+}
+
+/*
+ * @Test_Aim@ Validate what happens when setting bit 31 in
+ * 'input_version'. As per spec, FFA version is 31 bits long.
+ * Bit 31 set is an invalid input.
+ */
+test_result_t test_ffa_version_bit31(void)
+{
+	return test_ffa_version(FFA_VERSION_BIT31_MASK | SPM_VERSION, FFA_ERROR_NOT_SUPPORTED);
+}
+
+/*
+ * @Test_Aim@ Validate what happens for bigger version than SPM's.
+ */
+test_result_t test_ffa_version_bigger(void)
+{
+	return test_ffa_version(MAKE_FFA_VERSION(FFA_VERSION_MAJOR + 1, 0), SPM_VERSION);
+}
+
+/*
+ * @Test_Aim@ Validate what happens for smaller version than SPM's.
+ */
+test_result_t test_ffa_version_smaller(void)
+{
+	return test_ffa_version(MAKE_FFA_VERSION(0, 9), SPM_VERSION);
+}
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index dab4c6a..0c54e1c 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -8,4 +8,5 @@
 	$(addprefix tftf/tests/runtime_services/secure_service/,	\
 		ffa_helpers.c						\
 		test_ffa_direct_messaging.c				\
+		test_ffa_version.c					\
 	)
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 09af639..5ed2524 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -8,8 +8,22 @@
 
 <testsuites>
 
-  <testsuite name="Secure Partition Manager"
-             description="Test SPM APIs">
+  <testsuite name="PSA FF-A Version"
+             description="Test PSA FF-A Version ABI" >
+
+    <testcase name="Same FFA version as SPM"
+              function="test_ffa_version_equal" />
+    <testcase name="Setting bit 31 in input version"
+              function="test_ffa_version_bit31"/>
+    <testcase name="Bigger FFA version than SPM"
+              function="test_ffa_version_bigger" />
+    <testcase name="Smaller FFA version than SPM"
+              function="test_ffa_version_smaller" />
+
+  </testsuite>
+
+  <testsuite name="PSA FF-A Direct messaging"
+             description="Test PSA FF-A Direct messaging ABI" >
 
      <testcase name="PSA FF-A direct messaging API"
                function="test_ffa_direct_messaging" />