]>
Commit | Line | Data |
---|---|---|
89752b9b WD |
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 <stddef.h> | |
56 | #include <stdio.h> | |
57 | #include <stdlib.h> | |
58 | #include <ctype.h> | |
59 | #include <string.h> | |
60 | #include <elf.h> | |
61 | #include <unistd.h> | |
62 | #include <errno.h> | |
63 | ||
64 | extern int errno; | |
65 | ||
66 | /************************************************************************* | |
67 | | DEFINES | |
68 | |*************************************************************************/ | |
69 | ||
70 | #define FALSE 0 | |
71 | #define TRUE 1 | |
72 | ||
73 | /************************************************************************* | |
74 | | MACROS | |
75 | |*************************************************************************/ | |
76 | ||
77 | /************************************************************************* | |
78 | | TYPEDEFS | |
79 | |*************************************************************************/ | |
80 | ||
81 | typedef uint8_t CHAR; | |
82 | typedef uint8_t BYTE; | |
83 | typedef uint16_t WORD; | |
84 | typedef uint32_t DWORD; | |
85 | typedef int BOOL; | |
86 | ||
87 | /************************************************************************* | |
88 | | LOCALS | |
89 | |*************************************************************************/ | |
90 | ||
91 | /************************************************************************* | |
92 | | PROTOTYPES | |
93 | |*************************************************************************/ | |
94 | ||
95 | static char *ExtractHex(DWORD *value, char *getPtr); | |
96 | static char *ExtractDecimal(DWORD *value, char *getPtr); | |
97 | static void ExtractNumber(DWORD *value, char *getPtr); | |
98 | static BYTE *ExtractWord(WORD *value, BYTE *buffer); | |
99 | static BYTE *ExtractLong(DWORD *value, BYTE *buffer); | |
100 | static BYTE *ExtractBlock(WORD count, BYTE *data, BYTE *buffer); | |
101 | static char *WriteHex(char *pa, BYTE value, WORD *pCheckSum); | |
102 | static char *BuildSRecord(char *pa, WORD sType, DWORD addr, | |
103 | const BYTE *data, int nCount); | |
104 | static void ConvertELF(char *fileName, DWORD loadOffset); | |
105 | int main(int argc, char *argv[]); | |
106 | ||
107 | /************************************************************************* | |
108 | | FUNCTIONS | |
109 | |*************************************************************************/ | |
110 | ||
111 | static char* ExtractHex (DWORD* value, char* getPtr) | |
112 | { | |
113 | DWORD num; | |
114 | DWORD digit; | |
115 | BYTE c; | |
116 | ||
117 | while (*getPtr == ' ') getPtr++; | |
118 | num = 0; | |
119 | for (;;) { | |
120 | c = *getPtr; | |
121 | if ((c >= '0') && (c <= '9')) digit = (DWORD)(c - '0'); | |
122 | else if ((c >= 'A') && (c <= 'F')) digit = (DWORD)(c - 'A' + 10); | |
123 | else if ((c >= 'a') && (c <= 'f')) digit = (DWORD)(c - 'a' + 10); | |
124 | else break; | |
125 | num <<= 4; | |
126 | num += digit; | |
127 | getPtr++; | |
128 | } /* for */ | |
129 | *value = num; | |
130 | return getPtr; | |
131 | } /* ExtractHex */ | |
132 | ||
133 | static char* ExtractDecimal (DWORD* value, char* getPtr) | |
134 | { | |
135 | DWORD num; | |
136 | DWORD digit; | |
137 | BYTE c; | |
138 | ||
139 | while (*getPtr == ' ') getPtr++; | |
140 | num = 0; | |
141 | for (;;) { | |
142 | c = *getPtr; | |
143 | if ((c >= '0') && (c <= '9')) digit = (DWORD)(c - '0'); | |
144 | else break; | |
145 | num *= 10; | |
146 | num += digit; | |
147 | getPtr++; | |
148 | } /* for */ | |
149 | *value = num; | |
150 | return getPtr; | |
151 | } /* ExtractDecimal */ | |
152 | ||
153 | ||
154 | static void ExtractNumber (DWORD* value, char* getPtr) | |
155 | { | |
156 | BOOL neg = FALSE;; | |
157 | ||
158 | while (*getPtr == ' ') getPtr++; | |
159 | if (*getPtr == '-') { | |
160 | neg = TRUE; | |
161 | getPtr++; | |
162 | } /* if */ | |
163 | if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) { | |
164 | getPtr +=2; | |
165 | (void)ExtractHex(value, getPtr); | |
166 | } /* if */ | |
167 | else { | |
168 | (void)ExtractDecimal(value, getPtr); | |
169 | } /* else */ | |
170 | if (neg) *value = -(*value); | |
171 | } /* ExtractNumber */ | |
172 | ||
173 | ||
174 | static BYTE* ExtractWord(WORD* value, BYTE* buffer) | |
175 | { | |
176 | WORD x; | |
177 | x = (WORD)*buffer++; | |
178 | x = (x<<8) + (WORD)*buffer++; | |
179 | *value = x; | |
180 | return buffer; | |
181 | } /* ExtractWord */ | |
182 | ||
183 | ||
184 | static BYTE* ExtractLong(DWORD* value, BYTE* buffer) | |
185 | { | |
186 | DWORD x; | |
187 | x = (DWORD)*buffer++; | |
188 | x = (x<<8) + (DWORD)*buffer++; | |
189 | x = (x<<8) + (DWORD)*buffer++; | |
190 | x = (x<<8) + (DWORD)*buffer++; | |
191 | *value = x; | |
192 | return buffer; | |
193 | } /* ExtractLong */ | |
194 | ||
195 | ||
196 | static BYTE* ExtractBlock(WORD count, BYTE* data, BYTE* buffer) | |
197 | { | |
198 | while (count--) *data++ = *buffer++; | |
199 | return buffer; | |
200 | } /* ExtractBlock */ | |
201 | ||
202 | ||
203 | static char* WriteHex(char* pa, BYTE value, WORD* pCheckSum) | |
204 | { | |
205 | WORD temp; | |
206 | ||
207 | static char ByteToHex[] = "0123456789ABCDEF"; | |
208 | ||
209 | *pCheckSum += value; | |
210 | temp = value / 16; | |
211 | *pa++ = ByteToHex[temp]; | |
212 | temp = value % 16; | |
213 | *pa++ = ByteToHex[temp]; | |
214 | return pa; | |
215 | } | |
216 | ||
217 | ||
218 | static char* BuildSRecord(char* pa, WORD sType, DWORD addr, | |
219 | const BYTE* data, int nCount) | |
220 | { | |
221 | WORD addrLen; | |
222 | WORD sRLen; | |
223 | WORD checkSum; | |
224 | WORD i; | |
225 | ||
226 | switch (sType) { | |
227 | case 0: | |
228 | case 1: | |
229 | case 9: | |
230 | addrLen = 2; | |
231 | break; | |
232 | case 2: | |
233 | case 8: | |
234 | addrLen = 3; | |
235 | break; | |
236 | case 3: | |
237 | case 7: | |
238 | addrLen = 4; | |
239 | break; | |
240 | default: | |
241 | return pa; | |
242 | } /* switch */ | |
243 | ||
244 | *pa++ = 'S'; | |
245 | *pa++ = (char)(sType + '0'); | |
246 | sRLen = addrLen + nCount + 1; | |
247 | checkSum = 0; | |
248 | pa = WriteHex(pa, (BYTE)sRLen, &checkSum); | |
249 | ||
250 | /* Write address field */ | |
251 | for (i = 1; i <= addrLen; i++) { | |
252 | pa = WriteHex(pa, (BYTE)(addr >> (8 * (addrLen - i))), &checkSum); | |
253 | } /* for */ | |
254 | ||
255 | /* Write code/data fields */ | |
256 | for (i = 0; i < nCount; i++) { | |
257 | pa = WriteHex(pa, *data++, &checkSum); | |
258 | } /* for */ | |
259 | ||
260 | /* Write checksum field */ | |
261 | checkSum = ~checkSum; | |
262 | pa = WriteHex(pa, (BYTE)checkSum, &checkSum); | |
263 | *pa++ = '\0'; | |
264 | return pa; | |
265 | } | |
266 | ||
267 | ||
268 | static void ConvertELF(char* fileName, DWORD loadOffset) | |
269 | { | |
270 | FILE* file; | |
271 | int i; | |
272 | int rxCount; | |
273 | BYTE rxBlock[1024]; | |
274 | DWORD loadSize; | |
275 | DWORD firstAddr; | |
276 | DWORD loadAddr; | |
277 | DWORD loadDiff = 0; | |
278 | Elf32_Ehdr elfHeader; | |
279 | Elf32_Shdr sectHeader[32]; | |
280 | BYTE* getPtr; | |
281 | char srecLine[128]; | |
282 | char *hdr_name; | |
283 | ||
284 | ||
285 | /* open file */ | |
286 | if ((file = fopen(fileName,"rb")) == NULL) { | |
287 | fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno)); | |
288 | return; | |
289 | } /* if */ | |
290 | ||
291 | /* read ELF header */ | |
292 | rxCount = fread(rxBlock, 1, sizeof elfHeader, file); | |
293 | getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock); | |
294 | getPtr = ExtractWord(&elfHeader.e_type, getPtr); | |
295 | getPtr = ExtractWord(&elfHeader.e_machine, getPtr); | |
296 | getPtr = ExtractLong((DWORD *)&elfHeader.e_version, getPtr); | |
297 | getPtr = ExtractLong((DWORD *)&elfHeader.e_entry, getPtr); | |
298 | getPtr = ExtractLong((DWORD *)&elfHeader.e_phoff, getPtr); | |
299 | getPtr = ExtractLong((DWORD *)&elfHeader.e_shoff, getPtr); | |
300 | getPtr = ExtractLong((DWORD *)&elfHeader.e_flags, getPtr); | |
301 | getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr); | |
302 | getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr); | |
303 | getPtr = ExtractWord(&elfHeader.e_phnum, getPtr); | |
304 | getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr); | |
305 | getPtr = ExtractWord(&elfHeader.e_shnum, getPtr); | |
306 | getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr); | |
307 | if ( (rxCount != sizeof elfHeader) | |
308 | || (elfHeader.e_ident[0] != ELFMAG0) | |
309 | || (elfHeader.e_ident[1] != ELFMAG1) | |
310 | || (elfHeader.e_ident[2] != ELFMAG2) | |
311 | || (elfHeader.e_ident[3] != ELFMAG3) | |
312 | || (elfHeader.e_type != ET_EXEC) | |
313 | ) { | |
314 | fclose(file); | |
315 | fprintf (stderr, "*** illegal file format\n"); | |
316 | return; | |
317 | } /* if */ | |
318 | ||
319 | /* read all section headers */ | |
320 | fseek(file, elfHeader.e_shoff, SEEK_SET); | |
321 | for (i = 0; i < elfHeader.e_shnum; i++) { | |
322 | rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file); | |
323 | getPtr = ExtractLong((DWORD *)§Header[i].sh_name, rxBlock); | |
324 | getPtr = ExtractLong((DWORD *)§Header[i].sh_type, getPtr); | |
325 | getPtr = ExtractLong((DWORD *)§Header[i].sh_flags, getPtr); | |
326 | getPtr = ExtractLong((DWORD *)§Header[i].sh_addr, getPtr); | |
327 | getPtr = ExtractLong((DWORD *)§Header[i].sh_offset, getPtr); | |
328 | getPtr = ExtractLong((DWORD *)§Header[i].sh_size, getPtr); | |
329 | getPtr = ExtractLong((DWORD *)§Header[i].sh_link, getPtr); | |
330 | getPtr = ExtractLong((DWORD *)§Header[i].sh_info, getPtr); | |
331 | getPtr = ExtractLong((DWORD *)§Header[i].sh_addralign, getPtr); | |
332 | getPtr = ExtractLong((DWORD *)§Header[i].sh_entsize, getPtr); | |
333 | if (rxCount != sizeof sectHeader[0]) { | |
334 | fclose(file); | |
335 | fprintf (stderr, "*** illegal file format\n"); | |
336 | return; | |
337 | } /* if */ | |
338 | } /* for */ | |
339 | ||
340 | if ((hdr_name = strrchr(fileName, '/')) == NULL) { | |
341 | hdr_name = fileName; | |
342 | } else { | |
343 | ++hdr_name; | |
344 | } | |
345 | /* write start record */ | |
346 | (void)BuildSRecord(srecLine, 0, 0, (BYTE *)hdr_name, strlen(hdr_name)); | |
347 | printf("%s\r\n",srecLine); | |
348 | ||
349 | /* write data records */ | |
350 | firstAddr = ~0; | |
351 | loadAddr = 0; | |
352 | for (i = 0; i < elfHeader.e_shnum; i++) { | |
353 | if ( (sectHeader[i].sh_type == SHT_PROGBITS) | |
8bde7f77 WD |
354 | && (sectHeader[i].sh_size != 0) |
355 | ) { | |
89752b9b WD |
356 | loadSize = sectHeader[i].sh_size; |
357 | if (sectHeader[i].sh_flags != 0) { | |
8bde7f77 WD |
358 | loadAddr = sectHeader[i].sh_addr; |
359 | loadDiff = loadAddr - sectHeader[i].sh_offset; | |
89752b9b WD |
360 | } /* if */ |
361 | else { | |
8bde7f77 | 362 | loadAddr = sectHeader[i].sh_offset + loadDiff; |
89752b9b WD |
363 | } /* else */ |
364 | ||
365 | if (loadAddr < firstAddr) | |
8bde7f77 | 366 | firstAddr = loadAddr; |
89752b9b WD |
367 | |
368 | /* build s-records */ | |
369 | loadSize = sectHeader[i].sh_size; | |
370 | fseek(file, sectHeader[i].sh_offset, SEEK_SET); | |
371 | while (loadSize) { | |
8bde7f77 WD |
372 | rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file); |
373 | if (rxCount < 0) { | |
374 | fclose(file); | |
375 | fprintf (stderr, "*** illegal file format\n"); | |
376 | return; | |
377 | } /* if */ | |
378 | (void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount); | |
379 | loadSize -= rxCount; | |
380 | loadAddr += rxCount; | |
381 | printf("%s\r\n",srecLine); | |
89752b9b WD |
382 | } /* while */ |
383 | } /* if */ | |
384 | } /* for */ | |
385 | ||
386 | /* add end record */ | |
387 | (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0); | |
388 | printf("%s\r\n",srecLine); | |
389 | fclose(file); | |
390 | } /* ConvertELF */ | |
391 | ||
392 | ||
393 | /************************************************************************* | |
394 | | MAIN | |
395 | |*************************************************************************/ | |
396 | ||
397 | int main( int argc, char *argv[ ]) | |
398 | { | |
399 | DWORD offset; | |
400 | ||
401 | if (argc == 2) { | |
402 | ConvertELF(argv[1], 0); | |
403 | } /* if */ | |
404 | else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) { | |
405 | ExtractNumber(&offset, argv[2]); | |
406 | ConvertELF(argv[3], offset); | |
407 | } /* if */ | |
408 | else { | |
409 | fprintf (stderr, "Usage: img2srec [-o offset] <image>\n"); | |
410 | } /* if */ | |
411 | ||
412 | return 0; | |
413 | } /* main */ |