Introduce block_store factory

To allow for reuse of code concerned with constructing different
block_store stacks, a factory directory is added for different
factories to live. Two factories have been added so far: the
ref_ram factory constructs a ram-backed block store, partitioned
using the reference partition configuration expected by test cases.
The client factory constructs a block_storage_client that talks to
a remote block storage service provider.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ib4c02f12a0742fc9b75143de612dd273f2bfffa9
diff --git a/components/service/block_storage/factory/block_store_factory.h b/components/service/block_storage/factory/block_store_factory.h
new file mode 100644
index 0000000..a45f517
--- /dev/null
+++ b/components/service/block_storage/factory/block_store_factory.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef BLOCK_STORE_FACTORY_H
+#define BLOCK_STORE_FACTORY_H
+
+#include <util.h>
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Defines a common interface for constructing the block_store
+ * stack needed for a deployment. The concrete factory will depend
+ * on which factory component has been deployed. This interface
+ * is only intended to be used where only one type block store
+ * factory is needed in a deployment. This ifdef allows multiple
+ * block_store factory methods to be combined within a single build,
+ * each with a distinct function name. This is needed for some test
+ * deployments where different block_store stacks are constructed
+ * for different test cases.
+ */
+#ifdef CONCRETE_BLOCK_STORE_FACTORY
+
+#define BLOCK_STORE_FACTORY_FUNC_CREATE CONCAT(CONCRETE_BLOCK_STORE_FACTORY, _create)
+#define BLOCK_STORE_FACTORY_FUNC_DESTROY CONCAT(CONCRETE_BLOCK_STORE_FACTORY, _destroy)
+
+struct block_store *BLOCK_STORE_FACTORY_FUNC_CREATE(void);
+void BLOCK_STORE_FACTORY_FUNC_DESTROY(struct block_store *block_store);
+
+#endif
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+static inline struct block_store *block_store_factory_create(void)
+{
+#ifdef CONCRETE_BLOCK_STORE_FACTORY
+	return BLOCK_STORE_FACTORY_FUNC_CREATE();
+#else
+	#error No concrete block store factory
+#endif
+}
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store    The block store to destroy
+ */
+static inline void block_store_factory_destroy(struct block_store *block_store)
+{
+#ifdef CONCRETE_BLOCK_STORE_FACTORY
+	return BLOCK_STORE_FACTORY_FUNC_DESTROY(block_store);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/client/block_store_factory.c b/components/service/block_storage/factory/client/block_store_factory.c
new file mode 100644
index 0000000..c84faef
--- /dev/null
+++ b/components/service/block_storage/factory/client/block_store_factory.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "service/block_storage/block_store/client/block_storage_client.h"
+#include "protocols/rpc/common/packed-c/encoding.h"
+#include "service_locator.h"
+
+struct block_store_assembly {
+	struct block_storage_client client;
+	rpc_session_handle rpc_session_handle;
+	struct service_context *service_context;
+};
+
+struct block_store *client_block_store_factory_create(const char *sn)
+{
+	struct block_store *product = NULL;
+	struct block_store_assembly *assembly =
+		(struct block_store_assembly *)calloc(1, sizeof(struct block_store_assembly));
+
+	if (assembly) {
+
+		int status;
+
+		assembly->rpc_session_handle = NULL;
+		assembly->service_context = NULL;
+
+		service_locator_init();
+
+		assembly->service_context = service_locator_query(sn, &status);
+
+		if (assembly->service_context) {
+
+			struct rpc_caller *caller;
+
+			assembly->rpc_session_handle = service_context_open(
+				assembly->service_context,
+				TS_RPC_ENCODING_PACKED_C,
+				&caller);
+
+			if (assembly->rpc_session_handle)
+				product = block_storage_client_init(&assembly->client, caller);
+		}
+
+		if (!product) {
+
+			/* Something went wrong! */
+			free(assembly);
+		}
+	}
+
+	return product;
+}
+
+void client_block_store_factory_destroy(struct block_store *block_store)
+{
+	if (block_store) {
+
+		size_t offset_into_assembly =
+			offsetof(struct block_store_assembly, client) +
+			offsetof(struct block_storage_client, base_block_store);
+
+		struct block_store_assembly *assembly = (struct block_store_assembly *)
+			((uint8_t *)block_store - offset_into_assembly);
+
+		block_storage_client_deinit(&assembly->client);
+
+		if (assembly->service_context) {
+
+			if (assembly->rpc_session_handle) {
+				service_context_close(
+					assembly->service_context, assembly->rpc_session_handle);
+				assembly->rpc_session_handle = NULL;
+			}
+
+			service_context_relinquish(assembly->service_context);
+			assembly->service_context = NULL;
+		}
+
+		free(assembly);
+	}
+}
diff --git a/components/service/block_storage/factory/client/block_store_factory.h b/components/service/block_storage/factory/client/block_store_factory.h
new file mode 100644
index 0000000..6feebf4
--- /dev/null
+++ b/components/service/block_storage/factory/client/block_store_factory.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CLIENT_BLOCK_STORE_FACTORY_H
+#define CLIENT_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a block_storage_client
+ * (which is a block_store specialization). The constructed client
+ * establishes a session with the discovered block storage service
+ * provider.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \param[in] sn    Service name identifying block storage provider
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *client_block_store_factory_create(const char *sn);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store    The block store to destroy
+ */
+void client_block_store_factory_destroy(struct block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CLIENT_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/client/component.cmake b/components/service/block_storage/factory/client/component.cmake
new file mode 100644
index 0000000..759da54
--- /dev/null
+++ b/components/service/block_storage/factory/client/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, 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}/block_store_factory.c"
+	)
diff --git a/components/service/block_storage/factory/ref_ram/block_store_factory.c b/components/service/block_storage/factory/ref_ram/block_store_factory.c
new file mode 100644
index 0000000..631a933
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram/block_store_factory.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "block_store_factory.h"
+#include "service/block_storage/block_store/device/ram/ram_block_store.h"
+#include "service/block_storage/block_store/partitioned/partitioned_block_store.h"
+#include "service/block_storage/config/ref/ref_partition_configurator.h"
+
+struct block_store_assembly {
+	struct ram_block_store ram_block_store;
+	struct partitioned_block_store partitioned_block_store;
+};
+
+struct block_store *ref_ram_block_store_factory_create(void)
+{
+	struct block_store *product = NULL;
+	struct block_store_assembly *assembly =
+		(struct block_store_assembly *)calloc(1, sizeof(struct block_store_assembly));
+
+	if (assembly) {
+
+		struct uuid_octets back_store_guid;
+
+		memset(&back_store_guid, 0, sizeof(back_store_guid));
+
+		/* Initialise a ram_block_store to provide underlying storage */
+		struct block_store *back_store = ram_block_store_init(
+			&assembly->ram_block_store,
+			&back_store_guid,
+			REF_PARTITION_BACK_STORE_SIZE,
+			REF_PARTITION_BLOCK_SIZE);
+
+		/* Stack a partitioned_block_store over the back store */
+		product = partitioned_block_store_init(
+			&assembly->partitioned_block_store,
+			0,
+			&back_store_guid,
+			back_store,
+			NULL);
+
+		/* Use the reference partition configuration */
+		ref_partition_configure(&assembly->partitioned_block_store);
+
+		if (!product) {
+
+			/* Something went wrong! */
+			free(assembly);
+		}
+	}
+
+	return product;
+}
+
+void ref_ram_block_store_factory_destroy(struct block_store *block_store)
+{
+	if (block_store) {
+
+		size_t offset_into_assembly =
+			offsetof(struct block_store_assembly, partitioned_block_store) +
+			offsetof(struct partitioned_block_store, base_block_store);
+
+		struct block_store_assembly *assembly = (struct block_store_assembly *)
+			((uint8_t *)block_store - offset_into_assembly);
+
+		partitioned_block_store_deinit(&assembly->partitioned_block_store);
+		ram_block_store_deinit(&assembly->ram_block_store);
+
+		free(assembly);
+	}
+}
diff --git a/components/service/block_storage/factory/ref_ram/block_store_factory.h b/components/service/block_storage/factory/ref_ram/block_store_factory.h
new file mode 100644
index 0000000..189d208
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram/block_store_factory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef REF_RAM_BLOCK_STORE_FACTORY_H
+#define REF_RAM_BLOCK_STORE_FACTORY_H
+
+#include "service/block_storage/block_store/block_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A block store factory that constructs a partitioned block store with
+ * a ram back store. The reference partition configuration is used to
+ * provide a set of storage partitions that match the expectations of
+ * test cases. This factory should only really be used for test deployments.
+ */
+
+/**
+ * \brief Factory method to create a block_store
+ *
+ * \return A pointer to the constructed block_store (NULL on failure)
+ */
+struct block_store *ref_ram_block_store_factory_create(void);
+
+/**
+ * \brief Destroys a block_store created with block_store_factory_create
+ *
+ * \param[in] block_store    The block store to destroy
+ */
+void ref_ram_block_store_factory_destroy(struct block_store *block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* REF_RAM_BLOCK_STORE_FACTORY_H */
diff --git a/components/service/block_storage/factory/ref_ram/component.cmake b/components/service/block_storage/factory/ref_ram/component.cmake
new file mode 100644
index 0000000..7277cb3
--- /dev/null
+++ b/components/service/block_storage/factory/ref_ram/component.cmake
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, 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}/block_store_factory.c"
+	)
+
+# If none already defined, make this the default factory for the deployment
+if (NOT DEFINED TS_BLOCK_STORE_FACTORY)
+	set(TS_BLOCK_STORE_FACTORY "ref_ram_block_store_factory")
+	target_compile_definitions(${TGT} PRIVATE
+		CONCRETE_BLOCK_STORE_FACTORY=${TS_BLOCK_STORE_FACTORY})
+endif()
\ No newline at end of file
diff --git a/components/service/block_storage/test/service/block_storage_service_tests.cpp b/components/service/block_storage/test/service/block_storage_service_tests.cpp
index c86f8a8..00521b9 100644
--- a/components/service/block_storage/test/service/block_storage_service_tests.cpp
+++ b/components/service/block_storage/test/service/block_storage_service_tests.cpp
@@ -6,10 +6,9 @@
 
 #include <cstring>
 #include "common/uuid/uuid.h"
