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 70static 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 92static 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 113static 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 133static 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 143static 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 155static 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 162static 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 177static 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 227static 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 356int 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