refactor(direct message): create new dedicated test suite

Factored direct messaging related tests out of "ffa" test suite
and created a dedicated test suite for it.

Change-Id: I17b244d330ee634c4bd0c36a06160108de57953c
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index baa2d0e..abf2fae 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2494,6 +2494,7 @@
 
 	if (!plat_ffa_is_direct_request_valid(current, sender_vm_id,
 					      receiver_vm_id)) {
+		dlog_verbose("Invalid direct message request.\n");
 		return ffa_error(FFA_INVALID_PARAMETERS);
 	}
 
@@ -2697,6 +2698,7 @@
 
 	if (!plat_ffa_is_direct_response_valid(current, sender_vm_id,
 					       receiver_vm_id)) {
+		dlog_verbose("Invalid direct response call.\n");
 		return ffa_error(FFA_INVALID_PARAMETERS);
 	}
 
diff --git a/test/vmapi/el0_partitions/services/BUILD.gn b/test/vmapi/el0_partitions/services/BUILD.gn
index 5bf8920..97622fe 100644
--- a/test/vmapi/el0_partitions/services/BUILD.gn
+++ b/test/vmapi/el0_partitions/services/BUILD.gn
@@ -21,6 +21,7 @@
     "//src/arch/${plat_arch}/hftest/el0:interrupts",
     "//test/hftest:hftest_secondary_el0_partition",
     "//test/vmapi/common:common",
+    "//test/vmapi/primary_with_secondaries:primary_with_secondaries",
     "//test/vmapi/primary_with_secondaries/services:echo",
     "//test/vmapi/primary_with_secondaries/services:ffa_check",
     "//test/vmapi/primary_with_secondaries/services:relay",
diff --git a/test/vmapi/primary_with_secondaries/BUILD.gn b/test/vmapi/primary_with_secondaries/BUILD.gn
index acfb173..8dec7a2 100644
--- a/test/vmapi/primary_with_secondaries/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/BUILD.gn
@@ -87,6 +87,7 @@
   sources = [
     "boot.c",
     "debug_el1.c",
+    "dir_msg.c",
     "ffa.c",
     "floating_point.c",
     "indirect_messaging.c",
@@ -186,6 +187,7 @@
   ]
 
   sources = [
+    "dir_msg.c",
     "indirect_messaging.c",
     "memory_sharing.c",
   ]
@@ -265,6 +267,7 @@
   ]
 
   sources = [
+    "dir_msg.c",
     "indirect_messaging.c",
     "memory_sharing.c",
   ]
