MCUboot is an open-source secure bootloader designed for microcontrollers.
It ensures:
- Only authentic and verified firmware runs (via digital signatures).
- Fail-safe firmware upgrades (via slot-based copy and swap mechanisms).
- Rollback protection (to prevent downgrades to vulnerable firmware).
High Level Boot Flow
When the device powers up, MCUboot runs before application. It decides which image (primary or secondary) should be booted, and whether an update needs to be applied.
Here’s a high-level view:
+------------------------+
|   MCU Reset Vector     |
+------------------------+
           |
           v
+------------------------+
|   MCUboot (bootloader) |
+------------------------+
     |         |
     |         +--> Secondary Slot (new image)
     |
     v
+------------------------+
|   Primary Slot         |
|   (Active image)       |
+------------------------+
           |
           v
+------------------------+
|   App main()           |
+------------------------+
MCUboot performs the following:
- Initializes flash, crypto, and image metadata.
- Reads image headers and metadata (TLVs).
- Determines if a swap or overwrite is needed.
- Optionally performs image copy/swap.
- Verifies signature of the image.
- Jumps to application.
Image Layout
MCUboot application image has a header and TLV metadata. The layout in flash looks like this:
+-----------------------------------------------------------+
| Image Header (512 bytes, variable)                        |
+-----------------------------------------------------------+
| Application Binary Code                                   |
+-----------------------------------------------------------+
| TLV Info Header                                           |
+-----------------------------------------------------------+
| TLV Entries (Hash, Signature, KeyHash, etc.)              |
+-----------------------------------------------------------+
The TLVs may include:
- SHA256 hash of the image
- Signature (ECDSA or RSA)
- Key hash
- Custom TLVs (version, etc.)
Protected TLVs cannot be altered without invalidating the signature.
Flash Partition Layout
The default flash layout of STM32F411RE Nucleo board is:
+-------------------------------+ 0x08000000
| Bootloader (MCUboot)          | 16KB - Sector 0
+-------------------------------+ 0x08004000
| Bootloader (MCUboot)          | 16KB - Sector 1
+-------------------------------+ 0x08008000
| Bootloader (MCUboot)          | 16KB - Sector 2
+-------------------------------+ 0x0800C000
| Bootloader (MCUboot)          | 16KB - Sector 3
+-------------------------------+ 0x08010000
| Unused                        | 64KB - Sector 4
+-------------------------------+ 0x08020000
| Primary Slot (Slot 0)         | 128KB - Sector 5
+-------------------------------+ 0x08040000
| Secondary Slot (Slot 1)       | 128KB - Sector 6
+-------------------------------+ 0x08060000
| Scratch Area                  | 128KB - Sector 7
+-------------------------------+ 0x08080000 (end of flash)
Image Upgrade
MCUboot support three main upgrade methods -
- Overwrite: The new image from the secondary slot overwrites the primary image directly.
- Simple, less metadata
- No fail safe - if power fails mid copy, device may brick
 
- Swap Using Scratch: A small scratch area is used to temporarily store sectors during image swap.
- Complex - metadata tracks progress
- Allows resumable swaps after power loss
- Fail safe
- Needs extra scratch area
 
- Swap Using Move (No Scratch): Sector wise direct swap between slots
- Require homogeneous sectors between slots
- Primary slot needs an additional sector for swapping
- Not ideal for heterogeneous sector sizes
 
