Add io device for block_store volume access

To enable tf-a components to access data from a block_store, an
io device is added that conforms to the tf-a model. The io device
presents a storage partition, accessed via a block_store, as a
single seekable volume. Any concrete block_store may be used with
this io device.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I3c8e9e198332d7c2601ccff03fa129ee164e5359
diff --git a/components/common/uuid/uuid.h b/components/common/uuid/uuid.h
index 1bc4e67..02d83b6 100644
--- a/components/common/uuid/uuid.h
+++ b/components/common/uuid/uuid.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef UUID_H
-#define UUID_H
+#ifndef COMMON_UUID_H
+#define COMMON_UUID_H
 
 #include <stddef.h>
 #include <stdint.h>
@@ -69,4 +69,4 @@
 }
 #endif
 
-#endif /* UUID_H */
+#endif /* COMMON_UUID_H */
diff --git a/components/media/volume/base_io_dev/base_io_dev.h b/components/media/volume/base_io_dev/base_io_dev.h
new file mode 100644
index 0000000..83fcb72
--- /dev/null
+++ b/components/media/volume/base_io_dev/base_io_dev.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_BASE_IO_DEV_H
+#define MEDIA_BASE_IO_DEV_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Base io_dev definition. An io_dev is a tf-a abstraction used for accessing
+ * an underlying storage volume as a single file with posix-like file I/O
+ * operations.
+ *
+ * Export tf-a version with C++ linkage support.
+ */
+#include <drivers/io/io_storage.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_BASE_IO_DEV_H */
diff --git a/components/media/volume/storage/component.cmake b/components/media/volume/base_io_dev/component.cmake
similarity index 84%
rename from components/media/volume/storage/component.cmake
rename to components/media/volume/base_io_dev/component.cmake
index 98f5c3a..a14b615 100644
--- a/components/media/volume/storage/component.cmake
+++ b/components/media/volume/base_io_dev/component.cmake
@@ -9,7 +9,8 @@
 endif()
 
 #-------------------------------------------------------------------------------
