libsp: Add SP messaging layer

Add SP messaging layer on top of FF-A's direct messaging functions.

Change-Id: I70f053c17f20bdb25b6f86a26d185fb3143fcc0d
Signed-off-by: Imre Kis <imre.kis@arm.com>
diff --git a/components/messaging/ffa/libsp/component.cmake b/components/messaging/ffa/libsp/component.cmake
index a72e01c..2fec443 100644
--- a/components/messaging/ffa/libsp/component.cmake
+++ b/components/messaging/ffa/libsp/component.cmake
@@ -15,6 +15,7 @@
 	"${CMAKE_CURRENT_LIST_DIR}/ffa_memory_descriptors.c"
 	"${CMAKE_CURRENT_LIST_DIR}/sp_discovery.c"
 	"${CMAKE_CURRENT_LIST_DIR}/sp_memory_management.c"
+	"${CMAKE_CURRENT_LIST_DIR}/sp_messaging.c"
 	"${CMAKE_CURRENT_LIST_DIR}/sp_rxtx.c"
 	)
 
@@ -29,6 +30,7 @@
 	${CMAKE_CURRENT_LIST_DIR}/include/sp_api_types.h
 	${CMAKE_CURRENT_LIST_DIR}/include/sp_discovery.h
 	${CMAKE_CURRENT_LIST_DIR}/include/sp_memory_management.h
+	${CMAKE_CURRENT_LIST_DIR}/include/sp_messaging.h
 	${CMAKE_CURRENT_LIST_DIR}/include/sp_rxtx.h
 	)
 