diff --git a/test/vmapi/primary_with_secondaries/dir_msg.c b/test/vmapi/primary_with_secondaries/dir_msg.c
new file mode 100644
index 0000000..af7a7a1
--- /dev/null
+++ b/test/vmapi/primary_with_secondaries/dir_msg.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2023 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#include <stdint.h>
+
+#include "hf/ffa.h"
+
+#include "vmapi/hf/call.h"
+
+#include "primary_with_secondary.h"
+#include "test/hftest.h"
+#include "test/vmapi/ffa.h"
+
+/**
+ * Send direct message, verify that sent info is echoed back.
+ */
+TEST(direct_message, ffa_send_direct_message_req_echo)
+{
+	const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
+				0x88889999};
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_value res;
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+
+	SERVICE_SELECT(service1_info->vm_id, "ffa_direct_message_resp_echo",
+		       mb.send);
+	ffa_run(service1_info->vm_id, 0);
+
+	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, service1_info->vm_id,
+				      msg[0], msg[1], msg[2], msg[3], msg[4]);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+
+	EXPECT_EQ(res.arg3, msg[0]);
+	EXPECT_EQ(res.arg4, msg[1]);
+	EXPECT_EQ(res.arg5, msg[2]);
+	EXPECT_EQ(res.arg6, msg[3]);
+	EXPECT_EQ(res.arg7, msg[4]);
+}
+
+/**
+ * Initiate direct message request between test SPs.
+ * If test services are VMs, test should be skipped.
+ */
+TEST_PRECONDITION(direct_message, ffa_direct_message_services_echo,
+		  service1_and_service2_are_secure)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+	struct ffa_partition_info *service2_info = service2(mb.recv);
+	ffa_vm_id_t own_id = hf_vm_get_id();
+	struct ffa_value ret;
+
+	/* Run service2 for it to wait for a request from service1. */
+	SERVICE_SELECT(service2_info->vm_id, "ffa_direct_message_resp_echo",
+		       mb.send);
+	ffa_run(service2_info->vm_id, 0);
+
+	/* Service1 requests echo from service2. */
+	SERVICE_SELECT(service1_info->vm_id, "ffa_direct_message_echo_services",
+		       mb.send);
+
+	/* Send to service1 the uuid of the target for its message. */
+	ret = send_indirect_message(own_id, service1_info->vm_id, mb.send,
+				    &service2_info->vm_id,
+				    sizeof(service2_info->vm_id), 0);
+	ASSERT_EQ(ret.func, FFA_SUCCESS_32);
+	ffa_run(service1_info->vm_id, 0);
+}
+
+/**
+ * If Hafnium is the hypervisor, and service1 is a VM:
+ * - Service verifies disallowed SMC invocations while ffa_msg_send_direct_req
+ * is being serviced.
+ * If Hafnium as SPMC is deployed and service1 is an SP:
+ * - Validate the state transitions permitted under RTM_FFA_DIR_REQ partition
+ * runtime model
+ */
+TEST(direct_message, ffa_send_direct_message_req_disallowed_smc)
+{
+	const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
+				0x88889999};
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_value res;
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+
+	SERVICE_SELECT(service1_info->vm_id,
+		       "ffa_direct_msg_req_disallowed_smc", mb.send);
+	ffa_run(service1_info->vm_id, 0);
+
+	res = ffa_msg_send_direct_req(hf_vm_get_id(), service1_info->vm_id,
+				      msg[0], msg[1], msg[2], msg[3], msg[4]);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+}
+
+/**
+ * Send direct message to invalid destination.
+ */
+TEST(direct_message, ffa_send_direct_message_req_invalid_dst)
+{
+	const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
+				0x88889999};
+	struct ffa_value res;
+
+	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, HF_PRIMARY_VM_ID,
+				      msg[0], msg[1], msg[2], msg[3], msg[4]);
+
+	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
+}
+
+/**
+ * Verify that the primary VM can't send direct message responses.
+ */
+TEST(direct_message, ffa_send_direct_message_resp_invalid)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_value res;
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+
+	SERVICE_SELECT(service1_info->vm_id, "ffa_direct_message_resp_echo",
+		       mb.send);
+	ffa_run(service1_info->vm_id, 0);
+
+	res = ffa_msg_send_direct_resp(HF_PRIMARY_VM_ID, service1_info->vm_id,
+				       0, 0, 0, 0, 0);
+	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
+}
+
+/**
+ * Test has two purposes. It runs the test service via ffa_run, and validates
+ * that:
+ * - If service is an SP, it can't send a direct message request to a VM in the
+ * NWd.
+ * - If service is a secondary VM, it can't invoke a direct message request to
+ * the PVM (legacy behavior, for hafnium as an hypervisor).
+ */
+TEST(direct_message, ffa_secondary_direct_msg_req_invalid)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_value res;
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+
+	SERVICE_SELECT(service1_info->vm_id, "ffa_disallowed_direct_msg_req",
+		       mb.send);
+	ffa_run(service1_info->vm_id, 0);
+
+	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, service1_info->vm_id, 0,
+				      0, 0, 0, 0);
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+}
+
+/**
+ * Run secondary VM without sending a direct message request beforehand.
+ * Secondary VM must fail sending a direct message response.
+ */
+TEST(direct_message, ffa_secondary_direct_msg_resp_invalid)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_value res;
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+
+	SERVICE_SELECT(service1_info->vm_id, "ffa_disallowed_direct_msg_resp",
+		       mb.send);
+	ffa_run(service1_info->vm_id, 0);
+
+	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, service1_info->vm_id, 0,
+				      0, 0, 0, 0);
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+}
+
+/**
+ * Run secondary VM and send a direct message request. Secondary VM attempts
+ * altering the sender and receiver in its direct message responses, and must
+ * fail to do so.
+ */
+TEST(direct_message, ffa_secondary_spoofed_response)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_value res;
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+
+	SERVICE_SELECT(service1_info->vm_id,
+		       "ffa_direct_msg_resp_invalid_sender_receiver", mb.send);
+	ffa_run(service1_info->vm_id, 0);
+
+	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, service1_info->vm_id, 0,
+				      0, 0, 0, 0);
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+}
+
+/*
+ * Validate that the creation of a cyclic dependency via direct_messaging
+ * is not possible.
+ * The test only makes sense in the scope of validating the SPMC, as the
+ * hypervisor limits the direct message requests to be only invoked from
+ * the primary VM. Thus, using precondition that checks both involved test
+ * services are SPs.
+ */
+TEST_PRECONDITION(direct_message, fail_if_cyclic_dependency,
+		  service1_and_service2_are_secure)
+{
+	struct mailbox_buffers mb = set_up_mailbox();
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+	struct ffa_partition_info *service2_info = service2(mb.recv);
+	ffa_vm_id_t own_id = hf_vm_get_id();
+	struct ffa_value ret;
+
+	/* Run service2 for it to wait for a request from service1. */
+	SERVICE_SELECT(service2_info->vm_id, "ffa_direct_message_cycle_denied",
+		       mb.send);
+	ffa_run(service2_info->vm_id, 0);
+
+	/* Service1 requests echo from service2. */
+	SERVICE_SELECT(service1_info->vm_id, "ffa_direct_message_echo_services",
+		       mb.send);
+
+	/* Send to service1 the uuid of the target for its message. */
+	ret = send_indirect_message(own_id, service1_info->vm_id, mb.send,
+				    &service2_info->vm_id,
+				    sizeof(service2_info->vm_id), 0);
+
+	ASSERT_EQ(ret.func, FFA_SUCCESS_32);
+	EXPECT_EQ(ffa_run(service1_info->vm_id, 0).func, FFA_YIELD_32);
+}
diff --git a/test/vmapi/primary_with_secondaries/ffa.c b/test/vmapi/primary_with_secondaries/ffa.c
index cfea431..95068f9 100644
--- a/test/vmapi/primary_with_secondaries/ffa.c
+++ b/test/vmapi/primary_with_secondaries/ffa.c
@@ -212,136 +212,6 @@
 	EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
 }
 
