fiptool: Prepare ground for expanding the set of images at runtime

To allow operating on images with unknown UUIDs, fiptool needs to
be able to track an arbitrary amount of images and not be limited
to the set of images described by the builtin table.

Convert the table to a list to accommodate this scenario.

Change-Id: I0e6d738eece7795d74fc72d165a3098f223d4414
Signed-off-by: dp-arm <dimitris.papastamos@arm.com>
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index 7145815..70921ce 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -51,6 +51,8 @@
 #define OPT_TOC_ENTRY 0
 #define OPT_PLAT_TOC_FLAGS 1
 
+static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid);
+static image_t *lookup_image_from_uuid(const uuid_t *uuid);
 static int info_cmd(int argc, char *argv[]);
 static void info_usage(void);
 static int create_cmd(int argc, char *argv[]);
@@ -77,7 +79,9 @@
 	{ .name = "help",    .handler = help_cmd,    .usage = NULL          },
 };
 
-static image_t *images[MAX_IMAGES];
+static image_desc_t *image_desc_head;
+static size_t nr_image_descs;
+static image_t *image_head;
 static size_t nr_images;
 static uuid_t uuid_null = { 0 };
 static int verbose;
@@ -151,82 +155,141 @@
 	return d;
 }
 
-static void add_image(image_t *image)
+static image_desc_t *new_image_desc(const uuid_t *uuid,
+    const char *name, const char *cmdline_name)
 {
-	if (nr_images + 1 > MAX_IMAGES)
-		log_errx("Too many images");
-	images[nr_images++] = image;
+	image_desc_t *desc;
+
+	desc = xmalloc(sizeof(*desc),
+	    "failed to allocate memory for image descriptor");
+	memcpy(&desc->uuid, uuid, sizeof(uuid_t));
+	desc->name = xstrdup(name,
+	    "failed to allocate memory for image name");
+	desc->cmdline_name = xstrdup(cmdline_name,
+	    "failed to allocate memory for image command line name");
+	desc->action = DO_UNSPEC;
+	desc->action_arg = NULL;
+	return desc;
 }
 
-static void free_image(image_t *image)
+static void free_image_desc(image_desc_t *desc)
 {
-	free(image->buffer);
-	free(image);
+	free(desc->name);
+	free(desc->cmdline_name);
+	free(desc->action_arg);
+	free(desc);
 }
 
-static void replace_image(image_t *image_dst, image_t *image_src)
+static void add_image_desc(image_desc_t *desc)
 {
-	int i;
+	assert(lookup_image_desc_from_uuid(&desc->uuid) == NULL);
+	desc->next = image_desc_head;
+	image_desc_head = desc;
+	nr_image_descs++;
+}
 
