commit 6a2dd886eec990c1c8584d7a4ce6641d32297cd7
Author: Nico Huber <nico.huber@secunet.com>
Date:   Tue Jun 24 13:20:36 2014 +0200

    Add option to read ROM layout from IFD
    
    Add an option (-d|--ifd) to read the ROM layout from an Intel Firmware
    Descriptor (IFD). Works the same as the -l option, if given, -i
    specifies the images to update.
    
    I've tried to make it the least invasive, as I know, you have other
    layout related patches pending.
    
    [pg: forward ported to current flashrom]
    
    Signed-off-by: Nico Huber <nico.huber@secunet.com>
    Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com>

diff --git a/Makefile b/Makefile
index 7a48889..5203198 100644
--- a/Makefile
+++ b/Makefile
@@ -353,7 +353,7 @@ CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \
 ###############################################################################
 # Library code.
 
-LIB_OBJS = layout.o flashrom.o udelay.o programmer.o helpers.o
+LIB_OBJS = layout.o ifd.o flashrom.o udelay.o programmer.o helpers.o
 
 ###############################################################################
 # Frontend related stuff.
diff --git a/cli_classic.c b/cli_classic.c
index fc1b9ba..fbeffc6 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -41,7 +41,7 @@ static void cli_classic_usage(const char *name)
 	       "-z|"
 #endif
 	       "-p <programmername>[:<parameters>] [-c <chipname>]\n"
-	       "[-E|(-r|-w|-v) <file>] [-l <layoutfile> [-i <imagename>]...] [-n] [-f]]\n"
+	       "[-E|(-r|-w|-v) <file>] [(-l <layoutfile>|-d) [-i <imagename>]...] [-n] [-f]]\n"
 	       "[-V[V[V]]] [-o <logfile>]\n\n", name);
 
 	printf(" -h | --help                        print this help text\n"
@@ -55,6 +55,7 @@ static void cli_classic_usage(const char *name)
 	       " -f | --force                       force specific operations (see man page)\n"
 	       " -n | --noverify                    don't auto-verify\n"
 	       " -l | --layout <layoutfile>         read ROM layout from <layoutfile>\n"
+	       " -d | --ifd                         read layout from an Intel Firmware Descriptor\n"
 	       " -i | --image <name>                only flash image <name> from flash layout\n"
 	       " -o | --output <logfile>            log output to <logfile>\n"
 	       " -L | --list-supported              print supported devices\n"
@@ -98,7 +99,7 @@ int main(int argc, char *argv[])
 	struct flashctx *fill_flash;
 	const char *name;
 	int namelen, opt, i, j;
-	int startchip = -1, chipcount = 0, option_index = 0, force = 0;
+	int startchip = -1, chipcount = 0, option_index = 0, force = 0, ifd = 0;
 #if CONFIG_PRINT_WIKI == 1
 	int list_supported_wiki = 0;
 #endif
@@ -107,7 +108,7 @@ int main(int argc, char *argv[])
 	enum programmer prog = PROGRAMMER_INVALID;
 	int ret = 0;
 
-	static const char optstring[] = "r:Rw:v:nVEfc:l:i:p:Lzho:";
+	static const char optstring[] = "r:Rw:v:nVEfc:l:di:p:Lzho:";
 	static const struct option long_options[] = {
 		{"read",		1, NULL, 'r'},
 		{"write",		1, NULL, 'w'},
@@ -118,6 +119,7 @@ int main(int argc, char *argv[])
 		{"verbose",		0, NULL, 'V'},
 		{"force",		0, NULL, 'f'},
 		{"layout",		1, NULL, 'l'},
+		{"ifd",			0, NULL, 'd'},
 		{"image",		1, NULL, 'i'},
 		{"list-supported",	0, NULL, 'L'},
 		{"list-supported-wiki",	0, NULL, 'z'},
@@ -213,8 +215,20 @@ int main(int argc, char *argv[])
 					"more than once. Aborting.\n");
 				cli_classic_abort_usage();
 			}
+			if (ifd) {
+				fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n");
+				cli_classic_abort_usage();
+			}
 			layoutfile = strdup(optarg);
 			break;
+		case 'd':
+			if (layoutfile) {
+				fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n");
+				cli_classic_abort_usage();
+			}
+			layout_use_ifd();
+			ifd = 1;
+			break;
 		case 'i':
 			tempstr = strdup(optarg);
 			if (register_include_arg(tempstr)) {
@@ -375,7 +389,7 @@ int main(int argc, char *argv[])
 		goto out;
 	}
 
