Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Procedure to update bootloader from the application

We are using NRF5 SDK 17.0.2 on an NRF52840. 

I am implementing a bootloader update procedure.  Our updates always store the new image in external flash.  The spare space in the internal flash is insufficient to operate as a second bank for DFU.  As a result, we cannot directly use SD_MBR_COMMAND_COPY_BL since that requires the image to be present in the internal flash space.   

As an aside.. technically we could use the MBR but it would involve copying the application out to external flash and an unsigned application copy back from external flash, which I want to avoid for security reasons.

My preference would be for the application to perform the bootloader copy from external flash into the bootloader space.  This seems relatively straight forward, except I'm not sure how I can notify the MBR the bootloader is invalid during the update process.  It appears I can use the SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET with the softdevice address to bypass the bootloader loading, but its not clear from the documentation:

1) How do I revert the changes caused by NRF_UICR_BOOTLOADER_START_ADDRESS? 

2) Can the SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET command be called multiple times or is it only allowed to be called once?  If multiple calls are allowed, is the swap fail safe?

Alternatively, can I erase the MBR page and clear NRF_UICR_BOOTLOADER_START_ADDRESS during the update and then re-write the NRF_UICR_BOOTLOADER_START_ADDRESS at the completion to re-enable the bootloader?

Parents
  • Hi Anthony, 

    1. As mentioned in the documentation of sd_mbr_command_vector_table_base_set_t, you can pass the address 0 to restore the default forwarding: 

    * To restore default forwarding, this function should be called with @ref address set to 0. If a
    * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will
    * be forwarded to the SoftDevice.

    2. As far as I know this what this function does is to erase the address stored in the MBR setting page and write the new address into it. I don't see a reason it can't be called more than once. 

    We don't have an example on DFU updating the bootloader using external flash. So you pretty much on your own on this. But I would suggest to consider an option to have a small bootloader (B0) at the location of the current bootloader. This small bootloader will do two  simple tasks: 

    1 - To forward the interrupt to the real bootloader

    2 - To replace the real bootloader with the new bootloader image in the external flash. 

    The reason I suggest this, is to avoid a situation that your application already erases your bootloader but fails (power failure, corrupted application) to update the bootloader. 

    If you have the B0 that you verified reliable then you can rely on that in the event when a power failure happens when swapping the bootloader. Consider the B0 as an extra MBR but can swap the bootloader from the external address. This will also relieve the application from the task of swapping the bootloader. 
    Of course you can design your app to recover after an unsuccessful Bootloader update, as the MBR will still forward the vector to the application (AFAIK) after a reset. But it will increase the complexity of the application. 

  • Hi Hung,

    I've finally returned to this part of the project.  I don't see your recommendation of adding another bootloader as viable, since it would sacrifice more of the limited flash code space.  The application is quite large already, and reserving more space for another bootloader is going to be hard to sell to the development team.

    I have hit upon another problem with the plan i stated before. 

    I have the code ready to save a record in external flash to indicate the bootloader update is in progress.  This will allow restarting the update if an unplanned reset interrupts the procedure.  The next step after writing the dfu resume record is to update the MBR vector table, however I just discovered the sd_mbr_command_vector_table_base_set_t will reset the chip.  This is problematic because there is no indication after the reset whether the reset was an unplanned  reset or the planned reset after the vector table base was updated. 

    If there was a command to read the vector table base I could confirm the operation completed after reset.  I cannot find such a command... Is there any way to confirm the MBR completed the vector table base set operation?

Reply
  • Hi Hung,

    I've finally returned to this part of the project.  I don't see your recommendation of adding another bootloader as viable, since it would sacrifice more of the limited flash code space.  The application is quite large already, and reserving more space for another bootloader is going to be hard to sell to the development team.

    I have hit upon another problem with the plan i stated before. 

    I have the code ready to save a record in external flash to indicate the bootloader update is in progress.  This will allow restarting the update if an unplanned reset interrupts the procedure.  The next step after writing the dfu resume record is to update the MBR vector table, however I just discovered the sd_mbr_command_vector_table_base_set_t will reset the chip.  This is problematic because there is no indication after the reset whether the reset was an unplanned  reset or the planned reset after the vector table base was updated. 

    If there was a command to read the vector table base I could confirm the operation completed after reset.  I cannot find such a command... Is there any way to confirm the MBR completed the vector table base set operation?

Children
  • Hi Anthony, 

    If the flash size constrain doesn't allow you to have a 2nd bootloader then it make sense to integrate the bootloader swapping into the Application. Care must be taken as now you don't have a fail-safe restore if the application fails to update the bootloader and stay in a loop recovering that. 

    Regarding your question, you can read if the vector table base has been changed by reading the MBR Param page. I haven't looked at it myself, but AFAIK the customized forwarding address should be stored in the MBR Param. 

    To know if you were resetting from SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET or not, you can write to GPREGRET register a falg. It will be retained after the soft reset. 

Related