DFU target API on NCS v3.4.1

Dear Nordic team,

I am trying to set up OTA updates by using the DFU target API on an nRF9151 DK with MCUboot and TF-M partitions. (NCS v3.4.1) My goal is to use the immutable MCUboot bootloader and update both the application and the TF-M partition. I've declared

SB_CONFIG_BOOTLOADER_MCUBOOT=y

in the project's "sysbuild.conf" file and have set up a board overlay (PROJECT_DIR/boards/nrf9151dk_nrf9151_ns.overlay) with the following partitions.

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

/delete-node/ &boot_partition;
/delete-node/ &slot0_partition;
/delete-node/ &slot1_partition;
/delete-node/ &tfm_ps_partition;
/delete-node/ &tfm_its_partition;
/delete-node/ &tfm_otp_partition;
/delete-node/ &storage_partition;

&flash0 {
    /*
     * Flash partition layout for non-minimal TF-M in combination with MCUboot
     *
     * 0x0000_0000 BL2 - MCUBoot (64 KB)
     * 0x0001_0000 Primary image area (448 KB):
     *    0x0001_0000 Secure     image primary (192 KB)
     *    0x0004_0000 Non-secure image primary (256 KB)
     * 0x0008_0000 Secondary image area (448 KB):
     *    0x0008_0000 Secure     image secondary (192 KB)
     *    0x000b_0000 Non-secure image secondary (256 KB)
     * 0x000f_0000 Protected Storage Area (16 KB)
     * 0x000f_4000 Internal Trusted Storage Area (8 KB)
     * 0x000f_6000 OTP / NV counters area (8 KB)
     * 0x000f_8000 Non-secure storage, used when built with NRF_NS_STORAGE=ON,
     *             otherwise unused (32 KB)
     */
    partitions {
        ranges;
        #address-cells = <1>;
        #size-cells = <1>;

        boot_partition: partition@0 {
            compatible = "zephyr,mapped-partition";
            label = "mcuboot";
            reg = <0x00000000 0x10000>;
        };

        slot0_partition: partition@10000 {
            compatible = "zephyr,mapped-partition";
            label = "image-0";
            reg = <0x00010000 0x70000>;
            ranges = <0x0 0x10000 0x70000>;
            #address-cells = <1>;
            #size-cells = <1>;

            slot0_s_partition: partition@0 {
                compatible = "zephyr,mapped-partition";
                label = "image-0-secure";
                reg = <0x00000000 0x30000>;
            };

            slot0_ns_partition: partition@30000 {
                compatible = "zephyr,mapped-partition";
                label = "image-0-nonsecure";
                reg = <0x00030000 0x40000>;
            };
        };

        slot1_partition: partition@80000 {
            compatible = "zephyr,mapped-partition";
            label = "image-1";
            reg = <0x00080000 0x70000>;
            ranges = <0x0 0x80000 0x70000>;
            #address-cells = <1>;
            #size-cells = <1>;

            slot1_s_partition: partition@0 {
                compatible = "zephyr,mapped-partition";
                label = "image-1-secure";
                reg = <0x00000000 0x30000>;
            };

            slot1_ns_partition: partition@30000 {
                compatible = "zephyr,mapped-partition";
                label = "image-1-nonsecure";
                reg = <0x00030000 0x40000>;
            };
        };

        tfm_ps_partition: partition@f0000 {
            compatible = "zephyr,mapped-partition";
            label = "tfm-ps";
            reg = <0x000f0000 0x00004000>;
        };

        tfm_its_partition: partition@f4000 {
            compatible = "zephyr,mapped-partition";
            label = "tfm-its";
            reg = <0x000f4000 0x00002000>;
        };

        tfm_otp_partition: partition@f6000 {
            compatible = "zephyr,mapped-partition";
            label = "tfm-otp";
            reg = <0x000f6000 0x00002000>;
        };

        storage_partition: partition@f8000 {
            compatible = "zephyr,mapped-partition";
            label = "storage";
            reg = <0x000f8000 0x00008000>;
        };
    };
};

/delete-node/ &sram0_s;
/delete-node/ &sram0_ns;

