diff options
author | Imre Kis <imre.kis@arm.com> | 2021-10-27 19:57:42 +0200 |
---|---|---|
committer | Gyorgy Szing <Gyorgy.Szing@arm.com> | 2021-11-26 05:05:42 +0100 |
commit | e64a810ce073897661042e22ae7dce2a6e7b577f (patch) | |
tree | a61e2f23dfa3d1386c8029f71038e277a5a78b3a | |
parent | bef43b095edc28d9744f6c2be1a5ba4036998e64 (diff) | |
download | trusted-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
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_ */ |