Add FWU metadata V2 support

Adds metadata serialization support for the FWU-A V2 metadata
structure.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I482b81a69cadf8c5e60033ab4852858abc298ec6
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v2/component.cmake b/components/service/fwu/fw_store/banked/metadata_serializer/v2/component.cmake
new file mode 100644
index 0000000..1a274e3
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v2/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, 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}/metadata_serializer_v2.c"
+	)
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.c b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.c
new file mode 100644
index 0000000..c5a6688
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include <common/uuid/uuid.h>
+#include <protocols/service/fwu/packed-c/metadata_v2.h>
+#include <protocols/service/fwu/packed-c/status.h>
+#include <media/volume/volume.h>
+#include <media/volume/index/volume_index.h>
+#include <service/fwu/agent/fw_directory.h>
+#include <service/fwu/fw_store/banked/bank_tracker.h>
+#include <service/fwu/fw_store/banked/volume_id.h>
+#include <service/fwu/fw_store/banked/metadata_serializer/metadata_serializer.h>
+#include "metadata_serializer_v2.h"
+
+
+static size_t metadata_serializer_size(
+	const struct fw_directory *fw_dir)
+{
+	return
+		sizeof(struct fwu_metadata) +
+		offsetof(struct fwu_fw_store_desc, img_entry) +
+		sizeof(struct fwu_image_entry) * fw_directory_num_images(fw_dir);
+}
+
+static size_t metadata_serializer_max_size(void)
+{
+	return
+		sizeof(struct fwu_metadata) +
+		offsetof(struct fwu_fw_store_desc, img_entry) +
+		sizeof(struct fwu_image_entry) * FWU_MAX_FW_DIRECTORY_ENTRIES;
+}
+
+static int serialize_image_entries(
+	struct fwu_fw_store_desc *fw_store_desc,
+	const struct fw_directory *fw_dir,
+	const struct bank_tracker *bank_tracker)
+{
+	for (size_t image_index = 0; image_index < fw_store_desc->num_images; image_index++) {
+
+		/* Image entry indices in the fw_store_desc correspond to the image index
+		 * of the associate entry in the fw_directory.
+		 */
+		const struct image_info *image_info =
+			fw_directory_get_image_info(fw_dir, image_index);
+
+		assert(image_info);
+
+		/* Information about storage for the image is retrieved from the configured
+		 * volume objects that provide access to the banked storage. Both volumes
+		 * are assumed to have the same parent location, identified by the location
+		 * uuid.
+		 */
+		struct uuid_octets location_uuid = {0};
+		struct fwu_image_entry *entry = &fw_store_desc->img_entry[image_index];
+
+		/* Serialize bank storage info */
+		for (size_t bank_index = 0;
+			bank_index < BANK_SCHEME_NUM_BANKS; bank_index++) {
+
+			struct uuid_octets img_uuid = {0};
+			struct volume *volume = NULL;
+
+			int status = volume_index_find(
+				banked_volume_id(
+					image_info->location_id,
+					banked_usage_id(bank_index)),
+				&volume);
+
+			if (!status && volume) {
+				/* A concrete volume may not support retrieving storage IDs. If
+				 * this is the case, volume_get_storage_ids() will return an error,
+				 * which is deliberately ignored and UUIDs left in their default state.
+				 * To ensure that all banks reflect the same parent location, the
+				 * location uuid returned by the volume holding the first bank is
+				 * used as the parent.
+				 */
+				struct uuid_octets *parent_uuid = (bank_index == 0) ?
+					&location_uuid : NULL;
+
+				volume_get_storage_ids(volume, &img_uuid, parent_uuid);
+			}
+
+			struct fwu_img_bank_info *bank_info = &entry->img_bank_info[bank_index];
+
+			memcpy(bank_info->img_uuid, img_uuid.octets, OSF_UUID_OCTET_LEN);
+			bank_info->reserved = 0;
+			bank_info->accepted = bank_tracker_is_accepted(
+				bank_tracker, bank_index, image_index) ? 1 : 0;
+		}
+
+		/* Serialize per-image UUIDs */
+		memcpy(entry->img_type_uuid,
+			image_info->img_type_uuid.octets, OSF_UUID_OCTET_LEN);
+		memcpy(entry->location_uuid,
+			location_uuid.octets, OSF_UUID_OCTET_LEN);
+	}
+
+	return FWU_STATUS_SUCCESS;
+}
+
+static int serialize_fw_store_desc(
+	const struct fw_directory *fw_dir,
+	const struct bank_tracker *bank_tracker,
+	uint8_t *buf)
+{
+	struct fwu_fw_store_desc *fw_store_desc = (struct fwu_fw_store_desc *)buf;
+
+	fw_store_desc->num_banks = BANK_SCHEME_NUM_BANKS;
+	fw_store_desc->num_images = fw_directory_num_images(fw_dir);
+	fw_store_desc->img_entry_size = sizeof(struct fwu_image_entry);
+	fw_store_desc->bank_entry_size = sizeof(struct fwu_img_bank_info);
+
+	return serialize_image_entries(fw_store_desc, fw_dir, bank_tracker);
+}
+
+static int metadata_serializer_serialize(
+	uint32_t active_index,
+	uint32_t previous_active_index,
+	const struct fw_directory *fw_dir,
+	const struct bank_tracker *bank_tracker,
+	uint8_t *buf,
+	size_t buf_size,
+	size_t *metadata_len)
+{
+	int status = FWU_STATUS_UNKNOWN;
+	size_t serialized_size = metadata_serializer_size(fw_dir);
+
+	*metadata_len = 0;
+
+	if (serialized_size <= buf_size) {
+
+		struct fwu_metadata *metadata = (struct fwu_metadata *)buf;
+
+		/* Serialize metadata header */
+		metadata->crc_32 = 0;
+		metadata->version = 2;
+		metadata->metadata_size = (uint32_t)serialized_size;
+		metadata->header_size = (uint16_t)sizeof(struct fwu_metadata);
+		metadata->active_index = active_index;
+		metadata->previous_active_index = previous_active_index;
+
+		for (unsigned int bank_index = 0;
+			bank_index < FWU_METADATA_V2_NUM_BANK_STATES; bank_index++) {
+
+			if (bank_index < BANK_SCHEME_NUM_BANKS) {
+
+				if (bank_tracker_is_all_accepted(
+						bank_tracker,
+						bank_index,
+						fw_directory_num_images(fw_dir)))
+					metadata->bank_state[bank_index] =
+						FWU_METADATA_V2_BANK_STATE_ACCEPTED;
+				else if (bank_tracker_is_content(
+						bank_tracker,
+						bank_index))
+					metadata->bank_state[bank_index] =
+						FWU_METADATA_V2_BANK_STATE_VALID;
+				else
+					metadata->bank_state[bank_index] =
+						FWU_METADATA_V2_BANK_STATE_INVALID;
+
+			} else
+				metadata->bank_state[bank_index] =
+					FWU_METADATA_V2_BANK_STATE_INVALID;
+		}
+
+		/* Serialize optional fw store descriptor if required */
+		if (serialized_size > metadata->header_size)
+			status = serialize_fw_store_desc(
+				fw_dir,
+				bank_tracker,
+				&buf[metadata->header_size]);
+		else
+			status = FWU_STATUS_SUCCESS;
+
+		if (status == FWU_STATUS_SUCCESS)
+			*metadata_len = serialized_size;
+	}
+
+	return status;
+}
+
+static void metadata_serializer_deserialize_bank_info(
+	struct bank_tracker *bank_tracker,
+	const uint8_t *serialized_metadata,
+	size_t metadata_len)
+{
+	const struct fwu_metadata *metadata = (const struct fwu_metadata *)serialized_metadata;
+
+	/* Sanity check size values in header */
+	if ((metadata->header_size > metadata_len) ||
+		(metadata->metadata_size > metadata_len))
+		return;
+
+	/* Deserialize bank state in header and update bank_tracker to reflect the same state */
+	for (unsigned int bank_index = 0; bank_index < BANK_SCHEME_NUM_BANKS; bank_index++) {
+
+		if (metadata->bank_state[bank_index] == FWU_METADATA_V2_BANK_STATE_ACCEPTED)
+			bank_tracker_set_holds_accepted_content(bank_tracker, bank_index);
+		else if (metadata->bank_state[bank_index] == FWU_METADATA_V2_BANK_STATE_VALID)
+			bank_tracker_set_holds_content(bank_tracker, bank_index);
+	}
+
+	/* If present, deserialize the fw_store_desc */
+	if (metadata->metadata_size >=
+		metadata->header_size + offsetof(struct fwu_fw_store_desc, img_entry)) {
+
+		const struct fwu_fw_store_desc *fw_store_desc =
+			(const struct fwu_fw_store_desc *)(serialized_metadata + metadata->header_size);
+
+		size_t fw_store_desc_size =
+			metadata->metadata_size - metadata->header_size;
+		size_t total_img_entries_size =
+			fw_store_desc_size - offsetof(struct fwu_fw_store_desc, img_entry);
+		size_t per_img_entry_bank_info_size =
+			fw_store_desc->num_banks * fw_store_desc->bank_entry_size;
+
+		/* Sanity check fw_store_desc values */
+		if ((fw_store_desc->img_entry_size <
+				sizeof(struct fwu_image_entry)) ||
+			(fw_store_desc->bank_entry_size <
+				sizeof(struct fwu_img_bank_info)) ||
+			(fw_store_desc->num_banks >
+				BANK_SCHEME_NUM_BANKS) ||
+			(fw_store_desc->img_entry_size <
+				offsetof(struct fwu_image_entry, img_bank_info) +
+				per_img_entry_bank_info_size) ||
+			(fw_store_desc->num_images >
+				FWU_MAX_FW_DIRECTORY_ENTRIES) ||
+			(total_img_entries_size <
+				fw_store_desc->num_images * fw_store_desc->img_entry_size))
+			return;
+
+		/* Deserialize per-image info */
+		for (size_t image_index = 0;
+			image_index < fw_store_desc->num_images; image_index++) {
+
+			const struct fwu_image_entry *image_entry = (const struct fwu_image_entry *)
+				((const uint8_t *)fw_store_desc->img_entry +
+				image_index * fw_store_desc->img_entry_size);
+
+			for (size_t bank_index = 0;
+				bank_index < fw_store_desc->num_banks; bank_index++) {
+
+				const struct fwu_img_bank_info *bank_info =(const struct fwu_img_bank_info *)
+					((const uint8_t *)image_entry->img_bank_info +
+					bank_index * fw_store_desc->bank_entry_size);
+
+				if (bank_info->accepted)
+					bank_tracker_accept(bank_tracker, bank_index, image_index);
+			}
+		}
+	}
+}
+
+static void metadata_serializer_deserialize_active_indices(
+	uint32_t *active_index,
+	uint32_t *previous_active_index,
+	const uint8_t *serialized_metadata,
+	size_t metadata_len)
+{
+	const struct fwu_metadata *metadata = (const struct fwu_metadata *)serialized_metadata;
+
+	assert(metadata_len >= sizeof(struct fwu_metadata));
+
+	*active_index = metadata->active_index;
+	*previous_active_index = metadata->previous_active_index;
+}
+
+const struct metadata_serializer *metadata_serializer_v2(void)
+{
+	static const struct metadata_serializer serializer = {
+		metadata_serializer_serialize,
+		metadata_serializer_size,
+		metadata_serializer_max_size,
+		metadata_serializer_deserialize_bank_info,
+		metadata_serializer_deserialize_active_indices
+	};
+
+	return &serializer;
+}
diff --git a/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h
new file mode 100644
index 0000000..c095cc9
--- /dev/null
+++ b/components/service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef METADATA_SERIALIZER_V2_H
+#define METADATA_SERIALIZER_V2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Interface dependencies
+ */
+struct metadata_serializer;
+
+/**
+ * \brief Return a metadata_serializer for version 2 serialization
+ *
+ */
+const struct metadata_serializer *metadata_serializer_v2(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* METADATA_SERIALIZER_V2_H */
diff --git a/components/service/fwu/test/fwu_dut/fwu_dut.cpp b/components/service/fwu/test/fwu_dut/fwu_dut.cpp
index bfe2cef..7fccd6a 100644
--- a/components/service/fwu/test/fwu_dut/fwu_dut.cpp
+++ b/components/service/fwu/test/fwu_dut/fwu_dut.cpp
@@ -9,6 +9,7 @@
 #include <string>
 #include <common/endian/le.h>
 #include <service/fwu/test/metadata_checker/metadata_checker_v1.h>
+#include <service/fwu/test/metadata_checker/metadata_checker_v2.h>
 #include <CppUTest/TestHarness.h>
 #include "fwu_dut.h"
 
@@ -151,6 +152,9 @@
 	if (m_metadata_version == 1)
 		return new metadata_checker_v1(metadata_fetcher, num_images);
 
+	if (m_metadata_version == 2)
+		return new metadata_checker_v2(metadata_fetcher, num_images);
+
 	/* Unsupported metadata version */
 	assert(false);
 
diff --git a/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp
index 413f0de..89b2a5e 100644
--- a/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp
+++ b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,13 +7,13 @@
 #include <cassert>
 #include <service/fwu/test/fwu_client/remote/remote_fwu_client.h>
 #include <service/fwu/test/metadata_fetcher/client/client_metadata_fetcher.h>
-#include <service/fwu/test/metadata_checker/metadata_checker_v1.h>
 #include "proxy_fwu_dut.h"
 
 proxy_fwu_dut::proxy_fwu_dut(
 	unsigned int num_locations,
+	unsigned int metadata_version,
 	fwu_dut *remote_dut) :
-	fwu_dut(),
+	fwu_dut(metadata_version),
 	m_num_locations(num_locations),
 	m_remote_dut(remote_dut)
 {
@@ -52,7 +52,7 @@
 	fwu_client *fwu_client = new remote_fwu_client;
 	metadata_fetcher *metadata_fetcher = new client_metadata_fetcher(fwu_client);
 
-	return new metadata_checker_v1(metadata_fetcher, m_num_locations);
+	return fwu_dut::create_metadata_checker(metadata_fetcher, m_num_locations);
 }
 
 fwu_client *proxy_fwu_dut::create_fwu_client(void)
diff --git a/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h
index 298da5d..7fe0a81 100644
--- a/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h
+++ b/components/service/fwu/test/fwu_dut/proxy/proxy_fwu_dut.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -23,10 +23,12 @@
 	 * \brief proxy_fwu_dut constructor
 	 *
 	 * \param[in]  num_locations  The number of updatable fw locations
+	 * \param[in]  metadata_version  FWU metadata version supported by bootloader
 	 * \param[in]  remote_dut  The associated remote fwu dut
 	 */
 	proxy_fwu_dut(
 		unsigned int num_locations,
+		unsigned int metadata_version,
 		fwu_dut *remote_dut);
 
 	~proxy_fwu_dut();
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
index 3ae06de..fded211 100644
--- a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.cpp
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <cassert>
 #include <cstring>
 #include <sstream>
 #include <CppUTest/TestHarness.h>
@@ -14,6 +15,7 @@
 #include <service/fwu/installer/installer_index.h>
 #include <service/fwu/fw_store/banked/volume_id.h>
 #include <service/fwu/fw_store/banked/metadata_serializer/v1/metadata_serializer_v1.h>
+#include <service/fwu/fw_store/banked/metadata_serializer/v2/metadata_serializer_v2.h>
 #include <service/fwu/inspector/direct/direct_fw_inspector.h>
 #include <service/fwu/provider/serializer/packed-c/packedc_fwu_provider_serializer.h>
 #include <service/fwu/test/fwu_client/direct/direct_fwu_client.h>
@@ -22,8 +24,9 @@
 
 sim_fwu_dut::sim_fwu_dut(
 	unsigned int num_locations,
+	unsigned int metadata_version,
 	bool allow_partial_updates) :
-	fwu_dut(),
+	fwu_dut(metadata_version),
 	m_is_booted(false),
 	m_is_first_boot(true),
 	m_boot_info(),
@@ -130,7 +133,7 @@
 	/* Performs the generic update agent initialization that occurs on
 	 * each system boot.
 	 */
-	int status = banked_fw_store_init(&m_fw_store, metadata_serializer_v1());
+	int status = banked_fw_store_init(&m_fw_store, select_metadata_serializer());
 	LONGS_EQUAL(0, status);
 
 	status = update_agent_init(
@@ -465,3 +468,19 @@
 		LONGS_EQUAL(0, status);
 	}
 }