-	if (process_include_args()) {
+	if (!ifd && process_include_args()) {
 		ret = 1;
 		goto out;
 	}
diff --git a/flash.h b/flash.h
index c2de2d0..a4b5138 100644
--- a/flash.h
+++ b/flash.h
@@ -326,6 +326,14 @@ __attribute__((format(printf, 2, 3)));
 #define msg_cspew(...)	print(MSG_SPEW, __VA_ARGS__)	/* chip debug spew  */
 
 /* layout.c */
+typedef struct {
+	chipoff_t start;
+	chipoff_t end;
+	unsigned int included;
+	char name[256];
+} romentry_t;
+
+void layout_use_ifd(void);
 int register_include_arg(char *name);
 int process_include_args(void);
 int read_romlayout(const char *name);
@@ -333,6 +341,9 @@ int normalize_romentries(const struct flashctx *flash);
 int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents);
 void layout_cleanup(void);
 
+/* ifd.c */
+int ifd_read_romlayout(const uint8_t *oldcontents, const uint8_t *newcontents, unsigned flash_size, romentry_t *entries, int *n_entries);
+
 /* spi.c */
 struct spi_command {
 	unsigned int writecnt;
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index 0b4867d..ee38810 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -6,7 +6,7 @@ flashrom \- detect, read, write, verify and erase flash chips
 \fB\-p\fR <programmername>[:<parameters>]
                [\fB\-E\fR|\fB\-r\fR <file>|\fB\-w\fR <file>|\fB\-v\fR <file>] \
 [\fB\-c\fR <chipname>]
-               [\fB\-l\fR <file> [\fB\-i\fR <image>]] [\fB\-n\fR] [\fB\-f\fR]]
+               [(\fB\-l\fR <file>|\fB\-d\fR) [\fB\-i\fR <image>]] [\fB\-n\fR] [\fB\-f\fR]]
          [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>]
 .SH DESCRIPTION
 .B flashrom
@@ -137,6 +137,22 @@ To update only the images named
 .sp
 Overlapping sections are not supported.
 .TP
+.B "\-d, \-\-ifd"
+Read ROM layout from Intel Firmware Descriptor.
+.sp
+flashrom supports ROM layouts given by an Intel Firmware Descriptor
+(IFD). Both, the current flash ROM chips contents and the file's
+contents which are to be flashed, must contain an IFD with the same ROM
+regions.
+.sp
+The following ROM images may be present in an IFD:
+.sp
+  Flash_Descriptor     the IFD itself
+  BIOS                 the host firmware aka. BIOS
+  Intel_ME             Intel Management Engine firmware
+  GbE                  Gigabit Ethernet firmware
+  Platform_Data        platform specific data
+.TP
 .B "\-i, \-\-image <imagename>"
 Only flash region/image
 .B <imagename>
diff --git a/flashrom.c b/flashrom.c
index 408c555..22adaff 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -2010,7 +2010,10 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 	msg_cinfo("done.\n");
 
 	/* Build a new image taking the given layout into account. */
-	build_new_image(flash, oldcontents, newcontents);
+	if (build_new_image(flash, oldcontents, newcontents)) {
+		ret = 1;
+		goto out;
+	}
 
 	// ////////////////////////////////////////////////////////////
 
