This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

DFU bootloader - CRC always 0, always accepted

Hi all, in the forum I can read about people having issues with wrong CRC in the bootloader, but with SDK11; I have the opposite problem. It is always 0 and is always accepted. If I program my application using the bootloader, then flash something else to the application region using IAR, the new "faulty" application is accepted and started anyway.

Is there a reason for why CRC checking has been removed from each boot or is this a bug? (It was there for single_bank in SDK7 at least)

bootloader.c:

bool bootloader_app_is_valid(uint32_t app_addr)
//...
// A stored crc value of 0 indicates that CRC checking is not used.
    if (p_bootloader_settings->bank_0_crc != 0)
    {
        image_crc = crc16_compute((uint8_t *)DFU_BANK_0_REGION_START,
                                  p_bootloader_settings->bank_0_size,
                                  NULL);
    }

Looking at SDK7 single_bank.c I can see that the code in dfu_image_validate has changed from

        else
        {
            // Valid peer activity detected. Hence restart the DFU timer.
            err_code = dfu_timer_restart();
            
            // Calculate CRC from DFU_BANK_0_REGION_START to mp_app_write_address.
            m_image_crc  = crc16_compute((uint8_t*)DFU_BANK_0_REGION_START, 
                                         m_image_size, 
                                         NULL);
            received_crc = uint16_decode((uint8_t*)&m_init_packet[0]);
                
            if ((m_init_packet_length != 0) && (m_image_crc != received_crc))
            {
                return NRF_ERROR_INVALID_DATA;
            }
            m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE;
            err_code    = NRF_SUCCESS;
        }

to (dual_bank in SDK11):

        else
        {
            m_dfu_state = DFU_STATE_VALIDATE;

            // Valid peer activity detected. Hence restart the DFU timer.
            err_code = dfu_timer_restart();
            if (err_code == NRF_SUCCESS)
            {
                err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id,
                                                 m_image_size);
                VERIFY_SUCCESS(err_code);

                m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE;
            }
        }

Now the dfu_init_postvalidate(...) only compares the CRC once, it does not update the m_image_crc in dfu_dual_bank.c, thus the m_image_crc is always 0 and bootloader_dfu_update_process(..) is always called with .app_crc = 0, causing the bootloader setting to be stored with an app CRC = 0.

My solution was to make dfu_init_postvalidate() return the calculated CRC through a pointer and then update m_image_crc. This seems to work for me, and now the CRC is verified each bootup.

EDIT: I sent a reference to m_image_crc to dfu_init_postvalidate in dfu_dual_bank line 585):

                    err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id,
                                                 m_image_size,
                                                 &m_image_crc);

Then in dfu_init_template.c (and dfu_init.h) I added a pointer as a function parameter and update it with the calculated CRC:

uint32_t dfu_init_postvalidate(uint8_t * p_image, uint32_t image_len, uint16_t* p_crc)
{
//...
// calculate CRC from active block.
image_crc = crc16_compute(p_image, image_len, NULL);
*p_crc = image_crc;
//...
}

/EDIT

A second opinon on my solution and a reason for why it has been removed would be nice. Also if this is intended, maybe the comment on m_image_crc could be updated to clearify that it is not in use.

Best Regards Erik

Related