futility/updater: Add quirk to preserve management engine

In recent Intel platforms, updating Management Engine (ME) while SoC is in
S0 state is an unsupported use-case. To work-around this issue for the
devices that are in development, specifically during firmware update,
this quirk is added to preserve the ME region. In the subsequent boot,
ME region is updated as part of boot firmware update upstart script.

BUG=b:165590952
BRANCH=None
TEST=With the quirk enabled, ensured that the ME is preserved under the
following scenario:
chromeos-firmwareupdate --mode=autoupdate
chromeos-firmwareupdate --mode=recovery
futility update --mode=autoupdate -a /usr/sbin/chromeos-firmwareupdate
futility update --mode=recovery -a /usr/sbin/chromeos-firmwareupdate
In other scenarios, ME region is not preserved.

Change-Id: I81a52d11d1fb363b7e07ef3439b927449456b28a
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2465286
Tested-by: Karthikeyan Ramasubramanian <kramasub@chromium.org>
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Commit-Queue: Karthikeyan Ramasubramanian <kramasub@chromium.org>
diff --git a/futility/updater.c b/futility/updater.c
index 3e3dce2..fd13bb8 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -521,6 +521,13 @@
 				image_from, image_to, FMAP_SI_DESC);
 	}
 
+	if (try_apply_quirk(QUIRK_PRESERVE_ME, cfg) > 0) {
+		VB2_DEBUG("ME needs to be preserved - preserving %s.\n",
+			  FMAP_SI_ME);
+		return preserve_firmware_section(
+				image_from, image_to, FMAP_SI_ME);
+	}
+
 	return try_apply_quirk(QUIRK_UNLOCK_ME_FOR_UPDATE, cfg);
 }
 
diff --git a/futility/updater.h b/futility/updater.h
index 57829cb..3ed8039 100644
--- a/futility/updater.h
+++ b/futility/updater.h
@@ -44,6 +44,7 @@
 	QUIRK_ALLOW_EMPTY_WLTAG,
 	QUIRK_EC_PARTIAL_RECOVERY,
 	QUIRK_OVERRIDE_SIGNATURE_ID,
+	QUIRK_PRESERVE_ME,
 	QUIRK_MAX,
 };
 
diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c
index 841562f..e4056b0 100644
--- a/futility/updater_quirks.c
+++ b/futility/updater_quirks.c
@@ -382,6 +382,39 @@
 }
 
 /*
+ * Preserve ME during firmware update.
+ *
+ * Updating ME region while SoC is in S0 state is an unsupported use-case. On
+ * recent platforms, we are seeing issues more frequently because of this use-
+ * case. For the firmware updates performed using firmware update archive,
+ * preserve the ME region so that it gets updated in the successive boot.
+ *
+ * Returns:
+ *   1 to signal ME needs to be preserved.
+ *   0 to signal ME does not need to be preserved.
+ */
+static int quirk_preserve_me(struct updater_config *cfg)
+{
+	/* For a factory update donot preserve ME. */
+	if (cfg->factory_update) {
+	       WARN("Factory update. Not preserving ME.\n");
+	       return 0;
+	}
+
+	/*
+	 * For a non-archive update, the post boot script that updates ME
+	 * does not have access to the firmware image after the boot. Hence
+	 * donot preserve ME.
+	 */
+	if (!cfg->archive) {
+		WARN("Update using a non-archive image. Not preserving ME.\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
  * Registers known quirks to a updater_config object.
  */
 void updater_register_quirks(struct updater_config *cfg)
@@ -434,6 +467,12 @@
 	quirks->help = "chromium/146876241; override signature id for "
 			"devices shipped with different root key.";
 	quirks->apply = NULL; /* Simple config. */
+
+	quirks = &cfg->quirks[QUIRK_PRESERVE_ME];
+	quirks->name = "preserve_me";
+	quirks->help = "b/165590952; Preserve ME during firmware update except "
+		       "for factory update or developer images.";
+	quirks->apply = quirk_preserve_me;
 }
 
 /*