aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorImre Kis <imre.kis@arm.com>2021-02-25 17:56:19 +0100
committerGy├Ârgy Szing <gyorgy.szing@arm.com>2021-07-02 13:58:01 +0200
commitbe97e77f3b1737f2dddbf21f84eff5f8d14edd20 (patch)
treef78713c8d6fc7c8e40f40278368357a4c855858a
parentc674b5b698d149b5d042ea8f4aa46c303f55df83 (diff)
downloadtrusted-services-be97e77f3b1737f2dddbf21f84eff5f8d14edd20.tar.gz
libsp: Add FF-A direct message routing extension
The routing extension is a layer on top of FF-A which enables SPs to send direct messages to the normal world component while maintaining the state of the SPs in the call chain. Change-Id: Ic4d6d5cbbccbe1adb534e7b8d2502b78b3d9cb04 Signed-off-by: Imre Kis <imre.kis@arm.com>
-rw-r--r--components/messaging/ffa/libsp/component.cmake11
-rw-r--r--components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c221
-rw-r--r--components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h39
-rw-r--r--components/messaging/ffa/libsp/include/sp_messaging.h12
-rw-r--r--components/messaging/ffa/libsp/sp_messaging.c84
-rw-r--r--components/messaging/ffa/libsp/test/test_sp_messaging.cpp792
-rw-r--r--components/messaging/ffa/libsp/tests.cmake15
7 files changed, 1174 insertions, 0 deletions
diff --git a/components/messaging/ffa/libsp/component.cmake b/components/messaging/ffa/libsp/component.cmake
index 2fec443..a21c630 100644
--- a/components/messaging/ffa/libsp/component.cmake
+++ b/components/messaging/ffa/libsp/component.cmake
@@ -8,6 +8,8 @@ if (NOT DEFINED TGT)
message(FATAL_ERROR "mandatory parameter TGT is not defined.")
endif()
+set(FFA_DIRECT_MSG_ROUTING_EXTENSION ON CACHE BOOL "Enable FF-A direct message routing extension")
+
target_sources(${TGT} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/aarch64/ffa_syscalls_a64.S"
"${CMAKE_CURRENT_LIST_DIR}/ffa.c"
@@ -34,6 +36,15 @@ set_property(TARGET ${TGT} PROPERTY PUBLIC_HEADER
${CMAKE_CURRENT_LIST_DIR}/include/sp_rxtx.h
)
+if (FFA_DIRECT_MSG_ROUTING_EXTENSION)
+ target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/ffa_direct_msg_routing_extension.c"
+ )
+
+ target_compile_options(${TGT} PUBLIC
+ -DFFA_DIRECT_MSG_ROUTING_EXTENSION=1
+ )
+endif()
target_include_directories(${TGT}
PUBLIC
diff --git a/components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c b/components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c
new file mode 100644
index 0000000..6813573
--- /dev/null
+++ b/components/messaging/ffa/libsp/ffa_direct_msg_routing_extension.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "ffa_direct_msg_routing_extension.h"
+#include "ffa_api.h"
+#include <stdbool.h>
+
+#define SP_ID_INVALID FFA_ID_GET_ID_MASK
+#define FFA_ROUTING_EXT_RC_BIT BIT(0)
+#define FFA_ROUTING_EXT_ERROR_BIT BIT(1)
+
+enum sp_rc_state { idle = 0, root, leaf, rc_root, internal, forwarding };
+
+enum sp_rc_state state = idle;
+static uint16_t own_id = SP_ID_INVALID;
+static uint16_t caller_id = SP_ID_INVALID;
+static uint16_t callee_id = SP_ID_INVALID;
+
+static bool is_rc_message(const struct ffa_direct_msg *msg)
+{
+ return msg->args[0] & FFA_ROUTING_EXT_RC_BIT;
+}
+
+static bool is_error_message(const struct ffa_direct_msg *msg)
+{
+ return msg->args[0] & FFA_ROUTING_EXT_ERROR_BIT;
+}
+
+static ffa_result get_error_code_from_message(const struct ffa_direct_msg *msg)
+{
+ return (ffa_result)msg->args[1];
+}
+
+static ffa_result send_rc_error_message(struct ffa_direct_msg *req,
+ ffa_result error_code)
+{
+ return ffa_msg_send_direct_resp(req->destination_id, req->source_id,
+ (FFA_ROUTING_EXT_ERROR_BIT |
+ FFA_ROUTING_EXT_RC_BIT),
+ error_code, 0, 0, 0, req);
+}
+
+static ffa_result send_rc_error_message_to_rc_root(struct ffa_direct_msg *resp,
+ ffa_result error_code)
+{
+ return ffa_msg_send_direct_req(own_id, callee_id,
+ (FFA_ROUTING_EXT_RC_BIT |
+ FFA_ROUTING_EXT_ERROR_BIT),
+ error_code, 0, 0, 0, resp);
+}
+
+static ffa_result deny_unexpected_rc_responses(struct ffa_direct_msg *req)
+{
+ ffa_result ffa_res = FFA_OK;
+
+ while (is_rc_message(req)) {
+ ffa_res = send_rc_error_message(req, FFA_DENIED);
+ if (ffa_res != FFA_OK)
+ return ffa_res;
+ }
+
+ return FFA_OK;
+}
+
+static ffa_result deny_unexpected_requests(struct ffa_direct_msg *req)
+{
+ ffa_result ffa_res = FFA_OK;
+
+ while (!is_rc_message(req) || req->source_id != caller_id) {
+ ffa_res = send_rc_error_message(req, FFA_BUSY);
+ if (ffa_res != FFA_OK) {
+ /* Sending error message as a response to an invalid
+ * request has failed. Sending and FFA_MSG_WAIT to have
+ * a chance for receiving a valid message.
+ */
+ ffa_res = ffa_msg_wait(req);
+ if (ffa_res != FFA_OK) {
+ /* Even the FFA_MSG_WAIT failed so return. */
+ return ffa_res;
+ }
+ }
+ }
+
+ return FFA_OK;
+}
+
+static ffa_result request_received_hook(struct ffa_direct_msg *req)
+{
+ ffa_result ffa_res = FFA_OK;
+
+ ffa_res = deny_unexpected_rc_responses(req);
+ if (ffa_res != FFA_OK)
+ return ffa_res;
+
+ state = leaf;
+ own_id = req->destination_id;
+ caller_id = req->source_id;
+ callee_id = SP_ID_INVALID;
+
+ return FFA_OK;
+}
+
+ffa_result ffa_direct_msg_routing_ext_wait_post_hook(struct ffa_direct_msg *req)
+{
+ return request_received_hook(req);
+}
+
+void ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg *req)
+{
+ state = internal;
+ callee_id = req->destination_id;
+}
+
+ffa_result ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp)
+{
+ ffa_result ffa_res = FFA_OK;
+ struct ffa_direct_msg rc_resp = { 0 };
+
+ while (is_rc_message(resp)) {
+ if (is_error_message(resp)) {
+ /* The callee returned an error in an RC message. */
+ ffa_res = get_error_code_from_message(resp);
+ break;
+ }
+
+ /* Forwarding RC request towards the root (normal world) */
+ state = forwarding;
+
+ ffa_res = ffa_msg_send_direct_resp(own_id, caller_id,
+ resp->args[0], resp->args[1],
+ resp->args[2], resp->args[3],
+ resp->args[4], &rc_resp);
+ if (ffa_res != FFA_OK)
+ goto forward_ffa_error_to_rc_root;
+
+ /*
+ * Denying messages which are not RC responses or came from a
+ * different endpoint than the original caller.
+ */
+ ffa_res = deny_unexpected_requests(&rc_resp);
+ if (ffa_res != FFA_OK)
+ goto forward_ffa_error_to_rc_root;
+
+ /* Forwarding RC response towards the RC root. */
+ state = internal;
+ ffa_res = ffa_msg_send_direct_req(
+ own_id, callee_id, rc_resp.args[0], rc_resp.args[1],
+ rc_resp.args[2], rc_resp.args[3], rc_resp.args[4],
+ resp);
+
+ goto break_on_ffa_error;
+
+ /*
+ * At this point an FF-A error message was received while it was
+ * trying to forward the RC message. Forwarding erro to RC root.
+ */
+forward_ffa_error_to_rc_root:
+ ffa_res = send_rc_error_message_to_rc_root(resp, ffa_res);
+
+break_on_ffa_error:
+ if (ffa_res != FFA_OK) {
+ /* Exit loop, set leaf state and return with error. */
+ break;
+ }
+ }
+
+ /* Non-RC message was received or a non-recoverable error happened. */
+ state = leaf;
+ callee_id = SP_ID_INVALID;
+
+ return ffa_res;
+}
+
+void ffa_direct_msg_routing_ext_req_error_hook(void)
+{
+ state = leaf;
+ callee_id = SP_ID_INVALID;
+}
+
+void ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg *resp)
+{
+ state = idle;
+ caller_id = SP_ID_INVALID;
+ callee_id = SP_ID_INVALID;
+}
+
+ffa_result ffa_direct_msg_routing_ext_resp_post_hook(struct ffa_direct_msg *req)
+{
+ return request_received_hook(req);
+}
+
+void ffa_direct_msg_routing_ext_resp_error_hook(void)
+{
+}
+
+void ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg *req)
+{
+ req->args[0] = FFA_ROUTING_EXT_RC_BIT;
+ state = rc_root;
+}
+
+ffa_result
+ffa_direct_msg_routing_ext_rc_req_post_hook(struct ffa_direct_msg *resp)
+{
+ ffa_result ffa_res = FFA_OK;
+
+ ffa_res = deny_unexpected_requests(resp);
+ state = leaf;
+
+ if (is_error_message(resp))
+ ffa_res = get_error_code_from_message(resp);
+
+ return ffa_res;
+}
+
+void ffa_direct_msg_routing_ext_rc_req_error_hook(void)
+{
+ state = leaf;
+}
diff --git a/components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h b/components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h
new file mode 100644
index 0000000..3715f50
--- /dev/null
+++ b/components/messaging/ffa/libsp/include/ffa_direct_msg_routing_extension.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBSP_INCLUDE_FFA_DIRECT_MSG_ROUTING_EXTENSION_H_
+#define LIBSP_INCLUDE_FFA_DIRECT_MSG_ROUTING_EXTENSION_H_
+
+#include "ffa_api_types.h"
+#include "sp_api_defines.h"
+#include "sp_api_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ffa_result
+ffa_direct_msg_routing_ext_wait_post_hook(struct ffa_direct_msg *req);
+
+void ffa_direct_msg_routing_ext_req_pre_hook(struct ffa_direct_msg *req);
+ffa_result
+ffa_direct_msg_routing_ext_req_post_hook(struct ffa_direct_msg *resp);
+void ffa_direct_msg_routing_ext_req_error_hook(void);
+
+void ffa_direct_msg_routing_ext_resp_pre_hook(struct ffa_direct_msg *resp);
+ffa_result
+ffa_direct_msg_routing_ext_resp_post_hook(struct ffa_direct_msg *req);
+void ffa_direct_msg_routing_ext_resp_error_hook(void);
+
+void ffa_direct_msg_routing_ext_rc_req_pre_hook(struct ffa_direct_msg *req);
+ffa_result
+ffa_direct_msg_routing_ext_rc_req_post_hook(struct ffa_direct_msg *resp);
+void ffa_direct_msg_routing_ext_rc_req_error_hook(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSP_INCLUDE_FFA_DIRECT_MSG_ROUTING_EXTENSION_H_ */
diff --git a/components/messaging/ffa/libsp/include/sp_messaging.h b/components/messaging/ffa/libsp/include/sp_messaging.h
index 3ee5aae..4bb45f7 100644
--- a/components/messaging/ffa/libsp/include/sp_messaging.h
+++ b/components/messaging/ffa/libsp/include/sp_messaging.h
@@ -57,6 +57,18 @@ sp_result sp_msg_send_direct_req(const struct sp_msg *req, struct sp_msg *resp);
sp_result sp_msg_send_direct_resp(const struct sp_msg *resp,
struct sp_msg *req);
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+/**
+ * @brief Sends a request on the return channel 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_rc_req(const struct sp_msg *req, struct sp_msg *resp);
+#endif /* FFA_DIRECT_MSG_ROUTING_EXTENSION */
+
#ifdef __cplusplus
}
#endif
diff --git a/components/messaging/ffa/libsp/sp_messaging.c b/components/messaging/ffa/libsp/sp_messaging.c
index 9e29384..ba07ce1 100644
--- a/components/messaging/ffa/libsp/sp_messaging.c
+++ b/components/messaging/ffa/libsp/sp_messaging.c
@@ -6,6 +6,9 @@
#include "ffa_api.h"
#include "sp_api_defines.h"
#include "sp_messaging.h"
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+#include "ffa_direct_msg_routing_extension.h"
+#endif
#include <string.h>
@@ -57,6 +60,14 @@ sp_result sp_msg_wait(struct sp_msg *msg)
return SP_RESULT_FFA(ffa_res);
}
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ ffa_res = ffa_direct_msg_routing_ext_wait_post_hook(&ffa_msg);
+ if (ffa_res != FFA_OK) {
+ *msg = (struct sp_msg){ 0 };
+ return SP_RESULT_FFA(ffa_res);
+ }
+#endif
+
unpack_ffa_direct_msg(&ffa_msg, msg);
return SP_RESULT_OK;
@@ -78,6 +89,10 @@ sp_result sp_msg_send_direct_req(const struct sp_msg *req, struct sp_msg *resp)
pack_ffa_direct_msg(req, &ffa_req);
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ ffa_direct_msg_routing_ext_req_pre_hook(&ffa_req);
+#endif
+
ffa_res = ffa_msg_send_direct_req(ffa_req.source_id,
ffa_req.destination_id,
ffa_req.args[0], ffa_req.args[1],
@@ -85,10 +100,21 @@ sp_result sp_msg_send_direct_req(const struct sp_msg *req, struct sp_msg *resp)
ffa_req.args[4], &ffa_resp);
if (ffa_res != FFA_OK) {
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ ffa_direct_msg_routing_ext_req_error_hook();
+#endif
*resp = (struct sp_msg){ 0 };
return SP_RESULT_FFA(ffa_res);
}
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ ffa_res = ffa_direct_msg_routing_ext_req_post_hook(&ffa_resp);
+ if (ffa_res != SP_RESULT_OK) {
+ *resp = (struct sp_msg){ 0 };
+ return SP_RESULT_FFA(ffa_res);
+ }
+#endif
+
unpack_ffa_direct_msg(&ffa_resp, resp);
return SP_RESULT_OK;
@@ -110,6 +136,10 @@ sp_result sp_msg_send_direct_resp(const struct sp_msg *resp, struct sp_msg *req)
pack_ffa_direct_msg(resp, &ffa_resp);
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ ffa_direct_msg_routing_ext_resp_pre_hook(&ffa_resp);
+#endif
+
ffa_res = ffa_msg_send_direct_resp(ffa_resp.source_id,
ffa_resp.destination_id,
ffa_resp.args[0], ffa_resp.args[1],
@@ -117,11 +147,65 @@ sp_result sp_msg_send_direct_resp(const struct sp_msg *resp, struct sp_msg *req)
ffa_resp.args[4], &ffa_req);
if (ffa_res != FFA_OK) {
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ ffa_direct_msg_routing_ext_resp_error_hook();
+#endif
*req = (struct sp_msg){ 0 };
return SP_RESULT_FFA(ffa_res);
}
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ ffa_res = ffa_direct_msg_routing_ext_resp_post_hook(&ffa_req);
+ if (ffa_res != SP_RESULT_OK) {
+ *req = (struct sp_msg){ 0 };
+ return SP_RESULT_FFA(ffa_res);
+ }
+#endif
+
unpack_ffa_direct_msg(&ffa_req, req);
return SP_RESULT_OK;
}
+
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+sp_result sp_msg_send_rc_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_direct_msg_routing_ext_rc_req_pre_hook(&ffa_req);
+
+ ffa_res = ffa_msg_send_direct_resp(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) {
+ ffa_direct_msg_routing_ext_rc_req_error_hook();
+ *resp = (struct sp_msg){ 0 };
+ return SP_RESULT_FFA(ffa_res);
+ }
+
+ ffa_res = ffa_direct_msg_routing_ext_rc_req_post_hook(&ffa_resp);
+ if (ffa_res != SP_RESULT_OK) {
+ *resp = (struct sp_msg){ 0 };
+ return SP_RESULT_FFA(ffa_res);
+ }
+
+ unpack_ffa_direct_msg(&ffa_resp, resp);
+
+ return SP_RESULT_OK;
+}
+#endif
diff --git a/components/messaging/ffa/libsp/test/test_sp_messaging.cpp b/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
index 2ddf1ab..78bf8bf 100644
--- a/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
+++ b/components/messaging/ffa/libsp/test/test_sp_messaging.cpp
@@ -12,6 +12,11 @@
#define SP_MSG_ARG_OFFSET (1)
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+#define ROUTING_EXT_RC_BIT BIT(0)
+#define ROUTING_EXT_ERR_BIT BIT(1)
+#endif
+
TEST_GROUP(sp_messaging)
{
TEST_SETUP()
@@ -76,6 +81,22 @@ TEST_GROUP(sp_messaging)
}
}
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+ void wait_and_receive_request(uint16_t source_id, uint16_t dest_id)
+ {
+ struct ffa_direct_msg expected_ffa_req = { 0 };
+ struct sp_msg req = { 0 };
+
+ fill_ffa_msg(&expected_ffa_req);
+ expected_ffa_req.source_id = source_id;
+ expected_ffa_req.destination_id = dest_id;
+ expect_ffa_msg_wait(&expected_ffa_req, FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_wait(&req));
+ ffa_and_sp_msg_equal(&expected_ffa_req, &req);
+ }
+#endif
+
struct sp_msg req;
struct sp_msg resp;
struct ffa_direct_msg ffa_msg;
@@ -112,6 +133,45 @@ TEST(sp_messaging, sp_msg_wait)
ffa_and_sp_msg_equal(&ffa_msg, &req);
}
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+TEST(sp_messaging, sp_msg_wait_deny_rc_failure)
+{
+ struct ffa_direct_msg rc_msg = { 0 };
+ ffa_result result = FFA_ABORTED;
+
+ fill_ffa_msg(&rc_msg);
+ rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+ expect_ffa_msg_wait(&rc_msg, FFA_OK);
+
+ fill_ffa_msg(&ffa_msg);
+ expect_ffa_msg_send_direct_resp(
+ rc_msg.destination_id, rc_msg.source_id,
+ ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
+ SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &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_deny_rc)
+{
+ struct ffa_direct_msg rc_msg = { 0 };
+
+ fill_ffa_msg(&rc_msg);
+ rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+ expect_ffa_msg_wait(&rc_msg, FFA_OK);
+
+ fill_ffa_msg(&ffa_msg);
+ expect_ffa_msg_send_direct_resp(
+ rc_msg.destination_id, rc_msg.source_id,
+ ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
+ SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &ffa_msg, FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_wait(&req));
+ ffa_and_sp_msg_equal(&ffa_msg, &req);
+}
+#endif
+
TEST(sp_messaging, sp_msg_send_direct_req_resp_null)
{
LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
@@ -175,6 +235,564 @@ TEST(sp_messaging, sp_msg_send_direct_req_success)
MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
}
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+TEST(sp_messaging, sp_msg_send_direct_req_rc_forwarding_success)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_req = { 0 };
+ ffa_direct_msg rc_resp = { 0 };
+ ffa_direct_msg resp = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_req);
+ rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_req.source_id = rc_root_id;
+ rc_req.destination_id = own_id;
+ rc_req.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_ffa_msg(&rc_resp);
+ rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ rc_resp.source_id = root_id;
+ rc_resp.destination_id = own_id;
+ rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_sp_msg(&sp_resp);
+ sp_resp.source_id = rc_root_id;
+ sp_resp.destination_id = own_id;
+
+ resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ resp.source_id = rc_root_id;
+ resp.destination_id = own_id;
+ copy_sp_to_ffa_args(sp_resp.args, resp.args);
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_req, FFA_OK);
+
+ /* Forwarding RC request to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
+ rc_req.args[1], rc_req.args[2],
+ rc_req.args[3], rc_req.args[4],
+ &rc_resp, FFA_OK);
+
+ /* Fowarding RC response to RC root and receiving response */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
+ rc_resp.args[1], rc_resp.args[2],
+ rc_resp.args[3], rc_resp.args[4], &resp,
+ FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
+ ffa_and_sp_msg_equal(&resp, &sp_resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_rc_error)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_err = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_err);
+ rc_err.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_err.source_id = rc_root_id;
+ rc_err.destination_id = own_id;
+ rc_err.args[0] = ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT;
+ rc_err.args[1] = result;
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_err, FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_FFA(result),
+ sp_msg_send_direct_req(&sp_req, &sp_resp));
+ MEMCMP_EQUAL(&empty_sp_msg, &sp_resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_rc_forwarding_success_deny_request)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_req = { 0 };
+ ffa_direct_msg request_to_deny = { 0 };
+ ffa_direct_msg rc_resp = { 0 };
+ ffa_direct_msg resp = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_req);
+ rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_req.source_id = rc_root_id;
+ rc_req.destination_id = own_id;
+ rc_req.args[0] = ROUTING_EXT_RC_BIT;
+
+ request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ request_to_deny.source_id = root_id;
+ request_to_deny.destination_id = own_id;
+ request_to_deny.args[0] = 0;
+
+ fill_ffa_msg(&rc_resp);
+ rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ rc_resp.source_id = root_id;
+ rc_resp.destination_id = own_id;
+ rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_sp_msg(&sp_resp);
+ sp_resp.source_id = rc_root_id;
+ sp_resp.destination_id = own_id;
+
+ resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ resp.source_id = rc_root_id;
+ resp.destination_id = own_id;
+ copy_sp_to_ffa_args(sp_resp.args, resp.args);
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_req, FFA_OK);
+
+ /* Forwarding RC request to root and receiving a request to deny */
+ expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
+ rc_req.args[1], rc_req.args[2],
+ rc_req.args[3], rc_req.args[4],
+ &request_to_deny, FFA_OK);
+
+ /* Sending error to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(
+ own_id, root_id, ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
+ SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_OK);
+
+ /* Fowarding RC response to RC root and receiving response */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
+ rc_resp.args[1], rc_resp.args[2],
+ rc_resp.args[3], rc_resp.args[4], &resp,
+ FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
+ ffa_and_sp_msg_equal(&resp, &sp_resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_rc_forwarding_success_invalid_req_src)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_req = { 0 };
+ ffa_direct_msg request_to_deny = { 0 };
+ ffa_direct_msg rc_resp = { 0 };
+ ffa_direct_msg resp = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_req);
+ rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_req.source_id = rc_root_id;
+ rc_req.destination_id = own_id;
+ rc_req.args[0] = ROUTING_EXT_RC_BIT;
+
+ request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ /* This source ID should be denied in the current state. */
+ request_to_deny.source_id = rc_root_id;
+ request_to_deny.destination_id = own_id;
+ request_to_deny.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_ffa_msg(&rc_resp);
+ rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ rc_resp.source_id = root_id;
+ rc_resp.destination_id = own_id;
+ rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_sp_msg(&sp_resp);
+ sp_resp.source_id = rc_root_id;
+ sp_resp.destination_id = own_id;
+
+ resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ resp.source_id = rc_root_id;
+ resp.destination_id = own_id;
+ copy_sp_to_ffa_args(sp_resp.args, resp.args);
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_req, FFA_OK);
+
+ /* Forwarding RC request to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
+ rc_req.args[1], rc_req.args[2],
+ rc_req.args[3], rc_req.args[4],
+ &request_to_deny, FFA_OK);
+
+ /* Sending error to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(
+ own_id, rc_root_id, ROUTING_EXT_ERR_BIT | ROUTING_EXT_RC_BIT,
+ SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_OK);
+
+ /* Fowarding RC response to RC root and receiving response */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
+ rc_resp.args[1], rc_resp.args[2],
+ rc_resp.args[3], rc_resp.args[4], &resp,
+ FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
+ ffa_and_sp_msg_equal(&resp, &sp_resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_deny_fail_wait_success)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_req = { 0 };
+ ffa_direct_msg request_to_deny = { 0 };
+ ffa_direct_msg rc_resp = { 0 };
+ ffa_direct_msg resp = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_req);
+ rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_req.source_id = rc_root_id;
+ rc_req.destination_id = own_id;
+ rc_req.args[0] = ROUTING_EXT_RC_BIT;
+
+ request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ /* This source ID should be denied in the current state. */
+ request_to_deny.source_id = rc_root_id;
+ request_to_deny.destination_id = own_id;
+ request_to_deny.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_ffa_msg(&rc_resp);
+ rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ rc_resp.source_id = root_id;
+ rc_resp.destination_id = own_id;
+ rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_sp_msg(&sp_resp);
+ sp_resp.source_id = rc_root_id;
+ sp_resp.destination_id = own_id;
+
+ resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ resp.source_id = rc_root_id;
+ resp.destination_id = own_id;
+ copy_sp_to_ffa_args(sp_resp.args, resp.args);
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_req, FFA_OK);
+
+ /* Forwarding RC request to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
+ rc_req.args[1], rc_req.args[2],
+ rc_req.args[3], rc_req.args[4],
+ &request_to_deny, FFA_OK);
+
+ /* Sending error to root which fails */
+ expect_ffa_msg_send_direct_resp(
+ own_id, rc_root_id, (ROUTING_EXT_ERR_BIT | ROUTING_EXT_RC_BIT),
+ SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_DENIED);
+
+ /* Sending FFA_MSG_WAIT as we are still waiting for the RC response */
+ expect_ffa_msg_wait(&rc_resp, FFA_OK);
+
+ /* Fowarding RC response to RC root and receiving response */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
+ rc_resp.args[1], rc_resp.args[2],
+ rc_resp.args[3], rc_resp.args[4], &resp,
+ FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
+ ffa_and_sp_msg_equal(&resp, &sp_resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_deny_fail_wait_fail_forwarding)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_req = { 0 };
+ ffa_direct_msg request_to_deny = { 0 };
+ ffa_direct_msg rc_resp = { 0 };
+ ffa_direct_msg resp = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_req);
+ rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_req.source_id = rc_root_id;
+ rc_req.destination_id = own_id;
+ rc_req.args[0] = ROUTING_EXT_RC_BIT;
+
+ request_to_deny.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ /* This source ID should be denied in the current state. */
+ request_to_deny.source_id = rc_root_id;
+ request_to_deny.destination_id = own_id;
+ request_to_deny.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_ffa_msg(&rc_resp);
+ rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ rc_resp.source_id = root_id;
+ rc_resp.destination_id = own_id;
+ rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_sp_msg(&sp_resp);
+ sp_resp.source_id = rc_root_id;
+ sp_resp.destination_id = own_id;
+
+ resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ resp.source_id = rc_root_id;
+ resp.destination_id = own_id;
+ copy_sp_to_ffa_args(sp_resp.args, resp.args);
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_req, FFA_OK);
+
+ /* Forwarding RC request to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
+ rc_req.args[1], rc_req.args[2],
+ rc_req.args[3], rc_req.args[4],
+ &request_to_deny, FFA_OK);
+
+ /* Sending error to root which fails */
+ expect_ffa_msg_send_direct_resp(
+ own_id, rc_root_id, ROUTING_EXT_ERR_BIT | ROUTING_EXT_RC_BIT,
+ SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &rc_resp, FFA_DENIED);
+
+ /* Sending FFA_MSG_WAIT as we are still waiting for the RC response */
+ expect_ffa_msg_wait(&rc_resp, result);
+
+ /* Fowarding RC error as FFA_MSG_WAIT failed */
+ expect_ffa_msg_send_direct_req(
+ own_id, rc_root_id, (ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT),
+ result, 0, 0, 0, &resp, FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
+ ffa_and_sp_msg_equal(&resp, &sp_resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_rc_return_rc_error_msg)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_req = { 0 };
+ ffa_direct_msg rc_resp = { 0 };
+ ffa_direct_msg resp = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+ ffa_result result = FFA_ABORTED;
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_req);
+ rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_req.source_id = rc_root_id;
+ rc_req.destination_id = own_id;
+ rc_req.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_ffa_msg(&rc_resp);
+ rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ rc_resp.source_id = root_id;
+ rc_resp.destination_id = own_id;
+ rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_sp_msg(&sp_resp);
+ sp_resp.source_id = rc_root_id;
+ sp_resp.destination_id = own_id;
+
+ resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ resp.source_id = rc_root_id;
+ resp.destination_id = own_id;
+ copy_sp_to_ffa_args(sp_resp.args, resp.args);
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_req, FFA_OK);
+
+ /* Forwarding RC request to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
+ rc_req.args[1], rc_req.args[2],
+ rc_req.args[3], rc_req.args[4],
+ &rc_resp, result);
+
+ /* Fowarding RC error to RC root and receiving response */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id,
+ ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
+ SP_RESULT_FFA(result), 0, 0, 0, &resp,
+ FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_req(&sp_req, &sp_resp));
+ ffa_and_sp_msg_equal(&resp, &sp_resp);
+}
+
+TEST(sp_messaging, sp_msg_send_direct_req_rc_return_resp_fail)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ const uint16_t rc_root_id = 3;
+ ffa_direct_msg req = { 0 };
+ ffa_direct_msg rc_req = { 0 };
+ ffa_direct_msg rc_resp = { 0 };
+ ffa_direct_msg resp = { 0 };
+ sp_msg sp_req = { 0 };
+ sp_msg sp_resp = { 0 };
+ ffa_result result = FFA_ABORTED;
+
+ fill_sp_msg(&sp_req);
+ sp_req.source_id = own_id;
+ sp_req.destination_id = rc_root_id;
+
+ req.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ req.source_id = own_id;
+ req.destination_id = rc_root_id;
+ copy_sp_to_ffa_args(sp_req.args, req.args);
+
+ fill_ffa_msg(&rc_req);
+ rc_req.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ rc_req.source_id = rc_root_id;
+ rc_req.destination_id = own_id;
+ rc_req.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_ffa_msg(&rc_resp);
+ rc_resp.function_id = FFA_MSG_SEND_DIRECT_REQ_32;
+ rc_resp.source_id = root_id;
+ rc_resp.destination_id = own_id;
+ rc_resp.args[0] = ROUTING_EXT_RC_BIT;
+
+ fill_sp_msg(&sp_resp);
+ sp_resp.source_id = rc_root_id;
+ sp_resp.destination_id = own_id;
+
+ resp.function_id = FFA_MSG_SEND_DIRECT_RESP_32;
+ resp.source_id = rc_root_id;
+ resp.destination_id = own_id;
+ copy_sp_to_ffa_args(sp_resp.args, resp.args);
+
+ /* Initial request to current SP to set own_id */
+ wait_and_receive_request(root_id, own_id);
+
+ /* Sending request and receiving RC request from RC root */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, 0, req.args[1],
+ req.args[2], req.args[3], req.args[4],
+ &rc_req, FFA_OK);
+
+ /* Forwarding RC request to root and receiving RC response */
+ expect_ffa_msg_send_direct_resp(own_id, root_id, rc_req.args[0],
+ rc_req.args[1], rc_req.args[2],
+ rc_req.args[3], rc_req.args[4],
+ &rc_resp, FFA_OK);
+
+ /* Fowarding RC response to RC root and receiving response */
+ expect_ffa_msg_send_direct_req(own_id, rc_root_id, rc_resp.args[0],
+ rc_resp.args[1], rc_resp.args[2],
+ rc_resp.args[3], rc_resp.args[4], &resp,
+ result);
+
+ LONGS_EQUAL(SP_RESULT_FFA(result),
+ sp_msg_send_direct_req(&sp_req, &sp_resp));
+ MEMCMP_EQUAL(&empty_sp_msg, &sp_resp, sizeof(empty_sp_msg));
+}
+#endif
+
TEST(sp_messaging, sp_msg_send_direct_resp_req_null)
{
LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
@@ -239,3 +857,177 @@ TEST(sp_messaging, sp_msg_send_direct_resp_success)
LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_direct_resp(&resp, &req));
MEMCMP_EQUAL(&empty_sp_msg, &req, sizeof(empty_sp_msg));
}
+
+#if FFA_DIRECT_MSG_ROUTING_EXTENSION
+TEST(sp_messaging, sp_msg_send_direct_resp_deny_rc_failure)
+{
+ uint32_t expected_ffa_args[5] = { 0 };
+ struct ffa_direct_msg rc_msg = { 0 };
+
+ fill_sp_msg(&resp);
+
+ fill_ffa_msg(&rc_msg);
+ rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+
+ 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], &rc_msg, FFA_OK);
+
+ expect_ffa_msg_send_direct_resp(
+ rc_msg.destination_id, rc_msg.source_id,
+ ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
+ SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &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_deny_rc)
+{
+ uint32_t expected_ffa_args[5] = { 0 };
+ struct ffa_direct_msg rc_msg = { 0 };
+
+ fill_sp_msg(&resp);
+
+ fill_ffa_msg(&rc_msg);
+ rc_msg.args[0] = ROUTING_EXT_RC_BIT;
+
+ 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, 0,
+ expected_ffa_args[1],
+ expected_ffa_args[2],
+ expected_ffa_args[3],
+ expected_ffa_args[4], &rc_msg, FFA_OK);
+
+ expect_ffa_msg_send_direct_resp(
+ rc_msg.destination_id, rc_msg.source_id,
+ ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
+ SP_RESULT_FFA(FFA_DENIED), 0, 0, 0, &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_rc_req_req_null)
+{
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_msg_send_rc_req(&req, NULL));
+}
+
+TEST(sp_messaging, sp_msg_send_rc_req_resp_null)
+{
+ memset(&resp, 0x5a, sizeof(resp));
+ LONGS_EQUAL(SP_RESULT_INVALID_PARAMETERS,
+ sp_msg_send_rc_req(NULL, &resp));
+ MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_rc_req_ffa_error)
+{
+ ffa_result result = FFA_ABORTED;
+
+ fill_sp_msg(&resp);
+ memset(&req, 0x5a, sizeof(req));
+ fill_ffa_msg(&ffa_msg);
+
+ expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT, req.args[0],
+ req.args[1], req.args[2], req.args[3],
+ &ffa_msg, result);
+
+ LONGS_EQUAL(SP_RESULT_FFA(result), sp_msg_send_rc_req(&req, &resp));
+ MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_rc_req_deny_fail_wait_fail)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+
+ wait_and_receive_request(root_id, own_id);
+
+ fill_sp_msg(&req);
+ req.source_id = own_id;
+ req.destination_id = root_id;
+
+ fill_ffa_msg(&ffa_msg);
+ ffa_msg.source_id = root_id;
+ ffa_msg.destination_id = own_id;
+ /* Should be RC message so it will be denied */
+ ffa_msg.args[0] = 0;
+
+ expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT, req.args[0],
+ req.args[1], req.args[2], req.args[3],
+ &ffa_msg, FFA_OK);
+
+ expect_ffa_msg_send_direct_resp(
+ req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT,
+ SP_RESULT_FFA(FFA_BUSY), 0, 0, 0, &ffa_msg, result);
+
+ expect_ffa_msg_wait(&ffa_msg, result);
+
+ LONGS_EQUAL(SP_RESULT_FFA(result), sp_msg_send_rc_req(&req, &resp));
+ MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_rc_req_rc_error)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+ sp_result sp_err = SP_RESULT_NOT_FOUND;
+
+ wait_and_receive_request(root_id, own_id);
+
+ fill_sp_msg(&req);
+ req.source_id = own_id;
+ req.destination_id = root_id;
+
+ fill_ffa_msg(&ffa_msg);
+ ffa_msg.source_id = root_id;
+ ffa_msg.destination_id = own_id;
+ ffa_msg.args[0] = ROUTING_EXT_RC_BIT | ROUTING_EXT_ERR_BIT;
+ ffa_msg.args[1] = sp_err;
+
+ expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT, req.args[0],
+ req.args[1], req.args[2], req.args[3],
+ &ffa_msg, FFA_OK);
+
+ LONGS_EQUAL(sp_err, sp_msg_send_rc_req(&req, &resp));
+ MEMCMP_EQUAL(&empty_sp_msg, &resp, sizeof(empty_sp_msg));
+}
+
+TEST(sp_messaging, sp_msg_send_rc_req_success)
+{
+ const uint16_t root_id = 1;
+ const uint16_t own_id = 2;
+
+ wait_and_receive_request(root_id, own_id);
+
+ fill_sp_msg(&req);
+ req.source_id = own_id;
+ req.destination_id = root_id;
+
+ fill_ffa_msg(&ffa_msg);
+ ffa_msg.source_id = root_id;
+ ffa_msg.destination_id = own_id;
+ ffa_msg.args[0] = ROUTING_EXT_RC_BIT;
+
+ expect_ffa_msg_send_direct_resp(req.source_id, req.destination_id,
+ ROUTING_EXT_RC_BIT, req.args[0],
+ req.args[1], req.args[2], req.args[3],
+ &ffa_msg, FFA_OK);
+
+ LONGS_EQUAL(SP_RESULT_OK, sp_msg_send_rc_req(&req, &resp));
+ ffa_and_sp_msg_equal(&ffa_msg, &resp);
+}
+#endif
diff --git a/components/messaging/ffa/libsp/tests.cmake b/components/messaging/ffa/libsp/tests.cmake
index 092acef..d851442 100644
--- a/components/messaging/ffa/libsp/tests.cmake
+++ b/components/messaging/ffa/libsp/tests.cmake
@@ -138,4 +138,19 @@ unit_test_add_suite(
${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
COMPILE_DEFINITIONS
-DARM64
+)
+
+unit_test_add_suite(
+ NAME libsp_sp_messaging_with_routing_extension
+ 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
+ ${CMAKE_CURRENT_LIST_DIR}/ffa_direct_msg_routing_extension.c
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_LIST_DIR}/include/
+ ${UNIT_TEST_PROJECT_PATH}/components/common/utils/include
+ COMPILE_DEFINITIONS
+ -DARM64
+ -DFFA_DIRECT_MSG_ROUTING_EXTENSION=1
) \ No newline at end of file