MCUBoot manual compile + usage

We're using NCS embedded into our Makefile-based build system to compile nRF5340 applications out-of-tree, but still having unresolved problems. The target board is a custom nRF5340 design. I'm continuously looking for alternative ways to achieve my goal: have MCUBoot run on APP core alongside our program + being able to perform FW upgrade. The problems are described in the linked ticket, now I'd like to show what other things I've been trying to do.

I've figured out how to manually configure, menuconfig and compile NCS's MCUBoot, so now I can generate MCUBoot's zephyr.hex independently of my application. Burning it to the flash isn't a problem either. Important to note, the application has no MCUBoot enabled as a child image (because we're having problems with it, see the linked ticket), it's a simple, standalone program.

Once the application is compiled, the resulting zephyr.hex is signed like this:

imgtool.py sign --align=1 --version="9.8.7" --header-size=512 --slot-size=0x77000 --hex-addr=0x10000 zephyr.hex signed.hex

Burning signed.hex to flash, MCUBoot successfully boots it. Great!

To check how MCUBoot swapping is operating, generated a different zephyr.hex and signed it:

imgtool.py sign --align=1 --version="9.8.7" --header-size=512 --slot-size=0x77000 --hex-addr=0x87000 ph2.hex signed.hex

(In DTS, slot0_partition begins at 0x10000, while slot1_partition begins at 0x87000, their sizes are 0x77000)

After burning the new FW image to slot1, MCUBoot does nothing, still boots the original image. (Swapping is enabled in MCUBoot config). This is what MCUBoot displays on serial console:

*** Booting Zephyr OS build v3.2.99-ncs1 ***
I: Starting bootloader
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Swap type: none
I: Bootloader chainload address offset: 0x10000
�*** Booting Zephyr OS build v3.2.99-ncs1 ***
================================================================================
project config: default sample project
...
...

I'd like to ask for some help, pointers or advices on the following questions:

  1. how can I make MCUBoot swap my new FW image? I believe this must be something with the lack of FW image trailers. If so, how can I manually generate trailers, or how to init them?
  2. Planned FW upgrade will be working like this: the running application gets the image file fragments via some kind of networking (e.g. TCP/IP). How can the application pass the fragments to MCUBoot? This is pretty unclear to me, as MCUBoot executes first after reset, but when it loads the application from slot0, MCUBoot no longer remains in memory, it's no longer running (if I'm not totally wrong). So if my assumption is right, there must be some MCUBoot-support code in Zephyr, which makes it possible to write new image's fragment to slot1, generate trailer and so on.
    The first thing I want to experiment with is that a sample app is being burnt into slot0, and this app contains the image of a new app; this old sample app emits image fragments, which get written to slot1, and then resets and MCUBoot does its job (swaps images);

Many thanks, regards,

Parents
  • There is some progress regarding FW upgrade.

    We have given up the concept of manually compiling MCUboot, instead the build system does the job. It was a good decision ;)

    The new image to be burnt to APP and NET cores are available on the APP core (by TCP/IP or other magic of ours).

    Our custom board doesn't feature any external flash.

    I've enabled MCUboot on both APP and NET cores and created static partition layouts for both cores. This resulted in two large prog partitions (primary and secondary) on both cores (and other small partitions).

    We can successfully upgrade APP core's FW by using MCUboot's "move swap" feature. The FW upgrade is initiated somehow like this:

    struct flash_img_context fic;

    flash_img_init_id(&fic, PM_MCUBOOT_SECONDARY_ID);
    boot_erase_img_bank(PM_MCUBOOT_SECONDARY_ID);
    flash_img_buffered_write(&fic, fw_upg_img, sizeof(fw_upg_img), true);
    boot_request_upgrade(BOOT_UPGRADE_PERMANENT);

    On next reboot MCUboot copies the new image from secondary partition to primary, works well.

    Now we need to make it work for NET core too. Unfortunately, if we follow the same scheme for NET core flash partitioning as for APP core partitioning, the resulting primary and secondary partitions will be very small, less than 128kB, so the new image can easily outrun this size. If we had only one prog partition that could be almost 256kB in size.

    My idea is to programmatically shut down NET core and update NET core flash area from a program running on APP core. This way we don't need to create primary and secondary partitions on the NET core, and the only prog partition can be large enough.

    Does the MCU support this kind of operation?

    There are some other alternatives naturally. One that I can think of now: APP core resets NET core, the MCUboot on the NET core takes FW image parts from the APP-NET shared memory and upgrades the program partition. Does MCUboot support this or anything similar?

    Thanks, regards,

  • As I can see, a BusFault is generated when APP core tries to access NET core's flash area, but it's working in the opposite direction, at least NET core is capable of reading APP's flash area.

    The best would be if NET MCUboot could take FW image chunks from APP core through e.g. shared memory, so it could write directly onto flash, and there was no need for a secondary flash partition...

