Skip to content
Snippets Groups Projects
img2srec.c 9.73 KiB
Newer Older
  • Learn to ignore specific revisions
  • Wolfgang Denk's avatar
    Wolfgang Denk committed
    /*************************************************************************
    |  COPYRIGHT (c) 2000 BY ABATRON AG
    |*************************************************************************
    |
    |  PROJECT NAME: Linux Image to S-record Conversion Utility
    |  FILENAME    : img2srec.c
    |
    |  COMPILER    : GCC
    |
    |  TARGET OS   : LINUX / UNIX
    |  TARGET HW   : -
    |
    |  PROGRAMMER  : Abatron / RD
    |  CREATION    : 07.07.00
    |
    |*************************************************************************
    |
    |  DESCRIPTION :
    |
    |  Utility to convert a Linux Boot Image to S-record:
    |  ==================================================
    |
    |  This command line utility can be used to convert a Linux boot image
    |  (zimage.initrd) to S-Record format used for flash programming.
    |  This conversion takes care of the special sections "IMAGE" and INITRD".
    |
    |  img2srec [-o offset] image > image.srec
    |
    |
    |  Build the utility:
    |  ==================
    |
    |  To build the utility use GCC as follows:
    |
    |  gcc img2srec.c -o img2srec
    |
    |
    |*************************************************************************
    |
    |
    |  UPDATES     :
    |
    |  DATE      NAME  CHANGES
    |  -----------------------------------------------------------
    |  Latest update
    |
    |  07.07.00  aba   Initial release
    |
    |*************************************************************************/
    
    /*************************************************************************
    |  INCLUDES
    |*************************************************************************/
    
    
    #include "os_support.h"
    
    #include <stdbool.h>
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    #include <stddef.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    #include <elf.h>
    #include <unistd.h>
    #include <errno.h>
    
    /*************************************************************************
    |  FUNCTIONS
    |*************************************************************************/
    
    
    static char* ExtractHex (uint32_t* value,  char* getPtr)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
      uint32_t num;
      uint32_t digit;
      uint8_t  c;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
      while (*getPtr == ' ') getPtr++;
      num = 0;
      for (;;) {
        c = *getPtr;
    
        if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
        else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10);
        else if ((c >= 'a') && (c <= 'f')) digit = (uint32_t)(c - 'a' + 10);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
        else break;
        num <<= 4;
        num += digit;
        getPtr++;
      } /* for */
      *value = num;
      return getPtr;
    } /* ExtractHex */
    
    
    static char* ExtractDecimal (uint32_t* value,  char* getPtr)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
      uint32_t num;
      uint32_t digit;
      uint8_t  c;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
      while (*getPtr == ' ') getPtr++;
      num = 0;
      for (;;) {
        c = *getPtr;
    
        if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
        else break;
        num *= 10;
        num += digit;
        getPtr++;
      } /* for */
      *value = num;
      return getPtr;
    } /* ExtractDecimal */
    
    
    
    static void ExtractNumber (uint32_t* value,  char* getPtr)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
      bool  neg = false;;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
      while (*getPtr == ' ') getPtr++;
      if (*getPtr == '-') {
    
        neg = true;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
        getPtr++;
      } /* if */
      if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) {
        getPtr +=2;
        (void)ExtractHex(value, getPtr);
      } /* if */
      else {
        (void)ExtractDecimal(value, getPtr);
      } /* else */
      if (neg) *value = -(*value);
    } /* ExtractNumber */
    
    
    
    static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
      uint16_t x;
      x = (uint16_t)*buffer++;
      x = (x<<8) + (uint16_t)*buffer++;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      *value = x;
      return buffer;
    } /* ExtractWord */
    
    
    
    static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
      uint32_t x;
      x = (uint32_t)*buffer++;
      x = (x<<8) + (uint32_t)*buffer++;
      x = (x<<8) + (uint32_t)*buffer++;
      x = (x<<8) + (uint32_t)*buffer++;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      *value = x;
      return buffer;
    } /* ExtractLong */
    
    
    
    static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
      while (count--) *data++ = *buffer++;
      return buffer;
    } /* ExtractBlock */
    
    
    
    static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
      uint16_t  temp;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
      static  char ByteToHex[] = "0123456789ABCDEF";
    
      *pCheckSum += value;
      temp  = value / 16;
      *pa++ = ByteToHex[temp];
      temp  = value % 16;
      *pa++ = ByteToHex[temp];
      return pa;
    }
    
    
    
    static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr,
    			  const uint8_t* data, int nCount)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
    
      uint16_t  addrLen;
      uint16_t  sRLen;
      uint16_t  checkSum;
      uint16_t  i;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
      switch (sType) {
      case 0:
      case 1:
      case 9:
        addrLen = 2;
        break;
      case 2:
      case 8:
        addrLen = 3;
        break;
      case 3:
      case 7:
        addrLen = 4;
        break;
      default:
        return pa;
      } /* switch */
    
      *pa++ = 'S';
      *pa++ = (char)(sType + '0');
      sRLen = addrLen + nCount + 1;
      checkSum = 0;
    
      pa = WriteHex(pa, (uint8_t)sRLen, &checkSum);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
      /* Write address field */
      for (i = 1; i <= addrLen; i++) {
    
        pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      } /* for */
    
      /* Write code/data fields */
      for (i = 0; i < nCount; i++) {
        pa = WriteHex(pa, *data++, &checkSum);
      } /* for */
    
      /* Write checksum field */
      checkSum = ~checkSum;
    
      pa = WriteHex(pa, (uint8_t)checkSum, &checkSum);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      *pa++ = '\0';
      return pa;
    }
    
    
    
    static void ConvertELF(char* fileName, uint32_t loadOffset)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    {
      FILE*         file;
      int           i;
      int           rxCount;
    
      uint8_t          rxBlock[1024];
      uint32_t         loadSize;
      uint32_t         firstAddr;
      uint32_t         loadAddr;
      uint32_t         loadDiff = 0;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      Elf32_Ehdr    elfHeader;
      Elf32_Shdr    sectHeader[32];
    
      uint8_t*         getPtr;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      char          srecLine[128];
      char		*hdr_name;
    
    
      /* open file */
      if ((file = fopen(fileName,"rb")) == NULL) {
        fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno));
        return;
      } /* if */
    
      /* read ELF header */
      rxCount = fread(rxBlock, 1, sizeof elfHeader, file);
      getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock);
      getPtr = ExtractWord(&elfHeader.e_type, getPtr);
      getPtr = ExtractWord(&elfHeader.e_machine, getPtr);
    
      getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr);
      getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr);
      getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr);
      getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr);
      getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr);
      getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr);
      getPtr = ExtractWord(&elfHeader.e_phnum, getPtr);
      getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr);
      getPtr = ExtractWord(&elfHeader.e_shnum, getPtr);
      getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr);
      if (    (rxCount              != sizeof elfHeader)
           || (elfHeader.e_ident[0] != ELFMAG0)
           || (elfHeader.e_ident[1] != ELFMAG1)
           || (elfHeader.e_ident[2] != ELFMAG2)
           || (elfHeader.e_ident[3] != ELFMAG3)
           || (elfHeader.e_type     != ET_EXEC)
         ) {
        fclose(file);
        fprintf (stderr, "*** illegal file format\n");
        return;
      } /* if */
    
      /* read all section headers */
      fseek(file, elfHeader.e_shoff, SEEK_SET);
      for (i = 0; i < elfHeader.e_shnum; i++) {
        rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file);
    
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_name, rxBlock);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_type, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_flags, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addr, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_offset, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_size, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_link, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_info, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addralign, getPtr);
        getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_entsize, getPtr);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
        if (rxCount != sizeof sectHeader[0]) {
          fclose(file);
          fprintf (stderr, "*** illegal file format\n");
          return;
        } /* if */
      } /* for */
    
      if ((hdr_name = strrchr(fileName, '/')) == NULL) {
        hdr_name = fileName;
      } else {
        ++hdr_name;
      }
      /* write start record */
    
      (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name));
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
      printf("%s\r\n",srecLine);
    
      /* write data records */
      firstAddr = ~0;
      loadAddr  =  0;
      for (i = 0; i < elfHeader.e_shnum; i++) {
        if (    (sectHeader[i].sh_type == SHT_PROGBITS)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	 && (sectHeader[i].sh_size != 0)
    	 ) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
          loadSize = sectHeader[i].sh_size;
          if (sectHeader[i].sh_flags != 0) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	loadAddr = sectHeader[i].sh_addr;
    	loadDiff = loadAddr - sectHeader[i].sh_offset;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
          } /* if */
          else {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	loadAddr = sectHeader[i].sh_offset + loadDiff;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
          } /* else */
    
          if (loadAddr < firstAddr)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	firstAddr = loadAddr;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
          /* build s-records */
          loadSize = sectHeader[i].sh_size;
          fseek(file, sectHeader[i].sh_offset, SEEK_SET);
          while (loadSize) {
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file);
    	if (rxCount < 0) {
    	  fclose(file);
    	  fprintf (stderr, "*** illegal file format\n");
    	return;
    	} /* if */
    	(void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount);
    	loadSize -= rxCount;
    	loadAddr += rxCount;
    	printf("%s\r\n",srecLine);
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
          } /* while */
        } /* if */
      } /* for */
    
      /* add end record */
      (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0);
      printf("%s\r\n",srecLine);
      fclose(file);
    } /* ConvertELF */
    
    
    /*************************************************************************
    |  MAIN
    |*************************************************************************/
    
    int main( int argc, char *argv[ ])
    {
    
      uint32_t offset;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
      if (argc == 2) {
        ConvertELF(argv[1], 0);
      } /* if */
      else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) {
        ExtractNumber(&offset, argv[2]);
        ConvertELF(argv[3], offset);
      } /* if */
      else {
        fprintf (stderr, "Usage: img2srec [-o offset] <image>\n");
      } /* if */
    
      return 0;
    } /* main */