Merge "TFTF: Fix regions' mapping with no NS bit set"
diff --git a/Makefile b/Makefile
index 1851775..fea13db 100644
--- a/Makefile
+++ b/Makefile
@@ -94,6 +94,17 @@
 $(and $(patsubst 0,,$(value $(1))),$(patsubst 1,,$(value $(1))),$(error $(1) must be boolean))
 endef
 
+# CREATE_SEQ is a recursive function to create sequence of numbers from 1 to
+# $(2) and assign the sequence to $(1)
+define CREATE_SEQ
+$(if $(word $(2), $($(1))),\
+  $(eval $(1) += $(words $($(1))))\
+  $(eval $(1) := $(filter-out 0,$($(1)))),\
+  $(eval $(1) += $(words $($(1))))\
+  $(call CREATE_SEQ,$(1),$(2))\
+)
+endef
+
 ifeq (${PLAT},)
   $(error "Error: Unknown platform. Please use PLAT=<platform name> to specify the platform")
 endif
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 2e608e2..95724e7 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -70,6 +70,23 @@
 -  ``V``: Verbose build. If assigned anything other than 0, the build commands
    are printed. Default is 0.
 
+Arm FVP Platform Specific Build Options
+---------------------------------------
+
+-  ``FVP_CLUSTER_COUNT`` : Configures the cluster count to be used to build the
+   topology tree within TFTF. By default TFTF is configured for dual cluster for
+   CPUs with single thread (ST) and single cluster for SMT CPUs.
+   For ST CPUs this option can be used to override the default number of clusters
+   with a value in the range 1-4.
+
+-  ``FVP_MAX_CPUS_PER_CLUSTER``: Sets the maximum number of CPUs implemented in
+   a single cluster. This option defaults to the maximum value of 4 for ST CPUs
+   and maximum value of 8 for SMT CPUs.
+
+-  ``FVP_MAX_PE_PER_CPU``: Sets the maximum number of PEs implemented on any CPU
+   in the system. This option defaults to 1 to select ST CPUs. For platforms with
+   SMT CPUs this value must be set to 2.
+
 TFTF-specific Build Options
 ---------------------------
 
@@ -107,4 +124,4 @@
 
 --------------
 
-*Copyright (c) 2019, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
diff --git a/docs/getting_started/build.rst b/docs/getting_started/build.rst
index f137afe..27ad580 100644
--- a/docs/getting_started/build.rst
+++ b/docs/getting_started/build.rst
@@ -99,7 +99,7 @@
 
 ::
 
-    BL33=tftf.bin make PLAT=<platform> fip
+    BL33=<path/to/tftf.bin> make PLAT=<platform> fip
 
 Please refer to the `TF-A documentation`_ for further details.
 
diff --git a/include/common/fwu_nvm.h b/include/common/fwu_nvm.h
index 923a596..3865d4b 100644
--- a/include/common/fwu_nvm.h
+++ b/include/common/fwu_nvm.h
@@ -27,7 +27,7 @@
  * located in NVM. This particular value is chosen
  * to make sure the corruption is done beyond fip header.
  */
-#define FIP_CORRUPT_OFFSET		(0x300)
+#define FIP_CORRUPT_OFFSET		(0x400)
 
 /*
  * This is the base address for backup fip.bin image in NVM
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..d4ef803 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -7,19 +7,41 @@
 #ifndef FFA_HELPERS_H
 #define FFA_HELPERS_H
 
+#include <ffa_svc.h>
 #include <tftf_lib.h>
 #include <utils_def.h>
 
 /* This error code must be different to the ones used by FFA */
 #define FFA_TFTF_ERROR		-42
 
+/* Hypervisor ID at physical FFA instance */
+#define HYP_ID          (0)
+
+/* By convention, SP IDs (as opposed to VM IDs) have bit 15 set */
+#define SP_ID(x)        ((x) | (1 << 15))
+
+typedef unsigned short ffa_vm_id_t;
+typedef unsigned short ffa_vm_count_t;
+typedef unsigned short ffa_vcpu_count_t;
+
 #ifndef __ASSEMBLY__
 
 #include <stdint.h>
 
