All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: U-Boot Mailing List <u-boot@lists.denx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>,
	Steffen Jaeckel <jaeckel-floss@eyet-services.de>,
	Michal Simek <michal.simek@xilinx.com>,
	Tom Rini <trini@konsulko.com>, Dennis Gilmore <dennis@ausil.us>,
	Daniel Schwierzeck <daniel.schwierzeck@gmail.com>,
	Lukas Auer <lukas.auer@aisec.fraunhofer.de>,
	Simon Glass <sjg@chromium.org>
Subject: [PATCH 19/28] bootmethod: Add the uclass and core implementation
Date: Wed, 18 Aug 2021 21:45:52 -0600	[thread overview]
Message-ID: <20210818214547.19.I3b5bc09d034cd72b2a9c604a0907c10abc05956a@changeid> (raw)
In-Reply-To: <20210819034601.1618773-1-sjg@chromium.org>

Add a uclass for bootmethod and the various helpers needed to make it
work.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 MAINTAINERS            |   6 +
 boot/Kconfig           |   9 +
 boot/Makefile          |   1 +
 boot/bootmethod.c      | 445 +++++++++++++++++++++++++++++++++++++++++
 include/bootmethod.h   | 355 ++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h |   1 +
 6 files changed, 817 insertions(+)
 create mode 100644 boot/bootmethod.c
 create mode 100644 include/bootmethod.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 776ff703b9b..d977cee562b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -630,6 +630,12 @@ M:	Simon Glass <sjg@chromium.org>
 S:	Maintained
 F:	tools/binman/
 
+BOOTMETHOD
+M:	Simon Glass <sjg@chromium.org>
+S:	Maintained
+F:	boot/bootmethod.c
+F:	include/bootmethod.h
+
 BTRFS
 M:	Marek Behun <marek.behun@nic.cz>
 R:	Qu Wenruo <wqu@suse.com>
diff --git a/boot/Kconfig b/boot/Kconfig
index 0d4c38402c1..90f716c3ef1 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -290,6 +290,15 @@ endif # SPL
 
 endif # FIT
 
+config BOOTMETHOD
+	bool "Bootmethod support"
+	default y
+	help
+	  A bootmethod is a standard way of locating something to boot,
+	  typically an Operating System such as Linux. Enable this to support
+	  iterating through available bootmethods to find a bootflow suitable
+	  for booting.
+
 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 e8f984248e6..10d427e115c 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -22,6 +22,7 @@ endif
 obj-y += image.o
 obj-$(CONFIG_ANDROID_AB) += android_ab.o
 obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
+obj-$(CONFIG_$(SPL_TPL_)BOOTMETHOD) += bootmethod.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/bootmethod.c b/boot/bootmethod.c
new file mode 100644
index 00000000000..8e4157c6a47
--- /dev/null
+++ b/boot/bootmethod.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <blk.h>
+#include <bootmethod.h>
+#include <dm.h>
+#include <fs.h>
+#include <log.h>
+#include <malloc.h>
+#include <part.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+
+enum {
+	/*
+	 * Set some sort of limit on the number of bootflows a bootmethod can
+	 * return. Note that for disks this limits the partitions numbers that
+	 * are scanned to 1..MAX_BOOTFLOWS_PER_BOOTMETHOD
+	 */
+	MAX_BOOTFLOWS_PER_BOOTMETHOD	= 20,
+};
+
+static const char *const bootmethod_state[BOOTFLOWST_COUNT] = {
+	"base",
+	"media",
+	"part",
+	"fs",
+	"file",
+	"loaded",
+};
+
+static const char *const bootmethod_type[BOOTFLOWT_COUNT] = {
+};
+
+int bootmethod_get_state(struct bootflow_state **statep)
+{
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_BOOTMETHOD, &uc);
+	if (ret)
+		return ret;
+	*statep = uclass_get_priv(uc);
+
+	return 0;
+}
+
+const char *bootmethod_state_get_name(enum bootflow_state_t state)
+{
+	if (state < 0 || state >= BOOTFLOWST_COUNT)
+		return "?";
+
+	return bootmethod_state[state];
+}
+
+const char *bootmethod_type_get_name(enum bootflow_type_t type)
+{
+	if (type < 0 || type >= BOOTFLOWT_COUNT)
+		return "?";
+
+	return bootmethod_type[type];
+}
+
+void bootflow_free(struct bootflow *bflow)
+{
+	free(bflow->name);
+	free(bflow->subdir);
+	free(bflow->fname);
+	free(bflow->buf);
+}
+
+void bootflow_remove(struct bootflow *bflow)
+{
+	list_del(&bflow->bm_node);
+	list_del(&bflow->glob_node);
+
+	bootflow_free(bflow);
+	free(bflow);
+}
+
+void bootmethod_clear_bootflows(struct udevice *dev)
+{
+	struct bootmethod_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+	while (!list_empty(&ucp->bootflow_head)) {
+		struct bootflow *bflow;
+
+		bflow = list_first_entry(&ucp->bootflow_head, struct bootflow,
+					 bm_node);
+		bootflow_remove(bflow);
+	}
+}
+
+void bootmethod_clear_glob(void)
+{
+	struct bootflow_state *state;
+
+	if (bootmethod_get_state(&state))
+		return;
+
+	while (!list_empty(&state->glob_head)) {
+		struct bootflow *bflow;
+
+		bflow = list_first_entry(&state->glob_head, struct bootflow,
+					 glob_node);
+		bootflow_remove(bflow);
+	}
+}
+
+int bootmethod_add_bootflow(struct bootflow *bflow)
+{
+	struct bootmethod_uc_plat *ucp = dev_get_uclass_plat(bflow->dev);
+	struct bootflow_state *state;
+	struct bootflow *new;
+	int ret;
+
+	assert(bflow->dev);
+	ret = bootmethod_get_state(&state);
+	if (ret)
+		return ret;
+
+	new = malloc(sizeof(*bflow));
+	if (!new)
+		return log_msg_ret("bflow", -ENOMEM);
+	memcpy(new, bflow, sizeof(*bflow));
+
+	list_add_tail(&new->glob_node, &state->glob_head);
+	list_add_tail(&new->bm_node, &ucp->bootflow_head);
+
+	return 0;
+}
+
+int bootmethod_first_bootflow(struct udevice *dev, struct bootflow **bflowp)
+{
+	struct bootmethod_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+	if (list_empty(&ucp->bootflow_head))
+		return -ENOENT;
+
+	*bflowp = list_first_entry(&ucp->bootflow_head, struct bootflow,
+				   bm_node);
+
+	return 0;
+}
+
+int bootmethod_next_bootflow(struct bootflow **bflowp)
+{
+	struct bootflow *bflow = *bflowp;
+	struct bootmethod_uc_plat *ucp = dev_get_uclass_plat(bflow->dev);
+
+	*bflowp = NULL;
+
+	if (list_is_last(&bflow->bm_node, &ucp->bootflow_head))
+		return -ENOENT;
+
+	*bflowp = list_entry(bflow->bm_node.next, struct bootflow, bm_node);
+
+	return 0;
+}
+
+int bootflow_first_glob(struct bootflow **bflowp)
+{
+	struct bootflow_state *state;
+	int ret;
+
+	ret = bootmethod_get_state(&state);
+	if (ret)
+		return ret;
+
+	if (list_empty(&state->glob_head))
+		return -ENOENT;
+
+	*bflowp = list_first_entry(&state->glob_head, struct bootflow,
+				   glob_node);
+
+	return 0;
+}
+
+int bootflow_next_glob(struct bootflow **bflowp)
+{
+	struct bootflow_state *state;
+	struct bootflow *bflow = *bflowp;
+	int ret;
+
+	ret = bootmethod_get_state(&state);
+	if (ret)
+		return ret;
+
+	*bflowp = NULL;
+
+	if (list_is_last(&bflow->glob_node, &state->glob_head))
+		return -ENOENT;
+
+	*bflowp = list_entry(bflow->glob_node.next, struct bootflow, glob_node);
+
+	return 0;
+}
+
+int bootmethod_get_bootflow(struct udevice *dev, int seq,
+			    struct bootflow *bflow)
+{
+	const struct bootmethod_ops *ops = bootmethod_get_ops(dev);
+
+	if (!ops->get_bootflow)
+		return -ENOSYS;
+	memset(bflow, '\0', sizeof(*bflow));
+	bflow->dev = dev;
+	bflow->seq = seq;
+
+	return ops->get_bootflow(dev, seq, bflow);
+}
+
+static int next_bootflow(struct udevice *dev, int seq, struct bootflow *bflow)
+{
+	int ret;
+
+	ret = bootmethod_get_bootflow(dev, seq, bflow);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void bootmethod_iter_set_dev(struct bootmethod_iter *iter,
+				    struct udevice *dev)
+{
+	iter->dev = dev;
+	if (iter->flags & BOOTFLOWF_SHOW) {
+		if (dev)
+			printf("Scanning bootmethod '%s':\n", dev->name);
+		else
+			printf("No more bootmethods\n");
+	}
+}
+
+int bootmethod_scan_first_bootflow(struct bootmethod_iter *iter, int flags,
+				   struct bootflow *bflow)
+{
+	struct udevice *dev;
+	int ret;
+
+	iter->flags = flags;
+	iter->seq = 0;
+	ret = uclass_first_device_err(UCLASS_BOOTMETHOD, &dev);
+	if (ret)
+		return ret;
+	bootmethod_iter_set_dev(iter, dev);
+
+	ret = bootmethod_scan_next_bootflow(iter, bflow);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int bootmethod_scan_next_bootflow(struct bootmethod_iter *iter,
+				  struct bootflow *bflow)
+{
+	struct udevice *dev;
+	int ret;
+
+	do {
+		dev = iter->dev;
+		ret = next_bootflow(dev, iter->seq, bflow);
+
+		/* If we got a valid bootflow, return it */
+		if (!ret) {
+			log_debug("Bootmethod '%s' seq %d: Found bootflow\n",
+				  dev->name, iter->seq);
+			iter->seq++;
+			return 0;
+		}
+
+		/*
+		 * Unless there are no more partitions or no bootflow support,
+		 * try the next partition
+		 */
+		else if (ret != -ESHUTDOWN && ret != -ENOSYS) {
+			log_debug("Bootmethod '%s' seq %d: Error %d\n",
+				  dev->name, iter->seq, ret);
+			if ((iter->seq++ != MAX_BOOTFLOWS_PER_BOOTMETHOD) &&
+			    (iter->flags & BOOTFLOWF_ALL))
+				return log_msg_ret("all", ret);
+		}
+
+		/* we got to the end of that bootmethod, try the next */
+		ret = uclass_next_device_err(&dev);
+		bootmethod_iter_set_dev(iter, dev);
+
+		/* if there are no more bootmethods, give up */
+		if (ret)
+			return ret;
+
+		/* start at the beginning of this bootmethod */
+		iter->seq = 0;
+	} while (1);
+}
+
+int bootmethod_bind(struct udevice *parent, const char *drv_name,
+		    const char *name, struct udevice **devp)
+{
+	struct udevice *dev;
+	char dev_name[30];
+	char *str;
+	int ret;
+
+	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
+	str = strdup(dev_name);
+	if (!str)
+		return -ENOMEM;
+	ret = device_bind_driver(parent, drv_name, str, &dev);
+	if (ret)
+		return ret;
+	*devp = dev;
+
+	return 0;
+}
+
+int bootmethod_find_in_blk(struct udevice *dev, struct udevice *blk, int seq,
+			   struct bootflow *bflow)
+{
+	struct blk_desc *desc = dev_get_uclass_plat(blk);
+	struct disk_partition info;
+	char name[60];
+	int partnum = seq + 1;
+	int ret;
+
+	if (seq >= MAX_BOOTFLOWS_PER_BOOTMETHOD)
+		return -ESHUTDOWN;
+
+	bflow->blk = blk;
+	bflow->seq = seq;
+	snprintf(name, sizeof(name), "%s.part_%x", dev->name, partnum);
+	bflow->name = strdup(name);
+	if (!bflow->name)
+		return log_msg_ret("name", -ENOMEM);
+
+	bflow->state = BOOTFLOWST_BASE;
+	ret = part_get_info(desc, partnum, &info);
+
+	/* This error indicates the media is not present */
+	if (ret != -EOPNOTSUPP)
+		bflow->state = BOOTFLOWST_MEDIA;
+	if (ret)
+		return log_msg_ret("part", ret);
+
+	bflow->state = BOOTFLOWST_PART;
+	bflow->part = partnum;
+	ret = fs_set_blk_dev_with_part(desc, partnum);
+#ifdef CONFIG_DOS_PARTITION
+	log_debug("%s: Found partition %x type %x fstype %d\n", blk->name,
+		  partnum, info.sys_ind, ret ? -1 : fs_get_type());
+#endif
+	if (ret)
+		return log_msg_ret("fs", ret);
+
+	bflow->state = BOOTFLOWST_FS;
+
+	return 0;
+}
+
+int bootflow_boot(struct bootflow *bflow)
+{
+	bool done = false;
+	int ret;
+
+	if (bflow->state != BOOTFLOWST_LOADED)
+		return log_msg_ret("load", -EPROTO);
+
+	switch (bflow->type) {
+	case BOOTFLOWT_COUNT:
+		break;
+	}
+
+	if (!done)
+		return log_msg_ret("type", -ENOSYS);
+
+	if (ret)
+		return log_msg_ret("boot", ret);
+
+	/*
+	 * internal error, should not get here since we should have booted
+	 * something or returned an error
+	 */
+
+	return log_msg_ret("end", -EFAULT);
+}
+
+int bootmethod_setup_for_dev(struct udevice *parent, const char *drv_name)
+{
+	struct udevice *bm;
+	int ret;
+
+	if (!CONFIG_IS_ENABLED(BOOTMETHOD))
+		return 0;
+
+	ret = device_find_first_child_by_uclass(parent, UCLASS_BOOTMETHOD,
+						&bm);
+	if (ret) {
+		if (ret != -ENODEV) {
+			log_debug("Cannot access bootmethod device\n");
+			return ret;
+		}
+
+		ret = bootmethod_bind(parent, drv_name, "bootmethod", &bm);
+		if (ret) {
+			log_debug("Cannot create bootmethod device\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int bootmethod_init(struct uclass *uc)
+{
+	struct bootflow_state *state = uclass_get_priv(uc);
+
+	INIT_LIST_HEAD(&state->glob_head);
+
+	return 0;
+}
+
+static int bootmethod_post_bind(struct udevice *dev)
+{
+	struct bootmethod_uc_plat *ucp = dev_get_uclass_plat(dev);
+
+	INIT_LIST_HEAD(&ucp->bootflow_head);
+
+	return 0;
+}
+
+UCLASS_DRIVER(bootmethod) = {
+	.id		= UCLASS_BOOTMETHOD,
+	.name		= "bootmethod",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.priv_auto	= sizeof(struct bootflow_state),
+	.per_device_plat_auto	= sizeof(struct bootmethod_uc_plat),
+	.init		= bootmethod_init,
+	.post_bind	= bootmethod_post_bind,
+};
diff --git a/include/bootmethod.h b/include/bootmethod.h
new file mode 100644
index 00000000000..a45897b0c0c
--- /dev/null
+++ b/include/bootmethod.h
@@ -0,0 +1,355 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __bootmethod_h
+#define __bootmethod_h
+
+#include <linux/list.h>
+
+/**
+ * enum bootflow_state_t - states that a particular bootflow can be in
+ */
+enum bootflow_state_t {
+	BOOTFLOWST_BASE,	/**< Nothing known yet */
+	BOOTFLOWST_MEDIA,	/**< Media exists */
+	BOOTFLOWST_PART,	/**< Partition exists */
+	BOOTFLOWST_FS,		/**< Filesystem exists */
+	BOOTFLOWST_FILE,	/**< Bootflow file exists */
+	BOOTFLOWST_LOADED,	/**< Bootflow file loaded */
+
+	BOOTFLOWST_COUNT
+};
+
+enum bootflow_type_t {
+	BOOTFLOWT_COUNT,
+};
+
+/**
+ * struct bootflow_state - information about available bootflows, etc.
+ *
+ * This is attached to the bootmethod uclass so there is only one of them. It
+ * provides overall information about bootmethods and bootflows.
+ *
+ * @cur_bootmethod: Currently selected bootmethod (for commands)
+ * @cur_bootflow: Currently selected bootflow (for commands)
+ * @glob_head: Head for the global list of all bootmethods across all bootflows
+ */
+struct bootflow_state {
+	struct udevice *cur_bootmethod;
+	struct bootflow *cur_bootflow;
+	struct list_head glob_head;
+};
+
+/**
+ * struct bootmethod_uc_plat - uclass information about a bootmethod
+ *
+ * This is attached to each device in the bootmethod uclass and accessible via
+ * dev_get_uclass_plat(dev)
+ *
+ * @bootflows: List of available bootflows for this bootmethod
+ */
+struct bootmethod_uc_plat {
+	struct list_head bootflow_head;
+};
+
+extern struct bootflow_cmds g_bootflow_cmds;
+
+/**
+ * struct bootflow - information about a bootflow
+ *
+ * This is connected into two separate linked lists:
+ *
+ *   bm_sibling - links all bootflows in the same bootmethod
+ *   glob_sibling - links all bootflows in all bootmethods
+ *
+ * @bm_node: Points to siblings in the same bootmethod
+ * @glob_node: Points to siblings in the global list (all bootmethod)
+ * @dev: Bootmethod device which produced this bootflow
+ * @blk: Block device which contains this bootflow, NULL if this is a network
+ *	device
+ * @seq: Sequence number of bootflow within its bootmethod, typically the
+ *	partition number (0...)
+ * @name: Name of bootflow (allocated)
+ * @type: Bootflow type (enum bootflow_type_t)
+ * @state: Current state (enum bootflow_state_t)
+ * @part: Partition number
+ * @subdir: Subdirectory to fetch files from (with trailing /), or NULL if none
+ * @fname: Filename of bootflow file (allocated)
+ * @buf: Bootflow file contents (allocated)
+ * @size: Size of bootflow file in bytes
+ * @err: Error number received (0 if OK)
+ */
+struct bootflow {
+	struct list_head bm_node;
+	struct list_head glob_node;
+	struct udevice *dev;
+	struct udevice *blk;
+	int seq;
+	char *name;
+	enum bootflow_type_t type;
+	enum bootflow_state_t state;
+	int part;
+	char *subdir;
+	char *fname;
+	char *buf;
+	int size;
+	int err;
+};
+
+/**
+ * enum bootflow_flags_t - flags for the bootflow
+ *
+ * @BOOTFLOWF_FIXED: Only used fixed/internal media
+ * @BOOTFLOWF_SHOW: Show each bootmethod before scanning it
+ * @BOOTFLOWF_ALL: Return bootflows with errors as well
+ */
+enum bootflow_flags_t {
+	BOOTFLOWF_FIXED		= 1 << 0,
+	BOOTFLOWF_SHOW		= 1 << 1,
+	BOOTFLOWF_ALL		= 1 << 2,
+};
+
+/**
+ * struct bootmethod_iter - state for iterating through bootflows
+ *
+ * @flags: Flags to use (see enum bootflow_flags_t)
+ * @dev: Current bootmethod
+ * @seq: Current sequence number within that bootmethod (determines partition
+ *	number, for example)
+ */
+struct bootmethod_iter {
+	int flags;
+	struct udevice *dev;
+	int seq;
+};
+
+/**
+ * struct bootmethod_ops - Operations for the Platform Controller Hub
+ *
+ * Consider using ioctl() to add rarely used or driver-specific operations.
+ */
+struct bootmethod_ops {
+	/**
+	 * get_bootflow() - get a bootflow
+	 *
+	 * @dev:	Bootflow device to check
+	 * @seq:	Sequence number of bootflow to read (0 for first)
+	 * @bflow:	Returns bootflow if found
+	 * @return 0 if OK, -ESHUTDOWN if there are no more bootflows on this
+	 *	device, -ENOSYS if this device doesn't support bootflows,
+	 *	other -ve value on other error
+	 */
+	int (*get_bootflow)(struct udevice *dev, int seq,
+			    struct bootflow *bflow);
+};
+
+#define bootmethod_get_ops(dev)  ((struct bootmethod_ops *)(dev)->driver->ops)
+
+/**
+ * bootmethod_get_bootflow() - get a bootflow
+ *
+ * @dev:	Bootflow device to check
+ * @seq:	Sequence number of bootflow to read (0 for first)
+ * @bflow:	Returns bootflow if found
+ * @return 0 if OK, -ESHUTDOWN if there are no more bootflows on this device,
+ *	-ENOSYS if this device doesn't support bootflows, other -ve value on
+ *	other error
+ */
+int bootmethod_get_bootflow(struct udevice *dev, int seq,
+			    struct bootflow *bflow);
+
+/**
+ * bootmethod_scan_first_bootflow() - find the first bootflow
+ *
+ * This works through the available bootmethod devices until it finds one that
+ * can supply a bootflow. It then returns that
+ *
+ * If @flags includes BOOTFLOWF_ALL then bootflows with errors are returned too
+ *
+ * @iter:	Place to store private info (inited by this call)
+ * @flags:	Flags for bootmethod (enum bootflow_flags_t)
+ * @bflow:	Place to put the bootflow if found
+ * @return 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error
+ */
+int bootmethod_scan_first_bootflow(struct bootmethod_iter *iter, int flags,
+				   struct bootflow *bflow);
+
+/**
+ * bootmethod_scan_next_bootflow() - find the next bootflow
+ *
+ * This works through the available bootmethod devices until it finds one that
+ * can supply a bootflow. It then returns that bootflow
+ *
+ * @iter:	Private info (as set up by bootmethod_scan_first_bootflow())
+ * @bflow:	Place to put the bootflow if found
+ * @return 0 if found, -ESHUTDOWN if no more bootflows, -ve on error
+ */
+int bootmethod_scan_next_bootflow(struct bootmethod_iter *iter,
+				  struct bootflow *bflow);
+
+/**
+ * bootmethod_bind() - Bind a new named bootmethod device
+ *
+ * @parent:	Parent of the new device
+ * @drv_name:	Driver name to use for the bootmethod device
+ * @name:	Name for the device (parent name is prepended)
+ * @devp:	the new device (which has not been probed)
+ */
+int bootmethod_bind(struct udevice *parent, const char *drv_name,
+		    const char *name, struct udevice **devp);
+
+/**
+ * bootmethod_find_in_blk() - Find a bootmethod in a block device
+ *
+ * @dev: Bootflow device associated with this block device
+ * @blk: Block device to search
+ * @seq: Sequence number within block device, used as the partition number,
+ *	after adding 1
+ * @bflow:	Returns bootflow if found
+ * @return 0 if found, -ESHUTDOWN if no more bootflows, other -ve on error
+ */
+int bootmethod_find_in_blk(struct udevice *dev, struct udevice *blk, int seq,
+			   struct bootflow *bflow);
+
+/**
+ * bootmethod_list() - List all available bootmethods
+ *
+ * @probe: true to probe devices, false to leave them as is
+ */
+void bootmethod_list(bool probe);
+
+/**
+ * bootmethod_state_get_name() - Get the name of a bootflow state
+ *
+ * @state: State to check
+ * @return name, or "?" if invalid
+ */
+const char *bootmethod_state_get_name(enum bootflow_state_t state);
+
+/**
+ * bootmethod_type_get_name() - Get the name of a bootflow state
+ *
+ * @type: Type to check
+ * @return name, or "?" if invalid
+ */
+const char *bootmethod_type_get_name(enum bootflow_type_t type);
+
+/**
+ * bootmethod_get_state() - Get the (single) state for the bootmethod 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 bootmethod_get_state(struct bootflow_state **statep);
+
+/**
+ * bootmethod_clear_bootflows() - Clear bootflows from a bootmethod
+ *
+ * Each bootmethod maintains a list of discovered bootflows. This provides a
+ * way to clear it. These bootflows are removed from the global list too.
+ *
+ * @dev: bootmethod device to update
+ */
+void bootmethod_clear_bootflows(struct udevice *dev);
+
+/**
+ * bootmethod_clear_glob() - Clear the global list of bootflows
+ *
+ * This removes all bootflows globally and across all bootmethods.
+ */
+void bootmethod_clear_glob(void);
+
+/**
+ * bootmethod_add_bootflow() - Add a bootflow to the bootmethod's list
+ *
+ * All fields in @bflow must be set up. Note that @bflow->dev is used to add the
+ * bootflow to that device.
+ *
+ * @dev: Bootmethod device to add to
+ * @bflow: Bootflow to add. Note that fields within bflow must be allocated
+ *	since this function takes over ownership of these. This functions makes
+ *	a copy of @bflow itself (without allocating its fields again), so the
+ *	caller must dispose of the memory used by the @bflow pointer itself
+ * @return 0 if OK, -ENOMEM if out of memory
+ */
+int bootmethod_add_bootflow(struct bootflow *bflow);
+
+/**
+ * bootmethod_first_bootflow() - Get the first bootflow from a bootmethod
+ *
+ * Returns the first bootflow attached to a bootmethod
+ *
+ * @dev: bootmethod device
+ * @bflowp: Returns a pointer to the bootflow
+ * @return 0 if found, -ENOENT if there are no bootflows
+ */
+int bootmethod_first_bootflow(struct udevice *dev, struct bootflow **bflowp);
+
+/**
+ * bootmethod_next_bootflow() - Get the next bootflow from a bootmethod
+ *
+ * Returns the next bootflow attached to a bootmethod
+ *
+ * @bflowp: On entry, the last bootflow returned , e.g. from
+ *	bootmethod_first_bootflow()
+ * @return 0 if found, -ENOENT if there are no more bootflows
+ */
+int bootmethod_next_bootflow(struct bootflow **bflowp);
+
+/**
+ * bootflow_first_glob() - Get the first bootflow from the global list
+ *
+ * Returns the first bootflow in the global list, no matter what bootflow it is
+ * attached to
+ *
+ * @bflowp: Returns a pointer to the bootflow
+ * @return 0 if found, -ENOENT if there are no bootflows
+ */
+int bootflow_first_glob(struct bootflow **bflowp);
+
+/**
+ * bootflow_next_glob() - Get the next bootflow from the global list
+ *
+ * Returns the next bootflow in the global list, no matter what bootflow it is
+ * attached to
+ *
+ * @bflowp: On entry, the last bootflow returned , e.g. from
+ *	bootflow_first_glob()
+ * @return 0 if found, -ENOENT if there are no more bootflows
+ */
+int bootflow_next_glob(struct bootflow **bflowp);
+
+/**
+ * bootflow_free() - Free memory used by a bootflow
+ *
+ * This frees fields within @bflow, but not the @bflow pointer itself
+ */
+void bootflow_free(struct bootflow *bflow);
+
+/**
+ * bootflow_boot() - boot a bootflow
+ *
+ * @bflow: Bootflow to boot
+ * @return -EPROTO if bootflow has not been loaded, -ENOSYS if the bootflow
+ *	type is not supported, -EFAULT if the boot returned without an error
+ *	when we are expecting it to boot
+ */
+int bootflow_boot(struct bootflow *bflow);
+
+/**
+ * bootmethod_setup_for_dev() - Bind a new bootmethod device
+ *
+ * Creates a bootmethod device as a child of @parent. This should be called from
+ * the driver's bind() method or its uclass' post_bind() method.
+ *
+ * @parent: Parent device (e.g. MMC or Ethernet)
+ * @drv_name: Name of bootmethod driver to bind
+ * @return 0 if OK, -ve on error
+ */
+int bootmethod_setup_for_dev(struct udevice *parent, const char *drv_name);
+
+#endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index e7edd409f30..116d2f02f26 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_BOOTMETHOD,	/* Bootmethod for locating an OS to boot*/
 	UCLASS_BUTTON,		/* Button */
 	UCLASS_CACHE,		/* Cache controller */
 	UCLASS_CLK,		/* Clock source, e.g. used by peripherals */
-- 
2.33.0.rc1.237.g0d66db33f3-goog


  parent reply	other threads:[~2021-08-19  3:50 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-19  3:45 [PATCH 00/28] Initial implementation of bootmethod/bootflow Simon Glass
2021-08-19  3:45 ` [PATCH 01/28] Create a new boot/ directory Simon Glass
2021-08-19  3:45 ` [PATCH 02/28] pxe: Move API comments to the header files Simon Glass
2021-08-19  3:45 ` [PATCH 03/28] pxe: Use a context pointer Simon Glass
2021-08-19  3:45 ` [PATCH 04/28] pxe: Move do_getfile() into the context Simon Glass
2021-08-19  3:45 ` [PATCH 05/28] pxe: Add a userdata field to " Simon Glass
2021-08-19  3:45 ` [PATCH 06/28] pxe: Tidy up the is_pxe global Simon Glass
2021-08-19  3:45 ` [PATCH 07/28] pxe: Move pxe_utils files Simon Glass
2021-08-19  3:45 ` [PATCH 08/28] pxe: Tidy up some comments in pxe_utils Simon Glass
2021-08-19  3:45 ` [PATCH 09/28] pxe: Tidy up code style a little " Simon Glass
2021-08-19  3:45 ` [PATCH 10/28] pxe: Move common parsing coding into pxe_util Simon Glass
2021-08-19  3:45 ` [PATCH 11/28] pxe: Clean up the use of bootfile Simon Glass
2021-08-19  3:45 ` [PATCH 12/28] pxe: Drop get_bootfile_path() Simon Glass
2021-08-19  3:45 ` [PATCH 13/28] lib: Add tests for simple_itoa() Simon Glass
2021-08-19  3:45 ` [PATCH 14/28] lib: Add a function to convert a string to a hex value Simon Glass
2021-08-19  3:45 ` [PATCH 15/28] pxe: Return the file size from the getfile() function Simon Glass
2021-08-19  3:45 ` [PATCH 16/28] pxe: Refactor sysboot to have one helper Simon Glass
2021-08-19  3:45 ` [PATCH 17/28] doc: Move distro boot doc to rST Simon Glass
2021-08-19  3:45 ` [PATCH 18/28] pxe: Allow calling the pxe_get logic directly Simon Glass
2021-08-19  3:45 ` Simon Glass [this message]
2021-08-19  3:45 ` [PATCH 20/28] bootmethod: Add an implementation of distro boot Simon Glass
2021-08-19  3:45 ` [PATCH 21/28] bootmethod: Add a command Simon Glass
2021-08-19  3:45 ` [PATCH 22/28] bootflow: " Simon Glass
2021-08-19  3:45 ` [PATCH 23/28] bootmethod: Add tests for bootmethod and bootflow Simon Glass
2021-08-19  3:45 ` [PATCH 24/28] bootmethod: doc: Add documentation Simon Glass
2021-08-19  3:45 ` [PATCH 25/28] mmc: Allow for children other than the block device Simon Glass
2021-08-19  3:45 ` [PATCH 26/28] mmc: Add a bootmethod Simon Glass
2021-08-19  3:46 ` [PATCH 27/28] ethernet: " Simon Glass
2021-08-19  3:46 ` [PATCH 28/28] RFC: rpi: Switch over to use bootflow Simon Glass
2021-08-19 13:59 ` [PATCH 00/28] Initial implementation of bootmethod/bootflow Tom Rini
2021-08-19 14:25   ` Simon Glass
2021-08-19 17:27     ` Tom Rini
2021-08-23 12:35       ` Ilias Apalodimas
2021-08-23 17:25         ` Simon Glass
2021-08-23 20:08           ` Tom Rini
2021-08-24  9:29             ` Ilias Apalodimas
2021-08-25 13:11               ` Simon Glass
2021-08-25 13:29                 ` Peter Robinson
2021-08-25 21:34                   ` Mark Kettenis
2021-08-25 21:58                     ` Tom Rini
2021-08-20  3:15     ` AKASHI Takahiro
2021-08-20 18:22       ` Simon Glass
2021-08-23  0:46         ` AKASHI Takahiro
2021-08-23 11:54 ` Mark Kettenis
2021-08-23 17:25   ` Simon Glass
2021-08-23 20:01     ` Tom Rini
2021-08-24 10:22       ` Mark Kettenis
2021-08-25 10:45         ` Emmanuel Vadot
2021-08-25 13:11           ` Simon Glass
2021-08-25 14:42             ` AKASHI Takahiro
2021-08-25 14:56               ` Tom Rini
2021-08-25 21:54                 ` Mark Kettenis
2021-08-25 22:06                   ` Tom Rini
2021-08-26  6:33                     ` AKASHI Takahiro
2021-08-26 13:03                       ` Tom Rini
2021-08-26 12:01                     ` Mark Kettenis
2021-08-26 13:00                       ` Tom Rini
2021-08-26 13:32                         ` Mark Kettenis
2021-08-26 13:50                           ` Ilias Apalodimas
2021-08-26 11:55                 ` Peter Robinson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210818214547.19.I3b5bc09d034cd72b2a9c604a0907c10abc05956a@changeid \
    --to=sjg@chromium.org \
    --cc=daniel.schwierzeck@gmail.com \
    --cc=dennis@ausil.us \
    --cc=ilias.apalodimas@linaro.org \
    --cc=jaeckel-floss@eyet-services.de \
    --cc=lukas.auer@aisec.fraunhofer.de \
    --cc=michal.simek@xilinx.com \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.