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 dhendrix@chromium.org Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at
Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at --- 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. */