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