&sram0 {
    /*
     * SRAM partition layout for non-minimal TF-M
     *
     * 0x2000_0000  Secure RAM                      (   88 kB)
     * 0x2001_6000  Non-secure RAM area             (  168 kB)
     *   0x2001_6000  Modem shared area             ( 17768 B)
     *     0x2001_6000  control                     (  1256 B)
     *     0x2001_64e8  app -> cell                 (  8320 B)
     *     0x2001_8568  cell -> app                 (    8 kB)
     *   0x2001_a568  Application RAM               (154264 B)
     */
    sram0_s: sram@0 {
        reg = <0x0 0x16000>;
    };

    sram0_ns: sram@16000 {
        reg = <0x16000 0x2a000>;
        #address-cells = <1>;
        #size-cells = <1>;
        ranges = <0x0 0x16000 0x2a000>;

        /* Must be in first 128 kB of RAM. */
        sram0_ns_modem: sram0_ns@0 {
            /* Modem (shared) memory */
            reg = <0x0 0x4568>;
            #address-cells = <1>;
            #size-cells = <1>;
            ranges = <0x0 0x0 0x4568>;

            cpuapp_cpucell_ipc_shm_ctrl: sram0_ns_modem@0 {
                /* Modem IPC control */
                reg = <0x0 0x4e8>;
            };

            cpuapp_cpucell_ipc_shm_heap: sram0_ns_modem@4e8 {
                /* Modem IPC transmit */
                reg = <0x4e8 0x2080>;
            };

            cpucell_cpuapp_ipc_shm_heap: sram0_ns_modem@2568 {
                /* Modem IPC receive */
                reg = <0x2568 0x2000>;
            };
        };

        sram0_ns_app: sram0_ns@4568 {
            /* Non-Secure application memory */
            reg = <0x4568 0x25a98>;
        };
    };
};

&gd25wb256 {
    status = "okay";

    partitions {
        compatible = "fixed-partitions";
        #address-cells = <1>;
        #size-cells = <1>;

        lfs_partition: partition@0 {
            label = "lfs_storage";
            // reg = <0x00000000 0x00040000>; /* 256kB */
            reg = <0x00000000 0x02000000>; /* 32MB */
        };
    };
};

The code initializes the DFU target, downloads update chunks via CoAP and writes the chunks with `dfu_target_write`. The code compiles and runs, but causes a "SECURE FAULT" when running `dfu_target_write`:

[00:00:23.089,080] <err> os: ***** SECURE FAULT *****
[00:00:23.089,080] <err> os:   Address: 0x80000
[00:00:23.089,111] <err> os:   Attribution unit violation
[00:00:23.089,141] <err> os: r0/a1:  0x00080000  r1/a2:  0x00000000  r2/a3:  0xffffffff
[00:00:23.089,172] <err> os: r3/a4:  0x40039000 r12/ip:  0x00000100 r14/lr:  0x0004d47b
[00:00:23.089,202] <err> os:  xpsr:  0x21000000
[00:00:23.089,233] <err> os: Faulting instruction address (r15/pc): 0x000532fe
[00:00:23.089,324] <err> os: >>> ZEPHYR FATAL ERROR 41: Unknown error on CPU 0
[00:00:23.089,416] <err> os: Current thread: 0x200203c8 (main)
[00:00:23.282,043] <err> os: Halting system

