U-Boot’s standard boot framework (bootstd) discovers operating systems by scanning partitions for bootflow files. Until now, each partition could contribute at most one bootflow per bootmeth. In practice, formats like extlinux can define several labels in a single configuration file – each pointing to a different kernel – and BLS (Boot Loader Specification) installations can have multiple .conf files in loader/entries/ – all of these are invisible to the scanner; users only saw a single bootflow and had to navigate a menu at boot time to pick one.
Two new patch series change this, making every boot option visible during scanning.
Background
This work builds on two earlier efforts that laid the foundation for cleaner boot handling in U-Boot.
The first, A Three-Phase PXE: Cleaning Up the Boot Process, restructured the PXE/extlinux boot path into distinct parse, load and boot phases. This separation made it possible to parse a configuration file during scanning without immediately booting, which is essential for discovering multiple labels.
The second, BLS Comes to U-Boot: A New Bootmeth, added a Boot Loader Specification Type #1 bootmeth. BLS defines a directory of .conf entry files, each describing a separate kernel – a natural fit for multi-entry scanning once the infrastructure was in place.
With these pieces in place, the remaining work was to teach the bootflow iterator about multiple entries per partition and to wire it up in the extlinux and BLS bootmeths.
Infrastructure
The first series lays the groundwork with several independent improvements.
Iterator bug fixes. Two long-standing inconsistencies in bootflow_scan_first() and bootflow_scan_next() left iter->err in an unreliable state. The first function didn’t set iter->err before returning early for BOOTFLOWIF_ALL, and the second never cleared it on success. Both are now fixed, which is a prerequisite for the multi-entry iteration logic.
Bootmeth cleanup. A new free_bootflow() method in struct bootmeth_ops lets bootmeths properly clean up bflow->bootmeth_priv when a bootflow is freed. Previously bootflow_free() just called free(), which leaked internal allocations in the ChromiumOS, Android, and RAUC drivers. Each now implements the op to free its sub-allocations, while the framework handles freeing the outer struct.
Extlinux refactoring. The PXE context, previously embedded in platform data, is moved to a new struct extlinux_priv and passed explicitly to extlinux_boot() and extlinux_read_all(). This separates configuration from runtime state and makes it possible for each bootflow to have its own context.
Context alist. The single PXE context is replaced with an alist of contexts, one per parsed configuration file. A new bootmeth_id field on struct bootflow (initialised to -1) lets boot and read-all locate the correct context from the alist. The probe() and remove() functions manage the alist lifecycle. alist_add_placeholder() now zeroes new entries, helping to avoid uninitialised-memory bugs in callers.
Multi-entry scanning (booe series)
The second series adds the feature itself.
BOOTMETHF_MULTI flag. A new flag in enum bootmeth_flags declares that a bootmeth can produce multiple bootflows from a single partition. When set, iter_incr() increments the entry index before advancing to the next method. The entry index is passed to read_bootflow() via bflow->entry
Extlinux multi-entry. The extlinux bootmeth sets BOOTMETHF_MULTI and uses pxe_parse() to extract each label’s name during scanning. The extlinux_fill_info() function walks to the Nth label based on bflow->entry, returning -ENOENT when entries are exhausted.
BLS multi-entry. The BLS bootmeth scans loader/entries/ for .conf files using bflow->entry to select the Nth file. It also sets BOOTMETHF_MULTI. The test image places two entries in the directory, and the test detects the filesystem ordering at runtime since directory-order is not deterministic.
Include-file support. The extlinux scanning code now uses parse_pxefile() with pxe_process_includes() and the full extlinux_getfile callback, so labels defined in included files are correctly discovered. The parsed result is cached in the alist context – entry 0 triggers the parse, subsequent entries reuse the cache, and boot reuses it again. For bootmeths that don’t cache (e.g. PXE network boot), the context is set up from scratch.
Boot-specific entry. A new pxe_boot_entry() function parses the configuration and boots a specific label by index, replacing the menu-driven pxe_process_str(). This means each scanned bootflow boots its label directly.
Bootflow list and info. The bootflow list output gains an Ent column showing the entry number for multi-entry bootmeths. The bootflow info command shows the entry number and a short name (the extlinux label name or BLS title), making it easy to distinguish entries from the same partition.
What it looks like
Before:
Seq Method State Uclass Part E Name Filename
--- ----------- ------ -------- ---- - ------------------------ ----------------
0 extlinux ready usb 1 hub1.p4.usb_mass_storage. /extlinux/extlinux.conf
---
(1 bootflow, 1 valid)
After:
Seq Method State Uclass Part Ent E Name Filename
--- ----------- ------ -------- ---- --- - ------------------------ ----------------
1 extlinux ready usb 1 0 hub1.p4.usb_mass_storage. /extlinux/extlinux.conf
2 extlinux ready usb 1 1 hub1.p4.usb_mass_storage. /extlinux/extlinux.conf
---
(2 bootflows, 2 valid)
And bootflow info on each shows the detailed info:
Entry: 0: Ubuntu 25.04 6.8.0-53-generic
Entry: 1: Ubuntu 25.04 6.8.0-53-generic (rescue target)
Testing
Both series include comprehensive tests. The multi-entry test scans a USB device with a two-label Ubuntu extlinux configuration (including an include directive for the rescue label) and verifies both entries appear with the correct OS names. The BLS test uses two .conf files and handles non-deterministic FAT ordering. Existing tests for bootflow scan -b, bootflow info, and the bootctl UI are updated for the additional entries.
What’s next?
The PXE-parsing code is a little convoluted since it still supports parse-and-boot as a single operation. This is needed for VBE and PXE (network) operation at present. Those bootmeths could be refactored to avoid this.


