Merge "fix(fwu): invalidate the data cache for NS_BL1U and NS_BL2U images"
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 332f1d8..9031b34 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -10,6 +10,7 @@
 #include <arch_features.h>
 #include <ffa_svc.h>
 #include <plat_topology.h>
+#include <events.h>
 #include <psci.h>
 #include <spm_common.h>
 #include <tftf_lib.h>
@@ -341,4 +342,14 @@
 	uint32_t ffa_version_minor, const struct ffa_uuid *ffa_uuids,
 	size_t ffa_uuids_size);
 
+/**
+ * Turn on all cpus to execute a test in all.
+ * - 'cpu_on_handler' should have the code containing the test.
+ * - 'cpu_booted' is used for notifying which cores the test has been executed.
+ * This should be used in the test executed by cpu_on_handler at the end of
+ * processing to make sure it complies with this function's implementation.
+ */
+test_result_t spm_run_multi_core_test(uintptr_t cpu_on_handler,
+				      event_t *cpu_booted);
+
 #endif /* __TEST_HELPERS_H__ */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 85e8cd8..4350fbd 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -145,6 +145,11 @@
 #define ID_AA64PFR0_CSV2_SHIFT	U(56)
 #define ID_AA64PFR0_CSV2_MASK	ULL(0xf)
 #define ID_AA64PFR0_CSV2_LENGTH	U(4)
+#define ID_AA64PFR0_FEAT_RME_SHIFT		U(52)
+#define ID_AA64PFR0_FEAT_RME_MASK		ULL(0xf)
+#define ID_AA64PFR0_FEAT_RME_LENGTH		U(4)
+#define ID_AA64PFR0_FEAT_RME_NOT_SUPPORTED	U(0)
+#define ID_AA64PFR0_FEAT_RME_V1			U(1)
 
 /* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */
 #define ID_AA64DFR0_PMS_SHIFT	U(32)
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index edc40f0..1002936 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -125,4 +125,15 @@
 		ID_AA64DFR0_TRACEVER_SUPPORTED;
 }
 
+static inline unsigned int get_armv9_2_feat_rme_support(void)
+{
+	/*
+	 * Return the RME version, zero if not supported.  This function can be
+	 * used as both an integer value for the RME version or compared to zero
+	 * to detect RME presence.
+	 */
+	return (unsigned int)(read_id_aa64pfr0_el1() >>
+		ID_AA64PFR0_FEAT_RME_SHIFT) & ID_AA64PFR0_FEAT_RME_MASK;
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h
index eba1c9e..b25b6a1 100644
--- a/include/runtime_services/ffa_helpers.h
+++ b/include/runtime_services/ffa_helpers.h
@@ -70,6 +70,9 @@
 
 #define FFA_NOTIFICATIONS_FLAG_PER_VCPU	UINT32_C(0x1 << 0)
 
+/** Flag to delay Schedule Receiver Interrupt. */
+#define FFA_NOTIFICATIONS_FLAG_DELAY_SRI	UINT32_C(0x1 << 1)
+
 #define FFA_NOTIFICATIONS_FLAGS_VCPU_ID(id) UINT32_C((id & 0xFFFF) << 16)
 
 #define FFA_NOTIFICATIONS_FLAG_BITMAP_SP	UINT32_C(0x1 << 0)
@@ -93,6 +96,38 @@
 	return FFA_NOTIFICATIONS_BITMAP(val.ret4, val.ret5);
 }
 
+/*
+ * FFA_NOTIFICATION_INFO_GET is a SMC64 interface.
+ * The following macros are defined for SMC64 implementation.
+ */
+#define FFA_NOTIFICATIONS_INFO_GET_MAX_IDS		20U
+
+#define FFA_NOTIFICATIONS_INFO_GET_FLAG_MORE_PENDING	UINT64_C(0x1)
+
+#define FFA_NOTIFICATIONS_LISTS_COUNT_SHIFT		0x7U
+#define FFA_NOTIFICATIONS_LISTS_COUNT_MASK		0x1FU
+#define FFA_NOTIFICATIONS_LIST_SHIFT(l) 		(2 * (l - 1) + 12)
+#define FFA_NOTIFICATIONS_LIST_SIZE_MASK 		0x3U
+
+static inline uint32_t ffa_notifications_info_get_lists_count(
+	smc_ret_values ret)
+{
+	return (uint32_t)(ret.ret2 >> FFA_NOTIFICATIONS_LISTS_COUNT_SHIFT)
+	       & FFA_NOTIFICATIONS_LISTS_COUNT_MASK;
+}
+
+static inline uint32_t ffa_notifications_info_get_list_size(
+	smc_ret_values ret, uint32_t list)
+{
+	return (uint32_t)(ret.ret2 >> FFA_NOTIFICATIONS_LIST_SHIFT(list)) &
+	       FFA_NOTIFICATIONS_LIST_SIZE_MASK;
+}
+
+static inline bool ffa_notifications_info_get_more_pending(smc_ret_values ret)
+{
+	return (ret.ret2 & FFA_NOTIFICATIONS_INFO_GET_FLAG_MORE_PENDING) != 0U;
+}
+
 enum ffa_data_access {
 	FFA_DATA_ACCESS_NOT_SPECIFIED,
 	FFA_DATA_ACCESS_RO,
@@ -473,6 +508,7 @@
 				    ffa_notification_bitmap_t bitmap);
 smc_ret_values ffa_notification_get(ffa_id_t receiver, uint32_t vcpu_id,
 				    uint32_t flags);
+smc_ret_values ffa_notification_info_get(void);
 #endif /* __ASSEMBLY__ */
 
 #endif /* FFA_HELPERS_H */
diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h
index df19f98..4a62a79 100644
--- a/include/runtime_services/ffa_svc.h
+++ b/include/runtime_services/ffa_svc.h
@@ -12,13 +12,15 @@
 #include <uuid.h>
 
 /* FFA error codes. */
-#define FFA_ERROR_NOT_SUPPORTED	-1
+#define FFA_ERROR_NOT_SUPPORTED		-1
 #define FFA_ERROR_INVALID_PARAMETER	-2
 #define FFA_ERROR_NO_MEMORY		-3
 #define FFA_ERROR_BUSY			-4
 #define FFA_ERROR_INTERRUPTED		-5
 #define FFA_ERROR_DENIED		-6
-#define FFA_ERROR_RETRY		-7
+#define FFA_ERROR_RETRY			-7
+#define FFA_ERROR_ABORTED		-8
+#define FFA_ERROR_NO_DATA		-9
 
 /* The macros below are used to identify FFA calls from the SMC function ID */
 #define FFA_FNUM_MIN_VALUE	U(0x60)
@@ -135,6 +137,8 @@
 #define FFA_NOTIFICATION_UNBIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_UNBIND)
 #define FFA_NOTIFICATION_SET	FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_SET)
 #define FFA_NOTIFICATION_GET	FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_GET)
