[coreboot-gerrit] New patch to review for coreboot: WIP: Add ifwitool for managing IFWI images
Furquan Shaikh (furquan@google.com)
gerrit at coreboot.org
Wed May 18 22:53:32 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 29450219a74a6b99cf3090ee7d0ee464ddc1535a
Author: Furquan Shaikh <furquan at google.com>
Date: Wed May 18 13:46:59 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 | 889 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 1184 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..bf98490
--- /dev/null
+++ b/util/ifwitool/ifwitool.c
@@ -0,0 +1,889 @@
+/*
+ * 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",
+ 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