Not enough free space to run swap upgrade - understanding the numbers

Hi,

Recently in our application we hit the following problem that has been already raised on the DevZone (we use NCS 2.4.1):

[00:00:00.471,313] <wrn> mcuboot: Not enough free space to run swap upgrade
[00:00:00.471,343] <wrn> mcuboot: required 86016 bytes but only 77824 are available

This happens when attempting to upgrade mcuboot image with the signed_by_mcuboot_and_b0_s1_image_update.bin (we have b0 NSIB enabled), but to my understanding this could happen with the application image as well.

I'm aware of the following issue:

https://github.com/zephyrproject-rtos/zephyr/issues/58103

and the resolution that was integrated with sysbuild (only).

https://github.com/zephyrproject-rtos/zephyr/pull/64586

https://github.com/zephyrproject-rtos/mcuboot/commit/4c7942e58c5458ce3c4e50d3169e0f865910fe87

This seems well justified considering the mcuboot's overhead required for swap with move (1 extra sector to be able to move image and some metadata/trailer):

https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/mcuboot/design.html#swap-without-using-scratch

We ported the 4c7942e58c5458ce3c4e50d3169e0f865910fe87 mcuboot contribution to our project to do some testing. It works, however I'd like to better understand numbers we see because they look weird to me.

I added some extra logs to the mcuboot after porting the aforementioned commit and to the mcuboot's swap_run() function. This is what I got:

bootloader/mcuboot/boot/zephyr/CMakeLists.txt:

MCUBoot bootloader key file: .../child_image/es_key.pem
################# {key_size}:  ###################### 0
################# {boot_magic_size}:  ###################### 16
################# {boot_swap_data_size}:  ###################### 32
################# {boot_status_data_size}:  ###################### 6144
################# {boot_tlv_estimate}:  ###################### 150
################# {write_size}:  ###################### 8
################# {erase_size}:  ###################### 4096
################# {final_required_size}: ###################### 12288
-- Configuring done

mcuboot's swap_run(:

[00:00:00.471,252] <wrn> mcuboot: ##### sector_sz:4096 #####
[00:00:00.471,252] <wrn> mcuboot: ##### trailer_sz:3120 #####
[00:00:00.471,282] <wrn> mcuboot: ##### first_trailer_idx:19 #####
[00:00:00.471,282] <wrn> mcuboot: ##### last_idx:20 #####
[00:00:00.471,313] <wrn> mcuboot: Not enough free space to run swap upgrade
[00:00:00.471,343] <wrn> mcuboot: required 86016 bytes but only 77824 are available

And here comes the mcuboot compilation summary:

Memory region         Used Size  Region Size  %age Used
           FLASH:         77 KB      81408 B     96.86%
             RAM:       28480 B       256 KB     10.86%
        IDT_LIST:          0 GB         2 KB      0.00%

Now, it looks like the calculated final_required_size is 12k, so I's guess, the final slot size needed to accommodate the swap operation and mcuboot metadata should be 77KB + 12KB = 89KB. Why is the real required size then 86K (86016 from the device's console)? I know that the check in the build system only estimates the size of the TLVs but I'd say this is not so relevant and I suspect that it has something to do with the trailer size which is calculated differently by the build system (code from a4eda30f5b0cfd0cf15512be9dcd559239dbfc91 integrated in our project) and the firmware at runtime - interestingly enough, the difference is 3KB, exactly the same as the difference between the calculated and real required size.

BTW. Why does the https://github.com/zephyrproject-rtos/mcuboot/commit/4c7942e58c5458ce3c4e50d3169e0f865910fe87 skip the following when calculating the resulting required size?

    |   Swap info   |  0xff padding (BOOT_MAX_ALIGN minus 1 octet)  |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |   Copy done   |  0xff padding (BOOT_MAX_ALIGN minus 1 octet)  |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |   Image OK    |  0xff padding (BOOT_MAX_ALIGN minus 1 octet)  |

https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/mcuboot/design.html#image-trailer

To my understanding these fields should be included as well. Do I get something wrong here?

Thanks in advance for any help.

G

