Hi Daniel,

On Mon, 16 Feb 2026 at 14:22, Daniel Golle <[email protected]> wrote:
>
> Add a UBI volume storage backend for the image_loader framework.
>
> image_loader_init_ubi() takes a volume name, ensures the UBI device
> is attached (auto-attaching if needed), and installs a .read() callback
> wrapping ubi_volume_read().
>
> Auto-attach works by scanning the device tree for the first MTD
> partition with compatible = "linux,ubi", then calling ubi_part() on
> that partition. The partition name is resolved using the same
> precedence as the MTD partition parser: the "label" property first,
> then "name", then the node name. Since U-Boot only supports a single
> attached UBI device at a time, only the first matching partition is
> used. If a UBI device is already attached, the auto-attach step is
> skipped.
>
> UBI handles bad-block management and wear leveling internally, so the
> read callback is a straightforward passthrough. Note that
> ubi_volume_read() returns positive errno values; the wrapper negates
> them for the image_loader convention.
>
> Gated by CONFIG_IMAGE_LOADER_UBI (depends on CMD_UBI && IMAGE_LOADER).
>
> Signed-off-by: Daniel Golle <[email protected]>
> ---
>  boot/Kconfig            |   8 +++
>  boot/Makefile           |   1 +
>  boot/image-loader-ubi.c | 112 ++++++++++++++++++++++++++++++++++++++++
>  include/image-loader.h  |  13 +++++
>  4 files changed, 134 insertions(+)
>  create mode 100644 boot/image-loader-ubi.c
>
> diff --git a/boot/Kconfig b/boot/Kconfig
> index 23848a0f57e..89832014af6 100644
> --- a/boot/Kconfig
> +++ b/boot/Kconfig
> @@ -1203,6 +1203,14 @@ config IMAGE_LOADER_MTD
>           parallel NAND, etc.) using the image_loader framework.
>           NAND bad blocks are skipped transparently.
>
> +config IMAGE_LOADER_UBI
> +       bool "UBI volume backend for image loader"
> +       depends on IMAGE_LOADER && CMD_UBI
> +       help
> +         Allows loading images from UBI volumes using the image_loader
> +         framework. Auto-attaches the UBI device from the device tree
> +         if not already attached.
> +
>  config DISTRO_DEFAULTS
>         bool "(deprecated) Script-based booting of Linux distributions"
>         select CMDLINE
> diff --git a/boot/Makefile b/boot/Makefile
> index 1dde16db694..7d1d4a28106 100644
> --- a/boot/Makefile
> +++ b/boot/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_$(PHASE_)BOOTMETH_ANDROID) += 
> bootmeth_android.o
>  obj-$(CONFIG_IMAGE_LOADER) += image-loader.o
>  obj-$(CONFIG_IMAGE_LOADER_BLK) += image-loader-blk.o
>  obj-$(CONFIG_IMAGE_LOADER_MTD) += image-loader-mtd.o
> +obj-$(CONFIG_IMAGE_LOADER_UBI) += image-loader-ubi.o
>
>  obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_ABREC) += vbe_abrec.o vbe_common.o
>  obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_ABREC_FW) += vbe_abrec_fw.o
> diff --git a/boot/image-loader-ubi.c b/boot/image-loader-ubi.c
> new file mode 100644
> index 00000000000..64901a13378
> --- /dev/null
> +++ b/boot/image-loader-ubi.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * UBI volume backend for image_loader
> + *
> + * Copyright (C) 2026 Daniel Golle <[email protected]>
> + */
> +
> +#include <dm/ofnode.h>
> +#include <image-loader.h>
> +#include <log.h>
> +#include <malloc.h>
> +#include <mtd.h>
> +#include <ubi_uboot.h>
> +
> +struct image_loader_ubi_priv {
> +       char *vol_name;
> +};
> +
> +/**
> + * ubi_auto_attach() - attach UBI if not already attached
> + *
> + * If no UBI device is currently attached, walk the device tree for the
> + * first MTD partition node with compatible = "linux,ubi", find the
> + * corresponding MTD device by matching flash_node, and attach UBI to
> + * it via ubi_part_from_mtd().
> + *
> + * Since U-Boot only supports a single attached UBI device at a time,
> + * only the first matching partition is used.
> + *
> + * Return: 0 on success or if already attached, negative errno on failure
> + */
> +static int ubi_auto_attach(void)
> +{
> +       struct mtd_info *mtd;
> +       ofnode node;
> +
> +       /* Already attached? */
> +       if (ubi_devices[0])
> +               return 0;
> +
> +       mtd_probe_devices();

This should be handled by your new ubi driver for your uclass.

> +
> +       ofnode_for_each_compatible_node(node, "linux,ubi") {
> +               mtd_for_each_device(mtd) {
> +                       if (ofnode_equal(mtd->flash_node, node))
> +                               goto found;
> +               }
> +       }

Eek this is really strange. There should be a device so you can use
uclass_first_device(UCLASS_...).

> +
> +       log_err("image_loader_ubi: no MTD device for \"linux,ubi\" node\n");
> +       return -ENODEV;
> +
> +found:
> +       if (ubi_part_from_mtd(mtd)) {
> +               log_err("image_loader_ubi: failed to attach UBI on \"%s\"\n",
> +                       mtd->name);
> +               return -EIO;
> +       }
> +
> +       return 0;
> +}
> +
> +static int image_loader_ubi_read(struct image_loader *ldr, ulong src,
> +                                ulong size, void *dst)
> +{
> +       struct image_loader_ubi_priv *priv = ldr->priv;
> +       int ret;
> +
> +       ret = ubi_volume_read(priv->vol_name, dst, src, size);
> +       /* ubi_volume_read() returns positive errno values on error */

blank line before final return

> +       return ret ? -ret : 0;
> +}
> +
> +static void image_loader_ubi_cleanup(struct image_loader *ldr)
> +{
> +       struct image_loader_ubi_priv *priv = ldr->priv;
> +
> +       free(priv->vol_name);
> +       free(priv);
> +}
> +
> +int image_loader_init_ubi(struct image_loader *ldr, const char *vol_name)
> +{
> +       struct image_loader_ubi_priv *priv;
> +       int ret;
> +
> +       ret = ubi_auto_attach();
> +       if (ret)
> +               return ret;
> +
> +       if (!ubi_find_volume(vol_name)) {
> +               log_err("image_loader_ubi: volume \"%s\" not found\n",
> +                       vol_name);
> +               return -ENODEV;
> +       }
> +
> +       priv = malloc(sizeof(*priv));
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->vol_name = strdup(vol_name);
> +       if (!priv->vol_name) {
> +               free(priv);
> +               return -ENOMEM;
> +       }
> +
> +       ldr->read = image_loader_ubi_read;
> +       ldr->cleanup = image_loader_ubi_cleanup;
> +       ldr->priv = priv;
> +
> +       return 0;
> +}
> diff --git a/include/image-loader.h b/include/image-loader.h
> index 7ccf901d37d..a036e98982f 100644
> --- a/include/image-loader.h
> +++ b/include/image-loader.h
> @@ -172,4 +172,17 @@ int image_loader_init_blk(struct image_loader *ldr, 
> const char *ifname,
>   */
>  int image_loader_init_mtd(struct image_loader *ldr, const char *name);
>
> +/**
> + * image_loader_init_ubi() - Initialise loader for a UBI volume
> + *
> + * Ensures a UBI device is attached (auto-attaching from the device
> + * tree if needed), verifies the named volume exists, then installs a
> + * .read() callback wrapping ubi_volume_read().
> + *
> + * @ldr:       The image loader to initialise
> + * @vol_name:  UBI volume name
> + * Return: 0 on success, negative errno on failure
> + */
> +int image_loader_init_ubi(struct image_loader *ldr, const char *vol_name);
> +
>  #endif /* __IMAGE_LOADER_H */
> --
> 2.53.0

Regards,
SImon

Reply via email to