MCUBoot manual compile + usage

We're using NCS embedded into our Makefile-based build system to compile nRF5340 applications out-of-tree, but still having unresolved problems. The target board is a custom nRF5340 design. I'm continuously looking for alternative ways to achieve my goal: have MCUBoot run on APP core alongside our program + being able to perform FW upgrade. The problems are described in the linked ticket, now I'd like to show what other things I've been trying to do.

I've figured out how to manually configure, menuconfig and compile NCS's MCUBoot, so now I can generate MCUBoot's zephyr.hex independently of my application. Burning it to the flash isn't a problem either. Important to note, the application has no MCUBoot enabled as a child image (because we're having problems with it, see the linked ticket), it's a simple, standalone program.

Once the application is compiled, the resulting zephyr.hex is signed like this:

imgtool.py sign --align=1 --version="9.8.7" --header-size=512 --slot-size=0x77000 --hex-addr=0x10000 zephyr.hex signed.hex

Burning signed.hex to flash, MCUBoot successfully boots it. Great!

To check how MCUBoot swapping is operating, generated a different zephyr.hex and signed it:

imgtool.py sign --align=1 --version="9.8.7" --header-size=512 --slot-size=0x77000 --hex-addr=0x87000 ph2.hex signed.hex

(In DTS, slot0_partition begins at 0x10000, while slot1_partition begins at 0x87000, their sizes are 0x77000)

After burning the new FW image to slot1, MCUBoot does nothing, still boots the original image. (Swapping is enabled in MCUBoot config). This is what MCUBoot displays on serial console:

*** Booting Zephyr OS build v3.2.99-ncs1 ***
I: Starting bootloader
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Swap type: none
I: Bootloader chainload address offset: 0x10000
�*** Booting Zephyr OS build v3.2.99-ncs1 ***
================================================================================
project config: default sample project
...
...

I'd like to ask for some help, pointers or advices on the following questions:

  1. how can I make MCUBoot swap my new FW image? I believe this must be something with the lack of FW image trailers. If so, how can I manually generate trailers, or how to init them?
  2. Planned FW upgrade will be working like this: the running application gets the image file fragments via some kind of networking (e.g. TCP/IP). How can the application pass the fragments to MCUBoot? This is pretty unclear to me, as MCUBoot executes first after reset, but when it loads the application from slot0, MCUBoot no longer remains in memory, it's no longer running (if I'm not totally wrong). So if my assumption is right, there must be some MCUBoot-support code in Zephyr, which makes it possible to write new image's fragment to slot1, generate trailer and so on.
    The first thing I want to experiment with is that a sample app is being burnt into slot0, and this app contains the image of a new app; this old sample app emits image fragments, which get written to slot1, and then resets and MCUBoot does its job (swaps images);

Many thanks, regards,

  • Hello,

    I haven't tried to build MCUBoot as a separate application in a long time, to be honest. When building MCUBoot as a child-image, out-of-tree or not, the cmake build scripts will sign and prepare the update images for you automatically (for an overview of which files may be generated, see this link). I mention this because it might be useful to have a look at how the SDK handles this in multi-image builds. 

    For comparison, here's the imgtool command used to create app_update.bin when I built the Zephyr smp_srv sample:

    $ imgtool.py sign --key /home/vidarbe/ncs/v2.4.0/bootloader/mcuboot/root-rsa-2048.pem --header-size 0x200 --align 4 --version 0.0.0+0 --pad-header --slot-size 0x78000 /sdk_project/smp_svr/build/zephyr/app_to_sign.bin /sdk_project/smp_svr/build/zephyr/app_update.bin

    how can I make MCUBoot swap my new FW image? I believe this must be something with the lack of FW image trailers. If so, how can I manually generate trailers, or how to init them?

    The imgtool sign command will generate the image trailer as well. However, it will not include the magic word needed to mark the image as a pending update. You can include the magic word in the signed image by using the '--pad' option when signing the image with imgtool, or use the bootutil APIs from the main app https://github.com/nrfconnect/sdk-mcuboot/blob/main/boot/bootutil/include/bootutil/bootutil_public.h#L202. Enable CONFIG_MCUBOOT_BOOTUTIL_LIB in your application to include these APIs.

    2. You are correct, MCUBoot will not run after it has loaded the application. This is why the application needs to write the update instructions to the image trailer using the bootutil APIs mentioned above. 

    Best regards,

    Vidar

  • Hello Vidar!

    Thanks for the reply.

    Your answer to 1) is clear, I'll try it on the next week.

    To question 2): now I see bootutil can be used to initiate swapping, but how will my application write the new image itself into slot1? With flash/partition write API or is there any other recommended way to store new FW image into slot1 for proper MCUBoot/bootutil operation?

    (My assumption is that my app simply writes the new imgtool-prepared FW image to slot1 partition with Zephyr flash API, then calls bootutil to set it up for swapping)

  • Hello,

    You can use the flash image API to store the image, see https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/services/device_mgmt/dfu.html. We also have DFU libraries that builds on top of this API: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/libraries/dfu/index.html. It may be useful to grep/search through the SDK to find examples of how the API is used.    

  • There is some progress regarding FW upgrade.

    We have given up the concept of manually compiling MCUboot, instead the build system does the job. It was a good decision ;)

    The new image to be burnt to APP and NET cores are available on the APP core (by TCP/IP or other magic of ours).

    Our custom board doesn't feature any external flash.

    I've enabled MCUboot on both APP and NET cores and created static partition layouts for both cores. This resulted in two large prog partitions (primary and secondary) on both cores (and other small partitions).

    We can successfully upgrade APP core's FW by using MCUboot's "move swap" feature. The FW upgrade is initiated somehow like this:

    struct flash_img_context fic;

    flash_img_init_id(&fic, PM_MCUBOOT_SECONDARY_ID);
    boot_erase_img_bank(PM_MCUBOOT_SECONDARY_ID);
    flash_img_buffered_write(&fic, fw_upg_img, sizeof(fw_upg_img), true);
    boot_request_upgrade(BOOT_UPGRADE_PERMANENT);

    On next reboot MCUboot copies the new image from secondary partition to primary, works well.

    Now we need to make it work for NET core too. Unfortunately, if we follow the same scheme for NET core flash partitioning as for APP core partitioning, the resulting primary and secondary partitions will be very small, less than 128kB, so the new image can easily outrun this size. If we had only one prog partition that could be almost 256kB in size.

    My idea is to programmatically shut down NET core and update NET core flash area from a program running on APP core. This way we don't need to create primary and secondary partitions on the NET core, and the only prog partition can be large enough.

    Does the MCU support this kind of operation?

    There are some other alternatives naturally. One that I can think of now: APP core resets NET core, the MCUboot on the NET core takes FW image parts from the APP-NET shared memory and upgrades the program partition. Does MCUboot support this or anything similar?

    Thanks, regards,

  • As I can see, a BusFault is generated when APP core tries to access NET core's flash area, but it's working in the opposite direction, at least NET core is capable of reading APP's flash area.

    The best would be if NET MCUboot could take FW image chunks from APP core through e.g. shared memory, so it could write directly onto flash, and there was no need for a secondary flash partition...

Related