//***************************************************************************** // // bl_crc32.c - CRC32 calculation functions used in the boot loader. // // Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package. // //***************************************************************************** #include #include #include "inc/hw_types.h" #include "inc/hw_flash.h" #include "inc/hw_sysctl.h" #include "bl_config.h" #include "boot_loader/bl_crc32.h" //***************************************************************************** // // Storage for the CRC32 calculation lookup table. // //***************************************************************************** static uint32_t g_pui32CRC32Table[256]; //***************************************************************************** // // Initialize the CRC32 calculation table for the polynomial used. We pick // the commonly used ANSI X 3.66 polymonial. This code was informed by an // example found at http://www.createwindow.com/programming/crc32/index.htm. // //***************************************************************************** static uint32_t Reflect(uint32_t ui32Ref, uint8_t ui8Ch) { uint_fast32_t ui32Value; int_fast16_t i16Loop; // // Clear our accumulator variable. // ui32Value = 0; // // Swap bit 0 for bit 7, bit 1 for bit 6, etc. // for(i16Loop = 1; i16Loop < (ui8Ch + 1); i16Loop++) { if(ui32Ref & 1) { ui32Value |= 1 << (ui8Ch - i16Loop); } ui32Ref >>= 1; } // // Return the reflected value. // return(ui32Value); } //***************************************************************************** // // Initialize the lookup table used in calculating the CRC32 value. // //***************************************************************************** void InitCRC32Table(void) { uint_fast32_t ui32Polynomial; int_fast16_t i16Loop, i16Bit; // // This is the ANSI X 3.66 polynomial as required by the DFU // specification. // ui32Polynomial = 0x04c11db7; for(i16Loop = 0; i16Loop <= 0xFF; i16Loop++) { g_pui32CRC32Table[i16Loop]=Reflect(i16Loop, 8) << 24; for (i16Bit = 0; i16Bit < 8; i16Bit++) { g_pui32CRC32Table[i16Loop] = ((g_pui32CRC32Table[i16Loop] << 1) ^ (g_pui32CRC32Table[i16Loop] & ((uint32_t)1 << 31) ? ui32Polynomial : 0)); } g_pui32CRC32Table[i16Loop] = Reflect(g_pui32CRC32Table[i16Loop], 32); } } //***************************************************************************** // // Calculate the CRC for the supplied block of data. // //***************************************************************************** uint32_t CalculateCRC32(uint8_t *pui8Data, uint32_t ui32Length, uint32_t ui32CRC) { uint32_t ui32Count; uint8_t *pui8Buffer; uint8_t ui8Char; // // Get a pointer to the start of the data and the number of bytes to // process. // pui8Buffer = pui8Data; ui32Count = ui32Length; // // Perform the algorithm on each byte in the supplied buffer using the // lookup table values calculated in InitCRC32Table(). // while(ui32Count--) { ui8Char = *pui8Buffer++; ui32CRC = (ui32CRC >> 8) ^ g_pui32CRC32Table[(ui32CRC & 0xFF) ^ ui8Char]; } // // Return the result. // return(ui32CRC); } //***************************************************************************** // //! Checks that the embedded CRC in the image matches the expected value. //! //! \param pui32Image points to the start of the firmware image in memory. //! //! This function finds the firmware image information header and verifies that //! the embedded CRC32 matches one calculated over the image. //! //! \return Returns \b CHECK_CRC_OK if the CRC calculated matches the value //! embedded in the image, \b CHECK_CRC_NO_HEADER if no image information //! header was found at the top of the vector table, \b CHECK_CRC_BAD_CRC if //! an embedded CRC was found but did not match the calculated value or \b //! CHECK_CRC_ZERO_LENGTH if the length field of the image information header //! contains 0 (likely indicating that the image had not been run through the //! binpack tool which inserts the length and CRC values into the header). // //***************************************************************************** uint32_t CheckImageCRC32(uint32_t *pui32Image) { uint32_t ui32Loop, ui32FlashSize, ui32CRC; // // Determine the size of flash (giving an upper bound for the image // size). // if(CLASS_IS_TM4C129) { // // Get the flash size from the FLASH_PP register. // ui32FlashSize = ((2048 * ((HWREG(FLASH_PP) & FLASH_PP_SIZE_M) + 1)) - APP_START_ADDRESS); } else { // // Compute the size of the flash. // ui32FlashSize = (((HWREG(SYSCTL_DC0) & SYSCTL_DC0_FLASHSZ_M) << 11) + 0x800 - APP_START_ADDRESS); } // // Scan for the image information header marker bytes. Given that the // largest possible vector table includes 16 system exceptions and 240 // IC-specific vectors, we only need to search 257 words into memory before // giving up. // for(ui32Loop = 0; ui32Loop < 257; ui32Loop++) { // // Have we found the header marker words? // if((pui32Image[ui32Loop] == 0xFF01FF02) && (pui32Image[ui32Loop + 1] == 0xFF03FF04)) { // // Yes. Check to see if the length field is 0xFFFFFFFF. This // likely indicates that the image has not been processed by the // binpack tool which adds the length and CRC information to the // image header. // if(pui32Image[ui32Loop + 2] == 0xFFFFFFFF) { // // The header reports an image size of 0 so we can't go on and // check the CRC. // return(CHECK_CRC_NO_LENGTH); } // // Extract the image length and ensure that it is sensible // given the flash size. We assume the length is invalid if it // is larger than the available flash size or smaller than the // space taken up by the vector table and header we've already // scanned through. // if((pui32Image[ui32Loop + 2] > ui32FlashSize) || (pui32Image[ui32Loop + 2] < ((ui32Loop + 4) * sizeof(uint32_t)))) { // // The header reports an image size that is larger than the // available flash so this is obviously incorrect. Fail the // check. // return(CHECK_CRC_BAD_LENGTH); } // // Calculate the CRC32 value for the image. Note that we skip the // 4 bytes that hold the check CRC. // ui32CRC = CalculateCRC32((uint8_t *)pui32Image, (ui32Loop + 3) * sizeof(uint32_t), 0xffffffff); ui32CRC = CalculateCRC32((uint8_t *)&pui32Image[ui32Loop + 4], (pui32Image[ui32Loop + 2] - ((ui32Loop + 4) * sizeof(uint32_t))), ui32CRC); ui32CRC ^= 0xffffffff; // // Determine whether the calculated CRC matches the value stored // in the image information header. // if(ui32CRC == pui32Image[ui32Loop + 3]) { return(CHECK_CRC_OK); } else { return(CHECK_CRC_BAD_CRC); } } } // // If we drop out the loop, there was no image information header so // fail the call. // return(CHECK_CRC_NO_HEADER); }