[coreboot-gerrit] Patch set updated for coreboot: ifwitool: Add new tool for managing IFWI images

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Thu May 26 18:10:37 CEST 2016


Aaron Durbin (adurbin at chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14896

-gerrit

commit 70a3497d02bd92f7b40b756b9c05f8a38ac9651c
Author: Furquan Shaikh <furquan at google.com>
Date:   Thu May 19 16:12:16 2016 -0700

    ifwitool: Add new tool for managing IFWI images
    
    - Supports following operations:
     1. add raw image
     2. hooks to add subpart image
     3. extract raw/subpart image
     4. print
     5. delete raw image
     6. replace raw/subpart image
    
    Change-Id: I683a0ab13cc50eb60eecca34db4a8ffefc8dccbd
    Signed-off-by: Furquan Shaikh <furquan at google.com>
---
 util/cbfstool/Makefile     |    2 +
 util/cbfstool/Makefile.inc |    8 +
 util/cbfstool/ifwitool.c   | 1601 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1611 insertions(+)

diff --git a/util/cbfstool/Makefile b/util/cbfstool/Makefile
index 61a1a63..f49da3e 100644
--- a/util/cbfstool/Makefile
+++ b/util/cbfstool/Makefile
@@ -10,6 +10,7 @@ OBJCOPY ?= objcopy
 all: $(objutil)/cbfstool/cbfstool \
 	$(objutil)/cbfstool/fmaptool \
 	$(objutil)/cbfstool/rmodtool \
+	$(objutil)/cbfstool/ifwitool \
 
 .PHONY: clean
 clean:
@@ -17,6 +18,7 @@ clean:
 	$(RM) $(objutil)/cbfstool/cbfstool $(cbfsobj)
 	$(RM) $(objutil)/cbfstool/fmaptool $(fmapobj)
 	$(RM) $(objutil)/cbfstool/rmodtool $(rmodobj)
+	$(RM) $(objutil)/cbfstool/ifwitool $(ifwiobj)
 
 linux_trampoline.c: linux_trampoline.S
 	rm -f linux_trampoline.c
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index aa42f01..6c2b100 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -58,6 +58,10 @@ rmodobj += common.o
 rmodobj += elfheaders.o
 rmodobj += xdr.o
 
+ifwiobj :=
+ifwiobj += ifwitool.o
+ifwiobj += common.o
+
 TOOLCFLAGS ?= -Werror -Wall -Wextra
 TOOLCFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
 TOOLCFLAGS += -Wstrict-prototypes -Wwrite-strings
@@ -132,6 +136,10 @@ $(objutil)/cbfstool/rmodtool: $(addprefix $(objutil)/cbfstool/,$(rmodobj))
 	printf "    HOSTCC     $(subst $(objutil)/,,$(@)) (link)\n"
 	$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(rmodobj))
 
+$(objutil)/cbfstool/ifwitool: $(addprefix $(objutil)/cbfstool/,$(ifwiobj))
+	printf "    HOSTCC     $(subst $(objutil)/,,$(@)) (link)\n"
+	$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(ifwiobj))
+
 # Yacc source is superset of header
 $(objutil)/cbfstool/fmd.o: TOOLCFLAGS += -Wno-redundant-decls
 $(objutil)/cbfstool/fmd_parser.o: TOOLCFLAGS += -Wno-redundant-decls
