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 *)§Header[i].sh_name, rxBlock);
283fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_type, getPtr);
284fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_flags, getPtr);
285fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_addr, getPtr);
286fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_offset, getPtr);
287fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_size, getPtr);
288fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_link, getPtr);
289fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_info, getPtr);
290fd66066eSMike Frysinger getPtr = ExtractLong((uint32_t *)§Header[i].sh_addralign, getPtr);
291fd66066eSMike 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 */
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