aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Hall <julian.hall@arm.com>2020-11-23 18:12:17 +0100
committerGyorgy Szing <Gyorgy.Szing@arm.com>2020-11-27 16:47:03 +0100
commit8cff2b8f95ef9f41166dc13e7687e28d842203fe (patch)
treef16510a760805c6e5fed9dc7578aeceb6821949c
parentdf86fcee4f72a719cd56a57e1fbb03105bbfc024 (diff)
downloadtrusted-services-8cff2b8f95ef9f41166dc13e7687e28d842203fe.tar.gz
Add service locator component
Change-Id: I58ad588deff3c0904b3ba8b9162b20440e9ff7d3 Signed-off-by: Julian Hall <julian.hall@arm.com>
-rw-r--r--components/service/locator/component.cmake15
-rw-r--r--components/service/locator/interface/component.cmake17
-rw-r--r--components/service/locator/interface/service_locator.h115
-rw-r--r--components/service/locator/linux/component.cmake14
-rw-r--r--components/service/locator/linux/ffa/component.cmake15
-rw-r--r--components/service/locator/linux/ffa/linuxffa_location_strategy.c162
-rw-r--r--components/service/locator/linux/ffa/linuxffa_location_strategy.h27
-rw-r--r--components/service/locator/linux/ffa/linuxffa_service_context.c80
-rw-r--r--components/service/locator/linux/ffa/linuxffa_service_context.h38
-rw-r--r--components/service/locator/linux/linux_env.c18
-rw-r--r--components/service/locator/service_locator.c71
-rw-r--r--components/service/locator/service_name.c196
-rw-r--r--components/service/locator/service_name.h49
-rw-r--r--components/service/locator/standalone/component.cmake17
-rw-r--r--components/service/locator/standalone/services/crypto/component.cmake14
-rw-r--r--components/service/locator/standalone/services/crypto/crypto_service_context.cpp36
-rw-r--r--components/service/locator/standalone/services/crypto/crypto_service_context.h31
-rw-r--r--components/service/locator/standalone/standalone_env.cpp17
-rw-r--r--components/service/locator/standalone/standalone_location_strategy.cpp29
-rw-r--r--components/service/locator/standalone/standalone_location_strategy.h27
-rw-r--r--components/service/locator/standalone/standalone_service_context.cpp117
-rw-r--r--components/service/locator/standalone/standalone_service_context.h53
-rw-r--r--components/service/locator/standalone/standalone_service_registry.cpp83
-rw-r--r--components/service/locator/standalone/standalone_service_registry.h40
-rw-r--r--components/service/locator/test/component.cmake13
-rw-r--r--components/service/locator/test/sn_tests.cpp91
26 files changed, 1385 insertions, 0 deletions
diff --git a/components/service/locator/component.cmake b/components/service/locator/component.cmake
new file mode 100644
index 0000000..fe7d137
--- /dev/null
+++ b/components/service/locator/component.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, 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}/service_locator.c"
+ "${CMAKE_CURRENT_LIST_DIR}/service_name.c"
+ )
+
diff --git a/components/service/locator/interface/component.cmake b/components/service/locator/interface/component.cmake
new file mode 100644
index 0000000..b5aefa3
--- /dev/null
+++ b/components/service/locator/interface/component.cmake
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, 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} PROPERTY SERVICE_LOCATOR_PUBLIC_HEADER_FILES
+ "${CMAKE_CURRENT_LIST_DIR}/service_locator.h"
+ )
+
+target_include_directories(${TGT} PUBLIC
+ "${CMAKE_CURRENT_LIST_DIR}"
+ )
diff --git a/components/service/locator/interface/service_locator.h b/components/service/locator/interface/service_locator.h
new file mode 100644
index 0000000..3e1404b
--- /dev/null
+++ b/components/service/locator/interface/service_locator.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SERVICE_LOCATOR_H
+#define SERVICE_LOCATOR_H
+
+#include <rpc_caller.h>
+
+/*
+ * The service_locator puplic interface may be exported as a public interface to
+ * a shared library.
+ */
+#ifdef EXPORT_PUBLIC_INTERFACE_SERVICE_LOCATOR
+#define SERVICE_LOCATOR_EXPORTED __attribute__((__visibility__("default")))
+#else
+#define SERVICE_LOCATOR_EXPORTED
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The service_locator provides an interface for locating trusted service
+ * provider instances and establishing RPC sessions for using the service.
+ * The service_locator decouples clients from the details of any particular
+ * service deployment. By accessing trusted services using the service_locator,
+ * client code may be reused accross different service deployment scenarios.
+ */
+struct service_location_strategy;
+typedef void* rpc_session_handle;
+
+/*
+ * Initialises the singleton service locator. Must be called once
+ * but may be called more than once.
+ */
+SERVICE_LOCATOR_EXPORTED void service_locator_init(void);
+
+/*
+ * An environment specific implementation of this function is
+ * needed in order to initialise and register the set of
+ * concrete service_location_strategy objects to use when
+ * building a deployment for a particular environment.
+ */
+void service_locator_envinit(void);
+
+/*
+ * Register a service_location_strategy for locating service
+ * instances. When attempting to locate a service, the set
+ * of registered service_location_strategy objects will be tried
+ * in the order of registration.
+ */
+void service_locator_register_strategy(const struct service_location_strategy *strategy);
+
+/*
+ * Query to locate a service instance. If the given service name
+ * corresponds to an available service instance, a service_context
+ * is returned. The client should hang onto this until it has
+ * finished using the service. When the service is no longer needed,
+ * the client should call the relinquish method. Returns NULL
+ * if no service is located that corresponds to the service name.
+ */
+SERVICE_LOCATOR_EXPORTED struct service_context *service_locator_query(const char *sn, int *status);
+
+/*
+ * The service_context struct represents a service instance to a client
+ * after having located the service instance using the service locator. A
+ * service_context object allows a client to open and close RPC sessions
+ * associated with the service instance, wherever it happens to be deployed.
+ */
+struct service_context
+{
+ void *context;
+
+ rpc_session_handle (*open)(void *context, struct rpc_caller **caller);
+ void (*close)(void *context, rpc_session_handle session_handle);
+ void (*relinquish)(void *context);
+};
+
+/*
+ * Provides an abstract interface for a strategy that locates services
+ * in a particular way. The set of registered strategies forms a
+ * chain of responsibility for resolving a query made by a clisnt.
+ */
+struct service_location_strategy
+{
+ struct service_context *(*query)(const char *sn, int *status);
+};
+
+/*
+ * Open an RPC session in order to use the service associated with this
+ * service_context.
+ */
+SERVICE_LOCATOR_EXPORTED rpc_session_handle service_context_open(struct service_context *s, struct rpc_caller **caller);
+
+/*
+ * Close an RPC session.
+ */
+SERVICE_LOCATOR_EXPORTED void service_context_close(struct service_context *s, rpc_session_handle session_handle);
+
+/*
+ * Called by a client when it has finished using a service context.
+ */
+SERVICE_LOCATOR_EXPORTED void service_context_relinquish(struct service_context *context);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERVICE_LOCATOR_H */
diff --git a/components/service/locator/linux/component.cmake b/components/service/locator/linux/component.cmake
new file mode 100644
index 0000000..4247c69
--- /dev/null
+++ b/components/service/locator/linux/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, 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}/linux_env.c"
+ )
+
diff --git a/components/service/locator/linux/ffa/component.cmake b/components/service/locator/linux/ffa/component.cmake
new file mode 100644
index 0000000..1e5a287
--- /dev/null
+++ b/components/service/locator/linux/ffa/component.cmake
@@ -0,0 +1,15 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, 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}/linuxffa_location_strategy.c"
+ "${CMAKE_CURRENT_LIST_DIR}/linuxffa_service_context.c"
+ )
+
diff --git a/components/service/locator/linux/ffa/linuxffa_location_strategy.c b/components/service/locator/linux/ffa/linuxffa_location_strategy.c
new file mode 100644
index 0000000..8c1cb64
--- /dev/null
+++ b/components/service/locator/linux/ffa/linuxffa_location_strategy.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "linuxffa_location_strategy.h"
+#include "linuxffa_service_context.h"
+#include <common/uuid/uuid.h>
+#include <service/locator/service_name.h>
+#include <rpc/ffarpc/caller/linux/ffarpc_caller.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * There is the potential for there to be alternative deployment possibilities
+ * for a service instance. This will depend on deployment decisions such as
+ * running one service instance per SP, or multiple services per SP. The FFA
+ * location strategy accommodates this by allowing for more than one suggestion
+ * for a service to partition mapping.
+ */
+#define MAX_PARTITION_SUGGESTIONS (4)
+
+/*
+ * The maximum number of partition instances, identified by a particular UUID,
+ * that may be discovered.
+ */
+#define MAX_PARTITION_INSTANCES (4)
+
+static struct service_context *query(const char *sn, int *status);
+static size_t suggest_tf_org_partition_uuids(const char *sn, struct uuid_canonical *uuids, size_t uuid_limit);
+static size_t use_ffa_partition_uuid(const char *sn, struct uuid_canonical *uuids, size_t uuid_limit);
+static bool discover_partition(const char *sn, struct uuid_canonical *uuid, const char *dev_path, uint16_t *partition_id);
+
+const struct service_location_strategy *linuxffa_location_strategy(void)
+{
+ static const struct service_location_strategy strategy = { query };
+ return &strategy;
+}
+
+static struct service_context *query(const char *sn, int *status)
+{
+ struct service_context *result = NULL;
+ struct uuid_canonical uuids[MAX_PARTITION_SUGGESTIONS];
+ size_t num_suggestons = 0;
+ size_t suggeston_index;
+
+ /* Determine one or more candidate partition UUIDs from the specified service name. */
+ if (sn_check_authority(sn, "trustedfirmware.org")) {
+ num_suggestons = suggest_tf_org_partition_uuids(sn, uuids, MAX_PARTITION_SUGGESTIONS);
+ }
+ else if (sn_check_authority(sn, "ffa")) {
+ num_suggestons = use_ffa_partition_uuid(sn, uuids, MAX_PARTITION_SUGGESTIONS);
+ }
+
+ /* Attempt to discover suitable partitions */
+ for (suggeston_index = 0; suggeston_index < num_suggestons; ++suggeston_index) {
+
+ uint16_t partition_id;
+ const char *dev_path = "/sys/kernel/debug/buf";
+
+ if (discover_partition(sn, &uuids[suggeston_index], dev_path, &partition_id)) {
+
+ struct linuxffa_service_context *new_context = linuxffa_service_context_create(dev_path, partition_id);
+
+ if (new_context) result = &new_context->service_context;
+ break;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Returns a list of partition UUIDs to identify partitions that could potentially host the
+ * requested service. This mapping is based trustedfirmware.org ffa partition UUIDs. There
+ * may be multiple UUIDs because of different depeloyment decisions such as dedicated SP,
+ * SP hosting multple services.
+ */
+static size_t suggest_tf_org_partition_uuids(const char *sn, struct uuid_canonical *uuids, size_t uuid_limit)
+{
+ const struct service_to_uuid
+ {
+ const char *service;
+ const char *uuid;
+ }
+ partition_lookup[] =
+ {
+ {"crypto", "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0"},
+ {"secure-storage", "dc1eef48-b17a-4ccf-ac8b-dfcff7711b14"},
+ {NULL, NULL}
+ };
+
+ const struct service_to_uuid *entry = &partition_lookup[0];
+ size_t num_suggestions = 0;
+
+ while (entry->service && (num_suggestions < uuid_limit)) {
+
+ if (sn_check_service(sn, entry->service)) {
+
+ memcpy(uuids[num_suggestions].characters, entry->uuid, UUID_CANONICAL_FORM_LEN + 1);
+ ++num_suggestions;
+ }
+
+ ++entry;
+ }
+
+ return num_suggestions;
+}
+
+/*
+ * When an ffa service name where the service field is an explicit UUID is used, the UUID
+ * is used directly for partition discovery.
+ */
+static size_t use_ffa_partition_uuid(const char *sn, struct uuid_canonical *uuids, size_t uuid_limit)
+{
+ size_t num_suggestions = 0;
+
+ if ((num_suggestions < uuid_limit) &&
+ (sn_read_service(sn, uuids[num_suggestions].characters, UUID_CANONICAL_FORM_LEN + 1) == UUID_CANONICAL_FORM_LEN)) {
+
+ ++num_suggestions;
+ }
+
+ return num_suggestions;
+}
+
+/*
+ * Attempt to discover the partition that hosts the requested service instance.
+ */
+static bool discover_partition(const char *sn, struct uuid_canonical *uuid,
+ const char *dev_path, uint16_t *partition_id)
+{
+ bool discovered = false;
+ struct uuid_octets uuid_bytes;
+
+ if (uuid_parse_to_octets_reversed(uuid->characters, uuid_bytes.octets, UUID_OCTETS_LEN) == UUID_CANONICAL_FORM_LEN) {
+
+ struct ffarpc_caller ffarpc_caller;
+ unsigned int required_instance = sn_get_service_instance(sn);
+
+ ffarpc_caller_init(&ffarpc_caller, dev_path);
+
+ uint16_t discovered_partitions[MAX_PARTITION_INSTANCES];
+ size_t discovered_count;
+
+ discovered_count = ffarpc_caller_discover(&ffarpc_caller, uuid_bytes.octets,
+ discovered_partitions, MAX_PARTITION_INSTANCES);
+
+ if ((discovered_count > 0) && (required_instance < discovered_count)) {
+
+ *partition_id = discovered_partitions[required_instance];
+ discovered = true;
+ }
+
+ ffarpc_caller_deinit(&ffarpc_caller);
+ }
+
+ return discovered;
+}
diff --git a/components/service/locator/linux/ffa/linuxffa_location_strategy.h b/components/service/locator/linux/ffa/linuxffa_location_strategy.h
new file mode 100644
index 0000000..6bb7eeb
--- /dev/null
+++ b/components/service/locator/linux/ffa/linuxffa_location_strategy.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LINUXFFA_LOCATION_STRATEGY_H
+#define LINUXFFA_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 FFA from Linux userspace.
+ * Relies on an FFA Linux kernel driver.
+ */
+const struct service_location_strategy *linuxffa_location_strategy(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LINUXFFA_LOCATION_STRATEGY_H */ \ No newline at end of file
diff --git a/components/service/locator/linux/ffa/linuxffa_service_context.c b/components/service/locator/linux/ffa/linuxffa_service_context.c
new file mode 100644
index 0000000..2af7c60
--- /dev/null
+++ b/components/service/locator/linux/ffa/linuxffa_service_context.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "linuxffa_service_context.h"
+#include <rpc/ffarpc/caller/linux/ffarpc_caller.h>
+#include <stdlib.h>
+
+/* Concrete service_context methods */
+static rpc_session_handle linuxffa_service_context_open(void *context, struct rpc_caller **caller);
+static void linuxffa_service_context_close(void *context, rpc_session_handle session_handle);
+static void linuxffa_service_context_relinquish(void *context);
+
+
+struct linuxffa_service_context *linuxffa_service_context_create(const char *dev_path, uint16_t partition_id)
+{
+ struct linuxffa_service_context *new_context =
+ (struct linuxffa_service_context*)malloc(sizeof(struct linuxffa_service_context));
+
+ if (new_context) {
+ new_context->ffa_dev_path = dev_path;
+ new_context->partition_id = partition_id;
+
+ new_context->service_context.context = new_context;
+ new_context->service_context.open = linuxffa_service_context_open;
+ new_context->service_context.close = linuxffa_service_context_close;
+ new_context->service_context.relinquish = linuxffa_service_context_relinquish;
+ }
+
+ return new_context;
+}
+
+static rpc_session_handle linuxffa_service_context_open(void *context, struct rpc_caller **caller)
+{
+ struct linuxffa_service_context *this_context = (struct linuxffa_service_context*)context;
+ rpc_session_handle session_handle = NULL;
+ struct ffarpc_caller *ffarpc_caller = (struct ffarpc_caller*)malloc(sizeof(struct ffarpc_caller));
+
+ if (ffarpc_caller) {
+
+ int status;
+ *caller = ffarpc_caller_init(ffarpc_caller, this_context->ffa_dev_path);
+ status = ffarpc_caller_open(ffarpc_caller, this_context->partition_id);
+
+ if (status == 0) {
+ /* Successfully opened session */
+ session_handle = ffarpc_caller;
+ }
+ else {
+ /* Failed to open session */
+ ffarpc_caller_close(ffarpc_caller);
+ ffarpc_caller_deinit(ffarpc_caller);
+ free(ffarpc_caller);
+ }
+ }
+
+ return session_handle;
+}
+
+static void linuxffa_service_context_close(void *context, rpc_session_handle session_handle)
+{
+ struct ffarpc_caller *ffarpc_caller = (struct ffarpc_caller*)session_handle;
+
+ (void)context;
+
+ if (ffarpc_caller) {
+
+ ffarpc_caller_close(ffarpc_caller);
+ ffarpc_caller_deinit(ffarpc_caller);
+ free(ffarpc_caller);
+ }
+}
+
+static void linuxffa_service_context_relinquish(void *context)
+{
+ struct linuxffa_service_context *this_context = (struct linuxffa_service_context*)context;
+ free(this_context);
+}
diff --git a/components/service/locator/linux/ffa/linuxffa_service_context.h b/components/service/locator/linux/ffa/linuxffa_service_context.h
new file mode 100644
index 0000000..a16fe13
--- /dev/null
+++ b/components/service/locator/linux/ffa/linuxffa_service_context.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LINUXFFA_SERVICE_CONTEXT_H
+#define LINUXFFA_SERVICE_CONTEXT_H
+
+#include <service_locator.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A service_context that represents a service instance located in
+ * a partition, accessed via FFA. This service_context is suitable
+ * for use by client applications running in Linux userspace.
+ */
+struct linuxffa_service_context
+{
+ struct service_context service_context;
+ const char *ffa_dev_path;
+ uint16_t partition_id;
+};
+
+/*
+ * Factory method to create a service context associated with theh specified
+ * partition id.
+ */
+struct linuxffa_service_context *linuxffa_service_context_create(const char *dev_path, uint16_t partition_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LINUXFFA_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/linux/linux_env.c b/components/service/locator/linux/linux_env.c
new file mode 100644
index 0000000..cb940f4
--- /dev/null
+++ b/components/service/locator/linux/linux_env.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, 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>
+
+
+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
diff --git a/components/service/locator/service_locator.c b/components/service/locator/service_locator.c
new file mode 100644
index 0000000..90cb457
--- /dev/null
+++ b/components/service/locator/service_locator.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service_locator.h>
+#include "service_name.h"
+#include <assert.h>
+#include <stddef.h>
+
+#define SERVICE_LOCATOR_MAX_STATEGIES (8)
+
+/*
+ * The singleton service_locator object.
+ */
+static struct service_locator
+{
+ unsigned int num_strategies;
+ const struct service_location_strategy *strategies[SERVICE_LOCATOR_MAX_STATEGIES];
+
+} service_locator_instance = { .num_strategies = 0 };
+
+
+void service_locator_init(void)
+{
+ if (service_locator_instance.num_strategies == 0) service_locator_envinit();
+}
+
+void service_locator_register_strategy(const struct service_location_strategy *strategy)
+{
+ assert(service_locator_instance.num_strategies < SERVICE_LOCATOR_MAX_STATEGIES);
+
+ if (service_locator_instance.num_strategies < SERVICE_LOCATOR_MAX_STATEGIES) {
+
+ service_locator_instance.strategies[service_locator_instance.num_strategies] = strategy;
+ ++service_locator_instance.num_strategies;
+ }
+}
+
+struct service_context *service_locator_query(const char *sn, int *status)
+{
+ struct service_context *located_context = NULL;
+ unsigned int index = 0;
+
+ if (sn_is_valid(sn)) {
+
+ while (!located_context && (index < service_locator_instance.num_strategies)) {
+
+ located_context = service_locator_instance.strategies[index]->query(sn, status);
+ ++index;
+ }
+ }
+
+ return located_context;
+}
+
+rpc_session_handle service_context_open(struct service_context *s, struct rpc_caller **caller)
+{
+ return s->open(s->context, caller);
+}
+
+void service_context_close(struct service_context *s, rpc_session_handle session_handle)
+{
+ s->close(s->context, session_handle);
+}
+
+void service_context_relinquish(struct service_context *s)
+{
+ s->relinquish(s->context);
+}
diff --git a/components/service/locator/service_name.c b/components/service/locator/service_name.c
new file mode 100644
index 0000000..878b84b
--- /dev/null
+++ b/components/service/locator/service_name.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "service_name.h"
+
+/*
+ * Structure to hold result of parsing the service name. Sets
+ * indices and length of the following fields. Lengths are set to zero
+ * if field is not present.
+ */
+struct sn_parsed_fields
+{
+ size_t authority_pos;
+ size_t authority_len;
+ size_t service_pos;
+ size_t service_len;
+ size_t version_pos;
+ size_t version_len;
+ size_t instance_pos;
+ size_t instance_len;
+};
+
+/*
+ * Find the lengthof the current field, up to the specified separator or end
+ * of the service name.
+ */
+static size_t field_len(const char *sn, size_t from, size_t len, char separator)
+{
+ size_t field_len = 0;
+ size_t pos = from;
+
+ while (pos < len) {
+
+ if (sn[pos] == separator) break;
+
+ ++pos;
+ ++field_len;
+ }
+
+ return field_len;
+}
+
+/*
+ * Find the next field in the service name after the specified separator from the
+ * specified position.
+ */
+static bool find_next(const char *sn, size_t from, size_t len, char separator, size_t *next)
+{
+ bool found = false;
+ size_t pos = from;
+
+ while (pos < len) {
+
+ if (sn[pos] == separator) {
+ *next = pos + 1;
+ found = (*next < len);
+ break;
+ }
+
+ ++pos;
+ }
+
+ return found;
+}
+
+/*
+ * Parse the service name. Returns true if is a legal service
+ * name and mandatory fields are present;
+ */
+static bool sn_parse(const char *sn, struct sn_parsed_fields *fields)
+{
+ size_t sn_len = strlen(sn);
+ size_t field_pos = 0;
+
+ fields->authority_pos = 0;
+ fields->authority_len = 0;
+ fields->service_pos = 0;
+ fields->service_len = 0;
+ fields->version_pos = 0;
+ fields->version_len = 0;
+ fields->instance_pos = 0;
+ fields->instance_len = 0;
+
+ /* Absorb urn: if present */
+ if (memcmp("urn", &sn[field_pos], strlen("urn")) == 0) {
+ if (!find_next(sn, field_pos, sn_len, ':', &field_pos)) return false;
+ }
+
+ /* Check it is a service name */
+ if (memcmp("sn", &sn[field_pos], strlen("sn")) != 0) {
+ /* Not a service name */
+ return false;
+ }
+
+ /* Expect the authority field */
+ if (find_next(sn, field_pos, sn_len, ':', &field_pos)) {
+ fields->authority_pos = field_pos;
+ fields->authority_len = field_len(sn, field_pos, sn_len, ':');
+ }
+ else {
+ /* Missing mandatory authority field */
+ return false;
+ }
+
+ /* Expect the service field */
+ if (find_next(sn, field_pos, sn_len, ':', &field_pos)) {
+ fields->service_pos = field_pos;
+ fields->service_len = field_len(sn, field_pos, sn_len, ':');
+
+ /* Check for the optional version */
+ if (find_next(sn, field_pos, field_pos + fields->service_len, '.', &field_pos)) {
+ fields->version_pos = field_pos;
+ fields->version_len = field_len(sn, field_pos, sn_len, ':');
+ }
+ }
+ else {
+ /* Missing mandatory service field */
+ return false;
+ }
+
+ /* Check for optional instance */
+ if (find_next(sn, field_pos, sn_len, ':', &field_pos)) {
+ fields->instance_pos = field_pos;
+ fields->instance_len = sn_len - field_pos;
+ }
+
+ return true;
+}
+
+bool sn_is_valid(const char *sn)
+{
+ struct sn_parsed_fields fields;
+ return sn_parse(sn, &fields);
+}
+
+bool sn_check_authority(const char *sn, const char *auth)
+{
+ bool matched = false;
+ struct sn_parsed_fields fields;
+
+ if (sn_parse(sn, &fields) && fields.authority_len) {
+
+ matched = (memcmp(auth, &sn[fields.authority_pos], strlen(auth)) == 0);
+ }
+
+ return matched;
+}
+
+bool sn_check_service(const char *sn, const char *service)
+{
+ bool matched = false;
+ struct sn_parsed_fields fields;
+
+ if (sn_parse(sn, &fields) && fields.service_len) {
+
+ matched = (memcmp(service, &sn[fields.service_pos], strlen(service)) == 0);
+ }
+
+ return matched;
+}
+
+unsigned int sn_get_service_instance(const char *sn)
+{
+ unsigned int instance = 0;
+
+ struct sn_parsed_fields fields;
+
+ if (sn_parse(sn, &fields) && fields.instance_len) {
+
+ sscanf(&sn[fields.instance_pos], "%d", &instance);
+ }
+
+ return instance;
+}
+
+size_t sn_read_service(const char *sn, char *buf, size_t buf_len)
+{
+ size_t field_len = 0;
+
+ memset(buf, 0, buf_len);
+ struct sn_parsed_fields fields;
+
+ if (sn_parse(sn, &fields) && fields.service_len && (fields.service_len < buf_len)) {
+
+ field_len = fields.service_len;
+ memcpy(buf, &sn[fields.service_pos], field_len);
+ buf[field_len] = '\0';
+ }
+
+ return field_len;
+}
diff --git a/components/service/locator/service_name.h b/components/service/locator/service_name.h
new file mode 100644
index 0000000..441dea4
--- /dev/null
+++ b/components/service/locator/service_name.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SERVICE_NAME_H
+#define SERVICE_NAME_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Check if it is valid service name with all the mandatory sections.
+ */
+bool sn_is_valid(const char *sn);
+
+/*
+ * Check naming authority. Returns true for match.
+ */
+bool sn_check_authority(const char *sn, const char *auth);
+
+/*
+ * Check the service portion of the service name. Returns true for match.
+ */
+bool sn_check_service(const char *sn, const char *service);
+
+/*
+ * Get the service instance number
+ */
+unsigned int sn_get_service_instance(const char *sn);
+
+/*
+ * Read the service field and copy the null terminated string
+ * to the provided buffer. Returns the copied string length,
+ * minus the zero terminator.
+ */
+size_t sn_read_service(const char *sn, char *buf, size_t buf_len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERVICE_NAME_H */
diff --git a/components/service/locator/standalone/component.cmake b/components/service/locator/standalone/component.cmake
new file mode 100644
index 0000000..cb75c82
--- /dev/null
+++ b/components/service/locator/standalone/component.cmake
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, 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}/standalone_env.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/standalone_service_context.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/standalone_service_registry.cpp"
+ "${CMAKE_CURRENT_LIST_DIR}/standalone_location_strategy.cpp"
+ )
+
diff --git a/components/service/locator/standalone/services/crypto/component.cmake b/components/service/locator/standalone/services/crypto/component.cmake
new file mode 100644
index 0000000..0e5529b
--- /dev/null
+++ b/components/service/locator/standalone/services/crypto/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, 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}/crypto_service_context.cpp"
+ )
+
diff --git a/components/service/locator/standalone/services/crypto/crypto_service_context.cpp b/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
new file mode 100644
index 0000000..e3bc2e8
--- /dev/null
+++ b/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "crypto_service_context.h"
+
+crypto_service_context::crypto_service_context(const char *sn) :
+ standalone_service_context(sn),
+ m_crypto_provider(),
+ m_storage_provider(),
+ m_storage_caller()
+{
+
+}
+
+crypto_service_context::~crypto_service_context()
+{
+
+}
+
+void crypto_service_context::do_init()
+{
+ struct call_ep *storage_ep = sfs_provider_init(&m_storage_provider);
+ struct rpc_caller *storage_caller = direct_caller_init_default(&m_storage_caller, storage_ep);
+ struct call_ep *crypto_ep = mbed_crypto_provider_init(&m_crypto_provider, storage_caller);
+
+ standalone_service_context::set_call_ep(crypto_ep);
+}
+
+void crypto_service_context::do_deinit()
+{
+ mbed_crypto_provider_deinit(&m_crypto_provider);
+ direct_caller_deinit(&m_storage_caller);
+}
diff --git a/components/service/locator/standalone/services/crypto/crypto_service_context.h b/components/service/locator/standalone/services/crypto/crypto_service_context.h
new file mode 100644
index 0000000..6e79163
--- /dev/null
+++ b/components/service/locator/standalone/services/crypto/crypto_service_context.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_CRYPTO_SERVICE_CONTEXT_H
+#define STANDALONE_CRYPTO_SERVICE_CONTEXT_H
+
+#include <service/locator/standalone/standalone_service_context.h>
+#include <rpc/direct/direct_caller.h>
+#include <service/crypto/provider/mbedcrypto/crypto_provider.h>
+#include <service/secure_storage/provider/secure_flash_store/sfs_provider.h>
+
+class crypto_service_context : public standalone_service_context
+{
+public:
+ crypto_service_context(const char *sn);
+ virtual ~crypto_service_context();
+
+private:
+
+ void do_init();
+ void do_deinit();
+
+ struct mbed_crypto_provider m_crypto_provider;
+ struct sfs_provider m_storage_provider;
+ struct direct_caller m_storage_caller;
+};
+
+#endif /* STANDALONE_CRYPTO_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/standalone_env.cpp b/components/service/locator/standalone/standalone_env.cpp
new file mode 100644
index 0000000..80d1777
--- /dev/null
+++ b/components/service/locator/standalone/standalone_env.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service_locator.h>
+#include <service/locator/standalone/services/crypto/crypto_service_context.h>
+#include "standalone_location_strategy.h"
+#include "standalone_service_registry.h"
+
+void service_locator_envinit(void)
+{
+ static crypto_service_context crypto_context("sn:trustedfirmware.org:crypto:0");
+ standalone_service_registry::instance()->regsiter_service_instance(&crypto_context);
+ service_locator_register_strategy(standalone_location_strategy());
+} \ No newline at end of file
diff --git a/components/service/locator/standalone/standalone_location_strategy.cpp b/components/service/locator/standalone/standalone_location_strategy.cpp
new file mode 100644
index 0000000..57e370c
--- /dev/null
+++ b/components/service/locator/standalone/standalone_location_strategy.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "standalone_location_strategy.h"
+#include "standalone_service_registry.h"
+#include "standalone_service_context.h"
+
+static struct service_context *query(const char *sn, int *status)
+{
+ struct service_context *result = NULL;
+ standalone_service_registry *registry = standalone_service_registry::instance();
+ standalone_service_context *query_result = registry->query(sn, status);
+
+ if (query_result) {
+
+ result = query_result->get_service_context();
+ }
+
+ return result;
+}
+
+const struct service_location_strategy *standalone_location_strategy(void)
+{
+ static const struct service_location_strategy strategy = { query };
+ return &strategy;
+}
diff --git a/components/service/locator/standalone/standalone_location_strategy.h b/components/service/locator/standalone/standalone_location_strategy.h
new file mode 100644
index 0000000..7ea57ea
--- /dev/null
+++ b/components/service/locator/standalone/standalone_location_strategy.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_LOCATION_STRATEGY_H
+#define STANDALONE_LOCATION_STRATEGY_H
+
+#include <service_locator.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Returns a service_location_strategy for locating a service instance
+ * from a bundle of standalone service instances that are part of the
+ * client execution context.
+ */
+const struct service_location_strategy *standalone_location_strategy(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STANDALONE_LOCATION_STRATEGY_H */ \ No newline at end of file
diff --git a/components/service/locator/standalone/standalone_service_context.cpp b/components/service/locator/standalone/standalone_service_context.cpp
new file mode 100644
index 0000000..5e53ebe
--- /dev/null
+++ b/components/service/locator/standalone/standalone_service_context.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "standalone_service_context.h"
+#include <cassert>
+
+/* Concrete C service_context methods */
+static rpc_session_handle standalone_service_context_open(void *context, struct rpc_caller **caller);
+static void standalone_service_context_close(void *context, rpc_session_handle session_handle);
+static void standalone_service_context_relinquish(void *context);
+
+
+standalone_service_context::standalone_service_context(const char *sn) :
+ m_sn(sn),
+ m_ref_count(0),
+ m_service_context(),
+ m_call_ep(NULL)
+{
+ m_service_context.context = this;
+ m_service_context.open = standalone_service_context_open;
+ m_service_context.close = standalone_service_context_close;
+ m_service_context.relinquish = standalone_service_context_relinquish;
+}
+
+standalone_service_context::~standalone_service_context()
+{
+
+}
+
+void standalone_service_context::init()
+{
+ assert(m_ref_count >= 0);
+
+ if (!m_ref_count) do_init();
+ ++m_ref_count;
+}
+
+void standalone_service_context::deinit()
+{
+ assert(m_ref_count > 0);
+
+ --m_ref_count;
+ if (!m_ref_count) do_deinit();
+}
+
+rpc_session_handle standalone_service_context::open(struct rpc_caller **caller)
+{
+ struct rpc_session *session = new rpc_session(m_call_ep);
+ *caller = session->m_rpc_caller;
+ return static_cast<rpc_session_handle>(session);
+}
+
+void standalone_service_context::close(rpc_session_handle session_handle)
+{
+ struct rpc_session *session = reinterpret_cast<struct rpc_session*>(session_handle);
+ delete session;
+}
+
+const std::string &standalone_service_context::get_service_name() const
+{
+ return m_sn;
+}
+
+struct service_context *standalone_service_context::get_service_context()
+{
+ return &m_service_context;
+}
+
+void standalone_service_context::set_call_ep(call_ep *ep)
+{
+ m_call_ep = ep;
+}
+
+standalone_service_context::rpc_session::rpc_session(struct call_ep *call_ep) :
+ m_direct_caller(),
+ m_rpc_caller()
+{
+ m_rpc_caller = direct_caller_init_default(&m_direct_caller, call_ep);
+}
+
+standalone_service_context::rpc_session::~rpc_session()
+{
+ direct_caller_deinit(&m_direct_caller);
+}
+
+static rpc_session_handle standalone_service_context_open(void *context, struct rpc_caller **caller)
+{
+ rpc_session_handle handle = NULL;
+ standalone_service_context *this_context = reinterpret_cast<standalone_service_context*>(context);
+
+ if (this_context) {
+ handle = this_context->open(caller);
+ }
+
+ return handle;
+}
+
+static void standalone_service_context_close(void *context, rpc_session_handle session_handle)
+{
+ standalone_service_context *this_context = reinterpret_cast<standalone_service_context*>(context);
+
+ if (this_context) {
+ this_context->close(session_handle);
+ }
+}
+
+static void standalone_service_context_relinquish(void *context)
+{
+ standalone_service_context *this_context = reinterpret_cast<standalone_service_context*>(context);
+
+ if (this_context) {
+ this_context->deinit();
+ }
+}
diff --git a/components/service/locator/standalone/standalone_service_context.h b/components/service/locator/standalone/standalone_service_context.h
new file mode 100644
index 0000000..d8ebb1f
--- /dev/null
+++ b/components/service/locator/standalone/standalone_service_context.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_SERVICE_CONTEXT_H
+#define STANDALONE_SERVICE_CONTEXT_H
+
+#include <service_locator.h>
+#include <rpc/common/endpoint/call_ep.h>
+#include <rpc/direct/direct_caller.h>
+#include <string>
+
+class standalone_service_context
+{
+public:
+ standalone_service_context(const char *sn);
+ virtual ~standalone_service_context();
+
+ void init();
+ void deinit();
+
+ rpc_session_handle open(struct rpc_caller **caller);
+ void close(rpc_session_handle session_handle);
+
+ const std::string &get_service_name() const;
+ struct service_context *get_service_context();
+
+protected:
+ void set_call_ep(call_ep *ep);
+
+ virtual void do_init() {}
+ virtual void do_deinit() {}
+
+private:
+
+ struct rpc_session
+ {
+ rpc_session(struct call_ep *call_ep);
+ ~rpc_session();
+
+ struct direct_caller m_direct_caller;
+ struct rpc_caller *m_rpc_caller;
+ };
+
+ std::string m_sn;
+ int m_ref_count;
+ struct service_context m_service_context;
+ struct call_ep *m_call_ep;
+};
+
+#endif /* STANDALONE_SERVICE_CONTEXT_H */
diff --git a/components/service/locator/standalone/standalone_service_registry.cpp b/components/service/locator/standalone/standalone_service_registry.cpp
new file mode 100644
index 0000000..5625bc0
--- /dev/null
+++ b/components/service/locator/standalone/standalone_service_registry.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "standalone_service_registry.h"
+
+standalone_service_registry::standalone_service_registry() :
+ m_service_instances()
+{
+
+}
+
+standalone_service_registry::~standalone_service_registry()
+{
+
+}
+
+standalone_service_registry *standalone_service_registry::instance()
+{
+ static standalone_service_registry singleton_instance;
+ return &singleton_instance;
+}
+
+void standalone_service_registry::regsiter_service_instance(standalone_service_context *service_context)
+{
+ size_t index;
+
+ if (find_context_index(service_context->get_service_name().c_str(), &index)) {
+
+ m_service_instances[index] = service_context;
+ }
+ else {
+
+ m_service_instances.push_back(service_context);
+ }
+}
+
+standalone_service_context *standalone_service_registry::deregsiter_service_instance(const char *sn)
+{
+ size_t index;
+ standalone_service_context *context = NULL;
+
+ if (find_context_index(sn, &index)) {
+
+ context = m_service_instances[index];
+ m_service_instances.erase(m_service_instances.begin() + index);
+ }
+
+ return context;
+}
+
+standalone_service_context *standalone_service_registry::query(const char *sn, int *status)
+{
+ size_t index;
+ standalone_service_context *context = NULL;
+ (void)status;
+
+ if (find_context_index(sn, &index)) {
+
+ context = m_service_instances[index];
+ context->init();
+ }
+
+ return context;
+}
+
+bool standalone_service_registry::find_context_index(const char *sn, size_t *index) const
+{
+ bool found = false;
+
+ for (size_t i = 0; !found && i < m_service_instances.size(); i++) {
+
+ if (m_service_instances[i]->get_service_name().compare(sn) == 0) {
+
+ *index = i;
+ found = true;
+ }
+ }
+
+ return found;
+} \ No newline at end of file
diff --git a/components/service/locator/standalone/standalone_service_registry.h b/components/service/locator/standalone/standalone_service_registry.h
new file mode 100644
index 0000000..7a76aeb
--- /dev/null
+++ b/components/service/locator/standalone/standalone_service_registry.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STANDALONE_SERVICE_REGISTRY_H
+#define STANDALONE_SERVICE_REGISTRY_H
+
+#include "standalone_service_context.h"
+#include <vector>
+
+/*
+ * The standalone_service_registry supports a set of standalone
+ * service instances that are deployed as part of a standalone exectable
+ * or library. A standalone deployment of service providers should only
+ * be used for test and development. Because service provider instances
+ * are running within the same execution context as the client, a
+ * standalone deployment offers no isolation from the client.
+ */
+class standalone_service_registry
+{
+public:
+ standalone_service_registry();
+ virtual ~standalone_service_registry();
+
+ static standalone_service_registry *instance();
+
+ void regsiter_service_instance(standalone_service_context *service_context);
+ standalone_service_context *deregsiter_service_instance(const char *sn);
+
+ standalone_service_context *query(const char *sn, int *status);
+
+private:
+ bool find_context_index(const char *sn, size_t *index) const;
+
+ std::vector<standalone_service_context*> m_service_instances;
+};
+
+#endif /* STANDALONE_SERVICE_REGISTRY_H */ \ No newline at end of file
diff --git a/components/service/locator/test/component.cmake b/components/service/locator/test/component.cmake
new file mode 100644
index 0000000..04e98f3
--- /dev/null
+++ b/components/service/locator/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020, 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}/sn_tests.cpp"
+ )
diff --git a/components/service/locator/test/sn_tests.cpp b/components/service/locator/test/sn_tests.cpp
new file mode 100644
index 0000000..4f8630a
--- /dev/null
+++ b/components/service/locator/test/sn_tests.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service/locator/service_name.h>
+#include <CppUTest/TestHarness.h>
+#include <common/uuid/uuid.h>
+#include <string.h>
+
+TEST_GROUP(ServiceNameTests) {
+
+};
+
+TEST(ServiceNameTests, checkValidServiceNames) {
+
+ const char *sn1 = "sn:trustedfirmware.org:crypto:0";
+ CHECK(sn_is_valid(sn1));
+
+ const char *sn2 = "sn:trustedfirmware.org:secure-storage.1.0:0";
+ CHECK(sn_is_valid(sn2));
+
+ const char *sn3 = "urn:sn:trustedfirmware.org:tpm:3";
+ CHECK(sn_is_valid(sn3));
+
+ const char *sn4 = "sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0:0";
+ CHECK(sn_is_valid(sn4));
+
+ const char *sn5 = "sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ CHECK(sn_is_valid(sn5));
+}
+
+TEST(ServiceNameTests, checkInvalidServiceNames) {
+
+ const char *sn1 = "sn:trustedfirmware.org";
+ CHECK(!sn_is_valid(sn1));
+
+ const char *sn2 = "trustedfirmware.org:secure-storage.1.0:0";
+ CHECK(!sn_is_valid(sn2));
+}
+
+TEST(ServiceNameTests, checkFields) {
+
+ const char *sn1 = "sn:trustedfirmware.org:crypto:2";
+ CHECK(sn_check_authority(sn1, "trustedfirmware.org"));
+ CHECK(!sn_check_authority(sn1, "ffa"));
+ CHECK(sn_check_service(sn1, "crypto"));
+ CHECK_EQUAL(2, sn_get_service_instance(sn1));
+
+ const char *sn2 = "sn:trustedfirmware.org:secure-storage.1.0:0";
+ CHECK(sn_check_authority(sn2, "trustedfirmware.org"));
+ CHECK(sn_check_service(sn2, "secure-storage.1.0"));
+ CHECK(sn_check_service(sn2, "secure-storage"));
+ CHECK_EQUAL(0, sn_get_service_instance(sn2));
+
+ const char *sn3 = "sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0:7";
+ CHECK(sn_check_authority(sn3, "ffa"));
+ CHECK(sn_check_service(sn3, "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0"));
+ CHECK_EQUAL(7, sn_get_service_instance(sn3));
+
+ /* Check instance defaults to zero */
+ const char *sn4 = "sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ CHECK(sn_is_valid(sn4));
+ CHECK_EQUAL(0, sn_get_service_instance(sn4));
+}
+
+TEST(ServiceNameTests, readService) {
+
+ char buf[UUID_CANONICAL_FORM_LEN + 1];
+
+ const char *sn1 = "sn:trustedfirmware.org:crypto:2";
+ CHECK_EQUAL(strlen("crypto"), sn_read_service(sn1, buf, sizeof(buf)));
+ CHECK(memcmp(buf, "crypto", strlen("crypto") + 1) == 0);
+ CHECK_EQUAL(strlen("crypto"), strlen(buf));
+
+ const char *sn2 = "sn:trustedfirmware.org:crypto.1.7.0:2";
+ CHECK_EQUAL(strlen("crypto.1.7.0"), sn_read_service(sn2, buf, sizeof(buf)));
+ CHECK(memcmp(buf, "crypto.1.7.0", strlen("crypto.1.7.0") + 1) == 0);
+ CHECK_EQUAL(strlen("crypto.1.7.0"), strlen(buf));
+
+ const char *sn3 = "sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0:7";
+ CHECK_EQUAL(UUID_CANONICAL_FORM_LEN, sn_read_service(sn3, buf, sizeof(buf)));
+ CHECK(memcmp(buf, "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0", UUID_CANONICAL_FORM_LEN + 1) == 0);
+ CHECK_EQUAL(UUID_CANONICAL_FORM_LEN, strlen(buf));
+
+ const char *sn4 = "sn:ffa:d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0";
+ CHECK_EQUAL(UUID_CANONICAL_FORM_LEN, sn_read_service(sn4, buf, sizeof(buf)));
+ CHECK(memcmp(buf, "d9df52d5-16a2-4bb2-9aa4-d26d3b84e8c0", UUID_CANONICAL_FORM_LEN + 1) == 0);
+ CHECK_EQUAL(UUID_CANONICAL_FORM_LEN, strlen(buf));
+} \ No newline at end of file