about mcuboot flash dfu image invaild

Hello Sir,

I am currently working with the boards:52840dk and ncs:2.9.1

Regarding the issue of failed mcuboot upgrade after writing the upgrade firmware using flash APIs, where the “zephyr.signed.bin” file is the one written to flash.

(The code in this routine has been modified.)

I first transferred the upgraded firmware to the memory via the serial port or other way.

Then, this is the process of writing to the flash using the flash API

while (offset < length)
{
	size_t write_len = MIN(length - offset, CONFIG_IMG_BLOCK_BUF_SIZE);  //Each time, write in blocks of size blocksize.
	if (write_len < CONFIG_IMG_BLOCK_BUF_SIZE)
		break;
	ret = flash_img_buffered_write(&flash_ctx, &uart_rx_buf[offset],
								   write_len, false);  //During the write process, the data in the last write buffer is less than the block size
	if (ret != 0)
	{
		printk("Flash write failed at offset %zu: %d\n", offset, ret);
		return ret;
	}
	offset += write_len;
}
ret = flash_img_buffered_write(&flash_ctx, NULL, 0, true);	//flush The last written buffer
/*ret = flash_img_buffered_write(&flash_ctx, &uart_rx_buf[offset],
							   (length % 512), true);*/  
if (ret != 0)
{
	printk("Final flush failed: %d\n", ret);
	return ret;
}
bytes_written = flash_img_bytes_written(&flash_ctx); //Buffer for the total number of bytes read and written
printk("Total bytes written: %zu\n", bytes_written);
if (bytes_written % UART_RX_MTU != 0)  //Check if it has been fully written in
{
	ret = boot_request_upgrade(BOOT_UPGRADE_PERMANENT); //If fully written, it will enter the DFU mode and start the update process
	if (ret != 0)
	{
		printk("Failed to request upgrade: %d\n", ret);
		return ret;
	}
	printk("Firmware update completed successfully!\n");
}

However, the update failed continuously. This is the error log reported by mcuboot.

its display secondary slot is not vaild,then I dump flash data

In Flash, the corresponding address contains the content I wrote, and the size and other details are also correct. Then, the part circled in red at the top should be the check bit of the swap_type located at the end of the secondary slot sector.

The specific content and the address where it is located have also been confirmed to be correct.

However, it was never able to be upgraded. Later, after debugging, it was found that the program failed during the hash verification process. it should be the verification of the TLV field. It is located at the end of the image, which is the part circled in the above picture.

Here's the problem: even though the contents in the flash are identical to the zephyr.signed.bin file, the upgrade still fails. Later, I dumped a Zephyr routine that can be upgraded successfully and checked the flash status before upgrading. I found that the TLV fields at the end of this routine's flash are different from the last 69 bytes of the zephyr.signed.bin in this routine.

I have found in many official and unofficial documents that this zephyr.signed.bin is used for DFU/OTA upgrades, and apart from this file, I haven't found any other new files that seem suitable for upgrading.

Then the remaining possibility is that since Zephyr uses west flash for burning, could it be that west flash modifies the signature? Or there might be other issues? What should I do next?

Please forgive my not-so-fluent English

Djangyond Kang,

Embedded Developer

Shenzhen Best of Best Holdings Co.,Ltd

