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

Furquan Shaikh (furquan@google.com) gerrit at coreboot.org
Wed May 18 23:12:44 CEST 2016


Furquan Shaikh (furquan at google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14896

-gerrit

commit 284e5dc333c39130c8c0d2404f926b27ec22df0d
Author: Furquan Shaikh <furquan at google.com>
Date:   Wed May 18 14:12:20 2016 -0700

    WIP: Add ifwitool for managing IFWI images
    
    Still needs work to allow building using Makefile, support for subdir.
    
    Change-Id: I683a0ab13cc50eb60eecca34db4a8ffefc8dccbd
    Signed-off-by: Furquan Shaikh <furquan at google.com>
---
 util/ifwitool/buffer.c          |  55 +++
 util/ifwitool/buffer.h          |  39 ++
 util/ifwitool/console.h         |  40 ++
 util/ifwitool/file_operations.c | 133 ++++++
 util/ifwitool/file_operations.h |  28 ++
 util/ifwitool/ifwitool.c        | 890 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 1185 insertions(+)

diff --git a/util/ifwitool/buffer.c b/util/ifwitool/buffer.c
new file mode 100644
index 0000000..29f969b
--- /dev/null
+++ b/util/ifwitool/buffer.c
@@ -0,0 +1,55 @@
+/*
+ * 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 "buffer.h"
+
+#define NO_DEBUG
+
+#include "console.h"
+
+struct buffer *buffer_get(uint32_t size)
+{
+	struct buffer *buf = malloc(sizeof(*buf));
+	if (!buf) {
+		ERROR("Memory allocation failure (size = 0x%zx).\n",
+		      sizeof(*buf));
+		return NULL;
+	}
+
+	buf->data = malloc(size);
+	if (!buf->data) {
+		ERROR("Memory allocation failure (size = 0x%x).\n", size);
+		free(buf);
+		return NULL;
+	}
+
+	buf->size = size;
+
+	DEBUG("============== New buffer allocated ======================\n");
+	DEBUG("buf: %p\n", buf);
+	DEBUG("buf->data: %p\n", buf->data);
+	DEBUG("buf->size: 0x%x\n", buf->size);
+
+	return buf;
+}
+
+void buffer_free(struct buffer *buf)
+{
+	DEBUG("============== Freeing buffer ======================\n");
+	DEBUG("buf: %p\n", buf);
+	DEBUG("buf->data: %p\n", buf->data);
+	DEBUG("buf->size: 0x%x\n", buf->size);
+
+	free(buf->data);
+	free(buf);
+}
diff --git a/util/ifwitool/buffer.h b/util/ifwitool/buffer.h
new file mode 100644
index 0000000..e968d29
--- /dev/null
+++ b/util/ifwitool/buffer.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef __IFWITOOL_BUFFER_H__
+#define __IFWITOOL_BUFFER_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct buffer {
+	void *data;
+	uint32_t size;
+};
+
+struct buffer *buffer_get(uint32_t size);
+void buffer_free(struct buffer *buf);
+struct buffer *buffer_clone(struct buffer *buf, uint32_t size);
+
+static inline void *buffer_data(struct buffer *buf)
+{
+	return buf->data;
+}
+
+static inline uint32_t buffer_size(struct buffer *buf)
+{
+	return buf->size;
+}
+
+#endif /* __IFWITOOL_BUFFER_H__ */
diff --git a/util/ifwitool/console.h b/util/ifwitool/console.h
new file mode 100644
index 0000000..a16304b
--- /dev/null
+++ b/util/ifwitool/console.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef __IFWITOOL_CONSOLE_H__
+#define __IFWITOOL_CONSOLE_H__
+
+#include <stdio.h>
+
+extern int verbose;
+
+#define ERROR(...)	{ fprintf(stderr, "E: " __VA_ARGS__); }
+#define WARN(...)	{ fprintf(stderr, "W: " __VA_ARGS__); }
+#define LOG(...)	{ fprintf(stderr, __VA_ARGS__); }
+
+#ifndef NO_DEBUG
+
+#define INFO(...)	{ if (verbose > 0) fprintf(stderr, "I: " __VA_ARGS__); }
+#define DEBUG(...)	{ if (verbose > 2) fprintf(stderr, __VA_ARGS__); \
+			  else if (verbose > 1) fprintf(stderr, "D: " \
+							__VA_ARGS__); }
+
+#else	/* NO_DEBUG */
+
+#define INFO(...)	{}
+#define DEBUG(...)	{}
+
+#endif  /* NO_DEBUG */
+
+
+#endif /* __IFWITOOL_CONSOLE_H__ */
diff --git a/util/ifwitool/file_operations.c b/util/ifwitool/file_operations.c
new file mode 100644
index 0000000..0893eb5
--- /dev/null
+++ b/util/ifwitool/file_operations.c
@@ -0,0 +1,133 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "console.h"
+#include "file_operations.h"
+
+static FILE *file_open(const char *file_name, const char *flags)
+{
+	FILE *fp = fopen(file_name, flags);
+	if (!fp) {
+		ERROR("File open error %s.\n", file_name);
+		exit(-1);
+	}
+
+	return fp;
+}
+
+int32_t file_get_size(FILE *fp)
+{
+	int32_t size = -1;
+
+	if (fseek(fp, 0, SEEK_END)) {
+		ERROR("File seek error (offset = EOF).\n");
+		goto err;
+	}
+
+	size = ftell(fp);
+	if (size == -1) {
+		ERROR("File tell error.\n");
+		goto err;
+	}
+
+	if (fseek(fp, 0, SEEK_SET)) {
+		ERROR("File seek error (offset = 0).\n");
+		goto err;
+	}
+
+	return size;
+
+err:
+	fclose(fp);
+	exit(-1);
+}
+
+FILE *file_open_read(const char *file_name)
+{
+	return file_open(file_name, "rb");
+}
+
+FILE *file_open_write(const char *file_name)
+{
+	return file_open(file_name, "wb");
+}
+
+void file_read(void *buf, uint32_t size, FILE *fp, uint32_t offset)
+{
+	if (fseek(fp, offset, SEEK_SET)) {
+		ERROR("File seek error (offset = 0x%x).\n", offset);
+		goto err;
+	}
+
+	if (fread(buf, 1, size, fp) != size) {
+		ERROR("File read error (offset = 0x%x).\n", offset);
+		goto err;
+	}
+
+	return;
+err:
+	fclose(fp);
+	exit(-1);
+}
+
+void file_write(void *buf, uint32_t size, FILE *fp, uint32_t offset)
+{
+	if (fseek(fp, offset, SEEK_SET)) {
+		ERROR("File seek error (offset = 0x%x).\n", offset);
+		goto err;
+	}
+
+	if (fwrite(buf, 1, size, fp) != size) {
+		ERROR("File write error (offset = 0x%x).\n", offset);
+		goto err;
+	}
+
+	return;
+
+err:
+	fclose(fp);
+	exit(-1);
+}
+
+void file_write_dummy(FILE *fp, uint32_t offset, uint32_t size)
+{
+	if (fseek(fp, offset, SEEK_SET)) {
+		ERROR("File seek error (offset = 0x%x).\n", offset);
+		goto err;
+	}
+
+	void *buf = malloc(size);
+	if (!buf) {
+		ERROR("Memory allocation failure (size = 0x%x).\n", size);
+		goto err;
+	}
+
+	memset(buf, 0xFF, size);
+
+	if (fwrite(buf, 1, size, fp) != size) {
+		ERROR("File write error (offset = 0x%x).\n", offset);
+		goto err;
+	}
+
+	free(buf);
+
+	return;
+
+
+err:
+	fclose(fp);
+	exit(-1);
+}
diff --git a/util/ifwitool/file_operations.h b/util/ifwitool/file_operations.h
new file mode 100644
index 0000000..5fff54a
--- /dev/null
+++ b/util/ifwitool/file_operations.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef __IFWITOOL_FILE_OPERATIONS_H__
+#define __IFWITOOL_FILE_OPERATIONS_H__
+
+#include <stdint.h>
+#include <stdio.h>
+
+FILE *file_open_read(const char *file_name);
+FILE *file_open_write(const char *file_name);
+
+void file_read(void *buf, uint32_t size, FILE *fp, uint32_t offset);
+void file_write(void *buf, uint32_t size, FILE *fp, uint32_t offset);
+
+int32_t file_get_size(FILE *fp);
+
+#endif /* __IFWITOOL_FILE_OPERATIONS_H__ */
diff --git a/util/ifwitool/ifwitool.c b/util/ifwitool/ifwitool.c
new file mode 100644
index 0000000..f0108f6
--- /dev/null
+++ b/util/ifwitool/ifwitool.c
@@ -0,0 +1,890 @@
+/*
+ * 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 <assert.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "buffer.h"
+#include "console.h"
+#include "file_operations.h"
+
+#define ARRAY_SIZE(a)		(sizeof(a) / sizeof((a)[0]))
+#define ALIGN(val, by)		(((val) + (by) - 1) & ~((by) - 1))
+
+#define BPDT_SIGNATURE		(0x000055AA)
+
+int verbose = 0;
+
+static struct param {
+	const char *file_name;
+	const char *comp_name;
+} 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;
+};
+
+struct bpdt_entry {
+	uint16_t type;
+	uint16_t flags;
+	uint32_t offset;
+	uint32_t size;
+};
+
+enum comp_attributes {
+	ALIGNED_4K = (1 << 0),
+	LIES_WITHIN_BPDT_4K = (1 << 1),
+	S_BPDT_ENTRY = (1 << 2),
+	CONTAINS_SUBDIR = (1 << 3),
+	AUTO_GENERATED = (1 << 4),
+	MANDATORY_BPDT_ENTRY = (1 << 5),
+};
+
+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,
+};
+
+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,
+	IBB_TYPE,
+	UEP_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,
+};
+
+struct bpdt_comp {
+	const char *name;
+	enum comp_attributes attr;
+	const char *subdir_name;
+} comp[MAX_COMPS] = {
+	/* OEM SMIP */
+	{"SMIP", CONTAINS_SUBDIR, "SMIP"},
+	/* CSE RBE */
+	{"CSE_RBE", CONTAINS_SUBDIR | MANDATORY_BPDT_ENTRY, "RBEP"},
+	/* CSE BUP */
+	{"CSE_BUP", CONTAINS_SUBDIR | ALIGNED_4K | MANDATORY_BPDT_ENTRY,
+	 "FTPR"},
+	/* uCode */
+	{"uCODE", CONTAINS_SUBDIR, "UCOD"},
+	/* IBB */
+	{"bootblock", CONTAINS_SUBDIR, "IBBP"},
+	/* S-BPDT */
+	{"S_BPDT", AUTO_GENERATED | MANDATORY_BPDT_ENTRY, NULL},
+	/* OBB */
+	{"OBB", CONTAINS_SUBDIR | S_BPDT_ENTRY, "OBBP"},
+	/* CSE Main */
+	{"CSE_MAIN", S_BPDT_ENTRY, "NFTP"},
+	/* ISH */
+	{"ISH", S_BPDT_ENTRY, "ISHP"},
+	/* CSE IDLM */
+	{"CSE_IDLM", CONTAINS_SUBDIR | MANDATORY_BPDT_ENTRY, "DLMP"},
+	/* IFP Override */
+	{"IFP_OVERRIDE", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY, NULL},
+	/* Debug Tokens */
+	{"DEBUG_TOKENS", 0, NULL},
+	/* UFS Phy Configuration */
+	{"UFS_PHY", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY, NULL},
+	/* UFS GPP LUN ID */
+	{"UFS_GPP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY, NULL},
+	/* PMC */
+	{"PMC", CONTAINS_SUBDIR, "PMCP"},
+	/* IUNIT */
+	{"IUNIT", S_BPDT_ENTRY, "IUNP"},
+	/* NVM Config */
+	{"NVM_CONFIG", 0, NULL},
+	/* UEP */
+	{"UEP", /* LIES_WITHIN_BPDT_4K | */MANDATORY_BPDT_ENTRY, NULL},
+	/* UFS Rate B Config */
+	{"UFS_RATE_B", 0, NULL},
+};
+
+static void bpdt_header_print(struct bpdt_header *hdr, const char *name)
+{
+	DEBUG("%s Header:\n", name);
+	DEBUG("Signature: 0x%08x\n", hdr->signature);
+	DEBUG("Descriptor count: %d\n", hdr->descriptor_count);
+	DEBUG("BPDT Version: %d\n", hdr->bpdt_version);
+	DEBUG("Redundant Block XOR checksum: 0x%x\n", hdr->xor_redundant_block);
+	DEBUG("IFWI Version: 0x%x\n", hdr->ifwi_version);
+	DEBUG("FIT Tool Version: 0x%lx\n", hdr->fit_tool_version);
+}
+
+static void bpdt_create(struct bpdt_header *hdr)
+{
+	hdr->signature = BPDT_SIGNATURE;
+	hdr->descriptor_count = 0;
+	hdr->bpdt_version = 1;
+	hdr->xor_redundant_block = 0;
+	hdr->ifwi_version = 0;
+	hdr->fit_tool_version = 0;
+}
+
+static void bpdt_validate(struct bpdt_header *hdr, const char *name)
+{
+	if ((hdr->signature != BPDT_SIGNATURE) || (hdr->bpdt_version != 1)) {
+		ERROR("Invalid %s header.\n", name);
+		exit(-1);
+	}
+
+	INFO("Validated %s header.\n", name);
+	bpdt_header_print(hdr, name);
+}
+
+static void bpdt_entries_print(struct bpdt_entry *entry, uint32_t count)
+{
+	uint32_t i;
+
+	DEBUG("%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Type",
+	      "Flags", "Offset", "Size");
+
+	DEBUG("=============================================================="
+	      "=============================================================="
+	      "=======================\n");
+
+	for (i = 0; i < count; i++) {
+		DEBUG("%-25d%-25s%-25d0x%-23.08x0x%-23x0x%-23x\n", i+1,
+		      comp[entry[i].type].name, entry[i].type, entry[i].flags,
+		      entry[i].offset, entry[i].size);
+	}
+
+	DEBUG("=============================================================="
+	      "=============================================================="
+	      "=======================\n");
+}
+
+struct ifwi_image {
+	struct bpdt_header bpdt_header;
+	struct bpdt_header sbpdt_header;
+
+	struct buffer *bpdt_entries;
+	struct buffer *sbpdt_entries;
+
+	struct buffer *comp_buf[MAX_COMPS];
+} ifwi_image;
+
+static int read_comp_buf(struct bpdt_entry *entry, uint32_t count, FILE *fp)
+{
+	uint32_t type;
+	uint32_t i;
+
+	for (i = 0; i < count; i++) {
+		type = entry[i].type;
+
+		if (type == S_BPDT_TYPE) {
+			INFO ("Skipping copying S-BPDT.\n");
+			continue;
+		}
+
+		if (type >= MAX_COMPS) {
+			ERROR("Invalid type component %d.\n", type);
+			return -1;
+		}
+
+		if (ifwi_image.comp_buf[type]) {
+			ERROR("Multiple components of type %d.\n", type);
+			return -1;
+		}
+
+		if (entry[i].size == 0) {
+			INFO("Dummy component %d. Skipping.\n", type);
+			continue;
+		}
+
+		ifwi_image.comp_buf[type] = buffer_get(entry[i].size);
+
+		if (!ifwi_image.comp_buf[type])
+			return -1;
+
+		file_read(buffer_data(ifwi_image.comp_buf[type]), entry[i].size,
+			  fp, entry[i].offset);
+	}
+
+	return 0;
+}
+
+static struct bpdt_entry *__get_bpdt_entry_from_type(struct bpdt_entry *entries,
+						     uint32_t count,
+						     uint32_t type)
+{
+	uint32_t i;
+	for (i = 0; i < count; i++) {
+		if (entries[i].type == type)
+			return &entries[i];
+	}
+
+	return NULL;
+}
+
+static struct bpdt_entry *get_bpdt_entry_from_type(uint32_t type)
+{
+	struct bpdt_entry *curr;
+
+	curr = __get_bpdt_entry_from_type(buffer_data(ifwi_image.bpdt_entries),
+				       ifwi_image.bpdt_header.descriptor_count,
+				       type);
+
+	if (curr)
+		return curr;
+
+	return __get_bpdt_entry_from_type(buffer_data(ifwi_image.sbpdt_entries),
+				       ifwi_image.sbpdt_header.descriptor_count,
+				       type);
+}
+
+static struct bpdt_entry *__get_next_entry(struct bpdt_entry *entries,
+					   uint32_t count, uint32_t offset)
+{
+	uint32_t i;
+	uint32_t lowest_offset = UINT32_MAX;
+	struct bpdt_entry *next = NULL;
+
+	for (i = 0; i < count; i++) {
+		if (entries[i].offset == offset) {
+			next = &entries[i];
+			break;
+		}
+
+		if ((entries[i].offset > offset) &&
+		    (entries[i].offset < lowest_offset)) {
+			lowest_offset = entries[i].offset;
+			next = &entries[i];
+		}
+	}
+
+	return next;
+}
+
+static struct bpdt_entry *get_next_entry(uint32_t offset)
+{
+	struct bpdt_entry *next;
+	next = __get_next_entry(buffer_data(ifwi_image.bpdt_entries),
+				ifwi_image.bpdt_header.descriptor_count,
+				offset);
+
+	if (next)
+		return next;
+
+	return __get_next_entry(buffer_data(ifwi_image.sbpdt_entries),
+				ifwi_image.sbpdt_header.descriptor_count,
+				offset);
+}
+
+static void bpdt_reset(void)
+{
+	uint32_t i;
+	uint32_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 (ifwi_image.comp_buf[i] == NULL) {
+			if (comp[i].attr & MANDATORY_BPDT_ENTRY) {
+				bpdt_count++;
+				dummy_bpdt_count++;
+			}
+			continue;
+		}
+
+		if (comp[i].attr & S_BPDT_ENTRY)
+			sbpdt_count++;
+		else
+			bpdt_count++;
+	}
+
+	DEBUG("Count: BPDT = %d, Dummy BPDT = %d, S-BPDT = %d\n", bpdt_count,
+	      dummy_bpdt_count, sbpdt_count);
+
+	/* Update BPDT and S-BPDT entry counts. */
+	ifwi_image.bpdt_header.descriptor_count = bpdt_count;
+	ifwi_image.sbpdt_header.descriptor_count = sbpdt_count;
+
+	/* Free and reallocate buffers for entries. */
+	buffer_free(ifwi_image.bpdt_entries);
+	buffer_free(ifwi_image.sbpdt_entries);
+
+	ifwi_image.bpdt_entries = buffer_get(sizeof(struct bpdt_entry) *
+					     bpdt_count);
+	ifwi_image.sbpdt_entries = buffer_get(sizeof(struct bpdt_entry) *
+					      sbpdt_count);
+}
+
+static void sbpdt_fixup(struct bpdt_entry *sbpdt, uint32_t sbpdt_size)
+{
+	struct bpdt_entry *curr_entry;
+
+	/*
+	 * 1. Get first entry in S-BPDT.
+	 * 2. Check if there is any hole between end of S-BPDT and start of
+	 * first entry.
+	 * 3. Add this hole size to total size of S-BPDT.
+	 */
+	curr_entry = get_next_entry(sbpdt->offset + sbpdt->size);
+	if (curr_entry &&
+	    (curr_entry->offset != (sbpdt->offset + sbpdt->size))) {
+		sbpdt_size += curr_entry->offset -
+			(sbpdt->offset + sbpdt->size);
+	}
+
+	/*
+	 * Create comp_buf for S-BPDT so that it can be used by file writing
+	 * loop.
+	 */
+	ifwi_image.comp_buf[S_BPDT_TYPE] = buffer_get(sbpdt->size);
+	void *sbpdt_data = buffer_data(ifwi_image.comp_buf[S_BPDT_TYPE]);
+	memcpy(sbpdt_data, &ifwi_image.sbpdt_header,
+	       sizeof(struct bpdt_header));
+	memcpy((uint8_t *)sbpdt_data + sizeof(struct bpdt_header),
+	       buffer_data(ifwi_image.sbpdt_entries),
+	       buffer_size(ifwi_image.sbpdt_entries));
+
+	sbpdt->size += sbpdt_size;
+}
+
+static void ifwi_write(const char *image_name)
+{
+	FILE *fp = file_open_write(image_name);
+
+	uint32_t curr_offset = 0, type;
+	struct bpdt_entry *curr_entry;
+
+	/* BPDT */
+	file_write(&ifwi_image.bpdt_header, sizeof(struct bpdt_header), fp,
+		   curr_offset);
+	curr_offset += sizeof(struct bpdt_header);
+
+	/* BPDT entries */
+	file_write(buffer_data(ifwi_image.bpdt_entries),
+		   buffer_size(ifwi_image.bpdt_entries), fp, curr_offset);
+
+	curr_offset += buffer_size(ifwi_image.bpdt_entries);
+
+	while (1) {
+		curr_entry = get_next_entry(curr_offset);
+
+		if (curr_entry == NULL)
+			break;
+
+		assert(curr_entry->size != 0);
+
+		type = curr_entry->type;
+
+		if (curr_offset != curr_entry->offset)
+			file_write_dummy(fp, curr_offset,
+					 curr_entry->offset - curr_offset);
+
+		file_write(buffer_data(ifwi_image.comp_buf[type]),
+			   buffer_size(ifwi_image.comp_buf[type]),
+			   fp, curr_entry->offset);
+
+		curr_offset = curr_entry->offset +
+			buffer_size(ifwi_image.comp_buf[type]);
+	}
+
+	fclose(fp);
+}
+
+static void ifwi_repack(const char *image_name)
+{
+	bpdt_reset();
+
+	uint32_t i;
+	struct bpdt_entry *bpdt_entries, *sbpdt_entries, *curr_entry, *sbpdt;
+	uint32_t sbpdt_size = 0, size, type;
+	uint32_t bpdt_count, sbpdt_count, bpdt_curr = 0, sbpdt_curr = 0;
+
+	bpdt_entries = buffer_data(ifwi_image.bpdt_entries);
+	bpdt_count = ifwi_image.bpdt_header.descriptor_count;
+	sbpdt_entries = buffer_data(ifwi_image.sbpdt_entries);
+	sbpdt_count = ifwi_image.sbpdt_header.descriptor_count;
+
+	/* Initialize all entries using header_order. */
+	for (i = 0; i < ARRAY_SIZE(comp); i++) {
+		type = bpdt_header_order[i];
+
+		if (ifwi_image.comp_buf[type])
+			size = buffer_size(ifwi_image.comp_buf[type]);
+		else
+			size = 0;
+
+		if ((size == 0) && !(comp[type].attr & MANDATORY_BPDT_ENTRY))
+			continue;
+
+		if (comp[type].attr & S_BPDT_ENTRY) {
+			assert(sbpdt_curr < sbpdt_count);
+			curr_entry = &sbpdt_entries[sbpdt_curr];
+			sbpdt_size += size;
+			sbpdt_curr++;
+		} else {
+			assert(bpdt_curr < bpdt_count);
+			curr_entry = &bpdt_entries[bpdt_curr];
+			bpdt_curr++;
+		}
+
+		curr_entry->type = type;
+		curr_entry->flags = 0;
+		curr_entry->offset = 0;
+		curr_entry->size = size;
+
+		if (type == S_BPDT_TYPE) {
+			sbpdt = curr_entry;
+			curr_entry->size = sizeof(struct bpdt_header) +
+				buffer_size(ifwi_image.sbpdt_entries);
+		}
+	}
+
+	/* Calculate offsets for entries using pack_order. */
+	uint32_t curr_offset = sizeof(struct bpdt_header) +
+		buffer_size(ifwi_image.bpdt_entries);
+	uint32_t alignment;
+
+	for (i = 0; i < MAX_COMPS; i++) {
+		type = bpdt_pack_order[i];
+
+		curr_entry = get_bpdt_entry_from_type(type);
+
+		if ((curr_entry == NULL) || (curr_entry->size == 0))
+			continue;
+
+		if (comp[type].attr & LIES_WITHIN_BPDT_4K)
+			alignment = 512;
+		else
+			alignment = 4096;
+
+		curr_entry->offset = ALIGN(curr_offset, alignment);
+		curr_offset = curr_entry->offset + curr_entry->size;
+	}
+
+	sbpdt_fixup(sbpdt, sbpdt_size);
+
+	bpdt_entries_print(bpdt_entries, bpdt_count);
+	bpdt_entries_print(sbpdt_entries, sbpdt_count);
+
+	ifwi_write(image_name);
+}
+
+static int ifwi_parse(const char *image_name)
+{
+	DEBUG("Parsing IFWI image\n");
+
+	struct bpdt_header *bpdt_header_ptr = &ifwi_image.bpdt_header;
+	struct bpdt_header *sbpdt_header_ptr = &ifwi_image.sbpdt_header;
+	int ret = -1;
+
+	/* Open IFWI image file. */
+	FILE *fp = file_open_read(image_name);
+
+	/* Read BPDT header. */
+	file_read(bpdt_header_ptr, sizeof(*bpdt_header_ptr), fp, 0);
+	bpdt_validate(bpdt_header_ptr, "BPDT");
+
+	/* Read BPDT entries. */
+	ifwi_image.bpdt_entries = buffer_get(sizeof(struct bpdt_entry) *
+					     bpdt_header_ptr->descriptor_count);
+	struct bpdt_entry *bpdt_entries = buffer_data(ifwi_image.bpdt_entries);
+
+	file_read(bpdt_entries, buffer_size(ifwi_image.bpdt_entries), fp,
+		  sizeof(*bpdt_header_ptr));
+
+	/* Read S-BPDT header. */
+	uint32_t i;
+	for (i = 0; i < bpdt_header_ptr->descriptor_count; i++) {
+		if (bpdt_entries[i].type != S_BPDT_TYPE)
+			continue;
+
+		file_read(sbpdt_header_ptr, sizeof(*sbpdt_header_ptr), fp,
+			  bpdt_entries[i].offset);
+
+		break;
+	}
+
+	if (i == bpdt_header_ptr->descriptor_count) {
+		printf("No S-BPDT present. Creating one.\n");
+		bpdt_create(sbpdt_header_ptr);
+	}
+
+	bpdt_validate(sbpdt_header_ptr, "S-BPDT");
+
+	/* Read S-BPDT entries. */
+	ifwi_image.sbpdt_entries = buffer_get(sizeof(struct bpdt_entry) *
+					    sbpdt_header_ptr->descriptor_count);
+	struct bpdt_entry *sbpdt_entries =
+		buffer_data(ifwi_image.sbpdt_entries);
+
+	file_read(sbpdt_entries, buffer_size(ifwi_image.sbpdt_entries), fp,
+		  bpdt_entries[i].offset + sizeof(*sbpdt_header_ptr));
+
+	/* Print all entries. */
+	bpdt_entries_print(bpdt_entries, bpdt_header_ptr->descriptor_count);
+	bpdt_entries_print(sbpdt_entries, sbpdt_header_ptr->descriptor_count);
+
+	/* Read all components. */
+	if (read_comp_buf(bpdt_entries, bpdt_header_ptr->descriptor_count, fp))
+		goto out;
+
+	if (read_comp_buf(sbpdt_entries, sbpdt_header_ptr->descriptor_count,
+			  fp))
+		goto out;
+
+	ret = 0;
+
+out:
+	fclose(fp);
+	return ret;
+}
+
+typedef enum ifwi_ret {
+	COMM_ERR = -1,
+	NO_ACTION_REQUIRED = 0,
+	REPACK_REQUIRED = 1,
+} ifwi_ret_t;
+
+static int32_t get_comp_from_name(const char *name)
+{
+	int32_t 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;
+}
+
+static ifwi_ret_t ifwi_add(void)
+{
+	if (!param.file_name) {
+		ERROR("%s: -f option required\n", __FUNCTION__);
+		return COMM_ERR;
+	}
+
+	if (!param.comp_name) {
+		ERROR("%s: -n option required\n", __FUNCTION__);
+		return COMM_ERR;
+	}
+
+	int32_t type = get_comp_from_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 add auto-generated components.\n");
+		return COMM_ERR;
+	}
+
+	if (ifwi_image.comp_buf[type] != NULL) {
+		ERROR("Image already contains component %s.\n",
+		      param.comp_name);
+		return COMM_ERR;
+	}
+
+	FILE *param_file = file_open_read(param.file_name);
+
+	uint32_t size = file_get_size(param_file);
+	ifwi_image.comp_buf[type] = buffer_get(size);
+
+	if (!ifwi_image.comp_buf[type]) {
+		fclose(param_file);
+		return COMM_ERR;
+	}
+
+	file_read(buffer_data(ifwi_image.comp_buf[type]), size, param_file, 0);
+
+	fclose(param_file);
+
+	return REPACK_REQUIRED;
+}
+
+static ifwi_ret_t ifwi_delete(void)
+{
+	if (!param.comp_name) {
+		ERROR("%s: -n option required\n", __FUNCTION__);
+		return COMM_ERR;
+	}
+
+	int32_t type = get_comp_from_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 (ifwi_image.comp_buf[type] == NULL) {
+		ERROR("Image does not contain component %s.\n",
+		      param.comp_name);
+		return COMM_ERR;
+	}
+
+	buffer_free(ifwi_image.comp_buf[type]);
+	ifwi_image.comp_buf[type] = NULL;
+
+	return REPACK_REQUIRED;
+}
+
+static ifwi_ret_t ifwi_extract(void)
+{
+	if (!param.file_name) {
+		ERROR("%s: -f option required\n", __FUNCTION__);
+		return COMM_ERR;
+	}
+
+	if (!param.comp_name) {
+		ERROR("%s: -n option required\n", __FUNCTION__);
+		return COMM_ERR;
+	}
+
+	int32_t type = get_comp_from_name(param.comp_name);
+	if (type == -1)
+		return COMM_ERR;
+
+	struct bpdt_comp *curr_comp = &comp[type];
+
+	if (type == S_BPDT_TYPE) {
+		INFO("Nothing to extract.\n");
+		return NO_ACTION_REQUIRED;
+	}
+
+	if (ifwi_image.comp_buf[type] == NULL) {
+		ERROR("Image does not contain component %s.\n",
+		      param.comp_name);
+		return COMM_ERR;
+	}
+
+	INFO("Extracting component of type %d.\n", type);
+
+	FILE *param_file = file_open_write(param.file_name);
+
+	file_write(buffer_data(ifwi_image.comp_buf[type]),
+		   buffer_size(ifwi_image.comp_buf[type]), param_file, 0);
+
+	fclose(param_file);
+
+	INFO("Component %s stored in %s.\n", param.comp_name, param.file_name);
+
+	return NO_ACTION_REQUIRED;
+}
+
+static ifwi_ret_t ifwi_print(void)
+{
+	if (verbose > 1)
+		return REPACK_REQUIRED;
+
+	verbose += 3;
+
+	struct bpdt_header *bpdt_header_ptr = &ifwi_image.bpdt_header;
+	struct bpdt_header *sbpdt_header_ptr = &ifwi_image.sbpdt_header;
+
+	bpdt_header_print(bpdt_header_ptr, "BPDT");
+	printf("\n\n");
+	bpdt_entries_print(buffer_data(ifwi_image.bpdt_entries),
+			   bpdt_header_ptr->descriptor_count);
+	printf("\n\n");
+
+	bpdt_header_print(sbpdt_header_ptr, "S-BPDT");
+	printf("\n\n");
+	bpdt_entries_print(buffer_data(ifwi_image.sbpdt_entries),
+			   sbpdt_header_ptr->descriptor_count);
+	printf("\n\n");
+
+	verbose -= 3;
+
+	return REPACK_REQUIRED;
+}
+
+struct command {
+	const char *name;
+	const char *optstring;
+	ifwi_ret_t (*function)(void);
+};
+
+static const struct command commands[] = {
+	{"add", "f:n:vh?", ifwi_add},
+	{"delete", "f:n:vh?", ifwi_delete},
+	{"extract", "f:n:vh?", ifwi_extract},
+	{"print", "vh?", ifwi_print},
+};
+
+static struct option long_options[] = {
+	{"file",	required_argument, 0, 'f'},
+	{"help",	required_argument, 0, 'h'},
+	{"name",	required_argument, 0, 'n'},
+	{"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"
+	       " delete -n NAME\n"
+	       " extract -f FILE -n NAME\n"
+	       " print\n",
+	       name, name
+	       );
+}
+
+int main(int argc, char **argv)
+{
+	if (argc < 3) {
+		usage(argv[0]);
+		return 1;
+	}
+
+	char *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 'v':
+				verbose++;
+				break;
+			case 'h':
+			case '?':
+				usage(argv[0]);
+				return 1;
+			default:
+				break;
+			}
+		}
+
+		if (ifwi_parse(image_name)) {
+			ERROR("%s: ifwi parsing failed\n", argv[0]);
+			return 1;
+		}
+
+		ifwi_ret_t ret = commands[i].function();
+
+		if (ret == COMM_ERR) {
+			ERROR("%s: failed execution\n", argv[0]);
+			return 1;
+		}
+
+		if (ret == REPACK_REQUIRED)
+			ifwi_repack(image_name);
+
+		return 0;
+	}
+
+	ERROR("%s: invalid command\n", argv[0]);
+	return 1;
+}



More information about the coreboot-gerrit mailing list