[flashrom] [PATCH 3/5] layout: Add -i <image>[:<file>] support

Stefan Tauner stefan.tauner at student.tuwien.ac.at
Sat Dec 24 01:35:18 CET 2011


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 <dhendrix at chromium.org>

Signed-off-by: Stefan Tauner <stefan.tauner at student.tuwien.ac.at>
---

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





More information about the flashrom mailing list