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(-)
@@ -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);
@@ -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)
@@ -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
------
@@ -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 {
@@ -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
*