-#include "service/block_storage/block_store/client/block_storage_client.h"
+#include "service/block_storage/block_store/block_store.h"
+#include "service/block_storage/factory/client/block_store_factory.h"
 #include "service/block_storage/config/ref/ref_partition_configurator.h"
-#include "protocols/rpc/common/packed-c/encoding.h"
-#include "service_locator.h"
 #include "CppUTest/TestHarness.h"
 
 /**
@@ -24,23 +23,9 @@
 {
 	void setup()
 	{
-		struct rpc_caller *caller;
-		int status;
+		m_block_store = client_block_store_factory_create(
+			"sn:trustedfirmware.org:block-storage:0");
 
-		m_rpc_session_handle = NULL;
-		m_service_context = NULL;
-
-		service_locator_init();
-
-		m_service_context =
-			service_locator_query("sn:trustedfirmware.org:block-storage:0", &status);
-		CHECK_TRUE(m_service_context);
-
-		m_rpc_session_handle =
-			service_context_open(m_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
-		CHECK_TRUE(m_rpc_session_handle);
-
-		m_block_store = block_storage_client_init(&m_client, caller);
 		CHECK_TRUE(m_block_store);
 
 		uuid_parse_to_octets(REF_PARTITION_1_GUID,
@@ -55,25 +40,11 @@
 
 	void teardown()
 	{
-		block_storage_client_deinit(&m_client);
-
-		if (m_service_context) {
-
-			if (m_rpc_session_handle) {
-				service_context_close(m_service_context, m_rpc_session_handle);
-				m_rpc_session_handle = NULL;
-			}
-
-			service_context_relinquish(m_service_context);
-			m_service_context = NULL;
-		}
+		client_block_store_factory_destroy(m_block_store);
 	}
 
 	static const uint32_t LOCAL_CLIENT_ID = 1;
 
-	rpc_session_handle m_rpc_session_handle;
-	struct service_context *m_service_context;
-	struct block_storage_client m_client;
 	struct block_store *m_block_store;
 	struct uuid_octets m_partition_1_guid;
 	struct uuid_octets m_partition_2_guid;
diff --git a/components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp b/components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp
index b105c08..2d1227d 100644
--- a/components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp
+++ b/components/service/locator/standalone/services/block-storage/block_storage_service_context.cpp
@@ -6,15 +6,14 @@
 
 #include <assert.h>
 #include <cstring>
-#include "service/block_storage/config/ref/ref_partition_configurator.h"
 #include "service/block_storage/provider/serializer/packed-c/packedc_block_storage_serializer.h"
+#include "service/block_storage/factory/ref_ram/block_store_factory.h"
 #include "block_storage_service_context.h"
 
 block_storage_service_context::block_storage_service_context(const char *sn) :
 	standalone_service_context(sn),
 	m_block_storage_provider(),
-	m_ram_block_store(),
-	m_partitioned_block_store()
+	m_block_store(NULL)
 {
 
 }
@@ -26,33 +25,14 @@
 
 void block_storage_service_context::do_init()
 {
-	/* Initialize a ram_block_store to use as the back store */
-	struct uuid_octets back_store_guid;
-	memset(&back_store_guid, 0, sizeof(back_store_guid));
-
-	struct block_store *back_store = ram_block_store_init(
-		&m_ram_block_store,
-		&back_store_guid,
-		REF_PARTITION_BACK_STORE_SIZE,
-		REF_PARTITION_BLOCK_SIZE);
-	assert(back_store);
-
-	/* Stack a partitioned_block_store over the back store */
-	struct block_store *front_store = partitioned_block_store_init(
-		&m_partitioned_block_store,
-		0,
-		&back_store_guid,
-		back_store,
-		NULL);
-	assert(front_store);
-
-	/* Use the reference partition configuration */
-	ref_partition_configure(&m_partitioned_block_store);
+	/* Create backend block store */
+	m_block_store = ref_ram_block_store_factory_create();
+	assert(m_block_store);
 
 	/* Initialise the block storage service provider */
 	struct rpc_interface *rpc_iface = block_storage_provider_init(
 		&m_block_storage_provider,
-		front_store);
+		m_block_store);
 	assert(rpc_iface);
 
 	block_storage_provider_register_serializer(
@@ -66,6 +46,5 @@
 void block_storage_service_context::do_deinit()
 {
 	block_storage_provider_deinit(&m_block_storage_provider);
-	partitioned_block_store_deinit(&m_partitioned_block_store);
-	ram_block_store_deinit(&m_ram_block_store);
+	ref_ram_block_store_factory_destroy(m_block_store);
 }
diff --git a/components/service/locator/standalone/services/block-storage/block_storage_service_context.h b/components/service/locator/standalone/services/block-storage/block_storage_service_context.h
index 81a03dd..c47aede 100644
--- a/components/service/locator/standalone/services/block-storage/block_storage_service_context.h
+++ b/components/service/locator/standalone/services/block-storage/block_storage_service_context.h
@@ -10,8 +10,7 @@
 #include <service/locator/standalone/standalone_service_context.h>
 #include <rpc/direct/direct_caller.h>
 #include <service/block_storage/provider/block_storage_provider.h>
-#include <service/block_storage/block_store/device/ram/ram_block_store.h>
-#include <service/block_storage/block_store/partitioned/partitioned_block_store.h>
+#include <service/block_storage/block_store/block_store.h>
 
 class block_storage_service_context : public standalone_service_context
 {
@@ -25,8 +24,7 @@
 	void do_deinit();
 
 	struct block_storage_provider m_block_storage_provider;
-	struct ram_block_store m_ram_block_store;
-	struct partitioned_block_store m_partitioned_block_store;
+	struct block_store *m_block_store;
 };
 
 #endif /* STANDALONE_BLOCK_STORAGE_SERVICE_CONTEXT_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index d5edf4f..ad67ad7 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -87,6 +87,7 @@
 		"components/service/block_storage/provider"
 		"components/service/block_storage/provider/serializer/packed-c"
 		"components/service/block_storage/config/ref"
+		"components/service/block_storage/factory/ref_ram"
 		"components/service/crypto/client/cpp"
 		"components/service/crypto/client/cpp/protocol/protobuf"
 		"components/service/crypto/client/cpp/protocol/packed-c"
diff --git a/deployments/libts/linux-pc/CMakeLists.txt b/deployments/libts/linux-pc/CMakeLists.txt
index e034e80..832983b 100644
--- a/deployments/libts/linux-pc/CMakeLists.txt
+++ b/deployments/libts/linux-pc/CMakeLists.txt
@@ -70,6 +70,7 @@
 		"components/service/block_storage/provider"
 		"components/service/block_storage/provider/serializer/packed-c"
 		"components/service/block_storage/config/ref"
+		"components/service/block_storage/factory/ref_ram"
 		"components/service/crypto/provider"
 		"components/service/crypto/provider/serializer/protobuf"
 		"components/service/crypto/provider/serializer/packed-c"
diff --git a/deployments/ts-service-test/linux-pc/CMakeLists.txt b/deployments/ts-service-test/linux-pc/CMakeLists.txt
index 2690dab..99c1db2 100644
--- a/deployments/ts-service-test/linux-pc/CMakeLists.txt
+++ b/deployments/ts-service-test/linux-pc/CMakeLists.txt
@@ -84,6 +84,7 @@
 		"components/service/smm_variable/test/service"
 		"components/service/block_storage/block_store"
 		"components/service/block_storage/block_store/client"
+		"components/service/block_storage/factory/client"
 		"components/service/block_storage/test/service"
 		"components/common/uuid"
 )