Add fw_directory component

The fw_directory provides the update agent with a catalogue of
updatable images for a device. The contents of the fw_directory
is populated by a fw_inspector.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I681ca2aabd95f7cea8b9631a00fb5c92f81ef8b3
diff --git a/components/service/fwu/agent/component.cmake b/components/service/fwu/agent/component.cmake
new file mode 100644
index 0000000..a0d89ef
--- /dev/null
+++ b/components/service/fwu/agent/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}/fw_directory.c"
+	)
diff --git a/components/service/fwu/agent/fw_directory.c b/components/service/fwu/agent/fw_directory.c
new file mode 100644
index 0000000..c794832
--- /dev/null
+++ b/components/service/fwu/agent/fw_directory.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <protocols/service/fwu/packed-c/status.h>
+#include "fw_directory.h"
+
+void fw_directory_init(
+	struct fw_directory *fw_directory)
+{
+	assert(fw_directory);
+
+	/* The fw_directory is initially empty. It will be populated by a
+	 * fw_inspector.
+	 */
+	memset(fw_directory, 0, sizeof(struct fw_directory));
+}
+
+void fw_directory_deinit(
+	struct fw_directory *fw_directory)
+{
+	(void)fw_directory;
+}
+
+void fw_directory_set_boot_info(
+	struct fw_directory *fw_directory,
+	const struct boot_info *boot_info)
+{
+	assert(fw_directory);
+	fw_directory->boot_info = *boot_info;
+}
+
+int fw_directory_add_image_info(
+	struct fw_directory *fw_directory,
+	const struct image_info *image_info)
+{
+	assert(fw_directory);
+	assert(image_info);
+
+	int status = FWU_STATUS_UNKNOWN;
+
+	if (fw_directory->num_images < FWU_MAX_FW_DIRECTORY_ENTRIES) {
+
+		uint32_t image_index = fw_directory->num_images;
+
+		fw_directory->entries[image_index] = *image_info;
+		fw_directory->entries[image_index].image_index = image_index;
+
+		++fw_directory->num_images;
+
+		status = FWU_STATUS_SUCCESS;
+	}
+
+	return status;
+}
+
+const struct image_info *fw_directory_find_image_info(
+	const struct fw_directory *fw_directory,
+	const struct uuid_octets *img_type_uuid)
+{
+	assert(fw_directory);
+	assert(img_type_uuid);
+
+	const struct image_info *info = NULL;
+
+	for (size_t i = 0; i < fw_directory->num_images; i++) {
+
+		if (uuid_is_equal(img_type_uuid->octets,
+				fw_directory->entries[i].img_type_uuid.octets)) {
+
+			info = &fw_directory->entries[i];
+			break;
+		}
+	}
+
+	return info;
+}
+
+const struct boot_info *fw_directory_get_boot_info(
+	const struct fw_directory *fw_directory)
+{
+	assert(fw_directory);
+	return &fw_directory->boot_info;
+}
+
+const struct image_info *fw_directory_get_image_info(
+	const struct fw_directory *fw_directory,
+	size_t index)
+{
+	assert(fw_directory);
+
+	const struct image_info *info = NULL;
+
+	if (index < fw_directory->num_images)
+		info = &fw_directory->entries[index];
+
+	return info;
+}
+
+size_t fw_directory_num_images(
+	const struct fw_directory *fw_directory)
+{
+	assert(fw_directory);
+	return fw_directory->num_images;
+}
diff --git a/components/service/fwu/agent/fw_directory.h b/components/service/fwu/agent/fw_directory.h
new file mode 100644
index 0000000..119f5bc
--- /dev/null
+++ b/components/service/fwu/agent/fw_directory.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef FW_DIRECTORY_H
+#define FW_DIRECTORY_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <common/uuid/uuid.h>
+#include "install_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The default maximum number of images that can be held by the fw_directory.
+ * Can be overridden by an external definition.
+ */
+#ifndef FWU_MAX_FW_DIRECTORY_ENTRIES
+#define FWU_MAX_FW_DIRECTORY_ENTRIES	(20)
+#endif
+
+/**
+ * \brief Boot information structure definition
+ *
+ * The boot_info structure holds information obtained from the boot loader
+ * about the most recent boot.
+ */
+struct boot_info {
+	/* Identifies the bank that was used during boot */
+	uint32_t boot_index;
+
+	/* The state of the active_index metadata variable during boot */
+	uint32_t active_index;
+
+	/* The state of the previous_active_index metadata variable during boot */
+	uint32_t previous_active_index;
+};
+
+/**
+ * \brief Image information structure definition
+ *
+ * Information about an updatable image. Firmware may consist of an arbitrary
+ * number of images that may be updated as a single unit. Images may correspond
+ * to individual components, such as the Crypto SP image, or a collection of
+ * components contained within a package understood by firmware such as a FIP.
+ */
+struct image_info {
+	/* Unique identifier for the image type. This corresponds to the UUID/GUID
+	 * assigned by the originator of the update package to identify the image.
+	 */
+	struct uuid_octets img_type_uuid;
+
+	/* The maximum size that can be accommodated for an image of this type.
+	 * A platform integrator will have sized back-end storage to provide
+	 * sufficient headroom to accommodate updates.
+	 */
+	size_t max_size;
+
+	/* The lowest accepted version number for this image. This will correspond
+	 * to the NV anti-rollback counter value associated with the image.
+	 */
+	uint32_t lowest_accepted_version;
+
+	/* The version of the currently active version of this image. */
+	uint32_t active_version;
+
+	/* Bitmap of access permissions for this iamge. */
+	uint32_t permissions;
+
+	/* The index [0..n] of the image in the fw directory. */
+	uint32_t image_index;
+
+	/* The location_id assigned by the platform integrator. A fw_store may
+	 * be distributed over multiple locations (e.g. different storage partitions).
+	 * The location_id is used to associate installers to storage volumes.
+	 */
+	uint32_t location_id;
+
+	/* Identifies the type of installation needed for the image. */
+	enum install_type install_type;
+};
+
+/**
+ * \brief Firmware directory structure definition
+ *
+ * The fw_directory holds information about currently active firmware. Information
+ * will have been collected via a trusted pathway. A subset of the information held
+ * is presented to external clients.
+ */
+struct fw_directory {
+	struct boot_info boot_info;
+	size_t num_images;
+	struct image_info entries[FWU_MAX_FW_DIRECTORY_ENTRIES];
+};
+
+/**
+ * \brief Initialise a fw_directory
+ *
+ * Initialises the subject fw_directory. After initialisation, the empty fw_directory
+ * will need to be populated by a trusted agent (the fw_inspector).
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ */
+void fw_directory_init(
+	struct fw_directory *fw_directory);
+
+/**
+ * \brief De-initialise a fw_directory
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ */
+void fw_directory_deinit(
+	struct fw_directory *fw_directory);
+
+/**
+ * \brief Sets the boot_info held by the fw_directory
+ *
+ * Used by a fw_inspector to set the boot_info for the most recent system boot.
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ * \param[in]  boot_info       boot_info for most recent system boot
+ */
+void fw_directory_set_boot_info(
+	struct fw_directory *fw_directory,
+	const struct boot_info *boot_info);
+
+/**
+ * \brief Adds an image_info to the directory
+ *
+ * Used by a fw_inspector to add an image_info entry to the directory.
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ * \param[in]  image_info      The entry to add
+ *
+ * \return FWU status
+ */
+int fw_directory_add_image_info(
+	struct fw_directory *fw_directory,
+	const struct image_info *image_info);
+
+/**
+ * \brief Find an image_info entry
+ *
+ * Query to find an image_info entry using the image type UUID as the key.
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ * \param[in]  image_type_uuid Image type UUID
+ *
+ * \return Pointer to image_info or NULL
+ */
+const struct image_info *fw_directory_find_image_info(
+	const struct fw_directory *fw_directory,
+	const struct uuid_octets *img_type_uuid);
+
+/**
+ * \brief Get the boot_info
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ *
+ * \return Pointer to the boot_info
+ */
+const struct boot_info *fw_directory_get_boot_info(
+	const struct fw_directory *fw_directory);
+
+/**
+ * \brief Get an image_info by index
+ *
+ * Can be used for iterating over all image_info objects held.
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ * \param[in]  index           Index in range [0..num_images-1]
+ *
+ * \return Pointer to the image_info or NULL if index invalid
+ */
+const struct image_info *fw_directory_get_image_info(
+	const struct fw_directory *fw_directory,
+	size_t index);
+
+/**
+ * \brief Get the number of image_info entries held
+ *
+ * \param[in]  fw_directory    The subject fw_directory
+ *
+ * \return Number of entries
+ */
+size_t fw_directory_num_images(
+	const struct fw_directory *fw_directory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FW_DIRECTORY_H */
diff --git a/components/service/fwu/agent/install_type.h b/components/service/fwu/agent/install_type.h
new file mode 100644
index 0000000..dc72fbf
--- /dev/null
+++ b/components/service/fwu/agent/install_type.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef INSTALL_TYPE_H
+#define INSTALL_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief A classifier for the type of installation performed by an installer
+ *
+ * The scope of an update image may encompass the whole contents of a storage
+ * volume or just a part of the volume. The install_type is used to help
+ * associate an incoming image with an appropriate installer.
+ */
+enum install_type {
+
+	/* An installer that updates the entire contents of a storage volume.
+	 * This type of installer doesn't need to understand the installed
+	 * image format and can just install directly into a storage volume.
+	 */
+	INSTALL_TYPE_WHOLE_VOLUME,
+
+	/* An installer that updates a part of a storage volume. To achieve
+	 * this, the installer must have knowledge of the format of the target
+	 * storage volume.
+	 */
+	INSTALL_TYPE_SUB_VOLUME,
+
+	/* An installer that copies the entire contents of one volume to
+	 * another. No externally provided update data is installed. When
+	 * a platform with multiple locations receives an update that only
+	 * updates some locations, a whole volume copy installer can be used
+	 * to duplicate the active bank contents into the update bank.
+	 */
+	INSTALL_TYPE_WHOLE_VOLUME_COPY,
+
+	INSTALL_TYPE_LIMIT
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INSTALL_TYPE_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 474ecde..c1e40fb 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -108,6 +108,7 @@
 		"components/service/block_storage/factory/ref_ram"
 		"components/service/block_storage/factory/ref_ram_gpt"
 		"components/service/block_storage/factory/client"
+		"components/service/fwu/agent"
 		"components/service/crypto/client/cpp"
 		"components/service/crypto/client/cpp/protocol/protobuf"
 		"components/service/crypto/client/cpp/protocol/packed-c"