Add an optional sub-parameter to the -i parameter to allow building the
image to be written from multiple files. This will also allow regions to
be read from flash and written to separate image files in a later patch.

based on chromiumos'
d0ea9ed71e7f86bb8e8db2ca7c32a96de25343d8
Signed-off-by: David Hendricks <[email protected]>

Signed-off-by: Stefan Tauner <[email protected]>
---

TODO:
 - man page
 - definition or at least an explanation of precedence of command line 
parameters
---
 flash.h    |   10 +++++-
 flashrom.c |  117 ++++++++++++++++++++++++++++++++++++++++++++---------------
 layout.c   |   84 ++++++++++++++++++++++++++++++++++++-------
 3 files changed, 167 insertions(+), 44 deletions(-)

diff --git a/flash.h b/flash.h
index e51b6d4..c4d747b 100644
--- a/flash.h
+++ b/flash.h
@@ -39,6 +39,13 @@
 #define TIMEOUT_ERROR  -101
 
 typedef unsigned long chipaddr;
+typedef struct {
+       unsigned int start;
+       unsigned int end;
+       unsigned int included;
+       char name[256];
+       char file[256]; /* file == "" means not specified. */
+} romlayout_t;
 
 int register_shutdown(int (*function) (void *data), void *data);
 void *programmer_map_flash_region(const char *descr, unsigned long phys_addr,
@@ -292,7 +299,8 @@ int print(int type, const char *fmt, ...) 
__attribute__((format(printf, 2, 3)));
 int register_include_arg(char *name);
 int process_include_args(void);
 int read_romlayout(char *name);
-int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t 
*newcontents);
+romlayout_t *get_next_included_romentry(unsigned int start);
+int build_new_image(struct flashctx *flash, int oldcontents_valid, uint8_t 
*oldcontents, uint8_t *newcontents);
 
 /* spi.c */
 struct spi_command {
diff --git a/flashrom.c b/flashrom.c
index f1a6165..e33152f 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1069,7 +1069,7 @@ int read_buf_from_file(unsigned char *buf, unsigned long 
size,
        return 0;
 }
 
-int write_buf_to_file(unsigned char *buf, unsigned long size,
+int write_dump_to_file(unsigned char *buf, unsigned long size,
                      const char *filename)
 {
        unsigned long numbytes;
@@ -1094,26 +1094,81 @@ int write_buf_to_file(unsigned char *buf, unsigned long 
size,
        return 0;
 }
 
+int write_buf_to_file(unsigned char *buf, unsigned long size,
+                     const char *filename)
+{
+       romlayout_t *l;
+       int ret = 0;
+
+       ret = write_dump_to_file(buf, size, filename);
+       if (ret)
+               return ret;
+
+       l = get_next_included_romentry(0);
+
+       while (l != NULL) {
+               const char* name = (l->file[0] == '\0') ? l->name : l->file;
+               unsigned int len = l->end - l->start + 1;
+               msg_gdbg2("Writing \"%s\" to \"%s\" 0x%08x - 0x%08x (%uB)... ",
+                         l->name, name, l->start, l->end, len);
+               if(write_dump_to_file(buf + l->start, len, name)) {
+                       msg_gdbg2("failed. ");
+                       return 1;
+               }
+               msg_gdbg2("done. ");
+               l = get_next_included_romentry(l->end + 1);
+       };
+
+       return 0;
+}
+
+int read_flash_to_buf(struct flashctx *flash, uint8_t *buf)
+{
+       romlayout_t *l;
+
+       if (!flash->read) {
+               msg_cerr("No read function available for this flash chip.\n");
+               return 1;
+       }
+
+       l = get_next_included_romentry(0);
+       /* No included rom entries. Assume complete readout wanted. */
+       if (l == NULL)
+               return flash->read(flash, buf, 0, flash->total_size * 1024);
+
+       do {
+               unsigned int len = l->end - l->start + 1;
+               msg_gdbg2("Reading \"%s\" 0x%08x - 0x%08x (%uB)... ", l->name,
+                         l->start, l->end, len);
+               if(flash->read(flash, buf + l->start, l->start, len)) {
+                       msg_gdbg2("failed. ");
+                       return 1;
+               }
+               msg_gdbg2("done. ");
+               l = get_next_included_romentry(l->end + 1);
+       } while (l != NULL);
+
+       return 0;
+}
+
 int read_flash_to_file(struct flashctx *flash, const char *filename)
 {
        unsigned long size = flash->total_size * 1024;
-       unsigned char *buf = calloc(size, sizeof(char));
        int ret = 0;
+       uint8_t *buf;
 
        msg_cinfo("Reading flash... ");
-       if (!buf) {
+
+       buf = calloc(size, sizeof(uint8_t));
+       if (buf == NULL) {
                msg_gerr("Memory allocation failed!\n");
-               msg_cinfo("FAILED.\n");
-               return 1;
-       }
-       if (!flash->read) {
-               msg_cerr("No read function available for this flash chip.\n");
                ret = 1;
                goto out_free;
        }
-       if (flash->read(flash, buf, 0, size)) {
+
+       ret = read_flash_to_buf(flash, buf);
+       if (ret != 0) {
                msg_cerr("Read operation failed!\n");
-               ret = 1;
                goto out_free;
        }
 
@@ -1679,6 +1734,7 @@ int doit(struct flashctx *flash, int force, const char 
*filename, int read_it,
        uint8_t *newcontents;
        int ret = 0;
        unsigned long size = flash->total_size * 1024;
+       int read_all_first = 1; /* FIXME: Make this configurable. */
 
        if (chip_safety_check(flash, force, read_it, write_it, erase_it, 
verify_it)) {
                msg_cerr("Aborting.\n");
@@ -1745,28 +1801,27 @@ int doit(struct flashctx *flash, int force, const char 
*filename, int read_it,
 
        /* Read the whole chip to be able to check whether regions need to be
         * erased and to give better diagnostics in case write fails.
-        * The alternative would be to read only the regions which are to be
+        * The alternative is to read only the regions which are to be
         * preserved, but in that case we might perform unneeded erase which
         * takes time as well.
         */
-       msg_cinfo("Reading old flash chip contents... ");
-       if (flash->read(flash, oldcontents, 0, size)) {
-               ret = 1;
-               msg_cinfo("FAILED.\n");
-               goto out;
+       if (read_all_first) {
+               msg_cinfo("Reading old flash chip contents... ");
+               if (flash->read(flash, oldcontents, 0, size)) {
+                       ret = 1;
+                       msg_cinfo("FAILED.\n");
+                       goto out;
+               }
        }
        msg_cinfo("done.\n");
 
-       // This should be moved into each flash part's code to do it 
-       // cleanly. This does the job.
-       handle_romentries(flash, oldcontents, newcontents);
-
-       // ////////////////////////////////////////////////////////////
+       /* Build a new image from the given layout. */
+       build_new_image(flash, read_all_first, oldcontents, newcontents);
 
-       if (write_it) {
-               if (erase_and_write_flash(flash, oldcontents, newcontents)) {
-                       msg_cerr("Uh oh. Erase/write failed. Checking if "
-                                "anything changed.\n");
+       if (write_it && erase_and_write_flash(flash, oldcontents, newcontents)) 
{
+               msg_cerr("Uh oh. Erase/write failed.");
+               if (read_all_first) {
+                       msg_cerr("Checking if anything changed... ");
                        if (!flash->read(flash, newcontents, 0, size)) {
                                if (!memcmp(oldcontents, newcontents, size)) {
                                        msg_cinfo("Good. It seems nothing was "
@@ -1775,11 +1830,13 @@ int doit(struct flashctx *flash, int force, const char 
*filename, int read_it,
                                        ret = 1;
                                        goto out;
                                }
-                       }
-                       emergency_help_message();
-                       ret = 1;
-                       goto out;
-               }
+                       } else
+                               msg_cerr("failed.\n");
+               } else
+                       msg_cerr("\n");
+               emergency_help_message();
+               ret = 1;
+               goto out;
        }
 
        if (verify_it) {
diff --git a/layout.c b/layout.c
index 3928699..e16d03b 100644
--- a/layout.c
+++ b/layout.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <ctype.h>
 #include <limits.h>
 #include "flash.h"
@@ -34,13 +35,6 @@ static int romimages = 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.
@@ -183,6 +177,7 @@ int read_romlayout(char *name)
                rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16);
                rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16);
                rom_entries[romimages].included = 0;
+               strcpy(rom_entries[romimages].file, "");
                romimages++;
        }
 
@@ -220,14 +215,24 @@ int register_include_arg(char *name)
 static int find_romentry(char *name)
 {
        int i;
+       char *file = NULL;
 
        if (!romimages)
                return -1;
 
-       msg_gspew("Looking for region \"%s\"... ", name);
+       /* -i <image>[:<file>] */
+       if (strtok(name, ":")) {
+               file = strtok(NULL, "");
+       }
+       msg_gspew("Looking for region \"%s\" (file=\"%s\")... ",
+                 name, file ? file : "<not specified>");
+
        for (i = 0; i < romimages; i++) {
                if (!strcmp(rom_entries[i].name, name)) {
                        rom_entries[i].included = 1;
+                       snprintf(rom_entries[i].file,
+                                sizeof(rom_entries[i].file),
+                                "%s", file ? file : "");
                        msg_gspew("found.\n");
                        return i;
                }
@@ -299,7 +304,55 @@ romlayout_t *get_next_included_romentry(unsigned int start)
        return best_entry;
 }
 
-int handle_romentries(struct flashctx *flash, uint8_t *oldcontents, uint8_t 
*newcontents)
+/* If a file name is specified for this region, read the file contents and
+ * overwrite @newcontents in the range specified by @entry.
+ */
+static int read_content_from_file(romlayout_t *entry, uint8_t *newcontents)
+{
+       char *file;
+       FILE *fp;
+       int len;
+
+       file = entry->file;
+       len = entry->end - entry->start + 1;
+       if (file[0] != '\0') {
+               int numbytes;
+               if ((fp = fopen(file, "rb")) == NULL) {
+                       msg_gerr("Could not open file '%s': %s!\n", file,
+                                strerror(errno));
+                       return 1;
+               }
+               numbytes = fread(newcontents + entry->start, 1, len, fp);
+               fclose(fp);
+               if (numbytes != len) {
+                       msg_gerr("Could not read %d bytes from file '%s'!\n",
+                                len, file);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static void copy_old_content(struct flashctx *flash, int oldcontents_valid, 
uint8_t *oldcontents, uint8_t *newcontents, unsigned int start, unsigned int 
size)
+{
+       if (!oldcontents_valid) {
+               /* oldcontents is a zero-filled buffer. By reading into
+                * oldcontents, we avoid a rewrite of identical regions even if
+                * an initial full chip read didn't happen. */
+               msg_gdbg2("Read a chunk starting from 0x%06x (len=0x%06x).\n",
+                         start, size);
+               flash->read(flash, oldcontents + start, start, size);
+       }
+       memcpy(newcontents + start, oldcontents + start, size);
+}
+
+/**
+ * Modify @newcontents so that it contains the data that should be on the chip
+ * eventually. In the case the user wants to update only parts of it, copy
+ * the chunks to be preserved from @oldcontents to @newcontents. If 
@oldcontents
+ * is not valid, we need to fetch the current data from the chip first.
+ */
+int build_new_image(struct flashctx *flash, int oldcontents_valid, uint8_t 
*oldcontents, uint8_t *newcontents)
 {
        unsigned int start = 0;
        romlayout_t *entry;
@@ -318,14 +371,19 @@ int handle_romentries(struct flashctx *flash, uint8_t 
*oldcontents, uint8_t *new
                entry = get_next_included_romentry(start);
                /* No more romentries for remaining region? */
                if (entry == NULL) {
-                       memcpy(newcontents + start, oldcontents + start,
-                              size - start);
+                       copy_old_content(flash, oldcontents_valid, oldcontents,
+                                        newcontents, start, size - start);
                        break;
                }
                /* For non-included region, copy from old content. */
                if (entry->start > start)
-                       memcpy(newcontents + start, oldcontents + start,
-                              entry->start - start);
+                       copy_old_content(flash, oldcontents_valid, oldcontents,
+                                        newcontents, start,
+                                        entry->start - start);
+               /* For included region, copy from file if specified. */
+               if (read_content_from_file(entry, newcontents) < 0)
+                       return 1;
+
                /* Skip to location after current romentry. */
                start = entry->end + 1;
                /* Catch overflow. */
-- 
1.7.1


_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to