MCUboot Direct-XIP, always boots the primary partition

Hi

I am trying to modify the MCUboot image to meet the requirements of the project one of the rquirements is to boot the application directly from the secondary partition, I found the Direct-XIP configuration that does that exactly so I enable it at first it worked, the MCUboot image's "prj.conf" looked like this:

CONFIG_MCUBOOT_LOG_LEVEL_DBG=y
CONFIG_BOOT_SWAP_USING_MOVE=n
CONFIG_BOOT_DIRECT_XIP=y

later I made some modifications directly to the SDK since I needed to update the secondary partition's image so that the DFU service of the Bluetooth connection could overwrite the image, because the service detected that the image was never swapped and it will just restart the device without upgrading the image. To solve this I erased the Trailer of the secondary partition's image.

At some point (not sure when) the MCUboot stopped booting the secondary's partition image (the devices doesn't get stuck, it just boots the primary partition's image) even when the Log says that the image in the secondary partition is newer and that it will be booting it (the address send to the function "do_boot" is the address of the secondary partition).

I tried going back in all my changes but the error is still present.

Right now I have been debugging the booting process after the partition has been selected and it seems that both partitions have the same MSP (Main Stack Pointer) so that might be why the primary partition is booted even when the secondary partition is selected.

I also found that I might need to use a file that has the word "secondary" in its name when writing an image in the secondary partition, I suppose that this one has the correct MSP to boot the image in the secondary partition, but I cannot see it in the "build" folder, while searching for this file found the configuration "CONFIG_BOOT_BUILD_DIRECT_XIP_VARIANT" on the application's "prj.conf" but this configuration is of the SDK version 2.0.X and I am using the SDK version 1.8.0.

What should I do so that I can get the correct image for the secondary partition (I would like to avoid the migration of the SDK if posible) or what should I configure in the MCUboot so that it can be booted?

Thanks,
Erasmo

