Add mm communicate service location strategy
To support service discovery and RPC session extablishment
for SMM services reached via MM Communicate, a new service
location strategy and service context has been added to the
service locator. Client applications that need to use say the
smm-variable service can now use the service locator to
set-up a session.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I4a97af4763c6a48b9dbe2dcf87ec2c79654131de
diff --git a/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h b/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h
index ba15864..8420681 100644
--- a/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h
+++ b/components/rpc/mm_communicate/caller/linux/mm_communicate_caller.h
@@ -28,7 +28,6 @@
int ffa_fd;
const char *ffa_device_path;
uint16_t dest_partition_id;
- uint16_t dest_iface_id;
uint8_t *comm_buffer;
size_t comm_buffer_size;
size_t req_len;
@@ -55,7 +54,6 @@
int mm_communicate_caller_open(
struct mm_communicate_caller *s,
uint16_t dest_partition_id,
- uint16_t dest_iface_id,
const EFI_GUID *svc_guid);
int mm_communicate_caller_close(
diff --git a/components/service/locator/linux/ffa/linuxffa_location_strategy.c b/components/service/locator/linux/ffa/linuxffa_location_strategy.c
index 0c0b16c..a6ec465 100644
--- a/components/service/locator/linux/ffa/linuxffa_location_strategy.c
+++ b/components/service/locator/linux/ffa/linuxffa_location_strategy.c
@@ -116,7 +116,6 @@
{"protected-storage", "751bf801-3dde-4768-a514-0f10aeed1790", 0},
{"test-runner", "33c75baf-ac6a-4fe4-8ac7-e9909bee2d17", 0},
{"attestation", "a1baf155-8876-4695-8f7c-54955e8db974", 0},
- {"smm-variable", "ed32d533-99e6-4209-9cc0-2d72cdd998a7", 0},
/* Secure Enclave proxy accessed services */
{"crypto", "46bb39d1-b4d9-45b5-88ff-040027dab249", SE_PROXY_INTERFACE_ID_CRYPTO},
diff --git a/components/service/locator/linux/linux_env.c b/components/service/locator/linux/linux_env.c
index cb940f4..4bef301 100644
--- a/components/service/locator/linux/linux_env.c
+++ b/components/service/locator/linux/linux_env.c
@@ -1,18 +1,19 @@
/*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <service_locator.h>
#include <service/locator/linux/ffa/linuxffa_location_strategy.h>
-
+#include <service/locator/linux/mm_communicate/mm_communicate_location_strategy.h>
void service_locator_envinit(void)
{
- /*
- * Register all service location strategies that could be used
- * to locate services from Linux userspace.
- */
- service_locator_register_strategy(linuxffa_location_strategy());
-}
\ No newline at end of file
+ /*
+ * Register all service location strategies that could be used
+ * to locate services from Linux userspace.
+ */
+ service_locator_register_strategy(linuxffa_location_strategy());
+ service_locator_register_strategy(mm_communicate_location_strategy());
+}
diff --git a/components/service/locator/linux/mm_communicate/component.cmake b/components/service/locator/linux/mm_communicate/component.cmake
new file mode 100644
index 0000000..13bc961
--- /dev/null
+++ b/components/service/locator/linux/mm_communicate/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# 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_location_strategy.c"
+ "${CMAKE_CURRENT_LIST_DIR}/mm_communicate_service_context.c"
+ )
diff --git a/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c b/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c
new file mode 100644
index 0000000..632c682
--- /dev/null
+++ b/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include "mm_communicate_location_strategy.h"
+#include "mm_communicate_service_context.h"
+#include <common/uuid/uuid.h>
+#include <service/locator/service_name.h>
+#include <rpc/mm_communicate/caller/linux/mm_communicate_caller.h>
+#include <protocols/service/smm_variable/smm_variable_proto.h>
+
+#define MAX_PARTITION_INSTANCES (1)
+
+/* Structure to define the location of an smm service */
+struct smm_service_location
+{
+ struct uuid_canonical uuid;
+ uint16_t partition_id;
+ EFI_GUID svc_guid;
+};
+
+/* Structure to map a service name to FFA and MM Communicate labels */
+struct smm_service_label
+{
+ const char *service;
+ const char *uuid;
+ EFI_GUID svc_guid;
+};
+
+bool find_candidate_location(const char *sn, struct smm_service_location *location)
+{
+ static const struct smm_service_label service_lookup[] =
+ {
+ {
+ .service = "smm-variable",
+ .uuid = "ed32d533-99e6-4209-9cc0-2d72cdd998a7",
+ .svc_guid = SMM_VARIABLE_GUID
+ },
+ {
+ /* Terminator */
+ .service = NULL
+ }
+ };
+
+ bool found = false;
+ const struct smm_service_label *entry = &service_lookup[0];
+
+ while (entry->service) {
+
+ if (sn_check_service(sn, entry->service)) {
+
+ /* Found a match */
+ memcpy(location->uuid.characters,
+ entry->uuid,
+ UUID_CANONICAL_FORM_LEN + 1);
+
+ location->svc_guid = entry->svc_guid;
+
+ found = true;
+ break;
+ }
+
+ ++entry;
+ }
+
+ return found;
+}
+
+bool discover_partition(const char *dev_path, struct smm_service_location *location)
+{
+ bool discovered = false;
+
+ if (uuid_is_valid(location->uuid.characters) == UUID_CANONICAL_FORM_LEN) {
+
+ struct mm_communicate_caller mm_communicate_caller;
+
+ mm_communicate_caller_init(&mm_communicate_caller, dev_path);
+
+ uint16_t discovered_partitions[MAX_PARTITION_INSTANCES];
+ size_t discovered_count;
+
+ discovered_count = mm_communicate_caller_discover(
+ &mm_communicate_caller,
+ &location->uuid,
+ discovered_partitions,
+ MAX_PARTITION_INSTANCES);
+
+ if (discovered_count > 0) {
+
+ location->partition_id = discovered_partitions[0];
+ discovered = true;
+ }
+
+ mm_communicate_caller_deinit(&mm_communicate_caller);
+ }
+
+ return discovered;
+}
+
+static struct service_context *query(const char *sn, int *status)
+{
+ struct service_context *result = NULL;
+
+ if (!sn_check_authority(sn, "trustedfirmware.org")) return NULL;
+
+ struct smm_service_location location;
+ const char *dev_path = "/sys/kernel/debug/arm_ffa_user";
+
+ if (find_candidate_location(sn, &location) &&
+ discover_partition(dev_path, &location)) {
+
+ struct mm_communicate_service_context *new_context =
+ mm_communicate_service_context_create(
+ dev_path,
+ location.partition_id,
+ &location.svc_guid);
+
+ if (new_context) result = &new_context->service_context;
+ }
+
+ return result;
+}
+
+const struct service_location_strategy *mm_communicate_location_strategy(void)
+{
+ static const struct service_location_strategy strategy = { query };
+ return &strategy;
+}
diff --git a/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.h b/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.h
new file mode 100644
index 0000000..324ad36
--- /dev/null
+++ b/components/service/locator/linux/mm_communicate/mm_communicate_location_strategy.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MM_COMMUNICATE_LOCATION_STRATEGY_H
+#define MM_COMMUNICATE_LOCATION_STRATEGY_H
+
+#include <service_locator.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Returns a service_location_strategy for locating a service instance
+ * hosted in a secure partition, accessed using MM Communicate from Linux userspace.
+ * Relies on an FFA Linux kernel driver.
+ */
+const struct service_location_strategy *mm_communicate_location_strategy(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MM_COMMUNICATE_LOCATION_STRATEGY_H */
diff --git a/components/service/locator/linux/mm_communicate/mm_communicate_service_context.c b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.c
new file mode 100644
index 0000000..7e6330d
--- /dev/null
+++ b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <rpc/mm_communicate/caller/linux/mm_communicate_caller.h>
+#include "mm_communicate_service_context.h"
+
+/* Concrete service_context methods */
+static rpc_session_handle mm_communicate_service_context_open(void *context,
+ struct rpc_caller **caller);
+static void mm_communicate_service_context_close(void *context,
+ rpc_session_handle session_handle);
+static void mm_communicate_service_context_relinquish(void *context);
+
+
+struct mm_communicate_service_context *mm_communicate_service_context_create(
+ const char *dev_path,
+ uint16_t partition_id,
+ const EFI_GUID *svc_guid)
+{
+ struct mm_communicate_service_context *new_context = (struct mm_communicate_service_context*)
+ malloc(sizeof(struct mm_communicate_service_context));
+
+ if (new_context) {
+
+ new_context->ffa_dev_path = dev_path;
+ new_context->partition_id = partition_id;
+ new_context->svc_guid = *svc_guid;
+
+ new_context->service_context.context = new_context;
+ new_context->service_context.open = mm_communicate_service_context_open;
+ new_context->service_context.close = mm_communicate_service_context_close;
+ new_context->service_context.relinquish = mm_communicate_service_context_relinquish;
+ }
+
+ return new_context;
+}
+
+static rpc_session_handle mm_communicate_service_context_open(
+ void *context,
+ struct rpc_caller **caller)
+{
+ struct mm_communicate_service_context *this_context =
+ (struct mm_communicate_service_context*)context;
+
+ rpc_session_handle session_handle = NULL;
+
+ struct mm_communicate_caller *mm_communicate_caller =
+ (struct mm_communicate_caller*)malloc(sizeof(struct mm_communicate_caller));
+
+ if (mm_communicate_caller) {
+
+ *caller = mm_communicate_caller_init(mm_communicate_caller,
+ this_context->ffa_dev_path);
+ int status = mm_communicate_caller_open(mm_communicate_caller,
+ this_context->partition_id, &this_context->svc_guid);
+
+ if (status == 0) {
+ /* Successfully opened session */
+ session_handle = mm_communicate_caller;
+ }
+ else {
+ /* Failed to open session */
+ mm_communicate_caller_close(mm_communicate_caller);
+ mm_communicate_caller_deinit(mm_communicate_caller);
+ free(mm_communicate_caller);
+ }
+ }
+
+ return session_handle;
+}
+
+static void mm_communicate_service_context_close(
+ void *context,
+ rpc_session_handle session_handle)
+{
+ struct mm_communicate_caller *mm_communicate_caller =
+ (struct mm_communicate_caller*)session_handle;
+
+ (void)context;
+
+ if (mm_communicate_caller) {
+
+ mm_communicate_caller_close(mm_communicate_caller);
+ mm_communicate_caller_deinit(mm_communicate_caller);
+ free(mm_communicate_caller);
+ }
+}
+
+static void mm_communicate_service_context_relinquish(
+ void *context)
+{
+ struct mm_communicate_service_context *this_context =
+ (struct mm_communicate_service_context*)context;
+
+ free(this_context);
+}
diff --git a/components/service/locator/linux/mm_communicate/mm_communicate_service_context.h b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.h
new file mode 100644
index 0000000..6771c31
--- /dev/null
+++ b/components/service/locator/linux/mm_communicate/mm_communicate_service_context.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MM_COMMUNICATE_SERVICE_CONTEXT_H
+#define MM_COMMUNICATE_SERVICE_CONTEXT_H
+
+#include <service_locator.h>
+#include <protocols/common/efi/efi_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A service_context that represents a service instance located in
+ * a partition, accessed using the MM Communicate protocol over
+ * FFA.
+ */
+struct mm_communicate_service_context
+{
+ struct service_context service_context;
+ const char *ffa_dev_path;
+ uint16_t partition_id;
+ EFI_GUID svc_guid;
+};
+
+/*
+ * Factory method to create a service context associated with the specified
+ * partition id and service GUID.
+ */
+struct mm_communicate_service_context *mm_communicate_service_context_create(
+ const char *dev_path,
+ uint16_t partition_id,
+ const EFI_GUID *svc_guid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MM_COMMUNICATE_SERVICE_CONTEXT_H */