diff options
author | Hung-Te Lin <hungte@chromium.org> | 2018-08-21 23:09:57 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-09-05 09:15:17 -0700 |
commit | 7fbbf2df700d0ab8f984114d535445c16a3d9699 (patch) | |
tree | 2ea75b9ac1fd2af10a8712ff1ade23067b6446f5 | |
parent | 483fcf08acb9ad9bbedbb5f980314144260d5da4 (diff) | |
download | vboot-7fbbf2df700d0ab8f984114d535445c16a3d9699.tar.gz |
futility: cmd_update: Check contents before starting to update
In try-boot updating flow, we have to first check if RO content needs to be
changed or not, and do full (ro+ro) update if WP is disabled. Also, before
starting to update RW-A or RW-B, we should also check if the active system
already has same firmware contents.
An --force is also added to allow skipping the check.
BUG=chromium:875551
TEST=make futil; tests/futility/run_test_scripts.sh $(pwd)/build/futility
BRANCH=None
Change-Id: Ie2f75f9aab4696c75aedafbf45e418ee98a2a4b4
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1183654
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | futility/cmd_update.c | 90 | ||||
-rwxr-xr-x | tests/futility/test_update.sh | 4 |
2 files changed, 86 insertions, 8 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c index 13569570..9172763a 100644 --- a/futility/cmd_update.c +++ b/futility/cmd_update.c @@ -22,6 +22,7 @@ /* FMAP section names. */ static const char * const FMAP_RO_FRID = "RO_FRID", + * const FMAP_RO_SECTION = "RO_SECTION", * const FMAP_RO_GBB = "GBB", * const FMAP_RO_VPD = "RO_VPD", * const FMAP_RW_VPD = "RW_VPD", @@ -97,6 +98,7 @@ struct updater_config { struct firmware_image image, image_current; struct firmware_image ec_image, pd_image; int try_update; + int force_update; int emulate; struct system_property system_properties[SYS_PROP_MAX]; }; @@ -737,6 +739,43 @@ static int preserve_images(struct updater_config *cfg) } /* + * Compares if two sections have same size and data. + * Returns 0 if given sections are the same, otherwise non-zero. + */ +static int compare_section(const struct firmware_section *a, + const struct firmware_section *b) +{ + if (a->size != b->size) + return a->size - b->size; + return memcmp(a->data, b->data, a->size); +} + +/* + * Returns if the images are different (should be updated) in given section. + * If the section contents are the same or if the section does not exist on both + * images, return value is 0 (no need to update). Otherwise the return value is + * non-zero, indicating an update should be performed. + * If section_name is NULL, compare whole images. + */ +static int section_needs_update(const struct firmware_image *image_from, + const struct firmware_image *image_to, + const char *section_name) +{ + struct firmware_section from, to; + + if (!section_name) { + if (image_from->size != image_to->size) + return -1; + return memcmp(image_from->data, image_to->data, image_to->size); + } + + find_firmware_section(&from, image_from, section_name); + find_firmware_section(&to, image_to, section_name); + + return compare_section(&from, &to); +} + +/* * Returns true if the write protection is enabled on current system. */ static int is_write_protection_enabled(struct updater_config *cfg) @@ -757,6 +796,7 @@ enum updater_error_codes { UPDATE_ERR_NEED_RO_UPDATE, UPDATE_ERR_NO_IMAGE, UPDATE_ERR_SYSTEM_IMAGE, + UPDATE_ERR_INVALID_IMAGE, UPDATE_ERR_SET_COOKIES, UPDATE_ERR_WRITE_FIRMWARE, UPDATE_ERR_TARGET, @@ -768,9 +808,10 @@ static const char * const updater_error_messages[] = { [UPDATE_ERR_NEED_RO_UPDATE] = "RO changed and no WP. Need full update.", [UPDATE_ERR_NO_IMAGE] = "No image to update; try specify with -i.", [UPDATE_ERR_SYSTEM_IMAGE] = "Cannot load system active firmware.", + [UPDATE_ERR_INVALID_IMAGE] = "The given firmware image is not valid.", [UPDATE_ERR_SET_COOKIES] = "Failed writing system flags to try update.", [UPDATE_ERR_WRITE_FIRMWARE] = "Failed writing firmware.", - [UPDATE_ERR_TARGET] = "Cannot find target section to update.", + [UPDATE_ERR_TARGET] = "No valid RW target to update. Abort.", [UPDATE_ERR_UNKNOWN] = "Unknown error.", }; @@ -787,18 +828,43 @@ static enum updater_error_codes update_try_rw_firmware( int wp_enabled) { const char *target; + int has_update = 1; + + preserve_gbb(image_from, image_to); + if (!wp_enabled && section_needs_update( + image_from, image_to, FMAP_RO_SECTION)) + return UPDATE_ERR_NEED_RO_UPDATE; /* TODO(hungte): Support vboot1. */ - target = decide_rw_target(cfg, TARGET_UPDATE); - if (!target) { + target = decide_rw_target(cfg, TARGET_SELF); + if (target == NULL) { Error("TRY-RW update needs system to boot in RW firmware.\n"); return UPDATE_ERR_TARGET; } - printf(">> TRY-RW UPDATE: Updating %s to try on reboot.\n", target); - if (write_firmware(cfg, image_to, target)) - return UPDATE_ERR_WRITE_FIRMWARE; - if (set_try_cookies(cfg, target)) - return UPDATE_ERR_SET_COOKIES; + + printf("Checking %s contents...\n", target); + if (!firmware_section_exists(image_to, target)) { + Error("Cannot find section '%s' on firmware image: %s\n", + target, image_to->file_name); + return UPDATE_ERR_INVALID_IMAGE; + } + if (!cfg->force_update) + has_update = section_needs_update(image_from, image_to, target); + + if (has_update) { + target = decide_rw_target(cfg, TARGET_UPDATE); + printf(">> TRY-RW UPDATE: Updating %s to try on reboot.\n", + target); + + if (write_firmware(cfg, image_to, target)) + return UPDATE_ERR_WRITE_FIRMWARE; + if (set_try_cookies(cfg, target)) + return UPDATE_ERR_SET_COOKIES; + } + + /* TODO(hungte): Add optional checks here that may change has_update. */ + if (!has_update) + printf(">> No need to update.\n"); return UPDATE_ERR_DONE; } @@ -928,6 +994,7 @@ static struct option const long_opts[] = { {"ec_image", 1, NULL, 'e'}, {"pd_image", 1, NULL, 'P'}, {"try", 0, NULL, 't'}, + {"force", 0, NULL, 'F'}, {"wp", 1, NULL, 'W'}, {"emulate", 1, NULL, 'E'}, {"sys_props", 1, NULL, 'S'}, @@ -947,6 +1014,9 @@ static void print_help(int argc, char *argv[]) " --pd_image=FILE \tPD firmware image (i.e, pd.bin)\n" "-t, --try \tTry A/B update on reboot if possible\n" "\n" + "Legacy and compatibility options:\n" + " --force \tForce update (skip checking contents)\n" + "\n" "Debugging and testing options:\n" " --wp=1|0 \tSpecify write protection status\n" " --emulate=FILE \tEmulate system firmware using file\n" @@ -964,6 +1034,7 @@ static int do_update(int argc, char *argv[]) .ec_image = { .programmer = PROG_EC, }, .pd_image = { .programmer = PROG_PD, }, .try_update = 0, + .force_update = 0, .emulate = 0, .system_properties = { [SYS_PROP_MAINFW_ACT] = {.getter = host_get_mainfw_act}, @@ -1004,6 +1075,9 @@ static int do_update(int argc, char *argv[]) cfg.image_current.emulation); } break; + case 'F': + cfg.force_update = 1; + break; case 'S': override_properties_from_list(optarg, &cfg); break; diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 43de6a0e..bc2a2ec9 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -99,3 +99,7 @@ test_update "RW update (A->B)" \ test_update "RW update (B->A)" \ "${FROM_IMAGE}" "${TMP}.expected.a" \ -i "${TO_IMAGE}" -t --wp=1 --sys_props 1 + +test_update "RW update -> fallback to RO+RW Full update" \ + "${FROM_IMAGE}" "${TMP}.expected.full" \ + -i "${TO_IMAGE}" -t --wp=0 --sys_props 1 |