summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2018-08-21 18:57:19 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-08-31 05:22:47 -0700
commitc1f9b056a3a7f15f33581a0cf6ae3bf5af828e7a (patch)
tree2b2ef9f06bade39468c51ce6dd0e2381ba0ac913
parent677b535dda16fe8662d646860ff84b1ed744d902 (diff)
downloadvboot-stabilize-atlas-11022.B.tar.gz
futility: cmd_update: Implement updater logic "FULL UPDATE".stabilize-atlas-11022.B
The logic is same as --mode=factory or --mode=recovery,--wp=0 in legacy firmware updater. BUG=chromium:875551 TEST=make futil; futility update -i IMAGE tests/futility/run_test_scripts.sh $(pwd)/build/futility BRANCH=None Change-Id: Ifbfc4fb76f954483e779c8b508377d07561b67da Signed-off-by: Hung-Te Lin <hungte@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1183651 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--futility/cmd_update.c155
-rwxr-xr-xtests/futility/test_update.sh38
2 files changed, 179 insertions, 14 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index a3ca288f..a6727f05 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -270,10 +270,141 @@ static void free_image(struct firmware_image *image)
memset(image, 0, sizeof(*image));
}
+/*
+ * Emulates writing to firmware.
+ * Returns 0 if success, non-zero if error.
+ */
+static int emulate_write_firmware(const char *filename,
+ const struct firmware_image *image,
+ const char *section_name)
+{
+ struct firmware_image to_image = {0};
+ struct firmware_section from, to;
+ int errorcnt = 0;
+
+ from.data = image->data;
+ from.size = image->size;
+
+ if (load_image(filename, &to_image)) {
+ Error("%s: Cannot load image from %s.\n", __FUNCTION__,
+ filename);
+ return -1;
+ }
+
+ if (section_name) {
+ find_firmware_section(&from, image, section_name);
+ if (!from.data) {
+ Error("%s: No section %s in source image %s.\n",
+ __FUNCTION__, section_name, image->file_name);
+ errorcnt++;
+ }
+ find_firmware_section(&to, &to_image, section_name);
+ if (!to.data) {
+ Error("%s: No section %s in destination image %s.\n",
+ __FUNCTION__, section_name, filename);
+ errorcnt++;
+ }
+ } else if (image->size != to_image.size) {
+ Error("%s: Image size is different (%s:%d != %s:%d)\n",
+ __FUNCTION__, image->file_name, image->size,
+ to_image.file_name, to_image.size);
+ errorcnt++;
+ } else {
+ to.data = to_image.data;
+ to.size = to_image.size;
+ }
+
+ if (!errorcnt) {
+ size_t to_write = Min(to.size, from.size);
+
+ assert(from.data && to.data);
+ Debug("%s: Writing %d bytes\n", __FUNCTION__, to_write);
+ memcpy(to.data, from.data, to_write);
+ }
+
+ if (!errorcnt && vb2_write_file(
+ filename, to_image.data, to_image.size)) {
+ Error("%s: Failed writing to file: %s\n", __FUNCTION__,
+ filename);
+ errorcnt++;
+ }
+
+ free_image(&to_image);
+ return errorcnt;
+}
+
+/*
+ * Writes a section from given firmware image to system firmware.
+ * If section_name is NULL, write whole image.
+ * Returns 0 if success, non-zero if error.
+ */
+static int write_firmware(struct updater_config *cfg,
+ const struct firmware_image *image,
+ const char *section_name)
+{
+ /* TODO(hungte) replace by mkstemp */
+ const char *tmp_file = "/tmp/.fwupdate.write";
+ const char *programmer = cfg->emulate ? image->emulation :
+ image->programmer;
+
+ if (cfg->emulate) {
+ printf("%s: (emulation) %s %s from %s to %s.\n",
+ __FUNCTION__,
+ image->emulation ? "Writing" : "Skipped writing",
+ section_name ? section_name : "whole image",
+ image->file_name, programmer);
+
+ if (!image->emulation)
+ return 0;
+
+ /*
+ * TODO(hungte): Extract the real target from image->emulation,
+ * and allow to emulate writing with flashrom.
+ */
+ return emulate_write_firmware(
+ cfg->image_current.file_name, image,
+ section_name);
+
+ }
+ if (vb2_write_file(tmp_file, image->data, image->size) != VB2_SUCCESS) {
+ Error("%s: Cannot write temporary file for output: %s\n",
+ __FUNCTION__, tmp_file);
+ return -1;
+ }
+ return host_flashrom(FLASHROM_WRITE, tmp_file, programmer, 1,
+ section_name);
+}
+
+/*
+ * Write a section from given firmware image to system firmware if possible.
+ * If section_name is NULL, write whole image. If the image has no data or if
+ * the section does not exist, ignore and return success.
+ * Returns 0 if success, non-zero if error.
+ */
+static int write_optional_firmware(struct updater_config *cfg,
+ const struct firmware_image *image,
+ const char *section_name)
+{
+ if (!image->data) {
+ Debug("%s: No data in <%s> image.\n", __FUNCTION__,
+ image->programmer);
+ return 0;
+ }
+ if (section_name && !firmware_section_exists(image, section_name)) {
+ Debug("%s: Image %s<%s> does not have section %s.\n",
+ __FUNCTION__, image->file_name, image->programmer,
+ section_name);
+ return 0;
+ }
+
+ return write_firmware(cfg, image, section_name);
+}
+
enum updater_error_codes {
UPDATE_ERR_DONE,
UPDATE_ERR_NO_IMAGE,
UPDATE_ERR_SYSTEM_IMAGE,
+ UPDATE_ERR_WRITE_FIRMWARE,
UPDATE_ERR_UNKNOWN,
};
@@ -281,10 +412,32 @@ static const char * const updater_error_messages[] = {
[UPDATE_ERR_DONE] = "Done (no error)",
[UPDATE_ERR_NO_IMAGE] = "No image to update; try specify with -i.",
[UPDATE_ERR_SYSTEM_IMAGE] = "Cannot load system active firmware.",
+ [UPDATE_ERR_WRITE_FIRMWARE] = "Failed writing firmware.",
[UPDATE_ERR_UNKNOWN] = "Unknown error.",
};
/*
+ * The main updater for "Full update".
+ * This was also known as "--mode=factory" or "--mode=recovery, --wp=0" in
+ * legacy updater.
+ * Returns UPDATE_ERR_DONE if success, otherwise error.
+ */
+static enum updater_error_codes update_whole_firmware(
+ struct updater_config *cfg,
+ struct firmware_image *image_to)
+{
+ printf(">> FULL UPDATE: Updating whole firmware image(s), RO+RW.\n");
+
+ /* FMAP may be different so we should just update all. */
+ if (write_firmware(cfg, image_to, NULL) ||
+ write_optional_firmware(cfg, &cfg->ec_image, NULL) ||
+ write_optional_firmware(cfg, &cfg->pd_image, NULL))
+ return UPDATE_ERR_WRITE_FIRMWARE;
+
+ return UPDATE_ERR_DONE;
+}
+
+/*
* The main updater to update system firmware using the configuration parameter.
* Returns UPDATE_ERR_DONE if success, otherwise failure.
*/
@@ -312,7 +465,7 @@ static enum updater_error_codes update_firmware(struct updater_config *cfg)
image_from->file_name, image_from->ro_version,
image_from->rw_version_a, image_from->rw_version_b);
- return UPDATE_ERR_DONE;
+ return update_whole_firmware(cfg, image_to);
}
/*
diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh
index c130a56c..7e2a142d 100755
--- a/tests/futility/test_update.sh
+++ b/tests/futility/test_update.sh
@@ -6,25 +6,37 @@
me=${0##*/}
TMP="$me.tmp"
-# Include /usr/sbin for flahsrom(8)
-PATH=/usr/sbin:"${PATH}"
-
# Test data files
LINK_BIOS="${SCRIPTDIR}/data/bios_link_mp.bin"
PEPPY_BIOS="${SCRIPTDIR}/data/bios_peppy_mp.bin"
-LINK_VERSION="Google_Link.2695.1.133"
-PEPPY_VERSION="Google_Peppy.4389.89.0"
# Work in scratch directory
cd "$OUTDIR"
set -o pipefail
-# Prepare temporary files.
-cp -f "${LINK_BIOS}" "${TMP}.emu"
+# In all the test scenario, we want to test "updating from PEPPY to LINK".
+TO_IMAGE=${TMP}.src.link
+FROM_IMAGE=${TMP}.src.peppy
+cp -f ${LINK_BIOS} ${TO_IMAGE}
+cp -f ${PEPPY_BIOS} ${FROM_IMAGE}
+
+cp -f "${TO_IMAGE}" "${TMP}.expected.full"
+
+test_update() {
+ local test_name="$1"
+ local emu_src="$2"
+ local expected="$3"
+ local error_msg="${expected#!}"
+ local msg
+
+ shift 3
+ cp -f "${emu_src}" "${TMP}.emu"
+ echo "*** Test Item: ${test_name}"
+ "${FUTILITY}" update --emulate "${TMP}.emu" "$@"
+ cmp "${TMP}.emu" "${expected}"
+}
-# Test command execution.
-versions="$("${FUTILITY}" update -i "${PEPPY_BIOS}" --emulate "${TMP}.emu" |
- sed -n 's/.*(//; s/).*//p')"
-test "${versions}" = \
-"RO:${PEPPY_VERSION}, RW/A:${PEPPY_VERSION}, RW/B:${PEPPY_VERSION}
-RO:${LINK_VERSION}, RW/A:${LINK_VERSION}, RW/B:${LINK_VERSION}"
+# Test Full update.
+test_update "Full update" \
+ "${FROM_IMAGE}" "${TMP}.expected.full" \
+ -i "${TO_IMAGE}"