mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH] Import ARM Trusted Firmware fiptool utility
@ 2025-01-09 11:25 Ahmad Fatoum
  0 siblings, 0 replies; only message in thread
From: Ahmad Fatoum @ 2025-01-09 11:25 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

On some platforms like the STM32MP, barebox is located in a FIP binary.
For network booting, interacting with the FIP can be quite useful,
so as first step port fiptool(1) to barebox.

Later, we can build a bootm handler or maybe a file system on top.

For now, the command is sufficient to unpack the FIP and manually boot
the artifacts.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 commands/Kconfig   |  18 ++
 commands/Makefile  |   1 +
 commands/fiptool.c | 644 +++++++++++++++++++++++++++++++++++++++++++++
 include/fip.h      | 111 ++++++++
 include/fiptool.h  |  87 ++++++
 lib/Kconfig        |   3 +
 lib/Makefile       |   1 +
 lib/fip.c          | 426 ++++++++++++++++++++++++++++++
 lib/tbbr_config.c  | 204 ++++++++++++++
 9 files changed, 1495 insertions(+)
 create mode 100644 commands/fiptool.c
 create mode 100644 include/fip.h
 create mode 100644 include/fiptool.h
 create mode 100644 lib/fip.c
 create mode 100644 lib/tbbr_config.c

diff --git a/commands/Kconfig b/commands/Kconfig
index 5e4116c90f2f..84d1b629f0c1 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1163,6 +1163,24 @@ config CMD_SHA512SUM
 
 	  Calculate a SHA512 digest over a FILE or a memory area.
 
+config CMD_FIPTOOL
+	bool
+	select FIP
+	prompt "fiptool"
+	help
+	  Manipulate and inspect TF-A Firmware Image Packages.
+
+config CMD_FIPTOOL_WRITE
+	bool
+	depends on CMD_FIPTOOL
+	prompt "support create/update/remove subcommands to fiptool"
+	help
+	  Adds following subcommands that manipulate FIP files:
+
+	  fiptool create # Create a new FIP with the given images
+	  fiptool update # Update an existing FIP with the given images
+	  fiptool remove # Remove images from FIP
+
 config CMD_UNCOMPRESS
 	bool
 	select UNCOMPRESS
diff --git a/commands/Makefile b/commands/Makefile
index 6957d78295ec..2bc5ab8bfe9f 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_USB_GADGET_DFU)	+= dfu.o
 obj-$(CONFIG_USB_GADGET_SERIAL)	+= usbserial.o
 obj-$(CONFIG_CMD_GPIO)		+= gpio.o
 obj-$(CONFIG_CMD_UNCOMPRESS)	+= uncompress.o
+obj-$(CONFIG_CMD_FIPTOOL)	+= fiptool.o
 obj-$(CONFIG_CMD_I2C)		+= i2c.o
 obj-$(CONFIG_CMD_SPI)		+= spi.o
 obj-$(CONFIG_CMD_PWM)		+= pwm.o