+/*
+ * 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.
+ */
+
 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);
+smc_ret_values ffa_id_get(void);
+smc_ret_values ffa_msg_wait(void);
+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);
 
 #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/plat/arm/fvp/fvp_def.h b/plat/arm/fvp/fvp_def.h
index 3f01678..bcd3a7c 100644
--- a/plat/arm/fvp/fvp_def.h
+++ b/plat/arm/fvp/fvp_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -16,9 +16,13 @@
 /*******************************************************************************
  * Cluster Topology definitions
  ******************************************************************************/
-#define FVP_MAX_CPUS_PER_CLUSTER	8
-/* Currently the highest cluster count on the FVP is 4 (Quad cluster) */
-#define FVP_CLUSTER_COUNT		4
+#ifndef FVP_CLUSTER_COUNT
+#error "FVP_CLUSTER_COUNT is not set in makefile"
+#endif
+
+#ifndef FVP_MAX_CPUS_PER_CLUSTER
+#error "FVP_MAX_CPUS_PER_CLUSTER is not set in makefile"
+#endif
 
 /*******************************************************************************
  * FVP memory map related constants
diff --git a/plat/arm/fvp/fvp_topology.c b/plat/arm/fvp/fvp_topology.c
index e13e801..6dece28 100644
--- a/plat/arm/fvp/fvp_topology.c
+++ b/plat/arm/fvp/fvp_topology.c
@@ -22,13 +22,60 @@
 #define	CPU_DEF(cluster, cpu)	\
 	{ cluster, cpu, 0 },	\
 	{ cluster, cpu, 1 }
-
 #else
+/* ST: 1 thread per CPU */
 #define	CPU_DEF(cluster, cpu)	\
 	{ cluster, cpu }
-#endif
+#endif	/* FVP_MAX_PE_PER_CPU */
 
-/* 8 CPUs per cluster */
+/*
+ * Max CPUs per cluster:
+ * ST:	4
+ * SMT:	8
+ */
+#if (FVP_MAX_CPUS_PER_CLUSTER == 1)
+#define	CLUSTER_DEF(cluster)	\
+	CPU_DEF(cluster, 0)
+#elif (FVP_MAX_CPUS_PER_CLUSTER == 2)
+#define	CLUSTER_DEF(cluster)	\
+	CPU_DEF(cluster, 0),	\
+	CPU_DEF(cluster, 1)
+#elif (FVP_MAX_CPUS_PER_CLUSTER == 3)
+#define	CLUSTER_DEF(cluster)	\
+	CPU_DEF(cluster, 0),	\
+	CPU_DEF(cluster, 1),	\
+	CPU_DEF(cluster, 2)
+#elif (FVP_MAX_CPUS_PER_CLUSTER == 4)
+#define	CLUSTER_DEF(cluster)	\
+	CPU_DEF(cluster, 0),	\
+	CPU_DEF(cluster, 1),	\
+	CPU_DEF(cluster, 2),	\
+	CPU_DEF(cluster, 3)
+#elif (FVP_MAX_CPUS_PER_CLUSTER == 5)
+#define	CLUSTER_DEF(cluster)	\
+	CPU_DEF(cluster, 0),	\
+	CPU_DEF(cluster, 1),	\
+	CPU_DEF(cluster, 2),	\
+	CPU_DEF(cluster, 3),	\
+	CPU_DEF(cluster, 4)
+#elif (FVP_MAX_CPUS_PER_CLUSTER == 6)
+#define	CLUSTER_DEF(cluster)	\
+	CPU_DEF(cluster, 0),	\
+	CPU_DEF(cluster, 1),	\
+	CPU_DEF(cluster, 2),	\
+	CPU_DEF(cluster, 3),	\
+	CPU_DEF(cluster, 4),	\
+	CPU_DEF(cluster, 5)
+#elif (FVP_MAX_CPUS_PER_CLUSTER == 7)
+#define	CLUSTER_DEF(cluster)	\
+	CPU_DEF(cluster, 0),	\
+	CPU_DEF(cluster, 1),	\
+	CPU_DEF(cluster, 2),	\
+	CPU_DEF(cluster, 3),	\
+	CPU_DEF(cluster, 4),	\
+	CPU_DEF(cluster, 5),	\
+	CPU_DEF(cluster, 6)
+#else
 #define	CLUSTER_DEF(cluster)	\
 	CPU_DEF(cluster, 0),	\
 	CPU_DEF(cluster, 1),	\
