Add support for reading the current flash contents from a file

When developing software that has to be flashed to a flash chip to be
executed, it often takes a long time to read the current flash contents
(for flashrom to know what pages to erase and reprogram) each time
when writing the new image. However, when the flash was just reprogrammed,
its current state is known to be the previous image that was flashed
(assuming it was verified).

Thus, it makes sense to provide that image as a file for the flash contents
instead of wasting valuable time read the whole flash each time.

Change-Id: Idf153b6955f37779ae9bfb228a434ed10c304947
Signed-off-by: Mike Banon <mikebdp2@gmail.com>
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Reviewed-on: https://review.coreboot.org/23263
Reviewed-by: Nico Huber <nico.h@gmx.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/cli_classic.c b/cli_classic.c
index 441fc91..31f7394 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -60,6 +60,7 @@
 	       "      --ifd                         read layout from an Intel Firmware Descriptor\n"
 	       " -i | --image <name>                only flash image <name> from flash layout\n"
 	       " -o | --output <logfile>            log output to <logfile>\n"
+	       "      --flash-contents <ref-file>   assume flash contents to be <ref-file>\n"
 	       " -L | --list-supported              print supported devices\n"
 #if CONFIG_PRINT_WIKI == 1
 	       " -z | --list-supported-wiki         print supported devices in wiki syntax\n"
@@ -108,6 +109,10 @@
 	int dont_verify_it = 0, dont_verify_all = 0, list_supported = 0, operation_specified = 0;
 	struct flashrom_layout *layout = NULL;
 	enum programmer prog = PROGRAMMER_INVALID;
+	enum {
+		OPTION_IFD = 0x0100,
+		OPTION_FLASH_CONTENTS,
+	};
 	int ret = 0;
 
 	static const char optstring[] = "r:Rw:v:nNVEfc:l:i:p:Lzho:";
@@ -122,8 +127,9 @@
 		{"verbose",		0, NULL, 'V'},
 		{"force",		0, NULL, 'f'},
 		{"layout",		1, NULL, 'l'},
-		{"ifd",			0, NULL, 0x0100},
+		{"ifd",			0, NULL, OPTION_IFD},
 		{"image",		1, NULL, 'i'},
+		{"flash-contents",	1, NULL, OPTION_FLASH_CONTENTS},
 		{"list-supported",	0, NULL, 'L'},
 		{"list-supported-wiki",	0, NULL, 'z'},
 		{"programmer",		1, NULL, 'p'},
@@ -134,6 +140,7 @@
 	};
 
 	char *filename = NULL;
+	char *referencefile = NULL;
 	char *layoutfile = NULL;
 #ifndef STANDALONE
 	char *logfile = NULL;
@@ -229,7 +236,7 @@
 			}
 			layoutfile = strdup(optarg);
 			break;
-		case 0x0100:
+		case OPTION_IFD:
 			if (layoutfile) {
 				fprintf(stderr, "Error: --layout and --ifd both specified. Aborting.\n");
 				cli_classic_abort_usage();
@@ -243,6 +250,9 @@
 				cli_classic_abort_usage();
 			}
 			break;
+		case OPTION_FLASH_CONTENTS:
+			referencefile = strdup(optarg);
+			break;
 		case 'L':
 			if (++operation_specified > 1) {
 				fprintf(stderr, "More than one operation "
@@ -354,6 +364,9 @@
 	if (layoutfile && check_filename(layoutfile, "layout")) {
 		cli_classic_abort_usage();
 	}
+	if (referencefile && check_filename(referencefile, "reference")) {
+		cli_classic_abort_usage();
+	}
 
 #ifndef STANDALONE
 	if (logfile && check_filename(logfile, "log"))
@@ -569,7 +582,7 @@
 	else if (erase_it)
 		ret = do_erase(fill_flash);
 	else if (write_it)
-		ret = do_write(fill_flash, filename);
+		ret = do_write(fill_flash, filename, referencefile);
 	else if (verify_it)
 		ret = do_verify(fill_flash, filename);
 
@@ -583,6 +596,7 @@
 
 	layout_cleanup();
 	free(filename);
+	free(referencefile);
 	free(layoutfile);
 	free(pparam);
 	/* clean up global variables */