From patchwork Wed May 4 11:51:43 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nico Huber X-Patchwork-Id: 618391 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.coreboot.org (mail.coreboot.org [80.81.252.135]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3r0GfY2p2Dz9sDX for ; Wed, 4 May 2016 21:54:13 +1000 (AEST) Received: from [127.0.0.1] (helo=ra.coresystems.de) by mail.coreboot.org with esmtp (Exim 4.86_2) (envelope-from ) id 1axvMA-0006p1-4t; Wed, 04 May 2016 13:52:42 +0200 Received: from a.mx.secunet.com ([62.96.220.36]) by mail.coreboot.org with esmtps (TLSv1:DHE-RSA-AES256-SHA:256) (Exim 4.86_2) (envelope-from ) id 1axvLi-0006k2-2s for flashrom@flashrom.org; Wed, 04 May 2016 13:52:27 +0200 Received: from localhost (alg1 [127.0.0.1]) by a.mx.secunet.com (Postfix) with ESMTP id ACA9A1A05E2 for ; Wed, 4 May 2016 13:52:06 +0200 (CEST) X-Virus-Scanned: by secunet Received: from a.mx.secunet.com ([127.0.0.1]) by localhost (a.mx.secunet.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id CE_abBxvFGMC for ; Wed, 4 May 2016 13:52:05 +0200 (CEST) Received: from mail-essen-01.secunet.de (unknown [10.53.40.204]) by a.mx.secunet.com (Postfix) with ESMTP id 570AF1A074C for ; Wed, 4 May 2016 13:52:01 +0200 (CEST) Received: from schawa.localdomain (10.182.9.137) by mail-essen-01.secunet.de (10.53.40.204) with Microsoft SMTP Server (TLS) id 14.3.279.2; Wed, 4 May 2016 13:52:01 +0200 From: Nico Huber To: Date: Wed, 4 May 2016 13:51:43 +0200 Message-ID: <1462362706-31216-12-git-send-email-nico.huber@secunet.com> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1462362706-31216-1-git-send-email-nico.huber@secunet.com> References: <1462362706-31216-1-git-send-email-nico.huber@secunet.com> MIME-Version: 1.0 X-Originating-IP: [10.182.9.137] X-G-Data-MailSecurity-for-Exchange-SpamLevel: 0 X-G-Data-MailSecurity-for-Exchange-SpamFilter: 0; 1; str=0001.0A0C0201.5729E262.006D, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0 X-G-Data-MailSecurity-for-Exchange-State: 0 X-G-Data-MailSecurity-for-Exchange-Error: 0 X-G-Data-MailSecurity-for-Exchange-Sender: 32 X-G-Data-MailSecurity-for-Exchange-Server: d65e63f7-5c15-413f-8f63-c0d707471c93 X-EXCLAIMER-MD-CONFIG: 2c86f778-e09b-4440-8b15-867914633a10 X-G-Data-MailSecurity-for-Exchange-Guid: BEE82373-6226-4B36-A66C-BC025F6C2025 X-Spam-Score: -1.6 (-) Subject: [flashrom] [PATCH 11/14] Add option to read ROM layout from IFD X-BeenThere: flashrom@flashrom.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: flashrom discussion and development mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: flashrom-bounces@flashrom.org Sender: "flashrom" X-Duff: Orig. Duff, Duff Lite, Duff Dry, Duff Dark, Raspberry Duff, Lady Duff, Red Duff, Tartar Control Duff 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. v2: o Rebased on libflashrom, use libflashrom interface. o Use functions from ich_descriptors.c. Signed-off-by: Nico Huber --- cli_classic.c | 33 +++++++++++++++++++++---- flash.h | 2 +- flashrom.8.tmpl | 18 +++++++++++++- flashrom.c | 6 ++--- ich_descriptors.c | 54 +++++++++++++++++++++++++++++++++++++++- ich_descriptors.h | 2 ++ layout.c | 18 +++++++------- layout.h | 9 ++++++- libflashrom.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ libflashrom.h | 1 + 10 files changed, 196 insertions(+), 21 deletions(-) diff --git a/cli_classic.c b/cli_classic.c index aef7693..0853a2f 100644 --- a/cli_classic.c +++ b/cli_classic.c @@ -42,7 +42,7 @@ static void cli_classic_usage(const char *name) "-z|" #endif "-p [:] [-c ]\n" - "[-E|(-r|-w|-v) ] [-l [-i ]...] [-n] [-A] [-f]]\n" + "[-E|(-r|-w|-v) ] [(-l |-d) [-i ]...] [-n] [-A] [-f]]\n" "[-V[V[V]]] [-o ]\n\n", name); printf(" -h | --help print this help text\n" @@ -57,6 +57,7 @@ static void cli_classic_usage(const char *name) " -n | --noverify don't auto-verify\n" " -A | --noverify-all don't auto-verify whole chip\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" @@ -99,16 +100,17 @@ 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 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 fl_layout *layout = NULL; enum programmer prog = PROGRAMMER_INVALID; int ret = 0; - static const char optstring[] = "r:Rw:v:nAVEfc:l:i:p:Lzho:"; + static const char optstring[] = "r:Rw:v:nAVEfc:l:di:p:Lzho:"; static const struct option long_options[] = { {"read", 1, NULL, 'r'}, {"write", 1, NULL, 'w'}, @@ -120,6 +122,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'}, @@ -220,8 +223,19 @@ 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(); + } + ifd = 1; + break; case 'i': tempstr = strdup(optarg); if (register_include_arg(tempstr)) { @@ -376,7 +390,7 @@ int main(int argc, char *argv[]) ret = 1; goto out; } - if (process_include_args()) { + if (!ifd && process_include_args(get_global_layout())) { ret = 1; goto out; } @@ -530,8 +544,14 @@ int main(int argc, char *argv[]) } if (layoutfile) - fl_layout_set(fill_flash, get_global_layout()); + layout = get_global_layout(); + else if (ifd && (fl_layout_read_from_ifd(fill_flash, &layout, NULL, 0) || + process_include_args(layout))) { + ret = 1; + goto out_shutdown; + } + fl_layout_set(fill_flash, layout); fl_flag_set(fill_flash, FL_FLAG_FORCE, !!force); fl_flag_set(fill_flash, FL_FLAG_FORCE_BOARDMISMATCH, !!force_boardmismatch); fl_flag_set(fill_flash, FL_FLAG_VERIFY_AFTER_WRITE, !dont_verify_it); @@ -551,6 +571,9 @@ int main(int argc, char *argv[]) else if (verify_it) ret = do_verify(fill_flash, filename); + if (ifd) + fl_layout_release(layout); + out_shutdown: programmer_shutdown(); out: diff --git a/flash.h b/flash.h index fc024ac..05cb59b 100644 --- a/flash.h +++ b/flash.h @@ -285,6 +285,7 @@ void list_programmers_linebreak(int startcol, int cols, int paren); 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); int do_read(struct flashctx *, const char *filename); int do_erase(struct flashctx *); int do_write(struct flashctx *, const char *const filename); @@ -352,7 +353,6 @@ __attribute__((format(printf, 2, 3))); /* 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); int build_new_image(struct flashctx *flash, bool oldcontents_valid, uint8_t *oldcontents, uint8_t *newcontents); diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl index 34e1fe7..02d79e3 100644 --- a/flashrom.8.tmpl +++ b/flashrom.8.tmpl @@ -48,7 +48,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 @@ -179,6 +179,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 0bc8e6f..0fcbab8 100644 --- a/flashrom.c +++ b/flashrom.c @@ -2143,9 +2143,9 @@ int chip_safety_check(const struct flashctx *flash, int force, int read_it, int 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"); diff --git a/ich_descriptors.c b/ich_descriptors.c index c9e82eb..5d6b66f 100644 --- a/ich_descriptors.c +++ b/ich_descriptors.c @@ -23,6 +23,7 @@ #ifdef ICH_DESCRIPTORS_FROM_DUMP_ONLY #include +#include #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) @@ -916,4 +917,55 @@ int read_ich_descriptors_via_fdo(void *spibar, struct ich_descriptors *desc) msg_pdbg2(" done.\n"); return ICH_RET_OK; } + +/** + * @addtogroup fl-layout + * @{ + */ + +/** + * @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 fl_layout_ich *const layout, const void *const dump, const size_t len) +{ + static const char *regions[5] = { + "Flash_Descriptor", + "BIOS", + "Intel_ME", + "GbE", + "Platform_Data" + }; + + 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..107fad6 100644 --- a/ich_descriptors.h +++ b/ich_descriptors.h @@ -584,4 +584,6 @@ int read_ich_descriptors_from_dump(const uint32_t *dump, unsigned int len, struc 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 fl_layout_ich *, const void *dump, size_t len); + #endif /* __ICH_DESCRIPTORS_H__ */ diff --git a/layout.c b/layout.c index 9eadb22..ab80bb8 100644 --- a/layout.c +++ b/layout.c @@ -35,7 +35,7 @@ static struct fl_layout layout = { entries, 0 }; static char *include_args[MAX_ROMLAYOUT]; static int num_include_args = 0; /* the number of valid include_args. */ -const struct fl_layout *get_global_layout(void) +struct fl_layout *get_global_layout(void) { return &layout; } @@ -132,17 +132,17 @@ int register_include_arg(char *name) } /* 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 fl_layout *const fl_layout, char *name) { int i; - if (layout.num_entries == 0) + if (fl_layout->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 < fl_layout->num_entries; i++) { + if (!strcmp(fl_layout->entries[i].name, name)) { + fl_layout->entries[i].included = 1; msg_gspew("found.\n"); return i; } @@ -154,7 +154,7 @@ static int find_romentry(char *name) /* process -i arguments * returns 0 to indicate success, >0 to indicate failure */ -int process_include_args(void) +int process_include_args(struct fl_layout *const fl_layout) { int i; unsigned int found = 0; @@ -163,7 +163,7 @@ int process_include_args(void) return 0; /* User has specified an area, but no layout file is loaded. */ - if (layout.num_entries == 0) { + if (fl_layout->num_entries == 0) { msg_gerr("Region requested (with -i \"%s\"), " "but no layout data is available.\n", include_args[0]); @@ -171,7 +171,7 @@ int process_include_args(void) } for (i = 0; i < num_include_args; i++) { - if (find_romentry(include_args[i]) < 0) { + if (find_romentry(fl_layout, 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 3aebe8a..71bcac3 100644 --- a/layout.h +++ b/layout.h @@ -54,6 +54,13 @@ struct fl_layout_single { struct fl_romentry entry; }; -const struct fl_layout *get_global_layout(void); +struct fl_layout_ich { + struct fl_layout base; + struct fl_romentry entries[5]; +}; + +struct fl_layout *get_global_layout(void); + +int process_include_args(struct fl_layout *); #endif /* !__LAYOUT_H__ */ diff --git a/libflashrom.c b/libflashrom.c index eab9548..9adb484 100644 --- a/libflashrom.c +++ b/libflashrom.c @@ -31,6 +31,7 @@ #include "flash.h" #include "programmer.h" #include "layout.h" +#include "ich_descriptors.h" #include "libflashrom.h" /** @@ -293,6 +294,79 @@ int fl_layout_include_region(fl_layout_t *const layout, const char *name) } /** + * @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 flashctx Flash context to read the descriptor from flash. + * @param layout Pointer that getwhere to store the layout. + * @param dump The descriptor dump to compare to or NULL. + * @param len The length of the descriptor dump. + * + * @return 0 on success, + * 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 fl_layout_read_from_ifd(struct flashctx *const flashctx, fl_layout_t **const layout, + const void *const dump, const size_t len) +{ + struct fl_layout_ich dump_layout; + int ret = 1; + + void *const desc = malloc(0x1000); + struct fl_layout_ich *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 _unmap_ret; + } + msg_cinfo("done.\n"); + + if (layout_from_ich_descriptors(chip_layout, desc, 0x1000)) { + ret = 3; + goto _unmap_ret; + } + + if (dump) { + if (layout_from_ich_descriptors(&dump_layout, dump, len)) { + ret = 4; + goto _unmap_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 _unmap_ret; + } + } + + *layout = (struct fl_layout *)chip_layout; + ret = 0; + +_unmap_ret: + unmap_flash(flashctx); +_free_ret: + if (ret) + free(chip_layout); + free(desc); + return ret; +} + +/** * @brief Free a layout. * * @param layout Layout to free. diff --git a/libflashrom.h b/libflashrom.h index af56bc8..aceb388 100644 --- a/libflashrom.h +++ b/libflashrom.h @@ -63,6 +63,7 @@ int fl_image_verify(fl_flashctx_t *, const void *buffer, size_t buffer_len); struct fl_layout; typedef struct fl_layout fl_layout_t; +int fl_layout_read_from_ifd(fl_flashctx_t *, fl_layout_t **, const void *dump, size_t len); int fl_layout_include_region(fl_layout_t *, const char *name); void fl_layout_release(fl_layout_t *); void fl_layout_set(fl_flashctx_t *, const fl_layout_t *);