Using MCUBoot with nRF5340

Hello,

I try to figure out, how to correctly setup MCUboot for an nrf5340, so that:

  • Application is updatable
  • BT Stack is updatable
  • Firmware Updates are encrypted and signed
  • Updates are stored in external flash memory
  • No need to update the bootloader itself
  • Updates are stored on the external flash by some application specific protocol.

For that task, I upgraded our project to nrfconnect/sdk-nrf version v2.7.99-cs2. My current understanding is, that I want to use Sysbuild and have to define a static partition. I haven't found any comprehensive documentation, that defines exactly, which partitions are required for the given setup. So, I search for something in the examples, that could come close to my setup. The result of this example `pm_static.yml` looks like this:

app:
  address: 0x10200
  region: flash_primary
  size: 0xdfe00
mcuboot:
  address: 0x0
  region: flash_primary
  size: 0x10000
mcuboot_pad:
  address: 0x10000
  region: flash_primary
  size: 0x200
mcuboot_primary:
  address: 0x10000
  region: flash_primary
  size: 0xe0000
  span: [mcuboot_pad, app]
mcuboot_primary_app:
  address: 0x10200
  region: flash_primary
  size: 0xdfe00
  span: [app]
settings_storage:
  address: 0xf0000
  region: flash_primary
  size: 0x10000
mcuboot_primary_1:
  address: 0x0
  size: 0x40000
  device: nordic_ram_flash_controller
  region: ram_flash
mcuboot_secondary:
  address: 0x00000
  size: 0xe0000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  region: external_flash
mcuboot_secondary_1:
  address: 0xe0000
  size: 0x40000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  region: external_flash
external_flash:
  address: 0x120000
  size: 0x6e0000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  region: external_flash
pcd_sram:
  address: 0x20000000
  size: 0x2000
  region: sram_primary

However, in the resulting `partition_manager_report`:

  external_flash (0x800000 - 8192kB): 
+------------------------------------------------+
| 0x0: mcuboot_secondary (0xe0000 - 896kB)       |
| 0xe0000: mcuboot_secondary_1 (0x40000 - 256kB) |
| 0x120000: external_flash (0x6e0000 - 7040kB)   |
+------------------------------------------------+

  flash_primary (0x100000 - 1024kB): 
+--------------------------------------------------+
| 0x0: mcuboot (0x10000 - 64kB)                    |
+---0x10000: mcuboot_primary (0xe0000 - 896kB)-----+
| 0x10000: mcuboot_pad (0x200 - 512B)              |
+---0x10200: mcuboot_primary_app (0xdfe00 - 895kB)-+
| 0x10200: app (0xdfe00 - 895kB)                   |
+--------------------------------------------------+
| 0xf0000: settings_storage (0x10000 - 64kB)       |
+--------------------------------------------------+

  otp (0x2fc - 764B): 
+------------------------------+
| 0xff8100: otp (0x2fc - 764B) |
+------------------------------+

  sram_primary (0x80000 - 512kB): 
+-----------------------------------------------+
| 0x20000000: pcd_sram (0x2000 - 8kB)           |
| 0x20002000: sram_primary (0x6e000 - 440kB)    |
| 0x20070000: rpmsg_nrf53_sram (0x10000 - 64kB) |
+-----------------------------------------------+

