Add RPC service interface
Add interface for implementing services in an RPC endpoint.
Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: Id2639afa003da46230c93e6e55ff2ffa781df53d
diff --git a/components/rpc/common/endpoint/component.cmake b/components/rpc/common/endpoint/component.cmake
new file mode 100644
index 0000000..7d83028
--- /dev/null
+++ b/components/rpc/common/endpoint/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# 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()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rpc_service_interface.c"
+ )
+
diff --git a/components/rpc/common/endpoint/rpc_interface.h b/components/rpc/common/endpoint/rpc_interface.h
deleted file mode 100644
index eb98587..0000000
--- a/components/rpc/common/endpoint/rpc_interface.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef RPC_INTERFACE_H
-#define RPC_INTERFACE_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <rpc_status.h>
-#include <protocols/rpc/common/packed-c/status.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Definitions related to an rpc call endpoint */
-
-/** \brief Call parameter buffer
- *
- * Describes a buffer for holding call request and response parameters.
- */
-struct call_param_buf {
- size_t size;
- size_t data_len;
- void *data;
-};
-
-static inline struct call_param_buf call_param_buf_init_empty(void *data, size_t size)
-{
- struct call_param_buf v;
-
- v.size = size;
- v.data_len = 0;
- v.data = data;
-
- return v;
-}
-
-static inline struct call_param_buf call_param_buf_init_full(void *data,
- size_t size,
- size_t data_len)
-{
- struct call_param_buf v;
-
- v.size = size;
- v.data_len = data_len;
- v.data = data;
-
- return v;
-}
-
-/** \brief Call request
- *
- * A call request object represents a request from a client that will
- * be handled by a call endpoint.
- */
-struct call_req {
- uint32_t caller_id;
- uint32_t interface_id;
- uint32_t opcode;
- uint32_t encoding;
- rpc_opstatus_t opstatus;
- struct call_param_buf req_buf;
- struct call_param_buf resp_buf;
-};
-
-static inline uint32_t call_req_get_caller_id(const struct call_req *req)
-{
- return req->caller_id;
-}
-
-static inline uint32_t call_req_get_interface_id(const struct call_req *req)
-{
- return req->interface_id;
-}
-
-static inline uint32_t call_req_get_opcode(const struct call_req *req)
-{
- return req->opcode;
-}
-
-static inline uint32_t call_req_get_encoding(const struct call_req *req)
-{
- return req->encoding;
-}
-
-static inline rpc_opstatus_t call_req_get_opstatus(const struct call_req *req)
-{
- return req->opstatus;
-}
-
-static inline void call_req_set_opstatus(struct call_req *req, rpc_opstatus_t opstatus)
-{
- req->opstatus = opstatus;
-}
-
-static inline struct call_param_buf *call_req_get_req_buf(struct call_req *req)
-{
- return &req->req_buf;
-}
-
-static inline struct call_param_buf *call_req_get_resp_buf(struct call_req *req)
-{
- return &req->resp_buf;
-}
-
-/** \brief RPC interface
- *
- * A generalized RPC interface. Provides a standard interface for a
- * call endpoint that handles incoming call requests.
- */
-struct rpc_interface
-{
- void *context;
- rpc_status_t (*receive)(struct rpc_interface *iface, struct call_req *req);
-};
-
-static inline rpc_status_t rpc_interface_receive(struct rpc_interface *iface,
- struct call_req *req)
-{
- rpc_status_t rpc_status = TS_RPC_ERROR_INTERFACE_DOES_NOT_EXIST;
-
- if (iface) {
-
- rpc_status = iface->receive(iface, req);
- }
-
- return rpc_status;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* RPC_INTERFACE_H */
diff --git a/components/rpc/common/endpoint/rpc_service_interface.c b/components/rpc/common/endpoint/rpc_service_interface.c
new file mode 100644
index 0000000..67eeb2e
--- /dev/null
+++ b/components/rpc/common/endpoint/rpc_service_interface.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rpc_service_interface.h"
+
+rpc_status_t rpc_service_receive(struct rpc_service_interface *service,
+ struct rpc_request *request)
+{
+ if (!service)
+ return RPC_ERROR_INVALID_VALUE;
+
+ return service->receive(service->context, request);
+}
diff --git a/components/rpc/common/endpoint/rpc_service_interface.h b/components/rpc/common/endpoint/rpc_service_interface.h
new file mode 100644
index 0000000..3fdfed2
--- /dev/null
+++ b/components/rpc/common/endpoint/rpc_service_interface.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPC_INTERFACE_H
+#define RPC_INTERFACE_H
+
+#include "rpc_status.h"
+#include "rpc_uuid.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef EXPORT_PUBLIC_INTERFACE_RPC_SERVICE
+#define RPC_SERVICE_EXPORTED __attribute__((__visibility__("default")))
+#else
+#define RPC_SERVICE_EXPORTED
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief RPC buffer
+ *
+ * Describes an RPC buffer by its data pointer, size and the used data length.
+ */
+struct rpc_buffer {
+ uint8_t *data;
+ size_t data_length;
+ size_t size;
+};
+
+/**
+ * @brief RPC request
+ *
+ * The service should select the requested function by the opcode field. The call's request and
+ * response parameter buffer is accessible via the request and response rpc_buffers. The response's
+ * size must be indicated by the service through setting the data_length field of the response.
+ * The services can identify the caller via the source_id and client_id fields.
+ */
+struct rpc_request {
+ uint16_t source_id; /** Call source ID (i.e. FF-A source ID) */
+ uint8_t interface_id; /** Service interface ID */
+ uint16_t opcode; /** Opcode of the required function */
+ uint32_t client_id; /** Client ID for further caller identification */
+ service_status_t service_status; /** Service specific status code */
+ struct rpc_buffer request; /** Request buffer */
+ struct rpc_buffer response; /** Response buffer */
+};
+
+/**
+ * @brief RPC service interface
+ *
+ * An endpoint (i.e. secure partition) can implement multiple services which are identified by their
+ * service UUID. Once an endpoint receives an RPC call, it selects the matching
+ * rpc_service_interface instance, builds the rpc_request structure and calls the interface's
+ * receive function.
+ * If the service is not able to parse the request (invalid opcode, request or response buffer)
+ * it should return an rpc_status_t value indicating the issue with the RPC request. Otherwise it
+ * must return RPC_SUCCESS.
+ * Service level status codes should be passed in a service specific way.
+ */
+struct rpc_service_interface {
+ void *context;
+ struct rpc_uuid uuid;
+
+ rpc_status_t (*receive)(void *context, struct rpc_request *request);
+};
+
+/**
+ * @brief Call the receive function of the RPC interface.
+ *
+ * @param service The service instance
+ * @param request RPC request
+ * @return rpc_status_t
+ */
+RPC_SERVICE_EXPORTED
+rpc_status_t rpc_service_receive(struct rpc_service_interface *service,
+ struct rpc_request *request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RPC_INTERFACE_H */
diff --git a/components/rpc/common/test/call_param_buf_comparator.h b/components/rpc/common/test/call_param_buf_comparator.h
deleted file mode 100644
index 6bfa727..0000000
--- a/components/rpc/common/test/call_param_buf_comparator.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#ifndef CALL_PARAM_BUF_COMPARATOR_H_
-#define CALL_PARAM_BUF_COMPARATOR_H_
-
-#include <CppUTestExt/MockSupport.h>
-#include "../endpoint/rpc_interface.h"
-
-class call_param_buf_comparator : public MockNamedValueComparator
-{
-public:
- enum check_mode {
- mode_normal = 0,
- mode_ignore_data_len
- };
-
- call_param_buf_comparator(check_mode mode = mode_normal) : mode(mode)
- {
- }
-
- virtual bool isEqual(const void *object1, const void *object2)
- {
- struct call_param_buf *buf1 = (struct call_param_buf *)object1;
- struct call_param_buf *buf2 = (struct call_param_buf *)object2;
-
- return (buf1->size == buf2->size) &&
- (mode == mode_ignore_data_len || (buf1->data_len == buf2->data_len)) &&
- (buf1->data == buf2->data);
- }
-
- // LCOV_EXCL_START
- virtual SimpleString valueToString(const void *object)
- {
- struct call_param_buf *buf = (struct call_param_buf *)object;
-
- return StringFromFormat("<size = %zu, data_len = %zu%s, data = %p>",
- buf->size, buf->data_len,
- (mode == mode_ignore_data_len) ? " (ignored)" : "",
- buf->data);
- }
- // LCOV_EXCL_STOP
-
-private:
- check_mode mode;
-};
-
-#endif /* CALL_PARAM_BUF_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/call_req_comparator.h b/components/rpc/common/test/call_req_comparator.h
deleted file mode 100644
index 753bab2..0000000
--- a/components/rpc/common/test/call_req_comparator.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
- */
-
-#ifndef CALL_REQ_COMPARATOR_H_
-#define CALL_REQ_COMPARATOR_H_
-
-#include <CppUTestExt/MockSupport.h>
-#include <inttypes.h>
-#include "call_param_buf_comparator.h"
-
-class call_req_comparator : public MockNamedValueComparator
-{
-public:
- enum check_mode {
- mode_normal = 0,
- mode_ignore_opstatus
- };
-
- call_req_comparator(check_mode mode) : mode(mode)
- {
- }
-
- virtual bool isEqual(const void *object1, const void *object2)
- {
- struct call_req *req1 = (struct call_req *)object1;
- struct call_req *req2 = (struct call_req *)object2;
- call_param_buf_comparator buf_comparator_normal;
- call_param_buf_comparator buf_comparator_ignore_data_len(
- call_param_buf_comparator::mode_ignore_data_len);
-
- return (req1->caller_id == req2->caller_id) &&
- (req1->interface_id == req2->interface_id) &&
- (req1->opcode == req2->opcode) &&
- (req1->encoding == req2->encoding) &&
- (mode == mode_ignore_opstatus || req1->opstatus == req2->opstatus) &&
- buf_comparator_normal.isEqual(&req1->req_buf, &req2->req_buf) &&
- buf_comparator_ignore_data_len.isEqual(&req1->resp_buf, &req2->resp_buf);
- }
-
- // LCOV_EXCL_START
- virtual SimpleString valueToString(const void *object)
- {
- struct call_req *req = (struct call_req *)object;
- call_param_buf_comparator buf_comparator_normal;
- call_param_buf_comparator buf_comparator_ignore_data_len(
- call_param_buf_comparator::mode_ignore_data_len);
- SimpleString req_buf_str = buf_comparator_normal.valueToString(&req->req_buf);
- SimpleString resp_buf_str =
- buf_comparator_ignore_data_len.valueToString(&req->resp_buf);
-
- return StringFromFormat("caller_id = 0x%" PRIx32 ", interface_id = %" PRIu32 ", " \
- "opcode = %" PRIu32 ", encoding = %" PRIu32 ", " \
- "opstatus = 0x%" PRIx64 "%s, req_buf = %s, " \
- "resp_buf = %s",
- req->caller_id, req->interface_id, req->opcode,
- req->encoding, req->opstatus,
- (mode == mode_ignore_opstatus) ? " (ignore)" : "",
- req_buf_str.asCharString(), resp_buf_str.asCharString());
- }
- // LCOV_EXCL_STOP
-
-private:
- check_mode mode;
-};
-
-#endif /* CALL_REQ_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/mock_rpc_interface.cpp b/components/rpc/common/test/mock_rpc_interface.cpp
index af3836d..cf4a005 100644
--- a/components/rpc/common/test/mock_rpc_interface.cpp
+++ b/components/rpc/common/test/mock_rpc_interface.cpp
@@ -5,34 +5,34 @@
#include <CppUTestExt/MockSupport.h>
#include "mock_rpc_interface.h"
-#include "call_req_comparator.h"
+#include "rpc_request_comparator.h"
-static call_req_comparator req_comparator(call_req_comparator::mode_ignore_opstatus);
+static rpc_request_comparator req_comparator(rpc_request_comparator::mode_ignore_opstatus);
void mock_rpc_interface_init(void)
{
mock().installComparator("call_req", req_comparator);
}
-void expect_mock_rpc_interface_receive(struct rpc_interface *iface,
- const struct call_req *req, rpc_status_t result)
+void expect_mock_rpc_interface_receive(void *context,
+ const struct rpc_request *req, rpc_status_t result)
{
mock().expectOneCall("rpc_interface_receive").
- onObject(iface).
- withOutputParameterReturning("opstatus", &req->opstatus, sizeof(req->opstatus)).
- withOutputParameterReturning("resp_buf_data_len", &req->resp_buf.data_len,
- sizeof(req->resp_buf.data_len)).
+ onObject(context).
+ withOutputParameterReturning("service_status", &req->service_status, sizeof(req->service_status)).
+ withOutputParameterReturning("resp_buf_data_len", &req->response.data_length,
+ sizeof(req->response.data_length)).
withParameterOfType("call_req", "req", req).
andReturnValue(result);
}
-rpc_status_t mock_rpc_interface_receive(struct rpc_interface *iface,
- struct call_req *req)
+rpc_status_t mock_rpc_interface_receive(void *context,
+ struct rpc_request *req)
{
return mock().actualCall("rpc_interface_receive").
- onObject(iface).
- withOutputParameter("opstatus", &req->opstatus).
- withOutputParameter("resp_buf_data_len", &req->resp_buf.data_len).
+ onObject(context).
+ withOutputParameter("service_status", &req->service_status).
+ withOutputParameter("resp_buf_data_len", &req->response.data_length).
withParameterOfType("call_req", "req", req).
returnIntValue();
}
diff --git a/components/rpc/common/test/mock_rpc_interface.h b/components/rpc/common/test/mock_rpc_interface.h
index 7e80c4a..d24e71f 100644
--- a/components/rpc/common/test/mock_rpc_interface.h
+++ b/components/rpc/common/test/mock_rpc_interface.h
@@ -6,7 +6,7 @@
#ifndef MOCK_RPC_INTERFACE_H_
#define MOCK_RPC_INTERFACE_H_
-#include "../endpoint/rpc_interface.h"
+#include "../endpoint/rpc_service_interface.h"
#ifdef __cplusplus
extern "C" {
@@ -14,11 +14,10 @@
void mock_rpc_interface_init(void);
-void expect_mock_rpc_interface_receive(struct rpc_interface *iface,
- const struct call_req *req, rpc_status_t result);
+void expect_mock_rpc_interface_receive(void *context, const struct rpc_request *req,
+ rpc_status_t result);
-rpc_status_t mock_rpc_interface_receive(struct rpc_interface *iface,
- struct call_req *req);
+rpc_status_t mock_rpc_interface_receive(void *context, struct rpc_request *req);
#ifdef __cplusplus
}
diff --git a/components/rpc/common/test/rpc_buffer_comparator.h b/components/rpc/common/test/rpc_buffer_comparator.h
new file mode 100644
index 0000000..93d41be
--- /dev/null
+++ b/components/rpc/common/test/rpc_buffer_comparator.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef RPC_BUFFER_COMPARATOR_H_
+#define RPC_BUFFER_COMPARATOR_H_
+
+#include <CppUTestExt/MockSupport.h>
+#include "../endpoint/rpc_service_interface.h"
+
+class rpc_buffer_comparator : public MockNamedValueComparator
+{
+public:
+ enum check_mode {
+ mode_normal = 0,
+ mode_ignore_data_len
+ };
+
+ explicit rpc_buffer_comparator(check_mode mode = mode_normal) : mode(mode)
+ {
+ }
+
+ virtual bool isEqual(const void *object1, const void *object2)
+ {
+ struct rpc_buffer *buf1 = (struct rpc_buffer *)object1;
+ struct rpc_buffer *buf2 = (struct rpc_buffer *)object2;
+
+ return (buf1->data == buf2->data) &&
+ (buf1->size == buf2->size) &&
+ (mode == mode_ignore_data_len || buf1->data_length == buf2->data_length);
+ }
+
+ // LCOV_EXCL_START
+ virtual SimpleString valueToString(const void *object)
+ {
+ struct rpc_buffer *buf = (struct rpc_buffer *)object;
+
+ return StringFromFormat("<size = %zu, data_len = %zu%s, data = %p>",
+ buf->size, buf->data_length,
+ (mode == mode_ignore_data_len) ? " (ignored)" : "",
+ buf->data);
+ }
+ // LCOV_EXCL_STOP
+
+private:
+ check_mode mode;
+};
+
+#endif /* RPC_BUFFER_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/rpc_request_comparator.h b/components/rpc/common/test/rpc_request_comparator.h
new file mode 100644
index 0000000..9a74671
--- /dev/null
+++ b/components/rpc/common/test/rpc_request_comparator.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef CALL_REQ_COMPARATOR_H_
+#define CALL_REQ_COMPARATOR_H_
+
+#include <CppUTestExt/MockSupport.h>
+#include <inttypes.h>
+#include "rpc_buffer_comparator.h"
+
+class rpc_request_comparator : public MockNamedValueComparator
+{
+public:
+ enum check_mode {
+ mode_normal = 0,
+ mode_ignore_opstatus
+ };
+
+ explicit rpc_request_comparator(check_mode mode) : mode(mode)
+ {
+ }
+
+ virtual bool isEqual(const void *object1, const void *object2)
+ {
+ struct rpc_request *req1 = (struct rpc_request *)object1;
+ struct rpc_request *req2 = (struct rpc_request *)object2;
+ rpc_buffer_comparator buf_comparator_normal;
+ rpc_buffer_comparator buf_comparator_ignore_data_len(
+ rpc_buffer_comparator::mode_ignore_data_len);
+
+ return (req1->source_id == req2->source_id) &&
+ (req1->interface_id == req2->interface_id) &&
+ (req1->opcode == req2->opcode) &&
+ (req1->client_id == req2->client_id) &&
+ (mode == mode_ignore_opstatus || req1->service_status == req2->service_status) &&
+ buf_comparator_normal.isEqual(&req1->request, &req2->request) &&
+ buf_comparator_ignore_data_len.isEqual(&req1->response, &req2->response);
+ }
+
+ // LCOV_EXCL_START
+ virtual SimpleString valueToString(const void *object)
+ {
+ struct rpc_request *req = (struct rpc_request *)object;
+ rpc_buffer_comparator buf_comparator_normal;
+ rpc_buffer_comparator buf_comparator_ignore_data_len(
+ rpc_buffer_comparator::mode_ignore_data_len);
+ SimpleString req_buf_str = buf_comparator_normal.valueToString(&req->request);
+ SimpleString resp_buf_str =
+ buf_comparator_ignore_data_len.valueToString(&req->response);
+
+ return StringFromFormat("caller_id = 0x%" PRIx32 ", interface_id = %" PRIu32 ", " \
+ "opcode = %" PRIu32 ", encoding = %" PRIu32 ", " \
+ "opstatus = 0x%" PRIx64 "%s, req_buf = %s, " \
+ "resp_buf = %s",
+ req->source_id, req->interface_id, req->opcode,
+ req->client_id, req->service_status,
+ (mode == mode_ignore_opstatus) ? " (ignore)" : "",
+ req_buf_str.asCharString(), resp_buf_str.asCharString());
+ }
+ // LCOV_EXCL_STOP
+
+private:
+ check_mode mode;
+};
+
+#endif /* CALL_REQ_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/test_mock_rpc_interface.cpp b/components/rpc/common/test/test_mock_rpc_interface.cpp
index f3390f0..28bbf14 100644
--- a/components/rpc/common/test/test_mock_rpc_interface.cpp
+++ b/components/rpc/common/test/test_mock_rpc_interface.cpp
@@ -23,39 +23,39 @@
mock().clear();
}
- struct rpc_interface iface;
+ struct rpc_service_interface iface;
};
TEST(mock_rpc_interface, receive)
{
- rpc_status_t res = TS_RPC_ERROR_INTERNAL;
- struct call_req expected_req = { 0 };
- struct call_req req = { 0 };
+ rpc_status_t res = RPC_ERROR_INTERNAL;
+ struct rpc_request expected_req = { 0 };
+ struct rpc_request req = { 0 };
iface.context = (void *)1;
iface.receive = mock_rpc_interface_receive;
- expected_req.caller_id = 0x01234567;
- expected_req.interface_id = 0x89abcdef;
- expected_req.opcode = 0xfedcba98;
- expected_req.encoding = 0x76543210;
- expected_req.opstatus = (rpc_opstatus_t)-1;
+ expected_req.source_id = 0x4567;
+ expected_req.interface_id = 0xef;
+ expected_req.opcode = 0xba98;
+ expected_req.client_id = 0x76543210;
+ expected_req.service_status = (service_status_t)-1;
- expected_req.req_buf.size = 1;
- expected_req.req_buf.data_len = 2;
- expected_req.req_buf.data = (void *)3;
+ expected_req.request.size = 1;
+ expected_req.request.data_length = 2;
+ expected_req.request.data = (uint8_t *)3;
- expected_req.resp_buf.size = 4;
- expected_req.resp_buf.data_len = 5;
- expected_req.resp_buf.data = (void *)6;
+ expected_req.response.size = 4;
+ expected_req.response.data_length = 5;
+ expected_req.response.data = (uint8_t *)6;
memcpy(&req, &expected_req, sizeof(req));
- req.opstatus = 0;
- req.resp_buf.data_len = 0;
+ req.service_status = 0;
+ req.response.data_length = 0;
expect_mock_rpc_interface_receive(&iface, &expected_req, res);
LONGS_EQUAL(res, mock_rpc_interface_receive(&iface, &req));
- UNSIGNED_LONGLONGS_EQUAL(expected_req.opstatus, req.opstatus);
- UNSIGNED_LONGLONGS_EQUAL(expected_req.resp_buf.data_len, req.resp_buf.data_len);
+ UNSIGNED_LONGLONGS_EQUAL(expected_req.service_status, req.service_status);
+ UNSIGNED_LONGLONGS_EQUAL(expected_req.response.data_length, req.response.data_length);
}