Skip to content

Single-slot boot path is duplicated in ports; consider factoring it into boot/bootutil #2826

Description

@danielriege

The single-slot (MCUBOOT_SINGLE_APPLICATION_SLOT) boot path exists twice, in two
ports, and not at all in the shared library:

File Lines
boot/zephyr/single_loader.c 255
boot/mynewt/src/single_loader.c 136
boot/bootutil/src/ — none

Both provide boot_go() plus a local boot_image_validate(); Zephyr's
additionally provides boot_get_loader_state(), boot_get_image_max_sizes(),
boot_open_all_flash_areas(), boot_close_all_flash_areas() and
app_max_size(), of which the first four are only referenced by
boot_fetch_slot_state_sizes() in bootutil_misc.c, inside
#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO).

Neither implementation appears to depend on its host OS. In
boot/zephyr/single_loader.c I could find no Zephyr API call, no CONFIG_*
reference and no devicetree use; its includes are assert.h, bootutil/*,
bootutil_priv.h and mcuboot_config/mcuboot_config.h, and the only
non-bootutil symbols it references are the BOOT_LOG_* macros, which are
already part of the port configuration contract. The same appears to hold for
the Mynewt version.

Why it matters

boot_go() has two implementations — the multi-slot state machine in
boot/bootutil/src/loader.c, and the single-slot path — and the build system
selects between them (boot/zephyr/CMakeLists.txt, the
CONFIG_SINGLE_APPLICATION_SLOT branch). Because only the multi-slot
implementation lives in the shared library, an out-of-tree port that wants
single-slot support has to write the second one itself, even though it is
almost entirely calls into bootutil.

That also means the two in-tree copies can drift from each other and from
bootutil, and each has to be updated separately when the bootutil interface
changes.

Proposal

Move the OS-independent part of the single-slot boot path into
boot/bootutil/src/single_loader.c and have the Zephyr and Mynewt ports use it,
leaving anything genuinely port-specific behind. This would be a
behaviour-preserving refactor rather than a feature change, and would give
out-of-tree ports the same choice of boot_go() implementation that the in-tree
ports have.

Questions before attempting a PR

  1. Is consolidating these two into bootutil a direction you would accept in
    principle, or is the duplication deliberate?
  2. sim/Cargo.toml has features for overwrite-only, swap-move,
    swap-offset and so on, but none for single-slot, so as far as I can tell the
    single-slot path currently has no simulator coverage. For a
    behaviour-preserving move, would you want simulator coverage for single-slot
    added first (or as part of the same PR), or is the absence of coverage
    acceptable for a relocation?
  3. If you would take it, do you have a preference on scope — move Zephyr's
    version and have Mynewt adopt it, or reduce to the smaller common subset and
    let each port keep what only it needs?

Happy to do the work if the direction is welcome; asking first per
docs/contributing.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions