Add tests for FFA function FFA_SPM_ID_GET

Also add the ability for ffa_features_test to only use the expected
return if the minimum FF-A version for the feature is met.

Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I276500c666365c563a117aa7b250b18f51dcace7
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index bde29e1..3ca9c82 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -46,6 +46,10 @@
 	return (int32_t) val.ret2;
 }
 
+static inline ffa_id_t ffa_endpoint_id(smc_ret_values val) {
+	return (ffa_id_t) val.ret2 & 0xffff;
+}
+
 enum ffa_data_access {
 	FFA_DATA_ACCESS_NOT_SPECIFIED,
 	FFA_DATA_ACCESS_RO,
@@ -394,6 +398,7 @@
 smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id);
 smc_ret_values ffa_version(uint32_t input_version);
 smc_ret_values ffa_id_get(void);
+smc_ret_values ffa_spm_id_get(void);
 smc_ret_values ffa_msg_wait(void);
 smc_ret_values ffa_error(int32_t error_code);
 smc_ret_values ffa_features(uint32_t feature);
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index c970265..3a474e7 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,7 +22,7 @@
 
 /* The macros below are used to identify FFA calls from the SMC function ID */
 #define FFA_FNUM_MIN_VALUE	U(0x60)
-#define FFA_FNUM_MAX_VALUE	U(0x84)
+#define FFA_FNUM_MAX_VALUE	U(0x85)
 #define is_ffa_fid(fid) __extension__ ({		\
 	__typeof__(fid) _fid = (fid);			\
 	((GET_SMC_NUM(_fid) >= FFA_FNUM_MIN_VALUE) &&	\
@@ -85,6 +85,7 @@
 #define FFA_FNUM_MEM_RELINQUISH	U(0x76)
 #define FFA_FNUM_MEM_RECLAIM		U(0x77)
 #define FFA_FNUM_SECONDARY_EP_REGISTER	U(0x84)
+#define FFA_FNUM_SPM_ID_GET		U(0x85)
 
 /* FFA SMC32 FIDs */
 #define FFA_ERROR		FFA_FID(SMC_32, FFA_FNUM_ERROR)
@@ -114,6 +115,7 @@
 #define FFA_MEM_RETRIEVE_RESP	FFA_FID(SMC_32, FFA_FNUM_MEM_RETRIEVE_RESP)
 #define FFA_MEM_RELINQUISH	FFA_FID(SMC_32, FFA_FNUM_MEM_RELINQUISH)
 #define FFA_MEM_RECLAIM	FFA_FID(SMC_32, FFA_FNUM_MEM_RECLAIM)
+#define FFA_SPM_ID_GET		FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
 
 /* FFA SMC64 FIDs */
 #define FFA_SUCCESS_SMC64	FFA_FID(SMC_64, FFA_FNUM_SUCCESS)
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 02c1262..685e732 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -13,6 +13,8 @@
 
 /* Hypervisor ID at physical FFA instance */
 #define HYP_ID          (0)
+/* SPMC ID */
+#define SPMC_ID		U(0x8000)
 
 /* ID for the first Secure Partition. */
 #define SPM_VM_ID_FIRST                 SP_ID(1)
@@ -42,6 +44,7 @@
 	const char *test_name;
 	unsigned int feature;
 	unsigned int expected_ret;
+	unsigned int version_added;
 };
 
 struct mailbox_buffers {
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index cc2072c..73606bd 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -182,7 +182,7 @@
 
 	/* Get current FFA id */
 	smc_ret_values ffa_id_ret = ffa_id_get();
-	ffa_id_t ffa_id = (ffa_id_t)(ffa_id_ret.ret2 & 0xffff);
+	ffa_id_t ffa_id = ffa_endpoint_id(ffa_id_ret);
 	if (ffa_func_id(ffa_id_ret) != FFA_SUCCESS_SMC32) {
 		ERROR("FFA_ID_GET failed.\n");
 		panic();
diff --git a/spm/cactus/cactus_tests/cactus_test_ffa.c b/spm/cactus/cactus_tests/cactus_test_ffa.c
index 2ade7bd..93f0403 100644
--- a/spm/cactus/cactus_tests/cactus_test_ffa.c
+++ b/spm/cactus/cactus_tests/cactus_test_ffa.c
@@ -20,6 +20,8 @@
 #define FFA_MAJOR 1U
 #define FFA_MINOR 0U
 
+static uint32_t spm_version;
+
 static const uint32_t primary_uuid[4] = PRIMARY_UUID;
 static const uint32_t secondary_uuid[4] = SECONDARY_UUID;
 static const uint32_t tertiary_uuid[4] = TERTIARY_UUID;
@@ -32,23 +34,31 @@
 {
 	const char *test_features = "FFA Features interface";
 	smc_ret_values ffa_ret;
+	unsigned int expected_ret;
 	const struct ffa_features_test *ffa_feature_test_target;
 	unsigned int i, test_target_size =
 		get_ffa_feature_test_target(&ffa_feature_test_target);
+	struct ffa_features_test test_target;
 
 
 	announce_test_section_start(test_features);
 
 	for (i = 0U; i < test_target_size; i++) {
-		announce_test_start(ffa_feature_test_target[i].test_name);
+		test_target = ffa_feature_test_target[i];
 
-		ffa_ret = ffa_features(ffa_feature_test_target[i].feature);
-		expect(ffa_func_id(ffa_ret), ffa_feature_test_target[i].expected_ret);
-		if (ffa_feature_test_target[i].expected_ret == FFA_ERROR) {
+		announce_test_start(test_target.test_name);
+
+		ffa_ret = ffa_features(test_target.feature);
+		expected_ret = FFA_VERSION_COMPILED
+				>= test_target.version_added ?
+				test_target.expected_ret : FFA_ERROR;
+
+		expect(ffa_func_id(ffa_ret), expected_ret);
+		if (expected_ret == FFA_ERROR) {
 			expect(ffa_error_code(ffa_ret), FFA_ERROR_NOT_SUPPORTED);
 		}
 
-		announce_test_end(ffa_feature_test_target[i].test_name);
+		announce_test_end(test_target.test_name);
 	}
 
 	announce_test_section_end(test_features);
@@ -147,7 +157,7 @@
 	announce_test_start(test_ffa_version);
 
 	smc_ret_values ret = ffa_version(MAKE_FFA_VERSION(FFA_MAJOR, FFA_MINOR));
-	uint32_t spm_version = (uint32_t)ret.ret0;
+	spm_version = (uint32_t)ret.ret0;
 
 	bool ffa_version_compatible =
 		((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
@@ -163,6 +173,32 @@
 	announce_test_end(test_ffa_version);
 }
 
+void ffa_spm_id_get_test(void)
+{
+	const char *test_spm_id_get = "FFA_SPM_ID_GET SMC Function";
+
+	announce_test_start(test_spm_id_get);
+
+	if (spm_version >= MAKE_FFA_VERSION(1, 1)) {
+		smc_ret_values ret = ffa_spm_id_get();
+
+		expect(ffa_func_id(ret), FFA_SUCCESS_SMC32);
+
+		ffa_id_t spm_id = ffa_endpoint_id(ret);
+
+		VERBOSE("SPM ID = 0x%x\n", spm_id);
+		/*
+		 * Check the SPMC value given in the fvp_spmc_manifest
+		 * is returned.
+		 */
+		expect(spm_id, SPMC_ID);
+	} else {
+		NOTICE("FFA_SPM_ID_GET not supported in this version of FF-A."
+			" Test skipped.\n");
+	}
+	announce_test_end(test_spm_id_get);
+}
+
 void ffa_tests(struct mailbox_buffers *mb)
 {
 	const char *test_ffa = "FFA Interfaces";
@@ -171,6 +207,7 @@
 
 	ffa_features_test();
 	ffa_version_test();
+	ffa_spm_id_get_test();
 	ffa_partition_info_get_test(mb);
 
 	announce_test_section_end(test_ffa);
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 9a4dc72..4c69eb1 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -316,6 +316,15 @@
 	return tftf_smc(&args);
 }
 
+smc_ret_values ffa_spm_id_get(void)
+{
+	smc_args args = {
+		.fid = FFA_SPM_ID_GET
+	};
+
+	return tftf_smc(&args);
+}
+
 smc_ret_values ffa_msg_wait(void)
 {
 	smc_args args = {
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 88626e4..0482033 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -6,6 +6,7 @@
 
 #include <debug.h>
 #include <ffa_endpoints.h>
+#include <ffa_svc.h>
 #include <spm_common.h>
 #include <xlat_tables_v2.h>
 
@@ -166,6 +167,8 @@
 	{"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_SPM_ID_GET_32 check", FFA_SPM_ID_GET, FFA_SUCCESS_SMC32,
+		MAKE_FFA_VERSION(1, 1)},
 	{"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},
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_features.c b/tftf/tests/runtime_services/secure_service/test_ffa_features.c
index e4cd845..c6a4dca 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_features.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_features.c
@@ -19,24 +19,30 @@
 	}
 
 	smc_ret_values ffa_ret;
+	unsigned int expected_ret;
 	const struct ffa_features_test *ffa_feature_test_target;
 	unsigned int i, test_target_size =
 		get_ffa_feature_test_target(&ffa_feature_test_target);
+	struct ffa_features_test test_target;
 
 	for (i = 0U; i < test_target_size; i++) {
-		ffa_ret = ffa_features(ffa_feature_test_target[i].feature);
-		if (ffa_func_id(ffa_ret) != ffa_feature_test_target[i].expected_ret) {
+		test_target = ffa_feature_test_target[i];
+		ffa_ret = ffa_features(test_target.feature);
+		expected_ret = FFA_VERSION_COMPILED
+				>= test_target.version_added ?
+				test_target.expected_ret : FFA_ERROR;
+		if (ffa_func_id(ffa_ret) != expected_ret) {
 			tftf_testcase_printf("%s returned %x, expected %x\n",
-					     ffa_feature_test_target[i].test_name,
+					     test_target.test_name,
 					     ffa_func_id(ffa_ret),
-					     ffa_feature_test_target[i].expected_ret);
+					     expected_ret);
 			return TEST_RESULT_FAIL;
 		}
-		if ((ffa_feature_test_target[i].expected_ret == FFA_ERROR) &&
+		if ((expected_ret == FFA_ERROR) &&
 		    (ffa_error_code(ffa_ret) != FFA_ERROR_NOT_SUPPORTED)) {
 			tftf_testcase_printf("%s failed for the wrong reason: "
 					     "returned %x, expected %x\n",
-					     ffa_feature_test_target[i].test_name,
+					     test_target.test_name,
 					     ffa_error_code(ffa_ret),
 					     FFA_ERROR_NOT_SUPPORTED);
 			return TEST_RESULT_FAIL;
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_misc.c b/tftf/tests/runtime_services/secure_service/test_ffa_misc.c
new file mode 100644
index 0000000..6bf8352
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_misc.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <ffa_helpers.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+test_result_t test_ffa_spm_id_get(void)
+{
+	SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+	smc_ret_values ffa_ret = ffa_spm_id_get();
+
+	if (is_ffa_call_error(ffa_ret)) {
+		ERROR("FFA_SPM_ID_GET call failed! Error code: 0x%x\n",
+			ffa_error_code(ffa_ret));
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Check the SPMC value given in the fvp_spmc_manifest is returned */
+	ffa_id_t spm_id = ffa_endpoint_id(ffa_ret);
+
+	if (spm_id != SPMC_ID) {
+		ERROR("Expected SPMC_ID of 0x%x\n received: 0x%x\n",
+			SPMC_ID, spm_id);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index e62e03d..93c56e2 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -12,6 +12,7 @@
 		test_ffa_features.c					\
 		test_ffa_interrupts.c					\
 		test_ffa_memory_sharing.c				\
+		test_ffa_misc.c						\
 		test_ffa_rxtx_map.c					\
 		test_ffa_version.c					\
 		test_spm_cpu_features.c					\
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 32efc16..1cab4b0 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -89,4 +89,11 @@
      <testcase name="Check DMA command by SMMUv3TestEngine completes"
                function="test_smmu_spm" />
   </testsuite>
+
+  <testsuite name="FF-A Misc"
+             description="Test Misc FFA ABI Functions" >
+     <testcase name="Test FFA_SPM_ID_GET"
+               function="test_ffa_spm_id_get" />
+  </testsuite>
+
 </testsuites>