summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)"