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 55*37566090SMike Frysinger #include "os_support.h" 5689752b9bSwdenk #include <stddef.h> 5789752b9bSwdenk #include <stdio.h> 5889752b9bSwdenk #include <stdlib.h> 5989752b9bSwdenk #include <ctype.h> 6089752b9bSwdenk #include <string.h> 6189752b9bSwdenk #include <elf.h> 6289752b9bSwdenk #include <unistd.h> 6389752b9bSwdenk #include <errno.h> 6489752b9bSwdenk 6589752b9bSwdenk /************************************************************************* 6689752b9bSwdenk | DEFINES 6789752b9bSwdenk |*************************************************************************/ 6889752b9bSwdenk 6989752b9bSwdenk #define FALSE 0 7089752b9bSwdenk #define TRUE 1 7189752b9bSwdenk 7289752b9bSwdenk /************************************************************************* 7389752b9bSwdenk | MACROS 7489752b9bSwdenk |*************************************************************************/ 7589752b9bSwdenk 7689752b9bSwdenk /************************************************************************* 7789752b9bSwdenk | TYPEDEFS 7889752b9bSwdenk |*************************************************************************/ 7989752b9bSwdenk 8089752b9bSwdenk typedef uint8_t CHAR; 8189752b9bSwdenk typedef uint8_t BYTE; 8289752b9bSwdenk typedef uint16_t WORD; 8389752b9bSwdenk typedef uint32_t DWORD; 8489752b9bSwdenk typedef int BOOL; 8589752b9bSwdenk 8689752b9bSwdenk /************************************************************************* 8789752b9bSwdenk | LOCALS 8889752b9bSwdenk |*************************************************************************/ 8989752b9bSwdenk 9089752b9bSwdenk /************************************************************************* 9189752b9bSwdenk | PROTOTYPES 9289752b9bSwdenk |*************************************************************************/ 9389752b9bSwdenk 9489752b9bSwdenk static char *ExtractHex(DWORD *value, char *getPtr); 9589752b9bSwdenk static char *ExtractDecimal(DWORD *value, char *getPtr); 9689752b9bSwdenk static void ExtractNumber(DWORD *value, char *getPtr); 9789752b9bSwdenk static BYTE *ExtractWord(WORD *value, BYTE *buffer); 9889752b9bSwdenk static BYTE *ExtractLong(DWORD *value, BYTE *buffer); 9989752b9bSwdenk static BYTE *ExtractBlock(WORD count, BYTE *data, BYTE *buffer); 10089752b9bSwdenk static char *WriteHex(char *pa, BYTE value, WORD *pCheckSum); 10189752b9bSwdenk static char *BuildSRecord(char *pa, WORD sType, DWORD addr, 10289752b9bSwdenk const BYTE *data, int nCount); 10389752b9bSwdenk static void ConvertELF(char *fileName, DWORD loadOffset); 10489752b9bSwdenk int main(int argc, char *argv[]); 10589752b9bSwdenk 10689752b9bSwdenk /************************************************************************* 10789752b9bSwdenk | FUNCTIONS 10889752b9bSwdenk |*************************************************************************/ 10989752b9bSwdenk 11089752b9bSwdenk static char* ExtractHex (DWORD* value, char* getPtr) 11189752b9bSwdenk { 11289752b9bSwdenk DWORD num; 11389752b9bSwdenk DWORD digit; 11489752b9bSwdenk BYTE c; 11589752b9bSwdenk 11689752b9bSwdenk while (*getPtr == ' ') getPtr++; 11789752b9bSwdenk num = 0; 11889752b9bSwdenk for (;;) { 11989752b9bSwdenk c = *getPtr; 12089752b9bSwdenk if ((c >= '0') && (c <= '9')) digit = (DWORD)(c - '0'); 12189752b9bSwdenk else if ((c >= 'A') && (c <= 'F')) digit = (DWORD)(c - 'A' + 10); 12289752b9bSwdenk else if ((c >= 'a') && (c <= 'f')) digit = (DWORD)(c - 'a' + 10); 12389752b9bSwdenk else break; 12489752b9bSwdenk num <<= 4; 12589752b9bSwdenk num += digit; 12689752b9bSwdenk getPtr++; 12789752b9bSwdenk } /* for */ 12889752b9bSwdenk *value = num; 12989752b9bSwdenk return getPtr; 13089752b9bSwdenk } /* ExtractHex */ 13189752b9bSwdenk 13289752b9bSwdenk static char* ExtractDecimal (DWORD* value, char* getPtr) 13389752b9bSwdenk { 13489752b9bSwdenk DWORD num; 13589752b9bSwdenk DWORD digit; 13689752b9bSwdenk BYTE c; 13789752b9bSwdenk 13889752b9bSwdenk while (*getPtr == ' ') getPtr++; 13989752b9bSwdenk num = 0; 14089752b9bSwdenk for (;;) { 14189752b9bSwdenk c = *getPtr; 14289752b9bSwdenk if ((c >= '0') && (c <= '9')) digit = (DWORD)(c - '0'); 14389752b9bSwdenk else break; 14489752b9bSwdenk num *= 10; 14589752b9bSwdenk num += digit; 14689752b9bSwdenk getPtr++; 14789752b9bSwdenk } /* for */ 14889752b9bSwdenk *value = num; 14989752b9bSwdenk return getPtr; 15089752b9bSwdenk } /* ExtractDecimal */ 15189752b9bSwdenk 15289752b9bSwdenk 15389752b9bSwdenk static void ExtractNumber (DWORD* value, char* getPtr) 15489752b9bSwdenk { 15589752b9bSwdenk BOOL neg = FALSE;; 15689752b9bSwdenk 15789752b9bSwdenk while (*getPtr == ' ') getPtr++; 15889752b9bSwdenk if (*getPtr == '-') { 15989752b9bSwdenk neg = TRUE; 16089752b9bSwdenk getPtr++; 16189752b9bSwdenk } /* if */ 16289752b9bSwdenk if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) { 16389752b9bSwdenk getPtr +=2; 16489752b9bSwdenk (void)ExtractHex(value, getPtr); 16589752b9bSwdenk } /* if */ 16689752b9bSwdenk else { 16789752b9bSwdenk (void)ExtractDecimal(value, getPtr); 16889752b9bSwdenk } /* else */ 16989752b9bSwdenk if (neg) *value = -(*value); 17089752b9bSwdenk } /* ExtractNumber */ 17189752b9bSwdenk 17289752b9bSwdenk 17389752b9bSwdenk static BYTE* ExtractWord(WORD* value, BYTE* buffer) 17489752b9bSwdenk { 17589752b9bSwdenk WORD x; 17689752b9bSwdenk x = (WORD)*buffer++; 17789752b9bSwdenk x = (x<<8) + (WORD)*buffer++; 17889752b9bSwdenk *value = x; 17989752b9bSwdenk return buffer; 18089752b9bSwdenk } /* ExtractWord */ 18189752b9bSwdenk 18289752b9bSwdenk 18389752b9bSwdenk static BYTE* ExtractLong(DWORD* value, BYTE* buffer) 18489752b9bSwdenk { 18589752b9bSwdenk DWORD x; 18689752b9bSwdenk x = (DWORD)*buffer++; 18789752b9bSwdenk x = (x<<8) + (DWORD)*buffer++; 18889752b9bSwdenk x = (x<<8) + (DWORD)*buffer++; 18989752b9bSwdenk x = (x<<8) + (DWORD)*buffer++; 19089752b9bSwdenk *value = x; 19189752b9bSwdenk return buffer; 19289752b9bSwdenk } /* ExtractLong */ 19389752b9bSwdenk 19489752b9bSwdenk 19589752b9bSwdenk static BYTE* ExtractBlock(WORD count, BYTE* data, BYTE* buffer) 19689752b9bSwdenk { 19789752b9bSwdenk while (count--) *data++ = *buffer++; 19889752b9bSwdenk return buffer; 19989752b9bSwdenk } /* ExtractBlock */ 20089752b9bSwdenk 20189752b9bSwdenk 20289752b9bSwdenk static char* WriteHex(char* pa, BYTE value, WORD* pCheckSum) 20389752b9bSwdenk { 20489752b9bSwdenk WORD temp; 20589752b9bSwdenk 20689752b9bSwdenk static char ByteToHex[] = "0123456789ABCDEF"; 20789752b9bSwdenk 20889752b9bSwdenk *pCheckSum += value; 20989752b9bSwdenk temp = value / 16; 21089752b9bSwdenk *pa++ = ByteToHex[temp]; 21189752b9bSwdenk temp = value % 16; 21289752b9bSwdenk *pa++ = ByteToHex[temp]; 21389752b9bSwdenk return pa; 21489752b9bSwdenk } 21589752b9bSwdenk 21689752b9bSwdenk 21789752b9bSwdenk static char* BuildSRecord(char* pa, WORD sType, DWORD addr, 21889752b9bSwdenk const BYTE* data, int nCount) 21989752b9bSwdenk { 22089752b9bSwdenk WORD addrLen; 22189752b9bSwdenk WORD sRLen; 22289752b9bSwdenk WORD checkSum; 22389752b9bSwdenk WORD i; 22489752b9bSwdenk 22589752b9bSwdenk switch (sType) { 22689752b9bSwdenk case 0: 22789752b9bSwdenk case 1: 22889752b9bSwdenk case 9: 22989752b9bSwdenk addrLen = 2; 23089752b9bSwdenk break; 23189752b9bSwdenk case 2: 23289752b9bSwdenk case 8: 23389752b9bSwdenk addrLen = 3; 23489752b9bSwdenk break; 23589752b9bSwdenk case 3: 23689752b9bSwdenk case 7: 23789752b9bSwdenk addrLen = 4; 23889752b9bSwdenk break; 23989752b9bSwdenk default: 24089752b9bSwdenk return pa; 24189752b9bSwdenk } /* switch */ 24289752b9bSwdenk 24389752b9bSwdenk *pa++ = 'S'; 24489752b9bSwdenk *pa++ = (char)(sType + '0'); 24589752b9bSwdenk sRLen = addrLen + nCount + 1; 24689752b9bSwdenk checkSum = 0; 24789752b9bSwdenk pa = WriteHex(pa, (BYTE)sRLen, &checkSum); 24889752b9bSwdenk 24989752b9bSwdenk /* Write address field */ 25089752b9bSwdenk for (i = 1; i <= addrLen; i++) { 25189752b9bSwdenk pa = WriteHex(pa, (BYTE)(addr >> (8 * (addrLen - i))), &checkSum); 25289752b9bSwdenk } /* for */ 25389752b9bSwdenk 25489752b9bSwdenk /* Write code/data fields */ 25589752b9bSwdenk for (i = 0; i < nCount; i++) { 25689752b9bSwdenk pa = WriteHex(pa, *data++, &checkSum); 25789752b9bSwdenk } /* for */ 25889752b9bSwdenk 25989752b9bSwdenk /* Write checksum field */ 26089752b9bSwdenk checkSum = ~checkSum; 26189752b9bSwdenk pa = WriteHex(pa, (BYTE)checkSum, &checkSum); 26289752b9bSwdenk *pa++ = '\0'; 26389752b9bSwdenk return pa; 26489752b9bSwdenk } 26589752b9bSwdenk 26689752b9bSwdenk 26789752b9bSwdenk static void ConvertELF(char* fileName, DWORD loadOffset) 26889752b9bSwdenk { 26989752b9bSwdenk FILE* file; 27089752b9bSwdenk int i; 27189752b9bSwdenk int rxCount; 27289752b9bSwdenk BYTE rxBlock[1024]; 27389752b9bSwdenk DWORD loadSize; 27489752b9bSwdenk DWORD firstAddr; 27589752b9bSwdenk DWORD loadAddr; 27689752b9bSwdenk DWORD loadDiff = 0; 27789752b9bSwdenk Elf32_Ehdr elfHeader; 27889752b9bSwdenk Elf32_Shdr sectHeader[32]; 27989752b9bSwdenk BYTE* getPtr; 28089752b9bSwdenk char srecLine[128]; 28189752b9bSwdenk char *hdr_name; 28289752b9bSwdenk 28389752b9bSwdenk 28489752b9bSwdenk /* open file */ 28589752b9bSwdenk if ((file = fopen(fileName,"rb")) == NULL) { 28689752b9bSwdenk fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno)); 28789752b9bSwdenk return; 28889752b9bSwdenk } /* if */ 28989752b9bSwdenk 29089752b9bSwdenk /* read ELF header */ 29189752b9bSwdenk rxCount = fread(rxBlock, 1, sizeof elfHeader, file); 29289752b9bSwdenk getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock); 29389752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_type, getPtr); 29489752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_machine, getPtr); 29589752b9bSwdenk getPtr = ExtractLong((DWORD *)&elfHeader.e_version, getPtr); 29689752b9bSwdenk getPtr = ExtractLong((DWORD *)&elfHeader.e_entry, getPtr); 29789752b9bSwdenk getPtr = ExtractLong((DWORD *)&elfHeader.e_phoff, getPtr); 29889752b9bSwdenk getPtr = ExtractLong((DWORD *)&elfHeader.e_shoff, getPtr); 29989752b9bSwdenk getPtr = ExtractLong((DWORD *)&elfHeader.e_flags, getPtr); 30089752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr); 30189752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr); 30289752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_phnum, getPtr); 30389752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr); 30489752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_shnum, getPtr); 30589752b9bSwdenk getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr); 30689752b9bSwdenk if ( (rxCount != sizeof elfHeader) 30789752b9bSwdenk || (elfHeader.e_ident[0] != ELFMAG0) 30889752b9bSwdenk || (elfHeader.e_ident[1] != ELFMAG1) 30989752b9bSwdenk || (elfHeader.e_ident[2] != ELFMAG2) 31089752b9bSwdenk || (elfHeader.e_ident[3] != ELFMAG3) 31189752b9bSwdenk || (elfHeader.e_type != ET_EXEC) 31289752b9bSwdenk ) { 31389752b9bSwdenk fclose(file); 31489752b9bSwdenk fprintf (stderr, "*** illegal file format\n"); 31589752b9bSwdenk return; 31689752b9bSwdenk } /* if */ 31789752b9bSwdenk 31889752b9bSwdenk /* read all section headers */ 31989752b9bSwdenk fseek(file, elfHeader.e_shoff, SEEK_SET); 32089752b9bSwdenk for (i = 0; i < elfHeader.e_shnum; i++) { 32189752b9bSwdenk rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file); 32289752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_name, rxBlock); 32389752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_type, getPtr); 32489752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_flags, getPtr); 32589752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_addr, getPtr); 32689752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_offset, getPtr); 32789752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_size, getPtr); 32889752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_link, getPtr); 32989752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_info, getPtr); 33089752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_addralign, getPtr); 33189752b9bSwdenk getPtr = ExtractLong((DWORD *)§Header[i].sh_entsize, getPtr); 33289752b9bSwdenk if (rxCount != sizeof sectHeader[0]) { 33389752b9bSwdenk fclose(file); 33489752b9bSwdenk fprintf (stderr, "*** illegal file format\n"); 33589752b9bSwdenk return; 33689752b9bSwdenk } /* if */ 33789752b9bSwdenk } /* for */ 33889752b9bSwdenk 33989752b9bSwdenk if ((hdr_name = strrchr(fileName, '/')) == NULL) { 34089752b9bSwdenk hdr_name = fileName; 34189752b9bSwdenk } else { 34289752b9bSwdenk ++hdr_name; 34389752b9bSwdenk } 34489752b9bSwdenk /* write start record */ 34589752b9bSwdenk (void)BuildSRecord(srecLine, 0, 0, (BYTE *)hdr_name, strlen(hdr_name)); 34689752b9bSwdenk printf("%s\r\n",srecLine); 34789752b9bSwdenk 34889752b9bSwdenk /* write data records */ 34989752b9bSwdenk firstAddr = ~0; 35089752b9bSwdenk loadAddr = 0; 35189752b9bSwdenk for (i = 0; i < elfHeader.e_shnum; i++) { 35289752b9bSwdenk if ( (sectHeader[i].sh_type == SHT_PROGBITS) 35389752b9bSwdenk && (sectHeader[i].sh_size != 0) 35489752b9bSwdenk ) { 35589752b9bSwdenk loadSize = sectHeader[i].sh_size; 35689752b9bSwdenk if (sectHeader[i].sh_flags != 0) { 35789752b9bSwdenk loadAddr = sectHeader[i].sh_addr; 35889752b9bSwdenk loadDiff = loadAddr - sectHeader[i].sh_offset; 35989752b9bSwdenk } /* if */ 36089752b9bSwdenk else { 36189752b9bSwdenk loadAddr = sectHeader[i].sh_offset + loadDiff; 36289752b9bSwdenk } /* else */ 36389752b9bSwdenk 36489752b9bSwdenk if (loadAddr < firstAddr) 36589752b9bSwdenk firstAddr = loadAddr; 36689752b9bSwdenk 36789752b9bSwdenk /* build s-records */ 36889752b9bSwdenk loadSize = sectHeader[i].sh_size; 36989752b9bSwdenk fseek(file, sectHeader[i].sh_offset, SEEK_SET); 37089752b9bSwdenk while (loadSize) { 37189752b9bSwdenk rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file); 37289752b9bSwdenk if (rxCount < 0) { 37389752b9bSwdenk fclose(file); 37489752b9bSwdenk fprintf (stderr, "*** illegal file format\n"); 37589752b9bSwdenk return; 37689752b9bSwdenk } /* if */ 37789752b9bSwdenk (void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount); 37889752b9bSwdenk loadSize -= rxCount; 37989752b9bSwdenk loadAddr += rxCount; 38089752b9bSwdenk printf("%s\r\n",srecLine); 38189752b9bSwdenk } /* while */ 38289752b9bSwdenk } /* if */ 38389752b9bSwdenk } /* for */ 38489752b9bSwdenk 38589752b9bSwdenk /* add end record */ 38689752b9bSwdenk (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0); 38789752b9bSwdenk printf("%s\r\n",srecLine); 38889752b9bSwdenk fclose(file); 38989752b9bSwdenk } /* ConvertELF */ 39089752b9bSwdenk 39189752b9bSwdenk 39289752b9bSwdenk /************************************************************************* 39389752b9bSwdenk | MAIN 39489752b9bSwdenk |*************************************************************************/ 39589752b9bSwdenk 39689752b9bSwdenk int main( int argc, char *argv[ ]) 39789752b9bSwdenk { 39889752b9bSwdenk DWORD offset; 39989752b9bSwdenk 40089752b9bSwdenk if (argc == 2) { 40189752b9bSwdenk ConvertELF(argv[1], 0); 40289752b9bSwdenk } /* if */ 40389752b9bSwdenk else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) { 40489752b9bSwdenk ExtractNumber(&offset, argv[2]); 40589752b9bSwdenk ConvertELF(argv[3], offset); 40689752b9bSwdenk } /* if */ 40789752b9bSwdenk else { 40889752b9bSwdenk fprintf (stderr, "Usage: img2srec [-o offset] <image>\n"); 40989752b9bSwdenk } /* if */ 41089752b9bSwdenk 41189752b9bSwdenk return 0; 41289752b9bSwdenk } /* main */ 413