+
+const struct metadata_serializer *sim_fwu_dut::select_metadata_serializer(void) const
+{
+	unsigned int version = metadata_version();
+
+	if (version == 1)
+		return metadata_serializer_v1();
+
+	if (version == 2)
+		return metadata_serializer_v2();
+
+	/* Metadata version not supported */
+	assert(false);
+
+	return NULL;
+}
diff --git a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
index b30e32b..9929733 100644
--- a/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
+++ b/components/service/fwu/test/fwu_dut/sim/sim_fwu_dut.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -40,10 +40,12 @@
 	 * \brief sim_fwu_dut constructor
 	 *
 	 * \param[in]  num_locations  The number of updatable fw locations
+	 * \param[in]  metadata_version  FWU metadata version supported by bootloader
 	 * \param[in]  allow_partial_updates True if updating a subset of locations is permitted
 	 */
 	sim_fwu_dut(
 		unsigned int num_locations,
+		unsigned int metadata_version,
 		bool allow_partial_updates = false);
 
 	~sim_fwu_dut();
@@ -98,6 +100,8 @@
 	void install_factory_images(unsigned int num_locations);
 	void verify_boot_images(unsigned int boot_index);
 
+	const struct metadata_serializer *select_metadata_serializer(void) const;
+
 	bool m_is_booted;
 	bool m_is_first_boot;
 	struct boot_info m_boot_info;
