Add update agent implementation

Adds an implementation of the generic update agent component. This
implements the FWU state machine that ensures that a valid update
sequence is followed.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Icf51b6527f1f84eb0f693e1629f4d2b3b075d43a
diff --git a/components/service/fwu/agent/img_dir_serializer.c b/components/service/fwu/agent/img_dir_serializer.c
new file mode 100644
index 0000000..db210bc
--- /dev/null
+++ b/components/service/fwu/agent/img_dir_serializer.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <protocols/service/fwu/packed-c/fwu_proto.h>
+#include <service/fwu/fw_store/fw_store.h>
+#include "fw_directory.h"
+#include "img_dir_serializer.h"
+
+int img_dir_serializer_serialize(
+	const struct fw_directory *fw_dir,
+	const struct fw_store *fw_store,
+	uint8_t *buf,
+	size_t buf_size,
+	size_t *data_len)
+{
+	size_t serialized_len = img_dir_serializer_get_len(fw_dir);
+
+	*data_len = 0;
+
+	if (buf_size < serialized_len)
+		return FWU_STATUS_OUT_OF_BOUNDS;
+
+	struct ts_fwu_image_directory *output = (struct ts_fwu_image_directory *)buf;
+
+	/* Clear the output buffer */
+	memset(buf, 0, serialized_len);
+
+	/* Serialize boot info */
+	const struct boot_info *boot_info = fw_directory_get_boot_info(fw_dir);
+
+	assert(boot_info);
+
+	output->directory_version = 2;
+	output->img_info_offset = offsetof(struct ts_fwu_image_directory, img_info_entry);
+	output->num_images = fw_directory_num_images(fw_dir);
+	output->correct_boot = (boot_info->active_index == boot_info->boot_index);
+	output->img_info_size = sizeof(struct ts_fwu_image_info_entry);
+	output->reserved = 0;
+
+	/* Serialize image info for each image */
+	for (size_t image_index = 0; image_index < output->num_images; image_index++) {
+
+		const struct image_info *image_info =
+			fw_directory_get_image_info(fw_dir, image_index);
+
+		assert(image_info);
+
+		memcpy(output->img_info_entry[image_index].img_type_uuid,
+			image_info->img_type_uuid.octets,
+			OSF_UUID_OCTET_LEN);
+
+		output->img_info_entry[image_index].client_permissions =
+			image_info->permissions;
+		output->img_info_entry[image_index].img_max_size =
+			image_info->max_size;
+		output->img_info_entry[image_index].lowest_accepted_version =
+			image_info->lowest_accepted_version;
+		output->img_info_entry[image_index].img_version =
+			image_info->active_version;
+		output->img_info_entry[image_index].accepted =
+			(uint32_t)fw_store_is_accepted(fw_store, image_info);
+	}
+
+	*data_len = serialized_len;
+
+	return FWU_STATUS_SUCCESS;
+}
+
+size_t img_dir_serializer_get_len(
+	const struct fw_directory *fw_dir)
+{
+	return
+		offsetof(struct ts_fwu_image_directory, img_info_entry) +
+		sizeof(struct ts_fwu_image_info_entry) * fw_directory_num_images(fw_dir);
+}