[Concept,06/14] bootstd: Add free_bootflow() method for bootmeths

Message ID 20260322235719.1729267-7-sjg@u-boot.org
State New
Headers
Series bootstd: Infrastructure for multi-entry bootflow support |

Commit Message

Simon Glass March 22, 2026, 11:57 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add a free_bootflow() op to struct bootmeth_ops so bootmeths can free
internal allocations within bflow->bootmeth_priv. The
bootmeth_free_bootflow() stub calls the op if provided, then always
frees bootmeth_priv itself and sets it to NULL. This means drivers only
need to free sub-allocations, not the priv struct.

Update bootflow_free() to use the stub when a method is set.

Document the bootmeth_priv lifecycle in overview.rst and bootflow.h.

No drivers implement the op yet; the fallback to free() preserves the
existing behaviour.

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

 boot/bootflow.c                  |  4 +++-
 boot/bootmeth-uclass.c           | 10 ++++++++++
 doc/develop/bootstd/overview.rst |  7 +++++++
 include/bootflow.h               |  4 +++-
 include/bootmeth.h               | 24 ++++++++++++++++++++++++
 5 files changed, 47 insertions(+), 2 deletions(-)
  

Patch

diff --git a/boot/bootflow.c b/boot/bootflow.c
index 4a55cc637fa..d6549b5ce9a 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -726,7 +726,9 @@  void bootflow_free(struct bootflow *bflow)
 		free(bflow->buf);
 	free(bflow->os_name);
 	free(bflow->fdt_fname);
-	free(bflow->bootmeth_priv);
+	/* bootmeth_priv is only set when method is set */
+	if (bflow->method)
+		bootmeth_free_bootflow(bflow->method, bflow);
 
 	alist_for_each(img, &bflow->images)
 		free(img->fname);
diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c
index 5e0badfc7a9..0ca3e8fca32 100644
--- a/boot/bootmeth-uclass.c
+++ b/boot/bootmeth-uclass.c
@@ -84,6 +84,16 @@  int bootmeth_boot(struct udevice *dev, struct bootflow *bflow)
 	return ops->boot(dev, bflow);
 }
 
+void bootmeth_free_bootflow(struct udevice *dev, struct bootflow *bflow)
+{
+	const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
+
+	if (ops->free_bootflow)
+		ops->free_bootflow(dev, bflow);
+	free(bflow->bootmeth_priv);
+	bflow->bootmeth_priv = NULL;
+}
+
 int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow,
 		       const char *file_path, ulong *addrp, ulong align,
 		       enum bootflow_img_t type, ulong *sizep)
diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst
index 3e3b502460d..0ff4868ba44 100644
--- a/doc/develop/bootstd/overview.rst
+++ b/doc/develop/bootstd/overview.rst
@@ -855,6 +855,13 @@  list of scanned bootflows just for that device.
 The bootflow itself is documented in bootflow_h_. It includes various bits of
 information about the bootflow and a buffer to hold the file.
 
+The ``bootmeth_priv`` field allows a bootmeth to attach private data to each
+bootflow, such as parsed configuration state. When the bootflow is freed,
+``bootmeth_free_bootflow()`` calls the bootmeth's ``free_bootflow()`` op (if
+provided) to free internal allocations, then frees ``bootmeth_priv`` itself.
+Bootmeths that only store a flat struct in ``bootmeth_priv`` do not need to
+implement the op.
+
 
 Future
 ------
diff --git a/include/bootflow.h b/include/bootflow.h
index 6c6f07db97d..65aebefd3b3 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -98,7 +98,9 @@  enum bootflow_flags_t {
  * @luks_version: LUKS version (1 or 2) if BOOTFLOWF_ENCRYPTED is set, else 0
  * @cmdline: OS command line, or NULL if not known (allocated)
  * @x86_setup: Pointer to x86 setup block inside @buf, NULL if not present
- * @bootmeth_priv: Private data for the bootmeth
+ * @bootmeth_priv: Private data for the bootmeth (allocated). Freed by
+ *	bootmeth_free_bootflow() which calls the bootmeth's free_bootflow() op
+ *	for internal cleanup, then frees the pointer itself.
  * @images: List of loaded images (struct bootstd_img)
  */
 struct bootflow {
diff --git a/include/bootmeth.h b/include/bootmeth.h
index b5288843d03..2cc8b690bbf 100644
--- a/include/bootmeth.h
+++ b/include/bootmeth.h
@@ -155,6 +155,19 @@  struct bootmeth_ops {
 	 */
 	int (*boot)(struct udevice *dev, struct bootflow *bflow);
 
+	/**
+	 * free_bootflow() - free bootmeth-private data in a bootflow
+	 *
+	 * This is called from bootmeth_free_bootflow() to allow the bootmeth
+	 * to free any internal allocations within bflow->bootmeth_priv. The
+	 * caller handles free(bflow->bootmeth_priv) afterwards, so the op
+	 * should not free the priv struct itself.
+	 *
+	 * @dev:	Bootmethod device
+	 * @bflow:	Bootflow being freed
+	 */
+	void (*free_bootflow)(struct udevice *dev, struct bootflow *bflow);
+
 	/**
 	 * set_property() - set the bootmeth property
 	 *
@@ -309,6 +322,17 @@  int bootmeth_boot(struct udevice *dev, struct bootflow *bflow);
  */
 int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global);
 
+/**
+ * bootmeth_free_bootflow() - free bootmeth-private data in a bootflow
+ *
+ * Calls the bootmeth's free_bootflow() op if provided to free internal
+ * allocations, then frees bflow->bootmeth_priv and sets it to NULL.
+ *
+ * @dev:	Bootmethod device
+ * @bflow:	Bootflow being freed
+ */
+void bootmeth_free_bootflow(struct udevice *dev, struct bootflow *bflow);
+
 /**
  * bootmeth_set_order() - Set the bootmeth order
  *