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(a)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