xref: /openbmc/u-boot/tools/img2srec.c (revision 37566090)
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 *)&sectHeader[i].sh_name, rxBlock);
32389752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_type, getPtr);
32489752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_flags, getPtr);
32589752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_addr, getPtr);
32689752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_offset, getPtr);
32789752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_size, getPtr);
32889752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_link, getPtr);
32989752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_info, getPtr);
33089752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[i].sh_addralign, getPtr);
33189752b9bSwdenk     getPtr = ExtractLong((DWORD *)&sectHeader[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