diff options
author | Martyn Welch <martyn.welch@collabora.com> | 2024-10-09 14:15:40 +0100 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-10-15 10:24:27 -0600 |
commit | 3809fd35a5dbdbd62043ba0a72c3f37f58e69f9d (patch) | |
tree | b7a3cbf6da74d598d2e8529aaf18a30ce3ccba57 /boot | |
parent | 8ba82a91b3aa615fb6148ecfa2af4e91a28659ae (diff) | |
download | u-boot-3809fd35a5dbdbd62043ba0a72c3f37f58e69f9d.tar.gz |
bootstd: Add command to enable setting of bootmeth specific properties
We have previously added logic to allow a "fallback" option to be
specified in the extlinux configuration. Provide a command that allows
us to set this as the preferred default option when booting.
Combined with the bootcount functionality, this allows the "altbootcmd"
to provide a means of falling back to a previously known good state
after a failed update. For example, if "bootcmd" is set to:
bootflow scan -lb
We would set "altbootcmd" to:
bootmeth set extlinux fallback 1; bootflow scan -lb
Causing the boot process to boot from the fallback option.
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
Diffstat (limited to 'boot')
-rw-r--r-- | boot/bootmeth-uclass.c | 25 | ||||
-rw-r--r-- | boot/bootmeth_extlinux.c | 73 |
2 files changed, 97 insertions, 1 deletions
diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c index c0abadef97c..5b5fea39b3b 100644 --- a/boot/bootmeth-uclass.c +++ b/boot/bootmeth-uclass.c @@ -251,6 +251,31 @@ int bootmeth_set_order(const char *order_str) return 0; } +int bootmeth_set_property(const char *name, const char *property, const char *value) +{ + int ret; + int len; + struct udevice *dev; + const struct bootmeth_ops *ops; + + len = strlen(name); + + ret = uclass_find_device_by_namelen(UCLASS_BOOTMETH, name, len, + &dev); + if (ret) { + printf("Unknown bootmeth '%s'\n", name); + return ret; + } + + ops = bootmeth_get_ops(dev); + if (!ops->set_property) { + printf("set_property not found\n"); + return -ENODEV; + } + + return ops->set_property(dev, property, value); +} + int bootmeth_setup_fs(struct bootflow *bflow, struct blk_desc *desc) { int ret; diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index 26c61a65e24..be8fbf4df63 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -21,6 +21,39 @@ #include <mmc.h> #include <pxe_utils.h> +struct extlinux_plat { + bool use_fallback; +}; + +enum extlinux_option_type { + EO_FALLBACK, + EO_INVALID +}; + +struct extlinux_option { + char *name; + enum extlinux_option_type option; +}; + +static const struct extlinux_option options[] = { + {"fallback", EO_FALLBACK}, + {NULL, EO_INVALID} +}; + +static enum extlinux_option_type get_option(const char *option) +{ + int i = 0; + + while (options[i].name) { + if (!strcmp(options[i].name, option)) + return options[i].option; + + i++; + } + + return EO_INVALID; +}; + static int extlinux_get_state_desc(struct udevice *dev, char *buf, int maxsize) { if (IS_ENABLED(CONFIG_SANDBOX)) { @@ -142,14 +175,18 @@ static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) struct cmd_tbl cmdtp = {}; /* dummy */ struct pxe_context ctx; struct extlinux_info info; + struct extlinux_plat *plat; ulong addr; int ret; addr = map_to_sysmem(bflow->buf); info.dev = dev; info.bflow = bflow; + + plat = dev_get_plat(dev); + ret = pxe_setup_ctx(&ctx, &cmdtp, extlinux_getfile, &info, true, - bflow->fname, false, false); + bflow->fname, false, plat->use_fallback); if (ret) return log_msg_ret("ctx", -EINVAL); @@ -160,6 +197,38 @@ static int extlinux_boot(struct udevice *dev, struct bootflow *bflow) return 0; } +static int extlinux_set_property(struct udevice *dev, const char *property, const char *value) +{ + struct extlinux_plat *plat; + static enum extlinux_option_type option; + + plat = dev_get_plat(dev); + + option = get_option(property); + if (option == EO_INVALID) { + printf("Invalid option\n"); + return -EINVAL; + } + + switch (option) { + case EO_FALLBACK: + if (!strcmp(value, "1")) { + plat->use_fallback = true; + } else if (!strcmp(value, "0")) { + plat->use_fallback = false; + } else { + printf("Unexpected value '%s'\n", value); + return -EINVAL; + } + break; + default: + printf("Unrecognised property '%s'\n", property); + return -EINVAL; + } + + return 0; +} + static int extlinux_bootmeth_bind(struct udevice *dev) { struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); @@ -176,6 +245,7 @@ static struct bootmeth_ops extlinux_bootmeth_ops = { .read_bootflow = extlinux_read_bootflow, .read_file = bootmeth_common_read_file, .boot = extlinux_boot, + .set_property = extlinux_set_property, }; static const struct udevice_id extlinux_bootmeth_ids[] = { @@ -190,4 +260,5 @@ U_BOOT_DRIVER(bootmeth_1extlinux) = { .of_match = extlinux_bootmeth_ids, .ops = &extlinux_bootmeth_ops, .bind = extlinux_bootmeth_bind, + .plat_auto = sizeof(struct extlinux_plat) }; |