Parents
  • Hi,

    I got some generic feedback on the size calculations. 

    In general the image size calculations relay on write/boot-alignment requirements and erase-size. To make sure that you can move the images around you follow the swap using scratch algorithm. The sizes are rounded up and aligned with `align_up(${required_size} ${erase_size} required_size)` so first it checks the write size then align it with the erase size since it needs 1 page to shift the images up to rotate them using the swap algorithm.

    1 slot needs to fit the application + mcuboot metadata + status data but also be able to move so image-size is usually a bit smaller than slot size.

    PS: Sysbuild support is still new and the partition manager (which is used by default) is probably a better option for the nRF52840 at this point in time. 

  • Hi Einar,

    thanks for looking into that.

    Well, I actually read the docs you pointed out. I'm also aware that sysbuild is at its early stage of development. That's why my goal was not to use the sysbuild directly, rather to port the code contributed in the 4c7942e58c5458ce3c4e50d3169e0f865910fe87 to our application's CMake (which is based on partition manager) because the implemented logic seems very much reasonable and in fact, IMHO, should be somehow extended to support the current NCS build system because it prevents the DFU from stumbling upon the issue I mention.

    I'm also familiar with the image size alignment and mcuboot metadata required to perform the swap (as well as the additional page needed for swap by move algo).

    My question is about the numbers I see. You said

    o image-size is usually a bit smaller than slot size

    To my understanding the code from aforementioned commit aims to estimate what the "bit smaller" really means. However, I cannot understand the 3kB (89k vs. 86k) difference between data printed in the mcuboot warning log and the estimation from 4c7942e58c5458ce3c4e50d3169e0f865910fe87. It aligns well with my hypothesis that it's the image trailer being calculated differently in the firmware and in the build system:

    [00:00:00.471,252] <wrn> mcuboot: ##### trailer_sz:3120 ##### -> from the firmware

    ################# {boot_status_data_size}:  ###################### 6144 -> from the build system

    The latter is calculated here:

    https://github.com/zephyrproject-rtos/mcuboot/commit/4c7942e58c5458ce3c4e50d3169e0f865910fe87#diff-73248e09fee3c44341d1841b649cbb65a47808f15cc2b273020386af925a30b5R469

    And it plays well with the equation:

    Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * 3) 
    [I guess in practice it's 256*8*3 = 6144 bytes in my case]

    from the table in:

    developer.nordicsemi.com/.../design.html

    The total trailer size from the build system should be even bigger as, to my understanding, as according to the diagram from the link above, it should contain more data (16 bytes of magic data and 3 bytes for swap info, copy done and image OK fields) - maybe it's already included because of the align_up?

    Combining all, I don't get why the trailer size from the mcboot log is only 3k... (I'm just printing values calculated in:
    github.com/.../swap_move.c

    Warm Regards,

    George

Reply
  • Hi Einar,

    thanks for looking into that.

    Well, I actually read the docs you pointed out. I'm also aware that sysbuild is at its early stage of development. That's why my goal was not to use the sysbuild directly, rather to port the code contributed in the 4c7942e58c5458ce3c4e50d3169e0f865910fe87 to our application's CMake (which is based on partition manager) because the implemented logic seems very much reasonable and in fact, IMHO, should be somehow extended to support the current NCS build system because it prevents the DFU from stumbling upon the issue I mention.

    I'm also familiar with the image size alignment and mcuboot metadata required to perform the swap (as well as the additional page needed for swap by move algo).

    My question is about the numbers I see. You said

    o image-size is usually a bit smaller than slot size

    To my understanding the code from aforementioned commit aims to estimate what the "bit smaller" really means. However, I cannot understand the 3kB (89k vs. 86k) difference between data printed in the mcuboot warning log and the estimation from 4c7942e58c5458ce3c4e50d3169e0f865910fe87. It aligns well with my hypothesis that it's the image trailer being calculated differently in the firmware and in the build system:

    [00:00:00.471,252] <wrn> mcuboot: ##### trailer_sz:3120 ##### -> from the firmware

    ################# {boot_status_data_size}:  ###################### 6144 -> from the build system

    The latter is calculated here:

    https://github.com/zephyrproject-rtos/mcuboot/commit/4c7942e58c5458ce3c4e50d3169e0f865910fe87#diff-73248e09fee3c44341d1841b649cbb65a47808f15cc2b273020386af925a30b5R469

    And it plays well with the equation:

    Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * 3) 
    [I guess in practice it's 256*8*3 = 6144 bytes in my case]

    from the table in:

    developer.nordicsemi.com/.../design.html

    The total trailer size from the build system should be even bigger as, to my understanding, as according to the diagram from the link above, it should contain more data (16 bytes of magic data and 3 bytes for swap info, copy done and image OK fields) - maybe it's already included because of the align_up?

    Combining all, I don't get why the trailer size from the mcboot log is only 3k... (I'm just printing values calculated in:
    github.com/.../swap_move.c

    Warm Regards,

    George

Children
Related