Any way to add CRC of image during linking?

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Our bootloader expects an image of variable size with a CRC32 as it's last four bytes. The size is stored in external nvm. On boot it CRCs the image (minus the last 4 bytes) then compares it with the following 4 bytes. We are currently appending the CRC32 post-build with srec_cat, but this adds several steps to debugging. Is it possible to automate this process in the linker, so the ELF file also has the CRC in the correct position?

This topic has a solution.
Last Edited: Fri. Apr 26, 2019 - 02:40 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I couldn't find anything automatically generated by the IDE so I went the post-build script route.  The two magic programs you need are "srec_cat.exe" and in my case "arm-none-eabi-objcopy.exe".  Run the programs from a command line to see the options.

 

Generally it's a three step:  ELF-->SREC, SREC->BIN with CRC, BIN with CRC-->ELF

1. Extract a Motorola S-record file from the .ELF project output using "arm-none-eabi-objcopy.exe"

2. Use "srec_cat.exe" to manipulate the S-record file input file, calculate a CRC, and export the entire image as a binary file

3. Use "arm-none-eabi-objcopy.exe" one more time on the binary file with the CRC to get back to the .ELF file

 

In my case we insert the program length and 32-bit CRC at the top of flash memory.  Upon startup a CRC is calculated across the program image of <Length> bytes, and compared with <CRC>.  <Length> is stored at <TOP OF FLASH - 8>, <CRC> is stored at <TOP OF FLASH - 4>.  The linker .ld file also needed modifications to add the crc area, _crc_program_length, and _crc_program symbols.

 

The script and .ld file we use is attached.  It's for a SAME70 project.

 

 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here's the source code to check if <Length> and <CRC> are valid at startup

 

//------------------------------------------------------------------------------
// \brief:  crc_IsProgramCRCValid()
//          Verifies the stored CRC in the program area against the CRC of the program itself.
//          The CRC is stored at the last four bytes in the internal flash memory.
//          The length of the programmed area is stored in the four bytes before the CRC.
//
//  NOTE:   The inserted CRC via the post build step is a 802.3/CCITT-like value
//
// \param:  void
// \return: bool - returns true if all checks pass
//------------------------------------------------------------------------------
bool crc_IsProgramCRCValid(void)
{
    uint32_t CalculatedCRC;

    // verify the post-build script was run and the default values stored in the .ELF file are replaced
    if (__crc_program_length != (uint32_t)(&__crc_program_end - &__crc_program_begin)) {
        TRACE_ERROR("%s(%d): .ELF file stored code length does not match calculated value, check post-build script\r\n", __func__, __LINE__);
        return false;
    }
    if (__crc_program == 0xDEADC0DE) {
        TRACE_ERROR("%s(%d): .ELF file CRC32 is using the default value, check post-build script\r\n", __func__, __LINE__);
        return false;
    }

    // calculate the CCITT/802.3-like CRC for the program area
    CalculatedCRC = crc_Fast32(crc32_Table_0x04C11DB7, 0xffffffff, &__crc_program_begin, __crc_program_length, true, true, 0xffffffff);

#ifdef TP7_1_3_1
    #warning "TP7.1.3.1 active - overriding CRC calculated value to induce fcFirmwareCRCFailure"
    CalculatedCRC = ~__crc_program;
#endif

    return (CalculatedCRC == __crc_program);
}//end crc_IsProgramCRCValid()

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ScottMN wrote:

Here's the source code to check if <Length> and <CRC> are valid at startup

 

//------------------------------------------------------------------------------
// \brief:  crc_IsProgramCRCValid()
//          Verifies the stored CRC in the program area against the CRC of the program itself.
//          The CRC is stored at the last four bytes in the internal flash memory.
//          The length of the programmed area is stored in the four bytes before the CRC.
//
//  NOTE:   The inserted CRC via the post build step is a 802.3/CCITT-like value
//
// \param:  void
// \return: bool - returns true if all checks pass
//------------------------------------------------------------------------------
bool crc_IsProgramCRCValid(void)
{
    uint32_t CalculatedCRC;

    // verify the post-build script was run and the default values stored in the .ELF file are replaced
    if (__crc_program_length != (uint32_t)(&__crc_program_end - &__crc_program_begin)) {
        TRACE_ERROR("%s(%d): .ELF file stored code length does not match calculated value, check post-build script\r\n", __func__, __LINE__);
        return false;
    }
    if (__crc_program == 0xDEADC0DE) {
        TRACE_ERROR("%s(%d): .ELF file CRC32 is using the default value, check post-build script\r\n", __func__, __LINE__);
        return false;
    }

    // calculate the CCITT/802.3-like CRC for the program area
    CalculatedCRC = crc_Fast32(crc32_Table_0x04C11DB7, 0xffffffff, &__crc_program_begin, __crc_program_length, true, true, 0xffffffff);

#ifdef TP7_1_3_1
    #warning "TP7.1.3.1 active - overriding CRC calculated value to induce fcFirmwareCRCFailure"
    CalculatedCRC = ~__crc_program;
#endif

    return (CalculatedCRC == __crc_program);
}//end crc_IsProgramCRCValid()

 

 

Thanks, that's more or less what we are doing now. I was hoping there was some way to do it before the end of the build so I could just use the green play button for debugging instead of downloading the CRCed .bin and then attaching to the target.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

cbc02009 wrote:

I was hoping there was some way to do it before the end of the build so I could just use the green play button for debugging instead of downloading the CRCed .bin and then attaching to the target.

 

If you inject the CRC into the .ELF file, you can use the green play button directly.  It's seamless: clean, build, press go and the debugger runs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ScottMN wrote:

cbc02009 wrote:

I was hoping there was some way to do it before the end of the build so I could just use the green play button for debugging instead of downloading the CRCed .bin and then attaching to the target.

 

If you inject the CRC into the .ELF file, you can use the green play button directly.  It's seamless: clean, build, press go and the debugger runs.

 

I'm sorry, I completely misunderstood what you posted. I get it now. Thank you for your help.