MCUBoot’s secondary image on external Flash : Down into the rabbit hole and back

I struggled to host MCUBoot's secondary image on the external Flash of the nRF5340DK. I hit so many obstacles along the way that I'm pretty sure I went off track early on and didn't do this properly. First I followed these guidelines and added a device tree overlay:

/ {
        chosen {
                nordic,pm-ext-flash = &mx25r64;
        };

};

and made sure it also applied to MCUBoot (cmake from application):

set(mcuboot_DTC_OVERLAY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${BOARD}.overlay")

But at runtime, MCUBoot complained about BOOT_MAX_IMG_SECTORS:

W: Failed reading sectors; BOOT_MAX_IMG_SECTORS=128 - too small?

where I assume that 128 matches the number of sectors of the primary partition when the external Flash isn't use. So I doubled it :

set(mcuboot_CONFIG_BOOT_MAX_IMG_SECTORS 256)

even if I would have expected that CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY (defined in prj.conf) would take care of that. Next, MCUBoot complained about an incompatible amount of sectors. As a matter of fact, the generated static partitions (build/partitions.yml) defined the size of mcuboot_secondary as 0. So I also took care of that by redefining the static partitions and matching the size of the mcuboot_secondary to mcuboot_primary:

set(PM_STATIC_YML_FILE
  ${CMAKE_CURRENT_SOURCE_DIR}/partitions.yml
  )
  

app:
  address: 0xc200
  end_address: 0xfe000
  region: flash_primary
  size: 0xf1e00
external_flash:
  address: 0x0
  end_address: 0x800000
  region: external_flash
  size: 0x800000
mcuboot:
  address: 0x0
  end_address: 0xc000
  placement:
    before:
    - mcuboot_primary
  region: flash_primary
  size: 0xc000
mcuboot_pad:
  address: 0xc000
  end_address: 0xc200
  placement:
    align:
      start: 0x4000
    before:
    - mcuboot_primary_app
  region: flash_primary
  size: 0x200
mcuboot_primary:
  address: 0xc000
  end_address: 0xfe000
  orig_span: &id001
  - app
  - mcuboot_pad
  region: flash_primary
  size: 0xf2000
  span: *id001
mcuboot_primary_app:
  address: 0xc200
  end_address: 0xfe000
  orig_span: &id002
  - app
  region: flash_primary
  size: 0xf1e00
  span: *id002
mcuboot_secondary:
  address: 0x0
  device: MX25R64
  end_address: 0xf2000
  placement:
    align:
      start: 0x4
  region: external_flash
  size: 0xf2000
otp:
  address: 0xff8100
  end_address: 0xff83fc
  region: otp
  size: 0x2fc
pcd_sram:
  address: 0x2007e000
  end_address: 0x20080000
  placement:
    before:
    - end
  region: sram_primary
  size: 0x2000
settings_storage:
  address: 0xfe000
  end_address: 0x100000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x2000
sram_primary:
  address: 0x20000000
  end_address: 0x2007e000
  region: sram_primary
  size: 0x7e000


For there, things went smoothly up until the point where boot_request_upgrade is called (either directly or from DFU API). I dug a little deeper and found that it fails attempting to write the boot magic number. Unlike the chunks of firmware updates, the magic number is not hosted in RAM, but in the internal Flash program memory (variable defined as const) and write_from_nvmc instead of nrfx_qspi_write is called. Quite frankly I didn't bother to check why, but write_from_nvmc returns an error that translates to EINVAL (Invalid argument). I just went ahead and changed MCUBoot to :

int
boot_write_magic(const struct flash_area *fap)
{
    uint32_t off;
    int rc;
    static uint32_t lBootMagic[] = {
    0xf395c277,
    0x7fefd260,
    0x0f505235,
    0x8079b62c,
    };

    off = boot_magic_off(fap);

    printk("writing magic; fa_id=%d off=0x%lx (0x%lx), size=%d, total size=%d vs %d\n\n",
                 fap->fa_id, (unsigned long)off,
                 (unsigned long)(fap->fa_off + off), BOOT_MAGIC_SZ, fap->fa_size,off+BOOT_MAGIC_SZ);
    rc = flash_area_write(fap, off, lBootMagic, BOOT_MAGIC_SZ);
    if (rc != 0) {
        printk("flash_area_write failed with error code %d\n\n", rc);
        return BOOT_EFLASH;
    }

    return 0;
}

and I finally managed successfully upgrade the system using a secondary image hosted on the external Flash. But I had to change MCUBoot to do so. Is this a bug, or did I simply went off track somewhere? Thanks.

Parents
  • Hi,

     

    I'm sorry to hear that the process was this demanding! I will surely report this internally.

    For there, things went smoothly up until the point where boot_request_upgrade is called (either directly or from DFU API). I dug a little deeper and found that it fails attempting to write the boot magic number. Unlike the chunks of firmware updates, the magic number is not hosted in RAM, but in the internal Flash program memory (variable defined as const) and write_from_nvmc instead of nrfx_qspi_write is called. Quite frankly I didn't bother to check why, but write_from_nvmc returns an error that translates to EINVAL (Invalid argument). I just went ahead and changed MCUBoot to :

    Looking at the sequence, and your description of the problem, it seems that it is unable to write the external flash (secondary slot) magic tags.

    As a alternative test, could you try setting this in mcuboot.conf and see if it works w/o changing boot_write_magic() then?

    Here's the setting for child_image/mcuboot.conf:

    CONFIG_SPI_NRFX_RAM_BUFFER_SIZE=16

     

    Kind regards,

    Håkon

Reply
  • Hi,

     

    I'm sorry to hear that the process was this demanding! I will surely report this internally.

    For there, things went smoothly up until the point where boot_request_upgrade is called (either directly or from DFU API). I dug a little deeper and found that it fails attempting to write the boot magic number. Unlike the chunks of firmware updates, the magic number is not hosted in RAM, but in the internal Flash program memory (variable defined as const) and write_from_nvmc instead of nrfx_qspi_write is called. Quite frankly I didn't bother to check why, but write_from_nvmc returns an error that translates to EINVAL (Invalid argument). I just went ahead and changed MCUBoot to :

    Looking at the sequence, and your description of the problem, it seems that it is unable to write the external flash (secondary slot) magic tags.

    As a alternative test, could you try setting this in mcuboot.conf and see if it works w/o changing boot_write_magic() then?

    Here's the setting for child_image/mcuboot.conf:

    CONFIG_SPI_NRFX_RAM_BUFFER_SIZE=16

     

    Kind regards,

    Håkon

Children
Related