diff --git a/commands/fiptool.c b/commands/fiptool.c
new file mode 100644
index 000000000000..2d766f895bc1
--- /dev/null
+++ b/commands/fiptool.c
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Imported from TF-A v2.10.0
+ */
+
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/log2.h>
+#include <linux/stat.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <libfile.h>
+#include <unistd.h>
+#include <command.h>
+#include <malloc.h>
+#include <crypto/sha.h>
+#include <linux/kstrtox.h>
+#include <digest.h>
+#include <stdio.h>
+
+#include <fip.h>
+#include <fiptool.h>
+
+typedef struct cmd {
+	char              *name;
+	int              (*handler)(struct fip_state *fip, int, char **);
+	void             (*usage)(int);
+} cmd_t;
+
+
+static int write_image_to_file(const image_t *image, const char *filename)
+{
+	int fd;
+
+	fd = creat(filename, 0777);
+	if (fd < 0) {
+		pr_err("creat %s: %m\n", filename);
+		return -errno;
+	}
+
+	if (write_full(fd, image->buffer, image->toc_e.size) < 0) {
+		pr_err("Failed to write %s: %m\n", filename);
+		return -errno;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int info_cmd(struct fip_state *fip, int argc, char *argv[])
+{
+	image_desc_t *desc;
+	fip_toc_header_t toc_header;
+	int ret;
+
+	if (argc != 2)
+		return COMMAND_ERROR_USAGE;
+
+	argc--, argv++;
+
+	ret = parse_fip(fip, argv[0], &toc_header);
+	if (ret)
+		return ret;
+
+	pr_verbose("toc_header[name]: 0x%llX\n",
+	    (unsigned long long)toc_header.name);
+	pr_verbose("toc_header[serial_number]: 0x%llX\n",
+	    (unsigned long long)toc_header.serial_number);
+	pr_verbose("toc_header[flags]: 0x%llX\n",
+	    (unsigned long long)toc_header.flags);
+
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image = desc->image;
+
+		if (image == NULL)
+			continue;
+		printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"-e %s\"",
+		       desc->name,
+		       (unsigned long long)image->toc_e.offset_address,
+		       (unsigned long long)image->toc_e.size,
+		       desc->cmdline_name);
+
+		/*
+		 * Omit this informative code portion for:
+		 * Visual Studio missing SHA256.
+		 * Statically linked builds.
+		 */
+		if (IS_ENABLED(CONFIG_HAVE_DIGEST_SHA256) && fip->verbose) {
+			struct digest *sha256;
+			unsigned char md[SHA256_DIGEST_SIZE];
+			int err;
+
+			sha256 = digest_alloc("sha256");
+			if (!sha256)
+				continue;
+
+			err = digest_digest(sha256, image->buffer, image->toc_e.size, md);
+			if (err)
+				continue;
+
+			digest_free(sha256);
+
+			printf(", sha256=%*phN", (int)sizeof(md), md);
+		}
+		putchar('\n');
+	}
+
+	return 0;
+}
+
+
+static int uuid_cmd(struct fip_state *fip, int argc, char *argv[])
+{
+	for (toc_entry_t *t = toc_entries; t->cmdline_name != NULL; t++)
+		printf("%pU\t%-16s\t%s\n", &t->uuid, t->cmdline_name, t->name);
+	for (toc_entry_t *t = plat_def_toc_entries; t->cmdline_name != NULL; t++)
+		printf("%pU\t%-16s\t%s\n", &t->uuid, t->cmdline_name, t->name);
+	return 0;
+}
+
+
+static int parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
+{
+	unsigned long long flags;
+	char *endptr;
+
+	errno = 0;
+	flags = simple_strtoull(arg, &endptr, 16);
+	if (*endptr != '\0' || flags > U16_MAX) {
+		pr_err("Invalid platform ToC flags: %s\n", arg);
+		return -1;
+	}
+	/* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
+	*toc_flags |= flags << 32;
+
+	return 0;
+}
+
+static long get_image_align(char *arg)
+{
+	char *endptr;
+	long align;
+
+	errno = 0;
+	align = simple_strtol(arg, &endptr, 0);
+	if (*endptr != '\0' || align < 0 || !is_power_of_2(align)) {
+		pr_err("Invalid alignment: %s\n", arg);
+		return -1;
+	}
+
+	return align;
+}
+
+static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
+{
+	char *p, *val;
+
+	while ((p = strsep(&arg, ",")) != NULL) {
+		val = p + str_has_prefix(p, "uuid=");
+		if (val != p) {
+			uuid_parse(val, uuid);
+			continue;
+		}
+
+		val = p + str_has_prefix(p, "file=");
+		if (val != p) {
+			snprintf(filename, len, "%s", val);
+			continue;
+		}
+	}
+}
+
+static inline bool file_exists(const char *filename)
+{
+	struct stat st;
+
+	return stat(filename, &st) == 0;
+}
+
+static __maybe_unused int create_cmd(struct fip_state *fip, int argc, char *argv[])
+{
+	unsigned long long toc_flags = 0;
+	long align = 1;
+	int opt;
+
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
+
+	while ((opt = getopt(argc, argv, "e:p:a:b:")) > 0) {
+		switch (opt) {
+		case 'e': {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(fip, &optarg);
+			if (!desc)
+				return COMMAND_ERROR;
+			set_image_desc_action(desc, DO_PACK, optarg);
+			break;
+		}
+		case 'p':
+			if (parse_plat_toc_flags(optarg, &toc_flags))
+				return COMMAND_ERROR;
+			break;
+		case 'a':
+			align = get_image_align(optarg);
+			if (align < 0)
+				return COMMAND_ERROR;
+			break;
+		case 'b': {
+			char name[UUID_STRING_LEN + 1];
+			char filename[PATH_MAX] = { 0 };
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
+			    filename[0] == '\0')
+				return COMMAND_ERROR_USAGE;
+
+			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			if (desc == NULL) {
+				snprintf(name, sizeof(name), "%pU", &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(fip, desc);
+			}
+			set_image_desc_action(desc, DO_PACK, filename);
+			break;
+		}
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		return COMMAND_ERROR_USAGE;
+
+	if (update_fip(fip))
+		return COMMAND_ERROR;
+
+	return pack_images(fip, argv[0], toc_flags, align);
+}
+
+
+static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv[])
+{
+	char outfile[PATH_MAX] = { 0 };
+	fip_toc_header_t toc_header = { 0 };
+	unsigned long long toc_flags = 0;
+	long align = 1;
+	int pflag = 0;
+	int ret, opt;
+
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
+
+	while ((opt = getopt(argc, argv, "e:p:b:a:o:")) > 0) {
+		switch (opt) {
+		case 'e': {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(fip, &optarg);
+			if (!desc)
+				return COMMAND_ERROR;
+			set_image_desc_action(desc, DO_PACK, optarg);
+			break;
+		}
+		case 'p':
+			if (parse_plat_toc_flags(optarg, &toc_flags))
+				return COMMAND_ERROR;
+			pflag = 1;
+			break;
+		case 'b': {
+			char name[UUID_STRING_LEN + 1];
+			char filename[PATH_MAX] = { 0 };
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
+			    filename[0] == '\0')
+				return COMMAND_ERROR_USAGE;
+
+			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			if (desc == NULL) {
+				snprintf(name, sizeof(name), "%pU", &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(fip, desc);
+			}
+			set_image_desc_action(desc, DO_PACK, filename);
+			break;
+		}
+		case 'a':
+			align = get_image_align(optarg);
+			if (align < 0)
+				return COMMAND_ERROR;
+			break;
+		case 'o':
+			snprintf(outfile, sizeof(outfile), "%s", optarg);
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		return COMMAND_ERROR_USAGE;
+
+	if (outfile[0] == '\0')
+		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
+
+	if (file_exists(argv[0])) {
+		ret = parse_fip(fip, argv[0], &toc_header);
+		if (ret)
+			return ret;
+	}
+
+	if (pflag)
+		toc_header.flags &= ~(0xffffULL << 32);
+	toc_flags = (toc_header.flags |= toc_flags);
+
+	if (update_fip(fip))
+		return COMMAND_ERROR;
+
+	return pack_images(fip, outfile, toc_flags, align);
+}
+
+static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
+{
+	char outdir[PATH_MAX] = { 0 };
+	image_desc_t *desc;
+	int fflag = 0;
+	int unpack_all = 1;
+	int ret, opt;
+
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
+
+	while ((opt = getopt(argc, argv, "e:b:fo:")) > 0) {
+		switch (opt) {
+		case 'e': {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(fip, &optarg);
+			if (!desc)
+				return COMMAND_ERROR;
+			set_image_desc_action(desc, DO_UNPACK, optarg);
+			unpack_all = 0;
+			break;
+		}
+		case 'b': {
+			char name[UUID_STRING_LEN + 1];
+			char filename[PATH_MAX] = { 0 };
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
+			    filename[0] == '\0')
+				return COMMAND_ERROR_USAGE;
+
+			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			if (desc == NULL) {
+				snprintf(name, sizeof(name), "%pU", &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(fip, desc);
+			}
+			set_image_desc_action(desc, DO_UNPACK, filename);
+			unpack_all = 0;
+			break;
+		}
+		case 'f':
+			fflag = 1;
+			break;
+		case 'o':
+			snprintf(outdir, sizeof(outdir), "%s", optarg);
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		return COMMAND_ERROR_USAGE;
+
+	ret = parse_fip(fip, argv[0], NULL);
+	if (ret)
+		return ret;
+
+	if (outdir[0] != '\0')
+		if (chdir(outdir) == -1) {
+			pr_err("chdir %s: %m\n", outdir);
+			return COMMAND_ERROR;
+		}
+
+	/* Unpack all specified images. */
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+		char file[PATH_MAX];
+		image_t *image = desc->image;
+
+		if (!unpack_all && desc->action != DO_UNPACK)
+			continue;
+
+		/* Build filename. */
+		if (desc->action_arg == NULL)
+			snprintf(file, sizeof(file), "%s.bin",
+			    desc->cmdline_name);
+		else
+			snprintf(file, sizeof(file), "%s",
+			    desc->action_arg);
+
+		if (image == NULL) {
+			if (!unpack_all)
+				pr_warn("%s does not exist in %s\n", file, argv[0]);
+			continue;
+		}
+
+		if (!file_exists(file) || fflag) {
+			pr_verbose("Unpacking %s\n", file);
+			ret = write_image_to_file(image, file);
+			if (ret)
+				return ret;
+		} else {
+			pr_warn("File %s already exists, use -f to overwrite it\n", file);
+		}
+	}
+
+	return 0;
+}
+
+static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv[])
+{
+	char outfile[PATH_MAX] = { 0 };
+	fip_toc_header_t toc_header;
+	image_desc_t *desc;
+	long align = 1;
+	int ret, opt, fflag = 0;
+
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
+
+	while ((opt = getopt(argc, argv, "e:a:b:fo:")) > 0) {
+		switch (opt) {
+		case 'e': {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(fip, &optarg);
+			if (!desc)
+				return COMMAND_ERROR;
+			set_image_desc_action(desc, DO_REMOVE, NULL);
+			break;
+		}
+		case 'a':
+			align = get_image_align(optarg);
+			if (align < 0)
+				return COMMAND_ERROR;
+			break;
+		case 'b': {
+			char name[UUID_STRING_LEN + 1], filename[PATH_MAX];
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
+				return COMMAND_ERROR_USAGE;
+
+			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			if (desc == NULL) {
+				snprintf(name, sizeof(name), "%pU", &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(fip, desc);
+			}
+			set_image_desc_action(desc, DO_REMOVE, NULL);
+			break;
+		}
+		case 'f':
+			fflag = 1;
+			break;
+		case 'o':
+			snprintf(outfile, sizeof(outfile), "%s", optarg);
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		return COMMAND_ERROR_USAGE;
+
+	if (outfile[0] != '\0' && file_exists(outfile) && !fflag)
+		pr_err("File %s already exists, use -f to overwrite it\n",
+		    outfile);
+
+	if (outfile[0] == '\0')
+		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
+
+	ret = parse_fip(fip, argv[0], &toc_header);
+	if (ret)
+		return ret;
+
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+		if (desc->action != DO_REMOVE)
+			continue;
+
+		if (desc->image != NULL) {
+			pr_verbose("Removing %s\n", desc->cmdline_name);
+			free(desc->image);
+			desc->image = NULL;
+		} else {
+			pr_warn("%s does not exist in %s\n", desc->cmdline_name, argv[0]);
+		}
+	}
+
+	return pack_images(fip, outfile, toc_header.flags, align);
+}
+
+/* Available subcommands. */
+static cmd_t cmds[] = {
+	{ .name = "info",    .handler = info_cmd,    },
+	{ .name = "uuid",    .handler = uuid_cmd,    },
+	{ .name = "unpack",  .handler = unpack_cmd,  },
+#ifdef CONFIG_CMD_FIPTOOL_WRITE
+	{ .name = "create",  .handler = create_cmd,  },
+	{ .name = "update",  .handler = update_cmd,  },
+	{ .name = "remove",  .handler = remove_cmd,  },
+#endif
+};
+
+static int do_fiptool(int argc, char *argv[])
+{
+	int i, opt, ret = 0;
+	struct fip_state fip = {};
+
+	/*
+	 * Set POSIX mode so getopt stops at the first non-option
+	 * which is the subcommand.
+	 */
+	while ((opt = getopt(argc, argv, "+v")) > 0) {
+		switch (opt) {
+		case 'v':
+			fip.verbose = 1;
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		return COMMAND_ERROR_USAGE;
+
+	fill_image_descs(&fip);
+	for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+		if (strcmp(cmds[i].name, argv[0]) == 0) {
+			struct getopt_context gc;
+
+			getopt_context_store(&gc);
+
+			ret = cmds[i].handler(&fip, argc, argv);
+
+			getopt_context_restore(&gc);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(cmds))
+		return COMMAND_ERROR_USAGE;
+	free_image_descs(&fip);
+	return ret;
+}
+
+BAREBOX_CMD_HELP_START(fiptool)
+BAREBOX_CMD_HELP_TEXT("List information about the specified files or directories")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Global options:")
+BAREBOX_CMD_HELP_OPT ("-v",  "verbose output")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Commands:")
+BAREBOX_CMD_HELP_OPT("info",   "List images contained in FIP")
+BAREBOX_CMD_HELP_OPT("uuid",   "List possible FIP image types and their UUIDs")
+BAREBOX_CMD_HELP_OPT("unpack", "Unpack images from FIP")
+#ifdef CONFIG_CMD_FIPTOOL_WRITE
+BAREBOX_CMD_HELP_OPT("create", "Create a new FIP with the given images")
+BAREBOX_CMD_HELP_OPT("update", "Update an existing FIP with the given images")
+BAREBOX_CMD_HELP_OPT("remove", "Remove images from FIP")
+#endif
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("fiptool unpack [OPTS] FIP_FILENAME")
+BAREBOX_CMD_HELP_OPT("-a VALUE", "Each image is aligned to VALUE (default: 1)")
+BAREBOX_CMD_HELP_OPT("-b uuid=UUID,file=FILE", "Unpack an image with the given UUID into FILE")
+BAREBOX_CMD_HELP_OPT("-f", "force overwrite of the output FIP file if it already exists")
+BAREBOX_CMD_HELP_OPT("-o", "Set an alternative output FIP file")
+BAREBOX_CMD_HELP_OPT("-e TYPE[=FILE]", "unpack only TYPE entry")
+#ifdef CONFIG_CMD_FIPTOOL_WRITE
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("fiptool create [OPTS] FIP_FILENAME")
+BAREBOX_CMD_HELP_OPT("-a VALUE", "Each image is aligned to VALUE (default: 1)")
+BAREBOX_CMD_HELP_OPT("-b uuid=UUID,file=FILE", "Add an image with the given UUID pointed to by FILE")
+BAREBOX_CMD_HELP_OPT("-p", "16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header")
+BAREBOX_CMD_HELP_OPT("-e TYPE[=FILE]", "add TYPE entry from FILE")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("fiptool update [OPTS] FIP_FILENAME")
+BAREBOX_CMD_HELP_OPT("-a VALUE", "Each image is aligned to VALUE (default: 1)")
+BAREBOX_CMD_HELP_OPT("-b uuid=UUID,file=FILE", "Add an image with the given UUID pointed to by FILE")
+BAREBOX_CMD_HELP_OPT("-o", "Set an alternative output FIP file")
+BAREBOX_CMD_HELP_OPT("-p", "16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header")
+BAREBOX_CMD_HELP_OPT("-e TYPE[=FILE]", "update TYPE entry with FILE")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("fiptool remove [OPTS] FIP_FILENAME")
+BAREBOX_CMD_HELP_OPT("-a VALUE", "Each image is aligned to VALUE (default: 1)")
+BAREBOX_CMD_HELP_OPT("-b uuid=UUID", "Remove an image with the given UUID")
+BAREBOX_CMD_HELP_OPT("-f", "force overwrit of the output FIP file if it already exists")
+BAREBOX_CMD_HELP_OPT("-o", "Set an alternative output FIP file")
+BAREBOX_CMD_HELP_OPT("-e TYPE", "remove TYPE entry")
+#endif
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(fiptool)
+	.cmd		= do_fiptool,
+	BAREBOX_CMD_DESC("inspect and manipulate TF-A firmware image packages")
+	BAREBOX_CMD_OPTS("[-v] COMMAND [ARGS...]")
+	BAREBOX_CMD_GROUP(CMD_GRP_BOOT)
+	BAREBOX_CMD_HELP(cmd_fiptool_help)
+BAREBOX_CMD_END
diff --git a/include/fip.h b/include/fip.h
new file mode 100644
index 000000000000..a5d3e507fb34
--- /dev/null
+++ b/include/fip.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIRMWARE_IMAGE_PACKAGE_H
+#define FIRMWARE_IMAGE_PACKAGE_H
+
+#include <linux/uuid.h>
+#include <linux/types.h>
+
+/* This is used as a signature to validate the blob header */
+#define TOC_HEADER_NAME	0xAA640001
+
+
+/* ToC Entry UUIDs */
+#define UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U \
+	UUID_INIT(0x65922703, 0x2f74, 0xe644, 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10)
+#define UUID_TRUSTED_UPDATE_FIRMWARE_BL2U \
+	UUID_INIT(0x60b3eb37, 0xc1e5, 0xea41, 0x9d, 0xf3, 0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01)
+#define UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U \
+	UUID_INIT(0x4f511d11, 0x2be5, 0x4e49, 0xb4, 0xc5, 0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a)
+#define UUID_TRUSTED_FWU_CERT \
+	UUID_INIT(0x71408ab2, 0x18d6, 0x874c, 0x8b, 0x2e, 0xc6, 0xdc, 0xcd, 0x50, 0xf0, 0x96)
+#define UUID_CCA_CONTENT_CERT \
+	UUID_INIT(0x36d83d85, 0x761d, 0x4daf, 0x96, 0xf1, 0xcd, 0x99, 0xd6, 0x56, 0x9b, 0x00)
+#define UUID_CORE_SWD_KEY_CERT \
+	UUID_INIT(0x52222d31, 0x820f, 0x494d, 0x8b, 0xbc, 0xea, 0x68, 0x25, 0xd3, 0xc3, 0x5a)
+#define UUID_PLAT_KEY_CERT \
+	UUID_INIT(0xd43cd902, 0x5b9f, 0x412e, 0x8a, 0xc6, 0x92, 0xb6, 0xd1, 0x8b, 0xe6, 0x0d)
+#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \
+	UUID_INIT(0x5ff9ec0b, 0x4d22, 0x3e4d, 0xa5, 0x44, 0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a)
+#define UUID_SCP_FIRMWARE_SCP_BL2 \
+	UUID_INIT(0x9766fd3d, 0x89be, 0xe849, 0xae, 0x5d, 0x78, 0xa1, 0x40, 0x60, 0x82, 0x13)
+#define UUID_EL3_RUNTIME_FIRMWARE_BL31 \
+	UUID_INIT(0x47d4086d, 0x4cfe, 0x9846, 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x00)
+#define UUID_SECURE_PAYLOAD_BL32 \
+	UUID_INIT(0x05d0e189, 0x53dc, 0x1347, 0x8d, 0x2b, 0x50, 0x0a, 0x4b, 0x7a, 0x3e, 0x38)
+#define UUID_SECURE_PAYLOAD_BL32_EXTRA1 \
+	UUID_INIT(0x0b70c29b, 0x2a5a, 0x7840, 0x9f, 0x65, 0x0a, 0x56, 0x82, 0x73, 0x82, 0x88)
+#define UUID_SECURE_PAYLOAD_BL32_EXTRA2 \
+	UUID_INIT(0x8ea87bb1, 0xcfa2, 0x3f4d, 0x85, 0xfd, 0xe7, 0xbb, 0xa5, 0x02, 0x20, 0xd9)
+#define UUID_NON_TRUSTED_FIRMWARE_BL33 \
+	UUID_INIT(0xd6d0eea7, 0xfcea, 0xd54b, 0x97, 0x82, 0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4)
+#define UUID_REALM_MONITOR_MGMT_FIRMWARE \
+	UUID_INIT(0x6c0762a6, 0x12f2, 0x4b56, 0x92, 0xcb, 0xba, 0x8f, 0x63, 0x36, 0x06, 0xd9)
+
+/* Key certificates */
+#define UUID_ROT_KEY_CERT \
+	UUID_INIT(0x862d1d72, 0xf860, 0xe411, 0x92, 0x0b, 0x8b, 0xe7, 0x62, 0x16, 0x0f, 0x24)
+#define UUID_TRUSTED_KEY_CERT \
+	UUID_INIT(0x827ee890, 0xf860, 0xe411, 0xa1, 0xb4, 0x77, 0x7a, 0x21, 0xb4, 0xf9, 0x4c)
+#define UUID_NON_TRUSTED_WORLD_KEY_CERT \
+	UUID_INIT(0x1c67873d, 0x5f63, 0xe411, 0x97, 0x8d, 0x27, 0xc0, 0xc7, 0x14, 0x8a, 0xbd)
+#define UUID_SCP_FW_KEY_CERT \
+	UUID_INIT(0x024221a1, 0xf860, 0xe411, 0x8d, 0x9b, 0xf3, 0x3c, 0x0e, 0x15, 0xa0, 0x14)
+#define UUID_SOC_FW_KEY_CERT \
+	UUID_INIT(0x8ab8becc, 0xf960, 0xe411, 0x9a, 0xd0, 0xeb, 0x48, 0x22, 0xd8, 0xdc, 0xf8)
+#define UUID_TRUSTED_OS_FW_KEY_CERT \
+	UUID_INIT(0x9477d603, 0xfb60, 0xe411, 0x85, 0xdd, 0xb7, 0x10, 0x5b, 0x8c, 0xee, 0x04)
+#define UUID_NON_TRUSTED_FW_KEY_CERT \
+	UUID_INIT(0x8ad5832a, 0xfb60, 0xe411, 0x8a, 0xaf, 0xdf, 0x30, 0xbb, 0xc4, 0x98, 0x59)
+
+/* Content certificates */
+#define UUID_TRUSTED_BOOT_FW_CERT \
+	UUID_INIT(0xd6e269ea, 0x5d63, 0xe411, 0x8d, 0x8c, 0x9f, 0xba, 0xbe, 0x99, 0x56, 0xa5)
+#define UUID_SCP_FW_CONTENT_CERT \
+	UUID_INIT(0x44be6f04, 0x5e63, 0xe411, 0xb2, 0x8b, 0x73, 0xd8, 0xea, 0xae, 0x96, 0x56)
+#define UUID_SOC_FW_CONTENT_CERT \
+	UUID_INIT(0xe2b20c20, 0x5e63, 0xe411, 0x9c, 0xe8, 0xab, 0xcc, 0xf9, 0x2b, 0xb6, 0x66)
+#define UUID_TRUSTED_OS_FW_CONTENT_CERT \
+	UUID_INIT(0xa49f4411, 0x5e63, 0xe411, 0x87, 0x28, 0x3f, 0x05, 0x72, 0x2a, 0xf3, 0x3d)
+#define UUID_NON_TRUSTED_FW_CONTENT_CERT \
+	UUID_INIT(0x8ec4c1f3, 0x5d63, 0xe411, 0xa7, 0xa9, 0x87, 0xee, 0x40, 0xb2, 0x3f, 0xa7)
+#define UUID_SIP_SECURE_PARTITION_CONTENT_CERT \
+	UUID_INIT(0x776dfd44, 0x8697, 0x4c3b, 0x91, 0xeb, 0xc1, 0x3e, 0x02, 0x5a, 0x2a, 0x6f)
+#define UUID_PLAT_SECURE_PARTITION_CONTENT_CERT \
+	UUID_INIT(0xddcbbf4a, 0xcad6, 0x11ea, 0x87, 0xd0, 0x02, 0x42, 0xac, 0x13, 0x00, 0x03)
+
+/* Dynamic configs */
+#define UUID_HW_CONFIG \
+	UUID_INIT(0x08b8f1d9, 0xc9cf, 0x9349, 0xa9, 0x62, 0x6f, 0xbc, 0x6b, 0x72, 0x65, 0xcc)
+#define UUID_TB_FW_CONFIG \
+	UUID_INIT(0x6c0458ff, 0xaf6b, 0x7d4f, 0x82, 0xed, 0xaa, 0x27, 0xbc, 0x69, 0xbf, 0xd2)
+#define UUID_SOC_FW_CONFIG \
+	UUID_INIT(0x9979814b, 0x0376, 0xfb46, 0x8c, 0x8e, 0x8d, 0x26, 0x7f, 0x78, 0x59, 0xe0)
+#define UUID_TOS_FW_CONFIG \
+	UUID_INIT(0x26257c1a, 0xdbc6, 0x7f47, 0x8d, 0x96, 0xc4, 0xc4, 0xb0, 0x24, 0x80, 0x21)
+#define UUID_NT_FW_CONFIG \
+	UUID_INIT(0x28da9815, 0x93e8, 0x7e44, 0xac, 0x66, 0x1a, 0xaf, 0x80, 0x15, 0x50, 0xf9)
+#define UUID_FW_CONFIG \
+	UUID_INIT(0x5807e16a, 0x8459, 0x47be, 0x8e, 0xd5, 0x64, 0x8e, 0x8d, 0xdd, 0xab, 0x0e)
+
+#define UUID_STM32MP_CONFIG_CERT \
+	UUID_INIT(0x501d8dd2, 0x8bce, 0x49a5, 0x84, 0xeb, 0x55, 0x9a, 0x9f, 0x2e, 0xae, 0xaf)
+
+typedef struct fip_toc_header {
+	uint32_t	name;
+	uint32_t	serial_number;
+	uint64_t	flags;
+} fip_toc_header_t;
+
+typedef struct fip_toc_entry {
+	uuid_t		uuid;
+	uint64_t	offset_address;
+	uint64_t	size;
+	uint64_t	flags;
+} fip_toc_entry_t;
+
+#endif /* FIRMWARE_IMAGE_PACKAGE_H */
diff --git a/include/fiptool.h b/include/fiptool.h
new file mode 100644
index 000000000000..704845f45664
--- /dev/null
+++ b/include/fiptool.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef FIPTOOL_H
+#define FIPTOOL_H
+
+#include <linux/uuid.h>
+#include <fip.h>
+
+enum {
+	DO_UNSPEC = 0,
+	DO_PACK   = 1,
+	DO_UNPACK = 2,
+	DO_REMOVE = 3
+};
+
+typedef struct image_desc {
+	uuid_t             uuid;
+	char              *name;
+	char              *cmdline_name;
+	int                action;
+	char              *action_arg;
+	struct image      *image;
+	struct image_desc *next;
+} image_desc_t;
+
+typedef struct image {
+	struct fip_toc_entry toc_e;
+	void                *buffer;
+} image_t;
+
+struct fip_state {
+	image_desc_t *image_desc_head;
+	size_t nr_image_descs;
+	int verbose;
+};
+
+#define pr_verbose(...) do { \
+	if (fip->verbose) { \
+		pr_info(__VA_ARGS__); \
+	} else { \
+		pr_debug(__VA_ARGS__); \
+	} \
+} while (0)
+
+image_desc_t *new_image_desc(const uuid_t *uuid,
+			     const char *name, const char *cmdline_name);
+
+void set_image_desc_action(image_desc_t *desc, int action,
+    const char *arg);
+
+void free_image_desc(image_desc_t *desc);
+
+void add_image_desc(struct fip_state *fip, image_desc_t *desc);
+
+void free_image_descs(struct fip_state *fip);
+
+void fill_image_descs(struct fip_state *fip);
+
+image_desc_t *lookup_image_desc_from_uuid(struct fip_state *fip,
+						 const uuid_t *uuid);
+
+image_desc_t *lookup_image_desc_from_opt(struct fip_state *fip, char **arg);
+
+int parse_fip(struct fip_state *fip,
+		     const char *filename, fip_toc_header_t *toc_header_out);
+
+int pack_images(struct fip_state *fip,
+		const char *filename,
+		uint64_t toc_flags, unsigned long align);
+
+int update_fip(struct fip_state *fip);
+
+#define TOC_HEADER_SERIAL_NUMBER 0x12345678
+
+typedef struct toc_entry {
+	char         *name;
+	uuid_t        uuid;
+	char         *cmdline_name;
+} toc_entry_t;
+
+extern toc_entry_t toc_entries[];
+extern toc_entry_t plat_def_toc_entries[];
+
+#endif /* FIPTOOL_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 44133a54f31f..40c7b2cb5d65 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -111,6 +111,9 @@ config LIBUBIGEN
 config IMAGE_SPARSE
 	bool
 
+config FIP
+	bool
+
 config STMP_DEVICE
 	bool "STMP device support" if COMPILE_TEST
 
diff --git a/lib/Makefile b/lib/Makefile
index 1cf311ebcdb8..46b42146cbc9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -22,6 +22,7 @@ obj-y			+= readkey.o
 obj-y			+= kfifo.o
 obj-y			+= libbb.o
 obj-y			+= libgen.o
+obj-$(CONFIG_FIP)	+= fip.o tbbr_config.o
 obj-$(CONFIG_JSMN)	+= jsmn.o
 obj-$(CONFIG_BLOBGEN)	+= blobgen.o
 obj-y			+= stringlist.o
diff --git a/lib/fip.c b/lib/fip.c
new file mode 100644
index 000000000000..ae7ff8b3ad00
--- /dev/null
+++ b/lib/fip.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Imported from TF-A v2.10.0
+ */
+
+#define pr_fmt(fmt) "fip: " fmt
+
+#include <unistd.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/bug.h>
+#include <linux/log2.h>
+#include <malloc.h>
+#include <errno.h>
+#include <linux/limits.h>
+#include <linux/uuid.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libfile.h>
+
+#include <fip.h>
+#include <fiptool.h>
+
+image_desc_t *new_image_desc(const uuid_t *uuid,
+			     const char *name, const char *cmdline_name)
+{
+	image_desc_t *desc;
+
+	desc = xzalloc(sizeof(*desc));
+	memcpy(&desc->uuid, uuid, sizeof(uuid_t));
+	desc->name = xstrdup(name);
+	desc->cmdline_name = xstrdup(cmdline_name);
+	desc->action = DO_UNSPEC;
+	return desc;
+}
+
+void set_image_desc_action(image_desc_t *desc, int action,
+    const char *arg)
+{
+	ASSERT(desc != NULL);
+
+	if (desc->action_arg != (char *)DO_UNSPEC)
+		free(desc->action_arg);
+	desc->action = action;
+	desc->action_arg = NULL;
+	if (arg != NULL)
+		desc->action_arg = xstrdup(arg);
+}
+
+void free_image_desc(image_desc_t *desc)
+{
+	free(desc->name);
+	free(desc->cmdline_name);
+	free(desc->action_arg);
+	if (desc->image) {
+		free(desc->image->buffer);
+		free(desc->image);
+	}
+	free(desc);
+}
+
+void add_image_desc(struct fip_state *fip, image_desc_t *desc)
+{
+	image_desc_t **p = &fip->image_desc_head;
+
+	while (*p)
+		p = &(*p)->next;
+
+	ASSERT(*p == NULL);
+	*p = desc;
+	fip->nr_image_descs++;
+}
+
+void free_image_descs(struct fip_state *fip)
+{
+	image_desc_t *desc = fip->image_desc_head, *tmp;
+
+	while (desc != NULL) {
+		tmp = desc->next;
+		free_image_desc(desc);
+		desc = tmp;
+		fip->nr_image_descs--;
+	}
+	ASSERT(fip->nr_image_descs == 0);
+}
+
+void fill_image_descs(struct fip_state *fip)
+{
+	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(fip, desc);
+	}
+	for (toc_entry = plat_def_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(fip, desc);
+	}
+}
+
+image_desc_t *lookup_image_desc_from_uuid(struct fip_state *fip,
+						 const uuid_t *uuid)
+{
+	image_desc_t *desc;
+
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next)
+		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
+			return desc;
+	return NULL;
+}
+
+image_desc_t *lookup_image_desc_from_opt(struct fip_state *fip, char **arg)
+{
+	int len = 0;
+	image_desc_t *desc;
+	char *eq;
+
+	eq = strchrnul(*arg, '=');
+	len = eq - *arg;
+
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+		if (strncmp(desc->cmdline_name, *arg, len) == 0) {
+			if (*eq)
+				*arg = eq + 1;
+			return desc;
+		}
+	}
+
+	printf("unknown image type '%.*s'\n", len, *arg);
+	return NULL;
+}
+
+int parse_fip(struct fip_state *fip,
+		     const char *filename, fip_toc_header_t *toc_header_out)
+{
+	struct stat st;
+	int fd;
+	char *buf, *bufend;
+	fip_toc_header_t *toc_header;
+	fip_toc_entry_t *toc_entry;
+	int terminated = 0;
+	size_t st_size;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		pr_err("open %s: %m\n", filename);
+		return -errno;
+	}
+
+	if (fstat(fd, &st) == -1) {
+		pr_err("fstat %s: %m\n", filename);
+		return -errno;
+	}
+
+	st_size = st.st_size;
+
+	buf = xmalloc(st_size);
+	if (read_full(fd, buf, st_size) != st_size) {
+		pr_err("Failed to read %s: %m\n", filename);
+		return -errno;
+	}
+
+	bufend = buf + st_size;
+	close(fd);
+
+	if (st_size < sizeof(fip_toc_header_t)) {
+		pr_err("FIP %s is truncated\n", filename);
+		return -ENODATA;
+	}
+
+	toc_header = (fip_toc_header_t *)buf;
+	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
+
+	if (toc_header->name != TOC_HEADER_NAME) {
+		pr_err("%s is not a FIP file: unknown magic = 0x%08x\n",
+		       filename, toc_header->name);
+		return -EINVAL;
+	}
+
+	/* Return the ToC header if the caller wants it. */
+	if (toc_header_out != NULL)
+		*toc_header_out = *toc_header;
+
+	/* Walk through each ToC entry in the file. */
+	while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
+		image_t *image;
+		image_desc_t *desc;
+
+		/* Found the ToC terminator, we are done. */
+		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
+			terminated = 1;
+			break;
+		}
+
+		/*
+		 * Build a new image out of the ToC entry and add it to the
+		 * table of images.
+		 */
+		image = xzalloc(sizeof(*image));
+		image->toc_e = *toc_entry;
+		image->buffer = xmalloc(toc_entry->size);
+		/* Overflow checks before memory copy. */
+		if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) {
+			pr_err("FIP %s is corrupted: entry size exceeds 64 bit address space\n",
+			       filename);
+			return -EINVAL;
+		}
+		if (toc_entry->size + toc_entry->offset_address > st_size) {
+			pr_err("FIP %s is corrupted: entry size (0x%llx) exceeds FIP file size (0x%zx)\n",
+				filename, toc_entry->size + toc_entry->offset_address, st_size);
+			return -EINVAL;
+		}
+
+		memcpy(image->buffer, buf + toc_entry->offset_address,
+		    toc_entry->size);
+
+		/* If this is an unknown image, create a descriptor for it. */
+		desc = lookup_image_desc_from_uuid(fip, &toc_entry->uuid);
+		if (desc == NULL) {
+			char name[UUID_STRING_LEN + 1], filename[PATH_MAX];
+
+			snprintf(name, sizeof(name), "%pU", &toc_entry->uuid);
+			snprintf(filename, sizeof(filename), "%s%s",
+			    name, ".bin");
+			desc = new_image_desc(&toc_entry->uuid, name, "blob");
+			desc->action = DO_UNPACK;
+			desc->action_arg = xstrdup(filename);
+			add_image_desc(fip, desc);
+		}
+
+		ASSERT(desc->image == NULL);
+		desc->image = image;
+
+		toc_entry++;
+	}
+
+	if (terminated == 0) {
+		pr_err("FIP %s does not have a ToC terminator entry\n",
+		    filename);
+		return -EINVAL;
+	}
+	free(buf);
+	return 0;
+}
+
+static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
+{
+	struct stat st;
+	image_t *image;
+	int fd;
+
+	ASSERT(uuid != NULL);
+	ASSERT(filename != NULL);
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		pr_err("open %s: %m\n", filename);
+		return NULL;
+	}
+
+	if (fstat(fd, &st) == -1) {
+		pr_err("fstat %s: %m\n", filename);
+		return NULL;
+	}
+
+	image = xzalloc(sizeof(*image));
+	image->toc_e.uuid = *uuid;
+	image->buffer = xmalloc(st.st_size);
+	if (read_full(fd, image->buffer, st.st_size) != st.st_size) {
+		pr_err("Failed to read %s: %m\n", filename);
+		return NULL;
+	}
+	image->toc_e.size = st.st_size;
+
+	close(fd);
+	return image;
+}
+
+int pack_images(struct fip_state *fip,
+		const char *filename,
+		uint64_t toc_flags, unsigned long align)
+{
+	int fd;
+	image_desc_t *desc;
+	fip_toc_header_t *toc_header;
+	fip_toc_entry_t *toc_entry;
+	char *buf;
+	uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
+	size_t nr_images = 0;
+
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next)
+		if (desc->image != NULL)
+			nr_images++;
+
+	buf_size = sizeof(fip_toc_header_t) +
+	    sizeof(fip_toc_entry_t) * (nr_images + 1);
+	buf = calloc(1, buf_size);
+	if (buf == NULL)
+		return -ENOMEM;
+
+	/* Build up header and ToC entries from the image table. */
+	toc_header = (fip_toc_header_t *)buf;
+	toc_header->name = TOC_HEADER_NAME;
+	toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
+	toc_header->flags = toc_flags;
+
+	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
+
+	entry_offset = buf_size;
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image = desc->image;
+
+		if (image == NULL || (image->toc_e.size == 0ULL))
+			continue;
+		payload_size += image->toc_e.size;
+		entry_offset = (entry_offset + align - 1) & ~(align - 1);
+		image->toc_e.offset_address = entry_offset;
+		*toc_entry++ = image->toc_e;
+		entry_offset += image->toc_e.size;
+	}
+
+	/*
+	 * Append a null uuid entry to mark the end of ToC entries.
+	 * NOTE the offset address for the last toc_entry must match the fip
+	 * size.
+	 */
+	memset(toc_entry, 0, sizeof(*toc_entry));
+	toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
+
+	/* Generate the FIP file. */
+	fd = creat(filename, 0777);
+	if (fd < 0) {
+		pr_err("creat %s: %m\n", filename);
+		return -errno;
+	}
+
+	pr_verbose("Metadata size: %llu bytes\n", buf_size);
+
+	if (write_full(fd, buf, buf_size) < 0) {
+		pr_err("Failed to write %s: %m\n", filename);
+		return -errno;
+	}
+
+	pr_verbose("Payload size: %llu bytes\n", payload_size);
+
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image = desc->image;
+
+		if (image == NULL)
+			continue;
+		if (pwrite_full(fd, image->buffer, image->toc_e.size, image->toc_e.offset_address) < 0) {
+			pr_err("Failed to write %s: %m\n", filename);
+			return -errno;
+		}
+	}
+
+	if (lseek(fd, entry_offset, SEEK_SET) < 0) {
+		pr_err("Failed to set file position: %m\n");
+		return -errno;
+	}
+
+	pad_size = toc_entry->offset_address - entry_offset;
+	while (pad_size--) {
+		uint8_t zero = 0x00;
+		write(fd, &zero, sizeof(zero));
+	}
+
+	free(buf);
+	close(fd);
+	return 0;
+}
+
+/*
+ * This function is shared between the create and update subcommands.
+ * The difference between the two subcommands is that when the FIP file
+ * is created, the parsing of an existing FIP is skipped.  This results
+ * in update_fip() creating the new FIP file from scratch because the
+ * internal image table is not populated.
+ */
+int update_fip(struct fip_state *fip)
+{
+	image_desc_t *desc;
+
+	/* Add or replace images in the FIP file. */
+	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image;
+
+		if (desc->action != DO_PACK)
+			continue;
+
+		image = read_image_from_file(&desc->uuid,
+		    desc->action_arg);
+		if (!image)
+			return -1;
+
+		if (desc->image != NULL) {
+			pr_verbose("Replacing %s with %s\n",
+				   desc->cmdline_name,
+				   desc->action_arg);
+			free(desc->image);
+			desc->image = image;
+		} else {
+			pr_verbose("Adding image %s\n", desc->action_arg);
+			desc->image = image;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/tbbr_config.c b/lib/tbbr_config.c
new file mode 100644
index 000000000000..3d777e5648a9
--- /dev/null
+++ b/lib/tbbr_config.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// SPDX-FileCopyrightText: (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
+
+#include <stddef.h>
+#include <fiptool.h>
+
+/* The images used depends on the platform. */
+toc_entry_t toc_entries[] = {
+	{
+		.name = "SCP Firmware Updater Configuration FWU SCP_BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
+		.cmdline_name = "scp-fwu-cfg"
+	},
+	{
+		.name = "AP Firmware Updater Configuration BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
+		.cmdline_name = "ap-fwu-cfg"
+	},
+	{
+		.name = "Firmware Updater NS_BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
+		.cmdline_name = "fwu"
+	},
+	{
+		.name = "Non-Trusted Firmware Updater certificate",
+		.uuid = UUID_TRUSTED_FWU_CERT,
+		.cmdline_name = "fwu-cert"
+	},
+	{
+		.name = "Trusted Boot Firmware BL2",
+		.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+		.cmdline_name = "tb-fw"
+	},
+	{
+		.name = "SCP Firmware SCP_BL2",
+		.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+		.cmdline_name = "scp-fw"
+	},
+	{
+		.name = "EL3 Runtime Firmware BL31",
+		.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+		.cmdline_name = "soc-fw"
+	},
+	{
+		.name = "Secure Payload BL32 (Trusted OS)",
+		.uuid = UUID_SECURE_PAYLOAD_BL32,
+		.cmdline_name = "tos-fw"
+	},
+	{
+		.name = "Secure Payload BL32 Extra1 (Trusted OS Extra1)",
+		.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+		.cmdline_name = "tos-fw-extra1"
+	},
+	{
+		.name = "Secure Payload BL32 Extra2 (Trusted OS Extra2)",
+		.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+		.cmdline_name = "tos-fw-extra2"
+	},
+	{
+		.name = "Non-Trusted Firmware BL33",
+		.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+		.cmdline_name = "nt-fw"
+	},
+	{
+		.name = "Realm Monitor Management Firmware",
+		.uuid = UUID_REALM_MONITOR_MGMT_FIRMWARE,
+		.cmdline_name = "rmm-fw"
+	},
+	/* Dynamic Configs */
+	{
+		.name = "FW_CONFIG",
+		.uuid = UUID_FW_CONFIG,
+		.cmdline_name = "fw-config"
+	},
+	{
+		.name = "HW_CONFIG",
+		.uuid = UUID_HW_CONFIG,
+		.cmdline_name = "hw-config"
+	},
+	{
+		.name = "TB_FW_CONFIG",
+		.uuid = UUID_TB_FW_CONFIG,
+		.cmdline_name = "tb-fw-config"
+	},
+	{
+		.name = "SOC_FW_CONFIG",
+		.uuid = UUID_SOC_FW_CONFIG,
+		.cmdline_name = "soc-fw-config"
+	},
+	{
+		.name = "TOS_FW_CONFIG",
+		.uuid = UUID_TOS_FW_CONFIG,
+		.cmdline_name = "tos-fw-config"
+	},
+	{
+		.name = "NT_FW_CONFIG",
+		.uuid = UUID_NT_FW_CONFIG,
+		.cmdline_name = "nt-fw-config"
+	},
+	/* Key Certificates */
+	{
+		.name = "Root Of Trust key certificate",
+		.uuid = UUID_ROT_KEY_CERT,
+		.cmdline_name = "rot-cert"
+	},
+	{
+		.name = "Trusted key certificate",
+		.uuid = UUID_TRUSTED_KEY_CERT,
+		.cmdline_name = "trusted-key-cert"
+	},
+	{
+		.name = "SCP Firmware key certificate",
+		.uuid = UUID_SCP_FW_KEY_CERT,
+		.cmdline_name = "scp-fw-key-cert"
+	},
+	{
+		.name = "SoC Firmware key certificate",
+		.uuid = UUID_SOC_FW_KEY_CERT,
+		.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"
+	},
+	{
+		.name = "Non-Trusted Firmware key certificate",
+		.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+		.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"
+	},
+	{
+		.name = "SCP Firmware content certificate",
+		.uuid = UUID_SCP_FW_CONTENT_CERT,
+		.cmdline_name = "scp-fw-cert"
+	},
+	{
+		.name = "SoC Firmware content certificate",
+		.uuid = UUID_SOC_FW_CONTENT_CERT,
+		.cmdline_name = "soc-fw-cert"
+	},
+	{
+		.name = "Trusted OS Firmware content certificate",
+		.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+		.cmdline_name = "tos-fw-cert"
+	},
+	{
+		.name = "Non-Trusted Firmware content certificate",
+		.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+		.cmdline_name = "nt-fw-cert"
+	},
+	{
+		.name = "SiP owned Secure Partition content certificate",
+		.uuid = UUID_SIP_SECURE_PARTITION_CONTENT_CERT,
+		.cmdline_name = "sip-sp-cert"
+	},
+	{
+		.name = "Platform owned Secure Partition content certificate",
+		.uuid = UUID_PLAT_SECURE_PARTITION_CONTENT_CERT,
+		.cmdline_name = "plat-sp-cert"
+	},
+	{
+		.name = "CCA Content Certificate",
+		.uuid = UUID_CCA_CONTENT_CERT,
+		.cmdline_name = "cca-cert"
+	},
+	{
+		.name = "Core Secure World Key Certificate",
+		.uuid = UUID_CORE_SWD_KEY_CERT,
+		.cmdline_name = "core-swd-cert"
+	},
+	{
+		.name = "Platform Key Certificate",
+		.uuid = UUID_PLAT_KEY_CERT,
+		.cmdline_name = "plat-key-cert"
+	},
+	{
+		.name = NULL,
+		.uuid = { {0} },
+		.cmdline_name = NULL,
+	}
+};
+
+toc_entry_t plat_def_toc_entries[] = {
+#ifdef CONFIG_ARCH_STM32MP
+	{
+		.name = "STM32MP CONFIG CERT",
+		.uuid = UUID_STM32MP_CONFIG_CERT,
+		.cmdline_name = "stm32mp-cfg-cert"
+	},
+#endif
+
+	{
+		.name = NULL,
+		.uuid = { {0} },
+		.cmdline_name = NULL,
+	}
+};
-- 
2.39.5




^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-01-09 11:25 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-09 11:25 [PATCH] Import ARM Trusted Firmware fiptool utility Ahmad Fatoum

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox