]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
bootstd: Add the bootstd uclass and core implementation
authorSimon Glass <sjg@chromium.org>
Mon, 25 Apr 2022 05:31:06 +0000 (23:31 -0600)
committerTom Rini <trini@konsulko.com>
Mon, 25 Apr 2022 14:00:04 +0000 (10:00 -0400)
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 <sjg@chromium.org>
MAINTAINERS
boot/Kconfig
boot/Makefile
boot/bootstd-uclass.c [new file with mode: 0644]
configs/efi-x86_app32_defconfig
configs/efi-x86_app64_defconfig
doc/device-tree-bindings/bootstd.txt [new file with mode: 0644]
include/bootstd.h [new file with mode: 0644]
include/dm/uclass-id.h

index d6d45573fdc2f6718f8fa590b71953c57f968a88..dd099d6240f0cdfbf331d17f5ac1d902894172f2 100644 (file)
@@ -696,6 +696,8 @@ F:  tools/binman/
 BOOTDEVICE
 M:     Simon Glass <sjg@chromium.org>
 S:     Maintained
+F:     boot/bootstd.c
+F:     include/bootstd.h
 F:     include/bootflow.h
 
 BTRFS
index ec5b956490de451e60a2538266cedeec6cdab3d4..9faa55a5418c4538e8e744473001c68383958632 100644 (file)
@@ -292,6 +292,40 @@ endif # SPL
 
 endif # FIT
 
+config BOOTSTD
+       bool "Standard boot support"
+       default y
+       depends on DM && OF_CONTROL && BLK
+       help
+         U-Boot supports a standard way of locating something to boot,
+         typically an Operating System such as Linux, provided by a distro such
+         as Arch Linux or Debian. Enable this to support iterating through
+         available bootdevs and using bootmeths to find bootflows suitable for
+         booting.
+
+         Standard boot is not a standard way of booting, just a framework
+         within U-Boot for supporting all the different ways that exist.
+
+         Terminology:
+
+           - bootdev - a device which can hold a distro (e.g. MMC)
+           - bootmeth - a method to scan a bootdev to find bootflows (owned by
+               U-Boot)
+           - bootflow - a description of how to boot (owned by the distro)
+
+config BOOTSTD_FULL
+       bool "Enhanced features for standard boot"
+       default y if SANDBOX
+       help
+         This enables various useful features for standard boot, which are not
+         essential for operation:
+
+         - bootdev, bootmeth commands
+         - extra features in the bootflow command
+         - support for selecting the ordering of bootmeths ("bootmeth order")
+         - support for selecting the ordering of bootdevs using the devicetree
+           as well as the "boot_targets" environment variable
+
 config LEGACY_IMAGE_FORMAT
        bool "Enable support for the legacy image format"
        default y if !FIT_SIGNATURE
index 1b99e6ee33f3bbcf4c887057ba916602b00ee072..21dcf6a6056bcc556d0f8fdadfeebe1a45f8f293 100644 (file)
@@ -18,6 +18,9 @@ endif
 obj-y += image.o image-board.o
 obj-$(CONFIG_ANDROID_AB) += android_ab.o
 obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
+
+obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootstd-uclass.o
+
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
 obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o
 obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c
new file mode 100644 (file)
index 0000000..615cd89
--- /dev/null
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Uclass implementation for standard boot
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <bootflow.h>
+#include <bootstd.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/read.h>
+#include <dm/uclass-internal.h>
+
+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
+};
index 228643a1bd6ad3e386c8343a4a5993f5c14d3c1c..7a723c136c2b2bbb7c0ecd339dc8136bf2429478 100644 (file)
@@ -8,6 +8,7 @@ CONFIG_VENDOR_EFI=y
 CONFIG_TARGET_EFI_APP32=y
 CONFIG_DEBUG_UART=y
 CONFIG_FIT=y
+# CONFIG_BOOTSTD is not set
 CONFIG_SHOW_BOOT_PROGRESS=y
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
index 1ed2f130509f22ebd458747c102975c84425d31d..98f91d811642d9f0067a4ee9dcc05c575d0bc851 100644 (file)
@@ -8,6 +8,7 @@ CONFIG_VENDOR_EFI=y
 CONFIG_TARGET_EFI_APP64=y
 CONFIG_DEBUG_UART=y
 CONFIG_FIT=y
