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.
Document the whole layout handling including the new features a bit better.

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

Signed-off-by: Stefan Tauner <[email protected]>
---
 flashrom.8.tmpl | 47 +++++++++++++--------------
 flashrom.c      |  8 +++--
 layout.c        | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 116 insertions(+), 37 deletions(-)

diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index 5ede423..b1371e4 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 <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\-i\fR <image>[:<file>]]...] [\fB\-n\fR] 
[\fB\-f\fR]]
          [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>]
 .SH DESCRIPTION
 .B flashrom
@@ -103,44 +103,45 @@ size for the flash bus.
 * Force write even if write is known bad.
 .TP
 .B "\-l, \-\-layout <file>"
-Read ROM layout from
+Read layout entries from
 .BR <file> .
 .sp
-flashrom supports ROM layouts. This allows you to flash certain parts of
-the flash chip only. A ROM layout file contains multiple lines with the
-following syntax:
+A layout entry describes an address region of the flash chip and gives it a 
name. This allows to access certain
+parts of the flash chip only. A layout file can contain multiple entries one 
per line with the following syntax:
 .sp
-.B "  startaddr:endaddr imagename"
+.B "  startaddr:endaddr regionname"
 .sp
 .BR "startaddr " "and " "endaddr "
-are hexadecimal addresses within the ROM file and do not refer to any
-physical address. Please note that using a 0x prefix for those hexadecimal
+are hexadecimal addresses within the ROM file representing the flash ROM 
contents.
+Please note that using a 0x prefix for those hexadecimal
 numbers is not necessary, but you can't specify decimal/octal numbers.
-.BR "imagename " "is an arbitrary name for the region/image from"
-.BR " startaddr " "to " "endaddr " "(both addresses included)."
+.BR "regionname " "is an arbitrary name for the region from "
+.BR "startaddr " "to " "endaddr " "(both addresses included)."
 .sp
-Example:
+Example content of file rom.layout:
 .sp
   00000000:00008fff gfxrom
   00009000:0003ffff normal
   00040000:0007ffff fallback
 .sp
-If you only want to update the image named
-.BR "normal " "in a ROM based on the layout above, run"
-.sp
-.B "  flashrom \-p prog \-\-layout rom.layout \-\-image normal \-w some.rom"
+.TP
+.B "\-i, \-\-image <name>[:<file>]"
+Work on the flash region
+.B name
+instead of the full address space if a layout file is given and parsed 
correctly.
+Multiple such image parameters can be used to include the union of different 
regions.
+The optional
+.B file
+parameter specifies the name of an image file that is used to map the contents 
of that very region only.
+This is useful for example if you want to write only a part of the flash chip 
and leave everything else alone
+without preparing an image of the complete chip manually:
 .sp
-To update only the images named
-.BR "normal " "and " "fallback" ", run:"
+If you only want to update the image named
+.BR "normal " "and " "fallback " "in a ROM based on the layout mentioned 
above, run"
 .sp
 .B "  flashrom \-p prog \-l rom.layout \-i normal -i fallback \-w some.rom"
 .sp
-Overlapping sections are not supported.
-.TP
-.B "\-i, \-\-image <imagename>"
-Only flash region/image
-.B <imagename>
-from flash layout.
+.RB "Overlapping sections are resolved in an implementation-dependent manner - 
do " "not " "rely on it."
 .TP
 .B "\-L, \-\-list\-supported"
 List the flash chips, chipsets, mainboards, and external programmers
diff --git a/flashrom.c b/flashrom.c
index a00347e..cd15de7 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -1993,9 +1993,11 @@ int doit(struct flashctx *flash, int force, const char 
*filename, int read_it,
        }
        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);
+       if (handle_romentries(flash, oldcontents, newcontents)) {
+               msg_gerr("Could not prepare the data to be written due to 
problems with the layout,\n"
+                        "aborting.\n");
+               goto out;
+       }
 
        // ////////////////////////////////////////////////////////////
 
diff --git a/layout.c b/layout.c
index 86351b8..20fe303 100644
--- a/layout.c
+++ b/layout.c
@@ -23,6 +23,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
+#include <errno.h>
+#ifndef __LIBPAYLOAD__
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
 #include "flash.h"
 #include "programmer.h"
 
@@ -33,6 +38,7 @@ typedef struct {
        unsigned int end;
        unsigned int included;
        char name[256];
+       char *file;
 } romentry_t;
 
 /* rom_entries store the entries specified in a layout file and associated 
run-time data */
@@ -85,6 +91,7 @@ int read_romlayout(char *name)
                rom_entries[num_rom_entries].start = strtol(tstr1, (char 
**)NULL, 16);
                rom_entries[num_rom_entries].end = strtol(tstr2, (char **)NULL, 
16);
                rom_entries[num_rom_entries].included = 0;
+               rom_entries[num_rom_entries].file = NULL;
                num_rom_entries++;
        }
 