-# Depends on the tf-a external component
+# Depends on the tf-a external component. The base io_dev interface is realized
+# by the following tf-a files.
 #-------------------------------------------------------------------------------
 target_sources(${TGT} PRIVATE
 	"${TFA_SOURCE_DIR}/drivers/io/io_storage.c"
diff --git a/components/media/volume/block_io_dev/block_io_dev.c b/components/media/volume/block_io_dev/block_io_dev.c
new file mode 100644
index 0000000..18bd003
--- /dev/null
+++ b/components/media/volume/block_io_dev/block_io_dev.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <drivers/io/io_storage.h>
+#include "block_io_dev.h"
+
+/* Concrete io_dev interface functions */
+static io_type_t block_io_dev_type(
+	void);
+static int block_io_dev_open(
+	io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity);
+static int block_io_dev_close(
+	io_entity_t *entity);
+static int block_io_dev_seek(
+	io_entity_t *entity, int mode, signed long long offset);
+static int block_io_dev_size(
+	io_entity_t *entity, size_t *length);
+static int block_io_dev_read(
+	io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read);
+static int block_io_dev_write(
+	io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written);
+
+static const io_dev_funcs_t block_io_dev_dev_funcs = {
+	.type		= block_io_dev_type,
+	.open		= block_io_dev_open,
+	.seek		= block_io_dev_seek,
+	.size		= block_io_dev_size,
+	.read		= block_io_dev_read,
+	.write		= block_io_dev_write,
+	.close		= block_io_dev_close,
+	.dev_init	= NULL,
+	.dev_close	= NULL
+};
+
+
+int block_io_dev_init(
+	struct block_io_dev *this_instance,
+	struct block_store *block_store,
+	const struct uuid_octets *partition_guid,
+	uintptr_t *dev_handle,
+	uintptr_t *spec)
+{
+	this_instance->block_store = block_store;
+	this_instance->partition_guid = *partition_guid;
+
+	this_instance->file_pos = 0;
+	this_instance->size = 0;
+	this_instance->partition_handle = 0;
+
+	this_instance->partition_info.block_size = 0;
+	this_instance->partition_info.num_blocks = 0;
+
+	this_instance->dev_info.funcs = &block_io_dev_dev_funcs;
+	this_instance->dev_info.info = (uintptr_t)this_instance;
+
+	*dev_handle = (uintptr_t)&this_instance->dev_info;
+	*spec = (uintptr_t)this_instance;
+
+	return 0;
+}
+
+void block_io_dev_deinit(
+	struct block_io_dev *this_instance)
+{
+	(void)this_instance;
+}
+
+void block_io_dev_set_partition_guid(
+	struct block_io_dev *this_instance,
+	const struct uuid_octets *partition_guid)
+{
+	this_instance->partition_guid = *partition_guid;
+}
+
+static io_type_t block_io_dev_type(void)
+{
+	return IO_TYPE_BLOCK;
+}
+
+static int block_io_dev_open(
+	io_dev_info_t *dev_info,
+	const uintptr_t spec,
+	io_entity_t *entity)
+{
+	struct block_io_dev *this_instance = (struct block_io_dev*)dev_info->info;
+	psa_status_t psa_status = PSA_ERROR_BAD_STATE;
+
+	psa_status = block_store_get_partition_info(this_instance->block_store,
+		&this_instance->partition_guid,
+		&this_instance->partition_info);
+
+	if (psa_status == PSA_SUCCESS) {
+
+		this_instance->file_pos = 0;
+		this_instance->size =
+			this_instance->partition_info.block_size * this_instance->partition_info.num_blocks;
+
+		psa_status = block_store_open(this_instance->block_store, 0,
+			&this_instance->partition_guid,
+			&this_instance->partition_handle);
+
+		entity->info = (uintptr_t)this_instance;
+	}
+
+	return (psa_status == PSA_SUCCESS) ? 0 : -EPERM;
+}
+
+static int block_io_dev_close(
+	io_entity_t *entity)
+{
+	struct block_io_dev *this_instance = (struct block_io_dev*)entity->info;
+
+	psa_status_t psa_status = block_store_close(this_instance->block_store, 0,
+		this_instance->partition_handle);
+
+	if (psa_status == PSA_SUCCESS) {
+
+		this_instance->file_pos = 0;
+		this_instance->size = 0;
+	}
+
+	return (psa_status == PSA_SUCCESS) ? 0 : -ENXIO;
+}
+
+static int block_io_dev_seek(
+	io_entity_t *entity,
+	int mode,
+	signed long long offset)
+{
+	struct block_io_dev *this_instance = (struct block_io_dev*)entity->info;
+
+	switch (mode)
+	{
+		case IO_SEEK_SET:
+		{
+			if (offset <= this_instance->size)
+				this_instance->file_pos = (size_t)offset;
+			else
+				return -EINVAL;
+			break;
+		}
+		case IO_SEEK_CUR:
+		{
+			ssize_t target_pos = this_instance->file_pos + offset;
+			if ((target_pos >= 0) && (target_pos <= this_instance->size))
+				this_instance->file_pos = (size_t)target_pos;
+			else
+				return -EINVAL;
+			break;
+		}
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int block_io_dev_size(
+	io_entity_t *entity,
+	size_t *length)
+{
+	struct block_io_dev *this_instance = (struct block_io_dev*)entity->info;
+	*length = this_instance->size;
+	return 0;
+}
+
+static int block_io_dev_read(
+	io_entity_t *entity,
+	uintptr_t buffer,
+	size_t length,
+	size_t *length_read)
+{
+	struct block_io_dev *this_instance = (struct block_io_dev*)entity->info;
+	size_t bytes_read = 0;
+	*length_read = 0;
+
+	if (!this_instance->partition_info.block_size)
+		return -EIO;
+
+	while ((bytes_read < length) && (this_instance->file_pos < this_instance->size)) {
+
+		uint32_t lba = this_instance->file_pos / this_instance->partition_info.block_size;
+		size_t offset = this_instance->file_pos % this_instance->partition_info.block_size;
+
+		size_t bytes_remaining_in_block = this_instance->partition_info.block_size - offset;
+		size_t bytes_remaining_in_file = this_instance->size - this_instance->file_pos;
+
+		size_t bytes_remaining = length - bytes_read;
+		if (bytes_remaining > bytes_remaining_in_file) bytes_remaining = bytes_remaining_in_file;
+
+		size_t requested_len = (bytes_remaining < bytes_remaining_in_block) ?
+			bytes_remaining : bytes_remaining_in_block;
+		size_t actual_len = 0;
+
+		psa_status_t psa_status = block_store_read(
+			this_instance->block_store, 0,
+			this_instance->partition_handle,
+			lba, offset,
+			requested_len,
+			(uint8_t*)(buffer + bytes_read),
+			&actual_len);
+
+		if (psa_status != PSA_SUCCESS)
+			return -EIO;
+
+		bytes_read += actual_len;
+		this_instance->file_pos += actual_len;
+	}
+
+	*length_read = bytes_read;
+	return 0;
+}
+
+static int block_io_dev_write(
+	io_entity_t *entity,
+	const uintptr_t buffer,
+	size_t length,
+	size_t *length_written)
+{
+	struct block_io_dev *this_instance = (struct block_io_dev*)entity->info;
+	size_t bytes_written = 0;
+	*length_written = 0;
+
+	if (!this_instance->partition_info.block_size)
+		return -EIO;
+
+	while ((bytes_written < length) && (this_instance->file_pos < this_instance->size)) {
+
+		uint32_t lba = this_instance->file_pos / this_instance->partition_info.block_size;
+		size_t offset = this_instance->file_pos % this_instance->partition_info.block_size;
+
+		size_t bytes_remaining_in_block = this_instance->partition_info.block_size - offset;
+		size_t bytes_remaining_in_file = this_instance->size - this_instance->file_pos;
+
+		size_t bytes_remaining = length - bytes_written;
+		if (bytes_remaining > bytes_remaining_in_file) bytes_remaining = bytes_remaining_in_file;
+
+		size_t requested_len = (bytes_remaining < bytes_remaining_in_block) ?
+			bytes_remaining : bytes_remaining_in_block;
+		size_t actual_len = 0;
+
+		psa_status_t psa_status = block_store_write(
+			this_instance->block_store, 0,
+			this_instance->partition_handle,
+			lba, offset,
+			(uint8_t*)(buffer + bytes_written),
+			requested_len,
+			&actual_len);
+
+		if (psa_status != PSA_SUCCESS)
+			return -EIO;
+
+		bytes_written += actual_len;
+		this_instance->file_pos += actual_len;
+	}
+
+	*length_written = bytes_written;
+	return 0;
+}
diff --git a/components/media/volume/block_io_dev/block_io_dev.h b/components/media/volume/block_io_dev/block_io_dev.h
new file mode 100644
index 0000000..37c91ed
--- /dev/null
+++ b/components/media/volume/block_io_dev/block_io_dev.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEDIA_BLOCK_IO_DEV_H
+#define MEDIA_BLOCK_IO_DEV_H
+
+#include <common/uuid/uuid.h>
+#include <service/block_storage/block_store/block_store.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Export tf-a version with C++ linkage support.
+ */
+#include <drivers/io/io_driver.h>
+
+/**
+ * Provides a tf-a compatible io device that presents a block storage partition
+ * as a single volume. Access to the underlying storage is handled by an associated
+ * block_store. The block_store could be any concrete block_store.
+ */
+struct block_io_dev
+{
+	io_dev_info_t dev_info;
+	size_t file_pos;
+	size_t size;
+	struct block_store *block_store;
+	struct uuid_octets partition_guid;
+	storage_partition_handle_t partition_handle;
+	struct storage_partition_info partition_info;
+};
+
+/**
+ * @brief  Initialize an block_io_dev instance
+ *
+ * @param[in] this_instance    The subject block_io_dev
+ * @param[in] block_store      The associated block_store
+ * @param[in] partition_guid   The partition GUID
+ * @param[out] dev_handle	   Device handle used by tf-a components
+ * @param[out] spec			   Spec passed on io_open
+ *
+ * @return 0 on success
+ */
+int block_io_dev_init(
+	struct block_io_dev *this_instance,
+	struct block_store *block_store,
+	const struct uuid_octets *partition_guid,
+	uintptr_t *dev_handle,
+	uintptr_t *spec);
+
+/**
+ * @brief  De-initialize an block_io_dev instance
+ *
+ * @param[in] this_instance    The subject block_io_dev
+ */
+void block_io_dev_deinit(
+	struct block_io_dev *this_instance);
+
+/**
+ * @brief  Set the partition GUID
+ *
+ * Modifies the partition GUID. This will be used to identify the target
+ * storage partition on a subsequent call to io_dev_open.
+ *
+ * @param[in] this_instance    The subject block_io_dev
+ * @param[in] partition_guid   The partition GUID
+ */
+void block_io_dev_set_partition_guid(
+	struct block_io_dev *this_instance,
+	const struct uuid_octets *partition_guid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MEDIA_BLOCK_IO_DEV_H */
diff --git a/components/media/volume/storage/component.cmake b/components/media/volume/block_io_dev/component.cmake
similarity index 62%
copy from components/media/volume/storage/component.cmake
copy to components/media/volume/block_io_dev/component.cmake
index 98f5c3a..cba61fc 100644
--- a/components/media/volume/storage/component.cmake
+++ b/components/media/volume/block_io_dev/component.cmake
@@ -8,9 +8,6 @@
 	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
 endif()
 
-#-------------------------------------------------------------------------------
-# Depends on the tf-a external component
-#-------------------------------------------------------------------------------
 target_sources(${TGT} PRIVATE
-	"${TFA_SOURCE_DIR}/drivers/io/io_storage.c"
+	"${CMAKE_CURRENT_LIST_DIR}/block_io_dev.c"
 )
\ No newline at end of file
diff --git a/components/media/volume/block_io_dev/test/block_io_dev_tests.cpp b/components/media/volume/block_io_dev/test/block_io_dev_tests.cpp
new file mode 100644
index 0000000..f6ae2c4
--- /dev/null
+++ b/components/media/volume/block_io_dev/test/block_io_dev_tests.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <string>
+#include <cstring>
+#include <common/uuid/uuid.h>
+#include <service/block_storage/block_store/device/ram/ram_block_store.h>
+#include <media/volume/block_io_dev/block_io_dev.h>
+#include <media/volume/index/volume_index.h>
+#include <media/volume/base_io_dev/base_io_dev.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(BlockIoDevTests)
+{
+	void setup()
+	{
+		uuid_parse_to_octets("6152f22b-8128-4c1f-981f-3bd279519907",
+			m_partition_guid.octets, sizeof(m_partition_guid.octets));
+
+		m_block_store = ram_block_store_init(&m_ram_block_store,
+			&m_partition_guid, NUM_BLOCKS, BLOCK_SIZE);
+
+		CHECK_TRUE(m_block_store);
+
+		m_dev_handle = 0;
+		m_volume_spec = 0;
+
+		int result = block_io_dev_init(&m_block_io_dev,
+			m_block_store, &m_partition_guid,
+			&m_dev_handle, &m_volume_spec);
+
+		LONGS_EQUAL(0, result);
+		CHECK_TRUE(m_dev_handle);
+		CHECK_TRUE(m_volume_spec);
+
+		volume_index_init();
+		volume_index_add(TEST_VOLUME_ID, m_dev_handle, m_volume_spec);
+	}
+
+	void teardown()
+	{
+		block_io_dev_deinit(&m_block_io_dev);
+		ram_block_store_deinit(&m_ram_block_store);
+		volume_index_clear();
+	}
+
+	static const unsigned int TEST_VOLUME_ID = 5;
+	static const size_t NUM_BLOCKS = 100;
+	static const size_t BLOCK_SIZE = 512;
+
+	struct uuid_octets m_partition_guid;
+	struct block_store *m_block_store;
+	struct ram_block_store m_ram_block_store;
+	struct block_io_dev m_block_io_dev;
+	uintptr_t m_dev_handle;
+	uintptr_t m_volume_spec;
+};
+
+
+TEST(BlockIoDevTests, openClose)
+{
+	/* Check the open flow used by tf-a components */
+	uintptr_t dev_handle = 0;
+	uintptr_t volume_spec = 0;
+	uintptr_t file_handle = 0;
+	int result;
+
+	result = plat_get_image_source(TEST_VOLUME_ID, &dev_handle, &volume_spec);
+	LONGS_EQUAL(0, result);
+	CHECK_TRUE(dev_handle);
+
+	result = io_open(dev_handle, volume_spec, &file_handle);
+	LONGS_EQUAL(0, result);
+	CHECK_TRUE(file_handle);
+
+	io_close(file_handle);
+}
+
+TEST(BlockIoDevTests, readAndWrite)
+{
+	uintptr_t file_handle = 0;
+	int result;
+
+	result = io_open(m_dev_handle, m_volume_spec, &file_handle);
+	LONGS_EQUAL(0, result);
+	CHECK_TRUE(file_handle);
+
+	std::string message("Oh what a beautiful mornin'");
+
+	/* Ensure writes cross a block boundary */
+	size_t num_iterations = BLOCK_SIZE / message.size() + 2;
+
+	/* Write message a few times. Expect file pointer to advance on each write */
+	for (size_t i = 0; i < num_iterations; ++i) {
+
+		size_t len_written = 0;
+
+		result = io_write(file_handle,
+			(const uintptr_t)message.c_str(), message.size(),
+			&len_written);
+
+		LONGS_EQUAL(0, result);
+		UNSIGNED_LONGS_EQUAL(message.size(), len_written);
+	}
+
+	result = io_seek(file_handle, IO_SEEK_SET, 0);
+	LONGS_EQUAL(0, result);
+
+	/* Expect to read back the same data */
+	uint8_t read_buf[message.size()];
+
+	for (size_t i = 0; i < num_iterations; ++i) {
+
+		size_t len_read = 0;
+
+		memset(read_buf, 0, sizeof(read_buf));
+
+		result = io_read(file_handle,
+			(const uintptr_t)read_buf, sizeof(read_buf),
+			&len_read);
+
+		LONGS_EQUAL(0, result);
+		UNSIGNED_LONGS_EQUAL(message.size(), len_read);
+		MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+	}
+
+	io_close(file_handle);
+}
+
+TEST(BlockIoDevTests, seekAccess)
+{
+	uintptr_t file_handle = 0;
+	size_t len = 0;
+	int result;
+
+	result = io_open(m_dev_handle, m_volume_spec, &file_handle);
+	LONGS_EQUAL(0, result);
+	CHECK_TRUE(file_handle);
+
+	std::string message("Knees up Mother Brown");
+
+	/* Initially seek to an arbitrary position around the middle of the volume */
+	size_t start_pos = (NUM_BLOCKS * BLOCK_SIZE) / 2 + 27;
+
+	/* Seek and write a few times */
+	result = io_seek(file_handle, IO_SEEK_SET, start_pos);
+	LONGS_EQUAL(0, result);
+
+	result = io_write(file_handle, (const uintptr_t)message.c_str(), message.size(), &len);
+	LONGS_EQUAL(0, result);
+	UNSIGNED_LONGS_EQUAL(message.size(), len);
+
+	/* Using IO_SEEK_SET, seek forward, skipping over the written message */
+	result = io_seek(file_handle, IO_SEEK_SET, start_pos + 110);
+	LONGS_EQUAL(0, result);
+
+	result = io_write(file_handle, (const uintptr_t)message.c_str(), message.size(), &len);
+	LONGS_EQUAL(0, result);
+	UNSIGNED_LONGS_EQUAL(message.size(), len);
+
+	/* Using IO_SEEK_CUR, seek forward again, far enough to skip over the message */
+	result = io_seek(file_handle, IO_SEEK_CUR, 715);
+	LONGS_EQUAL(0, result);
+
+	result = io_write(file_handle, (const uintptr_t)message.c_str(), message.size(), &len);
+	LONGS_EQUAL(0, result);
+	UNSIGNED_LONGS_EQUAL(message.size(), len);
+
+	/* Perform the same sequence of seeks and expect to read back intact copies of the message */
+	uint8_t read_buf[message.size()];
+
+	result = io_seek(file_handle, IO_SEEK_SET, start_pos);
+	LONGS_EQUAL(0, result);
+
+	result = io_read(file_handle, (uintptr_t)read_buf, sizeof(read_buf), &len);
+	LONGS_EQUAL(0, result);
+	UNSIGNED_LONGS_EQUAL(message.size(), len);
+	MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+
+	result = io_seek(file_handle, IO_SEEK_SET, start_pos + 110);
+	LONGS_EQUAL(0, result);
+
+	result = io_read(file_handle, (uintptr_t)read_buf, sizeof(read_buf), &len);
+	LONGS_EQUAL(0, result);
+	UNSIGNED_LONGS_EQUAL(message.size(), len);
+	MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+
+	result = io_seek(file_handle, IO_SEEK_CUR, 715);
+	LONGS_EQUAL(0, result);
+
+	result = io_read(file_handle, (uintptr_t)read_buf, sizeof(read_buf), &len);
+	LONGS_EQUAL(0, result);
+	UNSIGNED_LONGS_EQUAL(message.size(), len);
+	MEMCMP_EQUAL(message.c_str(), read_buf, message.size());
+
+	io_close(file_handle);
+}
\ No newline at end of file
diff --git a/components/media/volume/storage/component.cmake b/components/media/volume/block_io_dev/test/component.cmake
similarity index 61%
copy from components/media/volume/storage/component.cmake
copy to components/media/volume/block_io_dev/test/component.cmake
index 98f5c3a..7be3a61 100644
--- a/components/media/volume/storage/component.cmake
+++ b/components/media/volume/block_io_dev/test/component.cmake
@@ -8,9 +8,6 @@
 	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
 endif()
 
-#-------------------------------------------------------------------------------
-# Depends on the tf-a external component
-#-------------------------------------------------------------------------------
 target_sources(${TGT} PRIVATE
-	"${TFA_SOURCE_DIR}/drivers/io/io_storage.c"
-)
\ No newline at end of file
+	"${CMAKE_CURRENT_LIST_DIR}/block_io_dev_tests.cpp"
+	)
diff --git a/components/media/volume/index/volume_index.c b/components/media/volume/index/volume_index.c
index fe8b209..7f68616 100644
--- a/components/media/volume/index/volume_index.c
+++ b/components/media/volume/index/volume_index.c
@@ -8,7 +8,6 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
-#include <plat/common/platform.h>
 #include "volume_index.h"
 
 #ifndef VOLUME_INDEX_MAX_ENTRIES
diff --git a/components/media/volume/index/volume_index.h b/components/media/volume/index/volume_index.h
index dd9964c..6d2bcab 100644
--- a/components/media/volume/index/volume_index.h
+++ b/components/media/volume/index/volume_index.h
@@ -4,8 +4,8 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef VOLUME_INDEX_H
-#define VOLUME_INDEX_H
+#ifndef MEDIA_VOLUME_INDEX_H
+#define MEDIA_VOLUME_INDEX_H
 
 #include <stdint.h>
 
@@ -14,6 +14,12 @@
 #endif
 
 /**
+ * For tf-a declaration of plat_get_image_source(). Included within C++ extern C
+ * guard to allow for calling from C++.
+ */
+#include <plat/common/platform.h>
+
+/**
  * @brief  Initialize the volume index
  *
  * The volume_index is a singleton that holds the mapping of volume IDs
@@ -49,4 +55,4 @@
 }
 #endif
 
-#endif /* VOLUME_INDEX_H */
+#endif /* MEDIA_VOLUME_INDEX_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 741ca40..67f8f30 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -162,8 +162,10 @@
 		"components/service/smm_variable/backend"
 		"components/service/smm_variable/backend/test"
 		"components/media/partition_table"
-		"components/media/volume/storage"
+		"components/media/volume/base_io_dev"
 		"components/media/volume/index"
+		"components/media/volume/block_io_dev"
+		"components/media/volume/block_io_dev/test"
 		"protocols/rpc/common/protobuf"
 		"protocols/rpc/common/packed-c"
 		"protocols/service/crypto/packed-c"