the partition `mcuboot_primary_1` is simply missing (and later the compilation of `nrf/modules/mcuboot/hooks/nrf53_hooks.c` fails with an undeclared symbol `PM_MCUBOOT_PRIMARY_1_ADDRESS`. 

I found this warning in the DTS parsing:

warning: FLASH_SIMULATOR (defined at drivers/flash/Kconfig.simulator:6) was assigned the value 'y'
but got the value 'n'. Check these unsatisfied dependencies: DT_HAS_ZEPHYR_SIM_FLASH_ENABLED (=n).
See http://docs.zephyrproject.org/latest/kconfig.html#CONFIG_FLASH_SIMULATOR and/or look up
FLASH_SIMULATOR in the menuconfig/guiconfig interface.

The referenced documentation just contains the sentence: "Enable the flash simulator."

What do I have to do, to use MCUBoot? 

Is there any comprehensive documentation, that clearly states, what is required to completely configure the bootloader?

Parents
  • Hello,

    I've created a demo based on the peripheral_lbs sample, please see attached below.

    Demo sample

    peripheral_lbs_enc_fota.zip

    Disclaimers

    - DFU with encrypted images is not a feature that has been tested or validated by Nordic ( nRF52840 + NCS + MCUBoot, CC310-enabled image encryption? ) .

    - The cmake signing script does not sign encrypt the netcore image. This can be fixed by patching relevant cmake script.

    - The application_dfu.zip generated by the build contains signed but not encrypted images. Use the /build/peripheral_lbs_fota_enc/zephyr/zephyr.signed.encrypted.bin binary instead (application image). The netcore image which is signed but not encrypted is called signed_by_mcuboot_and_b0_ipc_radio.bin and is located in build/.

    - I have not done any extensive testing of this demo, just verified that I was able to update the appcore FW.

    Best regards,

    Vidar

  • Thank you! I will go through that example.

    An other, very annoying observation I made: In the corse to, basically "try and error", figuring out some settings that fixes build errors, I found, that the build is not reproducible!

    Currently, I have a state, where I completely delete the build folder, start the build with `--pristine` added to the `west build` command and get alternating, two different errors. The one error, is the error above, while building the application.After I received that error, I delete the build folder again and rerun the build command. Every second time, I receive a linker error, while linking the application (a missing symbol, probably not defined due to the first issue).

    As the second error is a linker error, this can not be any effect from parallel build, where the order of build steps could change. I disable the usage of `ccache`, but the behavior does not change. :-/

  • I'm not sure if I have experienced the same. Could you please try and see if you experience the same with the sample I provided? The linker error for PM_MCUBOOT_PRIMARY_1_ADDRESS will be raised if the flash RAM partition is missing.

  • I'm not even able to trigger the error above. My `pm_static.yml` works in your example, albeit the resulting partition_manager_report look different. I guess, I have to revisit every switch and configuration bit and make two clean builds with every change.

    Largest difference, I see is that my build does not include the `b0n` (which I think is required for the update of the bluetooth HCI controller on the radio core).

  • Yes, B0n is required for netcore DFU. It is enabled through the SB_CONFIG_SECURE_BOOT_NETCORE symbol in sysbuild.conf

  • With your configuration, I was at least able to build all images without error. Now, I'm debugging the bootloader. I'm not able to enable RTT logging. But currently, the startup stops by an attempt to iterate over all images. All flash areas are opened and a few of the 11 flash areas do not have the fa_dev in struct flash_area set.

    This flash_map seem to be build in flash_map_partion_manager.c and there, fa_dev is assigned by `DEVICE_DT_GET_OR_NULL(DT_MTD_FROM_FIXED_PARTITION(part))` which somehow implies, that a value of 0 is expected for that map.

    Now, I wonder, why that member is assigned to 0, if later, at runtime, a value != 0 is expected and how can I figure out, what is going wrong.

  • Logging over RTT can be unreliable when there are multiple images in the boot chain, as the next image in the boot sequence may overwrite the RTT log buffer in RAM. However, a common reason for the bootloader failing to boot the app and entering FIH_PANIC is that there were an error in configuring the external flash. Can you provide your generated zephyr.dts and .config file? These are located in build/mcuboot/zephyr.

    Also, are you currently testing with or without a static partitioning file? Either way, please provide the partition file as well if possible.

Reply
  • Logging over RTT can be unreliable when there are multiple images in the boot chain, as the next image in the boot sequence may overwrite the RTT log buffer in RAM. However, a common reason for the bootloader failing to boot the app and entering FIH_PANIC is that there were an error in configuring the external flash. Can you provide your generated zephyr.dts and .config file? These are located in build/mcuboot/zephyr.

    Also, are you currently testing with or without a static partitioning file? Either way, please provide the partition file as well if possible.

Children
  • Currently, I try to use a static portions. Thanks for looking into this. Files are renamed to be accepted by your forums software.4530.zephyr.dts

    app:
      address: 0x10200
      region: flash_primary
      size: 0xdfe00
    mcuboot:
      address: 0x0
      region: flash_primary
      size: 0x10000
    mcuboot_pad:
      address: 0x10000
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0x10000
      region: flash_primary
      size: 0xe0000
      span: [mcuboot_pad, app]
    mcuboot_primary_app:
      address: 0x10200
      region: flash_primary
      size: 0xdfe00
      span: [app]
    settings_storage:
      address: 0xf0000
      region: flash_primary
      size: 0x10000
    mcuboot_primary_1:
      address: 0x0
      size: 0x40000
      device: nordic_ram_flash_controller
      region: ram_flash
    mcuboot_secondary:
      address: 0x00000
      size: 0xe0000
      device: DT_CHOSEN(nordic_pm_ext_flash)
      region: external_flash
    mcuboot_secondary_1:
      address: 0xe0000
      size: 0x40000
      device: DT_CHOSEN(nordic_pm_ext_flash)
      region: external_flash
    external_flash:
      address: 0x120000
      size: 0x6e0000
      device: DT_CHOSEN(nordic_pm_ext_flash)
      region: external_flash
    pcd_sram:
      address: 0x20000000
      size: 0x2000
      region: sram_primary
    
    4034..config.txt

  • Thanks. It appears that you are missing the 'nordic,pm-ext-flash' property in your zephyr.dts. Without this, the bootloader will not know which flash device to use for accessing the partitions in 'external_flash'. In my sample, I had a board overlay to set this 'chosen' (/peripheral_lbs_fota_enc/sysbuild/mcuboot/boards/nrf5340dk_nrf5340_cpuapp.overlay) 

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

  • This is the start of my `app.overlay`:

     &zephyr_udc0 {
        cdc_acm_uart0 {
            compatible = "zephyr,cdc-acm-uart";
        };
    };
    
    / {
        chosen {
            nordic,pm-ext-flash = &mx25r64;
        };
    };
    
    /*
       Disable QSPI peripheral, to not get the Zephyr QSPI driver linked in,
       which would clash with drivers/flash_memory.cpp
     */
    &qspi {
        status = "disabled";
    };
    
    ...

    I've disabled the qspi-disable part of the overlay file, but still there are some entries in `flash_map` with `fa_dev` set to 0 (and the resulting dts still does not contain the required chosen value):

    (gdb) p/x *flash_map@flash_map_entries
    $3 = {{
        fa_id = 0x0,
        pad16 = 0x0,
        fa_off = 0x0,
        fa_size = 0x10000,
        fa_dev = 0x94b0
      }, {
        fa_id = 0x1,
        pad16 = 0x0,
        fa_off = 0x0,
        fa_size = 0x40000,
        fa_dev = 0x949c
      }, {
        fa_id = 0x2,
        pad16 = 0x0,
        fa_off = 0x0,
        fa_size = 0xe0000,
        fa_dev = 0x0
      }, {
        fa_id = 0x3,
        pad16 = 0x0,
        fa_off = 0x10000,
        fa_size = 0x200,
        fa_dev = 0x94b0
      }, {
        fa_id = 0x4,
        pad16 = 0x0,
        fa_off = 0x10000,
        fa_size = 0xe0000,
        fa_dev = 0x94b0
      }, {
        fa_id = 0x5,
        pad16 = 0x0,
        fa_off = 0x10200,
        fa_size = 0xdfe00,
        fa_dev = 0x94b0
      }, {
        fa_id = 0x6,
        pad16 = 0x0,
        fa_off = 0x10200,
        fa_size = 0xdfe00,
        fa_dev = 0x94b0
      }, {
        fa_id = 0x7,
        pad16 = 0x0,
        fa_off = 0x40000,
        fa_size = 0x0,
        fa_dev = 0x949c
      }, {
        fa_id = 0x8,
        pad16 = 0x0,
        fa_off = 0xe0000,
        fa_size = 0x40000,
        fa_dev = 0x0
      }, {
        fa_id = 0x9,
        pad16 = 0x0,
        fa_off = 0xf0000,
        fa_size = 0x10000,
        fa_dev = 0x94b0
      }, {
        fa_id = 0xa,
        pad16 = 0x0,
        fa_off = 0x120000,
        fa_size = 0x6e0000,
        fa_dev = 0x0
      }}
    

    The number of entries in the array corresponds with the number of entries in pm_static.yml, but the order seems to be different.

    The only warning I receive from the `* Running CMake for mcuboot *` is about the RTT configuration. For the application cmake run, I got this warning:

        warning: UPDATEABLE_IMAGE_NUMBER (defined at /Users/todi/bloomlife/zephyr-
        workspace/nrf/samples/common/mcumgr_bt_ota_dfu/Kconfig:88, subsys/dfu/Kconfig:95) was assigned the
        value '2' but got the value ''. Check these unsatisfied dependencies:
        (((BOARD_THINGY53_NRF5340_CPUAPP || BOARD_THINGY53_NRF5340_CPUAPP_NS) && SOC_SERIES_NRF53X &&
        NCS_SAMPLE_MCUMGR_BT_OTA_DFU) || (!MCUBOOT && IMG_MANAGER)) (=n). See
        http://docs.zephyrproject.org/latest/kconfig.html#CONFIG_UPDATEABLE_IMAGE_NUMBER and/or look up
        UPDATEABLE_IMAGE_NUMBER in the menuconfig/guiconfig interface. The Application Development Primer,
        Setting Configuration Values, and Kconfig - Tips and Best Practices sections of the manual might be
        helpful too.
    

    Could that be a hint as to where the problem is?

  • Yes, but the app.overlay is normally not applied to the mcuboot build, only the main application. I see you are also disabling the QSPI node. Is the mx25r64 not on your QSPI bus?

    The only warning I receive from the `* Running CMake for mcuboot *` is about the RTT configuration. For the application cmake run, I got this warning:

    It looks like you are missing the CONFIG_IMG_MANAGER. Did you use my configurations from peripheral_lbs_fota_enc/boards/nrf5340dk_nrf5340_cpuapp.conf?

  • Sorry, but I can not directly use your configuration (that's a general problem of this documentation-by-example approach), because I have an application, that requires certain configurations and I need to somehow merge your configurations with the ones, required by my app.

    `CONFIG_NCS_SAMPLES_DEFAULTS` was applied for testing. Later, I probably have to remove this "catch-all" option and have to figure out, which parts of this are relevant.

    `CONFIG_BT`, `CONFIG_BT_PERIPHERAL` have the same values, `CONFIG_BT_DEVICE_NAME` is set, but to a different value.

    `CONFIG_BT_LBS`, `CONFIG_BT_LBS_POLL_BUTTON` and `CONFIG_DK_LIBRARY` are not used, as I don't want to receive the firmware updates via that BLE service.

    `CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE` is set to the exact value.

    Adding `CONFIG_NCS_SAMPLES_DEFAULTS` does not solve the issue.

    I made an other observation: When I change the device name in `device: DT_CHOSEN(nordic_pm_ext_flash)` from the `pm_static.yml` into something, that not exists, I do not get any build errors.

    Does this nordic_pm_ext_flash maps to `nordic,pm-ext-flash = &mx25r64;` in the chosen section?

Related