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(); + + ofnode_for_each_compatible_node(node, "linux,ubi") { + mtd_for_each_device(mtd) { + if (ofnode_equal(mtd->flash_node, node)) + goto found; + } + } + + 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 */ + 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