diff --git a/ifd.c b/ifd.c
new file mode 100644
index 0000000..1cb05cc
--- /dev/null
+++ b/ifd.c
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2013 secunet Security Networks AG
+ *
+ * ifd reading code borrowed from coreboot's ifdtool:
+ * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include "flash.h"
+
+/* flash descriptor */
+typedef struct {
+	uint32_t flvalsig;
+	uint32_t flmap0;
+	uint32_t flmap1;
+	uint32_t flmap2;
+	uint8_t  reserved[0xefc - 0x20];
+	uint32_t flumap1;
+} __attribute__((packed)) fdbar_t;
+
+/* regions */
+typedef struct {
+	uint32_t flreg0;
+	uint32_t flreg1;
+	uint32_t flreg2;
+	uint32_t flreg3;
+	uint32_t flreg4;
+} __attribute__((packed)) frba_t;
+
+typedef struct {
+	int base, limit, size;
+} region_t;
+
+static fdbar_t *find_fd(const uint8_t *image, int size)
+{
+	int i, found = 0;
+
+	/* Scan for FD signature */
+	for (i = 0; i <= (size - sizeof(fdbar_t)); i += 4) {
+		if (*(uint32_t *) (image + i) == 0x0FF0A55A) {
+			found = 1;
+			break;	// signature found.
+		}
+	}
+
+	if (!found)
+		return NULL;
+
+	msg_ginfo("Found Flash Descriptor signature at 0x%08x\n", i);
+
+	return (fdbar_t *) (image + i);
+}
+
+static region_t get_region(const frba_t *frba, int region_type)
+{
+	region_t region;
+	region.base = 0, region.limit = 0, region.size = 0;
+
+	switch (region_type) {
+	case 0:
+		region.base = (frba->flreg0 & 0x00000fff) << 12;
+		region.limit = ((frba->flreg0 & 0x0fff0000) >> 4) | 0xfff;
+		break;
+	case 1:
+		region.base = (frba->flreg1 & 0x00000fff) << 12;
+		region.limit = ((frba->flreg1 & 0x0fff0000) >> 4) | 0xfff;
+		break;
+	case 2:
+		region.base = (frba->flreg2 & 0x00000fff) << 12;
+		region.limit = ((frba->flreg2 & 0x0fff0000) >> 4) | 0xfff;
+		break;
+	case 3:
+		region.base = (frba->flreg3 & 0x00000fff) << 12;
+		region.limit = ((frba->flreg3 & 0x0fff0000) >> 4) | 0xfff;
+		break;
+	case 4:
+		region.base = (frba->flreg4 & 0x00000fff) << 12;
+		region.limit = ((frba->flreg4 & 0x0fff0000) >> 4) | 0xfff;
+		break;
+	default:
+		break;
+	}
+
+	region.size = region.limit - region.base + 1;
+
+	return region;
+}
+
+int ifd_read_romlayout(const uint8_t *const oldcontents, const uint8_t *const newcontents,
+		       const unsigned flash_size, romentry_t *const entries, int *const n_entries)
+{
+	static const char *regions[5] = {
+		"Flash_Descriptor",
+		"BIOS",
+		"Intel_ME",
+		"GbE",
+		"Platform_Data"
+	};
+
+	const int max_entries = *n_entries;
+	*n_entries = 0;
+
+	const fdbar_t *const fdb_old = find_fd(oldcontents, flash_size);
+	if (!fdb_old) {
+		msg_gerr("No IFD found in old flash contents.\n");
+		return 1;
+	}
+	const fdbar_t *const fdb_new = find_fd(newcontents, flash_size);
+	if (!fdb_old) {
+		msg_gerr("No IFD found in new flash contents.\n");
+		return 1;
+	}
+
+	const frba_t *const fr_old = (frba_t *)(oldcontents + (((fdb_old->flmap0 >> 16) & 0xff) << 4));
+	const frba_t *const fr_new = (frba_t *)(newcontents + (((fdb_new->flmap0 >> 16) & 0xff) << 4));
+	int i;
+	for (i = 0; i < 5; ++i) {
+		const region_t reg_old = get_region(fr_old, i);
+		const region_t reg_new = get_region(fr_new, i);
+		if (reg_old.base != reg_new.base || reg_old.limit != reg_new.limit) {
+			msg_gerr("Image '%s' doesn't match in old and new IFD, won't flash.\n", regions[i]);
+			return 1;
+		}
+		if (reg_old.size <= 0)
+			continue;
+
+		if (*n_entries >= max_entries) {
+			msg_gerr("Maximum number of ROM images (%i) in layout reached.\n", max_entries);
+			return 1;
+		}
+		entries[*n_entries].start = reg_old.base;
+		entries[*n_entries].end = reg_old.limit;
+		snprintf(entries[*n_entries].name, sizeof(entries[*n_entries].name), "%s", regions[i]);
+		msg_ginfo("Found flash region [%08x:%08x] %s\n",
+			  entries[*n_entries].start, entries[*n_entries].end, entries[*n_entries].name);
+		++*n_entries;
+	}
+	return 0;
+}
diff --git a/layout.c b/layout.c
index a12eb28..7d90d70 100644
--- a/layout.c
+++ b/layout.c
@@ -28,13 +28,6 @@
 
 #define MAX_ROMLAYOUT	32
 
-typedef struct {
-	chipoff_t start;
-	chipoff_t end;
-	unsigned int included;
-	char name[256];
-} romentry_t;
-
 /* rom_entries store the entries specified in a layout file and associated run-time data */
 static romentry_t rom_entries[MAX_ROMLAYOUT];
 static int num_rom_entries = 0; /* the number of successfully parsed rom_entries */
@@ -44,6 +37,13 @@ static int num_rom_entries = 0; /* the number of successfully parsed rom_entries
 static char *include_args[MAX_ROMLAYOUT];
 static int num_include_args = 0; /* the number of valid include_args. */
 
+static int use_ifd = 0;
+
+void layout_use_ifd(void)
+{
+	use_ifd = 1;
+}
+
 #ifndef __LIBPAYLOAD__
 int read_romlayout(const char *name)
 {
@@ -263,6 +263,16 @@ int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t
 	romentry_t *entry;
 	unsigned int size = flash->chip->total_size * 1024;
 
+	if (use_ifd) {
+		num_rom_entries = MAX_ROMLAYOUT;
+		if (ifd_read_romlayout(oldcontents, newcontents, size, rom_entries, &num_rom_entries))
+			return 1;
+		/* Call process_include_args() late, as we only
+		   just got to know the names of available images. */
+		if (process_include_args())
+			return 1;
+	}
+
 	/* If no regions were specified for inclusion, assume
 	 * that the user wants to write the complete new image.
 	 */