Parents
  • Hi Erasmo,

    I have some questions for clarification:

    1. Have you run eraseall on your chip during your testing?
    2. Can you post the changes you made to the nRF Connect SDK? (For example paste the contents of "git diff" into a text document and insert it here)
    3. Can you elaborate a bit more on why you erased the trailer to fix the issue in the first place?

    Regards,
    Sigurd Hellesvik

  • Hi Sigurd,

    Answering your questions in the same order:
    1. Yes, I have run the eraseall before and even during the flash command with the flag "--erase"

    2. I have actually undone all the changes I made to the nRF Connect SDK

    .../v1.8.0/bootloader/mcuboot ((v1.7.99-ncs4))
    $ git status
    HEAD detached at refs/heads/manifest-rev
    nothing to commit, working tree clean
    

    and the error is still present, in the application's project I configured the values:

    CONFIG_BOOTLOADER_MCUBOOT=y
    CONFIG_MCUBOOT_IMAGE_VERSION="0.1"

    and on the MCUboot image's configuration overlay file I set the values:

    CONFIG_MCUBOOT_LOG_LEVEL_DBG=y
    CONFIG_BOOT_SWAP_USING_MOVE=n
    CONFIG_BOOT_DIRECT_XIP=y

    Here the application's log that shows what the problem:

    // ========== Flashed the MCUboot and the application imagge with the --erase flag ========
    *** Booting Zephyr OS build v2.7.0-ncs1  ***
    I: Starting Direct-XIP bootloader
    I: Primary   slot: version=0.1.0+0
    I: Image 0 Secondary slot: Image not found
    I: Image 0 loaded from the primary slot
    I: Bootloader chainload address offset: 0xc000
    *** Booting Zephyr OS build v2.7.0-ncs1  *** 
    [00:00:00.004,791] <inf> : Executing application version {0.1} 
    [00:00:00.039,550] <inf> : BLE library successfully initialized
    [00:00:00.044,311] <inf> : BLE MAC address loaded, addr=C54DC37971B4
    [00:00:00.050,476] <inf> : BLE Advertising process successfully started
    [00:00:05.519,927] <inf> : BLE device connected
    // Started sending the new image through the Bluetooth's DFU service
    [00:00:21.366,058] <inf> mcuboot_util: Swap type: none
    [00:00:21.637,207] <inf> mcuboot_util: Swap type: none
    [00:00:21.637,329] <inf> mcuboot_util: Swap type: none
    // finished the DFU process and the device restarted automatically
    *** Booting Zephyr OS build v2.7.0-ncs1  ***
    I: Starting Direct-XIP bootloader
    I: Primary   slot: version=0.1.0+0
    I: Secondary slot: version=0.4.0+0
    I: Image 0 loaded from the secondary slot
    I: Bootloader chainload address offset: 0x74000 // This is the offset of the secondary partition
    *** Booting Zephyr OS build v2.7.0-ncs1  ***
    [00:00:00.004,821] <inf> : Executing application version {0.1} // As you can see the message is printing the version of theprimary partition's image
    [00:00:00.039,550] <inf> : BLE library successfully initialized
    [00:00:00.044,311] <inf> : BLE MAC address loaded, addr=C54DC37971B4
    [00:00:00.050,476] <inf> : BLE Advertising message successfully started

    This is how I print the application's first log message

    LOG_INF("Executing application version {%s}", CONFIG_MCUBOOT_IMAGE_VERSION);

    3. Just to be clear I didn't erase the trailer to fix the secondary partition's booting error. The thing is that I send the "app_update.bin" to my smartphone, then use the "nRF Connect" application to connect to the device through Bluetooth and do the DFU process. The problem here was that I couldn't overwrite the image in the secondary partition, for example:

    Lets say that in the primary partition I have the image version 2 and the secondary partition is empty, the primary partition is booted, then I do the DFU process and write the image version 1 in the secondary partition, the device restarts and since the secondary partition has a lower version than the primary partition the later is booted. After that I try to send the image version 3 through the DFU process so that it will overwrite the image version 1 that it's in the secondary partition but the during the process it reads that the image in the secondary partition is pending to be swapped, so it restarts the device so that the MCUboot do the swapping process but since I have enable the Direct-XIP configuration in the MCUboot image it will never swap the partitions' images and the swap state won't be updated so every time I try the DFU process it will read the same status and it will just restart the device, meaning I can only write an image in the secondary partition once and I cannot overwrite it.

    I debugged the MCUboot swapping process to see what values of the image's header and trailer modified during the process. On of them was the erasing the image's trailer. So what I did was to open the flash area of the secondary partition and then erase the trailer sector with the same function that the swap process used, this are the two functions I used to do this:

    struct boot_loader_state *state; // parameter of the function
    flash_area_open(FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state)), &fap);
    swap_erase_trailer_sectors(state, fap);

    this change did make it possible to overwrite the image in the secondary partition through the Bluetooth's DFU process.

    Regards

    Erasmo

  • This reply was deleted.
  • You should be aware that the image you put in the secondary slot should be built for that exact address. For example an app_update.bin file might be built for addr. 0x1000 and have the reset addr 0x1100. If you then put this binary file in addr 0x2000 (and reset addr should be 0x2100), it will still see 0x1100 and try to jump there to start code execution.

    Does this make sense? Do you think this is the core of your issue?

    Best regards,

    Simon

  • Yes, that makes sense to me and I also though that might be the issue.

    Is there a configuration that I can use to change the reset address and set it to point at the secondary partition ? or how could I make it boot from the secondary partition directly?

    Regards,

    Erasmo

  • I did some quick tests with the hello world sample to try to achieve this:

    I'm using an nRF52840 DK, since I don't have any nRF5340 DK at the home office at the moment, but it shouldn't matter

    To generate the update bin file, you need to add CONFIG_BOOTLOADER_MCUBOOT=y. When mcuboot is enabled, the image will then be put after the mcuboot, and in this case the offset was 0xc000.

    Also, if MCUboot is enabled, the Partition Manager will be used to locate all the partitions, and the way the partition manager works (if I remember correctly) is by defining the position off all the child images first and wherever there is room at the end, the primary application will be put. So you can not modify the address and size of the app directly. Instead you need to increase the size of mcuboot, so the application offset increases as well.

    • Next, I enabled CONFIG_BOOTLOADER_MCUBOOT=y in prj.conf (to generate app_update.bin)

    Then, let's say you want to create an image for address 0xd000. To achieve this, you can increase the size of the mcuboot partition by 0x1000.

    • In order to increase the mcuboot size by 0x1000, I set CONFIG_PM_PARTITION_SIZE_MCUBOOT=0xd000 (was previously 0xc000) in C:\v2.0.0\bootloader\mcuboot\boot\zephyr\prj.conf (can also be done directly from the application by using any of the methods in this ticket)
    • Then I built the sample and programmed merged.hex to the 52840 DK and confirmed using the nRF Connect Programme app that it was correctly placed.

    The bottom green area you see is just some mcuboot header info and is only 32 bytes. The orange are is mcuboot.

    Now you should find the app_update.bin file located in C:\Nordic\ncs_samples_local\nonzero_offset\build\zephyr\app_update.bin which is built for address 0xD200, and it should have the correct reset address (somewhere between 0xD200 and 0x12B5E). Read more about the reset vector address in Updating start address to nrf52840 dk via code.

    I'm sorry for the long answer, and that I couldn't find any more straight forward way to achieve this. Maybe someone in the community knows?

    Best regards,

    Simon

