Blame view

tools/img2srec.c 9.72 KB
89752b9b5   wdenk   Initial revision
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
  /*************************************************************************
  |  COPYRIGHT (c) 2000 BY ABATRON AG
  |*************************************************************************
  |
  |  PROJECT NAME: Linux Image to S-record Conversion Utility
  |  FILENAME    : img2srec.c
  |
  |  COMPILER    : GCC
  |
  |  TARGET OS   : LINUX / UNIX
  |  TARGET HW   : -
  |
  |  PROGRAMMER  : Abatron / RD
  |  CREATION    : 07.07.00
  |
  |*************************************************************************
  |
  |  DESCRIPTION :
  |
  |  Utility to convert a Linux Boot Image to S-record:
  |  ==================================================
  |
  |  This command line utility can be used to convert a Linux boot image
  |  (zimage.initrd) to S-Record format used for flash programming.
  |  This conversion takes care of the special sections "IMAGE" and INITRD".
  |
  |  img2srec [-o offset] image > image.srec
  |
  |
  |  Build the utility:
  |  ==================
  |
  |  To build the utility use GCC as follows:
  |
  |  gcc img2srec.c -o img2srec
  |
  |
  |*************************************************************************
  |
  |
  |  UPDATES     :
  |
  |  DATE      NAME  CHANGES
  |  -----------------------------------------------------------
  |  Latest update
  |
  |  07.07.00  aba   Initial release
  |
  |*************************************************************************/
  
  /*************************************************************************
  |  INCLUDES
  |*************************************************************************/
375660907   Mike Frysinger   compiler.h: unify...
54
  #include "os_support.h"
fd66066ee   Mike Frysinger   img2srec: use sta...
55
  #include <stdbool.h>
89752b9b5   wdenk   Initial revision
56
57
58
59
60
61
62
63
  #include <stddef.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <ctype.h>
  #include <string.h>
  #include <elf.h>
  #include <unistd.h>
  #include <errno.h>
89752b9b5   wdenk   Initial revision
64
  /*************************************************************************
89752b9b5   wdenk   Initial revision
65
66
  |  FUNCTIONS
  |*************************************************************************/
fd66066ee   Mike Frysinger   img2srec: use sta...
67
  static char* ExtractHex (uint32_t* value,  char* getPtr)
89752b9b5   wdenk   Initial revision
68
  {
fd66066ee   Mike Frysinger   img2srec: use sta...
69
70
71
    uint32_t num;
    uint32_t digit;
    uint8_t  c;
89752b9b5   wdenk   Initial revision
72
73
74
75
76
  
    while (*getPtr == ' ') getPtr++;
    num = 0;
    for (;;) {
      c = *getPtr;
fd66066ee   Mike Frysinger   img2srec: use sta...
77
78
79
      if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
      else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10);
      else if ((c >= 'a') && (c <= 'f')) digit = (uint32_t)(c - 'a' + 10);
89752b9b5   wdenk   Initial revision
80
81
82
83
84
85
86
87
      else break;
      num <<= 4;
      num += digit;
      getPtr++;
    } /* for */
    *value = num;
    return getPtr;
  } /* ExtractHex */
fd66066ee   Mike Frysinger   img2srec: use sta...
88
  static char* ExtractDecimal (uint32_t* value,  char* getPtr)
89752b9b5   wdenk   Initial revision
89
  {
fd66066ee   Mike Frysinger   img2srec: use sta...
90
91
92
    uint32_t num;
    uint32_t digit;
    uint8_t  c;
89752b9b5   wdenk   Initial revision
93
94
95
96
97
  
    while (*getPtr == ' ') getPtr++;
    num = 0;
    for (;;) {
      c = *getPtr;
fd66066ee   Mike Frysinger   img2srec: use sta...
98
      if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
89752b9b5   wdenk   Initial revision
99
100
101
102
103
104
105
106
      else break;
      num *= 10;
      num += digit;
      getPtr++;
    } /* for */
    *value = num;
    return getPtr;
  } /* ExtractDecimal */
fd66066ee   Mike Frysinger   img2srec: use sta...
107
  static void ExtractNumber (uint32_t* value,  char* getPtr)
89752b9b5   wdenk   Initial revision
108
  {
51855e898   Masahiro Yamada   treewide: remove ...
109
    bool  neg = false;
89752b9b5   wdenk   Initial revision
110
111
112
  
    while (*getPtr == ' ') getPtr++;
    if (*getPtr == '-') {
fd66066ee   Mike Frysinger   img2srec: use sta...
113
      neg = true;
89752b9b5   wdenk   Initial revision
114
115
116
117
118
119
120
121
122
123
124
      getPtr++;
    } /* if */
    if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) {
      getPtr +=2;
      (void)ExtractHex(value, getPtr);
    } /* if */
    else {
      (void)ExtractDecimal(value, getPtr);
    } /* else */
    if (neg) *value = -(*value);
  } /* ExtractNumber */
fd66066ee   Mike Frysinger   img2srec: use sta...
125
  static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer)
