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) 354 && (sectHeader[i].sh_size != 0) 355 ) { 356 loadSize = sectHeader[i].sh_size; 357 if (sectHeader[i].sh_flags != 0) { 358 loadAddr = sectHeader[i].sh_addr; 359 loadDiff = loadAddr - sectHeader[i].sh_offset; 360 } /* if */ 361 else { 362 loadAddr = sectHeader[i].sh_offset + loadDiff; 363 } /* else */ 364 365 if (loadAddr < firstAddr) 366 firstAddr = loadAddr; 367 368 /* build s-records */ 369 loadSize = sectHeader[i].sh_size; 370 fseek(file, sectHeader[i].sh_offset, SEEK_SET); 371 while (loadSize) { 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); 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 */ 414