futility: updater: Add '--fast' for quick development

When using 'futility update' with Servo Micro or CCD, the programmer is
pretty slow that every invocation of flashrom would take a very long
time, so re-reading firmware contents when writing (flashrom -w) seems
redundant. For such usage, a '--fast' would be helpful that
 - Uses the last read image (image_current) as --diff
 - Add --noverify

BUG=None
TEST=make futil; tests/futility/run_test_scripts.sh $(pwd)/build/futility
BRANCH=None

Change-Id: I1ad57185160a082ea6b5c94b837a4d3ba708b587
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1375495
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index c7bc964..b3308c8 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -16,6 +16,7 @@
 
 enum {
 	OPT_DUMMY = 0x100,
+	OPT_FAST,
 };
 
 /* Command line options */
@@ -35,6 +36,7 @@
 	{"repack", 1, NULL, 'k'},
 	{"unpack", 1, NULL, 'u'},
 	{"factory", 0, NULL, 'Y'},
+	{"fast", 0, NULL, OPT_FAST},
 	{"force", 0, NULL, 'F'},
 	{"programmer", 1, NULL, 'p'},
 	{"wp", 1, NULL, 'W'},
@@ -69,6 +71,7 @@
 		"    --repack=DIR    \tUpdates archive from DIR\n"
 		"    --unpack=DIR    \tExtracts archive to DIR\n"
 		"-p, --programmer=PRG\tChange AP (host) flashrom programmer\n"
+		"    --fast          \tReduce read cycles and do not verify\n"
 		"    --quirks=LIST   \tSpecify the quirks to apply\n"
 		"    --list-quirks   \tPrint all available quirks\n"
 		"\n"
@@ -174,6 +177,10 @@
 			args.verbosity++;
 			break;
 
+		case OPT_FAST:
+			args.fast_update = 1;
+			break;
+
 		case OPT_DUMMY:
 			break;
 		case 'h':
diff --git a/futility/updater.c b/futility/updater.c
index ab5cba4..d16fe38 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -244,10 +244,10 @@
  */
 static int host_flashrom(enum flashrom_ops op, const char *image_path,
 			 const char *programmer, int verbose,
-			 const char *section_name)
+			 const char *section_name, const char *extra)
 {
 	char *command, *result;
-	const char *op_cmd, *dash_i = "-i", *postfix = "", *ignore_lock = "";
+	const char *op_cmd, *dash_i = "-i", *postfix = "";
 	int r;
 
 	switch (verbose) {
@@ -297,9 +297,12 @@
 		return -1;
 	}
 
+	if (!extra)
+		extra = "";
+
 	/* TODO(hungte) In future we should link with flashrom directly. */
 	ASPRINTF(&command, "flashrom %s %s -p %s %s %s %s %s", op_cmd,
-		 image_path, programmer, dash_i, section_name, ignore_lock,
+		 image_path, programmer, dash_i, section_name, extra,
 		 postfix);
 
 	if (verbose)
@@ -329,7 +332,8 @@
 /* Helper function to return write protection status via given programmer. */
 static int host_get_wp(const char *programmer)
 {
-	return host_flashrom(FLASHROM_WP_STATUS, NULL, programmer, 0, NULL);
+	return host_flashrom(FLASHROM_WP_STATUS, NULL, programmer, 0, NULL,
+			     NULL);
 }
 
 /* Helper function to return host software write protection status. */
@@ -665,7 +669,7 @@
 		return -1;
 	RETURN_ON_FAILURE(host_flashrom(
 			FLASHROM_READ, tmp_file, image->programmer,
-			cfg->verbosity, NULL));
+			cfg->verbosity, NULL, NULL));
 	return load_firmware_image(image, tmp_file, NULL);
 }
 
@@ -831,7 +835,10 @@
 			  const char *section_name)
 {
 	const char *tmp_file = updater_create_temp_file(cfg);
+	const char *tmp_diff_file = NULL;
 	const char *programmer = image->programmer;
+	char *extra = NULL;
+	int r;
 
 	if (!tmp_file)
 		return -1;
@@ -850,8 +857,20 @@
 		ERROR("Cannot write temporary file for output: %s", tmp_file);
 		return -1;
 	}
-	return host_flashrom(FLASHROM_WRITE, tmp_file, programmer,
-			     cfg->verbosity + 1, section_name);
+	if (cfg->fast_update && image == &cfg->image && cfg->image_current.data)
+	{
+		tmp_diff_file = updater_create_temp_file(cfg);
+		if (vb2_write_file(tmp_diff_file, cfg->image_current.data,
+				   cfg->image_current.size) != VB2_SUCCESS) {
+			ERROR("Cannot write temporary file for diff image");
+			return -1;
+		}
+		ASPRINTF(&extra, "--noverify --diff=%s", tmp_diff_file);
+	}
+	r = host_flashrom(FLASHROM_WRITE, tmp_file, programmer,
+			  cfg->verbosity + 1, section_name, extra);
+	free(extra);
+	return r;
 }
 
 /*
@@ -1897,6 +1916,7 @@
 
 	/* Setup values that may change output or decision of other argument. */
 	cfg->verbosity = arg->verbosity;
+	cfg->fast_update = arg->fast_update;
 	cfg->factory_update = arg->is_factory;
 	if (arg->force_update)
 		cfg->force_update = 1;
diff --git a/futility/updater.h b/futility/updater.h
index 7db6ec4..c75493a 100644
--- a/futility/updater.h
+++ b/futility/updater.h
@@ -113,6 +113,7 @@
 	int legacy_update;
 	int factory_update;
 	int check_platform;
+	int fast_update;
 	int verbosity;
 	const char *emulation;
 };
@@ -125,6 +126,7 @@
 	char *output_dir;
 	char *repack, *unpack;
 	int is_factory, try_update, force_update, do_manifest, host_only;
+	int fast_update;
 	int verbosity;
 };