Reply Children
  • Do you need to update the network and app core simultaneously? If not, you can update the netcore separately using the same secondary slot and let the bootloader take care of transferring the image to the netcore.

  • Not needed to update simultaneously. Do I need to use MCUboot in this case on NET core? Shall I use PCD?

  • The MCUBoot bootloader on the appcore will check the reset vector address of the image your application uploaded to the secondary slot, and if it finds that the address belongs to the network core, it will update the net core. This requires PCD_APP and PDC_NET to be enabled, but they should be by default.

    https://github.com/nrfconnect/sdk-mcuboot/blob/adab597a0eb0eb9c030a7b797748a49ca89988c2/boot/bootutil/src/loader.c#L1052 

  • Thanks.

    I'm constantly having a tons of troubles with the build system and bootloaders. I'm summarizing the current situation, perhaps it makes it easier to solve the issues.

    • we're developing to both nRF5340 APP and NET cores;
    • APP and NET core applications are independent from each other in terms of build, so there's no child image or other magic involved. The applications are simply built and the resulting merged.hex files are burnt to flash by nrfjprog in two steps;
      • I've spent several hours to find the proper child image / multi image solution, but it all failed, and this was the only working solution to me;
    • APP core features MCUboot with static PM partitioning, two slots. I'm now able to upgrade APP core's FW;
    • NET core features also an MCUboot with static PM partitioning, but yesterday is realized this is the wrong approach;
    • according to my current knowledge, NET core is suggested to use the NSIB/B0N bootloader;
    • I've disabled MCUboot on NET core, enabled B0N (CONFIG_SECURE_BOOT);
    • at the moment I really don't care if devel keys are used to sign the bootloader/images, I'll treat them later;
    • if I'm not wrong, the NET core FW upgrade is accomplished somehow like this:
      • the new NET core image is downloaded to the APP core, where it's stored on the secondary slot;
      • when APP MCUboot is running, it detects that the image on the secondary slot is for the NET core;
      • NET core is reset by MCUboot;
      • B0N is running on the net core;
      • MCUboot controls B0N via SRAM (RPC? libmetal? openamp?), this way the new NET core FW image is passed to B0N, which programs into NET flash;

    My issues:

    • I don't understand why both PCD_APP and PCD_NET need to be enabled in APP MCUboot;
    • haven't ever seen a valid static partitioning for B0N, so I don't know whether my config is alright;
    • I can't find B0N configuration file, and don't know whether it has to be configured by me either. It's also unknown if it features a menuconfig like MCUboot does;
    • tried to understand samples/nrf5340/netboot entirely, but may have misunderstood:
      • on APP side, MCUboot calls pcd_network_core_update to reset NET core and to announce FW upgrade is available, and waits for NET core to take the image;
      • on NET side, to be able to utilize PCD, the B0N must be extended with custom code to call pcd_fw_copy(...) and friends. This function pulls the FW upgrade image from APP core, if available;
        • do I really have to take care of this? Doesn't B0N already have a factory code to do this?
        • if I have to take care of this, CONFIG_IS_SECURE_BOOTLOADER must be enabled, but in this case how will my general code compile to NET core?
    • finally, why my application for NET core with B0N won't compile;

    Config of NET core app:

    CONFIG_GPIO=y
    CONFIG_WATCHDOG=y
    CONFIG_HEAP_MEM_POOL_SIZE=38912
    CONFIG_PINCTRL=y
    CONFIG_SERIAL=y
    CONFIG_MAIN_STACK_SIZE=1536
    # CONFIG_NEWLIB_LIBC_NANO is not set
    CONFIG_ENTROPY_GENERATOR=y
    CONFIG_SECURE_BOOT=y
    # CONFIG_SB_MONOTONIC_COUNTER is not set
    # CONFIG_NRF_RPC_CBOR is not set
    CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS=1
    CONFIG_LIBBSP_CONSOLE_OTHER_CORE=y
    CONFIG_LIBBSP_CONSOLE_OTHER_CORE_PREFIX="APP:"
    CONFIG_NRF_RPC=y
    CONFIG_NRF_RPC_GROUP_INIT_WAIT_TIME=300
    CONFIG_SOC_SERIES_NRF53X=y
    CONFIG_SOC_NRF5340_CPUNET_QKAA=y
    CONFIG_BUILD_OUTPUT_INFO_HEADER=y
    CONFIG_SOC_LOG_LEVEL_ERR=y
    CONFIG_ARM_MPU=y
    CONFIG_HW_STACK_PROTECTION=y
    CONFIG_MPU_LOG_LEVEL_ERR=y
    CONFIG_KERNEL_LOG_LEVEL_ERR=y
    CONFIG_THREAD_NAME=y
    CONFIG_THREAD_MAX_NAME_LEN=16
    CONFIG_CLOCK_CONTROL_LOG_LEVEL_ERR=y
    CONFIG_CONSOLE=y
    CONFIG_UART_CONSOLE=y
    CONFIG_UART_CONSOLE_LOG_LEVEL_OFF=y
    CONFIG_ENTROPY_LOG_LEVEL_OFF=y
    CONFIG_ENTROPY_NRF5_THR_THRESHOLD=4
    CONFIG_ENTROPY_NRF5_ISR_THRESHOLD=12
    CONFIG_FLASH=y
    CONFIG_GPIO_LOG_LEVEL_OFF=y
    CONFIG_FXL6408_LOG_LEVEL_OFF=y
    CONFIG_MBOX_LOG_LEVEL_ERR=y
    CONFIG_PINCTRL_LOG_LEVEL_OFF=y
    CONFIG_UART_LOG_LEVEL_ERR=y
    CONFIG_WDT_LOG_LEVEL_OFF=y
    CONFIG_NEWLIB_LIBC=y
    CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=2048
    CONFIG_CBPRINTF_NANO=y
    CONFIG_CBPRINTF_PACKAGE_LOG_LEVEL_OFF=y
    CONFIG_CONSOLE_SUBSYS=y
    CONFIG_CONSOLE_GETCHAR=y
    CONFIG_CONSOLE_PUTCHAR_BUFSIZE=1024
    CONFIG_THREAD_ANALYZER=y
    CONFIG_THREAD_ANALYZER_USE_PRINTK=y
    # CONFIG_ASSERT_VERBOSE is not set
    CONFIG_ASSERT_NO_COND_INFO=y
    CONFIG_ASSERT_NO_MSG_INFO=y
    CONFIG_IPC_SERVICE_LOG_LEVEL_ERR=y
    CONFIG_LOG=y
    CONFIG_LOG_MODE_MINIMAL=y
    CONFIG_LOG_OUTPUT=y
    CONFIG_STREAM_FLASH=y
    CONFIG_STREAM_FLASH_ERASE=y
    CONFIG_COMPILER_FREESTANDING=y
    CONFIG_FORTIFY_SOURCE_NONE=y
    # CONFIG_OUTPUT_DISASSEMBLY is not set

    Current static PM config:

    # NOTE
    # 'b0n' and 'provision' partitions must not be defined, because they're automatically
    # done so by build system/PM.
    
    app:
      address: 0x1008800
      size: 0x32000
      

    Build output (no provision.hex is generated during build):

    -- west build: generating a build system
    Loading Zephyr default modules (Zephyr base).
    -- Application: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net
    -- CMake version: 3.25.2
    -- Found Python3: /usr/bin/python3.10 (found suitable exact version "3.10.10") found components: Interpreter 
    -- Cache files will be written to: /home/tselmeci/.cache/zephyr
    -- Zephyr version: 3.3.99 (/home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-wlt-v5r1-ncs/zephyr)
    -- Found west (found suitable version "1.1.0", minimum required is "0.7.1")
    -- Board: wlt_v5r1_net
    -- ZEPHYR_TOOLCHAIN_VARIANT not set, trying to locate Zephyr SDK
    -- Found host-tools: zephyr 0.16.1 (/home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1)
    -- Found toolchain: zephyr 0.16.1 (/home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1)
    -- Found Dtc: /bin/dtc (found suitable version "1.6.1", minimum required is "1.4.6") 
    -- Found BOARD.dts: /home/tselmeci/projects/base-env1.git/src/libbsp/nrfconnect/boards/arm/wlt-v5r1/wlt_v5r1_net.dts
    -- Generated zephyr.dts: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/zephyr/zephyr.dts
    -- Generated devicetree_generated.h: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/zephyr/include/generated/devicetree_generated.h
    -- Including generated dts.cmake file: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/zephyr/dts.cmake
    Parsing /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/Kconfig
    Loaded configuration '/home/tselmeci/projects/base-env1.git/src/libbsp/nrfconnect/boards/arm/wlt-v5r1/wlt_v5r1_net_defconfig'
    Merged configuration '/home/tselmeci/projects/base-env1.git/src/configs/app/wlt-v5r1-ncs/defconfig.net'
    Configuration saved to '/home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/zephyr/.config'
    Kconfig header saved to '/home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/zephyr/include/generated/autoconf.h'
    -- Found GnuLd: /home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd (found version "2.38") 
    -- The C compiler identification is GNU 12.2.0
    -- The CXX compiler identification is GNU 12.2.0
    -- The ASM compiler identification is GNU
    -- Found assembler: /home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
    
    === child image b0n -  begin ===
    loading initial cache file /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/b0n/child_image_preload.cmake
    Loading Zephyr default modules (Zephyr base).
    -- Application: /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/nrf/samples/nrf5340/netboot
    -- CMake version: 3.25.2
    -- Found Python3: /usr/bin/python3.10 (found suitable exact version "3.10.10") found components: Interpreter 
    -- Cache files will be written to: /home/tselmeci/.cache/zephyr
    -- Zephyr version: 3.3.99 (/home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-wlt-v5r1-ncs/zephyr)
    -- Found west (found suitable version "1.1.0", minimum required is "0.7.1")
    -- Board: wlt_v5r1_net
    -- Found host-tools: zephyr 0.16.1 (/home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1)
    -- Found toolchain: zephyr 0.16.1 (/home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1)
    -- Found Dtc: /bin/dtc (found suitable version "1.6.1", minimum required is "1.4.6") 
    -- Found BOARD.dts: /home/tselmeci/projects/base-env1.git/src/libbsp/nrfconnect/boards/arm/wlt-v5r1/wlt_v5r1_net.dts
    -- Generated zephyr.dts: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/b0n/zephyr/zephyr.dts
    -- Generated devicetree_generated.h: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/b0n/zephyr/include/generated/devicetree_generated.h
    -- Including generated dts.cmake file: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/b0n/zephyr/dts.cmake
    Parsing /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/nrf/samples/nrf5340/netboot/Kconfig
    Loaded configuration '/home/tselmeci/projects/base-env1.git/src/libbsp/nrfconnect/boards/arm/wlt-v5r1/wlt_v5r1_net_defconfig'
    Merged configuration '/home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/nrf/samples/nrf5340/netboot/prj.conf'
    Merged configuration '/home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/nrf/subsys/partition_manager/partition_manager_enabled.conf'
    Configuration saved to '/home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/b0n/zephyr/.config'
    Kconfig header saved to '/home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/b0n/zephyr/include/generated/autoconf.h'
    -- Found GnuLd: /home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd (found version "2.38") 
    -- The C compiler identification is GNU 12.2.0
    -- The CXX compiler identification is GNU 12.2.0
    -- The ASM compiler identification is GNU
    -- Found assembler: /home/tselmeci/projects/GNSS-cellular-tracker.git/toolchain/g4t-v1r1-gct/zephyr-sdk-0.16.1/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc
    Loading Zephyr default modules (Zephyr base (cached)).
    CMake Warning at /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-wlt-v5r1-ncs/zephyr/CMakeLists.txt:839 (message):
      No SOURCES given to Zephyr library: lib__libc__common
    
      Excluding target from build.
    
    
    CMake Warning at /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-wlt-v5r1-ncs/zephyr/CMakeLists.txt:1865 (message):
      __ASSERT() statements are globally ENABLED
    
    
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj/b0n
    === child image b0n -  end ===
    
    CMake Warning at /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/nrf/subsys/bootloader/cmake/debug_keys.cmake:36 (message):
      
    
          --------------------------------------------------------------
          --- WARNING: Using generated NSIB public/private key-pair. ---
          --- It should not be used for production.                  ---
          --- See CONFIG_SB_SIGNING_KEY_FILE                         ---
          --------------------------------------------------------------
          
    
    Call Stack (most recent call first):
      /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/nrf/subsys/bootloader/cmake/provision_hex.cmake:37 (include)
      /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/nrf/subsys/CMakeLists.txt:17 (include)
    
    
    -- libmetal version: 1.3.0 (/home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net)
    -- Build type:  
    -- Host:    Linux/x86_64
    -- Target:  Generic/arm
    -- Machine: arm
    -- Looking for include file stdatomic.h
    -- Looking for include file stdatomic.h - found
    -- open-amp version: 1.3.0 (/home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-v2.4.1-wlt-v5r1-ncs/modules/lib/open-amp/open-amp)
    -- Host:    Linux/x86_64
    -- Target:  Generic/arm
    -- Machine: arm
    -- C_FLAGS :  -Wall -Wextra
    -- Looking for include file fcntl.h
    -- Looking for include file fcntl.h - found
    Loading Zephyr default modules (Zephyr base (cached)).
    CMake Warning at /home/tselmeci/projects/base-env1.git/packages/nrfconnect/nrfconnect-wlt-v5r1-ncs/zephyr/CMakeLists.txt:839 (message):
      No SOURCES given to Zephyr library: lib__libc__common
    
      Excluding target from build.
    
    
    -- Found partition manager static configuration: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/pm_static.yml
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj
    -- west build: building application
    ninja: error: 'modules/nrf/subsys/app_hex', needed by 'zephyr/nrf/subsys/bootloader/generated/app_firmware.signature', missing and no known rule to make it
    FATAL ERROR: command exited with status 1: /bin/cmake --build /home/tselmeci/projects/base-env1.git/src/sample-wlt-v5r1-ncs/net/build/wlt-v5r1-ncs-obj
    make: *** [Makefile:48: compile] Error 1
    

    Any help is appreciated. Regards,

  • Hello,

    If possible, I'd recommend that you build the SMP Server Sample with the bt-overlay and compare your configuration against that build. This will build an application for the main core, along with MCUBOOT, and B0n + hcirpmsg for the netcore. You can run "west build -t partition_manager_report" to see the resulting memory layout, or inspect the generated partition manager file. 

    Tamas Selmeci said:
    I don't understand why both PCD_APP and PCD_NET need to be enabled in APP MCUboot;

    PCD_APP and PCD_NET should be enabled for the app core and the net core respectively. PCD_NET should not be enabled for the app core.

Related