diff --git a/components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h b/components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h
index c0c99af..aac99a7 100644
--- a/components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h
+++ b/components/service/fwu/test/fwu_dut_factory/fwu_dut_factory.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -30,6 +30,10 @@
 	static fwu_dut *create(
 		unsigned int num_locations,
 		bool allow_partial_updates = false);
+
+private:
+
+	static const unsigned int FWU_METADATA_VERSION = 2;
 };
 
 #endif /* FWU_DUT_FACTORY_H */
diff --git a/components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp b/components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp
index 2e22977..bbd2f45 100644
--- a/components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp
+++ b/components/service/fwu/test/fwu_dut_factory/remote_sim/fwu_dut_factory.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,12 +25,14 @@
 	/* Construct and set the simulated dut that provides the configured
 	 * device and fwu service provider.
 	 */
-	sim_fwu_dut *sim_dut =  new sim_fwu_dut(num_locations, allow_partial_updates);
+	sim_fwu_dut *sim_dut =  new sim_fwu_dut(num_locations,
+		FWU_METADATA_VERSION, allow_partial_updates);
 
 	fwu_service_context_set_provider(sim_dut->get_service_interface());
 
 	/* Construct a proxy_fwu_dut chained to the sim_fwu_dut. On deletion,
 	 * the proxy_fwu_dut deletes the associated sim_fwu_dut.
 	 */
