Merge rss_comm support.
RSS Comm is a new protocol used to between the SPs and security
subsystems like the Secure Enclave on Corstone-1000 or RSS on Kronos.
This change deprecates the OpenAMP based original solution. This will
be removed in a future release.
Change-Id: Ic9038bd5e185a41ae41c4d95316e7a28eb45adf4
Signed-Off-By: Gyorgy Szing <gyorgy.szing@arm.com>
diff --git a/components/messaging/openamp/sp/component.cmake b/components/messaging/openamp/sp/component.cmake
index cee76a0..f5b3d84 100644
--- a/components/messaging/openamp/sp/component.cmake
+++ b/components/messaging/openamp/sp/component.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -22,3 +22,7 @@
PUBLIC
"${CMAKE_CURRENT_LIST_DIR}"
)
+
+set_property(TARGET ${TGT} APPEND PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+ "mhu"
+)
diff --git a/components/messaging/openamp/sp/openamp_mhu.c b/components/messaging/openamp/sp/openamp_mhu.c
index bafba3e..20f071f 100644
--- a/components/messaging/openamp/sp/openamp_mhu.c
+++ b/components/messaging/openamp/sp/openamp_mhu.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -8,7 +8,7 @@
#include <config/interface/config_store.h>
#include <config/interface/config_blob.h>
#include <platform/interface/device_region.h>
-#include <platform/drivers/arm/mhu_driver/mhu_v2.h>
+#include <platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h>
#include <trace.h>
#include <errno.h>
#include <stdlib.h>
@@ -70,6 +70,8 @@
} while(!irq_status);
ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
+ if (ret < 0)
+ return -1;
ret = mhu_v2_x_channel_clear(rx_dev, channel);
if (ret != MHU_V_2_X_ERR_NONE) {
diff --git a/components/messaging/rss_comms/sp/component.cmake b/components/messaging/rss_comms/sp/component.cmake
new file mode 100644
index 0000000..b9b7c4f
--- /dev/null
+++ b/components/messaging/rss_comms/sp/component.cmake
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2024, 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}/rss_comms_messenger_api.h"
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rss_comms_messenger.c"
+ "${CMAKE_CURRENT_LIST_DIR}/rss_comms_platform.c"
+ )
+
+target_include_directories(${TGT}
+ PUBLIC
+ "${CMAKE_CURRENT_LIST_DIR}"
+ )
+
+set_property(TARGET ${TGT} APPEND PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+ "mhu"
+)
diff --git a/components/messaging/rss_comms/sp/rss_comms_messenger.c b/components/messaging/rss_comms/sp/rss_comms_messenger.c
new file mode 100644
index 0000000..644181e
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_messenger.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <trace.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "rss_comms_messenger_api.h"
+#include "rss_comms_platform_api.h"
+
+struct rss_comms_msg {
+ uint8_t *req_buf;
+ size_t req_len;
+ uint8_t *resp_buf;
+};
+
+int rss_comms_messenger_init(struct rss_comms_messenger *rss_comms)
+{
+ int ret = 0;
+
+ if (!rss_comms || rss_comms->msg || rss_comms->platform)
+ return -1;
+
+ rss_comms->msg = calloc(1, sizeof(struct rss_comms_msg));
+ if (!rss_comms->msg)
+ return -1;
+
+ rss_comms->platform = rss_comms_platform_init();
+ if (!rss_comms->platform) {
+ EMSG("Platform init failed");
+ free(rss_comms->msg);
+ rss_comms->msg = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+void rss_comms_messenger_deinit(struct rss_comms_messenger *rss_comms)
+{
+ struct rss_comms_msg *msg = NULL;
+
+ if (!rss_comms)
+ return;
+
+ if (rss_comms->msg) {
+ msg = (struct rss_comms_msg *)rss_comms->msg;
+
+ if (msg->req_buf)
+ free(msg->req_buf);
+ if (msg->resp_buf)
+ free(msg->resp_buf);
+
+ free(msg);
+ rss_comms->msg = NULL;
+ }
+
+ rss_comms_platform_deinit(rss_comms->platform);
+ rss_comms->platform = NULL;
+}
+
+int rss_comms_messenger_call_invoke(struct rss_comms_messenger *rss_comms, uint8_t **resp_buf,
+ size_t *resp_len)
+{
+ struct rss_comms_msg *msg = NULL;
+ int ret = 0;
+
+ if (!rss_comms || !resp_buf || !resp_len) {
+ EMSG("Invalid arguments");
+ return -1;
+ }
+
+ if (!rss_comms->msg) {
+ EMSG("msg is null");
+ return -1;
+ }
+
+ msg = (struct rss_comms_msg *)rss_comms->msg;
+ *resp_buf = calloc(1, *resp_len);
+
+ if (!(*resp_buf))
+ return -1;
+
+ ret = rss_comms_platform_invoke(rss_comms->platform, *resp_buf, msg->req_buf, resp_len,
+ msg->req_len);
+
+ if (ret < 0) {
+ free(*resp_buf);
+ *resp_buf = NULL;
+ return ret;
+ }
+
+ msg->resp_buf = *resp_buf;
+
+ return 0;
+}
+
+int rss_comms_messenger_call_begin(struct rss_comms_messenger *rss_comms, uint8_t **req_buf,
+ size_t req_len)
+{
+ int ret = 0;
+ struct rss_comms_msg *msg = NULL;
+
+ if (!rss_comms || !req_buf || !rss_comms->msg)
+ return -1;
+
+ if (req_len > UINT32_MAX || req_len == 0) {
+ EMSG("req_len invalid: %lu", req_len);
+ return -1;
+ }
+
+ msg = (struct rss_comms_msg *)rss_comms->msg;
+
+ if (msg->req_buf)
+ return -1;
+
+ msg->req_buf = calloc(1, req_len);
+
+ if (!msg->req_buf)
+ return -1;
+
+ *req_buf = msg->req_buf;
+ msg->req_len = req_len;
+
+ ret = rss_comms_platform_begin(rss_comms->platform, *req_buf, req_len);
+
+ return ret;
+}
+
+void rss_comms_messenger_call_end(struct rss_comms_messenger *rss_comms)
+{
+ int ret = 0;
+ struct rss_comms_msg *msg = NULL;
+
+ if (!rss_comms || !rss_comms->msg)
+ return;
+
+ msg = (struct rss_comms_msg *)rss_comms->msg;
+
+ if (msg->req_buf)
+ free(msg->req_buf);
+
+ if (msg->resp_buf)
+ free(msg->resp_buf);
+
+ msg->req_len = 0;
+ msg->req_buf = NULL;
+ msg->resp_buf = NULL;
+
+ ret = rss_comms_platform_end(rss_comms->platform);
+
+ if (ret < 0) {
+ EMSG("Platform end failed: %d", ret);
+ return;
+ }
+}
diff --git a/components/messaging/rss_comms/sp/rss_comms_messenger_api.h b/components/messaging/rss_comms/sp/rss_comms_messenger_api.h
new file mode 100644
index 0000000..02bb6b5
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_messenger_api.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RSS_COMMS_MESSENGER_API_H__
+#define __RSS_COMMS_MESSENGER_API_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct rss_comms_messenger {
+ void *msg;
+ void *platform;
+};
+
+int rss_comms_messenger_init(struct rss_comms_messenger *rss_comms);
+void rss_comms_messenger_deinit(struct rss_comms_messenger *rss_comms);
+int rss_comms_messenger_call_invoke(struct rss_comms_messenger *rss_comms, uint8_t **resp_buf,
+ size_t *resp_len);
+int rss_comms_messenger_call_begin(struct rss_comms_messenger *rss_comms, uint8_t **req_buf,
+ size_t req_len);
+void rss_comms_messenger_call_end(struct rss_comms_messenger *rss_comms);
+
+#endif /* __RSS_COMMS_MESSENGER_API_H__ */
diff --git a/components/messaging/rss_comms/sp/rss_comms_platform.c b/components/messaging/rss_comms/sp/rss_comms_platform.c
new file mode 100644
index 0000000..5e09db2
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_platform.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#include "platform/interface/mhu_interface.h"
+#include "rss_comms_messenger_api.h"
+#include "rss_comms_platform_api.h"
+
+struct rss_comms_platform {
+ struct platform_mhu_driver rx_dev;
+ struct platform_mhu_driver tx_dev;
+};
+
+struct rss_comms_platform *rss_comms_platform_init(void)
+{
+ struct rss_comms_platform *rss_comms_plat = NULL;
+ int ret = 0;
+
+ rss_comms_plat = calloc(1, sizeof(*rss_comms_plat));
+ if (!rss_comms_plat) {
+ EMSG("rss_comms calloc dev failed");
+ return NULL;
+ }
+
+ ret = platform_mhu_create(&rss_comms_plat->rx_dev, "mhu-receiver", true);
+ if (ret < 0)
+ goto free_plat;
+
+ ret = platform_mhu_create(&rss_comms_plat->tx_dev, "mhu-sender", false);
+ if (ret < 0)
+ goto free_rx_dev;
+
+ return rss_comms_plat;
+
+free_rx_dev:
+ platform_mhu_destroy(&rss_comms_plat->rx_dev);
+free_plat:
+ free(rss_comms_plat);
+
+ return NULL;
+}
+
+int rss_comms_platform_deinit(struct rss_comms_platform *rss_comms_plat)
+{
+ if (!rss_comms_plat)
+ return -1;
+
+ platform_mhu_destroy(&rss_comms_plat->rx_dev);
+ platform_mhu_destroy(&rss_comms_plat->tx_dev);
+
+ free(rss_comms_plat);
+
+ return 0;
+}
+
+int rss_comms_platform_invoke(struct rss_comms_platform *rss_comms_plat, uint8_t *resp_buf,
+ uint8_t *req_buf, size_t *resp_len, size_t req_len)
+{
+ struct platform_mhu_driver *rx_dev = NULL;
+ struct platform_mhu_driver *tx_dev = NULL;
+ int err = 0;
+
+ if (!rss_comms_plat || !resp_buf || !req_buf)
+ return -1;
+
+ rx_dev = &rss_comms_plat->rx_dev;
+ tx_dev = &rss_comms_plat->tx_dev;
+
+ if (!tx_dev->iface || !tx_dev->iface->send)
+ return -1;
+
+ err = tx_dev->iface->send(tx_dev->context, req_buf, req_len);
+ if (err != 0) {
+ EMSG("mhu send data failed!");
+ return -1;
+ }
+
+ if (!rx_dev->iface || !rx_dev->iface->wait_data || !rx_dev->iface->receive)
+ return -1;
+
+ err = rx_dev->iface->wait_data(rx_dev->context);
+ if (err != 0) {
+ EMSG("mhu wait for signal failed!");
+ return -1;
+ }
+
+ err = rx_dev->iface->receive(rx_dev->context, resp_buf, resp_len);
+ if (err != 0) {
+ EMSG("mhu receive data failed!");
+ return -1;
+ }
+
+ return 0;
+}
+
+int rss_comms_platform_begin(struct rss_comms_platform *rss_comms_plat, uint8_t *req_buf,
+ size_t req_len)
+{
+ return 0;
+}
+
+int rss_comms_platform_end(struct rss_comms_platform *rss_comms_plat)
+{
+ return 0;
+}
diff --git a/components/messaging/rss_comms/sp/rss_comms_platform_api.h b/components/messaging/rss_comms/sp/rss_comms_platform_api.h
new file mode 100644
index 0000000..ed55506
--- /dev/null
+++ b/components/messaging/rss_comms/sp/rss_comms_platform_api.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RSS_COMMS_PLATFORM_API_H__
+#define __RSS_COMMS_PLATFORM_API_H__
+
+#include <stdint.h>
+
+struct rss_comms_platform;
+
+struct rss_comms_platform *rss_comms_platform_init(void);
+int rss_comms_platform_deinit(struct rss_comms_platform *rss_comms_plat);
+int rss_comms_platform_invoke(struct rss_comms_platform *rss_comms_plat, uint8_t *resp_buf,
+ uint8_t *req_buf, size_t *resp_len, size_t req_len);
+int rss_comms_platform_begin(struct rss_comms_platform *rss_comms_plat, uint8_t *req_buf,
+ size_t req_len);
+int rss_comms_platform_end(struct rss_comms_platform *rss_comms_plat);
+
+#endif /* __RSS_COMMS_PLATFORM_API_H__ */
diff --git a/components/rpc/psa_ipc/service_psa_ipc.c b/components/rpc/psa_ipc/service_psa_ipc.c
index 36c8e36..66ef67c 100644
--- a/components/rpc/psa_ipc/service_psa_ipc.c
+++ b/components/rpc/psa_ipc/service_psa_ipc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -176,13 +176,13 @@
if (!resp_msg || !out_len || resp_msg->reply != PSA_SUCCESS)
goto caller_end;
- out_vec_param = (struct psa_outvec *)psa_ipc_phys_to_virt(caller,
+ out_vec_param = (struct psa_outvec *)psa_ipc_phys_to_virt(caller->context,
psa_u32_to_ptr(resp_msg->params.out_vec));
for (i = 0; i < resp_msg->params.out_len; i++) {
out_vec[i].len = out_vec_param[i].len;
unaligned_memcpy(psa_u32_to_ptr(out_vec[i].base),
- psa_ipc_phys_to_virt(caller,
+ psa_ipc_phys_to_virt(caller->context,
psa_u32_to_ptr(out_vec_param[i].base)),
out_vec[i].len);
}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_caller.c b/components/rpc/rss_comms/caller/sp/rss_comms_caller.c
new file mode 100644
index 0000000..d857a2e
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_caller.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rss_comms_caller.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "rpc_caller.h"
+#include "rpc_status.h"
+
+struct rss_comms_caller_context {
+ struct rss_comms_messenger rss_comms;
+};
+
+rpc_status_t open_session(void *context, const struct rpc_uuid *service_uuid, uint16_t endpoint_id)
+{
+ return RPC_SUCCESS;
+}
+
+rpc_status_t find_and_open_session(void *context, const struct rpc_uuid *service_uuid)
+{
+ return RPC_SUCCESS;
+}
+
+rpc_status_t close_session(void *context)
+{
+ return RPC_SUCCESS;
+}
+
+rpc_status_t create_shared_memory(void *context, size_t size,
+ struct rpc_caller_shared_memory *shared_memory)
+{
+ return RPC_ERROR_INVALID_VALUE;
+}
+
+rpc_status_t release_shared_memory(void *context, struct rpc_caller_shared_memory *shared_memory)
+{
+ return RPC_ERROR_INVALID_VALUE;
+}
+
+rpc_status_t call(void *context, uint16_t opcode, struct rpc_caller_shared_memory *shared_memory,
+ size_t request_length, size_t *response_length, service_status_t *service_status)
+{
+ return RPC_ERROR_INTERNAL;
+}
+
+rpc_status_t rss_comms_caller_invoke(rss_comms_call_handle handle, uint32_t opcode,
+ uint8_t **response_buffer, size_t *response_length)
+{
+ struct rpc_caller_interface *caller = (struct rpc_caller_interface *)handle;
+ struct rss_comms_caller_context *context = NULL;
+ int ret = 0;
+
+ if (!handle || !caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct rss_comms_caller_context *)caller->context;
+
+ ret = rss_comms_messenger_call_invoke(&context->rss_comms, response_buffer,
+ response_length);
+ if (ret < 0)
+ return RPC_ERROR_TRANSPORT_LAYER;
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t rss_comms_caller_init(struct rpc_caller_interface *rpc_caller)
+{
+ struct rss_comms_caller_context *context = NULL;
+ int ret = 0;
+
+ if (!rpc_caller || rpc_caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct rss_comms_caller_context *)calloc(1,
+ sizeof(struct rss_comms_caller_context));
+ if (!context)
+ return RPC_ERROR_INTERNAL;
+
+ ret = rss_comms_messenger_init(&context->rss_comms);
+
+ if (ret < 0) {
+ free(context);
+ return RPC_ERROR_TRANSPORT_LAYER;
+ }
+
+ rpc_caller->context = context;
+ rpc_caller->open_session = open_session;
+ rpc_caller->find_and_open_session = find_and_open_session;
+ rpc_caller->close_session = close_session;
+ rpc_caller->create_shared_memory = create_shared_memory;
+ rpc_caller->release_shared_memory = release_shared_memory;
+ rpc_caller->call = call;
+
+ return RPC_SUCCESS;
+}
+
+rss_comms_call_handle rss_comms_caller_begin(struct rpc_caller_interface *caller,
+ uint8_t **request_buffer, size_t request_length)
+{
+ struct rss_comms_caller_context *context = NULL;
+ int ret = 0;
+
+ if (!caller || !caller->context)
+ return NULL;
+
+ context = (struct rss_comms_caller_context *)caller->context;
+
+ ret = rss_comms_messenger_call_begin(&context->rss_comms, request_buffer, request_length);
+
+ if (ret < 0)
+ return NULL;
+
+ return caller;
+}
+
+rpc_status_t rss_comms_caller_end(rss_comms_call_handle handle)
+{
+ struct rpc_caller_interface *caller = (struct rpc_caller_interface *)handle;
+ struct rss_comms_caller_context *context = NULL;
+
+ if (!handle || !caller->context)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct rss_comms_caller_context *)caller->context;
+
+ rss_comms_messenger_call_end(&context->rss_comms);
+
+ return RPC_SUCCESS;
+}
+
+rpc_status_t rss_comms_caller_deinit(struct rpc_caller_interface *rpc_caller)
+{
+ struct rss_comms_caller_context *context = NULL;
+
+ if (!rpc_caller)
+ return RPC_ERROR_INVALID_VALUE;
+
+ context = (struct rss_comms_caller_context *)rpc_caller->context;
+
+ rss_comms_messenger_deinit(&context->rss_comms);
+
+ free(context);
+ rpc_caller->context = NULL;
+
+ return RPC_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_caller.h b/components/rpc/rss_comms/caller/sp/rss_comms_caller.h
new file mode 100644
index 0000000..a62edb5
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_caller.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __RSS_COMMS_CALLER_H__
+#define __RSS_COMMS_CALLER_H__
+
+#include "rpc_caller.h"
+#include "rss_comms_messenger_api.h"
+
+typedef void *rss_comms_call_handle;
+
+rpc_status_t rss_comms_caller_init(struct rpc_caller_interface *rpc_caller);
+rpc_status_t rss_comms_caller_deinit(struct rpc_caller_interface *rpc_caller);
+
+rss_comms_call_handle rss_comms_caller_begin(struct rpc_caller_interface *caller,
+ uint8_t **request_buffer, size_t request_length);
+
+rpc_status_t rss_comms_caller_invoke(rss_comms_call_handle handle, uint32_t opcode,
+ uint8_t **response_buffer, size_t *response_length);
+
+rpc_status_t rss_comms_caller_end(rss_comms_call_handle handle);
+
+#endif /* __RSS_COMMS_CALLER_H__ */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol.c b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.c
new file mode 100644
index 0000000..7969536
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include "rss_comms_protocol.h"
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ const struct psa_outvec *out_vec,
+ uint8_t out_len,
+ struct serialized_rss_comms_msg_t *msg,
+ size_t *msg_len)
+{
+ psa_status_t status = PSA_SUCCESS;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ switch (msg->header.protocol_ver) {
+ case RSS_COMMS_PROTOCOL_EMBED:
+ status = rss_protocol_embed_serialize_msg(handle, type, in_vec, in_len, out_vec,
+ out_len, &msg->msg.embed, msg_len);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+ status = rss_protocol_pointer_access_serialize_msg(handle, type, in_vec, in_len,
+ out_vec, out_len,
+ &msg->msg.pointer_access,
+ msg_len);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ default:
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ *msg_len += sizeof(struct serialized_rss_comms_header_t);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_deserialize_reply(struct psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct serialized_rss_comms_reply_t *reply,
+ size_t reply_size)
+{
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ switch (reply->header.protocol_ver) {
+ case RSS_COMMS_PROTOCOL_EMBED:
+ return rss_protocol_embed_deserialize_reply(out_vec, out_len, return_val,
+ &reply->reply.embed, reply_size);
+ case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+ return rss_protocol_pointer_access_deserialize_reply(out_vec, out_len, return_val,
+ &reply->reply.pointer_access,
+ reply_size);
+ default:
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_calculate_msg_len(psa_handle_t handle,
+ uint8_t protocol_ver,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ size_t *msg_len)
+{
+ psa_status_t status = PSA_SUCCESS;
+
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ switch (protocol_ver) {
+ case RSS_COMMS_PROTOCOL_EMBED:
+ status = rss_protocol_embed_calculate_msg_len(handle, in_vec, in_len, msg_len);
+ if (status != PSA_SUCCESS)
+ return status;
+
+ break;
+ case RSS_COMMS_PROTOCOL_POINTER_ACCESS:
+ default:
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ *msg_len += sizeof(struct serialized_rss_comms_header_t);
+
+ return PSA_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.h
new file mode 100644
index 0000000..2d597b4
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_H__
+#define __RSS_COMMS_PROTOCOL_H__
+
+#include <stdint.h>
+
+#include <psa/client.h>
+#include "rss_comms_protocol_embed.h"
+#include "rss_comms_protocol_pointer_access.h"
+#include "service/common/include/psa/client.h"
+
+enum rss_comms_protocol_version_t {
+ RSS_COMMS_PROTOCOL_EMBED = 0,
+ RSS_COMMS_PROTOCOL_POINTER_ACCESS = 1,
+};
+
+struct __packed serialized_rss_comms_header_t {
+ uint8_t protocol_ver;
+ uint8_t seq_num;
+ uint16_t client_id;
+};
+
+/* MHU message passed from Host to RSS to deliver a PSA client call */
+struct __packed serialized_rss_comms_msg_t {
+ struct serialized_rss_comms_header_t header;
+ union __packed {
+ struct rss_embed_msg_t embed;
+ struct rss_pointer_access_msg_t pointer_access;
+ } msg;
+};
+
+/* MHU reply message to hold the PSA client reply result returned by RSS */
+struct __packed serialized_rss_comms_reply_t {
+ struct serialized_rss_comms_header_t header;
+ union __packed {
+ struct rss_embed_reply_t embed;
+ struct rss_pointer_access_reply_t pointer_access;
+ } reply;
+};
+
+psa_status_t rss_protocol_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ const struct psa_outvec *out_vec,
+ uint8_t out_len,
+ struct serialized_rss_comms_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_deserialize_reply(struct psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct serialized_rss_comms_reply_t *reply,
+ size_t reply_size);
+
+psa_status_t rss_protocol_calculate_msg_len(psa_handle_t handle,
+ uint8_t protocol_ver,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ size_t *msg_len);
+
+#endif /* __RSS_COMMS_PROTOCOL_H__ */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_common.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_common.h
new file mode 100644
index 0000000..177d636
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_common.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * Packing scheme of the control parameter
+ *
+ * 31 30-28 27 26-24 23-20 19 18-16 15-0
+ * +------------+-----+------+-------+-----+-------+-------+------+
+ * | | | | invec | | | outvec| type |
+ * | Res | Res | Res | number| Res | Res | number| |
+ * +------------+-----+------+-------+-----+-------+-------+------+
+ *
+ * Res: Reserved.
+ */
+
+#ifndef RSS_COMMS_PROTOCOL_COMMON
+#define RSS_COMMS_PROTOCOL_COMMON
+
+#define TYPE_OFFSET (0U)
+#define TYPE_MASK (0xFFFFUL << TYPE_OFFSET)
+#define IN_LEN_OFFSET (24U)
+#define IN_LEN_MASK (0x7UL << IN_LEN_OFFSET)
+#define OUT_LEN_OFFSET (16U)
+#define OUT_LEN_MASK (0x7UL << OUT_LEN_OFFSET)
+
+#define PARAM_PACK(type, in_len, out_len) \
+ (((((uint32_t)(type)) << TYPE_OFFSET) & TYPE_MASK) | \
+ ((((uint32_t)(in_len)) << IN_LEN_OFFSET) & IN_LEN_MASK) | \
+ ((((uint32_t)(out_len)) << OUT_LEN_OFFSET) & OUT_LEN_MASK))
+
+#endif /* RSS_COMMS_PROTOCOL_COMMON */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.c b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.c
new file mode 100644
index 0000000..6d96ff2
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "rss_comms_protocol_common.h"
+#include "rss_comms_protocol_embed.h"
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ const struct psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_embed_msg_t *msg,
+ size_t *msg_len)
+{
+ uint32_t payload_size = 0;
+ uint32_t i;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+ msg->handle = handle;
+
+ /* Fill msg iovec lengths */
+ for (i = 0U; i < in_len; ++i) {
+ msg->io_size[i] = in_vec[i].len;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ msg->io_size[in_len + i] = out_vec[i].len;
+ }
+
+ for (i = 0U; i < in_len; ++i) {
+ if (in_vec[i].len > sizeof(msg->trailer) - payload_size) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ memcpy(msg->trailer + payload_size,
+ psa_u32_to_ptr(in_vec[i].base),
+ in_vec[i].len);
+ payload_size += in_vec[i].len;
+ }
+
+ /* Output the actual size of the message, to optimize sending */
+ *msg_len = sizeof(*msg) - sizeof(msg->trailer) + payload_size;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_embed_deserialize_reply(struct psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_embed_reply_t *reply,
+ size_t reply_size)
+{
+ uint32_t payload_offset = 0;
+ uint32_t i;
+
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ for (i = 0U; i < out_len; ++i) {
+ if ((sizeof(*reply) - sizeof(reply->trailer) + payload_offset)
+ > reply_size) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ memcpy(psa_u32_to_ptr(out_vec[i].base),
+ reply->trailer + payload_offset,
+ reply->out_size[i]);
+ out_vec[i].len = reply->out_size[i];
+ payload_offset += reply->out_size[i];
+ }
+
+ *return_val = reply->return_val;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_embed_calculate_msg_len(psa_handle_t handle,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ size_t *msg_len)
+{
+ uint32_t payload_size = 0;
+ uint32_t i = 0;
+
+ assert(in_vec != NULL);
+ assert(msg_len != NULL);
+
+ for (i = 0U; i < in_len; ++i)
+ payload_size += in_vec[i].len;
+
+ /* Output the actual size of the message, to optimize sending */
+ *msg_len = offsetof(struct rss_embed_msg_t, trailer) + payload_size;
+
+ return PSA_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.h
new file mode 100644
index 0000000..29e2250
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_embed.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_EMBED_H__
+#define __RSS_COMMS_PROTOCOL_EMBED_H__
+
+#include <psa/client.h>
+#include <sys/cdefs.h>
+
+struct __packed rss_embed_msg_t {
+ psa_handle_t handle;
+ uint32_t ctrl_param; /* type, in_len, out_len */
+ uint16_t io_size[PSA_MAX_IOVEC];
+ uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+struct __packed rss_embed_reply_t {
+ int32_t return_val;
+ uint16_t out_size[PSA_MAX_IOVEC];
+ uint8_t trailer[PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE];
+};
+
+psa_status_t rss_protocol_embed_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ const struct psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_embed_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_embed_deserialize_reply(struct psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_embed_reply_t *reply,
+ size_t reply_size);
+
+psa_status_t rss_protocol_embed_calculate_msg_len(psa_handle_t handle,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ size_t *msg_len);
+
+#endif /* __RSS_COMMS_PROTOCOL_EMBED_H__ */
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.c b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.c
new file mode 100644
index 0000000..6d7d771
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <assert.h>
+
+#include "rss_comms_protocol_common.h"
+#include "rss_comms_protocol_pointer_access.h"
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ const struct psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_pointer_access_msg_t *msg,
+ size_t *msg_len)
+{
+ unsigned int i;
+
+ assert(msg != NULL);
+ assert(msg_len != NULL);
+ assert(in_vec != NULL);
+
+ msg->ctrl_param = PARAM_PACK(type, in_len, out_len);
+ msg->handle = handle;
+
+ /* Fill msg iovec lengths */
+ for (i = 0U; i < in_len; ++i) {
+ msg->io_sizes[i] = in_vec[i].len;
+ msg->host_ptrs[i] = (uint64_t)in_vec[i].base;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ msg->io_sizes[in_len + i] = out_vec[i].len;
+ msg->host_ptrs[in_len + i] = (uint64_t)out_vec[i].base;
+ }
+
+ *msg_len = sizeof(*msg);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(struct psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_pointer_access_reply_t *reply,
+ size_t reply_size)
+{
+ unsigned int i;
+
+ assert(reply != NULL);
+ assert(return_val != NULL);
+
+ for (i = 0U; i < out_len; ++i) {
+ out_vec[i].len = reply->out_sizes[i];
+ }
+
+ *return_val = reply->return_val;
+
+ return PSA_SUCCESS;
+}
diff --git a/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.h b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.h
new file mode 100644
index 0000000..a1b278c
--- /dev/null
+++ b/components/rpc/rss_comms/caller/sp/rss_comms_protocol_pointer_access.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+#define __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__
+
+
+#include <psa/client.h>
+#include <sys/cdefs.h>
+
+struct __packed rss_pointer_access_msg_t {
+ psa_handle_t handle;
+ uint32_t ctrl_param;
+ uint32_t io_sizes[PSA_MAX_IOVEC];
+ uint64_t host_ptrs[PSA_MAX_IOVEC];
+};
+
+struct __packed rss_pointer_access_reply_t {
+ int32_t return_val;
+ uint32_t out_sizes[PSA_MAX_IOVEC];
+};
+
+psa_status_t rss_protocol_pointer_access_serialize_msg(psa_handle_t handle,
+ int16_t type,
+ const struct psa_invec *in_vec,
+ uint8_t in_len,
+ const struct psa_outvec *out_vec,
+ uint8_t out_len,
+ struct rss_pointer_access_msg_t *msg,
+ size_t *msg_len);
+
+psa_status_t rss_protocol_pointer_access_deserialize_reply(struct psa_outvec *out_vec,
+ uint8_t out_len,
+ psa_status_t *return_val,
+ const struct rss_pointer_access_reply_t *reply,
+ size_t reply_size);
+
+#endif /* __RSS_COMMS_PROTOCOL_POINTER_ACCESS_H__ */
diff --git a/components/rpc/rss_comms/component.cmake b/components/rpc/rss_comms/component.cmake
new file mode 100644
index 0000000..1cafb5c
--- /dev/null
+++ b/components/rpc/rss_comms/component.cmake
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2024, 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}/caller/sp/rss_comms_caller.h
+ )
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/rss_comms.c"
+ "${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_caller.c"
+ "${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_protocol.c"
+ "${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_protocol_embed.c"
+ "${CMAKE_CURRENT_LIST_DIR}/caller/sp/rss_comms_protocol_pointer_access.c"
+ )
+
+target_include_directories(${TGT}
+ PUBLIC
+ "${CMAKE_CURRENT_LIST_DIR}/caller/sp/"
+ )
+
diff --git a/components/rpc/rss_comms/rss_comms.c b/components/rpc/rss_comms/rss_comms.c
new file mode 100644
index 0000000..267d134
--- /dev/null
+++ b/components/rpc/rss_comms/rss_comms.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "protocols/rpc/common/packed-c/status.h"
+#include "psa/client.h"
+#include "rss_comms_caller.h"
+#include "rss_comms_protocol.h"
+#include "trace.h"
+
+/* This value should be set according to the implemented channels
+ * in the MHU. As only the Embed protocol is supported at the moment,
+ * it is set big enough to fit even the largest messages.
+ */
+#ifndef COMMS_MHU_MSG_SIZE
+#define COMMS_MHU_MSG_SIZE 0x2200
+#endif
+
+static uint8_t select_protocol_version(const struct psa_invec *in_vec, size_t in_len,
+ const struct psa_outvec *out_vec, size_t out_len)
+{
+ size_t comms_embed_msg_min_size;
+ size_t comms_embed_reply_min_size;
+ size_t in_size_total = 0;
+ size_t out_size_total = 0;
+ size_t i;
+
+ for (i = 0U; i < in_len; ++i) {
+ in_size_total += in_vec[i].len;
+ }
+ for (i = 0U; i < out_len; ++i) {
+ out_size_total += out_vec[i].len;
+ }
+
+ comms_embed_msg_min_size = sizeof(struct serialized_rss_comms_header_t) +
+ sizeof(struct rss_embed_msg_t) - PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+ comms_embed_reply_min_size = sizeof(struct serialized_rss_comms_header_t) +
+ sizeof(struct rss_embed_reply_t) -
+ PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE;
+
+ /* Use embed if we can pack into one message and reply, else use
+ * pointer_access. The underlying MHU transport protocol uses a
+ * single uint32_t to track the length, so the amount of data that
+ * can be in a message is 4 bytes less than mhu_get_max_message_size
+ * reports.
+ *
+ * TODO tune this with real performance numbers, it's possible a
+ * pointer_access message is less performant than multiple embed
+ * messages due to ATU configuration costs to allow access to the
+ * pointers.
+ */
+ if ((comms_embed_msg_min_size + in_size_total >
+ COMMS_MHU_MSG_SIZE - sizeof(uint32_t)) ||
+ (comms_embed_reply_min_size + out_size_total >
+ COMMS_MHU_MSG_SIZE - sizeof(uint32_t))) {
+ return RSS_COMMS_PROTOCOL_POINTER_ACCESS;
+ } else {
+ return RSS_COMMS_PROTOCOL_EMBED;
+ }
+}
+
+psa_status_t __psa_call(struct rpc_caller_interface *caller, psa_handle_t handle, int32_t client_id,
+ int32_t type, const struct psa_invec *in_vec, size_t in_len,
+ struct psa_outvec *out_vec, size_t out_len)
+{
+ static uint8_t seq_num = 1U;
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ psa_status_t psa_status = PSA_ERROR_INVALID_ARGUMENT;
+ psa_status_t return_val = PSA_ERROR_INVALID_ARGUMENT;
+ rss_comms_call_handle rpc_handle = (rss_comms_call_handle)caller;
+ size_t req_len = 0;
+ size_t resp_len = 0;
+ struct serialized_rss_comms_msg_t *req = NULL;
+ struct serialized_rss_comms_reply_t *reply = NULL;
+ uint8_t protocol_ver = 0;
+
+ protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
+
+ psa_status = rss_protocol_calculate_msg_len(handle, protocol_ver, in_vec, in_len, &req_len);
+ if (psa_status != PSA_SUCCESS) {
+ EMSG("Message size calculation failed: %d", psa_status);
+ return psa_status;
+ }
+
+ rpc_handle = rss_comms_caller_begin(caller, (uint8_t **)&req, req_len);
+ if (!rpc_handle) {
+ EMSG("Could not get handle");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ req->header.seq_num = seq_num;
+ /* No need to distinguish callers (currently concurrent calls are not supported). */
+ req->header.client_id = client_id;
+ req->header.protocol_ver = protocol_ver;
+
+ psa_status = rss_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec, out_len, req,
+ &req_len);
+ if (psa_status != PSA_SUCCESS) {
+ EMSG("Serialize msg failed: %d", psa_status);
+ return psa_status;
+ }
+
+ DMSG("Sending rss_comms message");
+ DMSG("protocol_ver=%u", req->header.protocol_ver);
+ DMSG("seq_num=%u", req->header.seq_num);
+ DMSG("client_id=%u", req->header.client_id);
+
+ resp_len = sizeof(*reply);
+
+ rpc_status = rss_comms_caller_invoke(rpc_handle, 0, (uint8_t **)&reply, &resp_len);
+ if (rpc_status != RPC_SUCCESS) {
+ EMSG("Invoke failed: %d", rpc_status);
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ DMSG("Received rss_comms reply");
+ DMSG("protocol_ver=%u", reply->header.protocol_ver);
+ DMSG("seq_num=%u", reply->header.seq_num);
+ DMSG("client_id=%u", reply->header.client_id);
+ DMSG("resp_len=%lu", resp_len);
+
+ psa_status = rss_protocol_deserialize_reply(out_vec, out_len, &return_val, reply, resp_len);
+ if (psa_status != PSA_SUCCESS) {
+ EMSG("Protocol deserialize reply failed: %d", psa_status);
+ return psa_status;
+ }
+
+ DMSG("Return_val=%d", return_val);
+
+ rss_comms_caller_end(rpc_handle);
+
+ seq_num++;
+
+ return return_val;
+}
+
+psa_status_t psa_call_client_id(struct rpc_caller_interface *caller, psa_handle_t psa_handle,
+ int32_t client_id, int32_t type, const struct psa_invec *in_vec,
+ size_t in_len, struct psa_outvec *out_vec, size_t out_len)
+{
+ return __psa_call(caller, psa_handle, client_id, type, in_vec, in_len, out_vec, out_len);
+}
+
+psa_status_t psa_call(struct rpc_caller_interface *caller, psa_handle_t psa_handle, int32_t type,
+ const struct psa_invec *in_vec, size_t in_len, struct psa_outvec *out_vec,
+ size_t out_len)
+{
+ return __psa_call(caller, psa_handle, 0, type, in_vec, in_len, out_vec, out_len);
+}
diff --git a/components/service/locator/sp/ffa/spffa_service_context.c b/components/service/locator/sp/ffa/spffa_service_context.c
index 0c1616f..f7730d0 100644
--- a/components/service/locator/sp/ffa/spffa_service_context.c
+++ b/components/service/locator/sp/ffa/spffa_service_context.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -52,7 +52,8 @@
return NULL;
rpc_status = rpc_caller_session_find_and_open(session, &this_context->caller,
- &this_context->service_uuid, 4096);
+ &this_context->service_uuid,
+ RPC_CALLER_SESSION_SHARED_MEMORY_SIZE);
if (rpc_status != RPC_SUCCESS) {
free(session);
return NULL;
diff --git a/components/service/locator/sp/ffa/spffa_service_context.h b/components/service/locator/sp/ffa/spffa_service_context.h
index ff9b2f2..e9ed9c6 100644
--- a/components/service/locator/sp/ffa/spffa_service_context.h
+++ b/components/service/locator/sp/ffa/spffa_service_context.h
@@ -13,6 +13,10 @@
extern "C" {
#endif
+#ifndef RPC_CALLER_SESSION_SHARED_MEMORY_SIZE
+#define RPC_CALLER_SESSION_SHARED_MEMORY_SIZE (4096)
+#endif /* RPC_CALLER_SESSION_SHARED_MEMORY_SIZE */
+
/*
* A service_context that represents a service instance located in
* a partition, accessed via FFA. This service_context is suitable
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
index 986628c..83247d7 100644
--- a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -155,12 +155,18 @@
struct rpc_caller_interface *caller = ipc->client.session->caller;
psa_status_t psa_status;
uint32_t support_flags;
+ uint32_t dummy_vec = 0;
+ /* Use dummy in vector to guarantee parameter checking */
+ struct psa_invec in_vec[] = {
+ { .base = psa_ptr_to_u32(&dummy_vec), .len = sizeof(dummy_vec) },
+ };
+
struct psa_outvec out_vec[] = {
{ .base = psa_ptr_to_u32(&support_flags), .len = sizeof(support_flags) },
};
psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
- TFM_PS_ITS_GET_SUPPORT, NULL, 0,
+ TFM_PS_ITS_GET_SUPPORT, in_vec, IOVEC_LEN(in_vec),
out_vec, IOVEC_LEN(out_vec));
if (psa_status != PSA_SUCCESS)
EMSG("ipc_get_support: failed to psa_call: %d", psa_status);
diff --git a/components/service/uefi/smm_variable/backend/uefi_variable_store.h b/components/service/uefi/smm_variable/backend/uefi_variable_store.h
index dc3d3ca..8be5f36 100644
--- a/components/service/uefi/smm_variable/backend/uefi_variable_store.h
+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.h
@@ -22,6 +22,11 @@
#endif
/**
+ * \brief Size of the variable store index for a given entry count
+ */
+#define UEFI_VARIABLE_STORE_INDEX_SIZE(count) (sizeof(struct variable_metadata) * (count))
+
+/**
* \brief delegate_variable_store structure definition
*
* A delegate_variable_store combines an association with a concrete
diff --git a/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in b/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
index d3added..32e2ae3 100644
--- a/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
+++ b/deployments/se-proxy/config/corstone1000-opteesp/default_se-proxy.dts.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -34,11 +34,5 @@
pages-count = <16>;
attributes = <0x3>; /* read-write */
};
- openamp-virtio {
- /* Armv8 A Foundation Platform values */
- base-address = <0x00000000 0x88000000>;
- pages-count = <256>;
- attributes = <0x3>; /* read-write */
- };
};
};
diff --git a/deployments/se-proxy/infra/corstone1000/infra.cmake b/deployments/se-proxy/infra/corstone1000/infra.cmake
index 4e7e2bd..a52a1b7 100644
--- a/deployments/se-proxy/infra/corstone1000/infra.cmake
+++ b/deployments/se-proxy/infra/corstone1000/infra.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -15,8 +15,8 @@
BASE_DIR ${TS_ROOT}
COMPONENTS
"components/rpc/common/caller"
- "components/rpc/psa_ipc"
- "components/messaging/openamp/sp"
+ "components/rpc/rss_comms"
+ "components/messaging/rss_comms/sp"
"components/service/attestation/client/psa_ipc"
"components/service/attestation/key_mngr/local"
"components/service/attestation/reporter/psa_ipc"
@@ -24,10 +24,6 @@
"components/service/secure_storage/backend/secure_storage_ipc"
)
-# OpenAMP
-include(${TS_ROOT}/external/openamp/openamp.cmake)
-target_link_libraries(se-proxy PRIVATE openamp)
-
target_sources(se-proxy PRIVATE
${CMAKE_CURRENT_LIST_DIR}/service_proxy_factory.c
diff --git a/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
index 6885f92..b3b93cf 100644
--- a/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
+++ b/deployments/se-proxy/infra/corstone1000/service_proxy_factory.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -8,7 +8,7 @@
#include <stddef.h>
#include <psa/sid.h>
#include "rpc/common/endpoint/rpc_service_interface.h"
-#include <rpc/psa_ipc/caller/sp/psa_ipc_caller.h>
+#include <rpc/rss_comms/caller/sp/rss_comms_caller.h>
#include <service/attestation/provider/attest_provider.h>
#include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h>
#include <service/crypto/factory/crypto_provider_factory.h>
@@ -29,15 +29,15 @@
rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
/* Static objects for proxy instance */
- static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_interface rss_comms = { 0 };
static struct rpc_caller_session rpc_session = { 0 };
static struct attest_provider attest_provider = { 0 };
- rpc_status = psa_ipc_caller_init(&psa_ipc);
+ rpc_status = rss_comms_caller_init(&rss_comms);
if (rpc_status != RPC_SUCCESS)
return NULL;
- rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
if (rpc_status != RPC_SUCCESS)
return NULL;
@@ -58,14 +58,14 @@
rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
/* Static objects for proxy instance */
- static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_interface rss_comms = { 0 };
static struct rpc_caller_session rpc_session = { 0 };
- rpc_status = psa_ipc_caller_init(&psa_ipc);
+ rpc_status = rss_comms_caller_init(&rss_comms);
if (rpc_status != RPC_SUCCESS)
return NULL;
- rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
if (rpc_status != RPC_SUCCESS)
return NULL;
@@ -87,14 +87,14 @@
const struct rpc_uuid ps_uuid = { .uuid = TS_PSA_PROTECTED_STORAGE_UUID };
/* Static objects for proxy instance */
- static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_interface rss_comms = { 0 };
static struct rpc_caller_session rpc_session = { 0 };
- rpc_status = psa_ipc_caller_init(&psa_ipc);
+ rpc_status = rss_comms_caller_init(&rss_comms);
if (rpc_status != RPC_SUCCESS)
return NULL;
- rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
if (rpc_status != RPC_SUCCESS)
return NULL;
@@ -113,14 +113,14 @@
const struct rpc_uuid its_uuid = { .uuid = TS_PSA_INTERNAL_TRUSTED_STORAGE_UUID };
/* Static objects for proxy instance */
- static struct rpc_caller_interface psa_ipc = { 0 };
+ static struct rpc_caller_interface rss_comms = { 0 };
static struct rpc_caller_session rpc_session = { 0 };
- rpc_status = psa_ipc_caller_init(&psa_ipc);
+ rpc_status = rss_comms_caller_init(&rss_comms);
if (rpc_status != RPC_SUCCESS)
return NULL;
- rpc_status = rpc_caller_session_open(&rpc_session, &psa_ipc, &dummy_uuid, 0, 0);
+ rpc_status = rpc_caller_session_open(&rpc_session, &rss_comms, &dummy_uuid, 0, 0);
if (rpc_status != RPC_SUCCESS)
return NULL;
diff --git a/deployments/smm-gateway/common/smm_gateway.c b/deployments/smm-gateway/common/smm_gateway.c
index f7279fa..eaa8613 100644
--- a/deployments/smm-gateway/common/smm_gateway.c
+++ b/deployments/smm-gateway/common/smm_gateway.c
@@ -11,6 +11,7 @@
#include "psa/crypto.h"
#include <service/secure_storage/backend/secure_storage_client/secure_storage_client.h>
#include <service/secure_storage/backend/mock_store/mock_store.h>
+#include <service/locator/sp/ffa/spffa_service_context.h>
#include <service_locator.h>
/* Build-time default configuration */
@@ -32,6 +33,26 @@
#define SMM_GATEWAY_MAX_UEFI_VARIABLES (40)
#endif
+/**
+ * The UEFI variable store index must fit into the RPC shared memory, otherwise
+ * load_variable_index/sync_variable_index will fail.
+ */
+#define SMM_UEFI_VARIABLE_STORE_INDEX_SIZE \
+ UEFI_VARIABLE_STORE_INDEX_SIZE(SMM_GATEWAY_MAX_UEFI_VARIABLES)
+
+_Static_assert(SMM_UEFI_VARIABLE_STORE_INDEX_SIZE < RPC_CALLER_SESSION_SHARED_MEMORY_SIZE,
+ "The UEFI variable index does not fit into the RPC shared memory, please increase " \
+ "RPC_CALLER_SESSION_SHARED_MEMORY_SIZE");
+
+/**
+ * The SP heap must be large enough for storing the UEFI variable index, the RPC shared memory and
+ * ~16kB of miscellaneous data.
+ */
+#define SMM_MIN_HEAP_SIZE \
+ SMM_UEFI_VARIABLE_STORE_INDEX_SIZE + RPC_CALLER_SESSION_SHARED_MEMORY_SIZE + 16 * 1024
+
+_Static_assert(SP_HEAP_SIZE > SMM_MIN_HEAP_SIZE, "Please increase SP_HEAP_SIZE");
+
/* The smm_gateway instance - it's a singleton */
static struct smm_gateway
{
diff --git a/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
index b8e4704..39d4f60 100644
--- a/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
+++ b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -35,11 +35,26 @@
set(SP_FFA_UUID_CANON "${SP_BIN_UUID_CANON}")
set(SP_BOOT_ORDER "8" CACHE STRING "Boot order of the SP")
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "smm-gateway")
+
+# SMM variable and RPC caller settings
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 40 CACHE STRING "Maximum UEFI variable count")
+set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 2*4096 CACHE STRING "RPC caller buffer size in SMMGW")
if (UEFI_AUTH_VAR)
-set(SP_HEAP_SIZE "64 * 1024" CACHE STRING "SP heap size in bytes")
+set(SMM_SP_HEAP_SIZE 64*1024 CACHE STRING "SMM gateway SP heap size")
else()
-set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(SMM_SP_HEAP_SIZE 32*1024 CACHE STRING "SMM gateway SP heap size")
endif()
+set(SP_HEAP_SIZE "${SMM_SP_HEAP_SIZE}" CACHE STRING "SP heap size in bytes")
+
+target_compile_definitions("smm-gateway" PRIVATE
+ RPC_CALLER_SESSION_SHARED_MEMORY_SIZE=${SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE}
+ SMM_GATEWAY_MAX_UEFI_VARIABLES=${SMM_GATEWAY_MAX_UEFI_VARIABLES}
+)
set(TRACE_PREFIX "SMMGW" CACHE STRING "Trace prefix")
@@ -66,11 +81,6 @@
include(../../infra/psa-varstore.cmake REQUIRED)
include(../../smm-gateway.cmake REQUIRED)
-#-------------------------------------------------------------------------------
-# Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "smm-gateway")
#-------------------------------------------------------------------------------
# Deployment specific build options
diff --git a/deployments/smm-gateway/config/default-sp/CMakeLists.txt b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
index 3dd182e..102c3ee 100644
--- a/deployments/smm-gateway/config/default-sp/CMakeLists.txt
+++ b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
@@ -40,11 +40,26 @@
set(SP_STACK_SIZE "64 * 1024" CACHE STRING "Stack size")
set(SP_BOOT_ORDER "8" CACHE STRING "Boot order of the SP")
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "smm-gateway")
+
+# SMM variable and RPC caller settings
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 40 CACHE STRING "Maximum UEFI variable count")
+set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 2*4096 CACHE STRING "RPC caller buffer size in SMMGW")
if (UEFI_AUTH_VAR)
-set(SP_HEAP_SIZE "64 * 1024" CACHE STRING "Heap size")
+set(SMM_SP_HEAP_SIZE 64*1024 CACHE STRING "SMM gateway SP heap size")
else()
-set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "Heap size")
+set(SMM_SP_HEAP_SIZE 32*1024 CACHE STRING "SMM gateway SP heap size")
endif()
+set(SP_HEAP_SIZE "${SMM_SP_HEAP_SIZE}" CACHE STRING "SP heap size in bytes")
+
+target_compile_definitions("smm-gateway" PRIVATE
+ RPC_CALLER_SESSION_SHARED_MEMORY_SIZE=${SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE}
+ SMM_GATEWAY_MAX_UEFI_VARIABLES=${SMM_GATEWAY_MAX_UEFI_VARIABLES}
+)
# Setting the MM communication buffer parameters
set(MM_COMM_BUFFER_ADDRESS "0x00000008 0x81000000" CACHE STRING "Address of MM communicte buffer in 64 bit DTS format")
@@ -65,12 +80,6 @@
include(../../smm-gateway.cmake REQUIRED)
#-------------------------------------------------------------------------------
-# Set target platform to provide drivers needed by the deployment
-#
-#-------------------------------------------------------------------------------
-add_platform(TARGET "smm-gateway")
-
-#-------------------------------------------------------------------------------
# Deployment specific build options
#-------------------------------------------------------------------------------
target_compile_definitions(smm-gateway PRIVATE
diff --git a/platform/drivers/arm/mhu_driver/component.cmake b/platform/drivers/arm/mhu_driver/component.cmake
deleted file mode 100644
index 77a5a50..0000000
--- a/platform/drivers/arm/mhu_driver/component.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-# Add source files for using mhu driver
-target_sources(${TGT}
- PRIVATE
- "${CMAKE_CURRENT_LIST_DIR}/mhu_v2_x.c"
-)
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake b/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake
new file mode 100644
index 0000000..e80c549
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Add source files for using mhu driver
+target_sources(${TGT}
+ PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/mhu_v2_x.c"
+ "${CMAKE_CURRENT_LIST_DIR}/mhu_wrapper_v2_x.c"
+ "${CMAKE_CURRENT_LIST_DIR}/mhu_adapter_v2_x.c"
+)
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu.h b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu.h
new file mode 100644
index 0000000..a02fdd8
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2022-2023 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MHU_H__
+#define __MHU_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Generic MHU error enumeration types.
+ */
+enum mhu_error_t {
+ MHU_ERR_NONE = 0,
+ MHU_ERR_NOT_INIT = -1,
+ MHU_ERR_ALREADY_INIT = -2,
+ MHU_ERR_UNSUPPORTED_VERSION = -3,
+ MHU_ERR_UNSUPPORTED = -4,
+ MHU_ERR_INVALID_ARG = -5,
+ MHU_ERR_BUFFER_TOO_SMALL = -6,
+ MHU_ERR_GENERAL = -7,
+};
+
+/**
+ * \brief Initializes sender MHU.
+ *
+ * \param[in] mhu_sender_dev Pointer to the sender MHU.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note This function must be called before mhu_send_data().
+ */
+enum mhu_error_t mhu_init_sender(void *mhu_sender_dev);
+
+/**
+ * \brief Initializes receiver MHU.
+ *
+ * \param[in] mhu_receiver_dev Pointer to the receiver MHU.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note This function must be called before mhu_receive_data().
+ */
+enum mhu_error_t mhu_init_receiver(void *mhu_receiver_dev);
+
+/**
+ * \brief Sends data over MHU.
+ *
+ * \param[in] mhu_sender_dev Pointer to the sender MHU.
+ * \param[in] send_buffer Pointer to buffer containing the data to be
+ * transmitted.
+ * \param[in] size Size of the data to be transmitted in bytes.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note The send_buffer must be 4-byte aligned and its length must be at least
+ * (4 - (size % 4)) bytes bigger than the data size to prevent buffer
+ * over-reading.
+ */
+enum mhu_error_t mhu_send_data(void *mhu_sender_dev,
+ const uint8_t *send_buffer,
+ size_t size);
+
+/**
+ * \brief Wait for data from MHU.
+ *
+ * \param[in] mhu_receiver_dev Pointer to the receiver MHU.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note This function must be called before mhu_receive_data() if the MHU
+ * receiver interrupt is not used.
+ */
+enum mhu_error_t mhu_wait_data(void *mhu_receiver_dev);
+
+/**
+ * \brief Receives data from MHU.
+ *
+ * \param[in] mhu_receiver_dev Pointer to the receiver MHU.
+ * \param[out] receive_buffer Pointer the buffer where to store the
+ * received data.
+ * \param[in,out] size As input the size of the receive_buffer,
+ * as output the number of bytes received.
+ * As a limitation, the size of the buffer
+ * must be a multiple of 4.
+ *
+ * \return Returns mhu_error_t error code.
+ *
+ * \note The receive_buffer must be 4-byte aligned and its length must be a
+ * multiple of 4.
+ */
+enum mhu_error_t mhu_receive_data(void *mhu_receiver_dev,
+ uint8_t *receive_buffer,
+ size_t *size);
+
+/**
+ * \brief Signals an interrupt over the last available channel and wait for the
+ * values to be cleared by the receiver.
+ *
+ * \param[in] mhu_sender_dev Pointer to the sender MHU.
+ * \param[in] value Value that will be used while signaling.
+ *
+ * \return Returns mhu_error_t error code.
+ */
+enum mhu_error_t signal_and_wait_for_clear(void *mhu_sender_dev,
+ uint32_t value);
+
+/**
+ * \brief Wait for signal on the last available channel in a loop and
+ * acknowledge the transfer by clearing the status on that channel.
+ *
+ * \param[in] mhu_receiver_dev Pointer to the receiver MHU.
+ * \param[in] value Value that will be used while waiting.
+ *
+ * \return Returns mhu_error_t error code.
+ */
+enum mhu_error_t wait_for_signal_and_clear(void *mhu_receiver_dev,
+ uint32_t value);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MHU_H__ */
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_adapter_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_adapter_v2_x.c
new file mode 100644
index 0000000..f781a35
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_adapter_v2_x.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <config/interface/config_store.h>
+#include <platform/interface/device_region.h>
+#include <platform/interface/mhu_interface.h>
+#include <stdlib.h>
+
+#include "mhu.h"
+#include "mhu_v2_x.h"
+
+static int mhu_adapter_send(void *context, unsigned char *send_buffer, size_t size)
+{
+ struct mhu_v2_x_dev_t *dev = NULL;
+
+ if (!context || !send_buffer || size == 0)
+ return -1;
+
+ dev = (struct mhu_v2_x_dev_t *)context;
+
+ if (mhu_send_data(dev, (uint8_t *)send_buffer, size) != MHU_ERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+static int mhu_adapter_receive(void *context, unsigned char *receive_buffer, size_t *size)
+{
+ struct mhu_v2_x_dev_t *dev = NULL;
+
+ if (!context || !receive_buffer || !size)
+ return -1;
+
+ dev = (struct mhu_v2_x_dev_t *)context;
+
+ if (mhu_receive_data(dev, (uint8_t *)receive_buffer, size) != MHU_ERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+static int mhu_adapter_wait_data(void *context)
+{
+ struct mhu_v2_x_dev_t *dev = NULL;
+
+ if (!context)
+ return -1;
+
+ dev = (struct mhu_v2_x_dev_t *)context;
+
+ if (mhu_wait_data(dev) != MHU_ERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+static int mhu_adapter_signal_and_wait_for_clear(void *context, uint32_t value)
+{
+ struct mhu_v2_x_dev_t *dev = NULL;
+
+ if (!context)
+ return -1;
+
+ dev = (struct mhu_v2_x_dev_t *)context;
+
+ if (signal_and_wait_for_clear(dev, value) != MHU_ERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+static int mhu_adapter_wait_for_signal_and_clear(void *context, uint32_t value)
+{
+ struct mhu_v2_x_dev_t *dev = NULL;
+
+ if (!context)
+ return -1;
+
+ dev = (struct mhu_v2_x_dev_t *)context;
+
+ if (wait_for_signal_and_clear(dev, value) == MHU_ERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+int platform_mhu_create(struct platform_mhu_driver *driver, const char *object_name,
+ bool is_receiver)
+{
+ struct mhu_v2_x_dev_t *new_instance = NULL;
+ enum mhu_error_t status = MHU_ERR_NONE;
+ struct device_region device_region = { 0 };
+ static const struct platform_mhu_iface iface = {
+ .send = mhu_adapter_send,
+ .receive = mhu_adapter_receive,
+ .wait_data = mhu_adapter_wait_data,
+ .signal_and_wait_for_clear = mhu_adapter_signal_and_wait_for_clear,
+ .wait_for_signal_and_clear = mhu_adapter_wait_for_signal_and_clear,
+ };
+
+ /* Default to leaving the driver in a safe but inoperable state. */
+ driver->iface = &iface;
+ driver->context = NULL;
+
+ if (!config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, object_name, 0, &device_region,
+ sizeof(device_region)))
+ return -1;
+
+ new_instance = calloc(1, sizeof(struct mhu_v2_x_dev_t));
+ if (!new_instance)
+ return -1;
+
+ new_instance->base = device_region.base_addr;
+
+ if (is_receiver) {
+ new_instance->frame = MHU_V2_X_RECEIVER_FRAME;
+ status = mhu_init_receiver(new_instance);
+ } else {
+ new_instance->frame = MHU_V2_X_SENDER_FRAME;
+ status = mhu_init_sender(new_instance);
+ }
+
+ if (status != MHU_ERR_NONE) {
+ free(new_instance);
+ return -1;
+ }
+
+ driver->context = new_instance;
+
+ return 0;
+}
+
+void platform_mhu_destroy(struct platform_mhu_driver *driver)
+{
+ if (!driver->context)
+ return;
+
+ free(driver->context);
+ driver->context = NULL;
+}
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.c
similarity index 95%
rename from platform/drivers/arm/mhu_driver/mhu_v2_x.c
rename to platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.c
index d7e70ef..7d04b0a 100644
--- a/platform/drivers/arm/mhu_driver/mhu_v2_x.c
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Arm Limited
+ * Copyright (c) 2020-2024 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,8 @@
*/
#include <stdint.h>
#include <stdbool.h>
-#include "mhu_v2.h"
+#include <stddef.h>
+#include "mhu_v2_x.h"
#define _MHU_V2_X_MAX_CHANNELS 124
#define _MHU_V2_1_MAX_CHCOMB_INT 4
@@ -70,7 +71,7 @@
volatile uint32_t reserved_0;
/* Offset: 0xFA0 (R/W) Channel Combined Interrupt Stat (Reserved in 2.0) */
volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
- /* Offset: 0xFC4 (R/ ) Reserved */
+ /* Offset: 0xFC4 (R/ ) Reserved */
volatile uint32_t reserved_1[6];
/* Offset: 0xFC8 (R/ ) Implementer Identification Register */
volatile uint32_t iidr;
@@ -142,7 +143,6 @@
enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
enum mhu_v2_x_supported_revisions rev)
{
- uint32_t AIDR = 0;
union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
if (dev->is_initialized) {
@@ -150,6 +150,7 @@
}
if (rev == MHU_REV_READ_FROM_HW) {
+ uint32_t AIDR = 0;
/* Read revision from HW */
if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
AIDR = p_mhu->recv_frame.aidr;
@@ -190,7 +191,12 @@
uint32_t mhu_v2_x_get_num_channel_implemented(const struct mhu_v2_x_dev_t *dev)
{
- union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+ union _mhu_v2_x_frame_t *p_mhu = NULL;
+
+ if (!dev)
+ return MHU_V_2_X_ERR_GENERAL;
+
+ p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
if ( !(dev->is_initialized) ) {
return MHU_V_2_X_ERR_NOT_INIT;
@@ -220,6 +226,23 @@
}
}
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t *value)
+{
+ union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+ if ( !(dev->is_initialized) ) {
+ return MHU_V_2_X_ERR_NOT_INIT;
+ }
+
+ if (dev->frame == MHU_V2_X_SENDER_FRAME) {
+ *value = (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_st;
+ return MHU_V_2_X_ERR_NONE;
+ } else {
+ return MHU_V_2_X_ERR_INVALID_ARG;
+ }
+}
+
enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
uint32_t channel)
{
@@ -591,10 +614,11 @@
}
for(j = 0; j < CH_PER_CH_COMB; j++) {
- if ((status >> (CH_PER_CH_COMB - j - 1)) & (ENABLE)) {
- *channel = (CH_PER_CH_COMB - j -1) + (i * CH_PER_CH_COMB);
+ if (status & ENABLE) {
+ *channel = (j + (i * CH_PER_CH_COMB));
return MHU_V_2_X_ERR_NONE;
}
+ status >>= 1;
}
}
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2.h b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h
similarity index 93%
rename from platform/drivers/arm/mhu_driver/mhu_v2.h
rename to platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h
index 26b3a5d..75f3f91 100644
--- a/platform/drivers/arm/mhu_driver/mhu_v2.h
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_v2_x.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Arm Limited
+ * Copyright (c) 2020-2024 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,8 +92,6 @@
*
* \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
*
- * Returns the number of channels implemented.
- *
* \return Returns the number of channels implemented.
*
* \note This function doesn't check if dev is NULL.
@@ -119,6 +117,23 @@
uint32_t channel, uint32_t val);
/**
+ * \brief Polls sender channel status.
+ *
+ * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel Channel to poll the status of.
+ * \param[out] value Pointer to variable that will store the value.
+ *
+ * Polls sender channel status.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev,
+ uint32_t channel, uint32_t *value);
+
+/**
* \brief Clears the channel after the value is send over it.
*
* \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
@@ -218,12 +233,12 @@
const struct mhu_v2_x_dev_t *dev, uint32_t channel);
/**
- * \brief Cleares the Channel interrupt.
+ * \brief Clears the Channel interrupt.
*
* \param[in] dev MHU device struct \ref mhu_v2_x_dev_t
* \param[in] channel Which channel's interrupt to clear.
*
- * Cleares the Channel interrupt.
+ * Clears the Channel interrupt.
*
* \return Returns mhu_v2_x_error_t error code
*
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_wrapper_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_wrapper_v2_x.c
new file mode 100644
index 0000000..68a30ab
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x/mhu_wrapper_v2_x.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2022-2024 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mhu.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "mhu_v2_x.h"
+
+#define MHU_NOTIFY_VALUE (1234u)
+
+static enum mhu_error_t
+error_mapping_to_mhu_error_t(enum mhu_v2_x_error_t err)
+{
+ switch (err) {
+ case MHU_V_2_X_ERR_NONE:
+ return MHU_ERR_NONE;
+ case MHU_V_2_X_ERR_NOT_INIT:
+ return MHU_ERR_NOT_INIT;
+ case MHU_V_2_X_ERR_ALREADY_INIT:
+ return MHU_ERR_ALREADY_INIT;
+ case MHU_V_2_X_ERR_UNSUPPORTED_VERSION:
+ return MHU_ERR_UNSUPPORTED_VERSION;
+ case MHU_V_2_X_ERR_INVALID_ARG:
+ return MHU_ERR_INVALID_ARG;
+ case MHU_V_2_X_ERR_GENERAL:
+ return MHU_ERR_GENERAL;
+ default:
+ return MHU_ERR_GENERAL;
+ }
+}
+
+enum mhu_error_t
+signal_and_wait_for_clear(void *mhu_sender_dev, uint32_t value)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev;
+ uint32_t channel_notify;
+ uint32_t wait_val;
+
+ if (mhu_sender_dev == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ dev = (struct mhu_v2_x_dev_t *)mhu_sender_dev;
+
+ /* Use the last channel for notifications */
+ channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+ /* FIXME: Avoid wasting a whole channel for notifying */
+ err = mhu_v2_x_channel_send(dev, channel_notify, value);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ do {
+ err = mhu_v2_x_channel_poll(dev, channel_notify, &wait_val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ break;
+ }
+ } while (wait_val != 0);
+
+ return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t
+wait_for_signal_and_clear(void *mhu_receiver_dev, uint32_t value)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev;
+ uint32_t channel_notify;
+ uint32_t wait_val;
+
+ if (mhu_receiver_dev == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ dev = (struct mhu_v2_x_dev_t *)mhu_receiver_dev;
+
+ /* Use the last channel for notifications */
+ channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1;
+
+ do {
+ /* Using the last channel for notifications */
+ err = mhu_v2_x_channel_receive(dev, channel_notify, &wait_val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ } while (wait_val != value);
+
+ /* Clear the last channel */
+ err = mhu_v2_x_channel_clear(dev, channel_notify);
+
+ return error_mapping_to_mhu_error_t(err);
+}
+
+static enum mhu_v2_x_error_t
+clear_and_wait_for_signal(struct mhu_v2_x_dev_t *dev)
+{
+ enum mhu_v2_x_error_t err;
+ uint32_t num_channels = 0;
+ uint32_t val, i;
+
+ if (dev == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ /* At least 1 channal needed for signalling. */
+ if (num_channels < 1) {
+ return MHU_ERR_GENERAL;
+ }
+ /* Clear all channels */
+ for (i = 0; i < num_channels; ++i) {
+ err = mhu_v2_x_channel_clear(dev, i);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return err;
+ }
+ }
+
+ do {
+ /* Using the last channel for notifications */
+ err = mhu_v2_x_channel_receive(dev, num_channels - 1, &val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ break;
+ }
+ } while (val != MHU_NOTIFY_VALUE);
+
+ return err;
+}
+
+enum mhu_error_t mhu_init_sender(void *mhu_sender_dev)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = mhu_sender_dev;
+
+ if (dev == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ err = mhu_v2_x_driver_init(dev, MHU_REV_READ_FROM_HW);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* This wrapper requires at least two channels to be implemented */
+ if (mhu_v2_x_get_num_channel_implemented(dev) < 2) {
+ return MHU_ERR_UNSUPPORTED;
+ }
+
+ return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_init_receiver(void *mhu_receiver_dev)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = mhu_receiver_dev;
+ uint32_t num_channels, i;
+
+ if (dev == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ err = mhu_v2_x_driver_init(dev, MHU_REV_READ_FROM_HW);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+
+ /* This wrapper requires at least two channels to be implemented */
+ if (num_channels < 2) {
+ return MHU_ERR_UNSUPPORTED;
+ }
+
+ /* Mask all channels except the notifying channel */
+ for (i = 0; i < (num_channels - 1); ++i) {
+ err = mhu_v2_x_channel_mask_set(dev, i, UINT32_MAX);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ /* The last channel is used for notifications */
+ err = mhu_v2_x_channel_mask_clear(dev, (num_channels - 1), UINT32_MAX);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ err = mhu_v2_x_interrupt_enable(dev, MHU_2_1_INTR_CHCOMB_MASK);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ return MHU_ERR_NONE;
+}
+
+enum mhu_error_t mhu_send_data(void *mhu_sender_dev,
+ const uint8_t *send_buffer,
+ size_t size)
+{
+ enum mhu_v2_x_error_t err;
+ enum mhu_error_t mhu_err;
+ struct mhu_v2_x_dev_t *dev = mhu_sender_dev;
+ uint32_t num_channels = 0;
+ uint32_t chan = 0;
+ uint32_t i;
+ uint32_t *p;
+
+ if (dev == NULL || send_buffer == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ } else if (size == 0) {
+ return MHU_ERR_NONE;
+ }
+
+ /* For simplicity, require the send_buffer to be 4-byte aligned. */
+ if ((uintptr_t)send_buffer & 0x3u) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ /* At least 2 channals needed for sending a message. */
+ if (num_channels < 2) {
+ return MHU_ERR_GENERAL;
+ }
+ err = mhu_v2_x_initiate_transfer(dev);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* First send over the size of the actual message. */
+ err = mhu_v2_x_channel_send(dev, chan, (uint32_t)size);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan++;
+
+ p = (uint32_t *)send_buffer;
+ for (i = 0; i < size; i += 4) {
+ err = mhu_v2_x_channel_send(dev, chan, *p++);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ if (++chan == (num_channels - 1)) {
+ mhu_err = signal_and_wait_for_clear(dev, MHU_NOTIFY_VALUE);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+ chan = 0;
+ }
+ }
+
+ /* Signal the end of transfer.
+ * It's not required to send a signal when the message was
+ * perfectly-aligned ((num_channels - 1) channels were used in the last
+ * round) preventing it from signaling twice at the end of transfer.
+ */
+ if (chan != 0) {
+ mhu_err = signal_and_wait_for_clear(dev, MHU_NOTIFY_VALUE);
+ if (mhu_err != MHU_ERR_NONE) {
+ return mhu_err;
+ }
+ }
+
+ err = mhu_v2_x_close_transfer(dev);
+ return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t mhu_wait_data(void *mhu_receiver_dev)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = mhu_receiver_dev;
+ uint32_t num_channels = 0;
+ uint32_t val;
+
+ if (dev == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ /* At least 1 channal needed for signalling. */
+ if (num_channels < 1) {
+ return MHU_ERR_GENERAL;
+ }
+
+ do {
+ /* Using the last channel for notifications */
+ err = mhu_v2_x_channel_receive(dev, num_channels - 1, &val);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ break;
+ }
+ } while (val != MHU_NOTIFY_VALUE);
+
+ return error_mapping_to_mhu_error_t(err);
+}
+
+enum mhu_error_t mhu_receive_data(void *mhu_receiver_dev,
+ uint8_t *receive_buffer,
+ size_t *size)
+{
+ enum mhu_v2_x_error_t err;
+ struct mhu_v2_x_dev_t *dev = mhu_receiver_dev;
+ uint32_t num_channels = 0;
+ uint32_t chan = 0;
+ uint32_t message_len;
+ uint32_t i;
+ uint32_t *p;
+
+ if (dev == NULL || receive_buffer == NULL) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ /* For simplicity, require:
+ * - the receive_buffer to be 4-byte aligned,
+ * - the buffer size to be a multiple of 4.
+ */
+ if (((uintptr_t)receive_buffer & 0x3u) || (*size & 0x3u)) {
+ return MHU_ERR_INVALID_ARG;
+ }
+
+ num_channels = mhu_v2_x_get_num_channel_implemented(dev);
+ /* At least 1 channal needed for signalling. */
+ if (num_channels < 1) {
+ return MHU_ERR_GENERAL;
+ }
+ /* The first word is the length of the actual message. */
+ err = mhu_v2_x_channel_receive(dev, chan, &message_len);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan++;
+
+ if (message_len > *size) {
+ /* Message buffer too small */
+ *size = message_len;
+ return MHU_ERR_BUFFER_TOO_SMALL;
+ }
+
+ p = (uint32_t *)receive_buffer;
+ for (i = 0; i < message_len; i += 4) {
+ err = mhu_v2_x_channel_receive(dev, chan, p++);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+
+ /* Only wait for next transfer if there is still missing data. */
+ if (++chan == (num_channels - 1) && (message_len - i) > 4) {
+ /* Busy wait for next transfer */
+ err = clear_and_wait_for_signal(dev);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ chan = 0;
+ }
+ }
+
+ /* Clear all channels */
+ for (i = 0; i < num_channels; ++i) {
+ err = mhu_v2_x_channel_clear(dev, i);
+ if (err != MHU_V_2_X_ERR_NONE) {
+ return error_mapping_to_mhu_error_t(err);
+ }
+ }
+
+ *size = message_len;
+
+ return MHU_ERR_NONE;
+}
diff --git a/platform/interface/mhu_interface.h b/platform/interface/mhu_interface.h
new file mode 100644
index 0000000..723ef07
--- /dev/null
+++ b/platform/interface/mhu_interface.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TS_PLATFORM_INTERFACE_MHU_H
+#define TS_PLATFORM_INTERFACE_MHU_H
+
+/*
+ * Interface definition for a platform MHU driver. A platform provider will
+ * provide concrete implementations of this interface for each alternative
+ * implementation supported.
+ */
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Virtual interface for a platform MHU driver. A platform will provide
+ * one or more concrete implementations of this interface.
+ */
+struct platform_mhu_iface {
+ /*
+ * \brief Sends data over MHU.
+ *
+ * \param[in] context Platform driver context.
+ * \param[in] send_buffer Pointer to buffer containing the data to be
+ * transmitted.
+ * \param[in] size Size of the data to be transmitted in bytes.
+ *
+ * \return 0 if successful.
+ *
+ * \note The send_buffer must be 4-byte aligned and its length must be at least
+ * (4 - (size % 4)) bytes bigger than the data size to prevent buffer
+ * over-reading.
+ */
+ int (*send)(void *context, unsigned char *send_buffer, size_t size);
+
+ /*
+ * \brief Receives data from MHU.
+ *
+ * \param[in] context Platform driver context.
+ * \param[out] receive_buffer Pointer the buffer where to store the
+ * received data.
+ * \param[in,out] size As input the size of the receive_buffer,
+ * as output the number of bytes received.
+ * As a limitation, the size of the buffer
+ * must be a multiple of 4.
+ *
+ * \return 0 if successful.
+ *
+ * \note The receive_buffer must be 4-byte aligned and its length must be a
+ * multiple of 4.
+ */
+ int (*receive)(void *context, unsigned char *receive_buffer, size_t *size);
+
+ /*
+ * \brief Wait for data from MHU.
+ *
+ * \param[in] context Platform driver context.
+ *
+ * \return 0 if successful.
+ *
+ * \note This function must be called before mhu_receive_data() if the MHU
+ * receiver interrupt is not used.
+ */
+ int (*wait_data)(void *context);
+
+ /*
+ * \brief Signals an interrupt over the last available channel and wait for the
+ * values to be cleared by the receiver.
+ *
+ * \param[in] context Platform driver context.
+ * \param[in] value Value that will be used while signaling.
+ *
+ * \return 0 if successful.
+ */
+ int (*signal_and_wait_for_clear)(void *context, uint32_t value);
+
+ /*
+ * \brief Wait for signal on the last available channel in a loop and
+ * acknowledge the transfer by clearing the status on that channel.
+ *
+ * \param[in] context Platform driver context.
+ * \param[in] value Value that will be used while waiting.
+ *
+ * \return 0 if successful.
+ */
+ int (*wait_for_signal_and_clear)(void *context, uint32_t value);
+};
+
+/*
+ * A platform MHU driver instance.
+ */
+struct platform_mhu_driver {
+ void *context; /**< Opaque driver context */
+ const struct platform_mhu_iface *iface; /**< Interface methods */
+};
+
+/*
+ * \brief Factory method to construct a platform specific MHU driver
+ *
+ * \param[out] driver Pointer to driver structure to initialize on construction.
+ * \param[in] object_name Deployment specific name of the instance in the config store.
+ * \param[in] is_receiver True if the MHU will be used for receiving data, false if sending.
+ *
+ * \return 0 if successful.
+ */
+int platform_mhu_create(struct platform_mhu_driver *driver, const char *object_name,
+ bool is_receiver);
+
+/*
+ * \brief Destroy a driver constructed using the factory method
+ *
+ * \param[in] driver Pointer to driver structure for constructed driver.
+ */
+void platform_mhu_destroy(struct platform_mhu_driver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TS_PLATFORM_INTERFACE_MHU_H */
diff --git a/platform/providers/arm/corstone1000/platform.cmake b/platform/providers/arm/corstone1000/platform.cmake
index a3c4209..d944acf 100644
--- a/platform/providers/arm/corstone1000/platform.cmake
+++ b/platform/providers/arm/corstone1000/platform.cmake
@@ -1,15 +1,29 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
-# Platform definition for the 'fvp_base_revc-2xaem8a' virtual platform.
+# Platform definition for the Corstone-1000 platform.
#-------------------------------------------------------------------------------
-# include MHU driver
-include(${TS_ROOT}/platform/drivers/arm/mhu_driver/component.cmake)
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 80 CACHE STRING "Maximum UEFI variable count")
+set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 4*4096 CACHE STRING "RPC caller buffer size in SMMGW")
+set(SMM_SP_HEAP_SIZE 80*1024 CACHE STRING "SMM gateway SP heap size")
target_compile_definitions(${TGT} PRIVATE
SMM_VARIABLE_INDEX_STORAGE_UID=0x787
- SMM_GATEWAY_MAX_UEFI_VARIABLES=100
+ PLAT_RSS_COMMS_PAYLOAD_MAX_SIZE=0x2080
+ COMMS_MHU_MSG_SIZE=0x3500
)
+
+get_property(_platform_driver_dependencies TARGET ${TGT}
+ PROPERTY TS_PLATFORM_DRIVER_DEPENDENCIES
+)
+
+#-------------------------------------------------------------------------------
+# Map platform dependencies to suitable drivers for this platform
+#
+#-------------------------------------------------------------------------------
+if ("mhu" IN_LIST _platform_driver_dependencies)
+ include(${TS_ROOT}/platform/drivers/arm/mhu_driver/mhu_v2_x/driver.cmake)
+endif()