89752b9b5   wdenk   Initial revision
126
  {
fd66066ee   Mike Frysinger   img2srec: use sta...
127
128
129
    uint16_t x;
    x = (uint16_t)*buffer++;
    x = (x<<8) + (uint16_t)*buffer++;
89752b9b5   wdenk   Initial revision
130
131
132
    *value = x;
    return buffer;
  } /* ExtractWord */
fd66066ee   Mike Frysinger   img2srec: use sta...
133
  static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer)
89752b9b5   wdenk   Initial revision
134
  {
fd66066ee   Mike Frysinger   img2srec: use sta...
135
136
137
138
139
    uint32_t x;
    x = (uint32_t)*buffer++;
    x = (x<<8) + (uint32_t)*buffer++;
    x = (x<<8) + (uint32_t)*buffer++;
    x = (x<<8) + (uint32_t)*buffer++;
89752b9b5   wdenk   Initial revision
140
141
142
    *value = x;
    return buffer;
  } /* ExtractLong */
fd66066ee   Mike Frysinger   img2srec: use sta...
143
  static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer)
89752b9b5   wdenk   Initial revision
144
145
146
147
  {
    while (count--) *data++ = *buffer++;
    return buffer;
  } /* ExtractBlock */
fd66066ee   Mike Frysinger   img2srec: use sta...
148
  static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum)
89752b9b5   wdenk   Initial revision
149
  {
fd66066ee   Mike Frysinger   img2srec: use sta...
150
    uint16_t  temp;
89752b9b5   wdenk   Initial revision
151
152
153
154
155
156
157
158
159
160
  
    static  char ByteToHex[] = "0123456789ABCDEF";
  
    *pCheckSum += value;
    temp  = value / 16;
    *pa++ = ByteToHex[temp];
    temp  = value % 16;
    *pa++ = ByteToHex[temp];
    return pa;
  }
fd66066ee   Mike Frysinger   img2srec: use sta...
161
162
  static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr,
  			  const uint8_t* data, int nCount)
89752b9b5   wdenk   Initial revision
163
  {
fd66066ee   Mike Frysinger   img2srec: use sta...
164
165
166
167
    uint16_t  addrLen;
    uint16_t  sRLen;
    uint16_t  checkSum;
    uint16_t  i;
89752b9b5   wdenk   Initial revision
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  
    switch (sType) {
    case 0:
    case 1:
    case 9:
      addrLen = 2;
      break;
    case 2:
    case 8:
      addrLen = 3;
      break;
    case 3:
    case 7:
      addrLen = 4;
      break;
    default:
      return pa;
    } /* switch */
  
    *pa++ = 'S';
    *pa++ = (char)(sType + '0');
    sRLen = addrLen + nCount + 1;
    checkSum = 0;
fd66066ee   Mike Frysinger   img2srec: use sta...
191
    pa = WriteHex(pa, (uint8_t)sRLen, &checkSum);
89752b9b5   wdenk   Initial revision
192
193
194
  
    /* Write address field */
    for (i = 1; i <= addrLen; i++) {
fd66066ee   Mike Frysinger   img2srec: use sta...
195
      pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum);
89752b9b5   wdenk   Initial revision
196
197
198
199
200
201
202
203
204
    } /* for */
  
    /* Write code/data fields */
    for (i = 0; i < nCount; i++) {
      pa = WriteHex(pa, *data++, &checkSum);
    } /* for */
  
    /* Write checksum field */
    checkSum = ~checkSum;
fd66066ee   Mike Frysinger   img2srec: use sta...
205
    pa = WriteHex(pa, (uint8_t)checkSum, &checkSum);
89752b9b5   wdenk   Initial revision
206
207
208
    *pa++ = '\0';
    return pa;
  }
fd66066ee   Mike Frysinger   img2srec: use sta...
209
  static void ConvertELF(char* fileName, uint32_t loadOffset)
89752b9b5   wdenk   Initial revision
210
211
212
213
  {
    FILE*         file;
    int           i;
    int           rxCount;
fd66066ee   Mike Frysinger   img2srec: use sta...
214
215
216
217
218
    uint8_t          rxBlock[1024];
    uint32_t         loadSize;
    uint32_t         firstAddr;
    uint32_t         loadAddr;
    uint32_t         loadDiff = 0;
89752b9b5   wdenk   Initial revision
219
220
    Elf32_Ehdr    elfHeader;
    Elf32_Shdr    sectHeader[32];
fd66066ee   Mike Frysinger   img2srec: use sta...
221
    uint8_t*         getPtr;
89752b9b5   wdenk   Initial revision
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    char          srecLine[128];
    char		*hdr_name;
  
  
    /* open file */
    if ((file = fopen(fileName,"rb")) == NULL) {
      fprintf (stderr, "Can't open %s: %s
  ", fileName, strerror(errno));
      return;
    } /* if */
  
    /* read ELF header */
    rxCount = fread(rxBlock, 1, sizeof elfHeader, file);
    getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock);
    getPtr = ExtractWord(&elfHeader.e_type, getPtr);
    getPtr = ExtractWord(&elfHeader.e_machine, getPtr);
fd66066ee   Mike Frysinger   img2srec: use sta...
238
239
240
241
242
    getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr);
    getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr);
    getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr);
    getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr);
    getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr);
