Add TS RPC ABI component

Add definitions and setters/getters for accessing TS RPC protocol fields
of RPC messages transmitted over FF-A direct messages.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I354fee84f693d65382d92eed50634ba9ff69ed65
diff --git a/components/rpc/ts_rpc/common/component.cmake b/components/rpc/ts_rpc/common/component.cmake
new file mode 100644
index 0000000..71d4e8e
--- /dev/null
+++ b/components/rpc/ts_rpc/common/component.cmake
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+	"${CMAKE_CURRENT_LIST_DIR}/ts_rpc_abi.h"
+	)
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/ts_rpc_abi.c"
+	)
diff --git a/components/rpc/ts_rpc/common/test/test_ts_rpc_abi.cpp b/components/rpc/ts_rpc/common/test/test_ts_rpc_abi.cpp
new file mode 100644
index 0000000..463792b
--- /dev/null
+++ b/components/rpc/ts_rpc/common/test/test_ts_rpc_abi.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../ts_rpc_abi.h"
+#include <stdint.h>
+#include <string.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(ts_rpc_abi) {
+	TEST_SETUP() {
+		memset(regs, 0x00, sizeof(regs));
+	}
+
+	void set_regs(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4)
+	{
+		regs[0] = a0;
+		regs[1] = a1;
+		regs[2] = a2;
+		regs[3] = a3;
+		regs[4] = a4;
+	}
+
+	void check_regs(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4)
+	{
+		UNSIGNED_LONGS_EQUAL(a0, regs[0]);
+		UNSIGNED_LONGS_EQUAL(a1, regs[1]);
+		UNSIGNED_LONGS_EQUAL(a2, regs[2]);
+		UNSIGNED_LONGS_EQUAL(a3, regs[3]);
+		UNSIGNED_LONGS_EQUAL(a4, regs[4]);
+	}
+
+	uint32_t regs[5];
+};
+
+TEST(ts_rpc_abi, flags)
+{
+	const uint8_t flags = 0x3f;
+
+	ts_rpc_abi_set_flags(regs, flags);
+	check_regs(0x3f000000, 0, 0, 0, 0);
+
+	UNSIGNED_LONGS_EQUAL(flags, ts_rpc_abi_get_flags(regs));
+}
+
+TEST(ts_rpc_abi, interface_id)
+{
+	const uint8_t interface_id = 0xa5;
+
+	ts_rpc_abi_set_interface_id(regs, interface_id);
+	check_regs(0x00a50000, 0, 0, 0, 0);
+
+	UNSIGNED_LONGS_EQUAL(interface_id, ts_rpc_abi_get_interface_id(regs));
+}
+
+TEST(ts_rpc_abi, management_interface_id)
+{
+	CHECK_FALSE(ts_rpc_abi_is_management_interface_id(regs));
+
+	ts_rpc_abi_set_management_interface_id(regs);
+	check_regs(0x00ff0000, 0, 0, 0, 0);
+
+	CHECK_TRUE(ts_rpc_abi_is_management_interface_id(regs));
+}
+
+TEST(ts_rpc_abi, opcode)
+{
+	const uint16_t opcode = 0x8765;
+
+	ts_rpc_abi_set_opcode(regs, 0x8765);
+	check_regs(0x00008765, 0, 0, 0, 0);
+
+	UNSIGNED_LONGS_EQUAL(0x8765, ts_rpc_abi_get_opcode(regs));
+}
+
+TEST(ts_rpc_abi, copy_control_reg)
+{
+	uint32_t source_regs[5] = { 0xfedcba98, 0, 0, 0, 0 };
+
+	ts_rpc_abi_copy_control_reg(regs, source_regs);
+
+	check_regs(0xfedcba98, 0, 0, 0, 0);
+}
+
+TEST(ts_rpc_abi, version)
+{
+	const uint32_t version = 0x98765432;
+
+	ts_rpc_abi_set_version(regs, version);
+	check_regs(0, version, 0, 0, 0);
+
+	UNSIGNED_LONGS_EQUAL(version, ts_rpc_abi_get_version(regs));
+
+}
+
+TEST(ts_rpc_abi, memory_handle)
+{
+	const uint64_t handle = 0xfedcba9876543210;
+
+	ts_rpc_abi_set_memory_handle(regs, handle);
+	check_regs(0, 0x76543210, 0xfedcba98, 0, 0);
+
+	UNSIGNED_LONGLONGS_EQUAL(handle, ts_rpc_abi_get_memory_handle(regs));
+}
+
+TEST(ts_rpc_abi, memory_tag)
+{
+	const uint64_t tag = 0xfedcba9876543210;
+
+	ts_rpc_abi_set_memory_tag(regs, tag);
+	check_regs(0, 0, 0, 0x76543210, 0xfedcba98);
+
+	UNSIGNED_LONGLONGS_EQUAL(tag, ts_rpc_abi_get_memory_tag(regs));
+}
+
+TEST(ts_rpc_abi, rpc_status)
+{
+	const uint32_t rpc_status = 0x89abcdef;
+
+	ts_rpc_abi_set_rpc_status(regs, rpc_status);
+	check_regs(0, rpc_status, 0, 0, 0);
+
+	UNSIGNED_LONGS_EQUAL(rpc_status, ts_rpc_abi_get_rpc_status(regs));
+}
+
+TEST(ts_rpc_abi, service_status)
+{
+	const uint32_t service_status = 0x89abcdef;
+
+	ts_rpc_abi_set_service_status(regs, service_status);
+	check_regs(0, 0, service_status, 0, 0);
+
+	UNSIGNED_LONGS_EQUAL(service_status, ts_rpc_abi_get_service_status(regs));
+}
+
+TEST(ts_rpc_abi, uuid)
+{
+	const struct rpc_uuid expected = {
+		.uuid = { 0xf0, 0x33, 0xbe, 0x6d, 0x6c, 0xc4, 0x47, 0x38,
+			  0x88, 0xfd, 0xdd, 0x44, 0xac, 0x56, 0x2b, 0x69}
+	};
+	struct rpc_uuid actual = { 0 };
+
+	ts_rpc_abi_set_uuid(regs, &expected);
+	check_regs(0, 0x6dbe33f0, 0x3847c46c, 0x44ddfd88, 0x692b56ac);
+
+	ts_rpc_abi_get_uuid(regs, &actual);
+	MEMCMP_EQUAL(expected.uuid, actual.uuid, sizeof(expected));
+}
+
+TEST(ts_rpc_abi, queried_interface_id)
+{
+	const uint8_t interface_id = 0xa5;
+
+	ts_rpc_abi_set_queried_interface_id(regs, interface_id);
+	check_regs(0, 0, interface_id, 0, 0);
+
+	UNSIGNED_LONGS_EQUAL(interface_id, ts_rpc_abi_get_queried_interface_id(regs));
+}
+
+TEST(ts_rpc_abi, request_length)
+{
+	const uint32_t length = 0x12345678;
+
+	ts_rpc_abi_set_request_length(regs, length);
+	check_regs(0, 0, 0, length, 0);
+
+	UNSIGNED_LONGS_EQUAL(length, ts_rpc_abi_get_request_length(regs));
+}
+
+TEST(ts_rpc_abi, client_id)
+{
+	const uint32_t client_id = 0xabcdef01;
+
+	ts_rpc_abi_set_client_id(regs, client_id);
+	check_regs(0, 0, 0, 0, client_id);
+
+	UNSIGNED_LONGS_EQUAL(client_id, ts_rpc_abi_get_client_id(regs));
+}
+
+TEST(ts_rpc_abi, response_length)
+{
+	const uint32_t length = 0x12345678;
+
+	ts_rpc_abi_set_response_length(regs, length);
+	check_regs(0, 0, 0, length, 0);
+
+	UNSIGNED_LONGS_EQUAL(length, ts_rpc_abi_get_response_length(regs));
+}
diff --git a/components/rpc/ts_rpc/common/ts_rpc_abi.c b/components/rpc/ts_rpc/common/ts_rpc_abi.c
new file mode 100644
index 0000000..674e668
--- /dev/null
+++ b/components/rpc/ts_rpc/common/ts_rpc_abi.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "ts_rpc_abi.h"
+#include <string.h>
+
+#define TS_RPC_CONTROL_REG			(0)
+
+#define TS_RPC_FLAGS_REG			(0)
+#define TS_RPC_FLAGS_SHIFT			(24)
+#define TS_RPC_FLAGS_MASK			(0x3f)
+
+#define TS_RPC_INTERFACE_ID_REG			(0)
+#define TS_RPC_INTERFACE_ID_SHIFT		(16)
+#define TS_RPC_INTERFACE_ID_MASK		(0xff)
+
+#define TS_RPC_MANAGEMENT_INTERFACE_ID		(0xff)
+
+#define TS_RPC_OPCODE_REG			(0)
+#define TS_RPC_OPCODE_SHIFT			(0)
+#define TS_RPC_OPCODE_MASK			(0xffff)
+
+#define TS_RPC_VERSION_REG			(1)
+#define TS_RPC_MEMORY_HANDLE_LSW_REG		(1)
+#define TS_RPC_MEMORY_HANDLE_MSW_REG		(2)
+#define TS_RPC_MEMORY_TAG_LSW_REG		(3)
+#define TS_RPC_MEMORY_TAG_MSW_REG		(4)
+#define TS_RPC_RPC_STATUS_REG			(1)
+#define TS_RPC_SERVICE_STATUS_REG		(2)
+#define TS_RPC_UUID_START_REG			(1)
+
+#define TS_RPC_QUERIED_INTERFACE_ID_REG		(2)
+#define TS_RPC_QUERIED_INTERFACE_ID_SHIFT	(0)
+#define TS_RPC_QUERIED_INTERFACE_ID_MASK	(0xff)
+
+#define TS_RPC_REQUEST_LENGTH_REG		(3)
+#define TS_RPC_CLIENT_ID_REG			(4)
+#define TS_RPC_RESPONSE_LENGTH_REG		(3)
+#define TS_RPC_FAST_REQUEST_DATA_START_REG	(1)
+#define TS_RPC_FAST_RESPONSE_DATA_START_REG	(2)
+
+static uint32_t get_field(const uint32_t regs[5], uint32_t reg, uint32_t shift, uint32_t mask)
+{
+	return (regs[reg] >> shift) & mask;
+}
+
+static void set_field(uint32_t regs[5], uint32_t reg, uint32_t shift, uint32_t mask,
+		      uint32_t value)
+{
+	regs[reg] &= ~(mask << shift);
+	regs[reg] |= (value & mask) << shift;
+}
+
+uint8_t ts_rpc_abi_get_flags(const uint32_t regs[5])
+{
+	return get_field(regs, TS_RPC_FLAGS_REG, TS_RPC_FLAGS_SHIFT, TS_RPC_FLAGS_MASK);
+}
+
+void ts_rpc_abi_set_flags(uint32_t regs[5], uint8_t flags)
+{
+	set_field(regs, TS_RPC_FLAGS_REG, TS_RPC_FLAGS_SHIFT, TS_RPC_FLAGS_MASK, flags);
+}
+
+uint8_t ts_rpc_abi_get_interface_id(const uint32_t regs[5])
+{
+	return get_field(regs, TS_RPC_INTERFACE_ID_REG, TS_RPC_INTERFACE_ID_SHIFT,
+			 TS_RPC_INTERFACE_ID_MASK);
+}
+
+void ts_rpc_abi_set_interface_id(uint32_t regs[5], uint8_t interface_id)
+{
+	set_field(regs, TS_RPC_INTERFACE_ID_REG, TS_RPC_INTERFACE_ID_SHIFT,
+		  TS_RPC_INTERFACE_ID_MASK, interface_id);
+}
+
+bool ts_rpc_abi_is_management_interface_id(const uint32_t regs[5])
+{
+	return ts_rpc_abi_get_interface_id(regs) == TS_RPC_MANAGEMENT_INTERFACE_ID;
+}
+
+void ts_rpc_abi_set_management_interface_id(uint32_t regs[5])
+{
+	ts_rpc_abi_set_interface_id(regs, TS_RPC_MANAGEMENT_INTERFACE_ID);
+}
+
+uint16_t ts_rpc_abi_get_opcode(const uint32_t regs[5])
+{
+	return get_field(regs, TS_RPC_OPCODE_REG, TS_RPC_OPCODE_SHIFT, TS_RPC_OPCODE_MASK);
+}
+
+void ts_rpc_abi_set_opcode(uint32_t regs[5], uint16_t opcode)
+{
+	set_field(regs, TS_RPC_OPCODE_REG, TS_RPC_OPCODE_SHIFT, TS_RPC_OPCODE_MASK, opcode);
+}
+
+void ts_rpc_abi_copy_control_reg(uint32_t response_regs[5], const uint32_t request_regs[5])
+{
+	response_regs[TS_RPC_CONTROL_REG] = request_regs[TS_RPC_CONTROL_REG];
+}
+
+uint32_t ts_rpc_abi_get_version(const uint32_t regs[5])
+{
+	return regs[TS_RPC_VERSION_REG];
+}
+
+void ts_rpc_abi_set_version(uint32_t regs[5], uint32_t version)
+{
+	regs[TS_RPC_VERSION_REG] = version;
+}
+
+uint64_t ts_rpc_abi_get_memory_handle(const uint32_t regs[5])
+{
+	return (uint64_t)regs[TS_RPC_MEMORY_HANDLE_MSW_REG] << 32 |
+		regs[TS_RPC_MEMORY_HANDLE_LSW_REG];
+}
+
+void ts_rpc_abi_set_memory_handle(uint32_t regs[5], uint64_t handle)
+{
+	regs[TS_RPC_MEMORY_HANDLE_LSW_REG] = handle;
+	regs[TS_RPC_MEMORY_HANDLE_MSW_REG] = handle >> 32;
+}
+
+uint64_t ts_rpc_abi_get_memory_tag(const uint32_t regs[5])
+{
+	return (uint64_t)regs[TS_RPC_MEMORY_TAG_MSW_REG] << 32 | regs[TS_RPC_MEMORY_TAG_LSW_REG];
+}
+
+void ts_rpc_abi_set_memory_tag(uint32_t regs[5], uint64_t tag)
+{
+	regs[TS_RPC_MEMORY_TAG_LSW_REG] = tag;
+	regs[TS_RPC_MEMORY_TAG_MSW_REG] = tag >> 32;
+}
+
+uint32_t ts_rpc_abi_get_rpc_status(const uint32_t regs[5])
+{
+	return regs[TS_RPC_RPC_STATUS_REG];
+}
+
+void ts_rpc_abi_set_rpc_status(uint32_t regs[5], uint32_t status)
+{
+	regs[TS_RPC_RPC_STATUS_REG] = status;
+}
+
+uint32_t ts_rpc_abi_get_service_status(const uint32_t regs[5])
+{
+	return regs[TS_RPC_SERVICE_STATUS_REG];
+}
+
+void ts_rpc_abi_set_service_status(uint32_t regs[5], uint32_t status)
+{
+	regs[TS_RPC_SERVICE_STATUS_REG] = status;
+}
+
+void ts_rpc_abi_get_uuid(const uint32_t regs[5], struct rpc_uuid *uuid)
+{
+	memcpy(uuid, &regs[TS_RPC_UUID_START_REG], sizeof(*uuid));
+}
+
+void ts_rpc_abi_set_uuid(uint32_t regs[5], const struct rpc_uuid *uuid)
+{
+	memcpy(&regs[TS_RPC_UUID_START_REG], uuid, sizeof(*uuid));
+}
+
+uint8_t ts_rpc_abi_get_queried_interface_id(const uint32_t regs[5])
+{
+	return get_field(regs, TS_RPC_QUERIED_INTERFACE_ID_REG, TS_RPC_QUERIED_INTERFACE_ID_SHIFT,
+			 TS_RPC_QUERIED_INTERFACE_ID_MASK);
+}
+
+void ts_rpc_abi_set_queried_interface_id(uint32_t regs[5], uint8_t interface_id)
+{
+	set_field(regs, TS_RPC_QUERIED_INTERFACE_ID_REG, TS_RPC_QUERIED_INTERFACE_ID_SHIFT,
+		  TS_RPC_QUERIED_INTERFACE_ID_MASK, interface_id);
+}
+
+uint32_t ts_rpc_abi_get_request_length(const uint32_t regs[5])
+{
+	return regs[TS_RPC_REQUEST_LENGTH_REG];
+}
+
+void ts_rpc_abi_set_request_length(uint32_t regs[5], uint32_t length)
+{
+	regs[TS_RPC_REQUEST_LENGTH_REG] = length;
+}
+
+uint32_t ts_rpc_abi_get_client_id(const uint32_t regs[5])
+{
+	return regs[TS_RPC_CLIENT_ID_REG];
+}
+
+void ts_rpc_abi_set_client_id(uint32_t regs[5], uint32_t client_id)
+{
+	regs[TS_RPC_CLIENT_ID_REG] = client_id;
+}
+
+uint32_t ts_rpc_abi_get_response_length(const uint32_t regs[5])
+{
+	return regs[TS_RPC_RESPONSE_LENGTH_REG];
+}
+
+void ts_rpc_abi_set_response_length(uint32_t regs[5], uint32_t length)
+{
+	regs[TS_RPC_RESPONSE_LENGTH_REG] = length;
+}
diff --git a/components/rpc/ts_rpc/common/ts_rpc_abi.h b/components/rpc/ts_rpc/common/ts_rpc_abi.h
new file mode 100644
index 0000000..8b0fa1c
--- /dev/null
+++ b/components/rpc/ts_rpc/common/ts_rpc_abi.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_RPC_ABI_H
+#define TS_RPC_ABI_H
+
+#include "rpc_uuid.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Trusted-services RPC ABI function
+ *
+ * This file contains getters and setters for TS ABI fields. They handle the five arg registers of
+ * the FF-A direct messages and extract or insert fields of suitable types.
+ */
+
+#define TS_RPC_ABI_FLAG_FAST_CALL			(0x01)
+
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_VERSION		(0)
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RETRIEVE	(1)
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_MEMORY_RELINQUISH	(2)
+#define TS_RPC_ABI_MANAGEMENT_OPCODE_INTERFACE_ID_QUERY	(3)
+
+#define TS_RPC_ABI_VERSION_V1				(1)
+
+uint8_t ts_rpc_abi_get_flags(const uint32_t regs[5]);
+void ts_rpc_abi_set_flags(uint32_t regs[5], uint8_t flags);
+
+uint8_t ts_rpc_abi_get_interface_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_interface_id(uint32_t regs[5], uint8_t interface_id);
+
+bool ts_rpc_abi_is_management_interface_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_management_interface_id(uint32_t regs[5]);
+
+uint16_t ts_rpc_abi_get_opcode(const uint32_t regs[5]);
+void ts_rpc_abi_set_opcode(uint32_t regs[5], uint16_t interface_id);
+
+void ts_rpc_abi_copy_control_reg(uint32_t response_regs[5], const uint32_t request_regs[5]);
+
+uint32_t ts_rpc_abi_get_version(const uint32_t regs[5]);
+void ts_rpc_abi_set_version(uint32_t regs[5], uint32_t version);
+
+uint64_t ts_rpc_abi_get_memory_handle(const uint32_t regs[5]);
+void ts_rpc_abi_set_memory_handle(uint32_t regs[5], uint64_t handle);
+
+uint64_t ts_rpc_abi_get_memory_tag(const uint32_t regs[5]);
+void ts_rpc_abi_set_memory_tag(uint32_t regs[5], uint64_t tag);
+
+uint32_t ts_rpc_abi_get_rpc_status(const uint32_t regs[5]);
+void ts_rpc_abi_set_rpc_status(uint32_t regs[5], uint32_t status);
+
+uint32_t ts_rpc_abi_get_service_status(const uint32_t regs[5]);
+void ts_rpc_abi_set_service_status(uint32_t regs[5], uint32_t status);
+
+void ts_rpc_abi_get_uuid(const uint32_t regs[5], struct rpc_uuid *uuid);
+void ts_rpc_abi_set_uuid(uint32_t regs[5], const struct rpc_uuid *uuid);
+
+uint8_t ts_rpc_abi_get_queried_interface_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_queried_interface_id(uint32_t regs[5], uint8_t interface_id);
+
+uint32_t ts_rpc_abi_get_request_length(const uint32_t regs[5]);
+void ts_rpc_abi_set_request_length(uint32_t regs[5], uint32_t length);
+
+uint32_t ts_rpc_abi_get_client_id(const uint32_t regs[5]);
+void ts_rpc_abi_set_client_id(uint32_t regs[5], uint32_t client_id);
+
+uint32_t ts_rpc_abi_get_response_length(const uint32_t regs[5]);
+void ts_rpc_abi_set_response_length(uint32_t regs[5], uint32_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TS_RPC_ABI_H */