+#define FFA_NOTIFICATION_INFO_GET \
+	FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_INFO_GET)
 #define FFA_SPM_ID_GET		FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
 
 /* FFA SMC64 FIDs */
@@ -151,7 +155,8 @@
 	FFA_FID(SMC_64, FFA_FNUM_MEM_RETRIEVE_REQ)
 #define FFA_SECONDARY_EP_REGISTER_SMC64 \
 	FFA_FID(SMC_64, FFA_FNUM_SECONDARY_EP_REGISTER)
-
+#define FFA_NOTIFICATION_INFO_GET_SMC64 \
+	FFA_FID(SMC_64, FFA_FNUM_NOTIFICATION_INFO_GET)
 /*
  * Reserve a special value for traffic targeted to the Hypervisor or SPM.
  */
diff --git a/include/runtime_services/realm_payload/realm_payload_test.h b/include/runtime_services/realm_payload/realm_payload_test.h
new file mode 100644
index 0000000..eccdbb3
--- /dev/null
+++ b/include/runtime_services/realm_payload/realm_payload_test.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <smccc.h>
+#include <tftf_lib.h>
+
+#define RMI_FNUM_MIN_VALUE	U(0x00)
+#define RMI_FNUM_MAX_VALUE	U(0x20)
+
+/* Get RMI fastcall std FID from function number */
+#define RMI_FID(smc_cc, func_num)			\
+	((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)	|	\
+	((smc_cc) << FUNCID_CC_SHIFT)		|	\
+	(OEN_ARM_START << FUNCID_OEN_SHIFT)	|	\
+	((func_num) << FUNCID_NUM_SHIFT))
+
+/*
+ * SMC_RMM_INIT_COMPLETE is the only function in the RMI that originates from
+ * the Realm world and is handled by the RMMD. The remaining functions are
+ * always invoked by the Normal world, forwarded by RMMD and handled by the
+ * RMM
+ */
+#define RMI_FNUM_VERSION_REQ		U(0)
+
+#define RMI_FNUM_GRAN_NS_REALM		U(1)
+#define RMI_FNUM_GRAN_REALM_NS		U(0x10)
+
+/********************************************************************************/
+
+
+/* RMI SMC64 FIDs handled by the RMMD */
+#define RMI_RMM_REQ_VERSION		RMI_FID(SMC_64, RMI_FNUM_VERSION_REQ)
+
+#define SMC_RMM_GRANULE_DELEGATE	RMI_FID(SMC_64, RMI_FNUM_GRAN_NS_REALM)
+#define SMC_RMM_GRANULE_UNDELEGATE	RMI_FID(SMC_64, RMI_FNUM_GRAN_REALM_NS)
+
+#define RMI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
+#define RMI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
+
+#define NUM_GRANULES			5
+#define NUM_RANDOM_ITERATIONS		7
+#define GRANULE_SIZE			4096
+
+#define B_DELEGATED			0
+#define B_UNDELEGATED			1
+
+#define NUM_CPU_DED_SPM			PLATFORM_CORE_COUNT / 2
+
+u_register_t realm_version(void);
+u_register_t realm_granule_delegate(uintptr_t);
+u_register_t realm_granule_undelegate(uintptr_t);
diff --git a/tftf/tests/common/test_helpers.c b/tftf/tests/common/test_helpers.c
index fffad67..80497bd 100644
--- a/tftf/tests/common/test_helpers.c
+++ b/tftf/tests/common/test_helpers.c
@@ -176,3 +176,46 @@
 
 	return TEST_RESULT_SUCCESS;
 }