-	return new proxy_fwu_dut(num_locations, sim_dut);
+	return new proxy_fwu_dut(num_locations,
+		FWU_METADATA_VERSION, sim_dut);
 }
\ No newline at end of file
diff --git a/components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp b/components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp
index be7dff8..a4e3799 100644
--- a/components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp
+++ b/components/service/fwu/test/fwu_dut_factory/sim/fwu_dut_factory.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,5 +17,6 @@
 	unsigned int num_locations,
 	bool allow_partial_updates)
 {
-	return new sim_fwu_dut(num_locations, allow_partial_updates);
+	return new sim_fwu_dut(num_locations,
+		FWU_METADATA_VERSION, allow_partial_updates);
 }
\ No newline at end of file
diff --git a/components/service/fwu/test/metadata_checker/component.cmake b/components/service/fwu/test/metadata_checker/component.cmake
index 033925f..a76655a 100644
--- a/components/service/fwu/test/metadata_checker/component.cmake
+++ b/components/service/fwu/test/metadata_checker/component.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -11,4 +11,5 @@
 target_sources(${TGT} PRIVATE
 	"${CMAKE_CURRENT_LIST_DIR}/metadata_checker.cpp"
 	"${CMAKE_CURRENT_LIST_DIR}/metadata_checker_v1.cpp"
+	"${CMAKE_CURRENT_LIST_DIR}/metadata_checker_v2.cpp"
 	)
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp b/components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp
index 57a545e..042226f 100644
--- a/components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v1.cpp
@@ -4,10 +4,16 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <service/fwu/agent/fw_directory.h>
 #include <protocols/service/fwu/packed-c/metadata_v1.h>
 #include <CppUTest/TestHarness.h>
 #include "metadata_checker_v1.h"
 
