]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
bootstd: Add command to enable setting of bootmeth specific properties
authorMartyn Welch <martyn.welch@collabora.com>
Wed, 9 Oct 2024 13:15:40 +0000 (14:15 +0100)
committerTom Rini <trini@konsulko.com>
Tue, 15 Oct 2024 16:24:27 +0000 (10:24 -0600)
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>
boot/bootmeth-uclass.c
boot/bootmeth_extlinux.c
cmd/bootmeth.c
doc/develop/bootstd/overview.rst
doc/usage/cmd/bootmeth.rst
include/bootmeth.h

index c0abadef97cae87d2df27dd30daa8c0d10ca2ba1..5b5fea39b3b3925375477ab41e2288f4ef4c7358 100644 (file)
@@ -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;
index 26c61a65e240a3b1a080660a15866e2823546d43..be8fbf4df63b6d2f81967d4b718016a32783acdd 100644 (file)
 #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)
 };
index ebf8b7e2530fb6a8eca5b70e46404da435d9d614..2f41fa1bec6b7c738cf9d92d3f020880962e8f15 100644 (file)
@@ -103,10 +103,31 @@ static int do_bootmeth_order(struct cmd_tbl *cmdtp, int flag, int argc,
        return 0;
 }
 
+static int do_bootmeth_set(struct cmd_tbl *cmdtp, int flag, int argc,
+                            char *const argv[])
+{
+       int ret;
+
+       if (argc < 4) {
+               printf("Required parameters not provided\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = bootmeth_set_property(argv[1], argv[2], argv[3]);
+       if (ret) {
+               printf("Failed (err=%d)\n", ret);
+               return CMD_RET_FAILURE;
+       }
+
+       return 0;
+}
+
 U_BOOT_LONGHELP(bootmeth,
        "list [-a]     - list available bootmeths (-a all)\n"
-       "bootmeth order [<bd> ...]  - select bootmeth order / subset to use");
+       "bootmeth order [<bd> ...]  - select bootmeth order / subset to use\n"
+       "bootmeth set <bootmeth> <property> <value> - set optional property");
 
 U_BOOT_CMD_WITH_SUBCMDS(bootmeth, "Boot methods", bootmeth_help_text,
        U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootmeth_list),
-       U_BOOT_SUBCMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_bootmeth_order));
+       U_BOOT_SUBCMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_bootmeth_order),
+       U_BOOT_SUBCMD_MKENT(set, CONFIG_SYS_MAXARGS, 1, do_bootmeth_set));
index c6f003851b2aba92474122f2c121697c37f62b81..a2913cd47be5e4c540ed47f894a838a61e7371f5 100644 (file)
@@ -103,6 +103,12 @@ provide a `read_bootflow()` method which checks whatever bootdevs it likes, then
 returns the bootflow, if found. Some of these bootmeths may be very slow, if
 they scan a lot of devices.
 
+The extlinux bootmeth also allows for bootmeth specific configuration to be
+set. A bootmeth that wishes to support this provides the `set_property()`
+method. This allows string properties and values to be passed to the bootmeth.
+It is up to the bootmeth to determine what action to take when this method is
+called.
+
 
 Boot process
 ------------
@@ -459,8 +465,8 @@ Three commands are available:
     See :doc:`/usage/cmd/bootflow`
 
 `bootmeth`
-    Allow listing of available bootmethds and setting the order in which they
-    are tried. See :doc:`/usage/cmd/bootmeth`
+    Allow listing of available bootmethds, setting the order in which they are
+    tried and bootmeth specific configuration. See :doc:`/usage/cmd/bootmeth`
 
 .. _BootflowStates:
 
index c3d2ec1574b98a247e736d249f84dcdfb7fba4f0..4f899d92b2e127cf3be887f9800a2e655f65f91a 100644 (file)
@@ -12,7 +12,8 @@ Synopsis
 ::
 
     bootmeth list [-a]          - list selected bootmeths (-a for all)
-    bootmeth order "[<bm> ...]" - select the order of bootmeths\n"
+    bootmeth order "[<bm> ...]" - select the order of bootmeths
+    bootmeth set <bootmeth> <property> <value> - set optional property
 
 
 Description
@@ -112,3 +113,38 @@ which are not::
         -    4  efi_mgr             EFI bootmgr flow
     -----  ---  ------------------  ------------------
     (5 bootmeths)
+
+
+bootmeth set
+~~~~~~~~~~~~
+
+Allows setting of bootmeth specific configuration. This allows finer grain
+control over the boot process in specific instances.
+
+
+Supported Configuration Options
+-------------------------------
+
+The following configuration options are currently supported:
+
+========  ===================  ======  ===============================
+Property  Supported Bootmeths  Values  Description
+========  ===================  ======  ===============================
+fallback  extlinux             0 | 1     Enable or disable fallback path
+========  ===================  ======  ===============================
+
+
+Bootmeth set Example
+--------------------
+
+With the bootcount functionality enabled, when the bootlimit is reached, the
+`altbootcmd` environment variable lists the command used for booting rather
+than `bootcmd`. We can set the fallback configuration to cause the fallback
+boot option to be preferred, to revert to a previous known working boot option
+after a failed update for example. So if `bootcmd` is set to::
+
+    bootflow scan -lb
+
+We would set "altbootcmd" to::
+
+    bootmeth set extlinux fallback 1; bootflow scan -lb
index 4d8ca48efd47cd95e81f3deeda2b712592d91436..a08ebf005ada534335ea844e6b652e4b71453dc3 100644 (file)
@@ -146,6 +146,22 @@ struct bootmeth_ops {
         *      something changes, other -ve on other error
         */
        int (*boot)(struct udevice *dev, struct bootflow *bflow);
+
+       /**
+        * set_property() - set the bootmeth property
+        *
+        * This allows the setting of boot method specific properties to enable
+        * automated finer grain control of the boot process
+        *
+        * @name: String containing the name of the relevant boot method
+        * @property: String containing the name of the property to set
+        * @value: String containing the value to be set for the specified
+        *         property
+        * Return: 0 if OK, -ENODEV if an unknown bootmeth or property is
+        *      provided, -ENOENT if there are no bootmeth devices
+        */
+       int (*set_property)(struct udevice *dev, const char *property,
+                           const char *value);
 };
 
 #define bootmeth_get_ops(dev)  ((struct bootmeth_ops *)(dev)->driver->ops)
@@ -290,6 +306,21 @@ int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global);
  */
 int bootmeth_set_order(const char *order_str);
 
+/**
+ * bootmeth_set_property() - Set the bootmeth property
+ *
+ * This allows the setting of boot method specific properties to enable
+ * automated finer grain control of the boot process
+ *
+ * @name: String containing the name of the relevant boot method
+ * @property: String containing the name of the property to set
+ * @value: String containing the value to be set for the specified property
+ * Return: 0 if OK, -ENODEV if an unknown bootmeth or property is provided,
+ * -ENOENT if there are no bootmeth devices
+ */
+int bootmeth_set_property(const char *name, const char *property,
+                         const char *value);
+
 /**
  * bootmeth_setup_fs() - Set up read to read a file
  *