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 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 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 112 113 static void ExtractNumber (uint32_t* value, char* getPtr) 114 { 115 bool neg = false; 116 117 while (*getPtr == ' ') getPtr++; 118 if (*getPtr == '-') { 119 neg = true; 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 133 static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer) 134 { 135 uint16_t x; 136 x = (uint16_t)*buffer++; 137 x = (x<<8) + (uint16_t)*buffer++; 138 *value = x; 139 return buffer; 140 } /* ExtractWord */ 141 142 143 static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer) 144 { 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++; 150 *value = x; 151 return buffer; 152 } /* ExtractLong */ 153 154 155 static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer) 156 { 157 while (count--) *data++ = *buffer++; 158 return buffer; 159 } /* ExtractBlock */ 160 161 162 static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum) 163 { 164 uint16_t temp; 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 177 static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr, 178 const uint8_t* data, int nCount) 179 { 180 uint16_t addrLen; 181 uint16_t sRLen; 182 uint16_t checkSum; 183 uint16_t i; 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; 207 pa = WriteHex(pa, (uint8_t)sRLen, &checkSum); 208 209 /* Write address field */ 210 for (i = 1; i <= addrLen; i++) { 211 pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum); 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; 221 pa = WriteHex(pa, (uint8_t)checkSum, &checkSum); 222 *pa++ = '\0'; 223 return pa; 224 } 225 226 227 static void ConvertELF(char* fileName, uint32_t loadOffset) 228 { 229 FILE* file; 230 int i; 231 int rxCount; 232 uint8_t rxBlock[1024]; 233 uint32_t loadSize; 234 uint32_t firstAddr; 235 uint32_t loadAddr; 236 uint32_t loadDiff = 0; 237 Elf32_Ehdr elfHeader; 238 Elf32_Shdr sectHeader[32]; 239 uint8_t* getPtr; 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); 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); 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); 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); 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 */ 305 (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name)); 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) 313 && (sectHeader[i].sh_size != 0) 314 ) { 315 loadSize = sectHeader[i].sh_size; 316 if (sectHeader[i].sh_flags != 0) { 317 loadAddr = sectHeader[i].sh_addr; 318 loadDiff = loadAddr - sectHeader[i].sh_offset; 319 } /* if */ 320 else { 321 loadAddr = sectHeader[i].sh_offset + loadDiff; 322 } /* else */ 323 324 if (loadAddr < firstAddr) 325 firstAddr = loadAddr; 326 327 /* build s-records */ 328 loadSize = sectHeader[i].sh_size; 329 fseek(file, sectHeader[i].sh_offset, SEEK_SET); 330 while (loadSize) { 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); 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 { 358 uint32_t offset; 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 */ 373