-/**
- * Send direct message, verify that sent info is echoed back.
- */
-TEST(ffa, ffa_send_direct_message_req_echo)
-{
-	const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
-				0x88889999};
-	struct mailbox_buffers mb = set_up_mailbox();
-	struct ffa_value res;
-
-	SERVICE_SELECT(SERVICE_VM1, "ffa_direct_message_resp_echo", mb.send);
-	ffa_run(SERVICE_VM1, 0);
-
-	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, msg[0],
-				      msg[1], msg[2], msg[3], msg[4]);
-
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
-
-	EXPECT_EQ(res.arg3, msg[0]);
-	EXPECT_EQ(res.arg4, msg[1]);
-	EXPECT_EQ(res.arg5, msg[2]);
-	EXPECT_EQ(res.arg6, msg[3]);
-	EXPECT_EQ(res.arg7, msg[4]);
-}
-
-/**
- * Send direct message, secondary verifies disallowed SMC invocations while
- * ffa_msg_send_direct_req is being serviced.
- */
-TEST(ffa, ffa_send_direct_message_req_disallowed_smc)
-{
-	const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
-				0x88889999};
-	struct mailbox_buffers mb = set_up_mailbox();
-	struct ffa_value res;
-
-	SERVICE_SELECT(SERVICE_VM1, "ffa_direct_msg_req_disallowed_smc",
-		       mb.send);
-	ffa_run(SERVICE_VM1, 0);
-
-	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, msg[0],
-				      msg[1], msg[2], msg[3], msg[4]);
-
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
-}
-
-/**
- * Send direct message to invalid destination.
- */
-TEST(ffa, ffa_send_direct_message_req_invalid_dst)
-{
-	const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
-				0x88889999};
-	struct ffa_value res;
-
-	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, HF_PRIMARY_VM_ID,
-				      msg[0], msg[1], msg[2], msg[3], msg[4]);
-
-	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
-}
-
-/**
- * Verify that the primary VM can't send direct message responses.
- */
-TEST(ffa, ffa_send_direct_message_resp_invalid)
-{
-	struct ffa_value res;
-	struct mailbox_buffers mb = set_up_mailbox();
-
-	SERVICE_SELECT(SERVICE_VM1, "ffa_direct_message_resp_echo", mb.send);
-	ffa_run(SERVICE_VM1, 0);
-
-	res = ffa_msg_send_direct_resp(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0,
-				       0, 0);
-	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
-}
-
-/**
- * Run secondary VM through ffa_run and check it cannot invoke
- * a direct message request.
- */
-TEST(ffa, ffa_secondary_direct_msg_req_invalid)
-{
-	struct mailbox_buffers mb = set_up_mailbox();
-	struct ffa_value res;
-
-	SERVICE_SELECT(SERVICE_VM1, "ffa_disallowed_direct_msg_req", mb.send);
-	ffa_run(SERVICE_VM1, 0);
-
-	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0, 0,
-				      0);
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
-}
-
-/**
- * Run secondary VM without sending a direct message request beforehand.
- * Secondary VM must fail sending a direct message response.
- */
-TEST(ffa, ffa_secondary_direct_msg_resp_invalid)
-{
-	struct mailbox_buffers mb = set_up_mailbox();
-	struct ffa_value res;
-
-	SERVICE_SELECT(SERVICE_VM1, "ffa_disallowed_direct_msg_resp", mb.send);
-	ffa_run(SERVICE_VM1, 0);
-
-	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0, 0,
-				      0);
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
-}
-
-/**
- * Run secondary VM and send a direct message request. Secondary VM attempts
- * altering the sender and receiver in its direct message responses, and must
- * fail to do so.
- */
-TEST(ffa, ffa_secondary_spoofed_response)
-{
-	struct mailbox_buffers mb = set_up_mailbox();
-	struct ffa_value res;
-
-	SERVICE_SELECT(SERVICE_VM1,
-		       "ffa_direct_msg_resp_invalid_sender_receiver", mb.send);
-	ffa_run(SERVICE_VM1, 0);
-
-	res = ffa_msg_send_direct_req(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0, 0, 0,
-				      0);
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
-}
-
 /*
  * The secondary vCPU is waiting for a direct request, but the primary instead
  * calls `FFA_RUN`. This should return immediately to the primary without the
diff --git a/test/vmapi/primary_with_secondaries/inc/primary_with_secondary.h b/test/vmapi/primary_with_secondaries/inc/primary_with_secondary.h
index 8a3c737..5e154f3 100644
--- a/test/vmapi/primary_with_secondaries/inc/primary_with_secondary.h
+++ b/test/vmapi/primary_with_secondaries/inc/primary_with_secondary.h
@@ -54,6 +54,7 @@
 
 /* Precondition functions for this test setup. */
 bool service1_is_vm(void);
