SPM: TFTF test of FFA_FEATURES interface.

Forwards FFA_FEATURES call to SPMC via SPMD from the normal world.
Expected responses should be edited according to the feature
implementation progress.

Signed-off-by: Max Shvetsov <maksims.svecovs@arm.com>
Change-Id: I057100b4086108b0779e3fa76fbd86e0818f765c
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index d4ef803..1a49fa8 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -32,7 +32,7 @@
  * TODO: In the future this file should be placed in a common folder, and not
  * under tftf. The functions in this file are also used by SPs for SPM tests.
  */
-
+bool check_spmc_execution_level(void);
 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);
@@ -42,6 +42,7 @@
 smc_ret_values ffa_msg_send_direct_resp(ffa_vm_id_t source_id,
 					ffa_vm_id_t dest_id, uint32_t message);
 smc_ret_values ffa_error(int32_t error_code);
+smc_ret_values ffa_features(uint32_t feature);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 9955c7c..6e7eca3 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -9,6 +9,11 @@
 #include <ffa_helpers.h>
 #include <ffa_svc.h>
 
+#define OPTEE_FFA_GET_API_VERSION	(0)
+#define OPTEE_FFA_GET_OS_VERSION	(1)
+#define OPTEE_FFA_GET_OS_VERSION_MAJOR	(3)
+#define OPTEE_FFA_GET_OS_VERSION_MINOR	(8)
+
 /*-----------------------------------------------------------------------------
  * FFA_RUN
  *
@@ -108,6 +113,49 @@
 }
 
 /*
+ * check_spmc_execution_level
+ *
+ * Attempt sending impdef protocol messages to OP-TEE through direct messaging.
+ * Criteria for detecting OP-TEE presence is that responses match defined
+ * version values. In the case of SPMC running at S-EL2 (and Cactus instances
+ * running at S-EL1) the response will not match the pre-defined version IDs.
+ *
+ * Returns true if SPMC is probed as being OP-TEE at S-EL1.
+ *
+ */
+bool check_spmc_execution_level(void)
+{
+	unsigned int is_optee_spmc_criteria = 0U;
+	smc_ret_values ret_values;
+
+	/*
+	 * Send a first OP-TEE-defined protocol message through
+	 * FFA direct message.
+	 *
+	 */
+	ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
+					      OPTEE_FFA_GET_API_VERSION);
+	if ((ret_values.ret3 == FFA_VERSION_MAJOR) &&
+	    (ret_values.ret4 == FFA_VERSION_MINOR)) {
+		is_optee_spmc_criteria++;
+	}
+
+	/*
+	 * Send a second OP-TEE-defined protocol message through
+	 * FFA direct message.
+	 *
+	 */
+	ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
+					      OPTEE_FFA_GET_OS_VERSION);
+	if ((ret_values.ret3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
+	    (ret_values.ret4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
+		is_optee_spmc_criteria++;
+	}
+
+	return (is_optee_spmc_criteria == 2U);
+}
+
+/*
  * FFA Version ABI helper.
  * Version fields:
  *	-Bits[30:16]: Major version.
@@ -164,3 +212,14 @@
 
 	return tftf_smc(&args);
 }
+
+/* Query the higher EL if the requested FF-A feature is implemented. */
+smc_ret_values ffa_features(uint32_t feature)
+{
+	smc_args args = {
+		.fid = FFA_FEATURES,
+		.arg1 = feature
+	};
+
+	return tftf_smc(&args);
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
index c83a403..6008b78 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_direct_messaging.c
@@ -16,11 +16,6 @@
 #define DIRECT_MSG_TEST_PATTERN2	(0xbbbb0000)
 #define DIRECT_MSG_TEST_PATTERN3	(0xcccc0000)
 
-#define OPTEE_FFA_GET_API_VERSION	(0)
-#define OPTEE_FFA_GET_OS_VERSION	(1)
-#define OPTEE_FFA_GET_OS_VERSION_MAJOR	(3)
-#define OPTEE_FFA_GET_OS_VERSION_MINOR	(8)
-
 static test_result_t send_receive_direct_msg(unsigned int sp_id,
 					     unsigned int test_pattern)
 {
@@ -51,49 +46,6 @@
 	return TEST_RESULT_SUCCESS;
 }
 
-/*
- * check_spmc_execution_level
- *
- * Attempt sending impdef protocol messages to OP-TEE through direct messaging.
- * Criteria for detecting OP-TEE presence is that responses match defined
- * version values. In the case of SPMC running at S-EL2 (and Cactus instances
- * running at S-EL1) the response will not match the pre-defined version IDs.
- *
- * Returns true if SPMC is probed as being OP-TEE at S-EL1.
- *
- */
-static bool check_spmc_execution_level(void)
-{
-	unsigned int is_optee_spmc_criteria = 0;
-	smc_ret_values ret_values;
-
-	/*
-	 * Send a first OP-TEE-defined protocol message through
-	 * FFA direct message.
-	 *
-	 */
-	ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
-					      OPTEE_FFA_GET_API_VERSION);
-	if ((ret_values.ret3 == FFA_VERSION_MAJOR) &&
-	    (ret_values.ret4 == FFA_VERSION_MINOR)) {
-		is_optee_spmc_criteria++;
-	}
-
-	/*
-	 * Send a second OP-TEE-defined protocol message through
-	 * FFA direct message.
-	 *
-	 */
-	ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
-					      OPTEE_FFA_GET_OS_VERSION);
-	if ((ret_values.ret3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
-	    (ret_values.ret4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
-		is_optee_spmc_criteria++;
-	}
-
-	return (is_optee_spmc_criteria == 2);
-}
-
 test_result_t test_ffa_direct_messaging(void)
 {
 	test_result_t result;
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_features.c b/tftf/tests/runtime_services/secure_service/test_ffa_features.c
new file mode 100644
index 0000000..b8475de
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_features.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <ffa_helpers.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+struct feature_test {
+	const char *test_name;
+	unsigned int feature;
+	u_register_t expected_ret;
+};
+
+static const struct feature_test test_target[] = {
+	{"FFA_ERROR_32 check", FFA_ERROR, FFA_SUCCESS_SMC32},
+	{"FFA_SUCCESS_32 check", FFA_SUCCESS_SMC32, FFA_SUCCESS_SMC32},
+	{"FFA_INTERRUPT_32 check", FFA_INTERRUPT, FFA_SUCCESS_SMC32},
+	{"FFA_VERSION_32 check", FFA_VERSION, FFA_SUCCESS_SMC32},
+	{"FFA_FEATURES_32 check", FFA_FEATURES, FFA_SUCCESS_SMC32},
+	{"FFA_RX_RELEASE_32 check", FFA_RX_RELEASE, FFA_SUCCESS_SMC32},
+	{"FFA_RXTX_MAP_32 check", FFA_RXTX_MAP_SMC32, FFA_ERROR},
+	{"FFA_RXTX_UNMAP_32 check", FFA_RXTX_UNMAP, FFA_ERROR},
+	{"FFA_PARTITION_INFO_GET_32 check", FFA_PARTITION_INFO_GET, FFA_SUCCESS_SMC32},
+	{"FFA_ID_GET_32 check", FFA_ID_GET, FFA_SUCCESS_SMC32},
+	{"FFA_MSG_POLL_32 check", FFA_MSG_POLL, FFA_SUCCESS_SMC32},
+	{"FFA_MSG_WAIT_32 check", FFA_MSG_WAIT, FFA_SUCCESS_SMC32},
+	{"FFA_YIELD_32 check", FFA_MSG_YIELD, FFA_SUCCESS_SMC32},
+	{"FFA_RUN_32 check", FFA_MSG_RUN, FFA_SUCCESS_SMC32},
+	{"FFA_MSG_SEND_32 check", FFA_MSG_SEND, FFA_SUCCESS_SMC32},
+	{"FFA_MEM_DONATE_32 check", FFA_MEM_DONATE_SMC32, FFA_SUCCESS_SMC32},
+	{"FFA_MEM_LEND_32 check", FFA_MEM_LEND_SMC32, FFA_SUCCESS_SMC32},
+	{"FFA_MEM_SHARE_32 check", FFA_MEM_SHARE_SMC32, FFA_SUCCESS_SMC32},
+	{"FFA_MEM_RETRIEVE_REQ_32 check", FFA_MEM_RETRIEVE_REQ_SMC32, FFA_SUCCESS_SMC32},
+	{"FFA_MEM_RETRIEVE_RESP_32 check", FFA_MEM_RETRIEVE_RESP, FFA_SUCCESS_SMC32},
+	{"FFA_MEM_RELINQUISH_32 check", FFA_MEM_RELINQUISH, FFA_SUCCESS_SMC32},
+	{"FFA_MEM_RECLAIM_32 check", FFA_MEM_RECLAIM, FFA_SUCCESS_SMC32}
+};
+
+test_result_t test_ffa_features(void)
+{
+	SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+	/* Check if SPMC is OP-TEE at S-EL1 */
+	if (check_spmc_execution_level()) {
+		/* FFA_FEATURES is not yet supported in OP-TEE */
+		return TEST_RESULT_SUCCESS;
+	}
+
+	smc_ret_values ffa_ret;
+	unsigned int i, test_target_size =
+		sizeof(test_target) / sizeof(struct feature_test);
+
+	for (i = 0U; i < test_target_size; i++) {
+		ffa_ret = ffa_features(test_target[i].feature);
+		if (ffa_ret.ret0 != test_target[i].expected_ret) {
+			tftf_testcase_printf("%s returned %lx, expected %lx\n",
+					     test_target[i].test_name,
+					     ffa_ret.ret0,
+					     test_target[i].expected_ret);
+			return TEST_RESULT_FAIL;
+		}
+		if ((test_target[i].expected_ret == (u_register_t)FFA_ERROR) &&
+		    (ffa_ret.ret2 != (u_register_t)FFA_ERROR_NOT_SUPPORTED)) {
+			tftf_testcase_printf("%s failed for the wrong reason: "
+					     "returned %lx, expected %lx\n",
+					     test_target[i].test_name,
+					     ffa_ret.ret2,
+					     (u_register_t)FFA_ERROR_NOT_SUPPORTED);
+			return TEST_RESULT_FAIL;
+		}
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index 0c54e1c..bef373f 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -9,4 +9,5 @@
 		ffa_helpers.c						\
 		test_ffa_direct_messaging.c				\
 		test_ffa_version.c					\
+		test_ffa_features.c					\
 	)
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 5ed2524..e2f29bf 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -30,4 +30,10 @@
 
   </testsuite>
 
+  <testsuite name="PSA FF-A features"
+             description="Test FFA_FEATURES ABI" >
+     <testcase name="Test FFA_FEATURES"
+               function="test_ffa_features" />
+  </testsuite>
+
 </testsuites>