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