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