-	for (i = 0; i < nr_images; i++) {
-		if (images[i] == image_dst) {
-			free_image(images[i]);
-			images[i] = image_src;
-			break;
-		}
+static void free_image_descs(void)
+{
+	image_desc_t *desc = image_desc_head, *tmp;
+
+	while (desc != NULL) {
+		tmp = desc->next;
+		free_image_desc(desc);
+		desc = tmp;
+		nr_image_descs--;
 	}
-	assert(i != nr_images);
+	assert(nr_image_descs == 0);
 }
 
+static void fill_image_descs(void)
+{
+	toc_entry_t *toc_entry;
+
+	for (toc_entry = toc_entries;
+	     toc_entry->cmdline_name != NULL;
+	     toc_entry++) {
+		image_desc_t *desc;
+
+		desc = new_image_desc(&toc_entry->uuid,
+		    toc_entry->name,
+		    toc_entry->cmdline_name);
+		add_image_desc(desc);
+	}
+}
+
+static void add_image(image_t *image)
+{
+	assert(lookup_image_from_uuid(&image->uuid) == NULL);
+	image->next = image_head;
+	image_head = image;
+	nr_images++;
+}
+
+static void free_image(image_t *image)
+{
+	free(image->buffer);
+	free(image);
+}
+
 static void remove_image(image_t *image)
 {
-	int i;
+	image_t *tmp = image_head, *prev;
 
-	for (i = 0; i < nr_images; i++) {
-		if (images[i] == image) {
-			free_image(images[i]);
-			images[i] = NULL;
-			break;
+	if (tmp == image) {
+		image_head = tmp->next;
+		free_image(tmp);
+	} else {
+		while (tmp != NULL && tmp != image) {
+			prev = tmp;
+			tmp = tmp->next;
 		}
+		assert(tmp != NULL);
+		prev->next = tmp->next;
+		free_image(tmp);
 	}
-	assert(i != nr_images);
-
-	/* Compact array. */
-	memmove(&images[i], &images[i + 1],
-	    (nr_images - i - 1) * sizeof(*images));
 	nr_images--;
 }
 
 static void free_images(void)
 {
-	int i;
+	image_t *image = image_head, *tmp;
 
-	for (i = 0; i < nr_images; i++) {
-		free_image(images[i]);
-		images[i] = NULL;
+	while (image != NULL) {
+		tmp = image->next;
+		free_image(image);
+		image = tmp;
+		nr_images--;
 	}
+	assert(nr_images == 0);
 }
 
-static toc_entry_t *lookup_entry_from_uuid(uuid_t *uuid)
+static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid)
 {
-	toc_entry_t *toc_entry = toc_entries;
+	image_desc_t *desc;
 
-	for (; toc_entry->cmdline_name != NULL; toc_entry++)
-		if (memcmp(&toc_entry->uuid, uuid, sizeof(uuid_t)) == 0)
-			return toc_entry;
+	for (desc = image_desc_head; desc != NULL; desc = desc->next)
+		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
+			return desc;
 	return NULL;
 }
 
-static image_t *lookup_image_from_uuid(uuid_t *uuid)
+static image_desc_t *lookup_image_desc_from_opt(const char *opt)
+{
+	image_desc_t *desc;
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next)
+		if (strcmp(desc->cmdline_name, opt) == 0)
+			return desc;
+	return NULL;
+}
+
+static image_t *lookup_image_from_uuid(const uuid_t *uuid)
 {
 	image_t *image;
-	int i;
 
-	for (i = 0; i < nr_images; i++) {
-		image = images[i];
+	for (image = image_head; image != NULL; image = image->next)
 		if (memcmp(&image->uuid, uuid, sizeof(uuid_t)) == 0)
 			return image;
-	}
 	return NULL;
 }
 
@@ -344,29 +407,32 @@
 	return 0;
 }
 
-static int fill_common_opts(struct option *opts, int has_arg)
+static struct option *add_opt(struct option *opts, size_t *nr_opts,
+    const char *name, int has_arg, int val)
 {
-	int i;
-
-	for (i = 0; toc_entries[i].cmdline_name != NULL; i++) {
-		opts[i].name = toc_entries[i].cmdline_name;
-		opts[i].has_arg = has_arg;
-		opts[i].flag = NULL;
-		opts[i].val = 0;
-	}
-	return i;
+	opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts));
+	if (opts == NULL)
+		log_err("realloc");
+	opts[*nr_opts].name = name;
+	opts[*nr_opts].has_arg = has_arg;
+	opts[*nr_opts].flag = NULL;
+	opts[*nr_opts].val = val;
+	++*nr_opts;
+	return opts;
 }
 
-static void add_opt(struct option *opts, int idx, char *name,
-    int has_arg, int val)
+static struct option *fill_common_opts(struct option *opts, size_t *nr_opts,
+    int has_arg)
 {
-	opts[idx].name = name;
-	opts[idx].has_arg = has_arg;
-	opts[idx].flag = NULL;
-	opts[idx].val = val;
+	image_desc_t *desc;
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next)
+		opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg,
+		    OPT_TOC_ENTRY);
+	return opts;
 }
 
