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(-) 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 * -- 2.43.0