+const size_t metadata_checker_v1::MAX_FWU_METADATA_SIZE =
+	offsetof(struct fwu_metadata, img_entry) +
+	FWU_MAX_FW_DIRECTORY_ENTRIES * sizeof(struct fwu_image_entry);
+
+
 metadata_checker_v1::metadata_checker_v1(
 	metadata_fetcher *metadata_fetcher,
 	unsigned int num_images) :
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v1.h b/components/service/fwu/test/metadata_checker/metadata_checker_v1.h
index f705987..81be66a 100644
--- a/components/service/fwu/test/metadata_checker/metadata_checker_v1.h
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v1.h
@@ -7,8 +7,6 @@
 #ifndef METADATA_CHECKER_V1_H
 #define METADATA_CHECKER_V1_H
 
-#include <service/fwu/agent/fw_directory.h>
-#include <protocols/service/fwu/packed-c/metadata_v1.h>
 #include "metadata_checker.h"
 
 /*
@@ -36,9 +34,7 @@
 
 private:
 
-	static const size_t MAX_FWU_METADATA_SIZE =
-		offsetof(struct fwu_metadata, img_entry) +
-		FWU_MAX_FW_DIRECTORY_ENTRIES * sizeof(struct fwu_image_entry);
+	static const size_t MAX_FWU_METADATA_SIZE;
 
 	bool is_all_accepted(unsigned int boot_index) const;
 
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v2.cpp b/components/service/fwu/test/metadata_checker/metadata_checker_v2.cpp
new file mode 100644
index 0000000..dadcba4
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v2.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service/fwu/agent/fw_directory.h>
+#include <protocols/service/fwu/packed-c/metadata_v2.h>
+#include <CppUTest/TestHarness.h>
+#include "metadata_checker_v2.h"
+
+const size_t metadata_checker_v2::MAX_FWU_METADATA_SIZE =
+	sizeof(struct fwu_metadata) +
+	offsetof(struct fwu_fw_store_desc, img_entry) +
+	sizeof(struct fwu_image_entry) * FWU_MAX_FW_DIRECTORY_ENTRIES;
+
+
+metadata_checker_v2::metadata_checker_v2(
+	metadata_fetcher *metadata_fetcher,
+	unsigned int num_images) :
+	metadata_checker(MAX_FWU_METADATA_SIZE, metadata_fetcher)
+{
+
+}
+
+metadata_checker_v2::~metadata_checker_v2()
+{
+
+}
+
+void metadata_checker_v2::get_active_indices(
+	uint32_t *active_index,
+	uint32_t *previous_active_index)
+{
+	load_metadata();
+
+	struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+	*active_index = metadata->active_index;
+	*previous_active_index = metadata->previous_active_index;
+}
+
+void metadata_checker_v2::check_regular(unsigned int boot_index)
+{
+	load_metadata();
+
+	struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+	UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+
+	BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_ACCEPTED,
+		metadata->bank_state[boot_index]);
+}
+
+void metadata_checker_v2::check_ready_for_staging(unsigned int boot_index)
+{
+	load_metadata();
+
+	struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+	UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+
+	BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_ACCEPTED,
+		metadata->bank_state[boot_index]);
+	BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_INVALID,
+		metadata->bank_state[alternate_bank_index(boot_index)]);
+}
+
+void metadata_checker_v2::check_ready_to_activate(unsigned int boot_index)
+{
+	load_metadata();
+
+	struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+	UNSIGNED_LONGS_EQUAL(boot_index, metadata->previous_active_index);
+	CHECK_TRUE(metadata->active_index != boot_index);
+
+	BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_VALID,
+		metadata->bank_state[metadata->active_index]);
+}
+
+void metadata_checker_v2::check_trial(unsigned int boot_index)
+{
+	load_metadata();
+
+	struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+	UNSIGNED_LONGS_EQUAL(boot_index, metadata->active_index);
+	CHECK_TRUE(metadata->previous_active_index != boot_index);
+
+	BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_VALID,
+		metadata->bank_state[boot_index]);
+}
+
+void metadata_checker_v2::check_fallback_to_previous(unsigned int boot_index)
+{
+	load_metadata();
+
+	struct fwu_metadata *metadata = reinterpret_cast<struct fwu_metadata *>(m_meta_buf);
+
+	UNSIGNED_LONGS_EQUAL(boot_index, metadata->previous_active_index);
+	CHECK_TRUE(metadata->active_index != boot_index);
+
+	BYTES_EQUAL(FWU_METADATA_V2_BANK_STATE_ACCEPTED,
+		metadata->bank_state[boot_index]);
+}
+
+unsigned int metadata_checker_v2::alternate_bank_index(unsigned int bank_index)
+{
+	return (bank_index == 0) ? 1 : 0;
+}
\ No newline at end of file
diff --git a/components/service/fwu/test/metadata_checker/metadata_checker_v2.h b/components/service/fwu/test/metadata_checker/metadata_checker_v2.h
new file mode 100644
index 0000000..76e001d
--- /dev/null
+++ b/components/service/fwu/test/metadata_checker/metadata_checker_v2.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef METADATA_CHECKER_V2_H
+#define METADATA_CHECKER_V2_H
+
+#include "metadata_checker.h"
+
+/*
+ * A metadata_checker for FWU-A V2 metadata
+ */
+class metadata_checker_v2 : public metadata_checker
+{
+public:
+
+	metadata_checker_v2(
+		metadata_fetcher *metadata_fetcher,
+		unsigned int num_images);
+
+	virtual ~metadata_checker_v2();
+
+	void get_active_indices(
+		uint32_t *active_index,
+		uint32_t *previous_active_index);
+
+	void check_regular(unsigned int boot_index);
+	void check_ready_for_staging(unsigned int boot_index);
+	void check_ready_to_activate(unsigned int boot_index);
+	void check_trial(unsigned int boot_index);
+	void check_fallback_to_previous(unsigned int boot_index);
+
+private:
+
+	static unsigned int alternate_bank_index(unsigned int bank_index);
+
+	static const size_t MAX_FWU_METADATA_SIZE;
+};
+
+#endif /* METADATA_CHECKER_V2_H */
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 7f8806c..9414af2 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -112,6 +112,7 @@
 		"components/service/fwu/agent"
 		"components/service/fwu/fw_store/banked"
 		"components/service/fwu/fw_store/banked/metadata_serializer/v1"
+		"components/service/fwu/fw_store/banked/metadata_serializer/v2"
 		"components/service/fwu/fw_store/banked/test"
 		"components/service/fwu/installer"
 		"components/service/fwu/installer/raw"
diff --git a/deployments/ts-service-test/linux-pc/CMakeLists.txt b/deployments/ts-service-test/linux-pc/CMakeLists.txt
index 6014e5d..dc93aa2 100644
--- a/deployments/ts-service-test/linux-pc/CMakeLists.txt
+++ b/deployments/ts-service-test/linux-pc/CMakeLists.txt
@@ -106,6 +106,7 @@
 		"components/service/fwu/agent"
 		"components/service/fwu/fw_store/banked"
 		"components/service/fwu/fw_store/banked/metadata_serializer/v1"
+		"components/service/fwu/fw_store/banked/metadata_serializer/v2"
 		"components/service/fwu/installer"
 		"components/service/fwu/installer/raw"
 		"components/service/fwu/installer/copy"