summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2022-11-10 11:59:53 +0800
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-01-19 16:17:29 +0000
commit4c9fbadcbd95c9d30eecdff43ed4f8d072bb7878 (patch)
treef462419308d56a419daeefe22167c2da29b3a1de
parent9020299e38c17642995f13a0fe8b09178f442d32 (diff)
downloadvboot-4c9fbadcbd95c9d30eecdff43ed4f8d072bb7878.tar.gz
futility: updater: add new quirk 'clear_mrc_data'
For devices with some memory training data that is not compatible with the new flashed firmware (and can't be automatically detected by the new firmware), we need a way to easily wipe out the existing memory training data to enforce a retraining at the next boot. This usually happens when repairing a device (with non-qualified firmware) and should never happen in the OTA. BUG=b:255617349 TEST=make; run test BRANCH=None Signed-off-by: Hung-Te Lin <hungte@chromium.org> Change-Id: I92befefa6be59da10ca7572e7849ef905f184a5f Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/4018593 Reviewed-by: Yu-Ping Wu <yupingso@chromium.org> Tested-by: Yu-Ping Wu <yupingso@chromium.org> Reviewed-by: Julius Werner <jwerner@chromium.org> Commit-Queue: Yu-Ping Wu <yupingso@chromium.org>
-rw-r--r--futility/updater.c20
-rw-r--r--futility/updater.h1
-rw-r--r--futility/updater_quirks.c51
-rw-r--r--futility/updater_utils.c17
-rw-r--r--futility/updater_utils.h5
5 files changed, 77 insertions, 17 deletions
diff --git a/futility/updater.c b/futility/updater.c
index e6ba3443..c0a500fc 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -581,23 +581,6 @@ static int section_needs_update(const struct firmware_image *image_from,
}
/*
- * Returns true if the write protection is enabled on current system.
- */
-static int is_write_protection_enabled(struct updater_config *cfg)
-{
- /* Default to enabled. */
- int wp = get_system_property(SYS_PROP_WP_HW, cfg);
- if (wp == WP_DISABLED)
- return wp;
- /* For error or enabled, check WP SW. */
- wp = get_system_property(SYS_PROP_WP_SW, cfg);
- /* Consider all errors as enabled. */
- if (wp != WP_DISABLED)
- return WP_ENABLED;
- return wp;
-}
-
-/*
* Checks if the given firmware images are compatible with current platform.
* In current implementation (following Chrome OS style), we assume the platform
* is identical to the name before a dot (.) in firmware version.
@@ -1227,6 +1210,9 @@ enum updater_error_codes update_firmware(struct updater_config *cfg)
if (try_apply_quirk(QUIRK_EVE_SMM_STORE, cfg))
return UPDATE_ERR_INVALID_IMAGE;
+ if (try_apply_quirk(QUIRK_CLEAR_MRC_DATA, cfg))
+ return UPDATE_ERR_SYSTEM_IMAGE;
+
if (debugging_enabled)
print_system_properties(cfg);
diff --git a/futility/updater.h b/futility/updater.h
index 768beece..cedeb302 100644
--- a/futility/updater.h
+++ b/futility/updater.h
@@ -51,6 +51,7 @@ enum quirk_types {
QUIRK_NO_VERIFY,
QUIRK_EXTRA_RETRIES,
QUIRK_EXTERNAL_FLASHROM,
+ QUIRK_CLEAR_MRC_DATA,
QUIRK_MAX,
};
diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c
index dab86ec8..4975997a 100644
--- a/futility/updater_quirks.c
+++ b/futility/updater_quirks.c
@@ -424,6 +424,52 @@ static int quirk_preserve_me(struct updater_config *cfg)
return 1;
}
+static int quirk_clear_mrc_data(struct updater_config *cfg)
+{
+ struct firmware_section section;
+ struct firmware_image *image = &cfg->image_current;
+ int i, count = 0;
+ int flash_now = 0;
+
+ /*
+ * Devices with multiple MRC caches (RECOVERY, RW, RW_VAR) will have the
+ * UNIFIED_MRC_CACHE; and devices with single RW cache will only have
+ * RW_MRC_CACHE (for example MediaTek devices).
+ */
+ const char * const mrc_names[] = {
+ "UNIFIED_MRC_CACHE",
+ "RW_MRC_CACHE",
+ };
+
+ if (is_write_protection_enabled(cfg) || cfg->try_update)
+ flash_now = 1;
+
+ for (i = 0; i < ARRAY_SIZE(mrc_names); i++) {
+ const char *name = mrc_names[i];
+ const char *write_names[2] = {0};
+
+ find_firmware_section(&section, image, name);
+ if (!section.size)
+ continue;
+
+ WARN("Wiping memory training data: %s\n", name);
+ memset(section.data, 0xff, section.size);
+ if (flash_now) {
+ write_names[0] = name;
+ write_system_firmware(cfg, image, write_names);
+ }
+ count++;
+ break;
+ }
+
+ if (count)
+ WARN("Next boot will take a few mins for memory training.\n");
+ else
+ ERROR("No known memory training data in the firmware image.\n");
+
+ return 0;
+}
+
/*
* Disable checking platform compatibility.
*/
@@ -522,6 +568,11 @@ void updater_register_quirks(struct updater_config *cfg)
quirks->name = "external_flashrom";
quirks->help = "Use external flashrom to access the system firmware.";
quirks->apply = NULL; /* Simple config. */
+
+ quirks = &cfg->quirks[QUIRK_CLEAR_MRC_DATA];
+ quirks->name = "clear_mrc_data";
+ quirks->help = "b/255617349: Clear memory training data (MRC).";
+ quirks->apply = quirk_clear_mrc_data;
}
/*
diff --git a/futility/updater_utils.c b/futility/updater_utils.c
index 8895c094..cb7ac604 100644
--- a/futility/updater_utils.c
+++ b/futility/updater_utils.c
@@ -359,6 +359,23 @@ const struct vb2_gbb_header *find_gbb(const struct firmware_image *image)
}
/*
+ * Returns true if the write protection is enabled on current system.
+ */
+int is_write_protection_enabled(struct updater_config *cfg)
+{
+ /* Default to enabled. */
+ int wp = get_system_property(SYS_PROP_WP_HW, cfg);
+ if (wp == WP_DISABLED)
+ return wp;
+ /* For error or enabled, check WP SW. */
+ wp = get_system_property(SYS_PROP_WP_SW, cfg);
+ /* Consider all errors as enabled. */
+ if (wp != WP_DISABLED)
+ return WP_ENABLED;
+ return wp;
+}
+
+/*
* Executes a command on current host and returns stripped command output.
* If the command has failed (exit code is not zero), returns an empty string.
* The caller is responsible for releasing the returned string.
diff --git a/futility/updater_utils.h b/futility/updater_utils.h
index a0dfc912..a5d012b8 100644
--- a/futility/updater_utils.h
+++ b/futility/updater_utils.h
@@ -176,6 +176,11 @@ void strip_string(char *s, const char *pattern);
int save_file_from_stdin(const char *output);
/*
+ * Returns true if the write protection is enabled on current system.
+ */
+int is_write_protection_enabled(struct updater_config *cfg);
+
+/*
* Executes a command on current host and returns stripped command output.
* If the command has failed (exit code is not zero), returns an empty string.
* The caller is responsible for releasing the returned string.