summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2018-08-21 23:09:57 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-09-05 09:15:17 -0700
commit7fbbf2df700d0ab8f984114d535445c16a3d9699 (patch)
tree2ea75b9ac1fd2af10a8712ff1ade23067b6446f5
parent483fcf08acb9ad9bbedbb5f980314144260d5da4 (diff)
downloadvboot-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.c90
-rwxr-xr-xtests/futility/test_update.sh4
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