diff --git a/util/cbfstool/ifwitool.c b/util/cbfstool/ifwitool.c
new file mode 100644
index 0000000..b3893aa
--- /dev/null
+++ b/util/cbfstool/ifwitool.c
@@ -0,0 +1,1601 @@
+/*
+ * ifwitool, CLI utility for IFWI manipulation
+ *
+ * Copyright 2016 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <commonlib/endian.h>
+#include <getopt.h>
+#include <stdlib.h>
+
+#include "common.h"
+
+#define BPDT_SIGNATURE				(0x000055AA)
+#define KiB					1024
+
+/* Parameters passed in by caller. */
+static struct param {
+	const char *file_name;
+	const char *comp_name;
+	const char *image_name;
+	bool subpart_ops;
+} param;
+
+struct bpdt_header {
+	uint32_t signature;
+	uint16_t descriptor_count;
+	uint16_t bpdt_version;
+	uint32_t xor_redundant_block;
+	uint32_t ifwi_version;
+	uint64_t fit_tool_version;
+} __attribute__((packed));
+#define BPDT_HEADER_SIZE			(sizeof(struct bpdt_header))
+
+struct bpdt_entry {
+	uint16_t type;
+	uint16_t flags;
+	uint32_t offset;
+	uint32_t size;
+} __attribute__((packed));
+#define BPDT_ENTRY_SIZE			(sizeof(struct bpdt_entry))
+
+struct bpdt {
+	struct bpdt_header h;
+	struct bpdt_entry e[1];
+} __attribute__((packed));
+
+#define BPDT_SIZE(c)				(BPDT_HEADER_SIZE + (c) * \
+						 BPDT_ENTRY_SIZE)
+
+struct subpart_header {
+	uint32_t marker;
+	uint32_t num_entries;
+	uint8_t header_version;
+	uint8_t entry_version;
+	uint8_t header_length;
+	uint8_t checksum;
+	uint8_t name[4];
+} __attribute__((packed));
+#define SUBPART_HEADER_SIZE			(sizeof(struct subpart_header))
+#define SUBPART_MARKER				0x44504324
+#define SUBPART_HEADER_VERSION_SUPPORTED	1
+#define SUBPART_ENTRY_VERSION_SUPPORTED	1
+
+struct subpart_entry {
+	uint8_t name[12];
+	uint32_t offset;
+	uint32_t length;
+	uint32_t rsvd;
+} __attribute__((packed));
+#define SUBPART_ENTRY_SIZE			(sizeof(struct subpart_entry))
+
+struct subpart {
+	struct subpart_header h;
+	struct subpart_entry e[1];
+} __attribute__((packed));
+#define SUBPART_SIZE(c)			(SUBPART_HEADER_SIZE +  (c) * \
+						 SUBPART_ENTRY_SIZE)
+
+/*
+ * Attributes for various IFWI components.
+ * LIES_WITHIN_BPDT_4K = Component should lie within the same 4K block as BPDT.
+ * NON_CRITICAL_COMP = Component entry should be present in S-BPDT.
+ * CONTAINS_SUBPART = Component might require subpart operation (TODO(furquan))
+ * AUTO_GENERATED = Component is generated by the tool.
+ * MANDATORY_BPDT_ENTRY = Even if component is deleted, BPDT should contain an
+ * entry for it with size 0 and offset 0.
+ */
+enum comp_attributes {
+	LIES_WITHIN_BPDT_4K = (1 << 0),
+	NON_CRITICAL_COMP = (1 << 1),
+	CONTAINS_SUBPART = (1 << 2),
+	AUTO_GENERATED = (1 << 3),
+	MANDATORY_BPDT_ENTRY = (1 << 4),
+};
+
+/* Type value for various IFWI components. */
+enum bpdt_entry_type {
+	SMIP_TYPE		= 0,
+	CSE_RBE_TYPE		= 1,
+	CSE_BUP_TYPE		= 2,
+	UCODE_TYPE		= 3,
+	IBB_TYPE		= 4,
+	S_BPDT_TYPE		= 5,
+	OBB_TYPE		= 6,
+	CSE_MAIN_TYPE		= 7,
+	ISH_TYPE		= 8,
+	CSE_IDLM_TYPE		= 9,
+	IFP_OVERRIDE_TYPE	= 10,
+	DEBUG_TOKENS_TYPE	= 11,
+	UFS_PHY_TYPE		= 12,
+	UFS_GPP_TYPE		= 13,
+	PMC_TYPE		= 14,
+	IUNIT_TYPE		= 15,
+	NVM_CONFIG_TYPE	= 16,
+	UEP_TYPE		= 17,
+	UFS_RATE_B_TYPE	= 18,
+	MAX_COMPS		= 19,
+};
+
+/*
+ * There are two order requirements for an IFWI image:
+ * 1. Order in which the entries lie within the BPDT.
+ * 2. Order in which the components lie within the image.
+ *
+ * header_order defines #1 i.e. the order in which the entries should appear in
+ * the BPDT. pack_order defines #2 i.e. the order in which components appear in
+ * the IFWI image. pack_order controls the offset and thus components would have
+ * increasing offsets as we loop over pack_order.
+ */
+enum bpdt_entry_type bpdt_header_order[MAX_COMPS] = {
+	CSE_IDLM_TYPE,
+	IFP_OVERRIDE_TYPE,
+	S_BPDT_TYPE,
+	CSE_RBE_TYPE,
+	UFS_PHY_TYPE,
+	UFS_GPP_TYPE,
+	CSE_BUP_TYPE,
+	UEP_TYPE,
+	NVM_CONFIG_TYPE,
+	SMIP_TYPE,
+	PMC_TYPE,
+	UCODE_TYPE,
+	IBB_TYPE,
+	DEBUG_TOKENS_TYPE,
+	UFS_RATE_B_TYPE,
+	ISH_TYPE,
+	CSE_MAIN_TYPE,
+	OBB_TYPE,
+	IUNIT_TYPE,
+};
+
+enum bpdt_entry_type bpdt_pack_order[MAX_COMPS] = {
+	CSE_IDLM_TYPE,
+	UFS_PHY_TYPE,
+	UFS_GPP_TYPE,
+	IFP_OVERRIDE_TYPE,
+	UEP_TYPE,
+	IBB_TYPE,
+	NVM_CONFIG_TYPE,
+	SMIP_TYPE,
+	CSE_RBE_TYPE,
+	PMC_TYPE,
+	CSE_BUP_TYPE,
+	UCODE_TYPE,
+	DEBUG_TOKENS_TYPE,
+	UFS_RATE_B_TYPE,
+	S_BPDT_TYPE,
+	ISH_TYPE,
+	CSE_MAIN_TYPE,
+	OBB_TYPE,
+	IUNIT_TYPE,
+};
+
+/* Utility functions. */
+enum ifwi_ret {
+	COMM_ERR = -1,
+	NO_ACTION_REQUIRED = 0,
+	REPACK_REQUIRED = 1,
+};
+
+struct cbp_ops {
+	enum ifwi_ret (*cbp_add)(int);
+};
+
+struct bpdt_comp {
+	const char *name;
+	uint32_t attr;
+	const char *subpart_name;
+	struct cbp_ops cbp_ops;
+} comp[MAX_COMPS] = {
+	/* OEM SMIP */
+	[SMIP_TYPE] = {"SMIP", CONTAINS_SUBPART, "SMIP", {NULL}},
+	/* CSE RBE */
+	[CSE_RBE_TYPE] = {"CSE_RBE", CONTAINS_SUBPART | MANDATORY_BPDT_ENTRY,
+			  "RBEP", {NULL}},
+	/* CSE BUP */
+	[CSE_BUP_TYPE] = {"CSE_BUP", CONTAINS_SUBPART | MANDATORY_BPDT_ENTRY,
+			  "FTPR", {NULL}},
+	/* uCode */
+	[UCODE_TYPE] = {"uCODE", CONTAINS_SUBPART, "UCOD", {NULL}},
+	/* IBB */
+	[IBB_TYPE] = {"bootblock", CONTAINS_SUBPART, "IBBP", {NULL}},
+	/* S-BPDT */
+	[S_BPDT_TYPE] = {"S_BPDT", AUTO_GENERATED | MANDATORY_BPDT_ENTRY,
+			 NULL, {NULL}},
+	/* OBB */
+	[OBB_TYPE] = {"OBB", CONTAINS_SUBPART | NON_CRITICAL_COMP, "OBBP",
+		      {NULL}},
+	/* CSE Main */
+	[CSE_MAIN_TYPE] = {"CSE_MAIN", CONTAINS_SUBPART | NON_CRITICAL_COMP,
+			   "NFTP", {NULL}},
+	/* ISH */
+	[ISH_TYPE] = {"ISH", NON_CRITICAL_COMP, "ISHP", {NULL}},
+	/* CSE IDLM */
+	[CSE_IDLM_TYPE] = {"CSE_IDLM", CONTAINS_SUBPART | MANDATORY_BPDT_ENTRY,
+			   "DLMP", {NULL}},
+	/* IFP Override */
+	[IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", LIES_WITHIN_BPDT_4K |
+			       MANDATORY_BPDT_ENTRY, NULL, {NULL}},
+	/* Debug Tokens */
+	[DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", 0, NULL, {NULL}},
+	/* UFS Phy Configuration */
+	[UFS_PHY_TYPE] = {"UFS_PHY", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
+			  NULL, {NULL}},
+	/* UFS GPP LUN ID */
+	[UFS_GPP_TYPE] = {"UFS_GPP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
+			  NULL, {NULL}},
+	/* PMC */
+	[PMC_TYPE] = {"PMC", CONTAINS_SUBPART, "PMCP", {NULL}},
+	/* IUNIT */
+	[IUNIT_TYPE] = {"IUNIT", NON_CRITICAL_COMP, "IUNP", {NULL}},
+	/* NVM Config */
+	[NVM_CONFIG_TYPE] = {"NVM_CONFIG", 0, NULL, {NULL}},
+	/* UEP */
+	[UEP_TYPE] = {"UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY, NULL,
+		      {NULL}},
+	/* UFS Rate B Config */
+	[UFS_RATE_B_TYPE] = {"UFS_RATE_B", 0, NULL, {NULL}},
+};
+
+/*
+ * Stores information about various components read from the input file.
+ * Also need to save any non-IFWI prefix and suffix in the image so that they
+ * can be restored when output image is created.
+ */
+struct ifwi_image {
+	struct buffer bpdt;
+
+	struct buffer non_ifwi_prefix;
+	struct buffer non_ifwi_suffix;
+
+	struct buffer subpart;
+
+	struct buffer comp_buf[MAX_COMPS];
+} ifwi_image;
+
+static void alloc_buffer(struct buffer *b, size_t s, const char *n)
+{
+	if (buffer_create(b, s, n) == 0)
+		return;
+
+	ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
+	exit(-1);
+}
+
+/* Read header/entry members in little-endian format. */
+static void read_member(void *src, size_t *offset, size_t size_bytes, void *dst)
+{
+	switch (size_bytes) {
+	case 1:
+		*(uint8_t *)dst = read_at_le8(src, *offset);
+		break;
+	case 2:
+		*(uint16_t *)dst = read_at_le16(src, *offset);
+		break;
+	case 4:
+		*(uint32_t *)dst = read_at_le32(src, *offset);
+		break;
+	case 8:
+		*(uint64_t *)dst = read_at_le64(src, *offset);
+		break;
+	default:
+		ERROR("Read size not supported %zd\n", size_bytes);
+		exit(-1);
+	}
+
+	*offset += size_bytes;
+}
+
+#define READ_MEMBER(m)		read_member(data, &offset, sizeof(m), &m)
+
+/* Convert to little endian format. */
+static void fix_member(void *data, size_t *offset, size_t size_bytes)
+{
+	uint8_t *src = (uint8_t *)data + *offset;
+
+	switch (size_bytes) {
+	case 1:
+		write_at_le8(data, *(uint8_t *)src, *offset);
+		break;
+	case 2:
+		write_at_le16(data, *(uint16_t *)src, *offset);
+		break;
+	case 4:
+		write_at_le32(data, *(uint32_t *)src, *offset);
+		break;
+	case 8:
+		write_at_le64(data, *(uint64_t *)src, *offset);
+		break;
+	default:
+		ERROR("Write size not supported %zd\n", size_bytes);
+		exit(-1);
+	}
+	*offset += size_bytes;
+}
+
+#define FIX_MEMBER(m)		fix_member(&m, &offset, sizeof(m))
+
+static void print_subpart(const char *name)
+{
+	if (verbose == 0)
+		return;
+
+	size_t i;
+	struct subpart *s = buffer_get(&ifwi_image.subpart);
+
+	printf("\n%-25s %-25s\n", "Subpart Header", name);
+	printf("%-25s 0x%-23.8x\n", "Marker", s->h.marker);
+	printf("%-25s %-25d\n", "Num entries", s->h.num_entries);
+	printf("%-25s %-25d\n", "Header Version", s->h.header_version);
+	printf("%-25s %-25d\n", "Entry Version", s->h.entry_version);
+	printf("%-25s 0x%-23x\n", "Header Length", s->h.header_length);
+	printf("%-25s 0x%-23x\n", "Checksum", s->h.checksum);
+	printf("%-25s ", "Name");
+	for (i = 0; i < sizeof(s->h.name); i++)
+		printf("%c", s->h.name[i]);
+
+	printf("\n%s entries\n", name);
+
+	printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
+	       "Length", "Rsvd");
+
+	printf("=============================================================="
+	       "===========================================================\n");
+
+	for (i = 0; i < s->h.num_entries; i++) {
+		printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i+1,
+		       s->e[i].name, s->e[i].offset, s->e[i].length,
+		       s->e[i].rsvd);
+	}
+
+	printf("=============================================================="
+	       "===========================================================\n");
+}
+
+static void bpdt_print_header(struct bpdt_header *h, const char *name)
+{
+	if (verbose == 0)
+		return;
+
+	printf("%-25s %-25s\n", "Header", name);
+	printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
+	printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
+	printf("%-25s %-25d\n", "BPDT Version", h->bpdt_version);
+	printf("%-25s 0x%-23x\n", "XOR checksum", h->xor_redundant_block);
+	printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
+	printf("%-25s 0x%-23lx\n", "FIT Tool Version", h->fit_tool_version);
+}
+
+static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
+			       const char *name)
+{
+	if (verbose == 0)
+		return;
+
+	printf("%s entries\n", name);
+
+	printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name",
+	       "Type", "Flags", "Offset", "Size", "File Offset");
+
+	printf("=============================================================="
+	       "=============================================================="
+	       "================================================\n");
+
+	size_t i;
+	for (i = 0; i < count; i++) {
+		printf("%-25zd%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx\n",
+		       i+1, comp[e[i].type].name, e[i].type, e[i].flags,
+		       e[i].offset, e[i].size,
+		       e[i].offset + buffer_size(&ifwi_image.non_ifwi_prefix));
+	}
+
+	printf("=============================================================="
+	       "=============================================================="
+	       "================================================\n");
+
+}
+
+static void bpdt_validate_header(struct bpdt_header *h, const char *name)
+{
+	assert (h->signature == BPDT_SIGNATURE);
+
+	if (h->bpdt_version != 1) {
+		ERROR("Invalid header : %s\n", name);
+		exit(-1);
+	}
+
+	DEBUG("Validated header : %s\n", name);
+}
+
+static void bpdt_read_header(void *data, struct bpdt_header *h,
+			     const char *name)
+{
+	size_t offset = 0;
+
+	READ_MEMBER(h->signature);
+	READ_MEMBER(h->descriptor_count);
+	READ_MEMBER(h->bpdt_version);
+	READ_MEMBER(h->xor_redundant_block);
+	READ_MEMBER(h->ifwi_version);
+	READ_MEMBER(h->fit_tool_version);
+
+	bpdt_validate_header(h, name);
+	bpdt_print_header(h, name);
+}
+
+static void bpdt_read_entries(void *h, struct bpdt_entry *e, size_t count,
+			      const char *name)
+{
+	size_t i, offset = 0;
+	void *data = (struct bpdt_header *)h + 1;
+
+	for (i = 0; i < count; i++) {
+		READ_MEMBER(e[i].type);
+		READ_MEMBER(e[i].flags);
+		READ_MEMBER(e[i].offset);
+		READ_MEMBER(e[i].size);
+	}
+
+	bpdt_print_entries(e, count, name);
+}
+
+/*
+ * Given type of component, identify BPDT entry for it.
+ * Component could lie either within BPDT or S-BPDT.
+ */
+static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
+					       size_t count, int type)
+{
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (e[i].type == type)
+			break;
+	}
+
+	if (i == count)
+		return NULL;
+
+	return &e[i];
+}
+
+static struct bpdt_entry *find_entry_by_type(int type)
+{
+	struct bpdt *b = buffer_get(&ifwi_image.bpdt);
+	assert(b);
+
+	struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
+						       b->h.descriptor_count,
+						       type);
+
+	if (curr)
+		return curr;
+
+	b = buffer_get(&ifwi_image.comp_buf[S_BPDT_TYPE]);
+	assert(b);
+
+	return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
+}
+
+/*
+ * Find component type given its name. If the name does not exist, returns -1.
+ */
+static int find_type_by_name(const char *name)
+{
+	int i;
+
+	for (i = 0; i < MAX_COMPS; i++) {
+		if ((strlen(comp[i].name) == strlen(name)) &&
+		    (!strcmp(comp[i].name, name)))
+			break;
+	}
+
+	if (i == MAX_COMPS) {
+		ERROR("Invalid component name %s.\n", name);
+		return -1;
+	}
+
+	return i;
+}
+
+/*
+ * Read the content of a component from input file and store it in
+ * ifwi_image.comp_buf[COMPONENT_TYPE].
+ *
+ * Returns the maximum offset occupied by the components.
+ */
+static size_t read_comp_buf(void *data, size_t size, struct bpdt_entry *e,
+			    size_t count)
+{
+	size_t i, type;
+	struct buffer *buf;
+	size_t max_offset = 0;
+
+	for (i = 0; i < count; i++) {
+		type = e[i].type;
+
+		if (type >= MAX_COMPS) {
+			ERROR("Invalid component type %zd.\n", type);
+			exit(-1);
+		}
+
+		if (buffer_size(&ifwi_image.comp_buf[type])) {
+			ERROR("Multiple components of type %zd(%s).\n", type,
+			      comp[type].name);
+			exit(-1);
+		}
+
+		if (e[i].size == 0) {
+			INFO("Dummy component %zd(%s). Skipping.\n", type,
+			     comp[type].name);
+			continue;
+		}
+
+		assert((e[i].offset + e[i].size) <= size);
+
+		if ((e[i].offset + e[i].size) > max_offset)
+			max_offset = e[i].offset + e[i].size;
+
+		/* Needs special handling for S-BPDT component. */
+		if (type == S_BPDT_TYPE)
+			continue;
+
+		buf = &ifwi_image.comp_buf[type];
+
+		alloc_buffer(buf, e[i].size, comp[type].name);
+		memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
+		       e[i].size);
+	}
+
+	assert(max_offset);
+	return max_offset;
+}
+
+/*
+ * Allocate buffer for bpdt header, entries and all component content.
+ * Returns offset in data where BPDT ends.
+ */
+static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
+				struct buffer *b, const char *name)
+{
+	struct bpdt_header bpdt_header;
+	assert((offset + BPDT_HEADER_SIZE) < size);
+	bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
+
+	/* Buffer to read BPDT header and entries. */
+	alloc_buffer(b, BPDT_SIZE(bpdt_header.descriptor_count), name);
+
+	struct bpdt *bpdt = buffer_get(b);
+	memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
+
+	/*
+	 * If no entries are present, maximum offset occupied is (offset +
+	 * BPDT_HEADER_SIZE).
+	 */
+	if (bpdt->h.descriptor_count == 0)
+		return (offset + BPDT_HEADER_SIZE);
+
+	/* Read all entries. */
+	assert((offset + BPDT_SIZE(bpdt->h.descriptor_count)) < size);
+	bpdt_read_entries((uint8_t *)data + offset, &bpdt->e[0],
+			  bpdt->h.descriptor_count, name);
+
+	/* Read all component content in comp_buf. */
+	return read_comp_buf(data, size, &bpdt->e[0], bpdt->h.descriptor_count);
+}
+
+static void parse_sbpdt(void *data, size_t size)
+{
+	struct bpdt_entry *s;
+	s  = find_entry_by_type(S_BPDT_TYPE);
+	if (!s)
+		return;
+
+	assert(size > s->offset);
+
+	alloc_bpdt_buffer(data, size, s->offset,
+			  &ifwi_image.comp_buf[S_BPDT_TYPE],
+			  "S-BPDT");
+}
+
+static uint8_t calc_checksum(struct subpart *s)
+{
+	size_t size = SUBPART_SIZE(s->h.num_entries);
+	uint8_t *data = (uint8_t *)s;
+	uint8_t checksum = 0;
+	size_t i;
+
+	uint8_t old_checksum = s->h.checksum;
+	s->h.checksum = 0;
+
+	for (i = 0; i < size; i++) {
+		checksum ^= data[i];
+	}
+
+	s->h.checksum = old_checksum;
+	return checksum;
+}
+
+static void validate_subpart(const char *name)
+{
+	struct subpart *s = buffer_get(&ifwi_image.subpart);
+
+	if ((s->h.marker != SUBPART_MARKER) ||
+	    (s->h.header_version != SUBPART_HEADER_VERSION_SUPPORTED) ||
+	    (s->h.entry_version != SUBPART_ENTRY_VERSION_SUPPORTED) ||
+	    (s->h.header_length != SUBPART_HEADER_SIZE)) {
+		ERROR("Invalid subpart for %s.\n", name);
+		exit(-1);
+	}
+
+	uint8_t checksum = calc_checksum(s);
+
+	if (checksum != s->h.checksum)
+		ERROR("Invalid checksum for %s(Expected=0x%x,Current=0x%x).\n",
+		      name, checksum, s->h.checksum);
+}
+
+static void parse_subpart(struct buffer *b, const char *name)
+{
+	struct buffer *s = &ifwi_image.subpart;
+	buffer_delete(s);
+
+	struct subpart_header hdr;
+	size_t offset = 0;
+	uint8_t *data = buffer_get(b);
+	size_t size = buffer_size(b);
+
+	/* Read Subpart header. */
+	assert(size >= SUBPART_HEADER_SIZE);
+	READ_MEMBER(hdr.marker);
+	READ_MEMBER(hdr.num_entries);
+	READ_MEMBER(hdr.header_version);
+	READ_MEMBER(hdr.entry_version);
+	READ_MEMBER(hdr.header_length);
+	READ_MEMBER(hdr.checksum);
+	memcpy(hdr.name, data + offset, sizeof(hdr.name));
+	offset += sizeof(hdr.name);
+
+	assert(size > SUBPART_SIZE(hdr.num_entries));
+	alloc_buffer(s, SUBPART_SIZE(hdr.num_entries), "Subpart");
+	memcpy(buffer_get(s), &hdr, SUBPART_HEADER_SIZE);
+
+	/* Read Subpart entries. */
+	struct subpart *subpart = buffer_get(s);
+	struct subpart_entry *e = &subpart->e[0];
+	uint32_t i;
+	for (i = 0; i < hdr.num_entries; i++) {
+		memcpy(e[i].name, data + offset, sizeof(e[i].name));
+		offset += sizeof(e[i].name);
+		READ_MEMBER(e[i].offset);
+		READ_MEMBER(e[i].length);
+		READ_MEMBER(e[i].rsvd);
+	}
+
+	validate_subpart(name);
+	print_subpart(name);
+}
+
+/* Parse input image file to identify different components. */
+static int ifwi_parse(void)
+{
+	DEBUG("Parsing IFWI image...\n");
+	const char *image_name = param.image_name;
+
+	/* Read input file. */
+	struct buffer buff;
+	if (buffer_from_file(&buff, image_name)) {
+		ERROR("Failed to read input file %s.\n", image_name);
+		return -1;
+	}
+
+	INFO("Buffer %p size 0x%zx\n", buff.data, buff.size);
+
+	/* Look for BPDT signature at 4K intervals. */
+	size_t offset = 0;
+	void *data = buffer_get(&buff);
+
+	while (offset < buffer_size(&buff)) {
+		if (read_at_le32(data, offset) == BPDT_SIGNATURE)
+			break;
+		offset += 4 * KiB;
+	}
+
+	if (offset >= buffer_size(&buff)) {
+		ERROR("Image does not contain BPDT!!\n");
+		return -1;
+	}
+
+	/* Read non-IFWI prefix, if present. */
+	if (offset) {
+		INFO("File contains non-IFWI prefix (size=0x%zx)\n", offset);
+		alloc_buffer(&ifwi_image.non_ifwi_prefix, offset,
+			     "Non-IFWI Prefix");
+		memcpy(buffer_get(&ifwi_image.non_ifwi_prefix), data, offset);
+	}
+
+	data = (uint8_t *)data + offset;
+	size_t ifwi_size = buffer_size(&buff) - offset;
+
+	/* Read BPDT and components. */
+	uintptr_t end_offset = alloc_bpdt_buffer(data, ifwi_size, 0,
+						 &ifwi_image.bpdt, "BPDT");
+
+	/* Parse S-BPDT, if any. */
+	parse_sbpdt(data, ifwi_size);
+
+	/*
+	 * Check if there is any non-IFWI suffix.
+	 * Assumption: non-IFWI suffix always starts on 4k boundary.
+	 */
+	end_offset = ALIGN(end_offset, 4 * KiB);
+
+	if (end_offset >= ifwi_size)
+		return 0;
+
+	size_t size = ifwi_size - end_offset;
+
+	INFO("File contains non-IFWI suffix (offset = 0x%zx, size=0x%zx)\n",
+	     end_offset, size);
+	alloc_buffer(&ifwi_image.non_ifwi_suffix, size,
+		     "Non-IFWI Suffix");
+	memcpy(buffer_get(&ifwi_image.non_ifwi_suffix),
+	       (uint8_t *)data + end_offset, size);
+
+	buffer_delete(&buff);
+
+	DEBUG("Parsing done\n");
+
+	return 0;
+}
+
+/*
+ * This function is used by repack to count the number of BPDT and S-BPDT
+ * entries that are present. It frees the current buffers used by the entries
+ * and allocates fresh buffers that can be used for repacking. Returns BPDT
+ * entries which are empty and need to be filled in.
+ */
+static void __bpdt_reset(struct buffer *b, size_t count)
+{
+	struct bpdt *bpdt = buffer_get(b);
+
+	/* If count has not changed, just zero out BPDT entries. */
+	if (bpdt->h.descriptor_count == count) {
+		memset(&bpdt->e[0], 0, BPDT_ENTRY_SIZE * count);
+		return;
+	}
+
+	/* Else, re-allocate buffer of new size and then zero out entries. */
+	char *name = strdup(b->name);
+	assert(name);
+
+	struct bpdt_header temp;
+	bpdt->h.descriptor_count = count;
+	memcpy(&temp, &bpdt->h, BPDT_HEADER_SIZE);
+
+	buffer_delete(b);
+	alloc_buffer(b, BPDT_SIZE(count), name);
+
+	bpdt = buffer_get(b);
+
+	memcpy(&bpdt->h, &temp, BPDT_HEADER_SIZE);
+	if (count == 0)
+		return;
+
+	memset(&bpdt->e[0], 0, BPDT_ENTRY_SIZE * count);
+}
+
+static void bpdt_reset(void)
+{
+	size_t i;
+	size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
+
+	/* Count number of BPDT and S-BPDT entries. */
+	for (i = 0; i < MAX_COMPS; i++) {
+		if (buffer_size(&ifwi_image.comp_buf[i]) == 0) {
+			if (comp[i].attr & MANDATORY_BPDT_ENTRY) {
+				bpdt_count++;
+				dummy_bpdt_count++;
+			}
+			continue;
+		}
+
+		if (comp[i].attr & NON_CRITICAL_COMP)
+			sbpdt_count++;
+		else
+			bpdt_count++;
+	}
+
+	DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
+	      dummy_bpdt_count, sbpdt_count);
+
+	/* Update BPDT if required. */
+	__bpdt_reset(&ifwi_image.bpdt, bpdt_count);
+
+	/* Update S-BPDT if required. */
+	__bpdt_reset(&ifwi_image.comp_buf[S_BPDT_TYPE], sbpdt_count);
+}
+
+/* Initialize BPDT entries in header order. */
+static void bpdt_entries_init_header_order(void)
+{
+	int i, type;
+	size_t size;
+
+	struct bpdt *bpdt, *sbpdt, *curr;
+	size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
+
+	bpdt = buffer_get(&ifwi_image.bpdt);
+	sbpdt = buffer_get(&ifwi_image.comp_buf[S_BPDT_TYPE]);
+
+	for (i = 0; i < MAX_COMPS; i++) {
+		type = bpdt_header_order[i];
+		size = buffer_size(&ifwi_image.comp_buf[type]);
+
+		if ((size == 0) && !(comp[type].attr & MANDATORY_BPDT_ENTRY))
+			continue;
+
+		if (comp[type].attr & NON_CRITICAL_COMP) {
+			curr = sbpdt;
+			count_ptr = &sbpdt_curr;
+		} else {
+			curr = bpdt;
+			count_ptr = &bpdt_curr;
+		}
+
+		assert(*count_ptr < curr->h.descriptor_count);
+		curr->e[*count_ptr].type = type;
+		curr->e[*count_ptr].flags = 0;
+		curr->e[*count_ptr].offset = 0;
+		curr->e[*count_ptr].size = size;
+
+		(*count_ptr)++;
+	}
+}
+
+/* Initialize offsets of entries using pack order. */
+static void bpdt_entries_init_pack_order(void)
+{
+	int i, type;
+	struct bpdt_entry *curr;
+	uint32_t alignment;
+	size_t curr_offset;
+	size_t max_offset = 0;
+
+	curr_offset = MAX(512, buffer_size(&ifwi_image.bpdt));
+
+	for (i = 0; i < MAX_COMPS; i++) {
+		type = bpdt_pack_order[i];
+		curr = find_entry_by_type(type);
+
+		if ((curr == NULL) || (curr->size == 0))
+			continue;
+
+		if (comp[type].attr & LIES_WITHIN_BPDT_4K)
+			alignment = 1;
+		else
+			alignment = 4 * KiB;
+
+		curr->offset = ALIGN(curr_offset, alignment);
+		curr_offset = curr->offset + curr->size;
+
+		if (max_offset < curr_offset)
+			max_offset = curr_offset;
+	}
+
+	/*
+	 * Update size of S-BPDT to include size of all non-critical
+	 * components.
+	 *
+	 * Assumption: S-BPDT always lies at the end of IFWI image.
+	 */
+	curr = find_entry_by_type(S_BPDT_TYPE);
+	assert(curr);
+
+	curr->size = max_offset - curr->offset;
+}
+
+/*
+ * Copy data from src to dst.
+ * curr_offset identifies the offset upto which data is written to in dst.
+ * write_offset identifies the offset at which data from src is to be written to
+ * dst.
+ *
+ * This function fills up FF in any hole present between end of last
+ * write(curr_offset) and offset for current src(write_offset).
+ *
+ * IMPORTANT: data_copy needs to be called in ascending order of write_offset to
+ * properly fill up holes with FF.
+ */
+static void data_copy(struct buffer *dst, size_t *curr_offset,
+		      size_t write_offset, struct buffer *src)
+{
+        uint8_t *data_dst = buffer_get(dst);
+	uint8_t *data_src = buffer_get(src);
+
+	assert(data_dst);
+
+	if (buffer_size(src) == 0)
+		return;
+
+	if (*curr_offset < write_offset)
+		memset(data_dst + *curr_offset, 0xFF,
+		       write_offset - *curr_offset);
+
+	memcpy(data_dst + write_offset, data_src, buffer_size(src));
+
+	*curr_offset = write_offset + buffer_size(src);
+}
+
+/*
+ * Identify the next entry that lies immediately above or at the passed in
+ * offset. Component could lie either within BPDT or S-BPDT.
+ *
+ * entries = Entries in BPDT or S-BPDT
+ * count   = Total number of entries in BPDT or S-BPDT
+ * offset  = Offset at or above which the next component lies at
+ */
+static struct bpdt_entry *__get_next_entry(struct bpdt *bpdt, size_t offset)
+{
+	uint32_t i;
+	size_t lowest_offset = SIZE_MAX;
+	struct bpdt_entry *next = NULL;
+
+	for (i = 0; i < bpdt->h.descriptor_count; i++) {
+		if (bpdt->e[i].offset == offset) {
+			next = &bpdt->e[i];
+			break;
+		}
+
+		if ((bpdt->e[i].offset > offset) &&
+		    (bpdt->e[i].offset < lowest_offset)) {
+			lowest_offset = bpdt->e[i].offset;
+			next = &bpdt->e[i];
+		}
+	}
+
+	return next;
+}
+
+static struct bpdt_entry *get_next_entry(size_t offset)
+{
+	struct bpdt_entry *next;
+	next = __get_next_entry(buffer_get(&ifwi_image.bpdt), offset);
+
+	if (next)
+		return next;
+
+	return __get_next_entry(buffer_get(&ifwi_image.comp_buf[S_BPDT_TYPE]),
+				offset);
+}
+
+/* Convert all members of BPDT to little-endian format. */
+static void bpdt_fixup_write_buffer(struct buffer *buf)
+{
+	struct bpdt *s = buffer_get(buf);
+
+	struct bpdt_header *h = &s->h;
+	struct bpdt_entry *e = &s->e[0];
+
+	size_t count = h->descriptor_count;
+
+	size_t offset = 0;
+
+	FIX_MEMBER(h->signature);
+	FIX_MEMBER(h->descriptor_count);
+	FIX_MEMBER(h->bpdt_version);
+	FIX_MEMBER(h->xor_redundant_block);
+	FIX_MEMBER(h->ifwi_version);
+	FIX_MEMBER(h->fit_tool_version);
+
+	uint32_t i;
+	for (i = 0; i < count; i++) {
+		FIX_MEMBER(e[i].type);
+		FIX_MEMBER(e[i].flags);
+		FIX_MEMBER(e[i].offset);
+		FIX_MEMBER(e[i].size);
+	}
+}
+
+/* Write BPDT to output buffer after fixup. */
+static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
+{
+	bpdt_fixup_write_buffer(src);
+	memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
+}
+
+/*
+ * Follows these steps to re-create image:
+ * 1. Write any non-IFWI prefix.
+ * 2. Write out BPDT header and entries.
+ * 3. Write component buffers to respective offsets.
+ * 4. Write any non-IFWI suffix.
+ *
+ * While performing the above steps, make sure that any empty holes are filled
+ * with FF.
+ */
+static void ifwi_write(const char *image_name)
+{
+	struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
+	assert(s);
+
+	size_t bpdt_offset = buffer_size(&ifwi_image.non_ifwi_prefix);
+	size_t non_ifwi_suffix_offset = s->offset + s->size;
+	size_t non_ifwi_suffix_size = buffer_size(&ifwi_image.non_ifwi_suffix);
+
+	if (non_ifwi_suffix_size)
+		non_ifwi_suffix_offset = ALIGN(s->offset + s->size, 4096);
+
+	size_t total_size = bpdt_offset + non_ifwi_suffix_offset +
+		non_ifwi_suffix_size;
+
+	struct buffer b;
+	size_t curr_offset = 0;
+
+	alloc_buffer(&b, total_size, "Final-IFWI");
+
+	/* Copy non-IFWI prefix, if any. */
+	data_copy(&b, &curr_offset, 0, &ifwi_image.non_ifwi_prefix);
+
+	struct buffer bpdt;
+	buffer_splice(&bpdt, &b, curr_offset, buffer_size(&b) - curr_offset);
+
+	curr_offset = buffer_size(&ifwi_image.bpdt);;
+
+	/* Copy components. */
+	struct bpdt_entry *curr;
+	while (1) {
+		curr = get_next_entry(curr_offset);
+		if (curr == NULL)
+			break;
+
+		assert(curr->size != 0);
+		data_copy(&bpdt, &curr_offset, curr->offset,
+			  &ifwi_image.comp_buf[curr->type]);
+	}
+
+	assert (curr_offset == (s->offset + s->size));
+
+	/*
+	 * Copy non-IFWI suffix, if any.
+	 * Assumption: Non-IFWI suffix starts on 4k boundary.
+	 */
+	if (non_ifwi_suffix_size == 0) {
+		buffer_delete(&b);
+		return;
+	}
+
+	data_copy(&bpdt, &curr_offset, non_ifwi_suffix_offset,
+		  &ifwi_image.non_ifwi_suffix);
+
+	/*
+	 * Convert BPDT to little-endian format and write it to output buffer.
+	 * S-BPDT is written first and then BPDT.
+	 */
+	bpdt_write(&bpdt, s->offset, &ifwi_image.comp_buf[S_BPDT_TYPE]);
+	bpdt_write(&bpdt, 0, &ifwi_image.bpdt);
+
+	if (buffer_write_file(&b, image_name)) {
+		ERROR("File write error\n");
+		exit(-1);
+	}
+
+	buffer_delete(&b);
+}
+
+/*
+ * Calculate size and offset of each component again since it might have changed
+ * because of add/delete operation. Also, re-create BPDT and S-BPDT entries and
+ * write back the new IFWI image to file.
+ */
+static void ifwi_repack(void)
+{
+	bpdt_reset();
+	bpdt_entries_init_header_order();
+	bpdt_entries_init_pack_order();
+
+	struct bpdt *b = buffer_get(&ifwi_image.bpdt);
+	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
+
+	b = buffer_get(&ifwi_image.comp_buf[S_BPDT_TYPE]);
+	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
+
+	ifwi_write(param.image_name);
+}
+
+static enum ifwi_ret ifwi_raw_add(int type)
+{
+	if (buffer_from_file(&ifwi_image.comp_buf[type], param.file_name))
+		return COMM_ERR;
+
+	return REPACK_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_cbp_add(int type)
+{
+	if (!(comp[type].attr & CONTAINS_SUBPART) ||
+	    (comp[type].cbp_ops.cbp_add == NULL)) {
+		ERROR("Component %s(%d) does not support cbp ops.\n",
+		      comp[type].name, type);
+		return COMM_ERR;
+	}
+
+	return comp[type].cbp_ops.cbp_add(type);
+}
+
+static enum ifwi_ret ifwi_add(void)
+{
+	if (!param.file_name) {
+		ERROR("%s: -f option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	if (!param.comp_name) {
+		ERROR("%s: -n option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	int type = find_type_by_name(param.comp_name);
+	if (type == -1)
+		return COMM_ERR;
+
+	struct bpdt_comp *curr_comp = &comp[type];
+
+	if (curr_comp->attr & AUTO_GENERATED) {
+		ERROR("Cannot delete auto-generated components.\n");
+		return COMM_ERR;
+	}
+
+	if (buffer_size(&ifwi_image.comp_buf[type])) {
+		ERROR("Image already contains component %s(%d).\n",
+		      param.comp_name, type);
+		return COMM_ERR;
+	}
+
+	if (param.subpart_ops)
+		return ifwi_cbp_add(type);
+
+	return ifwi_raw_add(type);
+}
+
+static enum ifwi_ret ifwi_delete(void)
+{
+	if (!param.comp_name) {
+		ERROR("%s: -n option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	int type = find_type_by_name(param.comp_name);
+	if (type == -1)
+		return COMM_ERR;
+
+	struct bpdt_comp *curr_comp = &comp[type];
+
+	if (curr_comp->attr & AUTO_GENERATED) {
+		ERROR("Cannot delete auto-generated components.\n");
+		return COMM_ERR;
+	}
+
+	if (buffer_size(&ifwi_image.comp_buf[type]) == 0) {
+		ERROR("Image does not contain component %s(%d).\n",
+		      param.comp_name, type);
+		return COMM_ERR;
+	}
+
+	buffer_delete(&ifwi_image.comp_buf[type]);
+
+	INFO("Component %s(%d) deleted.\n", comp[type].name, type);
+
+	return REPACK_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_cbp_extract(int type)
+{
+	if (!(comp[type].attr & CONTAINS_SUBPART)) {
+		ERROR("Component %s(%d) does not support cbp ops.\n",
+		      comp[type].name, type);
+		return COMM_ERR;
+	}
+
+	parse_subpart(&ifwi_image.comp_buf[type], comp[type].name);
+
+	uint32_t i;
+	struct subpart *s = buffer_get(&ifwi_image.subpart);
+
+	for (i = 0; i < s->h.num_entries; i++) {
+		if (!strcmp((char *)s->e[i].name, param.file_name))
+			break;
+	}
+
+	if (i == s->h.num_entries) {
+		ERROR("File %s not found in subpartition for %s.\n",
+		      param.file_name, param.comp_name);
+		exit(-1);
+	}
+
+	struct buffer dst;
+
+	DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
+	      s->e[i].length);
+	buffer_splice(&dst, &ifwi_image.comp_buf[type], s->e[i].offset,
+		      s->e[i].length);
+
+	if (buffer_write_file(&dst, param.file_name))
+		return COMM_ERR;
+
+	INFO("Component %s(%d) stored in %s.\n", param.comp_name, type,
+	     param.file_name);
+
+	return NO_ACTION_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_raw_extract(int type)
+{
+	if (buffer_write_file(&ifwi_image.comp_buf[type], param.file_name))
+		return COMM_ERR;
+
+	INFO("Component %s(%d) stored in %s.\n", param.comp_name, type,
+	     param.file_name);
+
+	return NO_ACTION_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_extract(void)
+{
+	if (!param.file_name) {
+		ERROR("%s: -f option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	if (!param.comp_name) {
+		ERROR("%s: -n option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	int type = find_type_by_name(param.comp_name);
+	if (type == -1)
+		return COMM_ERR;
+
+	if (type == S_BPDT_TYPE) {
+		ERROR("Nothing to extract.\n");
+		return NO_ACTION_REQUIRED;
+	}
+
+	if (buffer_size(&ifwi_image.comp_buf[type]) == 0) {
+		ERROR("Image does not contain component %s(%d).\n",
+		      param.comp_name, type);
+		return COMM_ERR;
+	}
+
+	INFO("Extracting component %s(%d).\n", param.comp_name, type);
+	if (param.subpart_ops)
+		return ifwi_cbp_extract(type);
+
+	return ifwi_raw_extract(type);
+}
+
+static enum ifwi_ret ifwi_print(void)
+{
+	verbose += 2;
+
+	struct bpdt *b = buffer_get(&ifwi_image.bpdt);
+
+	bpdt_print_header(&b->h, "BPDT");
+	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
+
+	b = buffer_get(&ifwi_image.comp_buf[S_BPDT_TYPE]);
+	bpdt_print_header(&b->h, "S-BPDT");
+	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
+
+	int i;
+	for (i = 0; i < MAX_COMPS ; i++) {
+		if (!(comp[i].attr & CONTAINS_SUBPART) ||
+		    (buffer_size(&ifwi_image.comp_buf[i]) == 0))
+			continue;
+
+		parse_subpart(&ifwi_image.comp_buf[i], comp[i].name);
+	}
+
+	verbose -= 2;
+
+	return NO_ACTION_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_raw_replace(int type)
+{
+	if (buffer_size(&ifwi_image.comp_buf[type]) == 0) {
+		INFO("Image does not contain component %s(%d).\n",
+		     param.comp_name, type);
+	} else
+		buffer_delete(&ifwi_image.comp_buf[type]);
+
+	return ifwi_raw_add(type);
+}
+
+static void subpart_fixup_write_buffer(struct buffer *buf)
+{
+	struct subpart *s = buffer_get(buf);
+	struct subpart_header *h = &s->h;
+	struct subpart_entry *e = &s->e[0];
+
+	size_t count = h->num_entries;
+	size_t offset = 0;
+
+	FIX_MEMBER(h->marker);
+	FIX_MEMBER(h->num_entries);
+	FIX_MEMBER(h->header_version);
+	FIX_MEMBER(h->entry_version);
+	FIX_MEMBER(h->header_length);
+	FIX_MEMBER(h->checksum);
+	offset += sizeof(h->name);
+
+	uint32_t i;
+	for (i = 0; i < count; i++) {
+		offset += sizeof(e[i].name);
+		FIX_MEMBER(e[i].offset);
+		FIX_MEMBER(e[i].length);
+		FIX_MEMBER(e[i].rsvd);
+	}
+}
+
+static enum ifwi_ret ifwi_cbp_replace(int type)
+{
+	if (buffer_size(&ifwi_image.comp_buf[type]) == 0) {
+		ERROR("Image does not contain component %s(%d).\n",
+		      param.comp_name, type);
+		return COMM_ERR;
+	}
+
+	if (!(comp[type].attr & CONTAINS_SUBPART)) {
+		ERROR("Component %s(%d) does not support cbp ops.\n",
+		      comp[type].name, type);
+		return COMM_ERR;
+	}
+
+	parse_subpart(&ifwi_image.comp_buf[type], comp[type].name);
+
+	uint32_t i;
+	struct subpart *s = buffer_get(&ifwi_image.subpart);
+
+	for (i = 0; i < s->h.num_entries; i++) {
+		if (!strcmp((char *)s->e[i].name, param.file_name))
+			break;
+	}
+
+	if (i == s->h.num_entries) {
+		ERROR("File %s not found in subpartition for %s.\n",
+		      param.file_name, param.comp_name);
+		exit(-1);
+	}
+
+	struct buffer b;
+	if (buffer_from_file(&b, param.file_name)) {
+		ERROR("Failed to read %s\n", param.file_name);
+		exit(-1);
+	}
+
+	struct buffer dst;
+	size_t dst_size = buffer_size(&ifwi_image.comp_buf[type] +
+				      buffer_size(&b) - s->e[i].length);
+	size_t comp_start = s->e[i].offset;
+	size_t comp_end = s->e[i].offset + s->e[i].length;
+
+	alloc_buffer(&dst, dst_size, ifwi_image.comp_buf[type].name);
+
+	uint8_t *src_data = buffer_get(&ifwi_image.comp_buf[type]);
+	uint8_t *dst_data = buffer_get(&dst);
+	size_t curr_offset = 0;
+
+	/* Copy data before the sub-partition entry. */
+	memcpy(dst_data + curr_offset, src_data, comp_start);
+	curr_offset += comp_start;
+
+	/* Copy sub-partition entry. */
+	memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
+	curr_offset += buffer_size(&b);
+
+	/* Copy remaining data. */
+	memcpy(dst_data + curr_offset, src_data + comp_end,
+	       buffer_size(&ifwi_image.comp_buf[type]) - comp_end);
+
+	/* Update component buffer. */
+	int offset = s->e[i].offset;
+	buffer_delete(&ifwi_image.comp_buf[type]);
+	ifwi_image.comp_buf[type] = dst;
+
+	/* Update length of entry in the subpartition. */
+	s->e[i].length = buffer_size(&b);
+	buffer_delete(&b);
+
+	/* Adjust offsets of affected entries in subpartition. */
+	offset = s->e[i].offset - offset;
+	for (; i < s->h.num_entries; i++) {
+		s->e[i].offset += offset;
+	}
+
+	/* Re-calculate checksum. */
+	s->h.checksum = calc_checksum(s);
+
+	/* Convert members to litte-endian. */
+	subpart_fixup_write_buffer(&ifwi_image.subpart);
+
+	memcpy(dst_data, buffer_get(&ifwi_image.subpart),
+	       buffer_size(&ifwi_image.subpart));
+
+	buffer_delete(&ifwi_image.subpart);
+
+	return REPACK_REQUIRED;
+}
+
+static enum ifwi_ret ifwi_replace(void)
+{
+	if (!param.file_name) {
+		ERROR("%s: -f option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	if (!param.comp_name) {
+		ERROR("%s: -n option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	int type = find_type_by_name(param.comp_name);
+	if (type == -1)
+		return COMM_ERR;
+
+	struct bpdt_comp *curr_comp = &comp[type];
+
+	if (curr_comp->attr & AUTO_GENERATED) {
+		ERROR("Cannot replace auto-generated components.\n");
+		return COMM_ERR;
+	}
+
+	if (param.subpart_ops)
+		return ifwi_cbp_replace(type);
+
+	return ifwi_raw_replace(type);
+}
+
+static enum ifwi_ret ifwi_create(void)
+{
+	if (!param.file_name) {
+		ERROR("%s: -f option required\n", __func__);
+		return COMM_ERR;
+	}
+
+	buffer_delete(&ifwi_image.non_ifwi_prefix);
+	buffer_delete(&ifwi_image.non_ifwi_suffix);
+
+	param.image_name = param.file_name;
+
+	return REPACK_REQUIRED;
+}
+
+struct command {
+	const char *name;
+	const char *optstring;
+	enum ifwi_ret (*function)(void);
+};
+
+static const struct command commands[] = {
+	{"add", "f:n:svh?", ifwi_add},
+	{"create", "f:vh?", ifwi_create},
+	{"delete", "f:n:vh?", ifwi_delete},
+	{"extract", "f:n:svh?", ifwi_extract},
+	{"print", "h?", ifwi_print},
+	{"replace", "f:n:svh?", ifwi_replace},
+};
+
+static struct option long_options[] = {
+	{"file",	required_argument, 0, 'f'},
+	{"help",	required_argument, 0, 'h'},
+	{"name",	required_argument, 0, 'n'},
+	{"subpart_ops", no_argument,       0, 's'},
+	{"verbose",	no_argument,       0, 'v'},
+	{NULL,		0,                 0,  0 }
+};
+
+static void usage(const char *name)
+{
+	printf("ifwitool: Utility for IFWI manipulation\n\n"
+	       "USAGE:\n"
+	       " %s [-h]\n"
+	       " %s FILE COMMAND [PARAMETERS]\n\n"
+	       "COMMANDs:\n"
+	       " add -f FILE -n NAME\n"
+	       " create -f FILE\n"
+	       " delete -n NAME\n"
+	       " extract -f FILE -n NAME\n"
+	       " print\n"
+	       " replace -f FILE -n NAME\n",
+	       name, name
+	       );
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 3) {
+		usage(argv[0]);
+		return 1;
+	}
+
+	param.image_name = argv[1];
+	char *cmd = argv[2];
+	optind += 2;
+
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		if (strcmp(cmd, commands[i].name) != 0)
+			continue;
+
+		int c;
+
+		while (1) {
+			int option_index;
+
+			c = getopt_long(argc, argv, commands[i].optstring,
+					long_options, &option_index);
+
+			if (c == -1)
+				break;
+
+			/* Filter out illegal long options. */
+			if (strchr(commands[i].optstring, c) == NULL) {
+				ERROR("%s: invalid option -- '%c'\n", argv[0],
+				      c);
+				c = '?';
+			}
+
+			switch(c) {
+			case 'n':
+				param.comp_name = optarg;
+				break;
+			case 'f':
+				param.file_name = optarg;
+				break;
+			case 's':
+				param.subpart_ops = 1;
+				break;
+			case 'v':
+				verbose++;
+				break;
+			case 'h':
+			case '?':
+				usage(argv[0]);
+				return 1;
+			default:
+				break;
+			}
+		}
+
+		if (ifwi_parse()) {
+			ERROR("%s: ifwi parsing failed\n", argv[0]);
+			return 1;
+		}
+
+		enum ifwi_ret ret = commands[i].function();
+
+		if (ret == COMM_ERR) {
+			ERROR("%s: failed execution\n", argv[0]);
+			return 1;
+		}
+
+		if (ret == REPACK_REQUIRED)
+			ifwi_repack();
+
+		return 0;
+	}
+
+	ERROR("%s: invalid command\n", argv[0]);
+	return 1;
+}



More information about the coreboot-gerrit mailing list