OFF CHIP OTA UPDATE using external flash

I am working on this project off chip ota update on nRF5_SDK  using ecample/thread/dfu

by now, i have done changes in these functions on_data_obj_create_request() and on_data_obj_write_request(). initially these functions were erasing and writing data in internal flash which I changed to qspi functions like nrf_drv_qspi_erase() and nrf_drv_qspi_write(). and it works perfectly.

Later i changed functions for hash verification which is also working but i am not sure about what should be the next step so that bootloader changes the earlier application with the new firmware image.

Parents
  • Hi,

    Unfortunately our experts on this matter are out-of-office today. We expect to get back to you beginning of next week. If you have any progress in the mean time then please update this ticket with your findings.

    Regards,
    Terje

  • I have made three changes in code 

    1: in flash erase i have changed it to erase external flash using QSPI.

    static void on_data_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
    {
        NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (data)");
    
        if (!nrf_dfu_validation_init_cmd_present())
        {
            /* Can't accept data because DFU isn't initialized by init command. */
            NRF_LOG_ERROR("Cannot create data object without valid init command");
            p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
            return;
        }
    
        if (p_req->create.object_size == 0)
        {
            NRF_LOG_ERROR("Object size cannot be 0.")
            p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
            return;
        }
    
        if (  ((p_req->create.object_size & (CODE_PAGE_SIZE - 1)) != 0)
            && (s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size != m_firmware_size_req))
        {
            NRF_LOG_ERROR("Object size must be page aligned");
            ota_error_code = 1;
            p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
            return;
        }
    
        if (p_req->create.object_size > DATA_OBJECT_MAX_SIZE)
        {
            /* It is impossible to handle the command because the size is too large */
            NRF_LOG_ERROR("Invalid size for object (too large)");
            p_res->result = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
            return;
        }
    
        if ((s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size) >
            m_firmware_size_req)
        {
            NRF_LOG_ERROR("Creating the object with size 0x%08x would overflow firmware size. "
                          "Offset is 0x%08x and firmware size is 0x%08x.",
                          p_req->create.object_size,
                          s_dfu_settings.progress.firmware_image_offset_last,
                          m_firmware_size_req);
    
            p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
            ota_error_code = 2;
            return;
        }
    
        s_dfu_settings.progress.data_object_size      = p_req->create.object_size;
        s_dfu_settings.progress.firmware_image_crc    = s_dfu_settings.progress.firmware_image_crc_last;
        s_dfu_settings.progress.firmware_image_offset = s_dfu_settings.progress.firmware_image_offset_last;
        s_dfu_settings.write_offset                   = s_dfu_settings.progress.firmware_image_offset_last;
    
        /* Erase the page we're at. */
        if (nrf_dfu_flash_erase((m_firmware_start_addr + s_dfu_settings.progress.firmware_image_offset),
                                CEIL_DIV(p_req->create.object_size, CODE_PAGE_SIZE), NULL) != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Erase operation failed");
            p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
            return;
        }
    
        NRF_LOG_DEBUG("Creating object with size: %d. Offset: 0x%08x, CRC: 0x%08x",
                     s_dfu_settings.progress.data_object_size,
                     s_dfu_settings.progress.firmware_image_offset,
                     s_dfu_settings.progress.firmware_image_crc);
        
       NRF_LOG_INFO("Creating object with size: %d.  Offset: 0x%08x, CRC: 0x%08x\r\n",
                     s_dfu_settings.progress.data_object_size,
                     s_dfu_settings.progress.firmware_image_offset,
                     s_dfu_settings.progress.firmware_image_crc);
    
    
          /* check if flash is enabled */
            if(is_flash_enable() == false)
            {
              NRF_LOG_INFO("Flash in sleep state. Reinintialising\r\n");
    
              Enable_Flash();
            }
    
            if(nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, FIRMWARE_FLASH_ADDR + (s_dfu_settings.progress.firmware_image_offset)) != NRFX_SUCCESS)
            {
              NRF_LOG_INFO("Failed to rrase data blocks in Ext Flash.\r\n");
            }
            else
            {
              NRF_LOG_INFO("Succsessfully Erased Ext Flash block at: 0x%X\r\n\r\n",FIRMWARE_FLASH_ADDR + (s_dfu_settings.progress.firmware_image_offset));
              WAIT_FOR_PERIPH();
              nrf_delay_ms(500);
            }
    
    
    }
     

    2: in flash store I have changed to write the code in external flash using QSPI.

    static void on_data_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
    {
        NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (data)");
    
        if (!nrf_dfu_validation_init_cmd_present())
        {
            /* Can't accept data because DFU isn't initialized by init command. */
            p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
            return;
        }
    
        uint32_t const data_object_offset = s_dfu_settings.progress.firmware_image_offset -
                                            s_dfu_settings.progress.firmware_image_offset_last;
    
        if ((p_req->write.len + data_object_offset) > s_dfu_settings.progress.data_object_size)
        {
            /* Can't accept data because too much data has been received. */
            NRF_LOG_ERROR("Write request too long");
            p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
            return;
        }
    
    
    
        uint32_t const write_addr = m_firmware_start_addr + s_dfu_settings.write_offset;
        /* CRC must be calculated before handing off the data to fstorage because the data is
         * freed on write completion.
         */
        uint32_t const next_crc =
            crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_crc);
    
        ASSERT(p_req->callback.write);
    
        ret_code_t ret = NRF_ERROR_BASE_NUM;
          //ret_code_t ret =
          //  nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);
    
            
            /* check if flash is enabled */
            if(is_flash_enable() == false)
            {
              NRF_LOG_INFO("Flash in sleep state. Reinintialising\r\n");
    
              Enable_Flash();
            }
            
            
            if(nrf_drv_qspi_write(p_req->write.p_data, p_req->write.len,FIRMWARE_FLASH_ADDR + s_dfu_settings.write_offset) != NRFX_SUCCESS)
            {
              NRF_LOG_INFO("\r\nFailed storing data blocks in Ext Flash.\r\n");
            }
            else
            {
              NRF_LOG_INFO("Succsessfully storing data block at: 0x%X\r\n\r\n",FIRMWARE_FLASH_ADDR + s_dfu_settings.write_offset);
              WAIT_FOR_PERIPH();
              p_req->callback.write((void*)p_req->write.p_data);
              ret = NRF_SUCCESS;
            }
    
        if (ret != NRF_SUCCESS)
        {
            /* When nrf_dfu_flash_store() fails because there is no space in the queue,
             * stop processing the request so that the peer can detect a CRC error
             * and retransmit this object. Remember to manually free the buffer !
             */
            p_req->callback.write((void*)p_req->write.p_data);
            return;
        }
    
        /* Update the CRC of the firmware image. */
        s_dfu_settings.write_offset                   += p_req->write.len;
        s_dfu_settings.progress.firmware_image_offset += p_req->write.len;
        s_dfu_settings.progress.firmware_image_crc     = next_crc;
    
        /* This is only used when the PRN is triggered and the 'write' message
         * is answered with a CRC message and these field are copied into the response.
         */
        p_res->write.crc    = s_dfu_settings.progress.firmware_image_crc;
        p_res->write.offset = s_dfu_settings.progress.firmware_image_offset;
    }

    3: in calculate hash i have changed it to copy data from QSPI and update the hash accordingly.

    ret_code_t nrf_crypto_hash_calculate(nrf_crypto_hash_context_t    * const p_context,
                                         nrf_crypto_hash_info_t       const * p_info,
                                         uint8_t                      const * p_data,
                                         size_t                               data_size,
                                         uint8_t                            * p_digest,
                                         size_t                       * const p_digest_size)
    {
        ret_code_t                      ret_val;
        nrf_crypto_hash_context_t     * p_ctx  = (nrf_crypto_hash_context_t *)p_context;
        void                          * p_allocated_context = NULL;
    
    // Internal allocation of context not available for CC310_BL in order to save code size.
    #if defined(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED) && (NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED == 1)
        
        // Do nothing
        
    #elif defined(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED) && (NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED == 0)
        
        // Validate input. Only validate input parameters that are used locally, others are validated
        // in the init, update and/or finalize functions.
        VERIFY_TRUE(p_info != NULL, NRF_ERROR_CRYPTO_INPUT_NULL);
    
        // Allocate context if needed (not provided by the user).
        if (p_context == NULL)
        {
            p_allocated_context = NRF_CRYPTO_ALLOC(p_info->context_size);
            if (p_allocated_context == NULL)
            {
                return NRF_ERROR_CRYPTO_ALLOC_FAILED;
            }
            p_ctx = (nrf_crypto_hash_context_t *)p_allocated_context;
        }
        
    #else
    
        #warning NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED define not found in sdk_config.h (Is the sdk_config.h valid?).
        
    #endif // NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED
    
        ret_val = nrf_crypto_hash_init(p_ctx, p_info);
        NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
    
    
        if(validation_state == 0)
        {
            ret_val = nrf_crypto_hash_update(p_ctx, p_data, data_size);
            NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
            validation_state = 1;
        }
        else
        {
            uint16_t firmware_blocks = data_size / FIRMWARE_BLOCK_SIZE;
            uint8_t rest_block = data_size % FIRMWARE_BLOCK_SIZE;
    
    
            printf("data_size: %d", data_size);
            printf("firmware_blocks: %d", firmware_blocks);
            printf("rest_block: %d", rest_block);
    
    
            for(uint16_t i=0; i <= firmware_blocks; i++)
            {
              /* check if flash is enabled */
                if(is_flash_enable() == false)
                {
                    printf("Flash in sleep state. Reinintialising\r\n");
    
                    Enable_Flash();
                }
            
                uint8_t m_buffer_rx[FIRMWARE_BLOCK_SIZE];
    
                if(i == firmware_blocks)
                {
                    if(nrf_drv_qspi_read(m_buffer_rx, rest_block,FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i)) != NRFX_SUCCESS)
                    {
                       printf("\r\nFailed read data blocks in Ext Flash.\r\n");
                    }
                    else
                    {
                       printf("Succsessfully read rest_block data block from: 0x%X\r\n\r\n",FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i));
                       WAIT_FOR_PERIPH();
                       ret_val = nrf_crypto_hash_update(p_ctx, m_buffer_rx, rest_block);
                       NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
                    }
                }
                else
                {
                    if(nrf_drv_qspi_read(m_buffer_rx, FIRMWARE_BLOCK_SIZE,FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i)) != NRFX_SUCCESS)
                    {
                        printf("\r\nFailed read data blocks in Ext Flash.\r\n");
                    }
                    else
                    {
                        printf("Succsessfully read data block %d from: 0x%X\r\n\r\n", i ,FIRMWARE_FLASH_ADDR + (FIRMWARE_BLOCK_SIZE * i));
                        WAIT_FOR_PERIPH();
                        ret_val = nrf_crypto_hash_update(p_ctx, m_buffer_rx, FIRMWARE_BLOCK_SIZE);
                        NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
                    }
                }            
            }
            validation_state = 0;
        }
    
        ret_val = nrf_crypto_hash_finalize(p_ctx, p_digest, p_digest_size);
        NRF_CRYPTO_VERIFY_SUCCESS_DEALLOCATE(ret_val, p_allocated_context);
    
    #if !NRF_MODULE_ENABLED(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256)
        // Free context if allocated internally
        if (p_allocated_context != NULL)
        {
            NRF_CRYPTO_FREE(p_allocated_context);
        }
    #endif // !NRF_MODULE_ENABLED(NRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256)
    
        return NRF_SUCCESS;
    }
    
    #endif // NRF_MODULE_ENABLED(NRF_CRYPTO_HASH)
    
    #endif // NRF_MODULE_ENABLED(NRF_CRYPTO)

    and after that few more changes to get notified that hash has been verified and also to find out flow of the code 

    1

    #if NRF_DFU_IN_APP
            res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
            printf("Post Validation Error Code: %d\r\n",res.result );
    
            #else
            res.result = nrf_dfu_validation_activation_prepare(m_firmware_start_addr, m_firmware_size_req);
            #endif

    2 and in this this change i didn't find the output after this  if (!is_trusted). may be this piece of code is not executing or something

    nrf_dfu_result_t postvalidate(uint32_t data_addr, uint32_t data_len, bool is_trusted)
    {
        nrf_dfu_result_t           ret_val = NRF_DFU_RES_CODE_SUCCESS;
        dfu_init_command_t const * p_init  = mp_init;
    
        if (!fw_hash_ok(p_init, data_addr, data_len))
        {
            ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_VERIFICATION_FAILED);
        }
        else
        {
            printf("postvalidate Hash ok\r\n");
          
            if (p_init->type == DFU_FW_TYPE_APPLICATION)
            {
                if (!postvalidate_app(p_init, data_addr, data_len, is_trusted))
                {
                    ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
                    printf("postvalidate fun error: postvalidate_app %d\r\n",ret_val);
                }
                else
                {
                  printf("postvalidate fun success\r\n");
                }
            }
    #if NRF_DFU_SUPPORTS_EXTERNAL_APP
            else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
            {
                if (!is_trusted)
                {
                    // This function must be implemented externally
                    ret_val = nrf_dfu_validation_post_external_app_execute(p_init, is_trusted);
                }
                else
                {
                    s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_EXT_APP;
                }
            }
    #endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
            else
            {
                bool with_sd = p_init->type & DFU_FW_TYPE_SOFTDEVICE;
                bool with_bl = p_init->type & DFU_FW_TYPE_BOOTLOADER;
    
                if (!postvalidate_sd_bl(p_init, with_sd, with_bl, data_addr, data_len, is_trusted))
                {
                    ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
                    if (is_trusted && with_sd && !DFU_REQUIRES_SOFTDEVICE &&
                        (data_addr == nrf_dfu_softdevice_start_address()))
                    {
                        nrf_dfu_softdevice_invalidate();
                    }
                }
            }
        }
    
        if (!is_trusted)
        {
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
                    printf("\r\nSet DFU setting current bank.\r\n");
    
                s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_1;
            }
            else
            {
                printf("nrf_dfu_settings_progress_reset if !is_trusted\r\n");
    
                nrf_dfu_settings_progress_reset();
            }
        }
        else
        {
            if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
            {
            printf("Mark the update as complete and valid.\r\n");
                // Mark the update as complete and valid.
                s_dfu_settings.bank_1.image_crc  = crc32_compute((uint8_t *)data_addr, data_len, NULL);
                s_dfu_settings.bank_1.image_size = data_len;
            }
            else
            {
                nrf_dfu_bank_invalidate(&s_dfu_settings.bank_1);
                        printf("Mark the update as Invalid. : %d\r\n",ret_val);
    
            }
    
            printf("nrf_dfu_settings_progress_reset if is_trusted\r\n");
    
            nrf_dfu_settings_progress_reset();
            s_dfu_settings.progress.update_start_address = data_addr;
        }
    
        return ret_val;
    }
    

    3

    static bool nrf_dfu_validation_hash_ok(uint8_t const * p_hash, uint32_t src_addr, uint32_t data_len, bool little_endian)
    {
        ret_code_t err_code;
        bool       result   = true;
        uint8_t    hash_be[NRF_CRYPTO_HASH_SIZE_SHA256];
        size_t     hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
    
        nrf_crypto_hash_context_t hash_context = {0};
    
        crypto_init();
    
        if (little_endian)
        {
            // Convert to hash to big-endian format for use in nrf_crypto.
            nrf_crypto_internal_swap_endian(hash_be,
                                            p_hash,
                                            NRF_CRYPTO_HASH_SIZE_SHA256);
            p_hash = hash_be;
        }
    
        NRF_LOG_DEBUG("Hash verification. start address: 0x%x, size: 0x%x",
                      src_addr,
                      data_len);
    
       NRF_LOG_INFO("Hash verification. start address: 0x%x, size: 0x%x",
                      src_addr,
                      data_len);
    
    
        err_code = nrf_crypto_hash_calculate(&hash_context,
                                             &g_nrf_crypto_hash_sha256_info,
                                             (uint8_t*)src_addr,
                                             data_len,
                                             m_fw_hash,
                                             &hash_len);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Could not run hash verification (err_code 0x%x).", err_code);
            result = false;
        }
        else if (memcmp(m_fw_hash, p_hash, NRF_CRYPTO_HASH_SIZE_SHA256) != 0)
        {
            NRF_LOG_WARNING("Hash verification failed.");
            NRF_LOG_INFO("Hash verification failed.");
            NRF_LOG_DEBUG("Expected FW hash:")
            NRF_LOG_INFO("Expected FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(p_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_DEBUG("Actual FW hash:")
            NRF_LOG_INFO("Actual FW hash:")
            NRF_LOG_HEXDUMP_DEBUG(m_fw_hash, NRF_CRYPTO_HASH_SIZE_SHA256);
            NRF_LOG_FLUSH();
    
            result = false;
        }
    
        return result;
    }

  • Hi Priyesh,

    It seems that you've made good progress on this already. The next step may be to modify the image copy functions in nrf_bootloader_fw_activation.c to enable the bootloader to copy images from bank 1 in the QSPI flash.

    Best regards,

    Vidar

  • Hi Vidar,

    Thank you for your guidance.

    I am also reading previous questions on devzone about the same subject and I have a few more questions regarding the process:

    1. External Flash Detection: How does the bootloader identify that there is a new firmware in the external flash? Initially, it appears to search for new firmware in the internal flash. Could you please provide more insights into this process?

    2. Logging: I'm also working on enabling logging in the bootloader. Could you please guide me on how to modify the flash address settings to ensure the logs are written correctly and do not conflict with other memory regions?

      MEMORY
      {
        FLASH (rx) : ORIGIN = 0xf8000, LENGTH = 0x6000
        RAM (rwx) :  ORIGIN = 0x20000008, LENGTH = 0x3fff8
        uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
        mbr_params_page (r) : ORIGIN = 0x000FE000, LENGTH = 0x1000
        bootloader_settings_page (r) : ORIGIN = 0x000FF000, LENGTH = 0x1000
        uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4
      }

  • Hi,

    The application signals the bootloader that a new update is available by setting the .bank_current value in the bootloader settings to NRF_DFU_CURRENT_BANK_1. The bootloader then validates the image based on the data stored in the settings page and subsequently runs the nrf_bootloader_fw_activate() to copy the image from bank 1 to its destination.

    This post discusses which part of the settings page can be updated by the application: RE: App-based DFU, changing bank#1 address? 

     With regards to logging, I recommend you try the 'debug' variant of the bootloader project. This project has logging over RTT enabled by default. 

    Best regards,

    Vidar

  • The application signals the bootloader that a new update is available by setting the .bank_current value in the bootloader settings to NRF_DFU_CURRENT_BANK_1.

    we are writing our app in external flash . NRF_DFU_CURRENT_BANK_1 is not set by our code what else we need to change after that. and what changes we are suppose to make in that red lined postvalidate() function.

    till now i have made some changes in my code to write magic number in external flash to trigger  bootloader about new application in external flash which is also working 

    1:in nrf_dfu_valodation.c file inside nrf_dfu_validation_signature_check() function: after image verification i have erased an address in external flash for magic number.

    // Function to perform signature check if required.
    static nrf_dfu_result_t nrf_dfu_validation_signature_check(dfu_signature_type_t signature_type,
                                                               uint8_t      const * p_signature,
                                                               uint32_t             signature_len,
                                                               uint8_t      const * p_data,
                                                               uint32_t             data_len)
    {
        ret_code_t err_code;
        size_t     hash_len = NRF_CRYPTO_HASH_SIZE_SHA256;
    
        nrf_crypto_hash_context_t         hash_context   = {0};
        nrf_crypto_ecdsa_verify_context_t verify_context = {0};
    
        crypto_init();
    
        NRF_LOG_INFO("Signature required. Checking signature.")
        if (p_signature == NULL)
        {
            NRF_LOG_WARNING("No signature found.");
            return EXT_ERR(NRF_DFU_EXT_ERROR_SIGNATURE_MISSING);
        }
    
        if (signature_type != DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256)
        {
            NRF_LOG_INFO("Invalid signature type");
            return EXT_ERR(NRF_DFU_EXT_ERROR_WRONG_SIGNATURE_TYPE);
        }
    
        NRF_LOG_INFO("Calculating hash (len: %d)", data_len);
        err_code = nrf_crypto_hash_calculate(&hash_context,
                                             &g_nrf_crypto_hash_sha256_info,
                                             p_data,
                                             data_len,
                                             m_sig_hash,
                                             &hash_len);
        if (err_code != NRF_SUCCESS)
        {
            return NRF_DFU_RES_CODE_OPERATION_FAILED;
        }
    
        if (sizeof(m_signature) != signature_len)
        {
            return NRF_DFU_RES_CODE_OPERATION_FAILED;
        }
    
        // Prepare the signature received over the air.
        memcpy(m_signature, p_signature, signature_len);
    
        // Calculate the signature.
        NRF_LOG_INFO("Verify signature");
    
        // The signature is in little-endian format. Change it to big-endian format for nrf_crypto use.
        nrf_crypto_internal_double_swap_endian_in_place(m_signature, sizeof(m_signature) / 2);
    
        err_code = nrf_crypto_ecdsa_verify(&verify_context,
                                           &m_public_key,
                                           m_sig_hash,
                                           hash_len,
                                           m_signature,
                                           sizeof(m_signature));
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Signature failed (err_code: 0x%x)", err_code);
            NRF_LOG_DEBUG("Signature:");
            NRF_LOG_HEXDUMP_DEBUG(m_signature, sizeof(m_signature));
            NRF_LOG_DEBUG("Hash:");
            NRF_LOG_HEXDUMP_DEBUG(m_sig_hash, hash_len);
            NRF_LOG_DEBUG("Public Key:");
            NRF_LOG_HEXDUMP_DEBUG(pk, sizeof(pk));
            NRF_LOG_FLUSH();
    
            return NRF_DFU_RES_CODE_INVALID_OBJECT;
        }
    
        NRF_LOG_INFO("Image verified");
    
        if(nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, MAGIC_NUMBER_ADDR) != NRFX_SUCCESS)
        {
          NRF_LOG_INFO("\r\nFailed to errase data blocks in Ext Flash for magic number.\r\n");
        }
        else
        {
          NRF_LOG_INFO("Succsessfully Erased Ext Flash block for magic number at: 0x%X\r\n\r\n",MAGIC_NUMBER_ADDR);
          WAIT_FOR_PERIPH();
        }
    
    
        return NRF_DFU_RES_CODE_SUCCESS;
    }

    2:in nrf_dfu_valodation.c file inside postvalidate() function: I have written the magic number in external flash .

    #include "nrf_drv_qspi.h"
    
    #define MAGIC_NUMBER_ADDR 0x200000  // block no. 32
    uint8_t MAGIC_NUMBER[]="12112345";
    
    
    
    nrf_dfu_result_t postvalidate(uint32_t data_addr, uint32_t data_len, bool is_trusted)
    {
        nrf_dfu_result_t           ret_val = NRF_DFU_RES_CODE_SUCCESS;
        dfu_init_command_t const * p_init  = mp_init;
    
        if (!fw_hash_ok(p_init, data_addr, data_len))
        {
            ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_VERIFICATION_FAILED);
        }
        else
        {
            printf("postvalidate Hash ok\r\n");
          
            if (p_init->type == DFU_FW_TYPE_APPLICATION)
            {
                if (!postvalidate_app(p_init, data_addr, data_len, is_trusted))
                {
                    ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
                    printf("postvalidate fun error: postvalidate_app %d\r\n",ret_val);
                }
                else
                {
                  printf("postvalidate fun success\r\n");
    
    
                  if(nrf_drv_qspi_write(MAGIC_NUMBER, sizeof(MAGIC_NUMBER),MAGIC_NUMBER_ADDR) != NRFX_SUCCESS)
                  {
                    printf("Failed to store magic number in Ext Flash.\r\n");
                  }
                  else
                  {
                    printf("Succsessfully storing magic number at: 0x%X\r\n\r\n",MAGIC_NUMBER_ADDR);
                    WAIT_FOR_PERIPH();
                  }
    
                }
            }

    3:in nrf_bootloader.c file inside nrf_bootloader_init() function: i have made changes to read that magic number again from external flash to verify the new firmware.


    #include "nrf_drv_qspi.h"
    
    #define DFU_QSPI_BANK_ADDR 0x200000  // block no. 32
    uint8_t DEFAULT_DFU_QSPI_BANK[8]= "12112345";
    uint8_t DFU_QSPI_BANK[8];
    uint8_t DFU_QSPI_BANK_SIZE = sizeof(DEFAULT_DFU_QSPI_BANK);
    
    
    
    ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer)
    {
        NRF_LOG_DEBUG("In nrf_bootloader_init");
    
        ret_code_t                            ret_val;
        nrf_bootloader_fw_activation_result_t activation_result;
        uint32_t                              initial_timeout;
        bool                                  dfu_enter = false;
    
        m_user_observer = observer;
    
        if (NRF_BL_DEBUG_PORT_DISABLE)
        {
            nrf_bootloader_debug_port_disable();
        }
    
        if (NRF_BL_DFU_ENTER_METHOD_BUTTON)
        {
            dfu_enter_button_init();
        }
    
        ret_val = nrf_dfu_settings_init(false);
        if (ret_val != NRF_SUCCESS)
        {
            return NRF_ERROR_INTERNAL;
        }
    
        #if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
    
        if(nrf_drv_qspi_read(DFU_QSPI_BANK, DFU_QSPI_BANK_SIZE,DFU_QSPI_BANK_ADDR) != NRFX_SUCCESS)
        {
          printf("\r\nFailed read DFU_QSPI_BANK.\r\n");
        }
        else
        {
          printf("Succsessfully read DFU_QSPI_BANK from: 0x%X\r\n\r\n",DFU_QSPI_BANK_ADDR);
          WAIT_FOR_PERIPH();
        }
    
        //compare data 
    
        // Postvalidate if DFU has signaled that update is ready.
        if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1)
        {
            postvalidate();
        }
        #endif
    
        // Check if an update needs to be activated and activate it.
        activation_result = nrf_bootloader_fw_activate();

    above all works but i am still not sure about changes in bootloader because app_activate(),sd_activate() and bl_activate() all are using the same uint32_t         src_addr = s_dfu_settings.progress.update_start_address; to find the updated address and also how to chnage the image size  uint32_t const image_size = s_dfu_settings.bank_1.image_size; there are multiple queries related to this. will you please, guide me with step by step changes .

    here is the output the changes i have made




  • I recommend you try the 'debug' variant of the bootloader project. This project has logging over RTT enabled by default

    I am using examples\thread\dfu\bootloader example for bootloader and there is not option of 'debug' variant in that project. should i change this bootloader example.

Reply Children
No Data
Related