[flashrom] [PATCH] Add option to read ROM layout from IFD

Nico Huber nico.huber at secunet.com
Tue Jun 18 17:34:35 CEST 2013


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.

Signed-off-by: Nico Huber <nico.huber at secunet.com>
---
 Makefile      |    2 +-
 cli_classic.c |   22 ++++++--
 flash.h       |   10 ++++
 flashrom.8    |   18 ++++++-
 flashrom.c    |    5 +-
 ifd.c         |  155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 layout.c      |   23 ++++++---
 7 files changed, 221 insertions(+), 14 deletions(-)
 create mode 100644 ifd.c

diff --git a/Makefile b/Makefile
index 805290c..5e77a48 100644
--- a/Makefile
+++ b/Makefile
@@ -306,7 +306,7 @@ CHIP_OBJS = jedec.o stm50flw0x0x.o w39.o w29ee011.o \
 ###############################################################################
 # Library code.
 
-LIB_OBJS = layout.o flashrom.o udelay.o programmer.o
+LIB_OBJS = layout.o ifd.o flashrom.o udelay.o programmer.o
 
 ###############################################################################
 # Frontend related stuff.
diff --git a/cli_classic.c b/cli_classic.c
index 14fb825..b3cc826 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'},
@@ -215,8 +217,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)) {
@@ -374,7 +388,7 @@ int main(int argc, char *argv[])
 		ret = 1;
 		goto out;
 	}
-	if (process_include_args()) {
+	if (!ifd && process_include_args()) {
 		ret = 1;
 		goto out;
 	}
diff --git a/flash.h b/flash.h
index 1857cc0..36b1e0d 100644
--- a/flash.h
+++ b/flash.h
@@ -306,11 +306,21 @@ int print(enum msglevel level, const char *fmt, ...) __attribute__((format(print
 #define msg_cspew(...)	print(MSG_SPEW, __VA_ARGS__)	/* chip debug spew  */
 
 /* layout.c */
+typedef struct {
+	unsigned int start;
+	unsigned int end;
+	unsigned int included;
+	char name[256];
+} romlayout_t;
+void layout_use_ifd(void);
 int register_include_arg(char *name);
 int process_include_args(void);
 int read_romlayout(char *name);
 int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents);
 
+/* ifd.c */
+int ifd_read_romlayout(const uint8_t *oldcontents, const uint8_t *newcontents, unsigned flash_size, romlayout_t *entries, int *n_entries);
+
 /* spi.c */
 struct spi_command {
 	unsigned int writecnt;
diff --git a/flashrom.8 b/flashrom.8
index 4e6ab55..82afb10 100644
--- a/flashrom.8
+++ b/flashrom.8
@@ -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 c11f723..bf690dc 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1958,7 +1958,10 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it,
 
 	// This should be moved into each flash part's code to do it 
 	// cleanly. This does the job.
-	handle_romentries(flash, oldcontents, newcontents);
+	if (handle_romentries(flash, oldcontents, newcontents)) {
+		ret = 1;
+		goto out;
+	}
 
 	// ////////////////////////////////////////////////////////////
 
diff --git a/ifd.c b/ifd.c
new file mode 100644
index 0000000..fd31f4f
--- /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, romlayout_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 1bd3152..81058f3 100644
--- a/layout.c
+++ b/layout.c
@@ -26,16 +26,10 @@
 #include "programmer.h"
 
 static int romimages = 0;
+static int use_ifd = 0;
 
 #define MAX_ROMLAYOUT	32
 
-typedef struct {
-	unsigned int start;
-	unsigned int end;
-	unsigned int included;
-	char name[256];
-} romlayout_t;
-
 /* include_args lists arguments specified at the command line with -i. They
  * must be processed at some point so that desired regions are marked as
  * "included" in the rom_entries list.
@@ -44,6 +38,11 @@ static char *include_args[MAX_ROMLAYOUT];
 static int num_include_args = 0; /* the number of valid entries. */
 static romlayout_t rom_entries[MAX_ROMLAYOUT];
 
+void layout_use_ifd(void)
+{
+	use_ifd = 1;
+}
+
 #ifndef __LIBPAYLOAD__
 int read_romlayout(char *name)
 {
@@ -223,6 +222,16 @@ int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_
 	romlayout_t *entry;
 	unsigned int size = flash->chip->total_size * 1024;
 
+	if (use_ifd) {
+		romimages = MAX_ROMLAYOUT;
+		if (ifd_read_romlayout(oldcontents, newcontents, size, rom_entries, &romimages))
+			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.
 	 */
-- 
1.7.9.5





More information about the flashrom mailing list