@@ -38,6 +85,7 @@
 	CPU_DEF(cluster, 5),	\
 	CPU_DEF(cluster, 6),	\
 	CPU_DEF(cluster, 7)
+#endif	/* FVP_MAX_CPUS_PER_CLUSTER */
 
 static const struct {
 	unsigned int cluster_id;
@@ -48,9 +96,15 @@
 } fvp_base_aemv8a_aemv8a_cores[] = {
 	/* Clusters 0...3 */
 	CLUSTER_DEF(0),
+#if (FVP_CLUSTER_COUNT > 1)
 	CLUSTER_DEF(1),
+#if (FVP_CLUSTER_COUNT > 2)
 	CLUSTER_DEF(2),
+#if (FVP_CLUSTER_COUNT > 3)
 	CLUSTER_DEF(3)
+#endif
+#endif
+#endif
 };
 
 /*
@@ -70,12 +124,18 @@
 	FVP_CLUSTER_COUNT,
 	/* Number of children for the first node */
 	FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU,
+#if (FVP_CLUSTER_COUNT > 1)
 	/* Number of children for the second node */
 	FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU,
+#if (FVP_CLUSTER_COUNT > 2)
 	/* Number of children for the third node */
 	FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU,
+#if (FVP_CLUSTER_COUNT > 3)
 	/* Number of children for the fourth node */
 	FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU
+#endif
+#endif
+#endif
 };
 
 const unsigned char *tftf_plat_get_pwr_domain_tree_desc(void)
diff --git a/plat/arm/fvp/platform.mk b/plat/arm/fvp/platform.mk
index 34f6051..b993d72 100644
--- a/plat/arm/fvp/platform.mk
+++ b/plat/arm/fvp/platform.mk
@@ -1,20 +1,61 @@
 #
-# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
 # Default number of threads per CPU on FVP
-FVP_MAX_PE_PER_CPU	:= 1
+FVP_MAX_PE_PER_CPU		:= 1
 
 # Check the PE per core count
 ifneq ($(FVP_MAX_PE_PER_CPU),$(filter $(FVP_MAX_PE_PER_CPU),1 2))
-$(error "Incorrect FVP_MAX_PE_PER_CPU specified for FVP port")
+$(error "Incorrect FVP_MAX_PE_PER_CPU = ${FVP_MAX_PE_PER_CPU} \
+	specified for FVP port")
 endif
 
