Sysbuild doesn't include MCUBoot headers in merged.hex when using upgradeable bootloader

I am in the process of migrating to NCS 2.7. My project includes NSIB, MCUBoot, TFM, and the application. Everything works fine with multi-image builds.

However when using sysbuild, MCUBoot (executing out of slot 0) is unable to find the headers for the s1_image and therefore aborts the boot. This happens because the merged.hex file flashed via 'west flash --erase' does not include the headers for the mcuboot or s1_image. If I manually flash signed_by_mcuboot_and_b0_s1_image.hex on top of the existing image then it will boot fine.

I am using a pm_static.yml, but I see the same behavior with dynamically generated partitions as well. For reference here are the flash regions from my partition_manager_report. 

  external_flash (0x200000 - 2048kB):
+------------------------------------------------------+
| 0x0: mcuboot_secondary (0xd7000 - 860kB)             |
| 0xd7000: persistent_settings (0x1000 - 4kB)          |
| 0xd8000: persistent_blob_oolong_task (0x4000 - 16kB) |
| 0xdc000: EXTERNAL_FLASH_UNUSED (0x124000 - 1168kB)   |
| 0x200000: external_flash (0x0 - 0B)                  |
+------------------------------------------------------+

  flash_primary (0x100000 - 1024kB):
+---------------------------------------------------+
+---0x0: b0_container (0x8000 - 32kB)---------------+
| 0x0: b0 (0x8000 - 32kB)                           |
+---0x8000: s0 (0x10000 - 64kB)---------------------+
| 0x8000: s0_pad (0x200 - 512B)                     |
+---0x8200: s0_image (0xee00 - 59kB)----------------+
| 0x8200: mcuboot (0xee00 - 59kB)                   |
+---------------------------------------------------+
| 0x17000: RESERVED_FOR_MOVE_S0 (0x1000 - 4kB)      |
+---0x18000: s1 (0x10000 - 64kB)--------------------+
| 0x18000: s1_pad (0x200 - 512B)                    |
| 0x18200: s1_image (0xee00 - 59kB)                 |
| 0x27000: RESERVED_FOR_MOVE_S1 (0x1000 - 4kB)      |
+---0x28000: mcuboot_primary (0xd8000 - 864kB)------+
| 0x28000: mcuboot_pad (0x200 - 512B)               |
+---0x28200: app_image (0xd6e00 - 859kB)------------+
+---0x28200: mcuboot_primary_app (0xd6e00 - 859kB)--+
+---0x28200: tfm_app (0xd6e00 - 859kB)--------------+
+---0x28200: tfm_secure (0x7e00 - 31kB)-------------+
| 0x28200: tfm (0x7e00 - 31kB)                      |
+---0x30000: tfm_nonsecure (0xcf000 - 828kB)--------+
| 0x30000: app (0xcf000 - 828kB)                    |
+---------------------------------------------------+
| 0xff000: RESERVED_FOR_MOVE_PRIMARY (0x1000 - 4kB) |
+---------------------------------------------------+

  otp (0x2f4 - 756B):
+------------------------------------+
| 0xff8108: provision (0x280 - 640B) |
| 0xff8388: otp (0x74 - 116B)        |
+-

The following files are all the ones merged into merged.hex from partition_manager.cmake:

  • 'BUILD/app_provision.hex' (implicit) 
  • 'BUILD/b0_container.hex' (implicit)
  • 'BUILD/s0_image.hex' (implicit)
  • 'BUILD/s0.hex' (implicit)
  • 'BUILD/s1.hex' (implicit)
  • 'BUILD/b0/zephyr/zephyr.hex' (explicit, unsigned hex name for b0 image)
  • 'BUILD/signed_by_b0_mcuboot.hex' (explicit, signed hex name for mcuboot image)
  • 'BUILD/signed_by_b0_s1_image.hex' (explicit, signed hex name for s1_image image)
  • 'BUILD/teabox/zephyr/teabox.signed.hex' (explicit, signed hex name for application image)

The files marked implicit are assigned at partition_manager.cmake#L235 whereas those marked explicit are assigned at partition_manager.cmake#L224. Now the implicit files are largely redundant, and could be somewhat cleaned up by changing the names of the partitions so that they don't match with the actual hex files. But more importantly, it can be seen that the signed mcuboot and s1_image hex files are for the images which have only been signed by b0. These images do not have valid mcuboot headers or signatures. This can be seen clearly by dumping the hex file ranges:

$ diff BUILD/s0.hex BUILD/s0_image.hex
$ diff BUILD/s0.hex BUILD/signed_by_b0_mcuboot.hex
$ srec_info BUILD/signed_by_b0_mcuboot.hex -Intel
Format: Intel Hexadecimal (MCS-86)
Data:   008200 - 011FC7
$ srec_info BUILD/signed_by_mcuboot_and_b0_mcuboot.hex -Intel
Format: Intel Hexadecimal (MCS-86)
Data:   008000 - 01205E

$ diff BUILD/s1.hex BUILD/signed_by_b0_s1_image.hex
$ srec_info BUILD/signed_by_b0_s1_image.hex -Intel
Format: Intel Hexadecimal (MCS-86)
Data:   018200 - 021FC7
$ srec_info BUILD/signed_by_mcuboot_and_b0_s1_image.hex -Intel
Format: Intel Hexadecimal (MCS-86)
Data:   018000 - 02205F

As can be seen above the ranges 0x8000-0x8200 and 0x18000-0x18200 are missing from the mcuboot and s1_images respectively. As expected, they are also missing from merged.hex:

$ srec_info BUILD/merged.hex -Intel
Format: Intel Hexadecimal (MCS-86)
Data:   000000 - 005D07
        008200 - 011FC7
        018200 - 021FC7
        028000 - 06B54A
        FF8130 - FF8193

The underlying issue in the sysbuild cmake structure is that BYPRODUCT_KERNEL_SIGNED_HEX_NAME is set to the b0 signed files at image_signing.cmake#L174. However, it should be reset to the mcuboot signed files inside b0_mcuboot_signing.cmake. If I add a sysbuild_set function to Zephyr and call 'sysbuild_set("${output}.hex" IMAGE ${application} VAR BYPRODUCT_KERNEL_SIGNED_HEX_NAME CACHE)' at b0_mcuboot_signing.cmake#L91 then it fixes the problem. The merged hex will contain signed_by_mcuboot_and_b0_mcuboot.hex and signed_by_mcuboot_and_b0_s1_image.hex and boot properly. The new merged.hex dump is shown below:

$ srec_info BUILD/merged.hex -Intel
Format: Intel Hexadecimal (MCS-86)
Data:   000000 - 005D07
        008000 - 01205E
        018000 - 02205E
        028000 - 06B54B
        FF8130 - FF8193

Now the thing I don't understand is that this should be broken for everybody using sysbuild and the upgradeable bootloader. I didn't test it, but a quick code inspection indicates that the problem still persists at tip of tree. Can someone at Nordic look into this and determine if this is the case?

Related