+bool service1_and_service2_are_secure(void);
 bool hypervisor_only(void);
 
 #define SERVICE_VM1 (HF_VM_ID_OFFSET + 1)
diff --git a/test/vmapi/primary_with_secondaries/primary_with_secondaries.c b/test/vmapi/primary_with_secondaries/primary_with_secondaries.c
index ae28c38..1771fc1 100644
--- a/test/vmapi/primary_with_secondaries/primary_with_secondaries.c
+++ b/test/vmapi/primary_with_secondaries/primary_with_secondaries.c
@@ -31,6 +31,16 @@
 	return mb;
 }
 
+bool service1_and_service2_are_secure(void)
+{
+	struct mailbox_buffers mb = get_precondition_mailbox();
+	struct ffa_partition_info *service1_info = service1(mb.recv);
+	struct ffa_partition_info *service2_info = service2(mb.recv);
+
+	return !IS_VM_ID(service1_info->vm_id) &&
+	       !IS_VM_ID(service2_info->vm_id);
+}
+
 /*
  * The following is a precondition function, for the current system set-up.
  * This is currently being used to skip memory sharing tests, when
@@ -40,6 +50,7 @@
 {
 	struct mailbox_buffers mb = get_precondition_mailbox();
 	struct ffa_partition_info *service1_info = service1(mb.recv);
+
 	return IS_VM_ID(service1_info->vm_id);
 }
 
diff --git a/test/vmapi/primary_with_secondaries/services/BUILD.gn b/test/vmapi/primary_with_secondaries/services/BUILD.gn
index b8a5334..67d63db 100644
--- a/test/vmapi/primary_with_secondaries/services/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/services/BUILD.gn
@@ -164,7 +164,10 @@
   ]
   deps = [ "//test/vmapi/common" ]
 
-  sources = [ "ffa_check.c" ]
+  sources = [
+    "dir_msg.c",
+    "ffa_check.c",
+  ]
 }
 
 # Group services together into VMs.
@@ -199,6 +202,7 @@
 
   deps = [
     ":echo",
+    ":ffa_check",
     ":interruptible",
     ":memory",
     ":relay",
@@ -214,6 +218,7 @@
 
   deps = [
     ":echo",
+    ":ffa_check",
     ":smp",
     "//test/hftest:hftest_secondary_vm",
     "//test/vmapi/primary_with_secondaries:primary_with_secondaries",
diff --git a/test/vmapi/primary_with_secondaries/services/dir_msg.c b/test/vmapi/primary_with_secondaries/services/dir_msg.c
new file mode 100644
index 0000000..e6b0d0f
--- /dev/null
+++ b/test/vmapi/primary_with_secondaries/services/dir_msg.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2023 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#include "hf/ffa.h"
+
+#include "vmapi/hf/call.h"
+
+#include "primary_with_secondary.h"
+#include "test/hftest.h"
+#include "test/vmapi/ffa.h"
+
+TEST_SERVICE(ffa_direct_message_resp_echo)
+{
+	struct ffa_value args = ffa_msg_wait();
+
+	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
+
+	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
+				 args.arg3, args.arg4, args.arg5, args.arg6,
+				 args.arg7);
+}
+
+TEST_SERVICE(ffa_direct_message_echo_services)
+{
+	const uint32_t msg[] = {0x00001111, 0x22223333, 0x44445555, 0x66667777,
+				0x88889999};
+	void *recv_buf = SERVICE_RECV_BUFFER();
+	struct ffa_value res;
+	ffa_vm_id_t target_id;
+
+	/* Retrieve FF-A ID of the target endpoint. */
+	receive_indirect_message((void *)&target_id, sizeof(target_id),
+				 recv_buf, NULL);
+
+	HFTEST_LOG("Echo test with: %x", target_id);
+
+	res = ffa_msg_send_direct_req(hf_vm_get_id(), target_id, msg[0], msg[1],
+				      msg[2], msg[3], msg[4]);
+
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+
+	EXPECT_EQ(res.arg3, msg[0]);
+	EXPECT_EQ(res.arg4, msg[1]);
+	EXPECT_EQ(res.arg5, msg[2]);
+	EXPECT_EQ(res.arg6, msg[3]);
+	EXPECT_EQ(res.arg7, msg[4]);
+
+	ffa_yield();
+}
+
+TEST_SERVICE(ffa_direct_msg_req_disallowed_smc)
+{
+	struct ffa_value args = ffa_msg_wait();
+	struct ffa_value ret;
+	void *recv_buf = SERVICE_RECV_BUFFER();
+	struct ffa_partition_info *service1_info = service1(recv_buf);
+
+	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
+
+	ret = ffa_yield();
+	EXPECT_FFA_ERROR(ret, FFA_DENIED);
+
+	ret = ffa_msg_wait();
+	EXPECT_FFA_ERROR(ret, FFA_DENIED);
+
+	ret = ffa_msg_send_direct_req(service1_info->vm_id, ffa_sender(args), 0,
+				      0, 0, 0, 0);
+	EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
+
+	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
+				 args.arg3, args.arg4, args.arg5, args.arg6,
+				 args.arg7);
+}
+
+/**
+ * Verify that services can't send direct message requests
+ * when invoked by FFA_RUN.
+ */
+TEST_SERVICE(ffa_disallowed_direct_msg_req)
+{
+	struct ffa_value args;
+	struct ffa_value ret;
+	void *recv_buf = SERVICE_RECV_BUFFER();
+	struct ffa_partition_info *service1_info = service1(recv_buf);
+
+	ret = ffa_msg_send_direct_req(service1_info->vm_id, HF_PRIMARY_VM_ID, 0,
+				      0, 0, 0, 0);
+	EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
+
+	ret = ffa_msg_send_direct_req(service1_info->vm_id, HF_VM_ID_BASE + 10,
+				      0, 0, 0, 0, 0);
+	EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
+
+	args = ffa_msg_wait();
+	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
+
+	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
+				 args.arg3, args.arg4, args.arg5, args.arg6,
+				 args.arg7);
+}
+
+/**
+ * Verify a service can't send a direct message response when it hasn't
+ * first been sent a request.
+ */
+TEST_SERVICE(ffa_disallowed_direct_msg_resp)
+{
+	struct ffa_value args;
+	struct ffa_value ret;
+	void *recv_buf = SERVICE_RECV_BUFFER();
+	struct ffa_partition_info *service1_info = service1(recv_buf);
+
+	ret = ffa_msg_send_direct_resp(service1_info->vm_id, HF_PRIMARY_VM_ID,
+				       0, 0, 0, 0, 0);
+	EXPECT_FFA_ERROR(ret, FFA_DENIED);
+
+	args = ffa_msg_wait();
+	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
+
+	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
+				 args.arg3, args.arg4, args.arg5, args.arg6,
+				 args.arg7);
+}
+
+/**
+ * Verify a service can't send a response to a different VM than the one
+ * that sent the request.
+ * Verify a service cannot send a response with a sender ID different from
+ * its own service ID.
+ */
+TEST_SERVICE(ffa_direct_msg_resp_invalid_sender_receiver)
+{
+	struct ffa_value res;
+	void *recv_buf = SERVICE_RECV_BUFFER();
+	struct ffa_partition_info *service2_info = service2(recv_buf);
+	ffa_vm_id_t invalid_receiver;
+	struct ffa_value args = ffa_msg_wait();
+	ffa_vm_id_t own_id = hf_vm_get_id();
+	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
+
+	ffa_vm_id_t sender = ffa_sender(args);
+	ASSERT_EQ(own_id, ffa_receiver(args));
+
+	/* Other receiver ID. */
+	invalid_receiver = IS_VM_ID(own_id) ? service2_info->vm_id : own_id;
+	res = ffa_msg_send_direct_resp(own_id, invalid_receiver, 0, 0, 0, 0, 0);
+	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
+
+	/* Spoof sender ID. */
+	res = ffa_msg_send_direct_resp(service2_info->vm_id, sender, 0, 0, 0, 0,
+				       0);
+	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
+
+	ffa_msg_send_direct_resp(own_id, sender, 0, 0, 0, 0, 0);
+}
+
+TEST_SERVICE(ffa_direct_message_cycle_denied)
+{
+	struct ffa_value res;
+	struct ffa_value args = ffa_msg_wait();
+	ffa_vm_id_t sender;
+	ffa_vm_id_t receiver;
+	ffa_vm_id_t own_id = hf_vm_get_id();
+
+	ASSERT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
+	receiver = ffa_receiver(args);
+	sender = ffa_sender(args);
+
+	EXPECT_EQ(receiver, hf_vm_get_id());
+
+	res = ffa_msg_send_direct_req(own_id, sender, 1, 2, 3, 4, 5);
+	EXPECT_FFA_ERROR(res, FFA_DENIED);
+
+	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
+				 args.arg3, args.arg4, args.arg5, args.arg6,
+				 args.arg7);
+}
diff --git a/test/vmapi/primary_with_secondaries/services/ffa_check.c b/test/vmapi/primary_with_secondaries/services/ffa_check.c
index c56cb6b..e8353f4 100644
--- a/test/vmapi/primary_with_secondaries/services/ffa_check.c
+++ b/test/vmapi/primary_with_secondaries/services/ffa_check.c
@@ -66,117 +66,20 @@
 	ffa_yield();
 }
 