-static void md_print(unsigned char *md, size_t len)
+static void md_print(const unsigned char *md, size_t len)
 {
 	size_t i;
 
@@ -380,7 +446,6 @@
 	uint64_t image_offset;
 	uint64_t image_size = 0;
 	fip_toc_header_t toc_header;
-	int i;
 
 	if (argc != 2)
 		info_usage();
@@ -400,22 +465,21 @@
 	image_offset = sizeof(fip_toc_header_t) +
 	    (sizeof(fip_toc_entry_t) * (nr_images + 1));
 
-	for (i = 0; i < nr_images; i++) {
-		toc_entry_t *toc_entry;
+	for (image = image_head; image != NULL; image = image->next) {
+		image_desc_t *desc;
 
-		image = images[i];
-		toc_entry = lookup_entry_from_uuid(&image->uuid);
-		if (toc_entry != NULL)
-			printf("%s: ", toc_entry->name);
+		desc = lookup_image_desc_from_uuid(&image->uuid);
+		if (desc != NULL)
+			printf("%s: ", desc->name);
 		else
 			printf("Unknown entry: ");
 		image_size = image->size;
 		printf("offset=0x%llX, size=0x%llX",
 		    (unsigned long long)image_offset,
 		    (unsigned long long)image_size);
-		if (toc_entry != NULL)
+		if (desc != NULL)
 			printf(", cmdline=\"--%s\"",
-			    toc_entry->cmdline_name);
+			    desc->cmdline_name);
 		if (verbose) {
 			unsigned char md[SHA256_DIGEST_LENGTH];
 
@@ -437,7 +501,7 @@
 	exit(1);
 }
 
-static int pack_images(char *filename, uint64_t toc_flags)
+static int pack_images(const char *filename, uint64_t toc_flags)
 {
 	FILE *fp;
 	image_t *image;
@@ -445,12 +509,11 @@
 	fip_toc_entry_t *toc_entry;
 	char *buf;
 	uint64_t entry_offset, buf_size, payload_size;
-	int i;
 
 	/* Calculate total payload size and allocate scratch buffer. */
 	payload_size = 0;
-	for (i = 0; i < nr_images; i++)
-		payload_size += images[i]->size;
+	for (image = image_head; image != NULL; image = image->next)
+		payload_size += image->size;
 
 	buf_size = sizeof(fip_toc_header_t) +
 	    sizeof(fip_toc_entry_t) * (nr_images + 1);
@@ -467,8 +530,7 @@
 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
 
 	entry_offset = buf_size;
-	for (i = 0; i < nr_images; i++) {
-		image = images[i];
+	for (image = image_head; image != NULL; image = image->next) {
 		memcpy(&toc_entry->uuid, &image->uuid, sizeof(uuid_t));
 		toc_entry->offset_address = entry_offset;
 		toc_entry->size = image->size;
@@ -498,11 +560,9 @@
 	if (verbose)
 		log_dbgx("Payload size: %zu bytes", payload_size);
 
-	for (i = 0; i < nr_images; i++) {
-		image = images[i];
+	for (image = image_head; image != NULL; image = image->next)
 		if (fwrite(image->buffer, 1, image->size, fp) != image->size)
 			log_errx("Failed to write image to %s", filename);
-	}
 
 	fclose(fp);
 	return 0;
@@ -517,38 +577,35 @@
  */
 static void update_fip(void)
 {
-	toc_entry_t *toc_entry;
+	image_desc_t *desc;
 	image_t *new_image, *old_image;
 
 	/* Add or replace images in the FIP file. */
-	for (toc_entry = toc_entries;
-	     toc_entry->cmdline_name != NULL;
-	     toc_entry++) {
-		if (toc_entry->action != DO_PACK)
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
+		if (desc->action != DO_PACK)
 			continue;
 
-		new_image = read_image_from_file(&toc_entry->uuid,
-		    toc_entry->action_arg);
-		old_image = lookup_image_from_uuid(&toc_entry->uuid);
+		new_image = read_image_from_file(&desc->uuid,
+		    desc->action_arg);
+		old_image = lookup_image_from_uuid(&desc->uuid);
 		if (old_image != NULL) {
-			if (verbose)
+			if (verbose) {
 				log_dbgx("Replacing image %s.bin with %s",
-				    toc_entry->cmdline_name,
-				    toc_entry->action_arg);
-			replace_image(old_image, new_image);
+				    desc->cmdline_name,
+				    desc->action_arg);
+			}
+			remove_image(old_image);
+			add_image(new_image);
 		} else {
 			if (verbose)
 				log_dbgx("Adding image %s",
-				    toc_entry->action_arg);
+				    desc->action_arg);
 			add_image(new_image);
 		}
-
-		free(toc_entry->action_arg);
-		toc_entry->action_arg = NULL;
 	}
 }
 
-static void parse_plat_toc_flags(char *arg, unsigned long long *toc_flags)
+static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
 {
 	unsigned long long flags;
 	char *endptr;
@@ -563,17 +620,17 @@
 
 static int create_cmd(int argc, char *argv[])
 {
-	struct option opts[toc_entries_len + 1];
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
 	unsigned long long toc_flags = 0;
-	int i;
 
 	if (argc < 2)
 		create_usage();
 
-	i = fill_common_opts(opts, required_argument);
-	add_opt(opts, i, "plat-toc-flags", required_argument,
+	opts = fill_common_opts(opts, &nr_opts, required_argument);
+	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
 	    OPT_PLAT_TOC_FLAGS);
-	add_opt(opts, ++i, NULL, 0, 0);
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
 
 	while (1) {
 		int c, opt_index = 0;
@@ -584,11 +641,14 @@
 
 		switch (c) {
 		case OPT_TOC_ENTRY: {
-			toc_entry_t *toc_entry;
+			image_desc_t *desc;
 
-			toc_entry = &toc_entries[opt_index];
-			toc_entry->action = DO_PACK;
-			toc_entry->action_arg = xstrdup(optarg,
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			assert(desc != NULL);
+			if (desc->action != DO_UNSPEC)
+				free(desc->action_arg);
+			desc->action = DO_PACK;
+			desc->action_arg = xstrdup(optarg,
 			    "failed to allocate memory for argument");
 			break;
 		}
@@ -601,6 +661,7 @@
 	}
 	argc -= optind;
 	argv += optind;
+	free(opts);
 
 	if (argc == 0)
 		create_usage();
@@ -629,21 +690,21 @@
 
 static int update_cmd(int argc, char *argv[])
 {
-	struct option opts[toc_entries_len + 2];
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
 	char outfile[FILENAME_MAX] = { 0 };
 	fip_toc_header_t toc_header = { 0 };
 	unsigned long long toc_flags = 0;
 	int pflag = 0;
-	int i;
 
 	if (argc < 2)
 		update_usage();
 
-	i = fill_common_opts(opts, required_argument);
-	add_opt(opts, i, "out", required_argument, 'o');
-	add_opt(opts, ++i, "plat-toc-flags", required_argument,
+	opts = fill_common_opts(opts, &nr_opts, required_argument);
+	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
+	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
 	    OPT_PLAT_TOC_FLAGS);
-	add_opt(opts, ++i, NULL, 0, 0);
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
 
 	while (1) {
 		int c, opt_index = 0;
@@ -654,19 +715,21 @@
 
 		switch (c) {
 		case OPT_TOC_ENTRY: {
-			toc_entry_t *toc_entry;
+			image_desc_t *desc;
 
-			toc_entry = &toc_entries[opt_index];
-			toc_entry->action = DO_PACK;
-			toc_entry->action_arg = xstrdup(optarg,
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			assert(desc != NULL);
+			if (desc->action != DO_UNSPEC)
+				free(desc->action_arg);
+			desc->action = DO_PACK;
+			desc->action_arg = xstrdup(optarg,
 			    "failed to allocate memory for argument");
 			break;
 		}
-		case OPT_PLAT_TOC_FLAGS: {
+		case OPT_PLAT_TOC_FLAGS:
 			parse_plat_toc_flags(optarg, &toc_flags);
 			pflag = 1;
 			break;
-		}
 		case 'o':
 			snprintf(outfile, sizeof(outfile), "%s", optarg);
 			break;
@@ -676,6 +739,7 @@
 	}
 	argc -= optind;
 	argv += optind;
+	free(opts);
 
 	if (argc == 0)
 		update_usage();
@@ -716,20 +780,20 @@
 
 static int unpack_cmd(int argc, char *argv[])
 {
-	struct option opts[toc_entries_len + 3];
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
 	char file[FILENAME_MAX], outdir[PATH_MAX] = { 0 };
-	toc_entry_t *toc_entry;
+	image_desc_t *desc;
 	int fflag = 0;
 	int unpack_all = 1;
-	int i;
 
 	if (argc < 2)
 		unpack_usage();
 
-	i = fill_common_opts(opts, required_argument);
-	add_opt(opts, i, "force", no_argument, 'f');
-	add_opt(opts, ++i, "out", required_argument, 'o');
-	add_opt(opts, ++i, NULL, 0, 0);
+	opts = fill_common_opts(opts, &nr_opts, required_argument);
+	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
+	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
 
 	while (1) {
 		int c, opt_index = 0;
@@ -739,13 +803,19 @@
 			break;
 
 		switch (c) {
-		case OPT_TOC_ENTRY:
-			unpack_all = 0;
-			toc_entry = &toc_entries[opt_index];
-			toc_entry->action = DO_UNPACK;
-			toc_entry->action_arg = xstrdup(optarg,
+		case OPT_TOC_ENTRY: {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			assert(desc != NULL);
+			if (desc->action != DO_UNSPEC)
+				free(desc->action_arg);
+			desc->action = DO_UNPACK;
+			desc->action_arg = xstrdup(optarg,
 			    "failed to allocate memory for argument");
+			unpack_all = 0;
 			break;
+		}
 		case 'f':
 			fflag = 1;
 			break;
@@ -758,6 +828,7 @@
 	}
 	argc -= optind;
 	argv += optind;
+	free(opts);
 
 	if (argc == 0)
 		unpack_usage();
@@ -769,29 +840,25 @@
 			log_err("chdir %s", outdir);
 
 	/* Unpack all specified images. */
-	for (toc_entry = toc_entries;
-	     toc_entry->cmdline_name != NULL;
-	     toc_entry++) {
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
 		image_t *image;
 
-		if (!unpack_all && toc_entry->action != DO_UNPACK)
+		if (!unpack_all && desc->action != DO_UNPACK)
 			continue;
 
 		/* Build filename. */
-		if (toc_entry->action_arg == NULL)
+		if (desc->action_arg == NULL)
 			snprintf(file, sizeof(file), "%s.bin",
-			    toc_entry->cmdline_name);
+			    desc->cmdline_name);
 		else
 			snprintf(file, sizeof(file), "%s",
-			    toc_entry->action_arg);
+			    desc->action_arg);
 
-		image = lookup_image_from_uuid(&toc_entry->uuid);
+		image = lookup_image_from_uuid(&desc->uuid);
 		if (image == NULL) {
 			if (!unpack_all)
 				log_warnx("Requested image %s is not in %s",
 				    file, argv[0]);
-			free(toc_entry->action_arg);
-			toc_entry->action_arg = NULL;
 			continue;
 		}
 
@@ -803,9 +870,6 @@
 			log_warnx("File %s already exists, use --force to overwrite it",
 			    file);
 		}
-
-		free(toc_entry->action_arg);
-		toc_entry->action_arg = NULL;
 	}
 
 	free_images();
@@ -832,20 +896,20 @@
 
 static int remove_cmd(int argc, char *argv[])
 {
-	struct option opts[toc_entries_len + 2];
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
 	char outfile[FILENAME_MAX] = { 0 };
 	fip_toc_header_t toc_header;
-	toc_entry_t *toc_entry;
+	image_desc_t *desc;
 	int fflag = 0;
-	int i;
 
 	if (argc < 2)
 		remove_usage();
 
-	i = fill_common_opts(opts, no_argument);
-	add_opt(opts, i, "force", no_argument, 'f');
-	add_opt(opts, ++i, "out", required_argument, 'o');
-	add_opt(opts, ++i, NULL, 0, 0);
+	opts = fill_common_opts(opts, &nr_opts, no_argument);
+	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
+	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
 
 	while (1) {
 		int c, opt_index = 0;
@@ -855,10 +919,15 @@
 			break;
 
 		switch (c) {
-		case OPT_TOC_ENTRY:
-			toc_entry = &toc_entries[opt_index];
-			toc_entry->action = DO_REMOVE;
+		case OPT_TOC_ENTRY: {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			assert(desc != NULL);
+			desc->action = DO_REMOVE;
+			desc->action_arg = NULL;
 			break;
+		}
 		case 'f':
 			fflag = 1;
 			break;
@@ -871,6 +940,7 @@
 	}
 	argc -= optind;
 	argv += optind;
+	free(opts);
 
 	if (argc == 0)
 		remove_usage();
@@ -884,22 +954,20 @@
 
 	parse_fip(argv[0], &toc_header);
 
-	for (toc_entry = toc_entries;
-	     toc_entry->cmdline_name != NULL;
-	     toc_entry++) {
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
 		image_t *image;
 
-		if (toc_entry->action != DO_REMOVE)
+		if (desc->action != DO_REMOVE)
 			continue;
-		image = lookup_image_from_uuid(&toc_entry->uuid);
+		image = lookup_image_from_uuid(&desc->uuid);
 		if (image != NULL) {
 			if (verbose)
 				log_dbgx("Removing %s.bin",
-				    toc_entry->cmdline_name);
+				    desc->cmdline_name);
 			remove_image(image);
 		} else {
 			log_warnx("Requested image %s.bin is not in %s",
-			    toc_entry->cmdline_name, argv[0]);
+			    desc->cmdline_name, argv[0]);
 		}
 	}
 
@@ -1011,6 +1079,7 @@
 	if (argc == 0)
 		usage();
 
+	fill_image_descs();
 	for (i = 0; i < NELEM(cmds); i++) {
 		if (strcmp(cmds[i].name, argv[0]) == 0) {
 			ret = cmds[i].handler(argc, argv);
@@ -1019,5 +1088,6 @@
 	}
 	if (i == NELEM(cmds))
 		usage();
+	free_image_descs();
 	return ret;
 }
diff --git a/tools/fiptool/fiptool.h b/tools/fiptool/fiptool.h
index 7705107..6ace400 100644
--- a/tools/fiptool/fiptool.h
+++ b/tools/fiptool/fiptool.h
@@ -38,10 +38,8 @@
 
 #define NELEM(x) (sizeof (x) / sizeof *(x))
 
-/* TODO: Do not hardcode, use realloc() */
-#define MAX_IMAGES 32
-
 enum {
+	DO_UNSPEC = 0,
 	DO_PACK   = 1,
 	DO_UNPACK = 2,
 	DO_REMOVE = 3
@@ -53,16 +51,26 @@
 	LOG_ERR
 };
 
+typedef struct image_desc {
+	uuid_t             uuid;
+	char              *name;
+	char              *cmdline_name;
+	int                action;
+	char              *action_arg;
+	struct image_desc *next;
+} image_desc_t;
+
 typedef struct image {
-	uuid_t            uuid;
-	size_t            size;
-	void             *buffer;
+	uuid_t             uuid;
+	size_t             size;
+	void              *buffer;
+	struct image      *next;
 } image_t;
 
 typedef struct cmd {
-	char             *name;
-	int             (*handler)(int, char **);
-	void            (*usage)(void);
+	char              *name;
+	int              (*handler)(int, char **);
+	void             (*usage)(void);
 } cmd_t;
 
 #endif /* __FIPTOOL_H__ */
diff --git a/tools/fiptool/tbbr_config.c b/tools/fiptool/tbbr_config.c
index b92e8da..c4b5519 100644
--- a/tools/fiptool/tbbr_config.c
+++ b/tools/fiptool/tbbr_config.c
@@ -38,151 +38,111 @@
 	{
 		.name = "SCP Firmware Updater Configuration FWU SCP_BL2U",
 		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
-		.cmdline_name = "scp-fwu-cfg",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "scp-fwu-cfg"
 	},
 	{
 		.name = "AP Firmware Updater Configuration BL2U",
 		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
-		.cmdline_name = "ap-fwu-cfg",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "ap-fwu-cfg"
 	},
 	{
 		.name = "Firmware Updater NS_BL2U",
 		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
-		.cmdline_name = "fwu",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "fwu"
 	},
 	{
 		.name = "Non-Trusted Firmware Updater certificate",
 		.uuid = UUID_TRUSTED_FWU_CERT,
-		.cmdline_name = "fwu-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "fwu-cert"
 	},
 	{
 		.name = "Trusted Boot Firmware BL2",
 		.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
-		.cmdline_name = "tb-fw",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "tb-fw"
 	},
 	{
 		.name = "SCP Firmware SCP_BL2",
 		.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
-		.cmdline_name = "scp-fw",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "scp-fw"
 	},
 	{
 		.name = "EL3 Runtime Firmware BL31",
 		.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
-		.cmdline_name = "soc-fw",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "soc-fw"
 	},
 	{
 		.name = "Secure Payload BL32 (Trusted OS)",
 		.uuid = UUID_SECURE_PAYLOAD_BL32,
-		.cmdline_name = "tos-fw",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "tos-fw"
 	},
 	{
 		.name = "Non-Trusted Firmware BL33",
 		.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
-		.cmdline_name = "nt-fw",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "nt-fw"
 	},
+
 	/* Key Certificates */
 	{
 		.name = "Root Of Trust key certificate",
 		.uuid = UUID_ROT_KEY_CERT,
-		.cmdline_name = "rot-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "rot-cert"
 	},
 	{
 		.name = "Trusted key certificate",
 		.uuid = UUID_TRUSTED_KEY_CERT,
-		.cmdline_name = "trusted-key-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "trusted-key-cert"
 	},
 	{
 		.name = "SCP Firmware key certificate",
 		.uuid = UUID_SCP_FW_KEY_CERT,
-		.cmdline_name = "scp-fw-key-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "scp-fw-key-cert"
 	},
 	{
 		.name = "SoC Firmware key certificate",
 		.uuid = UUID_SOC_FW_KEY_CERT,
-		.cmdline_name = "soc-fw-key-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "soc-fw-key-cert"
 	},
 	{
 		.name = "Trusted OS Firmware key certificate",
 		.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
-		.cmdline_name = "tos-fw-key-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "tos-fw-key-cert"
 	},
 	{
 		.name = "Non-Trusted Firmware key certificate",
 		.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
-		.cmdline_name = "nt-fw-key-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "nt-fw-key-cert"
 	},
+
 	/* Content certificates */
 	{
 		.name = "Trusted Boot Firmware BL2 certificate",
 		.uuid = UUID_TRUSTED_BOOT_FW_CERT,
-		.cmdline_name = "tb-fw-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "tb-fw-cert"
 	},
 	{
 		.name = "SCP Firmware content certificate",
 		.uuid = UUID_SCP_FW_CONTENT_CERT,
-		.cmdline_name = "scp-fw-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "scp-fw-cert"
 	},
 	{
 		.name = "SoC Firmware content certificate",
 		.uuid = UUID_SOC_FW_CONTENT_CERT,
-		.cmdline_name = "soc-fw-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "soc-fw-cert"
 	},
 	{
 		.name = "Trusted OS Firmware content certificate",
 		.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
-		.cmdline_name = "tos-fw-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "tos-fw-cert"
 	},
 	{
 		.name = "Non-Trusted Firmware content certificate",
 		.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
-		.cmdline_name = "nt-fw-cert",
-		.action = 0,
-		.action_arg = NULL
+		.cmdline_name = "nt-fw-cert"
 	},
 	{
 		.name = NULL,
 		.uuid = { 0 },
 		.cmdline_name = NULL,
-		.action = 0,
-		.action_arg = NULL
 	}
 };
 
diff --git a/tools/fiptool/tbbr_config.h b/tools/fiptool/tbbr_config.h
index c459335..0cf8e7f 100644
--- a/tools/fiptool/tbbr_config.h
+++ b/tools/fiptool/tbbr_config.h
@@ -39,11 +39,9 @@
 #define TOC_HEADER_SERIAL_NUMBER 0x12345678
 
 typedef struct toc_entry {
-	const char   *name;
+	char         *name;
 	uuid_t        uuid;
-	const char   *cmdline_name;
-	int           action;
-	char         *action_arg;
+	char         *cmdline_name;
 } toc_entry_t;
 
 extern toc_entry_t toc_entries[];