Skip to content

Commit

Permalink
bootstd: Add command to enable setting of bootmeth specific properties
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Martyn Welch <[email protected]>
  • Loading branch information
mwelchuk authored and trini committed Oct 15, 2024
1 parent 8ba82a9 commit 3809fd3
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 6 deletions.
25 changes: 25 additions & 0 deletions boot/bootmeth-uclass.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
73 changes: 72 additions & 1 deletion boot/bootmeth_extlinux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand All @@ -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[] = {
Expand All @@ -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)
};
25 changes: 23 additions & 2 deletions cmd/bootmeth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
10 changes: 8 additions & 2 deletions doc/develop/bootstd/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
------------
Expand Down Expand Up @@ -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:

Expand Down
38 changes: 37 additions & 1 deletion doc/usage/cmd/bootmeth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
31 changes: 31 additions & 0 deletions include/bootmeth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
*
Expand Down

0 comments on commit 3809fd3

Please sign in to comment.