-TEST_SERVICE(ffa_direct_message_resp_echo)
-{
-	struct ffa_value args = ffa_msg_wait();
-
-	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
-
-	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
-				 args.arg3, args.arg4, args.arg5, args.arg6,
-				 args.arg7);
-}
-
-TEST_SERVICE(ffa_direct_msg_req_disallowed_smc)
-{
-	struct ffa_value args = ffa_msg_wait();
-	struct ffa_value ret;
-
-	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
-
-	ret = ffa_yield();
-	EXPECT_FFA_ERROR(ret, FFA_DENIED);
-
-	ret = ffa_msg_send(ffa_receiver(args), ffa_sender(args), 0, 0);
-	EXPECT_FFA_ERROR(ret, FFA_DENIED);
-
-	ret = ffa_msg_wait();
-	EXPECT_FFA_ERROR(ret, FFA_DENIED);
-
-	ret = ffa_msg_send_direct_req(SERVICE_VM1, SERVICE_VM2, 0, 0, 0, 0, 0);
-	EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
-
-	ret = ffa_msg_poll();
-	EXPECT_FFA_ERROR(ret, FFA_DENIED);
-
-	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
-				 args.arg3, args.arg4, args.arg5, args.arg6,
-				 args.arg7);
-}
-
 /**
- * Verify that secondary VMs can't send direct message requests
- * when invoked by FFA_RUN.
+ * Service for indirect message error checking.
+ * The VM unmap its RX/TX and waits for a message.
  */
