189752b9bSwdenk /************************************************************************* 289752b9bSwdenk | COPYRIGHT (c) 2000 BY ABATRON AG 389752b9bSwdenk |************************************************************************* 489752b9bSwdenk | 589752b9bSwdenk | PROJECT NAME: Linux Image to S-record Conversion Utility 689752b9bSwdenk | FILENAME : img2srec.c 789752b9bSwdenk | 889752b9bSwdenk | COMPILER : GCC 989752b9bSwdenk | 1089752b9bSwdenk | TARGET OS : LINUX / UNIX 1189752b9bSwdenk | TARGET HW : - 1289752b9bSwdenk | 1389752b9bSwdenk | PROGRAMMER : Abatron / RD 1489752b9bSwdenk | CREATION : 07.07.00 1589752b9bSwdenk | 1689752b9bSwdenk |************************************************************************* 1789752b9bSwdenk | 1889752b9bSwdenk | DESCRIPTION : 1989752b9bSwdenk | 2089752b9bSwdenk | Utility to convert a Linux Boot Image to S-record: 2189752b9bSwdenk | ================================================== 2289752b9bSwdenk | 2389752b9bSwdenk | This command line utility can be used to convert a Linux boot image 2489752b9bSwdenk | (zimage.initrd) to S-Record format used for flash programming. 2589752b9bSwdenk | This conversion takes care of the special sections "IMAGE" and INITRD". 2689752b9bSwdenk | 2789752b9bSwdenk | img2srec [-o offset] image > image.srec 2889752b9bSwdenk | 2989752b9bSwdenk | 3089752b9bSwdenk | Build the utility: 3189752b9bSwdenk | ================== 3289752b9bSwdenk | 3389752b9bSwdenk | To build the utility use GCC as follows: 3489752b9bSwdenk | 3589752b9bSwdenk | gcc img2srec.c -o img2srec 3689752b9bSwdenk | 3789752b9bSwdenk | 3889752b9bSwdenk |************************************************************************* 3989752b9bSwdenk | 4089752b9bSwdenk | 4189752b9bSwdenk | UPDATES : 4289752b9bSwdenk | 4389752b9bSwdenk | DATE NAME CHANGES 4489752b9bSwdenk | ----------------------------------------------------------- 4589752b9bSwdenk | Latest update 4689752b9bSwdenk | 4789752b9bSwdenk | 07.07.00 aba Initial release 4889752b9bSwdenk | 4989752b9bSwdenk |*************************************************************************/ 5089752b9bSwdenk 5189752b9bSwdenk /************************************************************************* 5289752b9bSwdenk | INCLUDES 5389752b9bSwdenk |*************************************************************************/ 5489752b9bSwdenk 5537566090SMike Frysinger #include "os_support.h" 56*fd66066eSMike Frysinger #include <stdbool.h> 5789752b9bSwdenk #include <stddef.h> 5889752b9bSwdenk #include <stdio.h> 5989752b9bSwdenk #include <stdlib.h> 6089752b9bSwdenk #include <ctype.h> 6189752b9bSwdenk #include <string.h> 6289752b9bSwdenk #include <elf.h> 6389752b9bSwdenk #include <unistd.h> 6489752b9bSwdenk #include <errno.h> 6589752b9bSwdenk 6689752b9bSwdenk /************************************************************************* 6789752b9bSwdenk | FUNCTIONS 6889752b9bSwdenk |*************************************************************************/ 6989752b9bSwdenk 70*fd66066eSMike Frysinger static char* ExtractHex (uint32_t* value, char* getPtr) 7189752b9bSwdenk { 72*fd66066eSMike Frysinger uint32_t num; 73*fd66066eSMike Frysinger uint32_t digit; 74*fd66066eSMike Frysinger uint8_t c; 7589752b9bSwdenk 7689752b9bSwdenk while (*getPtr == ' ') getPtr++; 7789752b9bSwdenk num = 0; 7889752b9bSwdenk for (;;) { 7989752b9bSwdenk c = *getPtr; 80*fd66066eSMike Frysinger if ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0'); 81*fd66066eSMike Frysinger else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10); 82*fd66066eSMike Frysinger else if ((c >= 'a') && (c <= 'f')) digit = (uint32_t)(c - 'a' + 10); 8389752b9bSwdenk else break; 8489752b9bSwdenk num <<= 4; 8589752b9bSwdenk num += digit; 8689752b9bSwdenk getPtr++; 8789752b9bSwdenk } /* for */ 8889752b9bSwdenk *value = num; 8989752b9bSwdenk return getPtr; 9089752b9bSwdenk } /* ExtractHex */ 9189752b9bSwdenk 92*fd66066eSMike Frysinger static char* ExtractDecimal (uint32_t* value, char* getPtr) 9389752b9bSwdenk { 94*fd66066eSMike Frysinger uint32_t num; 95*fd66066eSMike Frysinger uint32_t digit; 96*fd66066eSMike Frysinger uint8_t c; 9789752b9bSwdenk 9889752b9bSwdenk while (*getPtr == ' ') getPtr++; 9989752b9bSwdenk num = 0; 10089752b9bSwdenk for (;;) { 10189752b9bSwdenk c = *getPtr; 102*fd66066eSMike Frysinger if ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0'); 10389752b9bSwdenk else break; 10489752b9bSwdenk num *= 10; 10589752b9bSwdenk num += digit; 10689752b9bSwdenk getPtr++; 10789752b9bSwdenk } /* for */ 10889752b9bSwdenk *value = num; 10989752b9bSwdenk return getPtr; 11089752b9bSwdenk } /* ExtractDecimal */ 11189752b9bSwdenk 11289752b9bSwdenk 113*fd66066eSMike Frysinger static void ExtractNumber (uint32_t* value, char* getPtr) 11489752b9bSwdenk { 115*fd66066eSMike Frysinger bool neg = false;; 11689752b9bSwdenk 11789752b9bSwdenk while (*getPtr == ' ') getPtr++; 11889752b9bSwdenk if (*getPtr == '-') { 119*fd66066eSMike Frysinger neg = true; 12089752b9bSwdenk getPtr++; 12189752b9bSwdenk } /* if */ 12289752b9bSwdenk if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) { 12389752b9bSwdenk getPtr +=2; 12489752b9bSwdenk (void)ExtractHex(value, getPtr); 12589752b9bSwdenk } /* if */ 12689752b9bSwdenk else { 12789752b9bSwdenk (void)ExtractDecimal(value, getPtr); 12889752b9bSwdenk } /* else */ 12989752b9bSwdenk if (neg) *value = -(*value); 13089752b9bSwdenk } /* ExtractNumber */ 13189752b9bSwdenk 13289752b9bSwdenk 133*fd66066eSMike Frysinger static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer) 13489752b9bSwdenk { 135*fd66066eSMike Frysinger uint16_t x; 136*fd66066eSMike Frysinger x = (uint16_t)*buffer++; 137*fd66066eSMike Frysinger x = (x<<8) + (uint16_t)*buffer++; 13889752b9bSwdenk *value = x; 13989752b9bSwdenk return buffer; 14089752b9bSwdenk } /* ExtractWord */ 14189752b9bSwdenk 14289752b9bSwdenk 143*fd66066eSMike Frysinger static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer) 14489752b9bSwdenk { 145*fd66066eSMike Frysinger uint32_t x; 146*fd66066eSMike Frysinger x = (uint32_t)*buffer++; 147*fd66066eSMike Frysinger x = (x<<8) + (uint32_t)*buffer++; 148*fd66066eSMike Frysinger x = (x<<8) + (uint32_t)*buffer++; 149*fd66066eSMike Frysinger x = (x<<8) + (uint32_t)*buffer++; 15089752b9bSwdenk *value = x; 15189752b9bSwdenk return buffer; 15289752b9bSwdenk } /* ExtractLong */ 15389752b9bSwdenk 15489752b9bSwdenk 155*fd66066eSMike Frysinger static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer) 15689752b9bSwdenk { 15789752b9bSwdenk while (count--) *data++ = *buffer++; 15889752b9bSwdenk return buffer; 15989752b9bSwdenk } /* ExtractBlock */ 16089752b9bSwdenk 16189752b9bSwdenk 162*fd66066eSMike Frysinger static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum) 16389752b9bSwdenk { 164*fd66066eSMike Frysinger uint16_t temp; 16589752b9bSwdenk 16689752b9bSwdenk static char ByteToHex[] = "0123456789ABCDEF"; 16789752b9bSwdenk 16889752b9bSwdenk *pCheckSum += value; 16989752b9bSwdenk temp = value / 16; 17089752b9bSwdenk *pa++ = ByteToHex[temp]; 17189752b9bSwdenk temp = value % 16; 17289752b9bSwdenk *pa++ = ByteToHex[temp]; 17389752b9bSwdenk return pa; 17489752b9bSwdenk } 17589752b9bSwdenk 17689752b9bSwdenk 177*fd66066eSMike Frysinger static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr, 178*fd66066eSMike Frysinger const uint8_t* data, int nCount) 17989752b9bSwdenk { 180*fd66066eSMike Frysinger uint16_t addrLen; 181*fd66066eSMike Frysinger uint16_t sRLen; 182*fd66066eSMike Frysinger uint16_t checkSum; 183*fd66066eSMike Frysinger uint16_t i; 18489752b9bSwdenk 18589752b9bSwdenk switch (sType) { 18689752b9bSwdenk case 0: 18789752b9bSwdenk case 1: 18889752b9bSwdenk case 9: 18989752b9bSwdenk addrLen = 2; 19089752b9bSwdenk break; 19189752b9bSwdenk case 2: 19289752b9bSwdenk case 8: 19389752b9bSwdenk addrLen = 3; 19489752b9bSwdenk break; 19589752b9bSwdenk case 3: 19689752b9bSwdenk case 7: 19789752b9bSwdenk addrLen = 4; 19889752b9bSwdenk break; 19989752b9bSwdenk default: 20089752b9bSwdenk return pa; 20189752b9bSwdenk } /* switch */ 20289752b9bSwdenk 20389752b9bSwdenk *pa++ = 'S'; 20489752b9bSwdenk *pa++ = (char)(sType + '0'); 20589752b9bSwdenk sRLen = addrLen + nCount + 1; 20689752b9bSwdenk checkSum = 0; 207*fd66066eSMike Frysinger pa = WriteHex(pa, (uint8_t)sRLen, &checkSum); 20889752b9bSwdenk 20989752b9bSwdenk /* Write address field */ 21089752b9bSwdenk for (i = 1; i <= addrLen; i++) { 211*fd66066eSMike Frysinger pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum); 21289752b9bSwdenk } /* for */ 21389752b9bSwdenk 21489752b9bSwdenk /* Write code/data fields */ 21589752b9bSwdenk for (i = 0; i < nCount; i++) { 21689752b9bSwdenk pa = WriteHex(pa, *data++, &checkSum); 21789752b9bSwdenk } /* for */ 21889752b9bSwdenk 21989752b9bSwdenk /* Write checksum field */ 22089752b9bSwdenk checkSum = ~checkSum; 221*fd66066eSMike Frysinger pa = WriteHex(pa, (uint8_t)checkSum, &checkSum); 22289752b9bSwdenk *pa++ = '\0'; 22389752b9bSwdenk return pa; 22489752b9bSwdenk } 22589752b9bSwdenk 22689752b9bSwdenk 227*fd66066eSMike Frysinger static void ConvertELF(char* fileName, uint32_t loadOffset) 22889752b9bSwdenk { 22989752b9bSwdenk FILE* file; 23089752b9bSwdenk int i; 23189752b9bSwdenk int rxCount; 232*fd66066eSMike Frysinger uint8_t rxBlock[1024]; 233*fd66066eSMike Frysinger uint32_t loadSize; 234*fd66066eSMike Frysinger uint32_t firstAddr; 235*fd66066eSMike Frysinger uint32_t loadAddr; 236*fd66066eSMike Frysinger uint32_t loadDiff = 0; 23789752b9bSwdenk Elf32_Ehdr elfHeader; 23889752b9bSwdenk Elf32_Shdr sectHeader[32]; 239*fd66066eSMike Frysinger uint8_t* getPtr; 24089752b9bSwdenk char srecLine[128]; 24189752b9bSwdenk char *hdr_name; 24289752b9bSwdenk 24389752b9bSwdenk 24489752b9bSwdenk /* open file */ 24589752b9bSwdenk if ((file = fopen(fileName,"rb")) == NULL) { 24689752b9bSwdenk fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno)); 24789752b9bSwdenk return; 24889752b9bSwdenk } /* if */ 24989752b9bSwdenk 25089752b9bSwdenk /* read ELF header */ 25189752b9bSwdenk rxCount = fread(rxBlock, 1, sizeof elfHeader, file); 25289752b9bSwdenk getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock); 25389752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_type, getPtr); 25489752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_machine, getPtr); 255*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr); 256*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr); 257*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr); 258*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr); 259*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr); 26089752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr); 26189752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr); 26289752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_phnum, getPtr); 26389752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr); 26489752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_shnum, getPtr); 26589752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr); 26689752b9bSwdenk if ( (rxCount != sizeof elfHeader) 26789752b9bSwdenk || (elfHeader.e_ident[0] != ELFMAG0) 26889752b9bSwdenk || (elfHeader.e_ident[1] != ELFMAG1) 26989752b9bSwdenk || (elfHeader.e_ident[2] != ELFMAG2) 27089752b9bSwdenk || (elfHeader.e_ident[3] != ELFMAG3) 27189752b9bSwdenk || (elfHeader.e_type != ET_EXEC) 27289752b9bSwdenk ) { 27389752b9bSwdenk fclose(file); 27489752b9bSwdenk fprintf (stderr, "*** illegal file format\n"); 27589752b9bSwdenk return; 27689752b9bSwdenk } /* if */ 27789752b9bSwdenk 27889752b9bSwdenk /* read all section headers */ 27989752b9bSwdenk fseek(file, elfHeader.e_shoff, SEEK_SET); 28089752b9bSwdenk for (i = 0; i < elfHeader.e_shnum; i++) { 28189752b9bSwdenk rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file); 282*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_name, rxBlock); 283*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_type, getPtr); 284*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_flags, getPtr); 285*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_addr, getPtr); 286*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_offset, getPtr); 287*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_size, getPtr); 288*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_link, getPtr); 289*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_info, getPtr); 290*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_addralign, getPtr); 291*fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_entsize, getPtr); 29289752b9bSwdenk if (rxCount != sizeof sectHeader[0]) { 29389752b9bSwdenk fclose(file); 29489752b9bSwdenk fprintf (stderr, "*** illegal file format\n"); 29589752b9bSwdenk return; 29689752b9bSwdenk } /* if */ 29789752b9bSwdenk } /* for */ 29889752b9bSwdenk 29989752b9bSwdenk if ((hdr_name = strrchr(fileName, '/')) == NULL) { 30089752b9bSwdenk hdr_name = fileName; 30189752b9bSwdenk } else { 30289752b9bSwdenk ++hdr_name; 30389752b9bSwdenk } 30489752b9bSwdenk /* write start record */ 305*fd66066eSMike Frysinger (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name)); 30689752b9bSwdenk printf("%s\r\n",srecLine); 30789752b9bSwdenk 30889752b9bSwdenk /* write data records */ 30989752b9bSwdenk firstAddr = ~0; 31089752b9bSwdenk loadAddr = 0; 31189752b9bSwdenk for (i = 0; i < elfHeader.e_shnum; i++) { 31289752b9bSwdenk if ( (sectHeader[i].sh_type == SHT_PROGBITS) 31389752b9bSwdenk && (sectHeader[i].sh_size != 0) 31489752b9bSwdenk ) { 31589752b9bSwdenk loadSize = sectHeader[i].sh_size; 31689752b9bSwdenk if (sectHeader[i].sh_flags != 0) { 31789752b9bSwdenk loadAddr = sectHeader[i].sh_addr; 31889752b9bSwdenk loadDiff = loadAddr - sectHeader[i].sh_offset; 31989752b9bSwdenk } /* if */ 32089752b9bSwdenk else { 32189752b9bSwdenk loadAddr = sectHeader[i].sh_offset + loadDiff; 32289752b9bSwdenk } /* else */ 32389752b9bSwdenk 32489752b9bSwdenk if (loadAddr < firstAddr) 32589752b9bSwdenk firstAddr = loadAddr; 32689752b9bSwdenk 32789752b9bSwdenk /* build s-records */ 32889752b9bSwdenk loadSize = sectHeader[i].sh_size; 32989752b9bSwdenk fseek(file, sectHeader[i].sh_offset, SEEK_SET); 33089752b9bSwdenk while (loadSize) { 33189752b9bSwdenk rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file); 33289752b9bSwdenk if (rxCount < 0) { 33389752b9bSwdenk fclose(file); 33489752b9bSwdenk fprintf (stderr, "*** illegal file format\n"); 33589752b9bSwdenk return; 33689752b9bSwdenk } /* if */ 33789752b9bSwdenk (void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount); 33889752b9bSwdenk loadSize -= rxCount; 33989752b9bSwdenk loadAddr += rxCount; 34089752b9bSwdenk printf("%s\r\n",srecLine); 34189752b9bSwdenk } /* while */ 34289752b9bSwdenk } /* if */ 34389752b9bSwdenk } /* for */ 34489752b9bSwdenk 34589752b9bSwdenk /* add end record */ 34689752b9bSwdenk (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0); 34789752b9bSwdenk printf("%s\r\n",srecLine); 34889752b9bSwdenk fclose(file); 34989752b9bSwdenk } /* ConvertELF */ 35089752b9bSwdenk 35189752b9bSwdenk 35289752b9bSwdenk /************************************************************************* 35389752b9bSwdenk | MAIN 35489752b9bSwdenk |*************************************************************************/ 35589752b9bSwdenk 35689752b9bSwdenk int main( int argc, char *argv[ ]) 35789752b9bSwdenk { 358*fd66066eSMike Frysinger uint32_t offset; 35989752b9bSwdenk 36089752b9bSwdenk if (argc == 2) { 36189752b9bSwdenk ConvertELF(argv[1], 0); 36289752b9bSwdenk } /* if */ 36389752b9bSwdenk else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) { 36489752b9bSwdenk ExtractNumber(&offset, argv[2]); 36589752b9bSwdenk ConvertELF(argv[3], offset); 36689752b9bSwdenk } /* if */ 36789752b9bSwdenk else { 36889752b9bSwdenk fprintf (stderr, "Usage: img2srec [-o offset] <image>\n"); 36989752b9bSwdenk } /* if */ 37089752b9bSwdenk 37189752b9bSwdenk return 0; 37289752b9bSwdenk } /* main */ 373