[PATCH v4 13/33] bootstd: Add the bootstd uclass and core implementation

Simon Glass sjg at chromium.org
Sun Mar 6 13:49:56 CET 2022


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 at chromium.org>
---

Changes in v4:
- NULL-terminate the default prefix list
- Use new Return style in function comments

Changes in v3:
- Add CONFIG_BOOTSTD_FULL to enable the full feature set
- Support bootdev-order and filename-prefixes only with CONFIG_BOOTSTD_FULL

 MAINTAINERS                          |   2 +
 boot/Kconfig                         |  34 ++++++
 boot/Makefile                        |   3 +
 boot/bootstd-uclass.c                | 152 +++++++++++++++++++++++++++
 doc/device-tree-bindings/bootstd.txt |  28 +++++
 include/bootstd.h                    |  80 ++++++++++++++
 include/dm/uclass-id.h               |   1 +
 7 files changed, 300 insertions(+)
 create mode 100644 boot/bootstd-uclass.c
 create mode 100644 doc/device-tree-bindings/bootstd.txt
 create mode 100644 include/bootstd.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6e6dcd7e26..9df9812978 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -685,6 +685,8 @@ F:	tools/binman/
 BOOTDEVICE
 M:	Simon Glass <sjg at chromium.org>
 S:	Maintained
+F:	boot/bootstd.c
+F:	include/bootstd.h
 F:	include/bootflow.h
 
 BTRFS
diff --git a/boot/Kconfig b/boot/Kconfig
index b83a4e8400..deb2bf386f 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -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
diff --git a/boot/Makefile b/boot/Makefile
index 2938c3f145..48031d1c2b 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -22,6 +22,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
index 0000000000..615cd89bf0
--- /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 <sjg at 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
+};
diff --git a/doc/device-tree-bindings/bootstd.txt b/doc/device-tree-bindings/bootstd.txt
new file mode 100644
index 0000000000..f048b9dd32
--- /dev/null
+++ b/doc/device-tree-bindings/bootstd.txt
@@ -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
index 0000000000..b002365f4f
--- /dev/null
+++ b/include/bootstd.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Standard U-Boot boot framework
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg at 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
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 0e26e1d138..cece0626a1 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -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 */
-- 
2.35.1.616.g0bdcbb4464-goog



More information about the U-Boot mailing list