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@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. */