aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorImre Kis <imre.kis@arm.com>2021-10-27 19:57:42 +0200
committerGyorgy Szing <Gyorgy.Szing@arm.com>2021-11-26 05:05:42 +0100
commite64a810ce073897661042e22ae7dce2a6e7b577f (patch)
treea61e2f23dfa3d1386c8029f71038e277a5a78b3a
parentbef43b095edc28d9744f6c2be1a5ba4036998e64 (diff)
downloadtrusted-services-e64a810ce073897661042e22ae7dce2a6e7b577f.tar.gz
Implement MM communicate RPC endpoint
Implement an RPC endpoint which accepts MM calls over FF-A direct messages using a pre-shared communication buffer. A new interface is introduced for describing MM communicate services so the RPC layer can forward the call to different handlers according to the GUID in the MM communicate header. Signed-off-by: Imre Kis <imre.kis@arm.com> Change-Id: Ie09b623e99de8a009d57cf39b98092b5316477d8
-rw-r--r--components/rpc/mm_communicate/common/mm_communicate_call_args.h24
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/component.cmake13
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c141
-rw-r--r--components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h78
4 files changed, 256 insertions, 0 deletions
diff --git a/components/rpc/mm_communicate/common/mm_communicate_call_args.h b/components/rpc/mm_communicate/common/mm_communicate_call_args.h
new file mode 100644
index 000000000..7d7311daf
--- /dev/null
+++ b/components/rpc/mm_communicate/common/mm_communicate_call_args.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef MM_COMMUNICATE_CALL_ARGS_H_
+#define MM_COMMUNICATE_CALL_ARGS_H_
+
+/**
+ * MM communication protocol is adapted to be used above FF-A direct messages
+ * by the following FF-A direct message argument indexes.
+ */
+
+/* SP message arg indexes */
+#define MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_ADDRESS 0
+#define MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_SIZE 1
+
+#define MM_COMMUNICATE_CALL_ARGS_RETURN_ID 0
+#define MM_COMMUNICATE_CALL_ARGS_RETURN_CODE 1
+#define MM_COMMUNICATE_CALL_ARGS_MBZ0 2
+#define MM_COMMUNICATE_CALL_ARGS_MBZ1 3
+#define MM_COMMUNICATE_CALL_ARGS_MBZ2 4
+
+#endif /* MM_COMMUNICATE_CALL_ARGS_H_ */
diff --git a/components/rpc/mm_communicate/endpoint/sp/component.cmake b/components/rpc/mm_communicate/endpoint/sp/component.cmake
new file mode 100644
index 000000000..456b9a7e3
--- /dev/null
+++ b/components/rpc/mm_communicate/endpoint/sp/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if(NOT DEFINED TGT)
+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/mm_communicate_call_ep.c"
+)
diff --git a/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c
new file mode 100644
index 000000000..09f1e2c56
--- /dev/null
+++ b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "components/rpc/mm_communicate/common/mm_communicate_call_args.h"
+#include "mm_communicate_call_ep.h"
+#include "protocols/common/mm/mm_smc.h"
+#include "util.h"
+#include <assert.h>
+#include <string.h>
+
+bool mm_communicate_call_ep_init(struct mm_communicate_ep *call_ep, uint8_t *comm_buffer,
+ size_t comm_buffer_size)
+{
+ unsigned int i = 0;
+
+ if (comm_buffer_size < EFI_MM_COMMUNICATE_HEADER_SIZE)
+ return false;
+
+ /* Initializing MM communication buffer */
+ call_ep->comm_buffer = comm_buffer;
+ call_ep->comm_buffer_size = comm_buffer_size;
+
+ /* Initializing service table */
+ for (i = 0; i < ARRAY_SIZE(call_ep->service_table); i++) {
+ struct mm_service_entry *entry = &call_ep->service_table[i];
+
+ memset(&entry->guid, 0x00, sizeof(entry->guid));
+ entry->iface = NULL;
+ }
+
+ return true;
+}
+
+static int32_t invoke_mm_service(struct mm_communicate_ep *call_ep, uint16_t source_id,
+ struct mm_service_interface *iface,
+ EFI_MM_COMMUNICATE_HEADER *header)
+{
+ rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+ struct mm_service_call_req call_req = { 0 };
+ int32_t result = 0;
+
+ call_req.guid = &header->HeaderGuid;
+
+ /*
+ * The subtraction for size field should be overflow-safe because of the
+ * check in the init funciton.
+ */
+ call_req.req_buf.data = header->Data;
+ call_req.req_buf.data_len = header->MessageLength;
+ call_req.req_buf.size = call_ep->comm_buffer_size - EFI_MM_COMMUNICATE_HEADER_SIZE;
+
+ call_req.resp_buf.data = header->Data;
+ call_req.resp_buf.data_len = 0;
+ call_req.resp_buf.size = call_ep->comm_buffer_size - EFI_MM_COMMUNICATE_HEADER_SIZE;
+
+ result = iface->receive(iface, &call_req);
+
+ header->MessageLength = call_req.resp_buf.data_len;
+
+ return result;
+}
+
+static int32_t handle_mm_communicate(struct mm_communicate_ep *call_ep, uint16_t source_id,
+ uintptr_t buffer_addr, size_t buffer_size)
+{
+ uintptr_t buffer_arg = 0;
+ size_t request_size = 0;
+ EFI_MM_COMMUNICATE_HEADER *header = NULL;
+ unsigned int i = 0;
+
+ /* Validating call args according to ARM MM spec 3.2.4 */
+ if (buffer_addr == 0)
+ return MM_RETURN_CODE_INVALID_PARAMETER;
+
+ /* Validating comm buffer contents */
+ header = (EFI_MM_COMMUNICATE_HEADER *)call_ep->comm_buffer;
+ if (ADD_OVERFLOW(header->MessageLength, EFI_MM_COMMUNICATE_HEADER_SIZE, &request_size))
+ return MM_RETURN_CODE_INVALID_PARAMETER;
+
+ if (call_ep->comm_buffer_size < request_size)
+ return MM_RETURN_CODE_INVALID_PARAMETER;
+
+ /* Finding iface_id by GUID */
+ for (i = 0; i < ARRAY_SIZE(call_ep->service_table); i++) {
+ const struct mm_service_entry *entry = &call_ep->service_table[i];
+
+ if (entry->iface != NULL &&
+ memcmp(&header->HeaderGuid, &entry->guid, sizeof(entry->guid)) == 0)
+ return invoke_mm_service(call_ep, source_id, entry->iface, header);
+ }
+
+ return MM_RETURN_CODE_NOT_SUPPORTED;
+}
+
+void mm_communicate_call_ep_attach_service(struct mm_communicate_ep *call_ep, const EFI_GUID *guid,
+ struct mm_service_interface *iface)
+{
+ unsigned int i = 0;
+ struct mm_service_entry *entry = NULL;
+ struct mm_service_entry *empty_entry = NULL;
+
+ assert(guid != NULL);
+ assert(iface != NULL);
+
+ for (i = 0; i < ARRAY_SIZE(call_ep->service_table); i++) {
+ entry = &call_ep->service_table[i];
+
+ if (entry->iface == NULL) {
+ empty_entry = entry;
+ break;
+ }
+ }
+
+ assert(empty_entry != NULL);
+
+ memcpy(&empty_entry->guid, guid, sizeof(empty_entry->guid));
+ empty_entry->iface = iface;
+}
+
+void mm_communicate_call_ep_receive(struct mm_communicate_ep *mm_communicate_call_ep,
+ const struct ffa_direct_msg *req_msg,
+ struct ffa_direct_msg *resp_msg)
+{
+ int32_t return_value = 0;
+ uintptr_t buffer_address = 0;
+ size_t buffer_size = 0;
+
+ buffer_address = req_msg->args[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_ADDRESS];
+ buffer_size = req_msg->args[MM_COMMUNICATE_CALL_ARGS_COMM_BUFFER_SIZE];
+
+ return_value = handle_mm_communicate(mm_communicate_call_ep, req_msg->source_id,
+ buffer_address, buffer_size);
+
+ resp_msg->args[MM_COMMUNICATE_CALL_ARGS_RETURN_ID] = ARM_SVC_ID_SP_EVENT_COMPLETE;
+ resp_msg->args[MM_COMMUNICATE_CALL_ARGS_RETURN_CODE] = return_value;
+ resp_msg->args[MM_COMMUNICATE_CALL_ARGS_MBZ0] = 0;
+ resp_msg->args[MM_COMMUNICATE_CALL_ARGS_MBZ1] = 0;
+ resp_msg->args[MM_COMMUNICATE_CALL_ARGS_MBZ2] = 0;
+}
diff --git a/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h
new file mode 100644
index 000000000..75d35152f
--- /dev/null
+++ b/components/rpc/mm_communicate/endpoint/sp/mm_communicate_call_ep.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef MM_COMMUNICATE_CALL_EP_H_
+#define MM_COMMUNICATE_CALL_EP_H_
+
+#include "components/rpc/common/endpoint/rpc_interface.h"
+#include "protocols/common/efi/efi_types.h"
+#include "ffa_api.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MM_COMMUNICATE_MAX_SERVICE_BINDINGS
+#define MM_COMMUNICATE_MAX_SERVICE_BINDINGS (8)
+#endif
+
+/**
+ * MM communication specialized call request structure which contains the GUID
+ * of the called service and the request/response buffers.
+ */
+struct mm_service_call_req {
+ EFI_GUID *guid;
+ struct call_param_buf req_buf;
+ struct call_param_buf resp_buf;
+};
+
+/**
+ * MM communicate service definition. The receive function should return an
+ * MM communication return code.
+ */
+struct mm_service_interface {
+ void *context;
+ int32_t (*receive)(struct mm_service_interface *iface, struct mm_service_call_req *req);
+};
+
+/**
+ * MM service entry for binding GUIDs to services.
+ */
+struct mm_service_entry {
+ EFI_GUID guid;
+ struct mm_service_interface *iface;
+};
+
+/**
+ * MM endpoint descriptor. It keeps track of the associated services and the
+ * MM communication buffer.
+ */
+struct mm_communicate_ep {
+ /* MM communication buffer */
+ uint8_t *comm_buffer;
+ size_t comm_buffer_size;
+
+ /* Array of binding entries between GUIDs and RPC ifaces. */
+ struct mm_service_entry service_table[MM_COMMUNICATE_MAX_SERVICE_BINDINGS];
+};
+
+bool mm_communicate_call_ep_init(struct mm_communicate_ep *call_ep, uint8_t *comm_buffer,
+ size_t comm_buffer_size);
+
+void mm_communicate_call_ep_attach_service(struct mm_communicate_ep *call_ep,
+ const EFI_GUID *guid,
+ struct mm_service_interface *iface);
+
+void mm_communicate_call_ep_receive(struct mm_communicate_ep *call_ep,
+ const struct ffa_direct_msg *req_msg,
+ struct ffa_direct_msg *resp_msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MM_COMMUNICATE_CALL_EP_H_ */