-# Pass FVP_MAX_PE_PER_CPU to the build system
+# Default cluster count and number of CPUs per cluster for FVP
+ifeq ($(FVP_MAX_PE_PER_CPU),1)
+FVP_CLUSTER_COUNT		:= 2
+FVP_MAX_CPUS_PER_CLUSTER	:= 4
+else
+FVP_CLUSTER_COUNT		:= 1
+FVP_MAX_CPUS_PER_CLUSTER	:= 8
+endif
+
+# Check cluster count and number of CPUs per cluster
+ifeq ($(FVP_MAX_PE_PER_CPU),2)
+# Multithreaded CPU: 1 cluster with up to 8 CPUs
+$(eval $(call CREATE_SEQ,CLS,1))
+$(eval $(call CREATE_SEQ,CPU,8))
+else
+# CPU with single thread: max 4 clusters with up to 4 CPUs
+$(eval $(call CREATE_SEQ,CLS,4))
+$(eval $(call CREATE_SEQ,CPU,4))
+endif
+
+# Check cluster count
+ifneq ($(FVP_CLUSTER_COUNT),$(filter $(FVP_CLUSTER_COUNT),$(CLS)))
+  $(error "Incorrect FVP_CLUSTER_COUNT = ${FVP_CLUSTER_COUNT} \
+  specified for FVP port with FVP_MAX_PE_PER_CPU = ${FVP_MAX_PE_PER_CPU}")
+endif
+
+# Check number of CPUs per cluster
+ifneq ($(FVP_MAX_CPUS_PER_CLUSTER),$(filter $(FVP_MAX_CPUS_PER_CLUSTER),$(CPU)))
+  $(error "Incorrect FVP_MAX_CPUS_PER_CLUSTER = ${FVP_MAX_CPUS_PER_CLUSTER} \
+  specified for FVP port with FVP_MAX_PE_PER_CPU = ${FVP_MAX_PE_PER_CPU}")
+endif
+
+# Pass FVP topology definitions to the build system
+$(eval $(call add_define,TFTF_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,TFTF_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
 $(eval $(call add_define,TFTF_DEFINES,FVP_MAX_PE_PER_CPU))
+
+$(eval $(call add_define,NS_BL1U_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,NS_BL1U_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
 $(eval $(call add_define,NS_BL1U_DEFINES,FVP_MAX_PE_PER_CPU))
+
+$(eval $(call add_define,NS_BL2U_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,NS_BL2U_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
 $(eval $(call add_define,NS_BL2U_DEFINES,FVP_MAX_PE_PER_CPU))
 
 PLAT_INCLUDES	:=	-Iplat/arm/fvp/include/
diff --git a/plat/arm/sgi/sgi575/tests_to_skip.txt b/plat/arm/sgi/sgi575/tests_to_skip.txt
index d4e24c3..5f132f5 100644
--- a/plat/arm/sgi/sgi575/tests_to_skip.txt
+++ b/plat/arm/sgi/sgi575/tests_to_skip.txt
@@ -7,4 +7,3 @@
 # System suspend is not supported as there are no wakeup sources in SGI-575 FVP
 PSCI STAT/Stats test cases after system suspend
 PSCI System Suspend Validation
-PSCI NODE_HW_STATE
diff --git a/plat/common/plat_topology.c b/plat/common/plat_topology.c
index 33b6e57..5ff7a31 100644
--- a/plat/common/plat_topology.c
+++ b/plat/common/plat_topology.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -364,6 +364,9 @@
 
 unsigned int tftf_find_random_cpu_other_than(unsigned int exclude_mpid)
 {
+#if (PLATFORM_CORE_COUNT == 1)
+	return INVALID_MPID;
+#else
 	unsigned int cpu_node, mpidr;
 	unsigned int possible_cpus_cnt = 0;
 	unsigned int possible_cpus[PLATFORM_CORE_COUNT];
@@ -378,4 +381,5 @@
 		return INVALID_MPID;
 
 	return possible_cpus[rand() % possible_cpus_cnt];
+#endif
 }
diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk
index a32d3d3..d98cd2a 100644
--- a/spm/cactus/cactus.mk
+++ b/spm/cactus/cactus.mk
@@ -25,6 +25,7 @@
 	$(addprefix spm/cactus/,			\
 		aarch64/cactus_entrypoint.S		\
 		cactus_debug.c				\
+		cactus_ffa_tests.c 			\
 		cactus_main.c				\
 	)						\
 	$(addprefix spm/common/,			\
@@ -35,7 +36,8 @@
 # TODO: Remove dependency on TFTF files.
 CACTUS_SOURCES	+=					\
 	tftf/framework/debug.c				\
-	tftf/framework/${ARCH}/asm_debug.S
+	tftf/framework/${ARCH}/asm_debug.S		\
+	tftf/tests/runtime_services/secure_service/ffa_helpers.c
 
 CACTUS_SOURCES	+= 	drivers/arm/pl011/${ARCH}/pl011_console.S	\
 			lib/${ARCH}/cache_helpers.S			\
@@ -52,6 +54,8 @@
 CACTUS_DEFINES	:=
 
 $(eval $(call add_define,CACTUS_DEFINES,DEBUG))
+$(eval $(call add_define,CACTUS_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,CACTUS_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
 $(eval $(call add_define,CACTUS_DEFINES,FVP_MAX_PE_PER_CPU))
 $(eval $(call add_define,CACTUS_DEFINES,ENABLE_ASSERTIONS))
 $(eval $(call add_define,CACTUS_DEFINES,LOG_LEVEL))
diff --git a/spm/cactus/cactus_debug.c b/spm/cactus/cactus_debug.c
index 91fbfda..43093a6 100644
--- a/spm/cactus/cactus_debug.c
+++ b/spm/cactus/cactus_debug.c
@@ -6,9 +6,9 @@
 
 #include <drivers/arm/pl011.h>
 #include <drivers/console.h>
+#include <sp_helpers.h>
 
 #include "cactus.h"
-#include "ffa_helpers.h"
 
 static int (*putc_impl)(int);
 
diff --git a/spm/cactus/cactus_ffa_tests.c b/spm/cactus/cactus_ffa_tests.c
new file mode 100644
index 0000000..411cc9f
--- /dev/null
+++ b/spm/cactus/cactus_ffa_tests.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <ffa_helpers.h>
+#include <sp_helpers.h>
+
+/* FFA version test helpers */
+#define FFA_MAJOR 1U
+#define FFA_MINOR 0U
+
+void ffa_tests(void)
+{
+	const char *test_ffa = "FFA Interfaces";
+	const char *test_ffa_version = "FFA Version interface";
+
+	announce_test_section_start(test_ffa);
+
+	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)(0xFFFFFFFF & ret.ret0);
+
+	bool ffa_version_compatible = ((spm_version >> FFA_VERSION_MAJOR_SHIFT) == FFA_MAJOR &&
+				       (spm_version & FFA_VERSION_MINOR_MASK) >= FFA_MINOR);
+
+	NOTICE("FFA_VERSION returned %u.%u; Compatible: %i\n",
+		spm_version >> FFA_VERSION_MAJOR_SHIFT,
+		spm_version & FFA_VERSION_MINOR_MASK,
+		(int)ffa_version_compatible);
+
+	expect((int)ffa_version_compatible, (int)true);
+
+	announce_test_end(test_ffa_version);
+
+	announce_test_section_end(test_ffa);
+}
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index d5d923d..49764ec 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -5,21 +5,23 @@
  */
 
 #include <assert.h>
-#include <debug.h>
-#include <drivers/arm/pl011.h>
-#include <drivers/console.h>
 #include <errno.h>
-#include <lib/aarch64/arch_helpers.h>
-#include <lib/xlat_tables/xlat_tables_v2.h>
-#include <lib/xlat_tables/xlat_mmu_helpers.h>
-#include <plat_arm.h>
-#include <plat/common/platform.h>
-#include <platform_def.h>
-#include <std_svc.h>
 
 #include "cactus.h"
 #include "cactus_def.h"
-#include "ffa_helpers.h"
+#include "cactus_tests.h"
+#include <debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <ffa_helpers.h>
+#include <lib/aarch64/arch_helpers.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <sp_helpers.h>
+#include <std_svc.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+#include <platform_def.h>
 
 /* Host machine information injected by the build system in the ELF file. */
 extern const char build_message[];
@@ -187,6 +189,9 @@
 	NOTICE("FFA id: %u\n", ffa_id);
 	cactus_print_memory_layout(ffa_id);
 
+	/* Invoking Tests */
+	ffa_tests();
+
 	/* End up to message loop */
 	message_loop(ffa_id);
 
diff --git a/spm/cactus/cactus_tests.h b/spm/cactus/cactus_tests.h
index f4bcb7e..23586f5 100644
--- a/spm/cactus/cactus_tests.h
+++ b/spm/cactus/cactus_tests.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,6 +12,11 @@
  */
 
 /*
+ * Test to FFA interfaces.
+ */
+void ffa_tests(void);
+
+/*
  * Test other things like the version number returned by SPM.
  */
 void misc_tests(void);
diff --git a/spm/cactus/ffa_helpers.h b/spm/cactus/ffa_helpers.h
deleted file mode 100644
index 8f6beb4..0000000
--- a/spm/cactus/ffa_helpers.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __FFA_HELPERS_H__
-#define __FFA_HELPERS_H__
-
-
-#include <ffa_svc.h>
-#include "tftf_lib.h"
-
-#define SPM_VM_ID_FIRST                 (1)
-
-#define SPM_VM_GET_COUNT                (0xFF01)
-#define SPM_VCPU_GET_COUNT              (0xFF02)
-#define SPM_DEBUG_LOG                   (0xBD000000)
-
-/* Hypervisor ID at physical FFA instance */
-#define HYP_ID          (0)
-
-/* By convention, SP IDs (as opposed to VM IDs) have bit 15 set */
-#define SP_ID(x)        ((x) | (1 << 15))
-
-typedef unsigned short ffa_vm_id_t;
-typedef unsigned short ffa_vm_count_t;
-typedef unsigned short ffa_vcpu_count_t;
-
-/* Functions */
-
-static inline ffa_vcpu_count_t spm_vcpu_get_count(ffa_vm_id_t vm_id)
-{
-	hvc_args args = {
-		.fid = SPM_VCPU_GET_COUNT,
-		.arg1 = vm_id
-	};
-
-	hvc_ret_values ret = tftf_hvc(&args);
-
-	return ret.ret0;
-}
-
-static inline ffa_vm_count_t spm_vm_get_count(void)
-{
-	hvc_args args = {
-		.fid = SPM_VM_GET_COUNT
-	};
-
-	hvc_ret_values ret = tftf_hvc(&args);
-
-	return ret.ret0;
-}
-
-static inline void spm_debug_log(char c)
-{
-	hvc_args args = {
-		.fid = SPM_DEBUG_LOG,
-		.arg1 = c
-	};
-
-	(void)tftf_hvc(&args);
-}
-
-static inline smc_ret_values ffa_id_get(void)
-{
-	smc_args args = {
-		.fid = FFA_ID_GET
-	};
-
-	return tftf_smc(&args);
-}
-
-static inline smc_ret_values ffa_msg_wait(void)
-{
-	smc_args args = {
-		.fid = FFA_MSG_WAIT
-	};
-
-	return tftf_smc(&args);
-}
-
-/* Send response through registers using direct messaging */
-static inline smc_ret_values ffa_msg_send_direct_resp(ffa_vm_id_t sender_vm_id,
-						ffa_vm_id_t target_vm_id,
-						uint32_t message)
-{
-	smc_args args = {
-		.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
-		.arg1 = ((uint32_t)sender_vm_id << 16) | target_vm_id,
-		.arg3 = message
-	};
-
-	return tftf_smc(&args);
-}
-
-static inline smc_ret_values ffa_error(int32_t error_code)
-{
-	smc_args args = {
-		.fid = FFA_ERROR,
-		.arg1 = 0,
-		.arg2 = error_code
-	};
-
-	return tftf_smc(&args);
-}
-
-#endif /* __FFA_HELPERS_H__ */
diff --git a/spm/cactus_mm/cactus_mm.mk b/spm/cactus_mm/cactus_mm.mk
index b96580c..6d69061 100644
--- a/spm/cactus_mm/cactus_mm.mk
+++ b/spm/cactus_mm/cactus_mm.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -53,6 +53,9 @@
 CACTUS_MM_DEFINES	+= -DENABLE_ASSERTIONS=0
 
 $(eval $(call add_define,CACTUS_MM_DEFINES,DEBUG))
+$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
+$(eval $(call add_define,CACTUS_MM_DEFINES,FVP_MAX_PE_PER_CPU))
 $(eval $(call add_define,CACTUS_MM_DEFINES,LOG_LEVEL))
 $(eval $(call add_define,CACTUS_MM_DEFINES,PLAT_${PLAT}))
 
diff --git a/spm/common/sp_helpers.c b/spm/common/sp_helpers.c
index 5aec977..7dc1648 100644
--- a/spm/common/sp_helpers.c
+++ b/spm/common/sp_helpers.c
@@ -9,6 +9,9 @@
 #include <platform_def.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <ffa_svc.h>
+
+#include "sp_helpers.h"
 
 uintptr_t bound_rand(uintptr_t min, uintptr_t max)
 {
@@ -52,7 +55,7 @@
 
 void announce_test_end(const char *test_desc)
 {
-	INFO("Test \"%s\" passed.\n", test_desc);
+	INFO("Test \"%s\" end.\n", test_desc);
 }
 
 void sp_sleep(uint32_t ms)
@@ -67,3 +70,40 @@
 		time2 = mmio_read_64(SYS_CNT_READ_BASE);
 	}
 }
+
+/*******************************************************************************
+ * Hypervisor Calls Wrappers
+ ******************************************************************************/
+
+ffa_vcpu_count_t spm_vcpu_get_count(ffa_vm_id_t vm_id)
+{
+	hvc_args args = {
+		.fid = SPM_VCPU_GET_COUNT,
+		.arg1 = vm_id
+	};
+
+	hvc_ret_values ret = tftf_hvc(&args);
+
+	return ret.ret0;
+}
+
+ffa_vm_count_t spm_vm_get_count(void)
+{
+	hvc_args args = {
+		.fid = SPM_VM_GET_COUNT
+	};
+
+	hvc_ret_values ret = tftf_hvc(&args);
+
+	return ret.ret0;
+}
+
+void spm_debug_log(char c)
+{
+	hvc_args args = {
+		.fid = SPM_DEBUG_LOG,
+		.arg1 = c
+	};
+
+	(void)tftf_hvc(&args);
+}
diff --git a/spm/common/sp_helpers.h b/spm/common/sp_helpers.h
index d06fec3..2b9cc2e 100644
--- a/spm/common/sp_helpers.h
+++ b/spm/common/sp_helpers.h
@@ -8,6 +8,14 @@
 #define SP_HELPERS_H
 
 #include <stdint.h>
+#include <tftf_lib.h>
+#include <ffa_helpers.h>
+
+#define SPM_VM_ID_FIRST                 (1)
+
+#define SPM_VM_GET_COUNT                (0xFF01)
+#define SPM_VCPU_GET_COUNT              (0xFF02)
+#define SPM_DEBUG_LOG                   (0xBD000000)
 
 typedef struct {
 	u_register_t fid;
@@ -57,4 +65,14 @@
 /* Sleep for at least 'ms' milliseconds. */
 void sp_sleep(uint32_t ms);
 
+/*
+ * Hypervisor Calls Wrappers
+ */
+
+ffa_vcpu_count_t spm_vcpu_get_count(ffa_vm_id_t vm_id);
+
+ffa_vm_count_t spm_vm_get_count(void);
+
+void spm_debug_log(char c);
+
 #endif /* SP_HELPERS_H */
diff --git a/spm/ivy/ivy.mk b/spm/ivy/ivy.mk
index 8d5475a..afc89f4 100644
--- a/spm/ivy/ivy.mk
+++ b/spm/ivy/ivy.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -52,6 +52,9 @@
 
 $(eval $(call add_define,IVY_DEFINES,DEBUG))
 $(eval $(call add_define,IVY_DEFINES,ENABLE_ASSERTIONS))
+$(eval $(call add_define,IVY_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,IVY_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
+$(eval $(call add_define,IVY_DEFINES,FVP_MAX_PE_PER_CPU))
 $(eval $(call add_define,IVY_DEFINES,LOG_LEVEL))
 $(eval $(call add_define,IVY_DEFINES,PLAT_${PLAT}))
 
diff --git a/spm/quark/quark.mk b/spm/quark/quark.mk
index 20ddd1f..ec4a3ed 100644
--- a/spm/quark/quark.mk
+++ b/spm/quark/quark.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+# Copyright (c) 2018-2020, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -49,6 +49,9 @@
 
 $(eval $(call add_define,QUARK_DEFINES,DEBUG))
 $(eval $(call add_define,QUARK_DEFINES,ENABLE_ASSERTIONS))
+$(eval $(call add_define,QUARK_DEFINES,FVP_CLUSTER_COUNT))
+$(eval $(call add_define,QUARK_DEFINES,FVP_MAX_CPUS_PER_CLUSTER))
+$(eval $(call add_define,QUARK_DEFINES,FVP_MAX_PE_PER_CPU))
 $(eval $(call add_define,QUARK_DEFINES,PLAT_${PLAT}))
 
 $(QUARK_DTB) : $(BUILD_PLAT)/quark $(BUILD_PLAT)/quark/quark.elf
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 9d19fec..9955c7c 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -106,3 +106,61 @@
 	return __ffa_msg_send_direct_req64_5(source_id, dest_id,
 					      message, 0, 0, 0, 0);
 }
+
+/*
+ * FFA Version ABI helper.
+ * Version fields:
+ *	-Bits[30:16]: Major version.
+ *	-Bits[15:0]: Minor version.
+ */
+smc_ret_values ffa_version(uint32_t input_version)
+{
+	smc_args args = {
+		.fid = FFA_VERSION,
+		.arg1 = input_version
+	};
+
+	return tftf_smc(&args);
+}
+
+smc_ret_values ffa_id_get(void)
+{
+	smc_args args = {
+		.fid = FFA_ID_GET
+	};
+
+	return tftf_smc(&args);
+}
+
+smc_ret_values ffa_msg_wait(void)
+{
+	smc_args args = {
+		.fid = FFA_MSG_WAIT
+	};
+
+	return tftf_smc(&args);
+}
+
+smc_ret_values ffa_msg_send_direct_resp(ffa_vm_id_t source_id,
+						ffa_vm_id_t dest_id,
+						uint32_t message)
+{
+	smc_args args = {
+		.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
+		.arg1 = ((uint32_t)source_id << 16) | dest_id,
+		.arg3 = message
+	};
+
+	return tftf_smc(&args);
+}
+
+smc_ret_values ffa_error(int32_t error_code)
+{
+	smc_args args = {
+		.fid = FFA_ERROR,
+		.arg1 = 0,
+		.arg2 = error_code
+	};
+
+	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 f189054..d14374b 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
@@ -12,12 +12,6 @@
 #include <ffa_svc.h>
 #include <test_helpers.h>
 
-/* Hypervisor ID at physical FFA instance */
-#define HYP_ID		(0)
-
-/* By convention, SP IDs (as opposed to VM IDs) have bit 15 set */
-#define SP_ID(x)	(x | (1 << 15))
-
 #define DIRECT_MSG_TEST_PATTERN1	(0xaaaa0000)
 #define DIRECT_MSG_TEST_PATTERN2	(0xbbbb0000)
 #define DIRECT_MSG_TEST_PATTERN3	(0xcccc0000)
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" />