diff options
-rw-r--r-- | futility/cmd_update.c | 119 | ||||
-rwxr-xr-x | tests/futility/test_update.sh | 10 |
2 files changed, 125 insertions, 4 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c index 8392c79e..33f71309 100644 --- a/futility/cmd_update.c +++ b/futility/cmd_update.c @@ -113,14 +113,28 @@ enum system_property_type { SYS_PROP_MAX }; +struct updater_config; +struct quirk_entry { + const char *name; + const char *help; + int (*apply)(struct updater_config *cfg); + int value; +}; + +enum quirk_types { + QUIRK_TEST, + QUIRK_MAX, +}; + struct updater_config { struct firmware_image image, image_current; struct firmware_image ec_image, pd_image; + struct system_property system_properties[SYS_PROP_MAX]; + struct quirk_entry quirks[QUIRK_MAX]; int try_update; int force_update; int legacy_update; int emulate; - struct system_property system_properties[SYS_PROP_MAX]; }; struct tempfile { @@ -466,6 +480,91 @@ static void override_properties_from_list(const char *override_list, } } +/* Gets the value (setting) of specified quirks from updater configuration. */ +static int get_config_quirk(enum quirk_types quirk, + const struct updater_config *cfg) +{ + assert(quirk < QUIRK_MAX); + return cfg->quirks[quirk].value; +} + +/* Prints the name and description from all supported quirks. */ +static void list_config_quirks(const struct updater_config *cfg) +{ + const struct quirk_entry *entry = cfg->quirks; + int i; + + printf("Supported quirks:\n"); + for (i = 0; i < QUIRK_MAX; i++, entry++) { + printf(" '%s': %s (default: %d)\n", entry->name, + entry->help ? entry->help : "(no description)", + get_config_quirk((enum quirk_types)i, cfg)); + } +} + +/* + * Applies a quirk if applicable (the value should be non-zero). + * Returns 0 on success, otherwise failure. + */ +static int try_apply_quirk(enum quirk_types quirk, struct updater_config *cfg) +{ + const struct quirk_entry *entry = cfg->quirks + quirk; + assert(quirk < QUIRK_MAX); + + if (!entry->value) + return 0; + + if (!entry->apply) { + ERROR("<%s> not implemented.", entry->name); + return -1; + } + DEBUG("Applying quirk <%s>.", entry->name); + return entry->apply(cfg); +} + +/* + * Initialize the updater_config quirks from a list of settings. + * Returns 0 on success, otherwise failure. + */ +static int setup_config_quirks(const char *quirks, struct updater_config *cfg) +{ + /* + * The list should be in NAME[=VALUE],... + * Value defaults to 1 if not specified. + */ + int r = 0; + char *buf = strdup(quirks); + char *token; + + token = strtok(buf, ", "); + for (; token; token = strtok(NULL, ", ")) { + const char *name = token; + char *equ = strchr(token, '='); + int i, value = 1; + struct quirk_entry *entry = cfg->quirks; + + if (equ) { + *equ = '\0'; + value = strtol(equ + 1, NULL, 0); + } + + DEBUG("Looking for quirk <%s=%d>.", name, value); + for (i = 0; i < QUIRK_MAX; i++, entry++) { + if (strcmp(name, entry->name)) + continue; + entry->value = value; + DEBUG("Set quirk %s to %d.", entry->name, value); + break; + } + if (i >= QUIRK_MAX) { + ERROR("Unknown quirk: %s", name); + r++; + } + } + free(buf); + return r; +} + /* * Finds a firmware section by given name in the firmware image. * If successful, return zero and *section argument contains the address and @@ -1545,6 +1644,8 @@ static struct option const long_opts[] = { {"ec_image", 1, NULL, 'e'}, {"pd_image", 1, NULL, 'P'}, {"try", 0, NULL, 't'}, + {"quirks", 1, NULL, 'f'}, + {"list-quirks", 0, NULL, 'L'}, {"mode", 1, NULL, 'm'}, {"force", 0, NULL, 'F'}, {"wp", 1, NULL, 'W'}, @@ -1567,6 +1668,8 @@ static void print_help(int argc, char *argv[]) "-e, --ec_image=FILE \tEC firmware image (i.e, ec.bin)\n" " --pd_image=FILE \tPD firmware image (i.e, pd.bin)\n" "-t, --try \tTry A/B update on reboot if possible\n" + " --quirks=LIST \tSpecify the quirks to apply\n" + " --list-quirks \tPrint all available quirks\n" "\n" "Legacy and compatibility options:\n" "-m, --mode=MODE \tRun updater in given mode\n" @@ -1590,9 +1693,6 @@ static int do_update(int argc, char *argv[]) .image_current = { .programmer = PROG_HOST, }, .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}, [SYS_PROP_TPM_FWVER] = {.getter = host_get_tpm_fwver}, @@ -1600,6 +1700,9 @@ static int do_update(int argc, char *argv[]) [SYS_PROP_WP_HW] = {.getter = host_get_wp_hw}, [SYS_PROP_WP_SW] = {.getter = host_get_wp_sw}, }, + .quirks = { + [QUIRK_TEST] = {.name="test", .help="Dummy quirk"}, + }, }; printf(">> Firmware updater started.\n"); @@ -1619,6 +1722,14 @@ static int do_update(int argc, char *argv[]) case 't': cfg.try_update = 1; break; + case 'f': + errorcnt += !!setup_config_quirks(optarg, &cfg); + break; + case 'L': + list_config_quirks(&cfg); + /* TODO(hungte): Remove this experimental quirk. */ + try_apply_quirk(QUIRK_TEST, &cfg); + return 0; case 'm': if (strcmp(optarg, "autoupdate") == 0) { cfg.try_update = 1; diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 0f3fafc7..8cba724b 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -19,6 +19,16 @@ test "$(test_sys_props "1, 2,3 ")" = "0,1, 1,2, 2,3, " test "$(test_sys_props " 1,, 2")" = "0,1, 2,2, " test "$(test_sys_props " , 4,")" = "1,4, " +test_quirks() { + ! "${FUTILITY}" --debug update --quirks "$*" | + sed -n 's/.*Set quirk \(.*\) to \(.*\)./\1,\2/p' | + tr '\n' ' ' +} + +test "$(test_quirks "test")" = "test,1 " +test "$(test_quirks "test=2")" = "test,2 " +test "$(test_quirks " test, test=2")" = "test,1 test,2 " + # Test data files LINK_BIOS="${SCRIPTDIR}/data/bios_link_mp.bin" PEPPY_BIOS="${SCRIPTDIR}/data/bios_peppy_mp.bin" |