summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2018-08-24 11:52:21 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-08-31 11:19:58 -0700
commitd7d098dfc83c8ae7dd09f07738d22bd8f506a049 (patch)
tree12319a0dd684a69c8859f85d1c10de8812d8851e
parentc1f9b056a3a7f15f33581a0cf6ae3bf5af828e7a (diff)
downloadvboot-d7d098dfc83c8ae7dd09f07738d22bd8f506a049.tar.gz
futility: cmd_update: Add "system property" and '--sys_props' to override
When updating firmware, we may need to get some system environment status, like which firmware slot was selected and boot (active), or setting cookies so the next boot will be using right (updated) slot. In verified boot, these status are manipulated by "system property" using API Vb{Get,Set}SystemProperty{String,Int}. The user land tool is `crossystem`. In order to run the firmware updater for testing and debugging, we need an easy way to toggle getting real system status, or fetch from predefined values. A new 'system_property' structure is introduced and included as part of `updater_config`. Each property can be access by `get_system_property(property_type)` function. If the value was not fetched yet, the function will call corresponding 'getter' function defined in property and then cache it. A new parameter '--sys_props` is also introduced so we can easily override them from command line so the updater will not get status from running system. The --sys_props takes a list of integers, eliminated by space or comma. For example, "1,2,3" => overrides [0]=1, [1]=2, [2]=3. "1 2,3" => overrides [0]=1, [1]=2, [2]=3. "1, ,3" => overrides [0]=1, [2]=3. BUG=chromium:875551 TEST=make futil; futility update -i IMAGE tests/futility/run_test_scripts.sh $(pwd)/build/futility BRANCH=None Change-Id: Ia2e06a953da1480da9a94f7f397802caa7468efa Signed-off-by: Hung-Te Lin <hungte@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1188015
-rw-r--r--futility/cmd_update.c133
-rwxr-xr-xtests/futility/test_update.sh13
2 files changed, 146 insertions, 0 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index a6727f05..c6f70410 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -7,6 +7,7 @@
*/
#include <assert.h>
+#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
@@ -50,10 +51,25 @@ struct firmware_section {
size_t size;
};
+struct system_property {
+ int (*getter)();
+ int value;
+ int initialized;
+};
+
+enum system_property_type {
+ /* TODO(hungte) Remove SYS_PROP_TEST* when we have more properties. */
+ SYS_PROP_TEST1,
+ SYS_PROP_TEST2,
+ SYS_PROP_TEST3,
+ SYS_PROP_MAX
+};
+
struct updater_config {
struct firmware_image image, image_current;
struct firmware_image ec_image, pd_image;
int emulate;
+ struct system_property system_properties[SYS_PROP_MAX];
};
/*
@@ -120,6 +136,107 @@ static int host_flashrom(enum flashrom_ops op, const char *image_path,
}
/*
+ * Gets the system property by given type.
+ * If the property was not loaded yet, invoke the property getter function
+ * and cache the result.
+ * Returns the property value.
+ */
+static int get_system_property(enum system_property_type property_type,
+ struct updater_config *cfg)
+{
+ struct system_property *prop;
+
+ assert(property_type < SYS_PROP_MAX);
+ prop = &cfg->system_properties[property_type];
+ if (!prop->initialized) {
+ prop->initialized = 1;
+ prop->value = prop->getter();
+ }
+ return prop->value;
+}
+
+static void print_system_properties(struct updater_config *cfg)
+{
+ int i;
+
+ /*
+ * There may be error messages when fetching properties from active
+ * system, so we want to peek at them first and then print out.
+ */
+ Debug("Scanning system properties...\n");
+ for (i = 0; i < SYS_PROP_MAX; i++) {
+ get_system_property((enum system_property_type)i, cfg);
+ }
+
+ printf("System properties: [");
+ for (i = 0; i < SYS_PROP_MAX; i++) {
+ printf("%d,",
+ get_system_property((enum system_property_type)i, cfg));
+ }
+ printf("]\n");
+}
+
+/*
+ * Overrides the return value of a system property.
+ * After invoked, next call to get_system_property(type, cfg) will return
+ * the given value.
+ */
+static void override_system_property(enum system_property_type property_type,
+ struct updater_config *cfg,
+ int value)
+{
+ struct system_property *prop;
+
+ assert(property_type < SYS_PROP_MAX);
+ prop = &cfg->system_properties[property_type];
+ prop->initialized = 1;
+ prop->value = value;
+}
+
+/*
+ * Overrides system properties from a given list.
+ * The list should be string of integers eliminated by comma and/or space.
+ * For example, "1 2 3" and "1,2,3" both overrides first 3 properties.
+ * To skip some properties you have to use comma, for example
+ * "1, , 3" will only override the first and 3rd properties.
+ * Invalid characters and fields will be ignored.
+ *
+ * The current implementation is only for unit testing.
+ * In future we may extend this with name=value so users can use it easily on
+ * actual systems.
+ */
+static void override_properties_from_list(const char *override_list,
+ struct updater_config *cfg)
+{
+ const char *s = override_list;
+ char *e, c;
+ int i = 0, wait_comma = 0;
+ long int v;
+
+ Debug("%s: Input is <%s>\n", __FUNCTION__, override_list);
+ for (c = *s; c; c = *++s) {
+ if (c == ',') {
+ if (!wait_comma)
+ i++;
+ wait_comma = 0;
+ }
+ if (!isascii(c) || !isdigit(c))
+ continue;
+ if (i >= SYS_PROP_MAX) {
+ Error("%s: Too many fields (max is %d): %s.\n",
+ __FUNCTION__, SYS_PROP_MAX, override_list);
+ return;
+ }
+ v = strtol(s, &e, 0);
+ s = e - 1;
+ Debug("%s: property[%d].value = %d\n", __FUNCTION__, i, v);
+ override_system_property((enum system_property_type)i, cfg, v);
+ wait_comma = 1;
+ i++;
+ }
+}
+
+/*
* Finds a firmware section by given name in the firmware image.
* If successful, return zero and *section argument contains the address and
* size of the section; otherwise failure.
@@ -465,6 +582,9 @@ 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);
+ if (debugging_enabled)
+ print_system_properties(cfg);
+
return update_whole_firmware(cfg, image_to);
}
@@ -473,6 +593,11 @@ static enum updater_error_codes update_firmware(struct updater_config *cfg)
*/
static void unload_updater_config(struct updater_config *cfg)
{
+ int i;
+ for (i = 0; i < SYS_PROP_MAX; i++) {
+ cfg->system_properties[i].initialized = 0;
+ cfg->system_properties[i].value = 0;
+ }
free_image(&cfg->image);
free_image(&cfg->image_current);
free_image(&cfg->ec_image);
@@ -487,6 +612,7 @@ static struct option const long_opts[] = {
{"ec_image", 1, NULL, 'e'},
{"pd_image", 1, NULL, 'P'},
{"emulate", 1, NULL, 'E'},
+ {"sys_props", 1, NULL, 'S'},
{"help", 0, NULL, 'h'},
{NULL, 0, NULL, 0},
};
@@ -504,6 +630,7 @@ static void print_help(int argc, char *argv[])
"\n"
"Debugging and testing options:\n"
" --emulate=FILE \tEmulate system firmware using file\n"
+ " --sys_props=LIST\tList of system properties to override\n"
"",
argv[0]);
}
@@ -516,6 +643,9 @@ static int do_update(int argc, char *argv[])
.image_current = { .programmer = PROG_HOST, },
.ec_image = { .programmer = PROG_EC, },
.pd_image = { .programmer = PROG_PD, },
+ .emulate = 0,
+ .system_properties = {
+ },
};
printf(">> Firmware updater started.\n");
@@ -542,6 +672,9 @@ static int do_update(int argc, char *argv[])
cfg.image_current.emulation);
}
break;
+ case 'S':
+ override_properties_from_list(optarg, &cfg);
+ break;
case 'h':
print_help(argc, argv);
diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh
index 7e2a142d..ca9c6f85 100755
--- a/tests/futility/test_update.sh
+++ b/tests/futility/test_update.sh
@@ -6,6 +6,19 @@
me=${0##*/}
TMP="$me.tmp"
+# Test --sys_props (primitive test needed for future updating tests).
+test_sys_props() {
+ ! "${FUTILITY}" --debug update --sys_props "$*" |
+ sed -n 's/.*property\[\(.*\)].value = \(.*\)/\1,\2,/p' |
+ tr '\n' ' '
+}
+
+test "$(test_sys_props "1,2,3")" = "0,1, 1,2, 2,3, "
+test "$(test_sys_props "1 2 3")" = "0,1, 1,2, 2,3, "
+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 data files
LINK_BIOS="${SCRIPTDIR}/data/bios_link_mp.bin"
PEPPY_BIOS="${SCRIPTDIR}/data/bios_peppy_mp.bin"