Reply
  • I did some quick tests with the hello world sample to try to achieve this:

    I'm using an nRF52840 DK, since I don't have any nRF5340 DK at the home office at the moment, but it shouldn't matter

    To generate the update bin file, you need to add CONFIG_BOOTLOADER_MCUBOOT=y. When mcuboot is enabled, the image will then be put after the mcuboot, and in this case the offset was 0xc000.

    Also, if MCUboot is enabled, the Partition Manager will be used to locate all the partitions, and the way the partition manager works (if I remember correctly) is by defining the position off all the child images first and wherever there is room at the end, the primary application will be put. So you can not modify the address and size of the app directly. Instead you need to increase the size of mcuboot, so the application offset increases as well.

    • Next, I enabled CONFIG_BOOTLOADER_MCUBOOT=y in prj.conf (to generate app_update.bin)

    Then, let's say you want to create an image for address 0xd000. To achieve this, you can increase the size of the mcuboot partition by 0x1000.

    • In order to increase the mcuboot size by 0x1000, I set CONFIG_PM_PARTITION_SIZE_MCUBOOT=0xd000 (was previously 0xc000) in C:\v2.0.0\bootloader\mcuboot\boot\zephyr\prj.conf (can also be done directly from the application by using any of the methods in this ticket)
    • Then I built the sample and programmed merged.hex to the 52840 DK and confirmed using the nRF Connect Programme app that it was correctly placed.

    The bottom green area you see is just some mcuboot header info and is only 32 bytes. The orange are is mcuboot.

    Now you should find the app_update.bin file located in C:\Nordic\ncs_samples_local\nonzero_offset\build\zephyr\app_update.bin which is built for address 0xD200, and it should have the correct reset address (somewhere between 0xD200 and 0x12B5E). Read more about the reset vector address in Updating start address to nrf52840 dk via code.

    I'm sorry for the long answer, and that I couldn't find any more straight forward way to achieve this. Maybe someone in the community knows?

    Best regards,

    Simon

Children
  • Hi Simon,

    I first attempted the configurations CONFIG_FLASH_LOAD_OFFSET=0x500  and CONFIG_USE_DT_CODE_PARTITION=n, but my project wouldn't apply it.

    Then I attempted increasing the size of the MCUboot partition so that the primary partition will start where the secondary partition starts but the image's partitions became so small that the application couldn't fit so I got and Overflow error durring compilation.

    After that I tried using the configuration CONFIG_SINGLE_APPLICATION_SLOT in the MCUboot image configuration to remove one of the two image's partitions, that way the only partition will have the size it will normally have after I increase the size of the MCUboot partition. But for this to work I had to disable the Bluetooth module and I need it.

    Solution:

    Luckily, while I was checking one of the ticket you reference me to I saw a comment about reducing the size of the secondary partition and increasing the primary partition using a pm_static.yml file (place it in the root folder of the project, where the prj.conf file is). But instead of continue changing the size of the partitions I tried swapping the position of the image's partitions mcuboot_primary and mcuboot_secondary, this way when the application compiled it has the address of the primary partition which now is in the flash area where the secondary partition is originally.

    pm_static.yml:

    app:
      address: 0xc200
      end_address: 0x84000
      region: flash_primary
      size: 0x77e00
    mcuboot:
      address: 0x0
      end_address: 0xc000
      placement:
        before:
        - mcuboot_secondary
      region: flash_primary
      size: 0xc000
    mcuboot_secondary:
      address: 0xc000
      end_address: 0x84000
      placement:
        before:
        - mcuboot_primary
        align:
          start: 0x4000
      region: flash_primary
      share_size:
      - mcuboot_primary
      size: 0x78000
    mcuboot_pad:
      address: 0x84000
      end_address: 0x84200
      placement:
        align:
          start: 0x4000
        before:
        - mcuboot_primary_app
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0x84000
      end_address: 0xfc000
      orig_span: &id001
      - mcuboot_pad
      - app
      region: flash_primary
      sharers: 0x1
      size: 0x78000
      span: *id001
    mcuboot_primary_app:
      address: 0x84200
      end_address: 0xfc000
      orig_span: &id002
      - app
      region: flash_primary
      size: 0x77e00
      span: *id002
    otp:
      address: 0xff8100
      end_address: 0xff83fc
      region: otp
      size: 0x2fc
    pcd_sram:
      address: 0x2006e000
      end_address: 0x20070000
      placement:
        before:
        - rpmsg_nrf53_sram
        - end
      region: sram_primary
      size: 0x2000
    rpmsg_nrf53_sram:
      address: 0x20070000
      end_address: 0x20080000
      placement:
        before:
        - end
      region: sram_primary
      size: 0x10000
    settings_storage:
      address: 0xfc000
      end_address: 0x100000
      placement:
        align:
          start: 0x4000
        before:
        - end
      region: flash_primary
      size: 0x4000
    sram_primary:
      address: 0x20000000
      end_address: 0x2006e000
      region: sram_primary
      size: 0x6e000
    

    How this works is that when I am going to flash the MCUboot image and the application in the primary partition I remove the pm_static file and when I need to generate an app_update.bin file for the secondary partition I add the pm_static file.

    Regards,

    Erasmo

  • There you go! That seems like a better solution than what I suggested

Related