My thoughts are that the "SECURE FAULT" might be caused, because the `slot1_partition` might be treated as a secure partition and therefore cannot be written to. (the fault points to the start of slot1_partitions's flash range) Also, I suspect that the image number passed into `dfu_target_init` might be incorrect. At first I though it would have to be set to `0` or `CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER`, but I am not sure about that. My current DFU target initialization looks like this:

#define IMAGE_NUMBER 0

...

int32_t img_type = dfu_target_img_type(chunk, chunk_len);
err = dfu_target_init(img_type, IMAGE_NUMBER, file_size, NULL);
if (err < 0) {
	LOG_DBG("Failed to initialize DFU target, errno: %d", err);
	goto out;
}

...

I've also tried to reference the board overlay in the "PROJECT_DIR/sysbuild_mcubot/boards" directory. There I've added a "nrf9151dk_nrf9151_ns.overlay" file with the following content:

#include "../../../boards/nrf9151dk_nrf9151_ns.overlay"
#include "../app.overlay"

The included "app.overlay" file has:

/ {
	chosen {
		zephyr,code-partition = &boot_partition;
	};
};

Am I missing some definitions in the overlay file, or does Sysbuild have to be made aware of the partitions some other way?

Is the image number `0` correct for this case?

To allow for modem delta updates in the next step, is this setup viable and can the same DFU target procedure and initialization be used?

Guidance is greatly appreciated.

Best,

Tom

Parents
  • Hi,

    With normal MCUboot swap behaviour, MCuboot does not know about TF-M. It just swaps the application as one blob.

    The application uploads the DFU candidate to the secondary slot. And the application only has Non-Secure access.
    So the secondary slot needs to be fully Non-Secure.

    From your DTS file:

    "
         * 0x0008_0000 Secondary image area (448 KB):
         *    0x0008_0000 Secure     image secondary (192 KB)
         *    0x000b_0000 Non-secure image secondary (256 KB)
    "

    For a normal swap-based DFU, I would recommend not splitting the Secondary slot int two partitions; Just use one.

    Regards,
    Sigurd Hellesvik

  • After I removed this

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

    from the DTSI file, the secure fault did not trigger anymore on dfu_target_write(). The update now completes with this setup:

    /delete-node/ &boot_partition;
    /delete-node/ &slot0_partition;
    /delete-node/ &slot1_partition;
    /delete-node/ &tfm_ps_partition;
    /delete-node/ &tfm_its_partition;
    /delete-node/ &tfm_otp_partition;
    /delete-node/ &storage_partition;
    
    &flash0 {
        /*
         * Flash partition layout for non-minimal TF-M in combination with MCUboot
         *
         * 0x0000_0000 BL2 - MCUBoot (64 KB)
         * 0x0001_0000 Primary image area (448 KB):
         *    0x0001_0000 Secure     image primary (192 KB)
         *    0x0004_0000 Non-secure image primary (256 KB)
         * 0x0008_0000 Secondary image area (448 KB):
         *    0x0008_0000 Secure     image secondary (192 KB)
         *    0x000b_0000 Non-secure image secondary (256 KB)
         * 0x000f_0000 Protected Storage Area (16 KB)
         * 0x000f_4000 Internal Trusted Storage Area (8 KB)
         * 0x000f_6000 OTP / NV counters area (8 KB)
         * 0x000f_8000 Non-secure storage, used when built with NRF_NS_STORAGE=ON,
         *             otherwise unused (32 KB)
         */
        partitions {
            ranges;
            #address-cells = <1>;
            #size-cells = <1>;
    
            boot_partition: partition@0 {
                compatible = "zephyr,mapped-partition";
                label = "mcuboot";
                reg = <0x00000000 0x10000>;
            };
    
            slot0_partition: partition@10000 {
                compatible = "zephyr,mapped-partition";
                label = "image-0";
                reg = <0x00010000 0x70000>;
                ranges = <0x0 0x10000 0x70000>;
                #address-cells = <1>;
                #size-cells = <1>;
    
                slot0_s_partition: partition@0 {
                    compatible = "zephyr,mapped-partition";
                    label = "image-0-secure";
                    reg = <0x00000000 0x30000>;
                };
    
                slot0_ns_partition: partition@30000 {
                    compatible = "zephyr,mapped-partition";
                    label = "image-0-nonsecure";
                    reg = <0x00030000 0x40000>;
                };
            };
    
            slot1_partition: partition@80000 {
                compatible = "zephyr,mapped-partition";
                label = "image-1";
                reg = <0x00080000 0x70000>;
                ranges = <0x0 0x80000 0x70000>;
                #address-cells = <1>;
                #size-cells = <1>;
    
                slot1_s_partition: partition@0 {
                    compatible = "zephyr,mapped-partition";
                    label = "image-1-secure";
                    reg = <0x00000000 0x30000>;
                };
    
                slot1_ns_partition: partition@30000 {
                    compatible = "zephyr,mapped-partition";
                    label = "image-1-nonsecure";
                    reg = <0x00030000 0x40000>;
                };
            };
    
            tfm_ps_partition: partition@f0000 {
                compatible = "zephyr,mapped-partition";
                label = "tfm-ps";
                reg = <0x000f0000 0x00004000>;
            };
    
            tfm_its_partition: partition@f4000 {
                compatible = "zephyr,mapped-partition";
                label = "tfm-its";
                reg = <0x000f4000 0x00002000>;
            };
    
            tfm_otp_partition: partition@f6000 {
                compatible = "zephyr,mapped-partition";
                label = "tfm-otp";
                reg = <0x000f6000 0x00002000>;
            };
    
            storage_partition: partition@f8000 {
                compatible = "zephyr,mapped-partition";
                label = "storage";
                reg = <0x000f8000 0x00008000>;
            };
        };
    };
    
    /delete-node/ &sram0_s;
    /delete-node/ &sram0_ns;
    
    &sram0 {
        /*
         * SRAM partition layout for non-minimal TF-M
         *
         * 0x2000_0000  Secure RAM                      (   88 kB)
         * 0x2001_6000  Non-secure RAM area             (  168 kB)
         *   0x2001_6000  Modem shared area             ( 17768 B)
         *     0x2001_6000  control                     (  1256 B)
         *     0x2001_64e8  app -> cell                 (  8320 B)
         *     0x2001_8568  cell -> app                 (    8 kB)
         *   0x2001_a568  Application RAM               (154264 B)
         */
        sram0_s: sram@0 {
            reg = <0x0 0x16000>;
        };
    
        sram0_ns: sram@16000 {
            reg = <0x16000 0x2a000>;
            #address-cells = <1>;
            #size-cells = <1>;
            ranges = <0x0 0x16000 0x2a000>;
    
            /* Must be in first 128 kB of RAM. */
            sram0_ns_modem: sram0_ns@0 {
                /* Modem (shared) memory */
                reg = <0x0 0x4568>;
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x0 0x0 0x4568>;
    
                cpuapp_cpucell_ipc_shm_ctrl: sram0_ns_modem@0 {
                    /* Modem IPC control */
                    reg = <0x0 0x4e8>;
                };
    
                cpuapp_cpucell_ipc_shm_heap: sram0_ns_modem@4e8 {
                    /* Modem IPC transmit */
                    reg = <0x4e8 0x2080>;
                };
    
                cpucell_cpuapp_ipc_shm_heap: sram0_ns_modem@2568 {
                    /* Modem IPC receive */
                    reg = <0x2568 0x2000>;
                };
            };
    
            sram0_ns_app: sram0_ns@4568 {
                /* Non-Secure application memory */
                reg = <0x4568 0x25a98>;
            };
        };
    };

    Out of interest, I tried your suggestion of removing the sub-partitions from slot1_partition, but that causes a build error.

  • Sorry, I meant using the same procedure using the DFU target API: What I can't really make out from the documentation is whether IMAGE_NUMBER = 0 is to be used and if a cold reboot suffices to apply the update to the modem.

  • Tom01 said:
    the same procedure using the DFU target API

    Sorry if Im a bit difficult here, but Im still not fully sure what you mean.

    When you say "is still the same", I expect a "before" and "after" state.
    You latest message mention the DFU Target API. Is it before and after the DFU Target API?
    If so, what did you use before?

  • No worries, English isn't my mother tongue, so I am probably not expressing myself clearly enough. 

    My main point of uncertainty is how to define the image number argument of "dfu_target_init()" and "dfu_target_schedule_update()". For the application update, I was looking at this documentation: https://nrfconnectdocs.nordicsemi.com/ncs/latest/nrf/app_dev/bootloaders_dfu/sysbuild_image_ids.html#image-numbers. But I am not certain if this also applies to modem delta updates or if modem updates at all care about the provided image number. 

    ->

    In my previous reply I posted a piece of conceptual code, going through the DFU target API methods that I use to prepare and schedule application firmware updates. (NCS v3.4.1 only, no comparison between SDKs)

    I was asking for confirmation that

    • the DFU target API methods of the conceptual code are to be used for modem delta updates as well and - more specifically - that "dfu_target_init(img_type, IMAGE_NUMBER, file_size, NULL)" also needs to be called with IMAGE_NUMBER=0
    • and that a cold reboot will trigger the modem update after calling "dfu_target_schedule_update(IMAGE_NUMBER)".
  • It makes sense to me now, thanks for elaborating.

    Tom01 said:
    the DFU target API methods of the conceptual code are to be used for modem delta updates as well and - more specifically - that "dfu_target_init(img_type, IMAGE_NUMBER, file_size, NULL)" also needs to be called with IMAGE_NUMBER=0

    Yes, 0 should be correct for image number.

    Tom01 said:
    and that a cold reboot will trigger the modem update after calling "dfu_target_schedule_update(IMAGE_NUMBER)".

    Yes. From DFU Target->Modem delta upgrades: 

    "When the transfer has completed, the application must call the dfu_target_done() function to release modem resources and then call dfu_target_schedule_update() to request the modem to apply the patch. On the next reboot, the modem tries to apply the patch."

    In other news, the pm-ext-flash issue is fixed in main, where the partition manager is removed. So for upcoming nRF Connect SDK versions, it will not happen anymore.

    Ref tree: Remove partition manager support · nrfconnect/sdk-nrf@8698181 and tfm: cleanup leftovers after pm migration · nrfconnect/sdk-nrf@2f51288

  • Ok, great. Thanks for the confirmation!

    Glad to hear that the pm-ext-flash fix made it to main already!

Reply Children
No Data
Related