+# CONFIG_BOOTSTD is not set
 CONFIG_SHOW_BOOT_PROGRESS=y
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
diff --git a/doc/device-tree-bindings/bootstd.txt b/doc/device-tree-bindings/bootstd.txt
new file mode 100644 (file)
index 0000000..f048b9d
--- /dev/null
@@ -0,0 +1,28 @@
+U-Boot standard boot device (bootstd)
+=====================================
+
+This is the controlling device for U-Boot standard boot, providing a way to
+boot operating systems in a way that can be controlled by distros.
+
+Required properties:
+
+compatible: "u-boot,boot-std"
+
+Optional properties:
+
+filename-prefixes:
+   List of strings, each a directory to search for bootflow files
+
+bootdev-order:
+   List of bootdevs to check for bootflows, each a bootdev label (the media
+   uclass followed by the numeric sequence number of the media device)
+
+
+Example:
+
+       bootstd {
+               compatible = "u-boot,boot-std";
+
+               filename-prefixes = "/", "/boot/";
+               bootdev-order = "mmc2", "mmc1";
+       };
diff --git a/include/bootstd.h b/include/bootstd.h
new file mode 100644 (file)
index 0000000..b002365
--- /dev/null
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Standard U-Boot boot framework
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __bootstd_h
+#define __bootstd_h
+
+struct udevice;
+
+/**
+ * struct bootstd_priv - priv data for the bootstd driver
+ *
+ * This is attached to the (only) bootstd device, so there is only one instance
+ * of this struct. It provides overall information about bootdevs and bootflows.
+ *
+ * @prefixes: NULL-terminated list of prefixes to use for bootflow filenames,
+ *     e.g. "/", "/boot/"; NULL if none
+ * @bootdev_order: Order to use for bootdevs (or NULL if none), with each item
+ *     being a bootdev label, e.g. "mmc2", "mmc1";
+ * @cur_bootdev: Currently selected bootdev (for commands)
+ * @cur_bootflow: Currently selected bootflow (for commands)
+ * @glob_head: Head for the global list of all bootflows across all bootdevs
+ * @bootmeth_count: Number of bootmeth devices in @bootmeth_order
+ * @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated
+ */
+struct bootstd_priv {
+       const char **prefixes;
+       const char **bootdev_order;
+       struct udevice *cur_bootdev;
+       struct bootflow *cur_bootflow;
+       struct list_head glob_head;
+       int bootmeth_count;
+       struct udevice **bootmeth_order;
+};
+
+/**
+ * bootstd_get_bootdev_order() - Get the boot-order list
+ *
+ * This reads the boot order, e.g. {"mmc0", "mmc2", NULL}
+ *
+ * The list is alloced by the bootstd driver so should not be freed. That is the
+ * reason for all the const stuff in the function signature
+ *
+ * Return: list of string points, terminated by NULL; or NULL if no boot order
+ */
+const char *const *const bootstd_get_bootdev_order(struct udevice *dev);
+
+/**
+ * bootstd_get_prefixes() - Get the filename-prefixes list
+ *
+ * This reads the prefixes, e.g. {"/", "/bpot", NULL}
+ *
+ * The list is alloced by the bootstd driver so should not be freed. That is the
+ * reason for all the const stuff in the function signature
+ *
+ * Return: list of string points, terminated by NULL; or NULL if no boot order
+ */
+const char *const *const bootstd_get_prefixes(struct udevice *dev);
+
+/**
+ * bootstd_get_priv() - Get the (single) state for the bootstd system
+ *
+ * The state holds a global list of all bootflows that have been found.
+ *
+ * Return: 0 if OK, -ve if the uclass does not exist
+ */
+int bootstd_get_priv(struct bootstd_priv **stdp);
+
+/**
+ * bootstd_clear_glob() - Clear the global list of bootflows
+ *
+ * This removes all bootflows globally and across all bootdevs.
+ */
+void bootstd_clear_glob(void);
+
+#endif
index 0e26e1d13824c06f56f9434935219667dddf59ed..cece0626a112413499d5112d13f772499102f4fd 100644 (file)
@@ -38,6 +38,7 @@ enum uclass_id {
        UCLASS_AXI,             /* AXI bus */
        UCLASS_BLK,             /* Block device */
        UCLASS_BOOTCOUNT,       /* Bootcount backing store */
+       UCLASS_BOOTSTD,         /* Standard boot driver */
        UCLASS_BUTTON,          /* Button */
        UCLASS_CACHE,           /* Cache controller */
        UCLASS_CLK,             /* Clock source, e.g. used by peripherals */