From patchwork Tue Jun 24 11:36:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: Add option to read ROM layout from IFD [v2] Date: Tue, 24 Jun 2014 11:36:38 -0000 From: Patrick Georgi X-Patchwork-Id: 4204 Message-Id: <53A962C6.1020406@secunet.com> To: Hi, I updated Nico's patch[1] for IFD parsing support in flashrom to apply to the current tree. Just want to put it out there to avoid duplicate work. Regards, Patrick [1] http://patchwork.coreboot.org/patch/3966/ commit 6a2dd886eec990c1c8584d7a4ce6641d32297cd7 Author: Nico Huber 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 Signed-off-by: Patrick Georgi 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 [:] [-c ]\n" - "[-E|(-r|-w|-v) ] [-l [-i ]...] [-n] [-f]]\n" + "[-E|(-r|-w|-v) ] [(-l |-d) [-i ]...] [-n] [-f]]\n" "[-V[V[V]]] [-o ]\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 read ROM layout from \n" + " -d | --ifd read layout from an Intel Firmware Descriptor\n" " -i | --image only flash image from flash layout\n" " -o | --output log output to \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 [:] [\fB\-E\fR|\fB\-r\fR |\fB\-w\fR |\fB\-v\fR ] \ [\fB\-c\fR ] - [\fB\-l\fR [\fB\-i\fR ]] [\fB\-n\fR] [\fB\-f\fR]] + [(\fB\-l\fR |\fB\-d\fR) [\fB\-i\fR ]] [\fB\-n\fR] [\fB\-f\fR]] [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR ] .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 " Only flash region/image .B 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 +#include +#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. */