summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2018-10-15 14:57:34 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-10-22 06:16:35 -0700
commit92fe37cef28d58f6d64c625b30e72fab99ff42a5 (patch)
treeb9ed716ec51119af8d8555e7589931201cfa0d94
parent4d4c36e9df592548ae169cf6f145ecc9399a7963 (diff)
downloadvboot-92fe37cef28d58f6d64c625b30e72fab99ff42a5.tar.gz
futility: updater: Add '--model' and select images by system model
For devices using Unified Build, we have to select and load images from archive by model configuration (setvars.sh). The system model can be retrieved by $(mosys platform model), but for developers who want to simulate or get images for particular platform, a command line argument --model is needed. BUG=chromium:875551 TEST=TEST=make futil; tests/futility/run_test_scripts.sh $(pwd)/build/futility BRANCH=None Change-Id: I8f4a6735b34bc694a05808b001c7309623b2afa3 Signed-off-by: Hung-Te Lin <hungte@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1278419 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--futility/cmd_update.c11
-rw-r--r--futility/updater.c91
-rw-r--r--futility/updater.h23
-rw-r--r--futility/updater_archive.c50
-rwxr-xr-xtests/futility/models/link/setvars.sh14
-rwxr-xr-xtests/futility/models/peppy/setvars.sh14
-rwxr-xr-xtests/futility/test_update.sh38
7 files changed, 206 insertions, 35 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index f382b9ca..ce81660d 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -26,6 +26,7 @@ static struct option const long_opts[] = {
{"quirks", 1, NULL, 'f'},
{"list-quirks", 0, NULL, 'L'},
{"mode", 1, NULL, 'm'},
+ {"model", 1, NULL, 'M'},
{"manifest", 0, NULL, 'A'},
{"factory", 0, NULL, 'Y'},
{"force", 0, NULL, 'F'},
@@ -64,6 +65,7 @@ static void print_help(int argc, char *argv[])
"Debugging and testing options:\n"
" --wp=1|0 \tSpecify write protection status\n"
" --emulate=FILE \tEmulate system firmware using file\n"
+ " --model=MODEL \tOverride system model for images\n"
" --sys_props=LIST\tList of system properties to override\n"
"-d, --debug \tPrint debugging messages\n"
"-v, --verbose \tPrint verbose messages\n"
@@ -75,7 +77,7 @@ static int do_update(int argc, char *argv[])
{
struct updater_config *cfg;
struct updater_config_arguments args = {0};
- int i, errorcnt = 0;
+ int i, errorcnt = 0, do_update = 1;
fprintf(stderr, ">> Firmware updater started.\n");
cfg = updater_new_config();
@@ -108,6 +110,9 @@ static int do_update(int argc, char *argv[])
case 'm':
args.mode = optarg;
break;
+ case 'M':
+ args.model = optarg;
+ break;
case 'A':
args.do_manifest = 1;
break;
@@ -160,8 +165,8 @@ static int do_update(int argc, char *argv[])
Error("Unexpected arguments.\n");
}
if (!errorcnt)
- errorcnt += updater_setup_config(cfg, &args);
- if (!errorcnt && !args.do_manifest) {
+ errorcnt += updater_setup_config(cfg, &args, &do_update);
+ if (!errorcnt && do_update) {
int r = update_firmware(cfg);
if (r != UPDATE_ERR_DONE) {
r = Min(r, UPDATE_ERR_UNKNOWN);
diff --git a/futility/updater.c b/futility/updater.c
index 5cd29f4a..17b12a2b 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -630,7 +630,8 @@ int load_firmware_image(struct firmware_image *image, const char *file_name,
* Loads the active system firmware image (usually from SPI flash chip).
* Returns 0 if success, non-zero if error.
*/
-int load_system_firmware(struct updater_config *cfg, struct firmware_image *image)
+int load_system_firmware(struct updater_config *cfg,
+ struct firmware_image *image)
{
const char *tmp_file = updater_create_temp_file(cfg);
@@ -1667,17 +1668,47 @@ static int updater_load_images(struct updater_config *cfg,
}
/*
+ * Setup what the updater has to do against an archive.
+ * Returns number of failures, or 0 on success.
+ */
+static int updater_setup_archive(
+ struct updater_config *cfg,
+ const struct updater_config_arguments *arg,
+ struct manifest *manifest)
+{
+ int errorcnt = 0;
+ struct archive *ar = cfg->archive;
+ const struct model_config *model;
+
+ if (arg->do_manifest) {
+ assert(!arg->image);
+ print_json_manifest(manifest);
+ /* No additional error. */
+ return errorcnt;
+ }
+
+ model = manifest_find_model(manifest, arg->model);
+ if (!model)
+ return ++errorcnt;
+
+ errorcnt += updater_load_images(
+ cfg, model->image, model->ec_image, model->pd_image);
+ errorcnt += patch_image_by_model(&cfg->image, model, ar);
+ return errorcnt;
+}
+
+/*
* Helper function to setup an allocated updater_config object.
* Returns number of failures, or 0 on success.
*/
int updater_setup_config(struct updater_config *cfg,
- const struct updater_config_arguments *arg)
+ const struct updater_config_arguments *arg,
+ int *do_update)
{
int errorcnt = 0;
int check_single_image = 0, check_wp_disabled = 0;
const char *default_quirks = NULL;
const char *archive_path = arg->archive;
- struct manifest *manifest = NULL;
/* Setup values that may change output or decision of other argument. */
cfg->verbosity = arg->verbosity;
@@ -1686,9 +1717,17 @@ int updater_setup_config(struct updater_config *cfg,
cfg->force_update = 1;
/* Check incompatible options and return early. */
- if (arg->do_manifest && !arg->archive) {
- ERROR("Manifest is only available for archive.");
- return ++errorcnt;
+ if (arg->do_manifest) {
+ if (!!arg->archive == !!arg->image) {
+ ERROR("--manifest needs either -a or -i");
+ return ++errorcnt;
+ }
+ if (arg->archive && (arg->ec_image || arg->pd_image)) {
+ ERROR("--manifest for archive (-a) does not accept "
+ "additional images (--ec_image, --pd_image).");
+ return ++errorcnt;
+ }
+ *do_update = 0;
}
/* Setup update mode. */
@@ -1740,6 +1779,11 @@ int updater_setup_config(struct updater_config *cfg,
errorcnt += !!load_firmware_image(
&cfg->image_current, arg->emulation, NULL);
}
+
+ /* Always load images specified from command line directly. */
+ errorcnt += updater_load_images(
+ cfg, arg->image, arg->ec_image, arg->pd_image);
+
if (!archive_path)
archive_path = ".";
cfg->archive = archive_open(archive_path);
@@ -1748,17 +1792,30 @@ int updater_setup_config(struct updater_config *cfg,
return ++errorcnt;
}
- errorcnt += updater_load_images(
- cfg, arg->image, arg->ec_image, arg->pd_image);
-
- if (arg->do_manifest) {
- manifest = new_manifest_from_archive(cfg->archive);
- if (!manifest) {
- ERROR("Failure in archive: %s", archive_path);
- return ++errorcnt;
+ /* Load images from archive. */
+ if (arg->archive) {
+ struct manifest *m = new_manifest_from_archive(cfg->archive);
+ if (m) {
+ errorcnt += updater_setup_archive(cfg, arg, m);
+ delete_manifest(m);
+ } else {
+ ERROR("Failure in archive: %s", arg->archive);
+ ++errorcnt;
}
- print_json_manifest(manifest);
- return errorcnt;
+ } else if (arg->do_manifest) {
+ char name[] = "default";
+ struct model_config model = {
+ .name = name,
+ .image = arg->image,
+ .ec_image = arg->ec_image,
+ .pd_image = arg->pd_image,
+ };
+ struct manifest manifest = {
+ .num = 1,
+ .models = &model,
+ };
+ assert(model.image);
+ print_json_manifest(&manifest);
}
/*
@@ -1781,8 +1838,6 @@ int updater_setup_config(struct updater_config *cfg,
errorcnt++;
ERROR("Factory mode needs WP disabled.");
}
- if (manifest)
- delete_manifest(manifest);
return errorcnt;
}
diff --git a/futility/updater.h b/futility/updater.h
index 21bdbdb5..c1405663 100644
--- a/futility/updater.h
+++ b/futility/updater.h
@@ -135,10 +135,10 @@ struct model_config {
struct manifest {
int num;
- int default_model;
- int has_keyset;
struct model_config *models;
struct archive *archive;
+ int default_model;
+ int has_keyset;
};
enum updater_error_codes {
@@ -183,7 +183,8 @@ void updater_delete_config(struct updater_config *cfg);
* Returns number of failures, or 0 on success.
*/
int updater_setup_config(struct updater_config *cfg,
- const struct updater_config_arguments *arg);
+ const struct updater_config_arguments *arg,
+ int *do_update);
/* Prints the name and description from all supported quirks. */
void updater_list_config_quirks(const struct updater_config *cfg);
@@ -307,4 +308,20 @@ void delete_manifest(struct manifest *manifest);
/* Prints the information of objects in manifest (models and images) in JSON. */
void print_json_manifest(const struct manifest *manifest);
+/*
+ * Modifies a firmware image from patch information specified in model config.
+ * Returns 0 on success, otherwise number of failures.
+ */
+int patch_image_by_model(
+ struct firmware_image *image, const struct model_config *model,
+ struct archive *archive);
+
+/*
+ * Finds the existing model_config from manifest that best matches current
+ * system (as defined by model_name).
+ * Returns a model_config from manifest, or NULL if not found.
+ */
+const struct model_config *manifest_find_model(const struct manifest *manifest,
+ const char *model_name);
+
#endif /* VBOOT_REFERENCE_FUTILITY_UPDATER_H_ */
diff --git a/futility/updater_archive.c b/futility/updater_archive.c
index 86d70e75..e08f736a 100644
--- a/futility/updater_archive.c
+++ b/futility/updater_archive.c
@@ -65,6 +65,7 @@ static const char * const SETVARS_IMAGE_MAIN = "IMAGE_MAIN",
* const DIR_KEYSET = "keyset",
* const DIR_MODELS = "models",
* const DEFAULT_MODEL_NAME = "default",
+ * const ENV_VAR_MODEL_DIR = "${MODEL_DIR}",
* const PATH_STARTSWITH_KEYSET = "keyset/",
* const PATH_ENDSWITH_SERVARS = "/setvars.sh";
@@ -418,6 +419,9 @@ static int model_config_parse_setvars_file(
for (line = strtok_r((char *)data, "\n\r", &ptr_line); line;
line = strtok_r(NULL, "\n\r", &ptr_line)) {
+ char *expand_path = NULL;
+ int found_valid = 1;
+
/* Format: KEY="value" */
k = strtok_r(line, "=", &ptr_token);
if (!k)
@@ -426,6 +430,12 @@ static int model_config_parse_setvars_file(
if (!v)
continue;
+ /* Some legacy updaters may be still using ${MODEL_DIR}. */
+ if (str_startswith(v, ENV_VAR_MODEL_DIR)) {
+ ASPRINTF(&expand_path, "%s%s%s", "models/", cfg->name,
+ v + strlen(ENV_VAR_MODEL_DIR));
+ }
+
if (strcmp(k, SETVARS_IMAGE_MAIN) == 0)
cfg->image = strdup(v);
else if (strcmp(k, SETVARS_IMAGE_EC) == 0)
@@ -435,8 +445,9 @@ static int model_config_parse_setvars_file(
else if (strcmp(k, SETVARS_SIGNATURE_ID) == 0)
cfg->signature_id = strdup(v);
else
- continue;
- valid++;
+ found_valid = 0;
+ free(expand_path);
+ valid += found_valid;
}
free(data);
return valid == 0;
@@ -524,7 +535,7 @@ static int apply_key_file(
* Modifies a firmware image from patch information specified in model config.
* Returns 0 on success, otherwise number of failures.
*/
-static int patch_image_by_model(
+int patch_image_by_model(
struct firmware_image *image, const struct model_config *model,
struct archive *archive)
{
@@ -646,6 +657,39 @@ static int manifest_scan_entries(const char *name, void *arg)
}
/*
+ * Finds the existing model_config from manifest that best matches current
+ * system (as defined by model_name).
+ * Returns a model_config from manifest, or NULL if not found.
+ */
+const struct model_config *manifest_find_model(const struct manifest *manifest,
+ const char *model_name)
+{
+ char *sys_model_name = NULL;
+ const struct model_config *model = NULL;
+ int i;
+
+ /* Match if the manifest has only one package without signature. */
+ if (manifest->num == 1 && !manifest->models[0].signature_id)
+ model = &manifest->models[0];
+
+ if (!model && !model_name) {
+ sys_model_name = host_shell("mosys platform name");
+ DEBUG("System model name: '%s'", sys_model_name);
+ model_name = sys_model_name;
+ }
+
+ for (i = 0; !model && i < manifest->num; i++) {
+ if (strcmp(model_name, manifest->models[i].name) == 0)
+ model = &manifest->models[i];
+ }
+ if (!model)
+ ERROR("Model '%s' is not defined in manifest.", model_name);
+
+ free(sys_model_name);
+ return model;
+}
+
+/*
* Creates a new manifest object by scanning files in archive.
* Returns the manifest on success, otherwise NULL for failure.
*/
diff --git a/tests/futility/models/link/setvars.sh b/tests/futility/models/link/setvars.sh
new file mode 100755
index 00000000..19180998
--- /dev/null
+++ b/tests/futility/models/link/setvars.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a template file which provides settings for firmware update of a
+# particular model. The pack_firmware.py script uses this to create a working
+# setvars-model.sh script.
+
+# Image and key files for model link
+IMAGE_MAIN="images/bios_link.bin"
+IMAGE_EC="images/ec_link.bin"
+IMAGE_PD=""
+SIGNATURE_ID="link"
diff --git a/tests/futility/models/peppy/setvars.sh b/tests/futility/models/peppy/setvars.sh
new file mode 100755
index 00000000..855e815a
--- /dev/null
+++ b/tests/futility/models/peppy/setvars.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Copyright 2017 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a template file which provides settings for firmware update of a
+# particular model. The pack_firmware.py script uses this to create a working
+# setvars-model.sh script.
+
+# Image and key files for model peppy
+IMAGE_MAIN="images/bios_peppy.bin"
+IMAGE_EC="images/ec_peppy.bin"
+IMAGE_PD=""
+SIGNATURE_ID="peppy"
diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh
index 6bb627c8..32fe921e 100755
--- a/tests/futility/test_update.sh
+++ b/tests/futility/test_update.sh
@@ -294,17 +294,39 @@ test_update "Full update (--quirks min_platform_version)" \
--quirks min_platform_version=3 \
-i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,1,3
-mkdir -p "${TMP}.archive"
-cp -f "${LINK_BIOS}" "${TMP}.archive/bios.bin"
-cp -f "${TO_IMAGE}" "${TMP}.archive/image_in_archive"
-test_update "Full update (--archive)" \
- "${FROM_IMAGE}" "${TMP}.expected.full" \
- -a "${TMP}.archive" \
- -i "image_in_archive" --wp=0 --sys_props 0,0x10001,1,3
+# Test archive and manifest.
+A="${TMP}.archive"
+mkdir -p "${A}"
+cp -f "${LINK_BIOS}" "${A}/bios.bin"
echo "TEST: Manifest (--manifest)"
-${FUTILITY} update -a "${TMP}.archive" --manifest >"${TMP}.json.out"
+${FUTILITY} update -a "${A}" --manifest >"${TMP}.json.out"
cmp "${TMP}.json.out" "${SCRIPTDIR}/link.manifest.json"
+cp -f "${TO_IMAGE}" "${A}/bios.bin"
+test_update "Full update (--archive, single package)" \
+ "${FROM_IMAGE}" "${TMP}.expected.full" \
+ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3
+
+rm -f "${A}/bios.bin"
+cp -r "${SCRIPTDIR}/models" "${A}/"
+mkdir -p "${A}/images"
+cp -f "${PEPPY_BIOS}" "${A}/images/bios_peppy.bin"
+cp -f "${LINK_BIOS}" "${A}/images/bios_link.bin"
+
+cp -f "${PEPPY_BIOS}" "${FROM_IMAGE}.ap"
+cp -f "${LINK_BIOS}" "${FROM_IMAGE}.al"
+patch_file ${FROM_IMAGE}.ap FW_MAIN_A 0 "corrupted"
+patch_file ${FROM_IMAGE}.al FW_MAIN_A 0 "corrupted"
+test_update "Full update (--archive, model=link)" \
+ "${FROM_IMAGE}.al" "${LINK_BIOS}" \
+ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=link
+test_update "Full update (--archive, model=peppy)" \
+ "${FROM_IMAGE}.ap" "${PEPPY_BIOS}" \
+ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=peppy
+test_update "Full update (--archive, model=unknown)" \
+ "${FROM_IMAGE}.ap" "!Model 'unknown' is not defined" \
+ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=unknown
+
# Test special programmer
if type flashrom >/dev/null 2>&1; then
echo "TEST: Full update (dummy programmer)"