diff --git a/components/messaging/ffa/libsp/include/sp_messaging.h b/components/messaging/ffa/libsp/include/sp_messaging.h
new file mode 100644
index 0000000..3ee5aae
--- /dev/null
+++ b/components/messaging/ffa/libsp/include/sp_messaging.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBSP_INCLUDE_SP_MESSAGING_H_
+#define LIBSP_INCLUDE_SP_MESSAGING_H_
+
+#include "sp_api_defines.h"
+#include "sp_api_types.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SP_MSG_ARG_COUNT (4)
+
+/**
+ * @brief      SP message type
+ */
+struct sp_msg {
+	uint16_t source_id;
+	uint16_t destination_id;
+	uint32_t args[SP_MSG_ARG_COUNT];
+};
+
+/**
+ * @brief      Wait for a message and returns it.
+ * @param[out] msg   The received message
+ *
+ * @return     The SP API result
+ */
+sp_result sp_msg_wait(struct sp_msg *msg);
+
+/**
+ * @brief      Sends a request message and waits for the response message
+ *             which it returns then.
+ *
+ * @param[in]  req   The request message
+ * @param[out] resp  The response message
+ *
+ * @return     The SP API result
+ */
+sp_result sp_msg_send_direct_req(const struct sp_msg *req, struct sp_msg *resp);
+
+/**
+ * @brief      Sends a response message and waits for a new request which it
+ *             returns then.
+ *
+ * @param[in]  resp  The response message
+ * @param[out] req   The request message
+ *
+ * @return     The SP API result
+ */
+sp_result sp_msg_send_direct_resp(const struct sp_msg *resp,
+				  struct sp_msg *req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSP_INCLUDE_SP_MESSAGING_H_ */
diff --git a/components/messaging/ffa/libsp/sp_messaging.c b/components/messaging/ffa/libsp/sp_messaging.c
new file mode 100644
index 0000000..9e29384
--- /dev/null
+++ b/components/messaging/ffa/libsp/sp_messaging.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "ffa_api.h"
+#include "sp_api_defines.h"
+#include "sp_messaging.h"
+
+#include <string.h>
+
+#define SP_MSG_ARG_OFFSET (1)
+
+static void pack_ffa_direct_msg(const struct sp_msg *msg,
+				struct ffa_direct_msg *ffa_msg)
+{
+	uint32_t i = 0;
+
+	ffa_msg->source_id = msg->source_id;
+	ffa_msg->destination_id = msg->destination_id;
+
+	ffa_msg->args[0] = 0;
+	memcpy(&ffa_msg->args[SP_MSG_ARG_OFFSET], msg->args, sizeof(msg->args));
+}
+
+static void unpack_ffa_direct_msg(const struct ffa_direct_msg *ffa_msg,
+				  struct sp_msg *msg)
+{
+	uint32_t i = 0;
+
+	if (ffa_msg->function_id != FFA_SUCCESS_32) {
+		/*
+		 * Handling request or response (error is handled before call)
+		 */
+		msg->source_id = ffa_msg->source_id;
+		msg->destination_id = ffa_msg->destination_id;
+
+		memcpy(msg->args, &ffa_msg->args[SP_MSG_ARG_OFFSET],
+		       sizeof(msg->args));
+	} else {
+		/* Success has no message parameters */
+		*msg = (struct sp_msg){ 0 };
+	}
+}
+
+sp_result sp_msg_wait(struct sp_msg *msg)
+{
+	ffa_result ffa_res = FFA_OK;
+	struct ffa_direct_msg ffa_msg = { 0 };
+
+	if (!msg)
+		return SP_RESULT_INVALID_PARAMETERS;
+
+	ffa_res = ffa_msg_wait(&ffa_msg);
+	if (ffa_res != FFA_OK) {
+		*msg = (struct sp_msg){ 0 };
+		return SP_RESULT_FFA(ffa_res);
+	}
+
+	unpack_ffa_direct_msg(&ffa_msg, msg);
+
+	return SP_RESULT_OK;
+}
+
+sp_result sp_msg_send_direct_req(const struct sp_msg *req, struct sp_msg *resp)
+{
+	ffa_result ffa_res = FFA_OK;
+	struct ffa_direct_msg ffa_req = { 0 };
+	struct ffa_direct_msg ffa_resp = { 0 };
+
+	if (!resp)
+		return SP_RESULT_INVALID_PARAMETERS;
+
+	if (!req) {
+		*resp = (struct sp_msg){ 0 };
+		return SP_RESULT_INVALID_PARAMETERS;
+	}
+
+	pack_ffa_direct_msg(req, &ffa_req);
+
+	ffa_res = ffa_msg_send_direct_req(ffa_req.source_id,
+					  ffa_req.destination_id,
+					  ffa_req.args[0], ffa_req.args[1],
+					  ffa_req.args[2], ffa_req.args[3],
+					  ffa_req.args[4], &ffa_resp);
+
+	if (ffa_res != FFA_OK) {
+		*resp = (struct sp_msg){ 0 };
+		return SP_RESULT_FFA(ffa_res);
+	}
+
+	unpack_ffa_direct_msg(&ffa_resp, resp);
+
+	return SP_RESULT_OK;
+}
+
+sp_result sp_msg_send_direct_resp(const struct sp_msg *resp, struct sp_msg *req)
+{
+	ffa_result ffa_res = FFA_OK;
+	struct ffa_direct_msg ffa_resp = { 0 };
+	struct ffa_direct_msg ffa_req = { 0 };
+
+	if (!req)
+		return SP_RESULT_INVALID_PARAMETERS;
+
+	if (!resp) {
+		*req = (struct sp_msg){ 0 };
+		return SP_RESULT_INVALID_PARAMETERS;
+	}
+
+	pack_ffa_direct_msg(resp, &ffa_resp);
+
+	ffa_res = ffa_msg_send_direct_resp(ffa_resp.source_id,
+					   ffa_resp.destination_id,
+					   ffa_resp.args[0], ffa_resp.args[1],
+					   ffa_resp.args[2], ffa_resp.args[3],
+					   ffa_resp.args[4], &ffa_req);
+
+	if (ffa_res != FFA_OK) {
+		*req = (struct sp_msg){ 0 };
+		return SP_RESULT_FFA(ffa_res);
+	}
+
+	unpack_ffa_direct_msg(&ffa_req, req);
+
+	return SP_RESULT_OK;
+}
diff --git a/components/messaging/ffa/libsp/test/test_sp_messaging.cpp b/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
new file mode 100644
index 0000000..2ddf1ab
--- /dev/null
+++ b/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+#include <stdint.h>
+#include <string.h>
+#include "mock_ffa_api.h"
+#include "../include/sp_messaging.h"
+
+#define SP_MSG_ARG_OFFSET (1)
+
+TEST_GROUP(sp_messaging)
+{
+	TEST_SETUP()
+	{
+		memset(&req, 0x00, sizeof(req));
+		memset(&resp, 0x00, sizeof(resp));
+		memset(&ffa_msg, 0x00, sizeof(ffa_msg));
+	}
+
+	TEST_TEARDOWN()
+	{
+		mock().checkExpectations();
+		mock().clear();
+	}
+
+	void copy_sp_to_ffa_args(const uint32_t sp_args[], uint32_t ffa_args[])
+	{
+		int i = 0;
+
+		for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+			ffa_args[i + SP_MSG_ARG_OFFSET] = sp_args[i];
+		}
+	}
+
+	void fill_ffa_msg(struct ffa_direct_msg * msg)
+	{
+		int i = 0;
+
+		msg->function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+		msg->source_id = source_id;
+		msg->destination_id = dest_id;
+
+		msg->args[0] = 0;
+		for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+			msg->args[i + SP_MSG_ARG_OFFSET] = args[i];
+		}
+	}
+
+	void fill_sp_msg(struct sp_msg * msg)
+	{
+		int i = 0;
+
+		msg->source_id = source_id;
+		msg->destination_id = dest_id;
+		for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+			msg->args[i] = args[i + SP_MSG_ARG_OFFSET];
+		}
+	}
+
+	void ffa_and_sp_msg_equal(const struct ffa_direct_msg *ffa_msg,
+				  const struct sp_msg *sp_msg)
+	{
+		int i = 0;
+
+		UNSIGNED_LONGS_EQUAL(ffa_msg->source_id, sp_msg->source_id);
+		UNSIGNED_LONGS_EQUAL(ffa_msg->destination_id,
+				     sp_msg->destination_id);
+		for (i = 0; i < SP_MSG_ARG_COUNT; i++) {
+			UNSIGNED_LONGS_EQUAL(
+				ffa_msg->args[i + SP_MSG_ARG_OFFSET],
+				sp_msg->args[i]);
+		}
+	}
+
+	struct sp_msg req;
+	struct sp_msg resp;
+	struct ffa_direct_msg ffa_msg;
+
+	const uint16_t source_id = 0x1234;
+	const uint16_t dest_id = 0x5678;
+	const uint32_t args[SP_MSG_ARG_COUNT] = { 0x01234567, 0x12345678,
+						  0x23456789, 0x3456789a };
+	const sp_result result = -1;
+	const sp_msg empty_sp_msg = (const sp_msg){ 0 };
+};
+
+TEST(sp_messaging, sp_msg_wait_null_msg)
+{
+	LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS, sp_msg_wait(NULL));
+}
+
+TEST(sp_messaging, sp_msg_wait_ffa_error)
+{
+	ffa_result result = FFA_ABORTED;
+
+	expect_ffa_msg_wait(&ffa_msg, result);
+
+	LONGS_EQUAL(SP_RESULT_FFA(result), sp_msg_wait(&req));
+	MEMCMP_EQUAL(&empty_sp_msg, &req, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_wait)
+{
+	fill_ffa_msg(&ffa_msg);
+	expect_ffa_msg_wait(&ffa_msg, FFA_OK);
+
+	LONGS_EQUAL(SP_RESULT_OK, sp_msg_wait(&req));
+	ffa_and_sp_msg_equal(&ffa_msg, &req);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_resp_null)
+{
+	LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+		    sp_msg_send_direct_req(&req, NULL));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_req_null)
+{
+	memset(&resp, 0x5a, sizeof(resp));
+	LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+		    sp_msg_send_direct_req(NULL, &resp));
+	MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_ffa_error)
+{
+	ffa_result result = FFA_ABORTED;
+	uint32_t expected_ffa_args[5] = { 0 };
+
+	fill_sp_msg(&req);
+	memset(&resp, 0x5a, sizeof(resp));
+	copy_sp_to_ffa_args(req.args, expected_ffa_args);
+	expect_ffa_msg_send_direct_req(
+		req.source_id, req.destination_id, expected_ffa_args[0],
+		expected_ffa_args[1], expected_ffa_args[2],
+		expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, result);
+
+	LONGS_EQUAL(SP_RESULT_FFA(result), sp_msg_send_direct_req(&req, &resp));
+	MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_msg)
+{
+	uint32_t expected_ffa_args[5] = { 0 };
+
+	fill_sp_msg(&req);
+	fill_ffa_msg(&ffa_msg);
+	copy_sp_to_ffa_args(req.args, expected_ffa_args);
+	expect_ffa_msg_send_direct_req(
+		req.source_id, req.destination_id, expected_ffa_args[0],
+		expected_ffa_args[1], expected_ffa_args[2],
+		expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
+
+	LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&req, &resp));
+	ffa_and_sp_msg_equal(&ffa_msg, &resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_success)
+{
+	uint32_t expected_ffa_args[5] = { 0 };
+
+	fill_sp_msg(&req);
+	ffa_msg.function_id = FFA_SUCCESS_32;
+	copy_sp_to_ffa_args(req.args, expected_ffa_args);
+	expect_ffa_msg_send_direct_req(
+		req.source_id, req.destination_id, expected_ffa_args[0],
+		expected_ffa_args[1], expected_ffa_args[2],
+		expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
+
+	LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&req, &resp));
+	MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_resp_req_null)
+{
+	LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+		    sp_msg_send_direct_resp(&resp, NULL));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_resp_resp_null)
+{
+	memset(&req, 0x5a, sizeof(req));
+	LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+		    sp_msg_send_direct_resp(NULL, &req));
+	MEMCMP_EQUAL(&empty_sp_msg, &req, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_resp_ffa_error)
+{
+	ffa_result result = FFA_ABORTED;
+	uint32_t expected_ffa_args[5] = { 0 };
+
+	fill_sp_msg(&resp);
+	memset(&req, 0x5a, sizeof(req));
+	copy_sp_to_ffa_args(resp.args, expected_ffa_args);
+	expect_ffa_msg_send_direct_resp(
+		resp.source_id, resp.destination_id, expected_ffa_args[0],
+		expected_ffa_args[1], expected_ffa_args[2],
+		expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, result);
+
+	LONGS_EQUAL(SP_RESULT_FFA(result),
+		    sp_msg_send_direct_resp(&resp, &req));
+	MEMCMP_EQUAL(&empty_sp_msg, &req, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_resp_msg)
+{
+	uint32_t expected_ffa_args[5] = { 0 };
+
+	fill_sp_msg(&resp);
+	fill_ffa_msg(&ffa_msg);
+	copy_sp_to_ffa_args(resp.args, expected_ffa_args);
+	expect_ffa_msg_send_direct_resp(
+		resp.source_id, resp.destination_id, expected_ffa_args[0],
+		expected_ffa_args[1], expected_ffa_args[2],
+		expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
+
+	LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_resp(&resp, &req));
+	ffa_and_sp_msg_equal(&ffa_msg, &req);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_resp_success)
+{
+	uint32_t expected_ffa_args[5] = { 0 };
+
+	fill_sp_msg(&req);
+	fill_sp_msg(&resp);
+	ffa_msg.function_id = FFA_SUCCESS_32;
+	copy_sp_to_ffa_args(resp.args, expected_ffa_args);
+	expect_ffa_msg_send_direct_resp(
+		resp.source_id, resp.destination_id, expected_ffa_args[0],
+		expected_ffa_args[1], expected_ffa_args[2],
+		expected_ffa_args[3], expected_ffa_args[4], &ffa_msg, FFA_OK);
+
+	LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_resp(&resp, &req));
+	MEMCMP_EQUAL(&empty_sp_msg, &req, sizeof(empty_sp_msg));
+}
diff --git a/components/messaging/ffa/libsp/tests.cmake b/components/messaging/ffa/libsp/tests.cmake
index 1658033..092acef 100644
--- a/components/messaging/ffa/libsp/tests.cmake
+++ b/components/messaging/ffa/libsp/tests.cmake
@@ -126,3 +126,16 @@
 	COMPILE_DEFINITIONS
 		-DARM64
 )
+
+unit_test_add_suite(
+	NAME libsp_sp_messaging
+	SOURCES
+		${CMAKE_CURRENT_LIST_DIR}/test/test_sp_messaging.cpp
+		${CMAKE_CURRENT_LIST_DIR}/test/mock_ffa_api.cpp
+		${CMAKE_CURRENT_LIST_DIR}/sp_messaging.c
+	INCLUDE_DIRECTORIES
+		${CMAKE_CURRENT_LIST_DIR}/include/
+		${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
+	COMPILE_DEFINITIONS
+		-DARM64
+)
\ No newline at end of file