Parents Reply Children
  • Hi,

    I have not tested updating via serial as I need exact insructions no how to do that, but fundamentally your approach works. I modified your main.c like this to call "boot_request_upgrade(BOOT_UPGRADE_PERMANENT)" when pressing button 1:

    #include <stdio.h>
    #include <zephyr/drivers/uart.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <string.h>
    #include <zephyr/dfu/flash_img.h>
    #include <zephyr/dfu/mcuboot.h>
    #include <zephyr/sys/util.h>
    #include <zephyr/storage/flash_map.h>
    #include <zephyr/drivers/gpio.h>
    
    #define SLOT0_PARTITION slot0_partition
    #define SLOT1_PARTITION slot1_partition
    
    #define SLOT0_PARTITION_ID FIXED_PARTITION_ID(SLOT0_PARTITION)
    
    #define SLOT1_PARTITION_ID FIXED_PARTITION_ID(SLOT1_PARTITION)
    
    #define BUF_SIZE 100000
    #define UART_RX_TIMEOUT_MS 20000
    
    #define UART_RX_MTU	34464
    
    const struct device *uart1 = DEVICE_DT_GET(DT_NODELABEL(uart1));
    int global = 65;
    uint8_t uart_tx_buf[128] = {0};
    uint8_t uart_rx_buf[100000] = {0};
    uint8_t uart_rx_buf2[128];
    // uint8_t new_buf[40000] = {0};
    // uint8_t firmware[40000]
    int flag = 0;
    int length = 0;
    #define TARGET_FLASH_AREA_ID 1
    struct flash_img_context flash_ctx;
    
    /*
     * Get button configuration from the devicetree sw0 alias. This is mandatory.
     */
    #define SW0_NODE	DT_ALIAS(sw0)
    #if !DT_NODE_HAS_STATUS_OKAY(SW0_NODE)
    #error "Unsupported board: sw0 devicetree alias is not defined"
    #endif
    static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios,
    							      {0});
    static struct gpio_callback button_cb_data;
    
    
    void button_pressed(const struct device *dev, struct gpio_callback *cb,
    		    uint32_t pins)
    {
    	int ret;
    
    	printk("Button pressed. Requesting upgrade... (new image must allready be copied into slot 1)\n");
    	ret = boot_request_upgrade(BOOT_UPGRADE_PERMANENT); //If fully written, it will enter the DFU mode and start the update process
    	if (ret != 0)
    	{
    		printk("Failed to request upgrade: %d\n", ret);
    		return;
    	}
    }
    
    static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
    {
    	ARG_UNUSED(dev);
    	switch (evt->type)
    	{
    	case UART_TX_DONE:
    		printk("UART_TX_DONE\n");
    		break;
    
    	case UART_RX_RDY:
    		printk("received %d bytes\n", evt->data.rx.len);
    		printk("offset %d \n", evt->data.rx.offset);
    		length = evt->data.rx.len;
    		// printk("rx_buf = %d %d %d %d %d\n", uart_rx_buf[32330], uart_rx_buf[32331], uart_rx_buf[32332], uart_rx_buf[32333], uart_rx_buf[32334]);
    		flag = 1;
    		//printk("offset %d \n", evt->data.rx.offset);
    		break;
    
    	case UART_RX_DISABLED:
    		break;
    
    	case UART_RX_BUF_REQUEST:
    		printk("REQUEST\n");
    		uart_rx_buf_rsp(uart1, uart_rx_buf, BUF_SIZE);
    		break;
    
    	case UART_RX_BUF_RELEASED:
    		break;
    
    	case UART_TX_ABORTED:
    		printk("UART_TX_ABORTED\n");
    		break;
    
    	default:
    		break;
    	}
    }
    
    void thread2_entry(void *p1, void *p2, void *p3)
    {
    
    	memset(uart_rx_buf, 0, BUF_SIZE);
    	int err = uart_callback_set(uart1, uart_cb, NULL);
    	if (err < 0)
    	{
    		printk("callback configuration failed\n");
    		return;
    	}
    
    	err = uart_rx_enable(uart1, uart_rx_buf, BUF_SIZE, UART_RX_TIMEOUT_MS);
    	if (err < 0)
    	{
    		printk("rxenable configuration failed\n");
    		return;
    	}
    
    	while (1)
    	{
    		k_msleep(3000);
    	}
    }
    
    K_THREAD_DEFINE(thread2, 1024, thread2_entry,
    				NULL, NULL, NULL,
    				K_HIGHEST_APPLICATION_THREAD_PRIO, 0, 0);
    
    
    int main(void)
    {
    	printf("second_version\n");
    
    	int ret;
    	size_t offset = 0;
    	size_t bytes_written;
    
    	if (!gpio_is_ready_dt(&button)) {
    		printk("Error: button device %s is not ready\n",
    		       button.port->name);
    		return 0;
    	}
    
    	ret = gpio_pin_configure_dt(&button, GPIO_INPUT);
    	if (ret != 0) {
    		printk("Error %d: failed to configure %s pin %d\n",
    		       ret, button.port->name, button.pin);
    		return 0;
    	}
    
    	ret = gpio_pin_interrupt_configure_dt(&button,
    					      GPIO_INT_EDGE_TO_ACTIVE);
    	if (ret != 0) {
    		printk("Error %d: failed to configure interrupt on %s pin %d\n",
    			ret, button.port->name, button.pin);
    		return 0;
    	}
    
    	gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
    	gpio_add_callback(button.port, &button_cb_data);
    	printk("Set up button at %s pin %d\n", button.port->name, button.pin);
    
    
    	/*ret = flash_img_init(&flash_ctx);
    	if (ret != 0)
    	{
    		printk("Flash init failed: %d\n", ret);
    		return ret;
    	}*/
    
    	ret = flash_img_init_id(&flash_ctx, SLOT1_PARTITION_ID);
    	if (ret != 0)
    	{
    		printk("Flash init failed: %d\n", ret);
    		return ret;
    	}
    
    	printk("Flash init success\n");
    	while (1)
    	{
    		k_msleep(5);
    		if (flag == 1)
    		{
    			while (offset < length)
    			{
    				size_t write_len = MIN(length - offset, CONFIG_IMG_BLOCK_BUF_SIZE);  //Each time, write in blocks of size blocksize.
    				if (write_len < CONFIG_IMG_BLOCK_BUF_SIZE)
    					break;
    
    				ret = flash_img_buffered_write(&flash_ctx, &uart_rx_buf[offset],
    											   write_len, false);  //During the write process, the data in the last write buffer is less than the block size
    				if (ret != 0)
    				{
    					printk("Flash write failed at offset %zu: %d\n", offset, ret);
    					return ret;
    				}
    
    				offset += write_len;
    			}
    
    			ret = flash_img_buffered_write(&flash_ctx, NULL, 0, true);	//flush The last written buffer
    			/*ret = flash_img_buffered_write(&flash_ctx, &uart_rx_buf[offset],
    										   (length % 512), true);*/  
    			if (ret != 0)
    			{
    				printk("Final flush failed: %d\n", ret);
    				return ret;
    			}
    
    			bytes_written = flash_img_bytes_written(&flash_ctx); //Buffer for the total number of bytes read and written
    			printk("Total bytes written: %zu\n", bytes_written);
    			if (bytes_written % UART_RX_MTU != 0)  //Check if it has been fully written in
    			{
    				ret = boot_request_upgrade(BOOT_UPGRADE_PERMANENT); //If fully written, it will enter the DFU mode and start the update process
    				if (ret != 0)
    				{
    					printk("Failed to request upgrade: %d\n", ret);
    					return ret;
    				}
    				printk("Firmware update completed successfully!\n");
    			}
    			offset = 0;
    			flag = 0;
    		}
    	}
    	return 0;
    }

    Then I built first version (with the printf saying "first_version") and flashed that. Then modified the printf, rebuilt the firmware and generated a hex file of the signed bin file that has the offset for slot 1 like this:

    $ bin2hex.py --offset=0x83000 build/serial_for_mcuboot/zephyr/zephyr.signed.bin build/serial_for_mcuboot/zephyr/zephyr.signed.offset.hex

    Then I programmed that file using nrfjprog, to write it to slot 1:

    nrfjprog --program build/serial_for_mcuboot/zephyr/zephyr.signed.offset.hex --verify

    The I pressed button 1 to call boot_request_upgrade(), and observed in the log that the new image was activated as it should:

    *** Booting MCUboot v2.1.0-dev-12e5ee106034 ***
    *** Using nRF Connect SDK v2.9.1-60d0d6c8d42d ***
    *** Using Zephyr OS v3.7.99-ca954a6216c9 ***
    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: Image index: 0, Swap type: none
    I: Bootloader chainload address offset: 0xc000
    *** Booting nRF Connect SDK v2.9.1-60d0d6c8d42d ***
    *** Using Zephyr OS v3.7.99-ca954a6216c9 ***
    REQUEST
    first_version
    Set up button at gpio@50000000 pin 11
    Flash init success
    Button pressed. Requesting upgrade... (new image must allready be copied into slot 1)
    *** Booting MCUboot v2.1.0-dev-12e5ee106034 ***
    *** Using nRF Connect SDK v2.9.1-60d0d6c8d42d ***
    *** Using Zephyr OS v3.7.99-ca954a6216c9 ***
    I: Starting bootloader
    I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    I: Secondary image: magic=good, swap_type=0x3, copy_done=0x3, image_ok=0x1
    I: Boot source: none
    I: Image index: 0, Swap type: perm
    I: Starting swap using move algorithm.
    I: Bootloader chainload address offset: 0xc000
    *** Booting nRF Connect SDK v2.9.1-60d0d6c8d42d ***
    *** Using Zephyr OS v3.7.99-ca954a6216c9 ***
    REQUEST
    second_version
    Set up button at gpio@50000000 pin 11
    Flash init success

    This tests your whole approach, except the part where you copy the data via UART, so unless you used the wrong image file to test with (?), this is where the problem must be and that should be looked at more closely.

    Br,

    Einar

Related