feat(indirect message): send and receive messages

Added helpers to receive and send indirect messages, respectively:
- `receive_indirect_message`;
- `send_indirect_message`;

Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I396870f15172f841167627b14c18b1504e0efbee
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index ad2ba08..fb1f61e 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -150,4 +150,10 @@
 	ffa_id_t receiver_id,
 	uint32_t mem_func);
 
+bool receive_indirect_message(void *buffer, size_t buffer_size, void *recv,
+			      ffa_id_t *sender, ffa_id_t receiver,
+			      ffa_id_t own_id);
+struct ffa_value send_indirect_message(
+		ffa_id_t from, ffa_id_t to, void *send, const void *payload,
+		size_t payload_size, uint32_t send_flags);
 #endif /* SPM_COMMON_H */
diff --git a/tftf/tests/aarch32_tests_to_skip.txt b/tftf/tests/aarch32_tests_to_skip.txt
index 210d465..6913cb1 100644
--- a/tftf/tests/aarch32_tests_to_skip.txt
+++ b/tftf/tests/aarch32_tests_to_skip.txt
@@ -18,3 +18,4 @@
 FF-A Notifications
 RMI and SPM tests
 FF-A SMCCC compliance
+FF-A Indirect Messaging
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 45ab71a..ffd488d 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -10,6 +10,7 @@
 #include <cactus_test_cmds.h>
 #include <debug.h>
 #include <ffa_endpoints.h>
+#include <assert.h>
 #include <ffa_svc.h>
 #include <lib/extensions/sve.h>
 #include <spm_common.h>
@@ -841,3 +842,107 @@
 	return ffa_memory_access_init(receiver_id, data_access,
 				      instruction_access, 0, NULL);
 }
+
+/**
+ * Receives message from the mailbox, copies it into the 'buffer', gets the
+ * pending framework notifications and releases the RX buffer.
+ * Returns false if it fails to copy the message to `buffer`, or true
+ * otherwise.
+ */
+bool receive_indirect_message(void *buffer, size_t buffer_size, void *recv,
+			      ffa_id_t *sender, ffa_id_t receiver, ffa_id_t own_id)
+{
+	const struct ffa_partition_msg *message;
+	struct ffa_partition_rxtx_header header;
+	ffa_id_t source_vm_id;
+	const uint32_t *payload;
+	struct ffa_value ret;
+	ffa_notification_bitmap_t fwk_notif;
+
+	if (buffer_size > FFA_MSG_PAYLOAD_MAX) {
+		return false;
+	}
+
+	ret = ffa_notification_get(receiver, 0,
+				   FFA_NOTIFICATIONS_FLAG_BITMAP_SPM);
+	if (is_ffa_call_error(ret)) {
+		return false;
+	}
+
+	fwk_notif = ffa_notification_get_from_framework(ret);
+
+	if (fwk_notif == 0U) {
+		ERROR("Expected Rx buffer full notification.");
+		return false;
+	}
+
+	message = (const struct ffa_partition_msg *)recv;
+	memcpy(&header, message, sizeof(struct ffa_partition_rxtx_header));
+
+	source_vm_id = header.sender;
+
+	if (is_ffa_spm_buffer_full_notification(fwk_notif)) {
+		/*
+		 * Expect the sender to always have been an SP.
+		 */
+		assert(IS_SP_ID(source_vm_id));
+	}
+
+	if (header.size > buffer_size) {
+		ERROR("Error in rxtx header. Message size: %#x; "
+		      "buffer size: %lu\n",
+		      header.size, buffer_size);
+		return false;
+	}
+
+	payload = (const uint32_t *)message->payload;
+
+	/* Get message to free the RX buffer. */
+	memcpy(buffer, payload, header.size);
+
+	/* Check receiver ID against own ID. */
+	if (receiver != own_id) {
+		ret = ffa_rx_release_with_id(receiver);
+	} else {
+		ret = ffa_rx_release();
+	}
+
+	if (is_ffa_call_error(ret)) {
+		ERROR("Failed to release the rx buffer\n");
+		return false;
+	}
+
+	if (receiver != header.receiver) {
+		ERROR("Header receiver: %x different than expected receiver: %x\n",
+		      header.receiver, receiver);
+		return false;
+	}
+
+
+	if (sender != NULL) {
+		*sender = source_vm_id;
+	}
+
+	return true;
+}
+
+/**
+ * Sends an indirect message: initializes the `ffa_rxtx_header`, copies the
+ * payload to the TX buffer.
+ * Uses the `send_flags` if any are provided in the call to FFA_MSG_SEND2.
+ */
+struct ffa_value send_indirect_message(
+		ffa_id_t from, ffa_id_t to, void *send, const void *payload,
+		size_t payload_size, uint32_t send_flags)
+{
+	struct ffa_partition_msg *message = (struct ffa_partition_msg *)send;
+
+	/* Initialize message header. */
+	ffa_rxtx_header_init(from, to, payload_size, &message->header);
+
+	/* Fill TX buffer with payload. */
+	memcpy(message->payload, payload, payload_size);
+
+	/* Send the message. */
+	return ffa_msg_send2(send_flags);
+}