From ef5e3891f57e6fc863fabbc94b1d7da79d1940bb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:06 -0600 Subject: bootstd: Add the bootstd uclass and core implementation The 'bootstd' device provides the central information about U-Boot standard boot. Add a uclass for bootstd and the various helpers needed to make it work. Also add a binding file. Signed-off-by: Simon Glass --- boot/bootstd-uclass.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 boot/bootstd-uclass.c (limited to 'boot/bootstd-uclass.c') diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c new file mode 100644 index 00000000000..615cd89bf0b --- /dev/null +++ b/boot/bootstd-uclass.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Uclass implementation for standard boot + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* These are used if filename-prefixes is not present */ +const char *const default_prefixes[] = {"/", "/boot/", NULL}; + +static int bootstd_of_to_plat(struct udevice *dev) +{ + struct bootstd_priv *priv = dev_get_priv(dev); + int ret; + + if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) { + /* Don't check errors since livetree and flattree are different */ + ret = dev_read_string_list(dev, "filename-prefixes", + &priv->prefixes); + dev_read_string_list(dev, "bootdev-order", + &priv->bootdev_order); + } + + return 0; +} + +static void bootstd_clear_glob_(struct bootstd_priv *priv) +{ + while (!list_empty(&priv->glob_head)) { + struct bootflow *bflow; + + bflow = list_first_entry(&priv->glob_head, struct bootflow, + glob_node); + /* add later bootflow_remove(bflow); */ + } +} + +void bootstd_clear_glob(void) +{ + struct bootstd_priv *std; + + if (bootstd_get_priv(&std)) + return; + + bootstd_clear_glob_(std); +} + +static int bootstd_remove(struct udevice *dev) +{ + struct bootstd_priv *priv = dev_get_priv(dev); + + free(priv->prefixes); + free(priv->bootdev_order); + bootstd_clear_glob_(priv); + + return 0; +} + +const char *const *const bootstd_get_bootdev_order(struct udevice *dev) +{ + struct bootstd_priv *std = dev_get_priv(dev); + + return std->bootdev_order; +} + +const char *const *const bootstd_get_prefixes(struct udevice *dev) +{ + struct bootstd_priv *std = dev_get_priv(dev); + + return std->prefixes ? std->prefixes : default_prefixes; +} + +int bootstd_get_priv(struct bootstd_priv **stdp) +{ + struct udevice *dev; + int ret; + + ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev); + if (ret) + return ret; + *stdp = dev_get_priv(dev); + + return 0; +} + +static int bootstd_probe(struct udevice *dev) +{ + struct bootstd_priv *std = dev_get_priv(dev); + + INIT_LIST_HEAD(&std->glob_head); + + return 0; +} + +/* For now, bind the boormethod device if none are found in the devicetree */ +int dm_scan_other(bool pre_reloc_only) +{ + struct udevice *bootstd; + int ret; + + /* These are not needed before relocation */ + if (!(gd->flags & GD_FLG_RELOC)) + return 0; + + /* Create a bootstd device if needed */ + uclass_find_first_device(UCLASS_BOOTSTD, &bootstd); + if (!bootstd) { + ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd", + &bootstd); + if (ret) + return log_msg_ret("bootstd", ret); + } + + return 0; +} + +static const struct udevice_id bootstd_ids[] = { + { .compatible = "u-boot,boot-std" }, + { } +}; + +U_BOOT_DRIVER(bootstd_drv) = { + .id = UCLASS_BOOTSTD, + .name = "bootstd_drv", + .of_to_plat = bootstd_of_to_plat, + .probe = bootstd_probe, + .remove = bootstd_remove, + .of_match = bootstd_ids, + .priv_auto = sizeof(struct bootstd_priv), +}; + +UCLASS_DRIVER(bootstd) = { + .id = UCLASS_BOOTSTD, + .name = "bootstd", +#if CONFIG_IS_ENABLED(OF_REAL) + .post_bind = dm_scan_fdt_dev, +#endif +}; -- cgit v1.2.3 From a950d31abe980ba40a0a94fbf41136550187f8cd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:08 -0600 Subject: bootstd: Add the bootmeth uclass and helpers A bootmeth is a method of locating an operating system. For now, just add the uclass itself. Drivers for particular bootmeths are added later. If no bootmeths devices are included in the devicetree, create them automatically. This avoids the need for boilerplate in the devicetree files. Signed-off-by: Simon Glass --- boot/bootstd-uclass.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'boot/bootstd-uclass.c') diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c index 615cd89bf0b..4c71c2829ef 100644 --- a/boot/bootstd-uclass.c +++ b/boot/bootstd-uclass.c @@ -109,8 +109,10 @@ static int bootstd_probe(struct udevice *dev) /* For now, bind the boormethod device if none are found in the devicetree */ int dm_scan_other(bool pre_reloc_only) { - struct udevice *bootstd; - int ret; + struct driver *drv = ll_entry_start(struct driver, driver); + const int n_ents = ll_entry_count(struct driver, driver); + struct udevice *dev, *bootstd; + int i, ret; /* These are not needed before relocation */ if (!(gd->flags & GD_FLG_RELOC)) @@ -125,6 +127,29 @@ int dm_scan_other(bool pre_reloc_only) return log_msg_ret("bootstd", ret); } + /* If there are no bootmeth devices, create them */ + uclass_find_first_device(UCLASS_BOOTMETH, &dev); + if (dev) + return 0; + + for (i = 0; i < n_ents; i++, drv++) { + /* + * Disable EFI Manager for now as no one uses it so it is + * confusing + */ + if (drv->id == UCLASS_BOOTMETH && + strcmp("efi_mgr_bootmeth", drv->name)) { + const char *name = drv->name; + + if (!strncmp("bootmeth_", name, 9)) + name += 9; + ret = device_bind(bootstd, drv, name, 0, ofnode_null(), + &dev); + if (ret) + return log_msg_ret("meth", ret); + } + } + return 0; } -- cgit v1.2.3 From a8f5be178db53f41338730e001b0f2ab459f7e31 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:09 -0600 Subject: bootstd: Add support for bootflows Add support for bootflows, including maintaining a list of them and iterating to find them. Signed-off-by: Simon Glass --- boot/bootstd-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'boot/bootstd-uclass.c') diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c index 4c71c2829ef..266bd7cb2e3 100644 --- a/boot/bootstd-uclass.c +++ b/boot/bootstd-uclass.c @@ -45,7 +45,7 @@ static void bootstd_clear_glob_(struct bootstd_priv *priv) bflow = list_first_entry(&priv->glob_head, struct bootflow, glob_node); - /* add later bootflow_remove(bflow); */ + bootflow_remove(bflow); } } -- cgit v1.2.3 From a080b98981a74e96ef2ff6b4de36b222fe42b8e5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:18 -0600 Subject: bootstd: Add a system bootdev for strange boot methods Some boot methods don't act on a single bootdev but instead do their own thing. An example is EFI bootmgr which scan various devices using its own logic. Add a bootdev to handle this. Signed-off-by: Simon Glass --- boot/bootstd-uclass.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'boot/bootstd-uclass.c') diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c index 266bd7cb2e3..3c6c32ae604 100644 --- a/boot/bootstd-uclass.c +++ b/boot/bootstd-uclass.c @@ -150,6 +150,12 @@ int dm_scan_other(bool pre_reloc_only) } } + /* Create the system bootdev too */ + ret = device_bind_driver(bootstd, "system_bootdev", "system-bootdev", + &dev); + if (ret) + return log_msg_ret("sys", ret); + return 0; } -- cgit v1.2.3