[RFC PATCH 00/20] boot: add OpenWrt boot method and on-demand FIT loading
Simon Glass
sjg at chromium.org
Tue Feb 17 14:32:12 CET 2026
Hi Daniel,
On Mon, 16 Feb 2026 at 14:21, Daniel Golle <daniel at makrotopia.org> wrote:
>
> Hi all,
>
> This RFC series adds a new boot method for OpenWrt's "uImage.FIT with
> embedded rootfs" firmware model, along with the underlying infrastructure
> to load FIT images on-demand directly from storage devices without copying
> them entirely to RAM first.
>
> I would like to discuss the design with U-Boot maintainers and fellow
> OpenWrt developers before submitting a formal patch series.
>
> Background: Why OpenWrt needs its own boot method
> ==================================================
>
> OpenWrt's modern embedded boot model uses a single uImage.FIT container
> that includes the Linux kernel, device tree, and a read-only root
> filesystem (squashfs or more recently erofs).
>
> At boot, the kernel maps the embedded squashfs directly from flash as a
> block device (/dev/fit0 via the fitblk driver[1]). No separate boot
> partition, boot filesystem, or initrd is required.
>
> This creates a monolithic, deterministic, flash-native firmware image that
> is fundamentally different from what U-Boot's existing boot methods
> (distroboot, EFI, extlinux) are designed for. Those methods assume:
>
> - A partition table with a boot filesystem (FAT ESP, ext4 /boot)
> - Kernel and initrd as separate files on that filesystem
> - Mutable boot state managed by filesystem metadata
> - Multi-OS flexibility on replaceable storage
>
> OpenWrt's model assumes:
>
> - A single-flash embedded appliance with no removable storage
> - One immutable firmware blob per slot
> - No boot filesystem at all
> - Boot-medium agnostic deployment (the same .itb image works on eMMC,
> SD, SPI-NOR, SPI-NAND/UBI, and raw NAND)
>
> [1]: https://github.com/openwrt/openwrt/blob/30ac12f4b4682207c5b0501b3ffc50d56f58b690/target/linux/generic/pending-6.12/510-block-add-uImage.FIT-subimage-block-driver.patch
>
> One image for all use cases
> ===========================
>
> The same .itb image can be:
>
> - Used as a sysupgrade image inside a running OpenWrt system
> - Flashed from U-Boot via TFTP or HTTP
> - Written to an eMMC or SD partition via dd
> - Stored in a UBI volume (SPI-NAND, raw NAND)
> - Stored in a raw MTD partition (SPI-NOR, parallel NOR)
>
> It is entirely boot-medium agnostic. UEFI and distroboot by contrast
> assume a block-oriented storage device with a specific partition layout
> and boot filesystem, and cannot easily be used on raw flash devices or
> UBI.
>
> Why boot filesystems are a problem for embedded
> ===============================================
>
> Boot filesystems (FAT ESPs, ext4 /boot) introduce:
>
> - Metadata corruption risks on power loss
> - fsck requirements after unclean shutdown
> - State drift across firmware upgrades
> - A structural single point of failure
>
> These are not theoretical concerns. OpenWrt is deployed in telecom
> infrastructure, industrial control systems, and ISP CPE devices —
> environments where thousands (sometimes millions) of devices must boot
> and receive software updates reliably for years without physical
> access. A corrupted FAT partition on a rooftop wireless backhaul
> device can mean a truck roll, in a private home often means scheduling
> a costly visit by the ISPs service team.
>
> The FIT-with-rootfs model eliminates this entire failure class:
>
> - No filesystem metadata to corrupt
> - No fsck needed after power loss
> - No mutable boot artifacts
> - Bit-identical system partitions across the entire fleet
>
> This is critical for QA reproducibility, telecom deployments, and any
> fleet where deterministic firmware state is a hard requirement.
>
> Reduced failure surface
> =======================
>
> A typical UEFI / distroboot path:
>
> Bootloader -> Filesystem driver -> Directory traversal -> File read
> -> Kernel -> Initrd -> Pivot to rootfs
>
> The OpenWrt uImage.FIT path:
>
> Bootloader -> Read FIT blob from partition -> Kernel
> -> squashfs/erofs rootfs mapped from same blob
>
> Fewer parsing stages mean fewer corruption vectors and lower boot-path
> complexity. The boot chain is shorter and each step is simpler.
>
> Secure boot friendly
> ====================
>
> FIT natively supports cryptographic signatures and verified boot chains.
> Because kernel, DTB, and rootfs are inside the same signed container,
> they are verified together — no unsigned kernel swapping, no mismatched
> kernel/rootfs pairs. This is structurally cleaner than verifying
> separate files scattered across a boot filesystem.
>
> Real-world adoption
> ===================
>
> This boot method is not a theoretical proposal — it is already the
> standard production boot method for a large number of shipping devices.
>
> In OpenWrt's MediaTek Filogic target alone, over 40 boards use
> fit_do_upgrade() for their primary firmware upgrade path. See
> target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh in
> openwrt.git for the full list.
>
> Beyond MediaTek, the SiFlower SF21-based BananaPi BPi-RV2 (NAND) also
> uses this exact method. Countless additional boards use minor variations,
> for example, appending the squashfs blob after the uImage.FIT container
> instead of using an IH_TYPE_FILESYSTEM uImage.FIT sub-image.
>
> Production / recovery architecture
> ===================================
>
> The slot configuration in this series supports:
>
> - A production FIT image
> - A recovery FIT image
> - Separate persistent data partition
>
> Recovery can reflash production remotely and preserve configuration.
> This dual-slot model — which Android eventually adopted for similar
> embedded constraints — is a natural fit for the OpenWrt deployment
> model.
>
> Why existing boot methods cannot be reused
> ==========================================
>
> 1. distroboot / extlinux: Require a boot filesystem containing
> extlinux.conf. OpenWrt avoids using a boot filesystem.
>
> 2. EFI: Requires an EFI System Partition with a PE binary. OpenWrt's
> firmware is a flat FIT blob, not an EFI application. EFI also mandates
> booting from a block-oriented storage device or PXE, while devices
> supported by OpenWrt often come with SPI-NAND or SPI-NOR flash,
> sometimes as little as 32 MiB in total.
>
> 3. script-based sf_bootdev: Reads a boot script from a fixed offset in
> SPI flash. It does not understand partitions, does not iterate MTD
> or UBI devices, and does not support FIT image detection.
>
> 4. On-demand loading: None of the existing methods support loading FIT
> subimages directly from storage. OpenWrt's FIT images typically
> contain a 5-20 MB squashfs that does NOT need to be copied to RAM —
> the kernel maps it directly from flash. The bootloader only needs
> to load the kernel and DTB (~5-10 MB), not the entire 20-50 MB
> container. This requires a new loading abstraction.
>
> What this series adds
> =====================
>
> The series is structured in two logical parts:
>
> Part 1: On-demand FIT loading infrastructure (patches 1-12)
> -----------------------------------------------------------
>
> A new image_loader abstraction that provides a read callback for loading
> data from storage on demand, rather than requiring the entire image to
> reside in RAM. This is wired into fit_image_load() so that bootm can
> load individual FIT subimages directly from block devices, MTD
> partitions, or UBI volumes.
>
> Three storage backends:
>
> - Block device (eMMC, SD, SATA, NVMe, USB mass storage, virtio)
> - MTD (SPI-NOR, raw NOR, raw NAND with bad block skipping)
> - UBI volume (SPI-NAND, raw NAND)
>
> The "bootm" command is extended to accept a storage device specification
> instead of a RAM address:
>
> bootm mmc 0:4 # boot FIT from eMMC partition 4
> bootm mtd recovery # boot FIT from MTD partition "recovery"
> bootm ubi recovery # boot FIT from UBI volume "recovery"
>
> This infrastructure is independently useful beyond the OpenWrt boot
> method. Any board that stores a FIT image directly in a partition
> (rather than as a file on a filesystem) can benefit from on-demand
> subimage loading.
>
> Part 2: OpenWrt boot method and bootdevs (patches 13-20)
> ---------------------------------------------------------
>
> A proper bootstd boot method (bootmeth_openwrt) that:
>
> - Scans block device partitions, MTD partitions, and UBI volumes
> for raw FIT images (detected by fdt_check_header on the first bytes)
> - Boots via the image_loader / bootm storage path
> - Supports configurable dual-slot boot (production + recovery) via
> environment variables
> - Provides a script hook (openwrt_boot_script) for boards that need
> to probe hardware before selecting the FIT configuration
>
> Two new boot devices are introduced:
>
> - mtd_bootdev: Iterates MTD partitions. A hunt callback walks the
> MTD subsystem device list to bind bootdevs for both UCLASS_MTD
> (SPI-NAND) and UCLASS_SPI_FLASH (SPI-NOR) devices.
>
> - ubi_bootdev: Auto-attaches UBI from DT (compatible = "linux,ubi")
> and iterates UBI volumes.
>
> The boot method integrates with bootstd's existing scan/priority
> framework. "bootflow scan" discovers OpenWrt firmware on all attached
> storage, and "bootflow boot" boots the first valid one — exactly like
> distroboot or EFI, but for raw FIT images.
>
> Slot configuration example:
>
> openwrt_slot_production=firmware
> openwrt_slot_recovery=recovery
> openwrt_boot_order=production recovery
>
> This enables production/recovery dual-boot, boot-loop detection (planned
> for a future series via pstore), and boot menu integration.
>
> Testing
> =======
>
> The BananaPi BPi-R3 (MT7986) is the ideal demonstration device for this
> series because it is the only commonly available board that exposes all
> four storage types — SPI-NOR, SPI-NAND, eMMC, and a microSD slot — and
> can boot from any of them using the very same uImage.FIT image. This
> makes it possible to test every image_loader backend and the full
> cross-media boot flow on a single board.
>
> - sandbox: unit tests for image_loader
> - BananaPi BPi-R3 (MT7986): real hardware testing with SPI-NOR,
> SPI-NAND (UBI), eMMC, and SD card — including combinations of
> present/absent flash devices and deliberate probe failures
>
> Patch overview
> ==============
>
> On-demand FIT loading (generic infrastructure):
>
> 01/20 boot: add image_loader on-demand loading abstraction
> 02/20 boot: image-loader: add block device backend
> 03/20 mtd: add mtd_read_skip_bad() helper
> 04/20 boot: image-loader: add MTD backend
> 05/20 cmd: ubi: export ubi_find_volume()
> 06/20 mtd: set flash_node on DT-created partitions
> 07/20 cmd: ubi: add ubi_part_from_mtd()
> 08/20 boot: image-loader: add UBI volume backend
> 09/20 boot: fit: support on-demand loading in fit_image_load()
> 10/20 cmd: bootm: accept storage device as image source
> 11/20 test: boot: add image_loader unit tests
> 12/20 doc: bootm: document direct storage boot
>
> OpenWrt boot method:
>
> 13/20 boot: bootmeth: add OpenWrt boot method skeleton
> 14/20 boot: bootmeth: openwrt: implement read_bootflow for block devices
> 15/20 boot: bootmeth: openwrt: implement boot via bootm storage path
> 16/20 boot: bootdev: add MTD boot device
> 17/20 boot: bootdev: add UBI boot device
> 18/20 boot: bootmeth: openwrt: support MTD and UBI bootdevs
> 19/20 boot: bootmeth: openwrt: add openwrt_boot_script hook for bootconf
> 20/20 boot: bootmeth: openwrt: add slot configuration from environment
>
> Diffstat summary:
>
> 29 files changed, 2666 insertions(+), 45 deletions(-)
>
> Planned future work
> ===================
>
> - pstore-based boot state tracking for automatic fallback to recovery
> after repeated boot failures and boot-loop avoidance
> - Comprehensive documentation and board migration guide
> - dm-verity integration for runtime integrity verification of the
> rootfs image, complementing FIT signature verification at boot
> - Board enablement patches for MediaTek (MT7986, MT7981, MT7988),
> Qualcomm (IPQ807x, IPQ60xx), and other OpenWrt-supported SoCs
>
> Comments, questions, and review very much appreciated.
Thanks for the detailed explanation. This seems fine to me and I
suspect it will be useful elsewhere. I will take a look at the patches
this week.
>
> AI tool disclosure
> ==================
>
> Major parts of this series were developed with assistance from GitHub
> Copilot (Claude Opus 4.6, Anthropic). The AI was used as a coding
> partner for scaffolding boilerplate, drafting documentation and commit
> messages, running checkpatch sweeps, and iterating on review feedback.
> All architectural decisions, U-Boot subsystem integration, hardware
> testing, and final review were done by the human author. Every line of
> code was reviewed and tested on real hardware before inclusion.
Regards,
Simon
>
>
> Cheers
>
>
> Daniel
>
>
> Daniel Golle (20):
> boot: add image_loader on-demand loading abstraction
> boot: image-loader: add block device backend
> mtd: add mtd_read_skip_bad() helper
> boot: image-loader: add MTD backend
> cmd: ubi: export ubi_find_volume()
> mtd: set flash_node on DT-created partitions
> cmd: ubi: add ubi_part_from_mtd()
> boot: image-loader: add UBI volume backend
> boot: fit: support on-demand loading in fit_image_load()
> cmd: bootm: accept storage device as image source
> test: boot: add image_loader unit tests
> doc: bootm: document direct storage boot
> boot: bootmeth: add OpenWrt boot method skeleton
> boot: bootmeth: openwrt: implement read_bootflow for block devices
> boot: bootmeth: openwrt: implement boot via bootm storage path
> boot: bootdev: add MTD boot device
> boot: bootdev: add UBI boot device
> boot: bootmeth: openwrt: support MTD and UBI bootdevs
> boot: bootmeth: openwrt: add openwrt_boot_script hook for bootconf
> boot: bootmeth: openwrt: add slot configuration from environment
>
> boot/Kconfig | 88 +++++++
> boot/Makefile | 8 +
> boot/bootm.c | 62 ++++-
> boot/bootmeth_openwrt.c | 248 +++++++++++++++++++
> boot/image-fit.c | 96 ++++++++
> boot/image-loader-blk.c | 133 ++++++++++
> boot/image-loader-mtd.c | 103 ++++++++
> boot/image-loader-ubi.c | 112 +++++++++
> boot/image-loader.c | 163 +++++++++++++
> boot/mtd_bootdev.c | 150 ++++++++++++
> boot/ubi_bootdev.c | 180 ++++++++++++++
> cmd/bootm.c | 148 +++++++++++-
> cmd/mtd.c | 65 ++---
> cmd/ubi.c | 33 ++-
> doc/develop/bootm-storage.rst | 210 ++++++++++++++++
> doc/develop/index.rst | 1 +
> doc/usage/fit/index.rst | 1 +
> doc/usage/fit/storage-boot.rst | 201 +++++++++++++++
> drivers/mtd/mtd-uclass.c | 15 ++
> drivers/mtd/mtdcore.c | 45 ++++
> drivers/mtd/mtdpart.c | 2 +
> include/bootm.h | 2 +
> include/image-loader.h | 188 +++++++++++++++
> include/image.h | 4 +
> include/linux/mtd/mtd.h | 24 ++
> include/ubi_uboot.h | 2 +
> test/boot/Makefile | 2 +
> test/boot/image_loader.c | 429 +++++++++++++++++++++++++++++++++
> test/cmd_ut.c | 2 +
> 29 files changed, 2673 insertions(+), 44 deletions(-)
> create mode 100644 boot/bootmeth_openwrt.c
> create mode 100644 boot/image-loader-blk.c
> create mode 100644 boot/image-loader-mtd.c
> create mode 100644 boot/image-loader-ubi.c
> create mode 100644 boot/image-loader.c
> create mode 100644 boot/mtd_bootdev.c
> create mode 100644 boot/ubi_bootdev.c
> create mode 100644 doc/develop/bootm-storage.rst
> create mode 100644 doc/usage/fit/storage-boot.rst
> create mode 100644 include/image-loader.h
> create mode 100644 test/boot/image_loader.c
>
> --
> 2.53.0
Regards,
Simon
More information about the U-Boot
mailing list