xref: /openbmc/u-boot/tools/img2srec.c (revision 821560fd)
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"
56fd66066eSMike 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 
ExtractHex(uint32_t * value,char * getPtr)70fd66066eSMike Frysinger static char* ExtractHex (uint32_t* value,  char* getPtr)
7189752b9bSwdenk {
72fd66066eSMike Frysinger   uint32_t num;
73fd66066eSMike Frysinger   uint32_t digit;
74fd66066eSMike Frysinger   uint8_t  c;
7589752b9bSwdenk 
7689752b9bSwdenk   while (*getPtr == ' ') getPtr++;
7789752b9bSwdenk   num = 0;
7889752b9bSwdenk   for (;;) {
7989752b9bSwdenk     c = *getPtr;
80fd66066eSMike Frysinger     if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
81fd66066eSMike Frysinger     else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10);
82fd66066eSMike 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 
ExtractDecimal(uint32_t * value,char * getPtr)92fd66066eSMike Frysinger static char* ExtractDecimal (uint32_t* value,  char* getPtr)
9389752b9bSwdenk {
94fd66066eSMike Frysinger   uint32_t num;
95fd66066eSMike Frysinger   uint32_t digit;
96fd66066eSMike Frysinger   uint8_t  c;
9789752b9bSwdenk 
9889752b9bSwdenk   while (*getPtr == ' ') getPtr++;
9989752b9bSwdenk   num = 0;
10089752b9bSwdenk   for (;;) {
10189752b9bSwdenk     c = *getPtr;
102fd66066eSMike 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 
ExtractNumber(uint32_t * value,char * getPtr)113fd66066eSMike Frysinger static void ExtractNumber (uint32_t* value,  char* getPtr)
11489752b9bSwdenk {
115*51855e89SMasahiro Yamada   bool  neg = false;
11689752b9bSwdenk 
11789752b9bSwdenk   while (*getPtr == ' ') getPtr++;
11889752b9bSwdenk   if (*getPtr == '-') {
119fd66066eSMike 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 
ExtractWord(uint16_t * value,uint8_t * buffer)133fd66066eSMike Frysinger static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer)
13489752b9bSwdenk {
135fd66066eSMike Frysinger   uint16_t x;
136fd66066eSMike Frysinger   x = (uint16_t)*buffer++;
137fd66066eSMike Frysinger   x = (x<<8) + (uint16_t)*buffer++;
13889752b9bSwdenk   *value = x;
13989752b9bSwdenk   return buffer;
14089752b9bSwdenk } /* ExtractWord */
14189752b9bSwdenk 
14289752b9bSwdenk 
ExtractLong(uint32_t * value,uint8_t * buffer)143fd66066eSMike Frysinger static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer)
14489752b9bSwdenk {
145fd66066eSMike Frysinger   uint32_t x;
146fd66066eSMike Frysinger   x = (uint32_t)*buffer++;
147fd66066eSMike Frysinger   x = (x<<8) + (uint32_t)*buffer++;
148fd66066eSMike Frysinger   x = (x<<8) + (uint32_t)*buffer++;
149fd66066eSMike Frysinger   x = (x<<8) + (uint32_t)*buffer++;
15089752b9bSwdenk   *value = x;
15189752b9bSwdenk   return buffer;
15289752b9bSwdenk } /* ExtractLong */
15389752b9bSwdenk 
15489752b9bSwdenk 
ExtractBlock(uint16_t count,uint8_t * data,uint8_t * buffer)155fd66066eSMike 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 
WriteHex(char * pa,uint8_t value,uint16_t * pCheckSum)162fd66066eSMike Frysinger static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum)
16389752b9bSwdenk {
164fd66066eSMike 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 
BuildSRecord(char * pa,uint16_t sType,uint32_t addr,const uint8_t * data,int nCount)177fd66066eSMike Frysinger static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr,
178fd66066eSMike Frysinger 			  const uint8_t* data, int nCount)
17989752b9bSwdenk {
180fd66066eSMike Frysinger   uint16_t  addrLen;
181fd66066eSMike Frysinger   uint16_t  sRLen;
182fd66066eSMike Frysinger   uint16_t  checkSum;
183fd66066eSMike 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;
207fd66066eSMike Frysinger   pa = WriteHex(pa, (uint8_t)sRLen, &checkSum);
20889752b9bSwdenk 
20989752b9bSwdenk   /* Write address field */
21089752b9bSwdenk   for (i = 1; i <= addrLen; i++) {
211fd66066eSMike 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;
221fd66066eSMike Frysinger   pa = WriteHex(pa, (uint8_t)checkSum, &checkSum);
22289752b9bSwdenk   *pa++ = '\0';
22389752b9bSwdenk   return pa;
22489752b9bSwdenk }
22589752b9bSwdenk 
22689752b9bSwdenk 
ConvertELF(char * fileName,uint32_t loadOffset)227fd66066eSMike Frysinger static void ConvertELF(char* fileName, uint32_t loadOffset)
22889752b9bSwdenk {
22989752b9bSwdenk   FILE*         file;
23089752b9bSwdenk   int           i;
23189752b9bSwdenk   int           rxCount;
232fd66066eSMike Frysinger   uint8_t          rxBlock[1024];
233fd66066eSMike Frysinger   uint32_t         loadSize;
234fd66066eSMike Frysinger   uint32_t         firstAddr;
235fd66066eSMike Frysinger   uint32_t         loadAddr;
236fd66066eSMike Frysinger   uint32_t         loadDiff = 0;
23789752b9bSwdenk   Elf32_Ehdr    elfHeader;
23889752b9bSwdenk   Elf32_Shdr    sectHeader[32];
239fd66066eSMike 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);
255fd66066eSMike Frysinger   getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr);
256fd66066eSMike Frysinger   getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr);
257fd66066eSMike Frysinger   getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr);
258fd66066eSMike Frysinger   getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr);
259fd66066eSMike 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);
282fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_name, rxBlock);
283fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_type, getPtr);
284fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_flags, getPtr);
285fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addr, getPtr);
286fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_offset, getPtr);
287fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_size, getPtr);
288fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_link, getPtr);
289fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_info, getPtr);
290fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addralign, getPtr);
291fd66066eSMike Frysinger     getPtr = ExtractLong((uint32_t *)&sectHeader[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 */
305fd66066eSMike 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 
main(int argc,char * argv[])35689752b9bSwdenk int main( int argc, char *argv[ ])
35789752b9bSwdenk {
358fd66066eSMike 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