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. */
On Tue, 18 Jun 2013 17:34:35 +0200 Nico Huber nico.huber@secunet.com wrote:
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
Hi Nico,
thanks for the patch! I planned something like that too for a while. I think we will either want to make it a broader "create layout file from existing data structures and probable hardware" or make it an ichspi-specific programmer option (I am not sure regarding the exact semantics in that case though... what would this option do if you specify -w too etc).
I'll integrate my layout patches first and will look back at this then (don't hold your breath ;).
Hello Stefan,
just one spontaneous thought, see below.
Am 18.06.2013 18:06, schrieb Stefan Tauner:
On Tue, 18 Jun 2013 17:34:35 +0200 Nico Huber nico.huber@secunet.com wrote:
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
Hi Nico,
thanks for the patch! I planned something like that too for a while. I think we will either want to make it a broader "create layout file from existing data structures and probable hardware" or make it an ichspi-specific programmer option (I am not sure regarding the exact semantics in that case though... what would this option do if you specify -w too etc).
I'd use it for external flashing, too. So an ichspi specific option should be out of the question.
Nico
I'll integrate my layout patches first and will look back at this then (don't hold your breath ;).