Add null_block_store component

A block_store that actually has no storage. Writes are ignored and
read blocks return all zeros. Can be used as a placeholder during
integration.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I25fa2b56cfa5a87a782aa2d2d730f1095eeedaca
diff --git a/components/service/block_storage/block_store/device/null/component.cmake b/components/service/block_storage/block_store/device/null/component.cmake
new file mode 100644
index 0000000..50a102c
--- /dev/null
+++ b/components/service/block_storage/block_store/device/null/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}/null_block_store.c"
+	)
diff --git a/components/service/block_storage/block_store/device/null/null_block_store.c b/components/service/block_storage/block_store/device/null/null_block_store.c
new file mode 100644
index 0000000..3b0ad2e
--- /dev/null
+++ b/components/service/block_storage/block_store/device/null/null_block_store.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+#include "null_block_store.h"
+
+static psa_status_t null_block_store_get_partition_info(void *context,
+	const struct uuid_octets *partition_guid,
+	struct storage_partition_info *info)
+{
+	struct null_block_store *null_block_store = (struct null_block_store*)context;
+	return block_device_get_partition_info(
+		&null_block_store->base_block_device, partition_guid, info);
+}
+
+static psa_status_t null_block_store_open(void *context,
+	uint32_t client_id,
+	const struct uuid_octets *partition_guid,
+	storage_partition_handle_t *handle)
+{
+	struct null_block_store *null_block_store = (struct null_block_store*)context;
+	return block_device_open(
+		&null_block_store->base_block_device, client_id, partition_guid, handle);
+}
+
+static psa_status_t null_block_store_close(void *context,
+	uint32_t client_id,
+	storage_partition_handle_t handle)
+{
+	struct null_block_store *null_block_store = (struct null_block_store*)context;
+	return block_device_close(
+		&null_block_store->base_block_device, client_id, handle);
+}
+
+static psa_status_t null_block_store_read(void *context,
+	uint32_t client_id,
+	storage_partition_handle_t handle,
+	uint32_t lba,
+	size_t offset,
+	size_t buffer_size,
+	uint8_t *buffer,
+	size_t *data_len)
+{
+	const struct null_block_store *null_block_store = (struct null_block_store*)context;
+	psa_status_t status = block_device_check_access_permitted(
+		&null_block_store->base_block_device, client_id, handle);
+
+	if (status == PSA_SUCCESS) {
+
+		const struct storage_partition *storage_partition =
+			&null_block_store->base_block_device.storage_partition;
+
+		if (storage_partition_is_lba_legal(storage_partition, lba) &&
+			(offset < storage_partition->block_size)) {
+
+			/* Just real zeros */
+			size_t bytes_remaining = storage_partition->block_size - offset;
+			size_t bytes_to_read = (buffer_size < bytes_remaining) ?
+				buffer_size :
+				bytes_remaining;
+
+			memset(buffer, 0, bytes_to_read);
+			*data_len = bytes_to_read;
+		}
+		else {
+
+			status = PSA_ERROR_INVALID_ARGUMENT;
+		}
+	}
+
+	return status;
+}
+
+static psa_status_t null_block_store_write(void *context,
+	uint32_t client_id,
+	storage_partition_handle_t handle,
+	uint32_t lba,
+	size_t offset,
+	const uint8_t *data,
+	size_t data_len,
+	size_t *num_written)
+{
+	struct null_block_store *null_block_store = (struct null_block_store*)context;
+	psa_status_t status = block_device_check_access_permitted(
+		&null_block_store->base_block_device, client_id, handle);
+
+	if (status == PSA_SUCCESS) {
+
+		const struct storage_partition *storage_partition =
+			&null_block_store->base_block_device.storage_partition;
+
+		if (storage_partition_is_lba_legal(storage_partition, lba) &&
+			(offset < storage_partition->block_size)) {
+
+			/* Don't actually write anything */
+			size_t bytes_remaining = storage_partition->block_size - offset;
+			size_t bytes_to_write = (data_len < bytes_remaining) ?
+				data_len :
+				bytes_remaining;
+
+			*num_written = bytes_to_write;
+		}
+		else {
+
+			status = PSA_ERROR_INVALID_ARGUMENT;
+		}
+	}
+
+	return status;
+}
+
+static psa_status_t null_block_store_erase(void *context,
+	uint32_t client_id,
+	storage_partition_handle_t handle,
+	uint32_t begin_lba,
+	size_t num_blocks)
+{
+	struct null_block_store *null_block_store = (struct null_block_store*)context;
+	const struct storage_partition *storage_partition =
+		&null_block_store->base_block_device.storage_partition;
+	psa_status_t status = block_device_check_access_permitted(
+		&null_block_store->base_block_device, client_id, handle);
+
+	/* Sanitize the erase starting point */
+	if ((status == PSA_SUCCESS) &&
+		!storage_partition_is_lba_legal(storage_partition, begin_lba))
+			status = PSA_ERROR_INVALID_ARGUMENT;
+
+	/* Do nothing */
+
+	return status;
+}
+
+struct block_store *null_block_store_init(
+	struct null_block_store *null_block_store,
+	const struct uuid_octets *disk_guid,
+	size_t num_blocks,
+	size_t block_size)
+{
+	/* Define concrete block store interface */
+	static const struct block_store_interface interface =
+	{
+		null_block_store_get_partition_info,
+		null_block_store_open,
+		null_block_store_close,
+		null_block_store_read,
+		null_block_store_write,
+		null_block_store_erase
+	};
+
+	/* Initialize base block_store */
+	null_block_store->base_block_device.base_block_store.context = null_block_store;
+	null_block_store->base_block_device.base_block_store.interface = &interface;
+
+	return block_device_init(
+			&null_block_store->base_block_device, disk_guid, num_blocks, block_size);
+}
+
+void null_block_store_deinit(
+	struct null_block_store *null_block_store)
+{
+	block_device_deinit(&null_block_store->base_block_device);
+}
diff --git a/components/service/block_storage/block_store/device/null/null_block_store.h b/components/service/block_storage/block_store/device/null/null_block_store.h
new file mode 100644
index 0000000..8c4e843
--- /dev/null
+++ b/components/service/block_storage/block_store/device/null/null_block_store.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef NULL_BLOCK_STORE_H
+#define NULL_BLOCK_STORE_H
+
+#include "service/block_storage/block_store/device/block_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief null_block_store structure
+ *
+ * A null_block_store is a block_device that will ignore write operations and
+ * always return zero for read blocks. Because there is no storage, a null_block_store
+ * can be any size and support any block size. It is intended to be used as a placeholder
+ * block device during integration.
+ */
+struct null_block_store
+{
+	struct block_device base_block_device;
+};
+
+/**
+ * \brief Initialize a null_block_store
+ *
+ * \param[in]  null_block_store  The subject null_block_store
+ * \param[in]  disk_guid   		The disk GUID (nil uuid for any)
+ * \param[in]  num_blocks       The number of contiguous blocks
+ * \param[in]  block_size       Block size in bytes
+ *
+ * \return Pointer to block_store or NULL on failure
+ */
+struct block_store *null_block_store_init(
+	struct null_block_store *null_block_store,
+	const struct uuid_octets *disk_guid,
+	size_t num_blocks,
+	size_t block_size);
+
+/**
+ * \brief De-initialize a null_block_store
+ *
+ * \param[in]  null_block_store  The subject null_block_store
+ */
+void null_block_store_deinit(
+	struct null_block_store *null_block_store);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NULL_BLOCK_STORE_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index c1b0317..a1be1dd 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -80,6 +80,7 @@
 		"components/service/block_storage/block_store/device"
 		"components/service/block_storage/block_store/device/ram"
 		"components/service/block_storage/block_store/device/ram/test"
+		"components/service/block_storage/block_store/device/null"
 		"components/service/block_storage/block_store/partitioned"
 		"components/service/block_storage/block_store/partitioned/test"
 		"components/service/crypto/client/cpp"