diff options
author | Hung-Te Lin <hungte@chromium.org> | 2022-11-10 11:59:53 +0800 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-01-19 16:17:29 +0000 |
commit | 4c9fbadcbd95c9d30eecdff43ed4f8d072bb7878 (patch) | |
tree | f462419308d56a419daeefe22167c2da29b3a1de | |
parent | 9020299e38c17642995f13a0fe8b09178f442d32 (diff) | |
download | vboot-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.c | 20 | ||||
-rw-r--r-- | futility/updater.h | 1 | ||||
-rw-r--r-- | futility/updater_quirks.c | 51 | ||||
-rw-r--r-- | futility/updater_utils.c | 17 | ||||
-rw-r--r-- | futility/updater_utils.h | 5 |
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(§ion, 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. |