Signature Verification
MCUboot verifies the image signature after the swap or overwrite using the public keys embedded at build time.
When MCUboot decides to boot an image (either in slot 0 or after swap from slot 1):
- It computes the SHA-256 hash of the firmware region (excluding TLVs).
- It locates the signature TLV and key hash TLV.
- It compares the key hash against the public key(s) compiled into MCUboot.
- If a match is found, it verifies the signature.
Version Management and Rollback Protection
App image carries a semantic version major.minor.revision.build encoded in its header and TLV:
Image Version: 1.2.0+5
When MCUboot detects a new image in the secondary slot, it checks the version before upgrading. MCUboot can be built to accept only the newer firmware version. This prevents accidental or malicious rollbacks to older, possibly vulnerable firmware.
Rollback protection ensures that once the device boots a confirmed image, it will never revert to an older or unverified one. After a successful upgrade, the application must confirm the image by updating the boot status flag in flash. If the device reboots before confirmation (e.g., crash or power loss), MCUboot will rollback to the previous image during the next boot.
Setup MCUboot for STM32F411RE Nucleo
Zephyr DTS for nucleo_f411re can be found at
boards/st/nucleo_f411re/nucleo_f411re.dts
Finally the complete DTS after building (source + overlay)
build/zephyr/zephyr.dts
Following partitions are defined in the DTS by default for the board
Partition           Label Name      Offset      Size              Final Offset (Hex)
boot_partition      mcuboot         0x0         0x10000 (64 KB)   0x08000000
slot0_partition     image-0         0x20000     0x20000 (128 KB)  0x08020000
slot1_partition     image-1         0x40000     0x20000 (128 KB)  0x08040000
scratch_partition   image-scratch   0x60000     0x20000 (128 KB)  0x08060000
Sector sizes from STM32F401RE reference manual
| Block       | Name     | Block Base address          | Size (Kbytes) |
|-------------|----------|-----------------------------|---------------|
|             | Sector 0 | 0x0800 0000 - 0x0800 3FFF   | 16            |
|             | Sector 1 | 0x0800 4000 - 0x0800 7FFF   | 16            |
| Main Memory | Sector 2 | 0x0800 8000 - 0x0800 BFFF   | 16            |
|             | Sector 3 | 0x0800 C000 - 0x0800 FFFF   | 16            |
|             | Sector 4 | 0x0801 0000 - 0x0801 FFFF   | 64            |
|             | Sector 5 | 0x0802 0000 - 0x0803 FFFF   | 128           |
|             | Sector 6 | 0x0804 0000 - 0x0805 FFFF   | 128           |
|             | Sector 7 | 0x0806 0000 - 0x0807 FFFF   | 128           
Partitions are mapped as follows:
| Partition  | Sector  | Sector size (Kbytes)|
|------------|---------|---------------------|
| boot       | 0-3     | 16                  |
| slot0      | 5       | 128                 |
| slot1      | 6       | 128                 |
| scratch    | 7       | 128                 |
By default, the DTS describe code-partition as 
zephyr,code-partition \= \&slot0\_partition;
Below DTS overlay is required for mcuboot to start the code from 0x0800\_0000
/ {
    chosen {
        zephyr,code-partition = &boot_partition;
    };
};
Complete script to build mcuboot and app image
- Build mcuboot -> zephyr.bin [mcuboot]
- swap using scratch
- no signature
 
- Build app -> zephyr.bin [app]
- Sign app - add image header and TLVs -> zephyr.signed.bin [app]
echo "=== Building mcuboot ==="
echo
pushd "${MCUBOOT_ZEPHYR_DIR}" >/dev/null
west build -b "${BOARD}" -d "${MCUBOOT_BUILD_DIR}" -p auto -- \
    -DDTC_OVERLAY_FILE="${DTS_MCUBOOT_OVERLAY_NUCLEO_F401RE}" \
    -DCONFIG_BOOT_MAX_IMG_SECTORS=8 \
    -DCONFIG_BOOT_MAX_IMG_SECTORS_AUTO=n \
    -DCONFIG_BOOT_SIGNATURE_TYPE_NONE=y \
    -DCONFIG_MCUBOOT_LOG_LEVEL_DBG=y
if [[ ! -f "${MCUBOOT_BIN}" ]]; then
  echo "ERROR: mcuboot binary not found at ${MCUBOOT_BIN}"
  popd >/dev/null
  exit 1
fi
popd >/dev/null
echo "+++ mcuboot built: ${MCUBOOT_BIN} +++"
echo "=== Building app ==="
echo
west build -b ${BOARD} . -d build-app -p auto -- \
  -DCONFIG_BOOTLOADER_MCUBOOT=y \
  -DCONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE=y
IMGTOOL_PY="${MCUBOOT_DIR}/scripts/imgtool.py"
west sign -d build-app -t imgtool -p ${IMGTOOL_PY}  -- \
  --pad \
  --slot-size 0x20000 \
  --header-size 0x200 \
  --align 4
 

 
    
Top comments (0)