summaryrefslogtreecommitdiff
path: root/boot_loader/bl_crc32.c
blob: 94139873fe8ba9aa20f602552d00c6d710346fd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
//*****************************************************************************
//
// 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 <stdint.h>
#include <stdbool.h>
#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);
}