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 
ExtractHex(uint32_t * value,char * getPtr)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 
ExtractDecimal(uint32_t * value,char * getPtr)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 
ExtractNumber(uint32_t * value,char * getPtr)112 static void ExtractNumber (uint32_t* value,  char* getPtr)
113 {
114   bool  neg = false;
115 
116   while (*getPtr == ' ') getPtr++;
117   if (*getPtr == '-') {
118     neg = true;
119     getPtr++;
120   } /* if */
121   if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) {
122     getPtr +=2;
123     (void)ExtractHex(value, getPtr);
124   } /* if */
125   else {
126     (void)ExtractDecimal(value, getPtr);
127   } /* else */
128   if (neg) *value = -(*value);
129 } /* ExtractNumber */
130 
ExtractWord(uint16_t * value,uint8_t * buffer)131 static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer)
132 {
133   uint16_t x;
134   x = (uint16_t)*buffer++;
135   x = (x<<8) + (uint16_t)*buffer++;
136   *value = x;
137   return buffer;
138 } /* ExtractWord */
139 
ExtractLong(uint32_t * value,uint8_t * buffer)140 static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer)
141 {
142   uint32_t x;
143   x = (uint32_t)*buffer++;
144   x = (x<<8) + (uint32_t)*buffer++;
145   x = (x<<8) + (uint32_t)*buffer++;
146   x = (x<<8) + (uint32_t)*buffer++;
147   *value = x;
148   return buffer;
149 } /* ExtractLong */
150 
ExtractBlock(uint16_t count,uint8_t * data,uint8_t * buffer)151 static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer)
152 {
153   while (count--) *data++ = *buffer++;
154   return buffer;
155 } /* ExtractBlock */
156 
WriteHex(char * pa,uint8_t value,uint16_t * pCheckSum)157 static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum)
158 {
159   uint16_t  temp;
160 
161   static  char ByteToHex[] = "0123456789ABCDEF";
162 
163   *pCheckSum += value;
164   temp  = value / 16;
165   *pa++ = ByteToHex[temp];
166   temp  = value % 16;
167   *pa++ = ByteToHex[temp];
168   return pa;
169 }
170 
BuildSRecord(char * pa,uint16_t sType,uint32_t addr,const uint8_t * data,int nCount)171 static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr,
172 			  const uint8_t* data, int nCount)
173 {
174   uint16_t  addrLen;
175   uint16_t  sRLen;
176   uint16_t  checkSum;
177   uint16_t  i;
178 
179   switch (sType) {
180   case 0:
181   case 1:
182   case 9:
183     addrLen = 2;
184     break;
185   case 2:
186   case 8:
187     addrLen = 3;
188     break;
189   case 3:
190   case 7:
191     addrLen = 4;
192     break;
193   default:
194     return pa;
195   } /* switch */
196 
197   *pa++ = 'S';
198   *pa++ = (char)(sType + '0');
199   sRLen = addrLen + nCount + 1;
200   checkSum = 0;
201   pa = WriteHex(pa, (uint8_t)sRLen, &checkSum);
202 
203   /* Write address field */
204   for (i = 1; i <= addrLen; i++) {
205     pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum);
206   } /* for */
207 
208   /* Write code/data fields */
209   for (i = 0; i < nCount; i++) {
210     pa = WriteHex(pa, *data++, &checkSum);
211   } /* for */
212 
213   /* Write checksum field */
214   checkSum = ~checkSum;
215   pa = WriteHex(pa, (uint8_t)checkSum, &checkSum);
216   *pa++ = '\0';
217   return pa;
218 }
219 
ConvertELF(char * fileName,uint32_t loadOffset)220 static void ConvertELF(char* fileName, uint32_t loadOffset)
221 {
222   FILE*         file;
223   int           i;
224   int           rxCount;
225   uint8_t          rxBlock[1024];
226   uint32_t         loadSize;
227   uint32_t         firstAddr;
228   uint32_t         loadAddr;
229   uint32_t         loadDiff = 0;
230   Elf32_Ehdr    elfHeader;
231   Elf32_Shdr    sectHeader[32];
232   uint8_t*         getPtr;
233   char          srecLine[128];
234   char		*hdr_name;
235 
236   /* open file */
237   if ((file = fopen(fileName,"rb")) == NULL) {
238     fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno));
239     return;
240   } /* if */
241 
242   /* read ELF header */
243   rxCount = fread(rxBlock, 1, sizeof elfHeader, file);
244   getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock);
245   getPtr = ExtractWord(&elfHeader.e_type, getPtr);
246   getPtr = ExtractWord(&elfHeader.e_machine, getPtr);
247   getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr);
248   getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr);
249   getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr);
250   getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr);
251   getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr);
252   getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr);
253   getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr);
254   getPtr = ExtractWord(&elfHeader.e_phnum, getPtr);
255   getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr);
256   getPtr = ExtractWord(&elfHeader.e_shnum, getPtr);
257   getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr);
258   if (    (rxCount              != sizeof elfHeader)
259        || (elfHeader.e_ident[0] != ELFMAG0)
260        || (elfHeader.e_ident[1] != ELFMAG1)
261        || (elfHeader.e_ident[2] != ELFMAG2)
262        || (elfHeader.e_ident[3] != ELFMAG3)
263        || (elfHeader.e_type     != ET_EXEC)
264      ) {
265     fclose(file);
266     fprintf (stderr, "*** illegal file format\n");
267     return;
268   } /* if */
269 
270   /* read all section headers */
271   fseek(file, elfHeader.e_shoff, SEEK_SET);
272   for (i = 0; i < elfHeader.e_shnum; i++) {
273     rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file);
274     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_name, rxBlock);
275     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_type, getPtr);
276     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_flags, getPtr);
277     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addr, getPtr);
278     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_offset, getPtr);
279     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_size, getPtr);
280     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_link, getPtr);
281     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_info, getPtr);
282     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addralign, getPtr);
283     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_entsize, getPtr);
284     if (rxCount != sizeof sectHeader[0]) {
285       fclose(file);
286       fprintf (stderr, "*** illegal file format\n");
287       return;
288     } /* if */
289   } /* for */
290 
291   if ((hdr_name = strrchr(fileName, '/')) == NULL) {
292     hdr_name = fileName;
293   } else {
294     ++hdr_name;
295   }
296   /* write start record */
297   (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name));
298   printf("%s\r\n",srecLine);
299 
300   /* write data records */
301   firstAddr = ~0;
302   loadAddr  =  0;
303   for (i = 0; i < elfHeader.e_shnum; i++) {
304     if (    (sectHeader[i].sh_type == SHT_PROGBITS)
305 	 && (sectHeader[i].sh_size != 0)
306 	 ) {
307       loadSize = sectHeader[i].sh_size;
308       if (sectHeader[i].sh_flags != 0) {
309 	loadAddr = sectHeader[i].sh_addr;
310 	loadDiff = loadAddr - sectHeader[i].sh_offset;
311       } /* if */
312       else {
313 	loadAddr = sectHeader[i].sh_offset + loadDiff;
314       } /* else */
315 
316       if (loadAddr < firstAddr)
317 	firstAddr = loadAddr;
318 
319       /* build s-records */
320       loadSize = sectHeader[i].sh_size;
321       fseek(file, sectHeader[i].sh_offset, SEEK_SET);
322       while (loadSize) {
323 	rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file);
324 	if (rxCount < 0) {
325 	  fclose(file);
326 	  fprintf (stderr, "*** illegal file format\n");
327 	return;
328 	} /* if */
329 	(void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount);
330 	loadSize -= rxCount;
331 	loadAddr += rxCount;
332 	printf("%s\r\n",srecLine);
333       } /* while */
334     } /* if */
335   } /* for */
336 
337   /* add end record */
338   (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0);
339   printf("%s\r\n",srecLine);
340   fclose(file);
341 } /* ConvertELF */
342 
343 /*************************************************************************
344 |  MAIN
345 |*************************************************************************/
346 
main(int argc,char * argv[])347 int main( int argc, char *argv[ ])
348 {
349   uint32_t offset;
350 
351   if (argc == 2) {
352     ConvertELF(argv[1], 0);
353   } /* if */
354   else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) {
355     ExtractNumber(&offset, argv[2]);
356     ConvertELF(argv[3], offset);
357   } /* if */
358   else {
359     fprintf (stderr, "Usage: img2srec [-o offset] <image>\n");
360   } /* if */
361 
362   return 0;
363 } /* main */
364