+
+test_result_t spm_run_multi_core_test(uintptr_t cpu_on_handler,
+				      event_t *cpu_done)
+{
+	unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int core_pos, cpu_node, mpidr;
+	int32_t ret;
+
+	VERBOSE("Powering on all cpus.\n");
+
+	for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+		tftf_init_event(&cpu_done[i]);
+	}
+
+	for_each_cpu(cpu_node) {
+		mpidr = tftf_get_mpidr_from_node(cpu_node);
+		if (mpidr == lead_mpid) {
+			continue;
+		}
+
+		ret = tftf_cpu_on(mpidr, cpu_on_handler, 0U);
+		if (ret != 0) {
+			ERROR("tftf_cpu_on mpidr 0x%x returns %d\n",
+			      mpidr, ret);
+		}
+	}
+
+	VERBOSE("Waiting secondary CPUs to turn off ...\n");
+
+	for_each_cpu(cpu_node) {
+		mpidr = tftf_get_mpidr_from_node(cpu_node);
+		if (mpidr == lead_mpid) {
+			continue;
+		}
+
+		core_pos = platform_get_core_pos(mpidr);
+		tftf_wait_for_event(&cpu_done[core_pos]);
+	}
+
+	VERBOSE("Done exiting.\n");
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
new file mode 100644
index 0000000..e552ecb
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
@@ -0,0 +1,386 @@
+#include <stdlib.h>
+
+#include <debug.h>
+#include <smccc.h>
+
+#include <arch_helpers.h>
+#include <cactus_test_cmds.h>
+#include <ffa_endpoints.h>
+#include <ffa_svc.h>
+#include <lib/events.h>
+#include <lib/power_management.h>
+#include <platform.h>
+#include <test_helpers.h>
+
+#include <plat_topology.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_del_undel(void);
+
+#define ECHO_VAL1 U(0xa0a0a0a0)
+#define ECHO_VAL2 U(0xb0b0b0b0)
+#define ECHO_VAL3 U(0xc0c0c0c0)
+
+/* Buffer to delegate and undelegate */
+static char bufferdelegate[NUM_GRANULES * GRANULE_SIZE * PLATFORM_CORE_COUNT] __aligned(GRANULE_SIZE);
+static char bufferstate[NUM_GRANULES * PLATFORM_CORE_COUNT];
+static int cpu_test_spm_rmi[PLATFORM_CORE_COUNT];
+
+/*
+ * The following test conducts SPM(direct messaging) tests on a subset of selected CPUs while
+ * simultaneously performing another set of tests of the RMI(delelgation)
+ * on the remaining CPU's to the full platform count. Once that test completes
+ * the same test is run again with a different assignment for what CPU does
+ * SPM versus RMI.
+ */
+
+/*
+ * Function that randomizes the CPU assignment of tests, SPM or RMI
+ */
+static void rand_cpu_spm_rmi(void)
+{
+	int fentry;
+	int seln;
+	for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+		cpu_test_spm_rmi[i] = -1;
+	}
+	for (int i = 0; i < NUM_CPU_DED_SPM; i++) {
+		fentry = 0;
+		while (fentry == 0) {
+			seln = (rand() % (PLATFORM_CORE_COUNT - 1)) + 1;
+			if (cpu_test_spm_rmi[seln] == -1) {
+				cpu_test_spm_rmi[seln] = 1;
+				fentry = 1;
+			}
+		}
+	}
+	for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+		if (cpu_test_spm_rmi[i] == -1) {
+			cpu_test_spm_rmi[i] = 0;
+		}
+	}
+}
+
+/*
+ * Get function to determine what has been assigned to a given CPU
+ */
+static int spm_rmi_test(unsigned int mpidr)
+{
+	return cpu_test_spm_rmi[platform_get_core_pos(mpidr)];
+}
+
+/*
+ * RMI function to randomize the initial state of granules allocated for the test.
+ * A certain subset will be delegated leaving the rest undelegated
+ */
+static test_result_t init_buffer_del_spm_rmi(void)
+{
+	u_register_t retrmm;
+
+	for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+		if ((rand() % 2) == 0) {
+			retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+			bufferstate[i] = B_DELEGATED;
+			if (retrmm != 0UL) {
+				tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+				return TEST_RESULT_FAIL;
+			}
+		} else {
+			bufferstate[i] = B_UNDELEGATED;
+		}
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * SPM functions for the direct messaging
+ */
+static const struct ffa_uuid expected_sp_uuids[] = {
+		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
+	};
+
+
+static event_t cpu_booted[PLATFORM_CORE_COUNT];
+
+static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
+					  ffa_id_t dest,
+					  uint64_t value)
+{
+	smc_ret_values ret;
+	ret = cactus_echo_send_cmd(sender, dest, value);
+
+	/*
+	 * Return responses may be FFA_MSG_SEND_DIRECT_RESP or FFA_INTERRUPT,
+	 * but only expect the former. Expect SMC32 convention from SP.
+	 */
+	if (!is_ffa_direct_response(ret)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (cactus_get_response(ret) != CACTUS_SUCCESS ||
+	    cactus_echo_get_val(ret) != value) {
+		ERROR("Echo Failed!\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * Handler that is passed during tftf_cpu_on to individual CPU cores.
+ * Runs a specific core and send a direct message request.
+ * Expects core_pos | SP_ID as a response.
+ */
+static test_result_t run_spm_direct_message(void)
+{
+	unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int core_pos = platform_get_core_pos(mpid);
+	test_result_t ret = TEST_RESULT_SUCCESS;
+	smc_ret_values ffa_ret;
+
+	/*
+	 * Send a direct message request to SP1 (MP SP) from current physical
+	 * CPU. Notice SP1 ECs are already woken as a result of the PSCI_CPU_ON
+	 * invocation so they already reached the message loop.
+	 * The SPMC uses the MP pinned context corresponding to the physical
+	 * CPU emitting the request.
+	 */
+	ret = send_cactus_echo_cmd(HYP_ID, SP_ID(1), ECHO_VAL1);
+	if (ret != TEST_RESULT_SUCCESS) {
+		goto out;
+	}
+
+	/*
+	 * Secure Partitions beyond the first SP only have their first
+	 * EC (or vCPU0) woken up at boot time by the SPMC.
+	 * Other ECs need one round of ffa_run to reach the message loop.
+	 */
+	ffa_ret = ffa_run(SP_ID(2), core_pos);
+	if (ffa_func_id(ffa_ret) != FFA_MSG_WAIT) {
+		ERROR("Failed to run SP%x on core %u\n", SP_ID(2),
+				core_pos);
+		ret = TEST_RESULT_FAIL;
+		goto out;
+	}
+
+	/*
+	 * Send a direct message request to SP2 (MP SP) from current physical
+	 * CPU. The SPMC uses the MP pinned context corresponding to the
+	 * physical CPU emitting the request.
+	 */
+	ret = send_cactus_echo_cmd(HYP_ID, SP_ID(2), ECHO_VAL2);
+	if (ret != TEST_RESULT_SUCCESS) {
+		goto out;
+	}
+
+	/*
+	 * Send a direct message request to SP3 (UP SP) from current physical CPU.
+	 * The SPMC uses the single vCPU migrated to the new physical core.
+	 * The single SP vCPU may receive requests from multiple physical CPUs.
+	 * Thus it is possible one message is being processed on one core while
+	 * another (or multiple) cores attempt sending a new direct message
+	 * request. In such case the cores attempting the new request receive
+	 * a busy response from the SPMC. To handle this case a retry loop is
+	 * implemented permitting some fairness.
+	 */
+	uint32_t trial_loop = 5U;
+	while (trial_loop--) {
+		ffa_ret = cactus_echo_send_cmd(HYP_ID, SP_ID(3), ECHO_VAL3);
+		if ((ffa_func_id(ffa_ret) == FFA_ERROR) &&
+		    (ffa_error_code(ffa_ret) == FFA_ERROR_BUSY)) {
+			VERBOSE("%s(%u) trial %u\n", __func__, core_pos, trial_loop);
+			waitms(1);
+			continue;
+		}
+
+		if (is_ffa_direct_response(ffa_ret) == true) {
+			if (cactus_get_response(ffa_ret) != CACTUS_SUCCESS ||
+				cactus_echo_get_val(ffa_ret) != ECHO_VAL3) {
+				ERROR("Echo Failed!\n");
+				ret = TEST_RESULT_FAIL;
+			}
+
+			goto out;
+		}
+	}
+
+	ret = TEST_RESULT_FAIL;
+
+out:
+	/* Tell the lead CPU that the calling CPU has completed the test */
+	tftf_send_event(&cpu_booted[core_pos]);
+
+	return ret;
+}
+#endif
+
+/*
+ * Test function to dispatch a number of SPM and RMI tests to the platform
+ * number of CPU's.  The test is run twice on a another set of randomly determined
+ * CPU's.
+ */
+test_result_t test_ffa_secondary_core_direct_realm_msg(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int cpu_node, mpidr;
+	int32_t ret;
+
+	/**********************************************************************
+	 * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+	 **********************************************************************/
+	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+	for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+		tftf_init_event(&cpu_booted[i]);
+	}
+
+	/*
+	 * Randomize the assignment of the CPU's to either SPM or RMI
+	 */
+	rand_cpu_spm_rmi();
+
+	/*
+	 * Randomize the initial state of the RMI granules to realm or non-secure
+	 */
+	if (init_buffer_del_spm_rmi() == TEST_RESULT_FAIL) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/*
+	 * Main test to run both SPM and RMI together
+	 */
+	for_each_cpu(cpu_node) {
+		mpidr = tftf_get_mpidr_from_node(cpu_node);
+		if (mpidr == lead_mpid) {
+			continue;
+		}
+
+		if (spm_rmi_test(mpidr) == 1) {
+			ret = tftf_cpu_on(mpidr, (uintptr_t)run_spm_direct_message, 0U);
+			if (ret != 0) {
+				ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+				return TEST_RESULT_FAIL;
+			}
+		} else {
+			ret = tftf_cpu_on(mpidr,
+				(uintptr_t)realm_multi_cpu_payload_del_undel, 0);
+
+			if (ret != PSCI_E_SUCCESS) {
+				ERROR("CPU ON failed for 0x%llx\n",
+					(unsigned long long)mpidr);
+				return TEST_RESULT_FAIL;
+			}
+		}
+	}
+
+	VERBOSE("Waiting for secondary CPUs to turn off ...\n");
+
+	for_each_cpu(cpu_node) {
+		mpidr = tftf_get_mpidr_from_node(cpu_node);
+		if (mpidr == lead_mpid) {
+			continue;
+		}
+
+		while (tftf_psci_affinity_info(mpidr, MPIDR_AFFLVL0) !=
+				PSCI_STATE_OFF) {
+				continue;
+		}
+	}
+
+	/*
+	 * Randomize the CPU's again
+	 */
+	rand_cpu_spm_rmi();
+
+	/*
+	 * Run test again
+	 */
+	for_each_cpu(cpu_node) {
+		mpidr = tftf_get_mpidr_from_node(cpu_node);
+		if (mpidr == lead_mpid) {
+			continue;
+		}
+
+		if (spm_rmi_test(mpidr) == 1) {
+			ret = tftf_cpu_on(mpidr, (uintptr_t)run_spm_direct_message, 0U);
+			if (ret != 0) {
+				ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+				return TEST_RESULT_FAIL;
+			}
+		} else {
+			ret = tftf_cpu_on(mpidr,
+				(uintptr_t)realm_multi_cpu_payload_del_undel, 0);
+
+			if (ret != PSCI_E_SUCCESS) {
+				ERROR("CPU ON failed for 0x%llx\n",
+					(unsigned long long)mpidr);
+				return TEST_RESULT_FAIL;
+			}
+		}
+	}
+
+	VERBOSE("Waiting for secondary CPUs to turn off ...\n");
+
+	for_each_cpu(cpu_node) {
+		mpidr = tftf_get_mpidr_from_node(cpu_node);
+		if (mpidr == lead_mpid) {
+			continue;
+		}
+
+		while (tftf_psci_affinity_info(mpidr, MPIDR_AFFLVL0) !=
+				PSCI_STATE_OFF) {
+			continue;
+		}
+
+	}
+
+	VERBOSE("Done exiting.\n");
+
+	/**********************************************************************
+	 * All tests passed.
+	 **********************************************************************/
+
+	return TEST_RESULT_SUCCESS;
+#endif
+}
+
+#ifdef __aarch64__
+/*
+ * Multi CPU testing of delegate and undelegate of granules
+ * The granules are first randomly initialized to either realm or non secure
+ * using the function init_buffer_del and then the function below
+ * assigns NUM_GRANULES to each CPU for delegation or undelgation
+ * depending upon the initial state
+ */
+static test_result_t realm_multi_cpu_payload_del_undel(void)
+{
+	u_register_t retrmm;
+	unsigned int cpu_node;
+
+	cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+	for (int i = 0; i < NUM_GRANULES; i++) {
+		if (bufferstate[((cpu_node * NUM_GRANULES) + i)] == B_UNDELEGATED) {
+			retrmm = realm_granule_delegate((u_register_t)
+					&bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+			bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_DELEGATED;
+		} else {
+			retrmm = realm_granule_undelegate((u_register_t)
+					&bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+			bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_UNDELEGATED;
+		}
+		if (retrmm != 0UL) {
+			tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+			return TEST_RESULT_FAIL;
+		}
+	}
+	return TEST_RESULT_SUCCESS;
+}
+#endif
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
new file mode 100644
index 0000000..d1063f4
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <plat_topology.h>
+#include <power_management.h>
+#include <platform.h>
+#include <runtime_services/realm_payload/realm_payload_test.h>
+#include <test_helpers.h>
+
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_test(void);
+static test_result_t realm_multi_cpu_payload_del_undel(void);
+
+/* Buffer to delegate and undelegate */
+static char bufferdelegate[NUM_GRANULES * GRANULE_SIZE * PLATFORM_CORE_COUNT] __aligned(GRANULE_SIZE);
+static char bufferstate[NUM_GRANULES * PLATFORM_CORE_COUNT];
+#endif
+
+/*
+ * Overall test for realm payload in three sections:
+ * 1. Single CPU version check: SMC call to realm payload to return
+ * version information
+ * 2. Multi CPU version check: SMC call to realm payload to return
+ * version information from all CPU's in system
+ * 3. Delegate and Undelegate Non-Secure granule via
+ * SMC call to realm payload
+ * 4. Multi CPU delegation where random assignment of states
+ * (realm, non-secure)is assigned to a set of granules.
+ * Each CPU is given a number of granules to delegate in
+ * parallel with the other CPU's
+ * 5. Fail testing of delegation parameters such as
+ * attempting to perform a delegation on the same granule
+ * twice and then testing a misaligned address
+ */
+
+#ifdef __aarch64__
+test_result_t init_buffer_del(void)
+{
+	u_register_t retrmm;
+
+	for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+		if ((rand() % 2) == 0) {
+			retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+			bufferstate[i] = B_DELEGATED;
+			if (retrmm != 0UL) {
+				tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+				return TEST_RESULT_FAIL;
+			}
+		} else {
+			bufferstate[i] = B_UNDELEGATED;
+		}
+	}
+	return TEST_RESULT_SUCCESS;
+}
+#endif
+
+/*
+ * Single CPU version check function
+ */
+test_result_t realm_version_single_cpu(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+	u_register_t retrmm;
+
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	retrmm = realm_version();
+
+	tftf_testcase_printf("RMM version is: %lu.%lu\n",
+			RMI_ABI_VERSION_GET_MAJOR(retrmm),
+			RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+	return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/*
+ * Multi CPU version check function in parallel.
+ */
+test_result_t realm_version_multi_cpu(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+	u_register_t lead_mpid, target_mpid;
+	int cpu_node;
+	long long ret;
+
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		ret = tftf_cpu_on(target_mpid,
+			(uintptr_t)realm_multi_cpu_payload_test, 0);
+
+		if (ret != PSCI_E_SUCCESS) {
+			ERROR("CPU ON failed for 0x%llx\n",
+				(unsigned long long)target_mpid);
+			return TEST_RESULT_FAIL;
+		}
+
+	}
+
+	ret = realm_multi_cpu_payload_test();
+
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+				PSCI_STATE_OFF) {
+			continue;
+		}
+	}
+
+	return ret;
+#endif
+}
+
+/*
+ * Delegate and Undelegate Non Secure Granule
+ */
+test_result_t realm_delegate_undelegate(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+	u_register_t retrmm;
+
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	retrmm = realm_granule_delegate((u_register_t)bufferdelegate);
+	if (retrmm != 0UL) {
+		tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+	retrmm = realm_granule_undelegate((u_register_t)bufferdelegate);
+	if (retrmm != 0UL) {
+		tftf_testcase_printf("Undelegate operation returns fail, %lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+	tftf_testcase_printf("Delegate and undelegate of buffer 0x%lx succeeded\n",
+			(uintptr_t)bufferdelegate);
+
+	return TEST_RESULT_SUCCESS;
+#endif
+}
+
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_test(void)
+{
+	u_register_t retrmm = realm_version();
+
+	tftf_testcase_printf("Multi CPU RMM version on CPU %llx is: %lu.%lu\n",
+			read_mpidr_el1() & MPID_MASK, RMI_ABI_VERSION_GET_MAJOR(retrmm),
+			RMI_ABI_VERSION_GET_MINOR(retrmm));
+
+	return TEST_RESULT_SUCCESS;
+}
+#endif
+
+/*
+ * Select all CPU's to randomly delegate/undelegate
+ * granule pages to stress the delegate mechanism
+ */
+test_result_t realm_delundel_multi_cpu(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+	u_register_t lead_mpid, target_mpid;
+	int cpu_node;
+	long long ret;
+
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	if (init_buffer_del() == TEST_RESULT_FAIL) {
+		return TEST_RESULT_FAIL;
+	}
+
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		ret = tftf_cpu_on(target_mpid,
+			(uintptr_t)realm_multi_cpu_payload_del_undel, 0);
+
+		if (ret != PSCI_E_SUCCESS) {
+			ERROR("CPU ON failed for 0x%llx\n",
+				(unsigned long long)target_mpid);
+			return TEST_RESULT_FAIL;
+		}
+
+	}
+
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+				PSCI_STATE_OFF) {
+			continue;
+		}
+	}
+
+	ret = TEST_RESULT_SUCCESS;
+	return ret;
+#endif
+}
+
+/*
+ * Multi CPU testing of delegate and undelegate of granules
+ * The granules are first randomly initialized to either realm or non secure
+ * using the function init_buffer_del and then the function below
+ * assigns NUM_GRANULES to each CPU for delegation or undelgation
+ * depending upon the initial state
+ */
+#ifdef __aarch64__
+static test_result_t realm_multi_cpu_payload_del_undel(void)
+{
+	u_register_t retrmm;
+	unsigned int cpu_node;
+
+	cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+	for (int i = 0; i < NUM_GRANULES; i++) {
+		if (bufferstate[((cpu_node * NUM_GRANULES) + i)] == B_UNDELEGATED) {
+			retrmm = realm_granule_delegate((u_register_t)
+					&bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+			bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_DELEGATED;
+		} else {
+			retrmm = realm_granule_undelegate((u_register_t)
+					&bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+			bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_UNDELEGATED;
+		}
+		if (retrmm != 0UL) {
+			tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+			return TEST_RESULT_FAIL;
+		}
+	}
+	return TEST_RESULT_SUCCESS;
+}
+#endif
+
+/*Fail testing of delegation process. The first is an error expected
+ * for processing the same granule twice and the second is submission of
+ * a misaligned address
+ */
+
+test_result_t realm_fail_del(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+	u_register_t retrmm;
+
+	retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+	retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+
+	if (retrmm == 0UL) {
+		tftf_testcase_printf
+			("Delegate operation does not fail as expected for double delegation, %lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[1]);
+
+	if (retrmm == 0UL) {
+		tftf_testcase_printf
+			("Delegate operation does not return fail for misaligned address, %lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+#endif
+}
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c b/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c
new file mode 100644
index 0000000..e6aa10b
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test_helpers.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <runtime_services/realm_payload/realm_payload_test.h>
+
+u_register_t realm_version(void)
+{
+	smc_args args = { RMI_RMM_REQ_VERSION };
+	smc_ret_values ret;
+
+	ret = tftf_smc(&args);
+	return ret.ret0;
+}
+
+u_register_t realm_granule_delegate(u_register_t add)
+{
+	smc_args args = { 0 };
+	smc_ret_values ret;
+
+	args.fid = SMC_RMM_GRANULE_DELEGATE;
+	args.arg1 = add;
+
+	ret = tftf_smc(&args);
+	return ret.ret0;
+}
+
+u_register_t realm_granule_undelegate(u_register_t add)
+{
+	smc_args args = { 0 };
+	smc_ret_values ret;
+
+	args.fid = SMC_RMM_GRANULE_UNDELEGATE;
+	args.arg1 = add;
+
+	ret = tftf_smc(&args);
+	return ret.ret0;
+}
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index 6011d8b..cbc028e 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -607,3 +607,19 @@
 
 	return tftf_smc(&args);
 }
+
+smc_ret_values ffa_notification_info_get(void)
+{
+	smc_args args = {
+		.fid = FFA_NOTIFICATION_INFO_GET_SMC64,
+		.arg1 = FFA_PARAM_MBZ,
+		.arg2 = FFA_PARAM_MBZ,
+		.arg3 = FFA_PARAM_MBZ,
+		.arg4 = FFA_PARAM_MBZ,
+		.arg5 = FFA_PARAM_MBZ,
+		.arg6 = FFA_PARAM_MBZ,
+		.arg7 = FFA_PARAM_MBZ
+	};
+
+	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 1b9abe9..fb76362 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
@@ -24,7 +24,6 @@
 		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
 	};
 
-
 static event_t cpu_booted[PLATFORM_CORE_COUNT];
 
 static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
@@ -165,7 +164,6 @@
 /**
  * Handler that is passed during tftf_cpu_on to individual CPU cores.
  * Runs a specific core and send a direct message request.
- * Expects core_pos | SP_ID as a response.
  */
 static test_result_t cpu_on_handler(void)
 {
@@ -255,48 +253,9 @@
  */
 test_result_t test_ffa_secondary_core_direct_msg(void)
 {
-	unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
-	unsigned int core_pos, cpu_node, mpidr;
-	int32_t ret;
-
 	/**********************************************************************
 	 * Check SPMC has ffa_version and expected FFA endpoints are deployed.
 	 **********************************************************************/
 	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
-
-	for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
-		tftf_init_event(&cpu_booted[i]);
-	}
-
-	for_each_cpu(cpu_node) {
-		mpidr = tftf_get_mpidr_from_node(cpu_node);
-		if (mpidr == lead_mpid) {
-			continue;
-		}
-
-		ret = tftf_cpu_on(mpidr, (uintptr_t)cpu_on_handler, 0U);
-		if (ret != 0) {
-			ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
-		}
-	}
-
-	VERBOSE("Waiting secondary CPUs to turn off ...\n");
-
-	for_each_cpu(cpu_node) {
-		mpidr = tftf_get_mpidr_from_node(cpu_node);
-		if (mpidr == lead_mpid) {
-			continue;
-		}
-
-		core_pos = platform_get_core_pos(mpidr);
-		tftf_wait_for_event(&cpu_booted[core_pos]);
-	}
-
-	VERBOSE("Done exiting.\n");
-
-	/**********************************************************************
-	 * All tests passed.
-	 **********************************************************************/
-
-	return TEST_RESULT_SUCCESS;
+	return spm_run_multi_core_test((uintptr_t)cpu_on_handler, cpu_booted);
 }
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
index 85a93a6..2245895 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
@@ -15,6 +15,23 @@
 #include <spm_common.h>
 #include <test_helpers.h>
 
+/**
+ * Defining variables to test the per-vCPU notifications.
+ * The conceived test follows the same logic, despite the sender receiver type
+ * of endpoint (VM or secure partition).
+ * Using global variables because these need to be accessed in the cpu on handler
+ * function 'request_notification_get_per_vcpu_on_handler'.
+ * In each specific test function, change 'per_vcpu_receiver' and
+ * 'per_vcpu_sender' have the logic work for:
+ * - NWd to SP;
+ * - SP to NWd;
+ * - SP to SP.
+ */
+static ffa_id_t per_vcpu_receiver;
+static ffa_id_t per_vcpu_sender;
+uint32_t per_vcpu_flags_get;
+static event_t per_vcpu_finished[PLATFORM_CORE_COUNT];
+
 static const struct ffa_uuid expected_sp_uuids[] = {
 		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
 };
@@ -444,6 +461,41 @@
 	return true;
 }
 
+static bool is_notifications_info_get_as_expected(
+	smc_ret_values *ret, uint16_t *ids, uint32_t *lists_sizes,
+	const uint32_t max_ids_count, uint32_t lists_count, bool more_pending)
+{
+	if (lists_count != ffa_notifications_info_get_lists_count(*ret) ||
+	    more_pending != ffa_notifications_info_get_more_pending(*ret)) {
+		ERROR("Notification info get not as expected.\n"
+		      "    Lists counts: %u; more pending %u\n",
+		      ffa_notifications_info_get_lists_count(*ret),
+		      ffa_notifications_info_get_more_pending(*ret));
+		dump_smc_ret_values(*ret);
+		return false;
+	}
+
+	for (uint32_t i = 0; i < lists_count; i++) {
+		uint32_t cur_size =
+				ffa_notifications_info_get_list_size(*ret,
+								     i + 1);
+
+		if (lists_sizes[i] != cur_size) {
+			ERROR("Expected list size[%u] %u != %u\n", i,
+			      lists_sizes[i], cur_size);
+			return false;
+		}
+	}
+
+	/* Compare the IDs list */
+	if (memcmp(&ret->ret3, ids, sizeof(ids[0]) * max_ids_count) != 0) {
+		ERROR("List of IDs not as expected\n");
+		return false;
+	}
+
+	return true;
+}
+
 /**
  * Helper to bind notification and set it.
  * If receiver is SP it will request SP to perform the bind, else invokes
@@ -509,21 +561,60 @@
 						receiver);
 }
 
+static bool notifications_info_get(
+	uint16_t *expected_ids, uint32_t expected_lists_count,
+	uint32_t *expected_lists_sizes, const uint32_t max_ids_count,
+	bool expected_more_pending)
+{
+	smc_ret_values ret;
+
+	VERBOSE("Getting pending notification's info.\n");
+
+	ret = ffa_notification_info_get();
+
+	return !is_ffa_call_error(ret) &&
+		is_notifications_info_get_as_expected(&ret, expected_ids,
+						      expected_lists_sizes,
+						      max_ids_count,
+						      expected_lists_count,
+						      expected_more_pending);
+}
+
 /**
  * Test to validate a VM can signal an SP.
  */
 test_result_t test_ffa_notifications_vm_signals_sp(void)
 {
-	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
 	const ffa_id_t sender = 1;
 	const ffa_id_t receiver = SP_ID(1);
-	ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(1) | FFA_NOTIFICATION(60);
+	ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(1) |
+						  FFA_NOTIFICATION(60);
 	const uint32_t flags_get = FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
 
+	/* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+	uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+	uint32_t lists_count;
+	uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+	const bool more_notif_pending = false;
+
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
 	if (!notification_bind_and_set(sender, receiver, notifications, 0)) {
 		return TEST_RESULT_FAIL;
 	}
 
+	/**
+	 * Simple list of IDs expected on return from FFA_NOTIFICATION_INFO_GET.
+	 */
+	ids[0] = receiver;
+	lists_count = 1;
+
+	if (!notifications_info_get(ids, lists_count, lists_sizes,
+				    FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+				    more_notif_pending)) {
+		return TEST_RESULT_FAIL;
+	}
+
 	if (!notification_get_and_validate(receiver, 0, notifications, 0,
 					   flags_get)) {
 		return TEST_RESULT_FAIL;
@@ -542,17 +633,36 @@
  */
 test_result_t test_ffa_notifications_sp_signals_sp(void)
 {
-	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
 	const ffa_id_t sender = SP_ID(1);
 	const ffa_id_t receiver = SP_ID(2);
 	uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
 
-	/** Request receiver to bind a set of notifications to the sender */
+	/* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+	uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+	uint32_t lists_count;
+	uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	/* Request receiver to bind a set of notifications to the sender. */
 	if (!notification_bind_and_set(sender, receiver,
 					       g_notifications, 0)) {
 		return TEST_RESULT_FAIL;
 	}
 
+	/*
+	 * FFA_NOTIFICATION_INFO_GET return list should be simple, containing
+	 * only the receiver's ID.
+	 */
+	ids[0] = receiver;
+	lists_count = 1;
+
+	if (!notifications_info_get(ids, lists_count, lists_sizes,
+				    FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+				    false)) {
+		return TEST_RESULT_FAIL;
+	}
+
 	if (!notification_get_and_validate(receiver, g_notifications, 0, 0,
 					   get_flags)) {
 		return TEST_RESULT_FAIL;
@@ -577,6 +687,11 @@
 	uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP;
 	smc_ret_values ret;
 
+	/* Variables to validate calls to FFA_NOTIFICATION_INFO_GET. */
+	uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+	uint32_t lists_count;
+	uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+
 	/* Ask SPMC to allocate notifications bitmap. */
 	if (!notifications_bitmap_create(receiver, 1)) {
 		return TEST_RESULT_FAIL;
@@ -587,6 +702,19 @@
 		return TEST_RESULT_FAIL;
 	}
 
+	/*
+	 * FFA_NOTIFICATION_INFO_GET return list should be simple, containing
+	 * only the receiver's ID.
+	 */
+	ids[0] = receiver;
+	lists_count = 1;
+
+	if (!notifications_info_get(ids, lists_count, lists_sizes,
+				    FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+				    false)) {
+		return TEST_RESULT_FAIL;
+	}
+
 	/* Get pending notifications, and retrieve response. */
 	if (!notification_get_and_validate(receiver, g_notifications, 0, 0,
 					   get_flags)) {
@@ -650,3 +778,329 @@
 
 	return TEST_RESULT_SUCCESS;
 }
+
+/**
+ * Test the result of a call to FFA_NOTIFICATION_INFO_GET if no pending
+ * notifications.
+ */
+test_result_t test_ffa_notifications_info_get_none(void)
+{
+	SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
+	if (check_spmc_execution_level()) {
+		VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	smc_ret_values ret;
+
+	ret = ffa_notification_info_get();
+
+	if (!is_expected_ffa_error(ret, FFA_ERROR_NO_DATA)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/**
+ * CPU_ON handler for testing per-vCPU notifications to SPs (either from VMs
+ * or from SPs). It requests the SP to retrieve its pending notifications
+ * within its current Execution Context. The SP shall obtain all per-vCPU
+ * targeted to the running vCPU.
+ */
+static test_result_t request_notification_get_per_vcpu_on_handler(void)
+{
+	unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int core_pos = platform_get_core_pos(mpid);
+	smc_ret_values ret;
+	test_result_t result = TEST_RESULT_FAIL;
+
+	uint64_t exp_from_vm = 0;
+	uint64_t exp_from_sp = 0;
+
+	if (IS_SP_ID(per_vcpu_sender)) {
+		exp_from_sp = FFA_NOTIFICATION(core_pos);
+	} else {
+		exp_from_vm = FFA_NOTIFICATION(core_pos);
+	}
+
+	VERBOSE("Request get per-vCPU notification to %x, core: %u.\n",
+		 per_vcpu_receiver, core_pos);
+
+	/*
+	 * Secure Partitions secondary ECs need one round of ffa_run to reach
+	 * the message loop.
+	 */
+	if (per_vcpu_receiver != SP_ID(1)) {
+		ret = ffa_run(per_vcpu_receiver, core_pos);
+
+		if (ffa_func_id(ret) != FFA_MSG_WAIT) {
+			ERROR("Failed to run SP%x on core %u\n",
+			      per_vcpu_receiver, core_pos);
+			goto out;
+		}
+	}
+
+	/* Request to get notifications sent to the respective vCPU. */
+	if (!notification_get_and_validate(
+		per_vcpu_receiver, exp_from_sp, exp_from_vm, core_pos,
+		per_vcpu_flags_get)) {
+		goto out;
+	}
+
+	result = TEST_RESULT_SUCCESS;
+
+out:
+	/* Tell the lead CPU that the calling CPU has completed the test. */
+	tftf_send_event(&per_vcpu_finished[core_pos]);
+
+	return result;
+}
+
+/**
+ * Base function to test signaling of per-vCPU notifications.
+ * Test whole flow between two FF-A endpoints: binding, getting notification
+ * info, and getting pending notifications.
+ * Each vCPU will receive a notification whose ID is the same as the core
+ * position.
+ */
+static test_result_t base_test_per_vcpu_notifications(ffa_id_t sender,
+						      ffa_id_t receiver)
+{
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	/*
+	 * Manually set variables to validate what should be the return of to
+	 * FFA_NOTIFICATION_INFO_GET.
+	 */
+	uint16_t exp_ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+		receiver, 0, 1, 2,
+		receiver, 3, 4, 5,
+		receiver, 6, 7, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0,
+	};
+	uint32_t exp_lists_count = 3;
+	uint32_t exp_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+		3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	};
+
+	const bool exp_more_notif_pending = false;
+	test_result_t result = TEST_RESULT_SUCCESS;
+	uint64_t notifications_to_unbind = 0;
+
+	per_vcpu_flags_get = IS_SP_ID(sender)
+				? FFA_NOTIFICATIONS_FLAG_BITMAP_SP
+				: FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+
+	/*
+	 * Prepare notifications bitmap to request Cactus to bind them as
+	 * per-vCPU.
+	 */
+	for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+		notifications_to_unbind |= FFA_NOTIFICATION(i);
+
+		uint32_t flags = FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+				 FFA_NOTIFICATIONS_FLAGS_VCPU_ID((uint16_t)i);
+
+		if (!notification_bind_and_set(sender,
+					       receiver,
+					       FFA_NOTIFICATION(i),
+					       flags)) {
+			return TEST_RESULT_FAIL;
+		}
+	}
+
+	/* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+	if (!notifications_info_get(exp_ids, exp_lists_count, exp_lists_sizes,
+				    FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+				    exp_more_notif_pending)) {
+		ERROR("Info Get Failed....\n");
+		result = TEST_RESULT_FAIL;
+		goto out;
+	}
+
+	/*
+	 * Request SP to get notifications in core 0, as this is not iterated
+	 * at the CPU ON handler.
+	 */
+	if (!notification_get_and_validate(
+		receiver,
+		IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0,
+		!IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0,
+		0,
+		per_vcpu_flags_get)) {
+		result = TEST_RESULT_FAIL;
+	}
+
+	/* Setting global variables to be accessed by the cpu_on handler. */
+	per_vcpu_receiver = receiver;
+	per_vcpu_sender = sender;
+
+	/*
+	 * Bring up all the cores, and request the receiver to get notifications
+	 * in each one of them.
+	 */
+	if (spm_run_multi_core_test(
+		(uintptr_t)request_notification_get_per_vcpu_on_handler,
+		per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+		result = TEST_RESULT_FAIL;
+	}
+
+out:
+	/* As a clean-up, unbind notifications. */
+	if (!request_notification_unbind(receiver, receiver,
+					 sender,
+					 notifications_to_unbind,
+					 CACTUS_SUCCESS, 0)) {
+		result = TEST_RESULT_FAIL;
+	}
+
+	return result;
+}
+
+/**
+ * Test to validate a VM can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_vm_signals_sp_per_vcpu(void)
+{
+	return base_test_per_vcpu_notifications(0, SP_ID(1));
+}
+
+/**
+ * Test to validate an SP can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_per_vcpu(void)
+{
+	return base_test_per_vcpu_notifications(SP_ID(1), SP_ID(2));
+}
+
+static test_result_t notification_get_per_vcpu_on_handler(void)
+{
+	unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int core_pos = platform_get_core_pos(mpid);
+	smc_ret_values ret;
+	test_result_t result = TEST_RESULT_SUCCESS;
+
+	VERBOSE("Getting per-vCPU notifications from %x, core: %u.\n",
+		 per_vcpu_receiver, core_pos);
+
+	ret = ffa_run(per_vcpu_sender, core_pos);
+
+	if (ffa_func_id(ret) != FFA_MSG_WAIT) {
+		ERROR("Failed to run SP%x on core %u\n",
+		      per_vcpu_sender, core_pos);
+		result = TEST_RESULT_FAIL;
+		goto out;
+	}
+
+	if (!notification_get_and_validate(per_vcpu_receiver,
+					   FFA_NOTIFICATION(core_pos), 0,
+					   core_pos,
+					   FFA_NOTIFICATIONS_FLAG_BITMAP_SP)) {
+		result = TEST_RESULT_FAIL;
+		goto out;
+	}
+
+out:
+	/* Tell the lead CPU that the calling CPU has completed the test. */
+	tftf_send_event(&per_vcpu_finished[core_pos]);
+
+	return result;
+}
+
+/**
+ * Test whole flow from binding, to getting notifications' info, and getting
+ * pending notifications, namely signaling of notifications from SP to a VM.
+ * Each vCPU will receive a notification whose ID is the same as the core
+ * position.
+ */
+test_result_t test_ffa_notifications_sp_signals_vm_per_vcpu(void)
+{
+	/* Making a VM the receiver, and an SP the sender */
+	per_vcpu_receiver = 1;
+	per_vcpu_sender = SP_ID(2);
+
+	/**
+	 * Manually set variables to validate what should be the return of to
+	 * FFA_NOTIFICATION_INFO_GET.
+	 */
+	uint16_t exp_ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+		per_vcpu_receiver, 0, 1, 2,
+		per_vcpu_receiver, 3, 4, 5,
+		per_vcpu_receiver, 6, 7, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0,
+	};
+	uint32_t exp_lists_count = 3;
+	uint32_t exp_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+		3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	};
+
+	const bool exp_more_notif_pending = false;
+	test_result_t result = TEST_RESULT_SUCCESS;
+	uint64_t notifications_to_unbind = 0;
+	smc_ret_values ret;
+
+	CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+	/* Create bitmap for receiver. */
+	if (!notifications_bitmap_create(per_vcpu_receiver,
+					 PLATFORM_CORE_COUNT)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Bind notifications, and request Cactus SP to set them. */
+	for (uint32_t i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+		notifications_to_unbind |= FFA_NOTIFICATION(i);
+
+		uint32_t flags = FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+				 FFA_NOTIFICATIONS_FLAG_PER_VCPU  |
+				 FFA_NOTIFICATIONS_FLAGS_VCPU_ID((uint16_t)i);
+
+		if (!notification_bind_and_set(per_vcpu_sender,
+					      per_vcpu_receiver,
+					      FFA_NOTIFICATION(i),
+					      flags)) {
+			return TEST_RESULT_FAIL;
+		};
+	}
+
+	/* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+	if (!notifications_info_get(exp_ids, exp_lists_count, exp_lists_sizes,
+				    FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+				    exp_more_notif_pending)) {
+		ERROR("Info Get Failed....\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	/*
+	 * Get notifications in core 0, as it is not iterated at the CPU ON
+	 * handler.
+	 */
+	if (!notification_get_and_validate(per_vcpu_receiver,
+					   FFA_NOTIFICATION(0), 0, 0,
+					   FFA_NOTIFICATIONS_FLAG_BITMAP_SP)) {
+		result = TEST_RESULT_FAIL;
+	}
+
+	/* Bring up all the cores, and get notifications in each one of them. */
+	if (spm_run_multi_core_test(
+		(uintptr_t)notification_get_per_vcpu_on_handler,
+		per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+		ERROR("Failed to get per-vCPU notifications\n");
+		result = TEST_RESULT_FAIL;
+	}
+
+	/* As a clean-up, unbind notifications. */
+	ret = ffa_notification_unbind(per_vcpu_sender, per_vcpu_receiver,
+				      notifications_to_unbind);
+	if (is_ffa_call_error(ret)) {
+		result = TEST_RESULT_FAIL;
+	}
+
+	return result;
+}
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
new file mode 100644
index 0000000..a8642fa
--- /dev/null
+++ b/tftf/tests/tests-realm-payload.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES	+=							\
+	$(addprefix tftf/tests/runtime_services/realm_payload/,		\
+		realm_payload_test_helpers.c				\
+		realm_payload_test.c					\
+		realm_payload_spm_test.c				\
+	)
+
+TESTS_SOURCES	+=							\
+	$(addprefix tftf/tests/runtime_services/secure_service/,	\
+		ffa_helpers.c						\
+		spm_common.c						\
+		test_ffa_direct_messaging.c				\
+		test_ffa_interrupts.c					\
+		test_ffa_memory_sharing.c				\
+		test_ffa_setup_and_discovery.c				\
+		test_spm_cpu_features.c					\
+		test_spm_smmu.c						\
+	)
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
new file mode 100644
index 0000000..b401409
--- /dev/null
+++ b/tftf/tests/tests-realm-payload.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright (c) 2021, Arm Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+
+  <testsuite name="Realm payload tests" description="Tests for Realm management interface">
+	  <testcase name="Realm payload boot" function="realm_version_single_cpu" />
+	  <testcase name="Realm payload multi CPU request" function="realm_version_multi_cpu" />
+	  <testcase name="Realm payload Delegate and Undelegate" function="realm_delegate_undelegate" />
+	  <testcase name="Multi CPU Realm payload Delegate and Undelegate" function="realm_delundel_multi_cpu" />
+	  <testcase name="Testing delegation fails" function="realm_fail_del" />
+	  <testcase name="Realm testing with SPM tests" function="test_ffa_secondary_core_direct_realm_msg" />
+  </testsuite>
+
+</testsuites>
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index b59ca0b..5752b8e 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -128,6 +128,14 @@
                function="test_ffa_notifications_sp_signals_vm" />
      <testcase name="Notifications unbind while pending"
                function="test_ffa_notifications_unbind_pending" />
+     <testcase name="Notifications info get no data"
+               function="test_ffa_notifications_info_get_none" />
+     <testcase name="Notifications VM signals SP per-vCPU"
+               function="test_ffa_notifications_vm_signals_sp_per_vcpu" />
+     <testcase name="Notifications SP signals SP per-vCPU"
+               function="test_ffa_notifications_sp_signals_sp_per_vcpu" />
+     <testcase name="Notifications SP signals VM per-vCPU"
+               function="test_ffa_notifications_sp_signals_vm_per_vcpu" />
   </testsuite>
 
 </testsuites>
diff --git a/tftf/tests/tests-standard.mk b/tftf/tests/tests-standard.mk
index c6c9029..a722077 100644
--- a/tftf/tests/tests-standard.mk
+++ b/tftf/tests/tests-standard.mk
@@ -23,6 +23,7 @@
 	tests-tsp.mk				\
 	tests-uncontainable.mk			\
 	tests-debugfs.mk                        \
+	tests-realm-payload.mk			\
 )
 
 include ${TESTS_MAKEFILE}
diff --git a/tftf/tests/tests-standard.xml b/tftf/tests/tests-standard.xml
index 8c66cda..384a5f4 100644
--- a/tftf/tests/tests-standard.xml
+++ b/tftf/tests/tests-standard.xml
@@ -24,6 +24,7 @@
   <!ENTITY tests-spm SYSTEM "tests-spm.xml">
   <!ENTITY tests-pmu-leakage SYSTEM "tests-pmu-leakage.xml">
   <!ENTITY tests-debugfs SYSTEM "tests-debugfs.xml">
+  <!ENTITY tests-realm-payload SYSTEM "tests-realm-payload.xml">
 ]>
 
 <testsuites>
@@ -43,5 +44,6 @@
   &tests-spm;
   &tests-pmu-leakage;
   &tests-debugfs;
+  &tests-realm-payload;
 
 </testsuites>