-TEST_SERVICE(ffa_disallowed_direct_msg_req)
+TEST_SERVICE(ffa_indirect_msg_error)
 {
-	struct ffa_value args;
-	struct ffa_value ret;
+	EXPECT_EQ(ffa_rxtx_unmap().func, FFA_SUCCESS_32);
 
-	ret = ffa_msg_send_direct_req(SERVICE_VM1, HF_PRIMARY_VM_ID, 0, 0, 0, 0,
-				      0);
-	EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
-
-	ret = ffa_msg_send_direct_req(SERVICE_VM1, SERVICE_VM2, 0, 0, 0, 0, 0);
-	EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
-
-	args = ffa_msg_wait();
-	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
-
-	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
-				 args.arg3, args.arg4, args.arg5, args.arg6,
-				 args.arg7);
+	ffa_msg_wait();
 }
 
 /**
- * Verify a secondary VM can't send a direct message response when it hasn't
- * first been sent a request.
- */
-TEST_SERVICE(ffa_disallowed_direct_msg_resp)
-{
-	struct ffa_value args;
-	struct ffa_value ret;
-
-	ret = ffa_msg_send_direct_resp(SERVICE_VM1, HF_PRIMARY_VM_ID, 0, 0, 0,
-				       0, 0);
-	EXPECT_FFA_ERROR(ret, FFA_DENIED);
-
-	args = ffa_msg_wait();
-	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
-
-	ffa_msg_send_direct_resp(ffa_receiver(args), ffa_sender(args),
-				 args.arg3, args.arg4, args.arg5, args.arg6,
-				 args.arg7);
-}
-
-/**
- * Verify a secondary VM can't send a response to a different VM than the one
- * that sent the request.
- * Verify a secondary VM cannot send a response with a sender ID different from
- * its own secondary VM ID.
- */
-TEST_SERVICE(ffa_direct_msg_resp_invalid_sender_receiver)
-{
-	struct ffa_value args = ffa_msg_wait();
-	struct ffa_value res;
-
-	EXPECT_EQ(args.func, FFA_MSG_SEND_DIRECT_REQ_32);
-
-	ffa_vm_id_t sender = ffa_sender(args);
-	ffa_vm_id_t receiver = ffa_receiver(args);
-
-	res = ffa_msg_send_direct_resp(receiver, SERVICE_VM2, 0, 0, 0, 0, 0);
-	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
-
-	res = ffa_msg_send_direct_resp(SERVICE_VM2, sender, 0, 0, 0, 0, 0);
-	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
-
-	ffa_msg_send_direct_resp(receiver, sender, 0, 0, 0, 0, 0);
-}
-
-/**
- * Secondary VM waits for a direct message request but primary VM
- * calls ffa_run instead. Verify the secondary VM does not run.
+ * Service waits for a direct message request but primary VM
+ * calls ffa_run instead. Verify the service does not run.
  */
 TEST_SERVICE(ffa_direct_msg_run)
 {
@@ -193,14 +96,3 @@
 	ffa_msg_send_direct_resp(ffa_receiver(res), ffa_sender(res), 4, 0, 0, 0,
 				 0);
 }
-
-/**
- * Service for indirect message error checking.
- * The VM unmap its RX/TX and waits for a message.
- */
-TEST_SERVICE(ffa_indirect_msg_error)
-{
-	EXPECT_EQ(ffa_rxtx_unmap().func, FFA_SUCCESS_32);
-
-	ffa_msg_wait();
-}