89752b9b5   wdenk   Initial revision
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
    getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr);
    getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr);
    getPtr = ExtractWord(&elfHeader.e_phnum, getPtr);
    getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr);
    getPtr = ExtractWord(&elfHeader.e_shnum, getPtr);
    getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr);
    if (    (rxCount              != sizeof elfHeader)
         || (elfHeader.e_ident[0] != ELFMAG0)
         || (elfHeader.e_ident[1] != ELFMAG1)
         || (elfHeader.e_ident[2] != ELFMAG2)
         || (elfHeader.e_ident[3] != ELFMAG3)
         || (elfHeader.e_type     != ET_EXEC)
       ) {
      fclose(file);
      fprintf (stderr, "*** illegal file format
  ");
      return;
    } /* if */
  
    /* read all section headers */
    fseek(file, elfHeader.e_shoff, SEEK_SET);
    for (i = 0; i < elfHeader.e_shnum; i++) {
      rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file);
fd66066ee   Mike Frysinger   img2srec: use sta...
266
267
268
269
270
271
272
273
274
275
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_name, rxBlock);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_type, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_flags, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addr, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_offset, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_size, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_link, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_info, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addralign, getPtr);
      getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_entsize, getPtr);
89752b9b5   wdenk   Initial revision
276
277
278
279
280
281
282
283
284
285
286
287
288
289
      if (rxCount != sizeof sectHeader[0]) {
        fclose(file);
        fprintf (stderr, "*** illegal file format
  ");
        return;
      } /* if */
    } /* for */
  
    if ((hdr_name = strrchr(fileName, '/')) == NULL) {
      hdr_name = fileName;
    } else {
      ++hdr_name;
    }
    /* write start record */
fd66066ee   Mike Frysinger   img2srec: use sta...
290
    (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name));
89752b9b5   wdenk   Initial revision
291
292
293
294
295
296
297
298
    printf("%s\r
  ",srecLine);
  
    /* write data records */
    firstAddr = ~0;
    loadAddr  =  0;
    for (i = 0; i < elfHeader.e_shnum; i++) {
      if (    (sectHeader[i].sh_type == SHT_PROGBITS)
8bde7f776   wdenk   * Code cleanup:
299
300
  	 && (sectHeader[i].sh_size != 0)
  	 ) {
89752b9b5   wdenk   Initial revision
301
302
        loadSize = sectHeader[i].sh_size;
        if (sectHeader[i].sh_flags != 0) {
8bde7f776   wdenk   * Code cleanup:
303
304
  	loadAddr = sectHeader[i].sh_addr;
  	loadDiff = loadAddr - sectHeader[i].sh_offset;
89752b9b5   wdenk   Initial revision
305
306
        } /* if */
        else {
8bde7f776   wdenk   * Code cleanup:
307
  	loadAddr = sectHeader[i].sh_offset + loadDiff;
89752b9b5   wdenk   Initial revision
308
309
310
        } /* else */
  
        if (loadAddr < firstAddr)
8bde7f776   wdenk   * Code cleanup:
311
  	firstAddr = loadAddr;
89752b9b5   wdenk   Initial revision
312
313
314
315
316
  
        /* build s-records */
        loadSize = sectHeader[i].sh_size;
        fseek(file, sectHeader[i].sh_offset, SEEK_SET);
        while (loadSize) {
8bde7f776   wdenk   * Code cleanup:
317
318
319
320
321
322
323
324
325
326
327
328
  	rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file);
  	if (rxCount < 0) {
  	  fclose(file);
  	  fprintf (stderr, "*** illegal file format
  ");
  	return;
  	} /* if */
  	(void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount);
  	loadSize -= rxCount;
  	loadAddr += rxCount;
  	printf("%s\r
  ",srecLine);
89752b9b5   wdenk   Initial revision
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
        } /* while */
      } /* if */
    } /* for */
  
    /* add end record */
    (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0);
    printf("%s\r
  ",srecLine);
    fclose(file);
  } /* ConvertELF */
  
  
  /*************************************************************************
  |  MAIN
  |*************************************************************************/
  
  int main( int argc, char *argv[ ])
  {
fd66066ee   Mike Frysinger   img2srec: use sta...
347
    uint32_t offset;
89752b9b5   wdenk   Initial revision
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
  
    if (argc == 2) {
      ConvertELF(argv[1], 0);
    } /* if */
    else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) {
      ExtractNumber(&offset, argv[2]);
      ConvertELF(argv[3], offset);
    } /* if */
    else {
      fprintf (stderr, "Usage: img2srec [-o offset] <image>
  ");
    } /* if */
  
    return 0;
  } /* main */