@@ -138,14 +145,9 @@ int register_include_arg(char *name)
 static int find_romentry(char *name)
 {
        int i;
-
-       if (num_rom_entries == 0)
-               return -1;
-
        msg_gspew("Looking for region \"%s\"... ", name);
        for (i = 0; i < num_rom_entries; i++) {
-               if (!strcmp(rom_entries[i].name, name)) {
-                       rom_entries[i].included = 1;
+               if (strcmp(rom_entries[i].name, name) == 0) {
                        msg_gspew("found.\n");
                        return i;
                }
@@ -167,19 +169,36 @@ int process_include_args(void)
 
        /* User has specified an area, but no layout file is loaded. */
        if (num_rom_entries == 0) {
-               msg_gerr("Region requested (with -i \"%s\"), "
-                        "but no layout data is available.\n",
+               msg_gerr("Region requested (with -i/--image \"%s\"),\n"
+                        "but no layout data is available. To include one use 
the -l/--layout syntax).\n",
                         include_args[0]);
                return 1;
        }
 
        for (i = 0; i < num_include_args; i++) {
-               if (find_romentry(include_args[i]) < 0) {
-                       msg_gerr("Invalid region specified: \"%s\".\n",
-                                include_args[i]);
+               char *name = strtok(include_args[i], ":"); /* -i 
<image>[:<file>] */
+               int idx = find_romentry(name);
+               if (idx < 0) {
+                       msg_gerr("Invalid region specified: \"%s\".\n", 
include_args[i]);
                        return 1;
                }
+               rom_entries[idx].included = 1;
                found++;
+
+               char *file = strtok(NULL, ""); /* remaining non-zero length 
token or NULL */
+               if (file != NULL) {
+#ifdef __LIBPAYLOAD__
+                       msg_gerr("Error: No file I/O support in libpayload\n");
+                       return 1;
+#else
+                       file = strdup(file);
+                       if (file == NULL) {
+                               msg_gerr("Out of memory!\n");
+                               return 1;
+                       }
+                       rom_entries[idx].file = file;
+#endif
+               }
        }
 
        msg_ginfo("Using region%s: \"%s\"", num_include_args > 1 ? "s" : "",
@@ -200,6 +219,8 @@ void layout_cleanup(void)
        num_include_args = 0;
 
        for (i = 0; i < num_rom_entries; i++) {
+               free(rom_entries[i].file);
+               rom_entries[i].file = NULL;
                rom_entries[i].included = 0;
        }
        num_rom_entries = 0;
@@ -232,6 +253,57 @@ romentry_t *get_next_included_romentry(unsigned int start)
        return best_entry;
 }
 
+/* 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(romentry_t *entry, uint8_t *newcontents)
+{
+       char *file = entry->file;
+       if (file == NULL)
+               return 0;
+
+#ifdef __LIBPAYLOAD__
+       msg_gerr("Error: No file I/O support in libpayload\n");
+       return 1;
+#else
+       int len = entry->end - entry->start + 1;
+       FILE *fp;
+       if ((fp = fopen(file, "rb")) == NULL) {
+               msg_gerr("Error: Opening layout image file \"%s\" failed: 
%s\n", file, strerror(errno));
+               return 1;
+       }
+
+       struct stat file_stat;
+       if (fstat(fileno(fp), &file_stat) != 0) {
+               msg_gerr("Error: Getting metadata of layout image file \"%s\" 
failed: %s\n", file, strerror(errno));
+               fclose(fp);
+               return 1;
+       }
+       if (file_stat.st_size != len) {
+               msg_gerr("Error: Image size (%jd B) doesn't match the flash 
chip's size (%d B)!\n",
+                        (intmax_t)file_stat.st_size, len);
+               fclose(fp);
+               return 1;
+       }
+
+       int numbytes = fread(newcontents + entry->start, 1, len, fp);
+       if (ferror(fp)) {
+               msg_gerr("Error: Reading layout image file \"%s\" failed: 
%s\n", file, strerror(errno));
+               fclose(fp);
+               return 1;
+       }
+       if (fclose(fp)) {
+               msg_gerr("Error: Closing layout image file \"%s\" failed: 
%s\n", file, strerror(errno));
+               return 1;
+       }
+       if (numbytes != len) {
+               msg_gerr("Error: Failed to read layout image file \"%s\" 
completely.\n"
+                        "Got %d bytes, wanted %d!\n", file, numbytes, len);
+               return 1;
+       }
+       return 0;
+#endif
+}
+
 int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, 
uint8_t *newcontents)
 {
        unsigned int start = 0;
@@ -259,6 +331,10 @@ int handle_romentries(const struct flashctx *flash, 
uint8_t *oldcontents, uint8_
                if (entry->start > start)
                        memcpy(newcontents + start, oldcontents + 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. */
-- 
Kind regards, Stefan Tauner


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

Reply via email to