]>
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 | ||
37566090 | 55 | #include "os_support.h" |
fd66066e | 56 | #include <stdbool.h> |
89752b9b WD |
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 | ||
89752b9b WD |
66 | /************************************************************************* |
67 | | FUNCTIONS | |
68 | |*************************************************************************/ | |
69 | ||
fd66066e | 70 | static char* ExtractHex (uint32_t* value, char* getPtr) |
89752b9b | 71 | { |
fd66066e MF |
72 | uint32_t num; |
73 | uint32_t digit; | |
74 | uint8_t c; | |
89752b9b WD |
75 | |
76 | while (*getPtr == ' ') getPtr++; | |
77 | num = 0; | |
78 | for (;;) { | |
79 | c = *getPtr; | |
fd66066e MF |
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); | |
89752b9b WD |
83 | else break; |
84 | num <<= 4; | |
85 | num += digit; | |
86 | getPtr++; | |
87 | } /* for */ | |
88 | *value = num; | |
89 | return getPtr; | |
90 | } /* ExtractHex */ | |
91 | ||
fd66066e | 92 | static char* ExtractDecimal (uint32_t* value, char* getPtr) |
89752b9b | 93 | { |
fd66066e MF |
94 | uint32_t num; |
95 | uint32_t digit; | |
96 | uint8_t c; | |
89752b9b WD |
97 | |
98 | while (*getPtr == ' ') getPtr++; | |
99 | num = 0; | |
100 | for (;;) { | |
101 | c = *getPtr; | |
fd66066e | 102 | if ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0'); |
89752b9b WD |
103 | else break; |
104 | num *= 10; | |
105 | num += digit; | |
106 | getPtr++; | |
107 | } /* for */ | |
108 | *value = num; | |
109 | return getPtr; | |
110 | } /* ExtractDecimal */ | |
111 | ||
112 | ||
fd66066e | 113 | static void ExtractNumber (uint32_t* value, char* getPtr) |
89752b9b | 114 | { |
51855e89 | 115 | bool neg = false; |
89752b9b WD |
116 | |
117 | while (*getPtr == ' ') getPtr++; | |
118 | if (*getPtr == '-') { | |
fd66066e | 119 | neg = true; |
89752b9b WD |
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 | ||
fd66066e | 133 | static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer) |
89752b9b | 134 | { |
fd66066e MF |
135 | uint16_t x; |
136 | x = (uint16_t)*buffer++; | |
137 | x = (x<<8) + (uint16_t)*buffer++; | |
89752b9b WD |
138 | *value = x; |
139 | return buffer; | |
140 | } /* ExtractWord */ | |
141 | ||
142 | ||
fd66066e | 143 | static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer) |
89752b9b | 144 | { |
fd66066e MF |
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++; | |
89752b9b WD |
150 | *value = x; |
151 | return buffer; | |
152 | } /* ExtractLong */ | |
153 | ||
154 | ||
fd66066e | 155 | static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer) |
89752b9b WD |
156 | { |
157 | while (count--) *data++ = *buffer++; | |
158 | return buffer; | |
159 | } /* ExtractBlock */ | |
160 | ||
161 | ||
fd66066e | 162 | static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum) |
89752b9b | 163 | { |
fd66066e | 164 | uint16_t temp; |
89752b9b WD |
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 | ||
fd66066e MF |
177 | static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr, |
178 | const uint8_t* data, int nCount) | |
89752b9b | 179 | { |
fd66066e MF |
180 | uint16_t addrLen; |
181 | uint16_t sRLen; | |
182 | uint16_t checkSum; | |
183 | uint16_t i; | |
89752b9b WD |
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; | |
fd66066e | 207 | pa = WriteHex(pa, (uint8_t)sRLen, &checkSum); |
89752b9b WD |
208 | |
209 | /* Write address field */ | |
210 | for (i = 1; i <= addrLen; i++) { | |
fd66066e | 211 | pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum); |
89752b9b WD |
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; | |
fd66066e | 221 | pa = WriteHex(pa, (uint8_t)checkSum, &checkSum); |
89752b9b WD |
222 | *pa++ = '\0'; |
223 | return pa; | |
224 | } | |
225 | ||
226 | ||
fd66066e | 227 | static void ConvertELF(char* fileName, uint32_t loadOffset) |
89752b9b WD |
228 | { |
229 | FILE* file; | |
230 | int i; | |
231 | int rxCount; | |
fd66066e MF |
232 | uint8_t rxBlock[1024]; |
233 | uint32_t loadSize; | |
234 | uint32_t firstAddr; | |
235 | uint32_t loadAddr; | |
236 | uint32_t loadDiff = 0; | |
89752b9b WD |
237 | Elf32_Ehdr elfHeader; |
238 | Elf32_Shdr sectHeader[32]; | |
fd66066e | 239 | uint8_t* getPtr; |
89752b9b WD |
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); | |
fd66066e MF |
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); | |
89752b9b WD |
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); | |
fd66066e MF |
282 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_name, rxBlock); |
283 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_type, getPtr); | |
284 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_flags, getPtr); | |
285 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_addr, getPtr); | |
286 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_offset, getPtr); | |
287 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_size, getPtr); | |
288 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_link, getPtr); | |
289 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_info, getPtr); | |
290 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_addralign, getPtr); | |
291 | getPtr = ExtractLong((uint32_t *)§Header[i].sh_entsize, getPtr); | |
89752b9b WD |
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 */ | |
fd66066e | 305 | (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name)); |
89752b9b WD |
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) | |
8bde7f77 WD |
313 | && (sectHeader[i].sh_size != 0) |
314 | ) { | |
89752b9b WD |
315 | loadSize = sectHeader[i].sh_size; |
316 | if (sectHeader[i].sh_flags != 0) { | |
8bde7f77 WD |
317 | loadAddr = sectHeader[i].sh_addr; |
318 | loadDiff = loadAddr - sectHeader[i].sh_offset; | |
89752b9b WD |
319 | } /* if */ |
320 | else { | |
8bde7f77 | 321 | loadAddr = sectHeader[i].sh_offset + loadDiff; |
89752b9b WD |
322 | } /* else */ |
323 | ||
324 | if (loadAddr < firstAddr) | |
8bde7f77 | 325 | firstAddr = loadAddr; |
89752b9b WD |
326 | |
327 | /* build s-records */ | |
328 | loadSize = sectHeader[i].sh_size; | |
329 | fseek(file, sectHeader[i].sh_offset, SEEK_SET); | |
330 | while (loadSize) { | |
8bde7f77 WD |
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); | |
89752b9b WD |
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 | { | |
fd66066e | 358 | uint32_t offset; |
89752b9b WD |
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 */ |