[flashrom] [PATCH 2/4] layout: Add -i <image>[:<file>] support.

Stefan Tauner stefan.tauner at student.tuwien.ac.at
Thu Sep 12 22:40:06 CEST 2013


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

Signed-off-by: Stefan Tauner <stefan.tauner at 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. */
-- 
Kind regards, Stefan Tauner





More information about the flashrom mailing list