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 <nico.hu...@secunet.com>
---
 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 <programmername>[:<parameters>] [-c <chipname>]\n"
-              "[-E|(-r|-w|-v) <file>] [-l <layoutfile> [-i <imagename>]...] 
[-n] [-A] [-f]]\n"
+              "[-E|(-r|-w|-v) <file>] [(-l <layoutfile>|-d) [-i 
<imagename>]...] [-n] [-A] [-f]]\n"
               "[-V[V[V]]] [-o <logfile>]\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 <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"
@@ -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 <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
@@ -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 <imagename>"
 Only flash region/image
 .B <imagename>
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 <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)
@@ -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 *);
-- 
2.7.0


_______________________________________________
flashrom mailing list
flashrom@flashrom.org
https://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to