Nico Huber has uploaded this change for review. ( https://review.coreboot.org/21795
Change subject: Add option to read ROM layout from IFD ......................................................................
Add option to read ROM layout from IFD
Add an option --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.
v2: o Rebased on libflashrom, use libflashrom interface. o Use functions from ich_descriptors.c.
v3: o Move ich_descriptors.o to LIB_OBJS, thus build it independent of arch and programmers. o Bail out if we aren't compiled for little endian. o Update flashrom.8.tmpl.
v4: o Incorporated David's comments. o Removed single-character `-d` option.
v5: Changed region names to match the output of `ifdtool --layout ...`
Original-Change-Id: Ifafff2bf6d5c5e62283416b3269723f81fdc0fa3 Original-Reviewed-on: https://review.coreboot.org/17953 Original-Tested-by: build bot (Jenkins) no-reply@coreboot.org Original-Reviewed-by: Stefan Reinauer stefan.reinauer@coreboot.org
Change-Id: I7d45b16c350385c09cf11e5493f50748830dd5e3 Signed-off-by: Nico Huber nico.huber@secunet.com --- M Makefile M cli_classic.c M flash.h M flashrom.8.tmpl M flashrom.c M ich_descriptors.c M ich_descriptors.h M layout.c M layout.h M libflashrom.c M libflashrom.h 11 files changed, 195 insertions(+), 25 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/95/21795/1
diff --git a/Makefile b/Makefile index 55874ae..44aa24c 100644 --- a/Makefile +++ b/Makefile @@ -519,7 +519,7 @@ ############################################################################### # Library code.
-LIB_OBJS = libflashrom.o layout.o flashrom.o udelay.o programmer.o helpers.o +LIB_OBJS = libflashrom.o layout.o flashrom.o udelay.o programmer.o helpers.o ich_descriptors.o
############################################################################### # Frontend related stuff. @@ -744,7 +744,7 @@ PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o internal.o ifeq ($(ARCH), x86) PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o amd_imc.o wbsio_spi.o mcp6x_spi.o -PROGRAMMER_OBJS += ichspi.o ich_descriptors.o dmi.o +PROGRAMMER_OBJS += ichspi.o dmi.o ifeq ($(CONFIG_INTERNAL_DMI), yes) FEATURE_CFLAGS += -D'CONFIG_INTERNAL_DMI=1' endif diff --git a/cli_classic.c b/cli_classic.c index 33d3e4b..4c3db4d 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -42,7 +42,7 @@ "-z|" #endif "-p <programmername>[:<parameters>] [-c <chipname>]\n" - "[-E|(-r|-w|-v) <file>] [-l <layoutfile> [-i <imagename>]...] [-n] [-N] [-f]]\n" + "[-E|(-r|-w|-v) <file>] [(-l <layoutfile>|--ifd) [-i <imagename>]...] [-n] [-N] [-f]]\n" "[-V[V[V]]] [-o <logfile>]\n\n", name);
printf(" -h | --help print this help text\n" @@ -57,6 +57,7 @@ " -n | --noverify don't auto-verify\n" " -N | --noverify-all verify included regions only (cf. -i)\n" " -l | --layout <layoutfile> read ROM layout from <layoutfile>\n" + " --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" @@ -99,12 +100,13 @@ 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 int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; int dont_verify_it = 0, dont_verify_all = 0, list_supported = 0, operation_specified = 0; + struct flashrom_layout *layout = NULL; enum programmer prog = PROGRAMMER_INVALID; int ret = 0;
@@ -120,6 +122,7 @@ {"verbose", 0, NULL, 'V'}, {"force", 0, NULL, 'f'}, {"layout", 1, NULL, 'l'}, + {"ifd", 0, NULL, 0x0100}, {"image", 1, NULL, 'i'}, {"list-supported", 0, NULL, 'L'}, {"list-supported-wiki", 0, NULL, 'z'}, @@ -220,7 +223,18 @@ "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 0x0100: + if (layoutfile) { + fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n"); + cli_classic_abort_usage(); + } + ifd = 1; break; case 'i': tempstr = strdup(optarg); @@ -376,7 +390,7 @@ ret = 1; goto out; } - if (process_include_args()) { + if (!ifd && process_include_args(get_global_layout())) { ret = 1; goto out; } @@ -529,9 +543,15 @@ goto out_shutdown; }
- if (layoutfile) - flashrom_layout_set(fill_flash, get_global_layout()); + if (layoutfile) { + layout = get_global_layout(); + } else if (ifd && (flashrom_layout_read_from_ifd(&layout, fill_flash, NULL, 0) || + process_include_args(layout))) { + ret = 1; + goto out_shutdown; + }
+ flashrom_layout_set(fill_flash, layout); flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE, !!force); #if CONFIG_INTERNAL == 1 flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE_BOARDMISMATCH, !!force_boardmismatch); @@ -553,6 +573,8 @@ else if (verify_it) ret = do_verify(fill_flash, filename);
+ flashrom_layout_release(layout); + out_shutdown: programmer_shutdown(); out: diff --git a/flash.h b/flash.h index 7c7ecd5..47c32f4 100644 --- a/flash.h +++ b/flash.h @@ -287,6 +287,8 @@ int selfcheck(void); int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename); int write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename); +int prepare_flash_access(struct flashctx *, bool read_it, bool write_it, bool erase_it, bool verify_it); +void finalize_flash_access(struct flashctx *); int do_read(struct flashctx *, const char *filename); int do_erase(struct flashctx *); int do_write(struct flashctx *, const char *const filename); @@ -354,7 +356,6 @@
/* layout.c */ int register_include_arg(char *name); -int process_include_args(void); int read_romlayout(const char *name); int normalize_romentries(const struct flashctx *flash); void layout_cleanup(void); diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl index 34e7f02..143d76c 100644 --- a/flashrom.8.tmpl +++ b/flashrom.8.tmpl @@ -48,8 +48,8 @@ \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-N\fR] \ -[\fB-f\fR]] + [(\fB-l\fR <file>|\fB--ifd\fR) [\fB-i\fR <image>]] \ +[\fB-n\fR] [\fB-N\fR] [\fB-f\fR]] [\fB-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>] .SH DESCRIPTION .B flashrom @@ -195,6 +195,22 @@ .sp Overlapping sections are not supported. .TP +.B "--ifd" +Read ROM layout from Intel Firmware Descriptor. +.sp +flashrom supports ROM layouts given by an Intel Firmware Descriptor +(IFD). The on-chip descriptor will be read and used to generate the +layout. If you need to change the layout, you have to update the IFD +only first. +.sp +The following ROM images may be present in an IFD: +.sp + fd the IFD itself + bios the host firmware aka. BIOS + me Intel Management Engine firmware + gbe gigabit ethernet firmware + pd platform specific data +.TP .B "-i, --image <imagename>" Only flash region/image .B <imagename> diff --git a/flashrom.c b/flashrom.c index fc555fb..b7eaac8 100644 --- a/flashrom.c +++ b/flashrom.c @@ -2168,9 +2168,9 @@ return 0; }
-static int prepare_flash_access(struct flashctx *const flash, - const bool read_it, const bool write_it, - const bool erase_it, const bool verify_it) +int prepare_flash_access(struct flashctx *const flash, + const bool read_it, const bool write_it, + const bool erase_it, const bool verify_it) { if (chip_safety_check(flash, flash->flags.force, read_it, write_it, erase_it, verify_it)) { msg_cerr("Aborting.\n"); @@ -2193,7 +2193,7 @@ return 0; }
-static void finalize_flash_access(struct flashctx *const flash) +void finalize_flash_access(struct flashctx *const flash) { unmap_flash(flash); } diff --git a/ich_descriptors.c b/ich_descriptors.c index 2cc1c73..4af8764 100644 --- a/ich_descriptors.c +++ b/ich_descriptors.c @@ -23,6 +23,7 @@
#ifdef ICH_DESCRIPTORS_FROM_DUMP_ONLY #include <stdio.h> +#include <string.h> #define print(t, ...) printf(__VA_ARGS__) #endif
@@ -38,7 +39,7 @@ #include "programmer.h"
#ifndef min -#define min(a, b) (a < b) ? a : b +#define min(a, b) (((a) < (b)) ? (a) : (b)) #endif
void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity, bool print_vcl) @@ -919,4 +920,42 @@ return ICH_RET_OK; } #endif + +/** + * @brief Read a layout from the dump of an Intel ICH descriptor. + * + * @param layout Pointer where to store the layout. + * @param dump The descriptor dump to read from. + * @param len The length of the descriptor dump. + * + * @return 0 on success, + * 1 if the descriptor couldn't be parsed. + */ +int layout_from_ich_descriptors(struct ich_layout *const layout, const void *const dump, const size_t len) +{ + static const char *regions[] = { "fd", "bios", "me", "gbe", "pd" }; + + struct ich_descriptors desc; + if (read_ich_descriptors_from_dump(dump, len, &desc)) + return 1; + + memset(layout, 0x00, sizeof(*layout)); + + size_t i, j; + for (i = 0, j = 0; i < min(desc.content.NR + 1, ARRAY_SIZE(regions)); ++i) { + const chipoff_t base = ICH_FREG_BASE(desc.region.FLREGs[i]); + const chipoff_t limit = ICH_FREG_LIMIT(desc.region.FLREGs[i]) + 0xfff; + if (limit <= base) + continue; + layout->entries[j].start = base; + layout->entries[j].end = limit; + layout->entries[j].included = false; + snprintf(layout->entries[j].name, sizeof(layout->entries[j].name), "%s", regions[i]); + ++j; + } + layout->base.entries = layout->entries; + layout->base.num_entries = j; + return 0; +} + #endif /* ICH_DESCRIPTORS_FROM_DUMP_ONLY */ diff --git a/ich_descriptors.h b/ich_descriptors.h index e355e54..ecf44bf 100644 --- a/ich_descriptors.h +++ b/ich_descriptors.h @@ -584,4 +584,6 @@ int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc); int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors *desc, uint8_t idx);
+int layout_from_ich_descriptors(struct ich_layout *, const void *dump, size_t len); + #endif /* __ICH_DESCRIPTORS_H__ */ diff --git a/layout.c b/layout.c index 2d53295..9bf0b03 100644 --- a/layout.c +++ b/layout.c @@ -35,7 +35,7 @@ static char *include_args[MAX_ROMLAYOUT]; static int num_include_args = 0; /* the number of valid include_args. */
-const struct flashrom_layout *get_global_layout(void) +struct flashrom_layout *get_global_layout(void) { return &layout; } @@ -132,17 +132,17 @@ }
/* returns the index of the entry (or a negative value if it is not found) */ -static int find_romentry(char *name) +static int find_romentry(struct flashrom_layout *const l, char *name) { int i;
- if (layout.num_entries == 0) + if (l->num_entries == 0) return -1;
msg_gspew("Looking for region "%s"... ", name); - for (i = 0; i < layout.num_entries; i++) { - if (!strcmp(layout.entries[i].name, name)) { - layout.entries[i].included = 1; + for (i = 0; i < l->num_entries; i++) { + if (!strcmp(l->entries[i].name, name)) { + l->entries[i].included = 1; msg_gspew("found.\n"); return i; } @@ -154,7 +154,7 @@ /* process -i arguments * returns 0 to indicate success, >0 to indicate failure */ -int process_include_args(void) +int process_include_args(struct flashrom_layout *const l) { int i; unsigned int found = 0; @@ -163,7 +163,7 @@ return 0;
/* User has specified an area, but no layout file is loaded. */ - if (layout.num_entries == 0) { + if (l->num_entries == 0) { msg_gerr("Region requested (with -i "%s"), " "but no layout data is available.\n", include_args[0]); @@ -171,7 +171,7 @@ }
for (i = 0; i < num_include_args; i++) { - if (find_romentry(include_args[i]) < 0) { + if (find_romentry(l, include_args[i]) < 0) { msg_gerr("Invalid region specified: "%s".\n", include_args[i]); return 1; diff --git a/layout.h b/layout.h index 349cebc..c93d754 100644 --- a/layout.h +++ b/layout.h @@ -57,6 +57,13 @@ struct romentry entry; };
-const struct flashrom_layout *get_global_layout(void); +struct ich_layout { + struct flashrom_layout base; + struct romentry entries[5]; +}; + +struct flashrom_layout *get_global_layout(void); + +int process_include_args(struct flashrom_layout *);
#endif /* !__LAYOUT_H__ */ diff --git a/libflashrom.c b/libflashrom.c index f17b627..962e96f 100644 --- a/libflashrom.c +++ b/libflashrom.c @@ -31,6 +31,8 @@ #include "flash.h" #include "programmer.h" #include "layout.h" +#include "hwaccess.h" +#include "ich_descriptors.h" #include "libflashrom.h"
/** @@ -305,6 +307,86 @@ }
/** + * @brief Read a layout from the Intel ICH descriptor in the flash. + * + * Optionally verify that the layout matches the one in the given + * descriptor dump. + * + * @param[out] layout Points to a struct flashrom_layout pointer that + * gets set if the descriptor is read and parsed + * successfully. + * @param[in] flashctx Flash context to read the descriptor from flash. + * @param[in] dump The descriptor dump to compare to or NULL. + * @param[in] len The length of the descriptor dump. + * + * @return 0 on success, + * 6 if descriptor parsing isn't implemented for the host, + * 5 if the descriptors don't match, + * 4 if the descriptor dump couldn't be parsed, + * 3 if the descriptor on flash couldn't be parsed, + * 2 if the descriptor on flash couldn't be read, + * 1 on any other error. + */ +int flashrom_layout_read_from_ifd(struct flashrom_layout **const layout, struct flashctx *const flashctx, + const void *const dump, const size_t len) +{ +#ifndef __FLASHROM_LITTLE_ENDIAN__ + return 6; +#else + struct ich_layout dump_layout; + int ret = 1; + + void *const desc = malloc(0x1000); + struct ich_layout *const chip_layout = malloc(sizeof(*chip_layout)); + if (!desc || !chip_layout) { + msg_gerr("Out of memory!\n"); + goto _free_ret; + } + + if (prepare_flash_access(flashctx, true, false, false, false)) + goto _free_ret; + + msg_cinfo("Reading ich descriptor... "); + if (flashctx->chip->read(flashctx, desc, 0, 0x1000)) { + msg_cerr("Read operation failed!\n"); + msg_cinfo("FAILED.\n"); + ret = 2; + goto _finalize_ret; + } + msg_cinfo("done.\n"); + + if (layout_from_ich_descriptors(chip_layout, desc, 0x1000)) { + ret = 3; + goto _finalize_ret; + } + + if (dump) { + if (layout_from_ich_descriptors(&dump_layout, dump, len)) { + ret = 4; + goto _finalize_ret; + } + + if (chip_layout->base.num_entries != dump_layout.base.num_entries || + memcmp(chip_layout->entries, dump_layout.entries, sizeof(dump_layout.entries))) { + ret = 5; + goto _finalize_ret; + } + } + + *layout = (struct flashrom_layout *)chip_layout; + ret = 0; + +_finalize_ret: + finalize_flash_access(flashctx); +_free_ret: + if (ret) + free(chip_layout); + free(desc); + return ret; +#endif +} + +/** * @brief Free a layout. * * @param layout Layout to free. diff --git a/libflashrom.h b/libflashrom.h index 9fb5a47..c5d972e 100644 --- a/libflashrom.h +++ b/libflashrom.h @@ -64,6 +64,7 @@ int flashrom_image_verify(struct flashrom_flashctx *, const void *buffer, size_t buffer_len);
struct flashrom_layout; +int flashrom_layout_read_from_ifd(struct flashrom_layout **, struct flashrom_flashctx *, const void *dump, size_t len); int flashrom_layout_include_region(struct flashrom_layout *, const char *name); void flashrom_layout_release(struct flashrom_layout *); void flashrom_layout_set(struct flashrom_flashctx *, const struct flashrom_layout *);