Updatable bootlaoder (over BLE SMP)

Hi,

I have added a support for application DFU over BLE SMP to our project (with mcumgr). It work with no problem. Now what I want to achieve is an updatable MCUBoot with the same transport layer. We already have a NSIB and proper static memory map configuration (configured with Partition Manager's pm_static.yml - we have mcuboot_secondary slot set in the external flash and B0 slots in internal flash). I have looked through code and it seems to me like the zephyr_img_mgmt implementation natively supports only application image updates with mcuboot backend. Is there any out of the box solution for updating the mcuboot itself? Is mcumgr flexible enough to upload the image to the partition/address other than mcuboot_secondary - in particular to the S1 slot of the B0 bootloader configured in the internal flash memory?

I have tried the solution proposed here but with the BLE SMP transport instead of UART:Update mcuboot with SMP
But it doesn't seem to work as the uploaded image lands in the mcuboot's external flash partition (verified with debbuger that the flash device being opened is the mx25r64).

I'd presume that the binary to be uploaded with mcumgr must have encoded all information needed to upload it to the proper memory address (judged by CBOR decoding implemented here: https://github.com/nrfconnect/sdk-zephyr/blob/main/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c#L508). Does the `signed_by_mcuboot_and_b0_s1_image_update` file meet this criteria? If so, I guess it should be feasible to adapt the mcumgr to handle my case. I'd really appreciate any kind of guide or list of steps required to achieve that.

Also, I saw the CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD, which sounds like something which might help, but I cannot really understand what it does from the KConfig description. I'd warmly welcome any explanation here.

Thanks in advance,

G

Parents
  • Hi,

    See  Bootloaders and Device Firmware Updates.

    For an unofficial sample, see https://github.com/hellesvik-nordic/samples_for_nrf_connect_sdk/tree/main/bootloader_samples/updatable_bootloader

    If you got questions after that, let me know, and I will explain.

    PS:

    Is mcumgr flexible enough to upload the image to the partition/address other than mcuboot_secondary - in particular to the S1 slot of the B0 bootloader configured in the internal flash memory?

    No. So we fix this by just uploading to mcuboot_secondary, and automatically swapping to s1 instead of mcuboot_primary

    Regards,
    Sigurd Hellesvik

  • Hi Sigurd, thanks for your hints and sorry for delayed response. I was able to run your reference sample with the attached patch (apparently there have been some changes in NCS 2.4.0 which require KConfig adaptation) and update the mcuboot successfully. I have also ported this solution to our BLE SMP application. One thing that bothers me is the fact that we need to reboot the device twice. Can you please explain why is it required? Do you think this solution pose any potential risk assuming that the same implementation and flash partition is used for application image updates? When is the mcuboot image actually swapped to the s1 (instead of mcuboot_primary as you mentioned)? Does it happen at first boot (and then the image lands in s0 with the next reboot)? Does the NSIB support any kind of rollback mechanism? Like restoring an old mcuboot image (from s1? mcuboot_secondary?) in case the new one is broken for whatever reason? I'd like to better understand the solution as all seem to happen under the hood and we are using mcuboot_secondary to update mcuboot itself which is not very intuitive, at least for me.

    8461.diff.patch

  • george232 said:
    One thing that bothers me is the fact that we need to reboot the device twice. Can you please explain why is it required?

    With only MCUboot and mcumgr, we can update the application.
    Adding another bootloader, it is not possible to update MCUboot as well.
    However, design-wise, this could be done in two possible ways. Either add a new DFU method for MCUboot updates, or by leveraging the existing MCUboot DFU mechanism.
    The last one is the one we have in our design.

    So we use mcumgr to transfer the image to primary slot. After the image is here, it needs to be swapped to s0/s1. And MCUboot is the one swapping.
    MCUboot only runs on startup, so we must restart the device for MCUboot to run. After this, the new MCUboot is in s0/s1. This will not run until next reboot, so to verify that it runs, another restart is required.

    I would argue that two restarts is reasonable for bootloader updates, as this is a feature which likely will be used infrequently.

    george232 said:
    Do you think this solution pose any potential risk assuming that the same implementation and flash partition is used for application image updates?

    I think there might be a bug if you try to swap the new MCUboot update into the current MCUboot slot. Test this yourself to be sure. When I tried this recently, mcuboot_secondary became stuck at "pending" and I could not upload new images. Our developers are aware, and I do have a workaround for this if you also see the bug and want a fix.

    Conceptually, the risk would be that you overwrite and forget the previous Application DFU when updating the bootloader.
    However, after the Test step of DFU, MCUboot does not swap back to the previous version, so I do not think that will be an issue.
    One reason to not allow a swap-back is so no attacker can use this to downgrade the application firmware.

    george232 said:
    When is the mcuboot image actually swapped to the s1 (instead of mcuboot_primary as you mentioned)?

    MCUboot does the swapping. It swaps to s0 or s1 depending on which image has been uploaded.

    george232 said:
    Does it happen at first boot (and then the image lands in s0 with the next reboot)?

    The boot order is: NSIB->MCUboot->application

    Example for s1 DFU:

    Application: Upload image to mcuboot_secondary
    Reboot
    NSIB: will detect that s0 is newest MCUboot version -> Runs MCUboot(s0)
    MCUboot(s0): Will detect new image to be swapped in mcuboot_secondary. Swaps mcuboot_secondary <-> s1
    Application: Run as normal
    Reboot
    NSIB: Will detect that will detect that s0 is newest MCUboot version -> Runs MCUboot(s1)
    MCUboot(s1): Nothing to do
    Application: Run as normal

    george232 said:
    Does the NSIB support any kind of rollback mechanism?

    NSIB will run s0 or s1. It will try to boot the slot with the highest version.
    However, NSIB will verify the slot first, to see that it is properly signed and not broken. If it can not verify a slot, it will boot the other slot. See source code.

    george232 said:
    Like restoring an old mcuboot image (from s1? mcuboot_secondary?) in case the new one is broken for whatever reason?

    The above point assumes that the other s1/s0 is a working version of MCUboot, in which case it has a backup-slot to boot to.

  • MCUboot does the swapping. It swaps to s0 or s1 depending on which image has been uploaded.

    So the target partition is encoded in the signed_by_mcuboot_and_b0_s0/s1_image_update.bin? Can you point to the script where it is implemented in the NCS (and possibly in the MCUBoot)? I thought that MCUBoot could only swap between its secondary and primary slots.

    NSIB: will detect that s0 is newest MCUboot version -> Runs MCUboot(s0)

    Newest because the S1 does not contain any image, right?

    NSIB: Will detect that will detect that s0 is newest MCUboot version -> Runs MCUboot(s1)

    Do you mean that S1 is the newest version, right?

  • george232 said:
    So the target partition is encoded in the signed_by_mcuboot_and_b0_s0/s1_image_update.bin? Can you point to the script where it is implemented in the NCS (and possibly in the MCUBoot)? I thought that MCUBoot could only swap between its secondary and primary slots.

    I will have to look into this.

    george232 said:
    Newest because the S1 does not contain any image, right?

    Pretty much yes. Techincally, I think both slots have the same image at start, and that S0 is just checked first.

    george232 said:
    Do you mean that S1 is the newest version, right?

    Yes, I mean S1 here.

  • Sigurd Hellesvik said:
    So the target partition is encoded in the signed_by_mcuboot_and_b0_s0/s1_image_update.bin? Can you point to the script where it is implemented in the NCS (and possibly in the MCUBoot)? I thought that MCUBoot could only swap between its secondary and primary slots.

    github.com/.../loader.c

  • Ok, all clear. Thanks for the explanation. However it seems that for the DFU to work that way we need to use S0/S1 slot alternately. If I upload the signed_by_mcuboot_and_b0_s1_image_update.bin with new mcuboot image and the use the signed_by_mcuboot_and_b0_s0_image_update.bin with newer image it works flawlessly. But then if I use signed_by_mcuboot_and_b0_s0_image_update.bin again (with the even newer mcuboot), the image is uploaded correctly and I can tag it as `pending` but it won't get swapped to the S0 at the subsequent reboot. What's even more concerning is the fact that this image persist in the secondary slot tagged with pending flag (it persists even after the reboot) and I cannot upload another image, even the one targeting to the S1 (signed_by_mcuboot_and_b0_s1_image_update.bin) - the error is: "Image upload inspect failed: 5". I see that there is a logic in the img_manager which determines if the slot is active by checking if there is any flag set. So the DFU is kind of blocked. Is there a way to clear the flags from mcumgr go tool? I cannot see such an option in the CLI help. On the current NCS main I see CONFIG_MCUMGR_GRP_IMG_ALLOW_ERASE_PENDING has been introduced, maybe using this one would help?

Reply
  • Ok, all clear. Thanks for the explanation. However it seems that for the DFU to work that way we need to use S0/S1 slot alternately. If I upload the signed_by_mcuboot_and_b0_s1_image_update.bin with new mcuboot image and the use the signed_by_mcuboot_and_b0_s0_image_update.bin with newer image it works flawlessly. But then if I use signed_by_mcuboot_and_b0_s0_image_update.bin again (with the even newer mcuboot), the image is uploaded correctly and I can tag it as `pending` but it won't get swapped to the S0 at the subsequent reboot. What's even more concerning is the fact that this image persist in the secondary slot tagged with pending flag (it persists even after the reboot) and I cannot upload another image, even the one targeting to the S1 (signed_by_mcuboot_and_b0_s1_image_update.bin) - the error is: "Image upload inspect failed: 5". I see that there is a logic in the img_manager which determines if the slot is active by checking if there is any flag set. So the DFU is kind of blocked. Is there a way to clear the flags from mcumgr go tool? I cannot see such an option in the CLI help. On the current NCS main I see CONFIG_MCUMGR_GRP_IMG_ALLOW_ERASE_PENDING has been introduced, maybe using this one would help?

Children
No Data
Related