Skip to content

3. Boot Chain

Austin Shirley edited this page Oct 22, 2026 · 4 revisions

Boot sequence

ROM -> TF-A BL2 (fsbl1/fsbl2) -> FIP -> OP-TEE (BL32) -> U-Boot (BL33) -> Linux

TF-A produces the following artifacts:

  • *.stm32: raw BL2, written to fsbl1 and fsbl2.
  • fip.bin: FIP containing BL32 and BL33, written to fip-active and fip-factory.

Firmware update and fallback

The boot chain provides A/B recovery for both the firmware (the FIP) and the root filesystem without relying on PSA Firmware Update (FWU) metadata. This keeps every component on its upstream release, since the upstream FWU path would require out-of-tree patches to TF-A and U-Boot. For the reasoning behind this choice, refer to the Differences page.

The mechanism has three parts:

  • BL2 normally loads the FIP from fip-active. When that load fails, BL2 walks forward in 128 KB steps across the FIP window and falls back to the fip-factory copy. The factory copy is normally immutable, so a corrupt or interrupted firmware update still leaves a bootable image. RAUC manages fip-active as a raw bootloader slot.
  • U-Boot iterates a boot order of slot A, then slot B, then the factory root filesystem. Each A/B slot carries a retry counter that is decremented before an attempt and reset by rauc-mark-good after a healthy boot. If the factory root filesystem also fails, U-Boot runs stm32prog usb 0, so the board enumerates as a USB DFU target for recovery without any change to the BOOT pins.
  • Because there is no FWU metadata to report which firmware slot booted, the running U-Boot version is stamped from git describe at build time and recorded both in the U-Boot environment and in /etc/firmware/expected-bl33-version on the root filesystem. At boot, report-boot-state.service compares the two and writes a verdict to /run/boot-state, where a companion application can detect that the device fell back to factory firmware and offer a repair.

Root filesystem

Root filesystem slots mount read-only, with /tmp and /run on tmpfs. For persistent data, overlayfs is used for /etc and /var, with the upper dir on the overlay UBI volume (/mnt/overlay).

The overlay persists across reboots and RAUC installs, and is shared by the A, B, and factory slots. A full DFU reflash wipes it.

A file modified in the overlay always shadows that path in the rootfs, including changes from later updates. Prefer drop-in directories or separate files for runtime-edited config.

Machine ID

U-Boot derives a stable 128-bit systemd machine ID from the fixed prefix deadba7d + 96-bit die UID (OTP words 13-15).

try_boot passes it as systemd.machine_id= on the kernel command line, to ensure the ID is stable across A/B/factory slots and reflashes. If the OTP read fails, the argument is omitted and systemd generates a random ID.

On the read-only rootfs, systemd bind-mounts the ID over /etc/machine-id. machine-id-overlay.service copies it into the /etc overlay upper dir and unmounts it before etc.mount, so it stays visible once the overlay is mounted.

Device tree

All DTS files live in board/myd-yf135/dts/ and are passed to each firmware component via BR2_*_CUSTOM_DTS_PATH (Linux: external.mk hook, see below). Nothing is patched into upstream source.

File Used by
stm32mp135d-myd-yf135.dts Linux, U-Boot
stm32mp135d-myd-yf135-u-boot.dtsi U-Boot additions
stm32mp135d-myd-yf135-tf-a.dts / .dtsi TF-A BL2
stm32mp135d-myd-yf135-tf-a-fw-config.dts BL32/BL33 load addresses
stm32mp135d-myd-yf135-optee.dts OP-TEE secure peripherals

Due to a recent refactoring of the kernel ST device tree sources, a special build step is needed to inject DTS files into the build via external.mk. This may be fixed in a future Buildroot release.

Superprojects can extend all five DTs (including Linux and U-Boot), see Parent device tree.

Key board-specific pin fix

The upstream qspi_bk1_pins_a definition has wrong IO2 and IO3 pins for this board:

Signal Upstream MYD-YF135
QSPI_BK1_IO2 PD11 (AF9) PD7 (AF11)
QSPI_BK1_IO3 PH7 (AF13) PD13 (AF9)

This is fixed via qspi_bk1_pins_b defined in the board DTS.

NAND parameters and OTP

Upstream TF-A BL2 reads the SPI-NAND geometry from OTP word 9. SOMs ship with this word blank (0x00000000), so it must be burned once before the first boot from SPI-NAND. The vendor BSP never reads this word (see Differences).

For the Micron MT29F2G01ABAGDWB on this SOM, the value is 0x80424000. Bit breakdown (from plat/st/stm32mp1/stm32mp1_def.h):

Bits Field Value Meaning
31 NAND_PARAM_STORED_IN_OTP 1 Parameters from OTP
30-29 page_size 00 2 KB pages
28-27 block_size 00 64 pages/block (128 KB)
26-19 block_nb 0x08 2048 blocks (8 x 256)
18 width 0 8-bit bus
17-15 ECC 100 On-die ECC
14 nb_planes 1 2 planes

Burn it from the U-Boot console:

STM32MP> fuse sense 0 9
STM32MP> fuse prog 0 9 0x80424000
STM32MP> fuse sense 0 9

The first fuse sense should show 00000000 and the last should show 80424000. If the word is not blank, stop. OTP bits are one-way: fuse prog can set bits but never clear them, so continue only if the value already burned is a subset of 0x80424000.

TF-A's spi_nand_read_from_cache() selects the plane from the nb_planes field. If the plane count is wrong, BL2 reads pages out of order. Boot can appear to work until a load spans a plane boundary, and then the data comes back corrupt.

Clone this wiki locally