uboot/tools/img2srec.c
<<
>>
Prefs
   1/*************************************************************************
   2|  COPYRIGHT (c) 2000 BY ABATRON AG
   3|*************************************************************************
   4|
   5|  PROJECT NAME: Linux Image to S-record Conversion Utility
   6|  FILENAME    : img2srec.c
   7|
   8|  COMPILER    : GCC
   9|
  10|  TARGET OS   : LINUX / UNIX
  11|  TARGET HW   : -
  12|
  13|  PROGRAMMER  : Abatron / RD
  14|  CREATION    : 07.07.00
  15|
  16|*************************************************************************
  17|
  18|  DESCRIPTION :
  19|
  20|  Utility to convert a Linux Boot Image to S-record:
  21|  ==================================================
  22|
  23|  This command line utility can be used to convert a Linux boot image
  24|  (zimage.initrd) to S-Record format used for flash programming.
  25|  This conversion takes care of the special sections "IMAGE" and INITRD".
  26|
  27|  img2srec [-o offset] image > image.srec
  28|
  29|
  30|  Build the utility:
  31|  ==================
  32|
  33|  To build the utility use GCC as follows:
  34|
  35|  gcc img2srec.c -o img2srec
  36|
  37|
  38|*************************************************************************
  39|
  40|
  41|  UPDATES     :
  42|
  43|  DATE      NAME  CHANGES
  44|  -----------------------------------------------------------
  45|  Latest update
  46|
  47|  07.07.00  aba   Initial release
  48|
  49|*************************************************************************/
  50
  51/*************************************************************************
  52|  INCLUDES
  53|*************************************************************************/
  54
  55#include "os_support.h"
  56#include <stdbool.h>
  57#include <stddef.h>
  58#include <stdio.h>
  59#include <stdlib.h>
  60#include <ctype.h>
  61#include <string.h>
  62#include <elf.h>
  63#include <unistd.h>
  64#include <errno.h>
  65
  66/*************************************************************************
  67|  FUNCTIONS
  68|*************************************************************************/
  69
  70static char* ExtractHex (uint32_t* value,  char* getPtr)
  71{
  72  uint32_t num;
  73  uint32_t digit;
  74  uint8_t  c;
  75
  76  while (*getPtr == ' ') getPtr++;
  77  num = 0;
  78  for (;;) {
  79    c = *getPtr;
  80    if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
  81    else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10);
  82    else if ((c >= 'a') && (c <= 'f')) digit = (uint32_t)(c - 'a' + 10);
  83    else break;
  84    num <<= 4;
  85    num += digit;
  86    getPtr++;
  87  } /* for */
  88  *value = num;
  89  return getPtr;
  90} /* ExtractHex */
  91
  92static char* ExtractDecimal (uint32_t* value,  char* getPtr)
  93{
  94  uint32_t num;
  95  uint32_t digit;
  96  uint8_t  c;
  97
  98  while (*getPtr == ' ') getPtr++;
  99  num = 0;
 100  for (;;) {
 101    c = *getPtr;
 102    if      ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
 103    else break;
 104    num *= 10;
 105    num += digit;
 106    getPtr++;
 107  } /* for */
 108  *value = num;
 109  return getPtr;
 110} /* ExtractDecimal */
 111
 112
 113static void ExtractNumber (uint32_t* value,  char* getPtr)
 114{
 115  bool  neg = false;
 116
 117  while (*getPtr == ' ') getPtr++;
 118  if (*getPtr == '-') {
 119    neg = true;
 120    getPtr++;
 121  } /* if */
 122  if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) {
 123    getPtr +=2;
 124    (void)ExtractHex(value, getPtr);
 125  } /* if */
 126  else {
 127    (void)ExtractDecimal(value, getPtr);
 128  } /* else */
 129  if (neg) *value = -(*value);
 130} /* ExtractNumber */
 131
 132
 133static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer)
 134{
 135  uint16_t x;
 136  x = (uint16_t)*buffer++;
 137  x = (x<<8) + (uint16_t)*buffer++;
 138  *value = x;
 139  return buffer;
 140} /* ExtractWord */
 141
 142
 143static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer)
 144{
 145  uint32_t x;
 146  x = (uint32_t)*buffer++;
 147  x = (x<<8) + (uint32_t)*buffer++;
 148  x = (x<<8) + (uint32_t)*buffer++;
 149  x = (x<<8) + (uint32_t)*buffer++;
 150  *value = x;
 151  return buffer;
 152} /* ExtractLong */
 153
 154
 155static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer)
 156{
 157  while (count--) *data++ = *buffer++;
 158  return buffer;
 159} /* ExtractBlock */
 160
 161
 162static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum)
 163{
 164  uint16_t  temp;
 165
 166  static  char ByteToHex[] = "0123456789ABCDEF";
 167
 168  *pCheckSum += value;
 169  temp  = value / 16;
 170  *pa++ = ByteToHex[temp];
 171  temp  = value % 16;
 172  *pa++ = ByteToHex[temp];
 173  return pa;
 174}
 175
 176
 177static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr,
 178                          const uint8_t* data, int nCount)
 179{
 180  uint16_t  addrLen;
 181  uint16_t  sRLen;
 182  uint16_t  checkSum;
 183  uint16_t  i;
 184
 185  switch (sType) {
 186  case 0:
 187  case 1:
 188  case 9:
 189    addrLen = 2;
 190    break;
 191  case 2:
 192  case 8:
 193    addrLen = 3;
 194    break;
 195  case 3:
 196  case 7:
 197    addrLen = 4;
 198    break;
 199  default:
 200    return pa;
 201  } /* switch */
 202
 203  *pa++ = 'S';
 204  *pa++ = (char)(sType + '0');
 205  sRLen = addrLen + nCount + 1;
 206  checkSum = 0;
 207  pa = WriteHex(pa, (uint8_t)sRLen, &checkSum);
 208
 209  /* Write address field */
 210  for (i = 1; i <= addrLen; i++) {
 211    pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum);
 212  } /* for */
 213
 214  /* Write code/data fields */
 215  for (i = 0; i < nCount; i++) {
 216    pa = WriteHex(pa, *data++, &checkSum);
 217  } /* for */
 218
 219  /* Write checksum field */
 220  checkSum = ~checkSum;
 221  pa = WriteHex(pa, (uint8_t)checkSum, &checkSum);
 222  *pa++ = '\0';
 223  return pa;
 224}
 225
 226
 227static void ConvertELF(char* fileName, uint32_t loadOffset)
 228{
 229  FILE*         file;
 230  int           i;
 231  int           rxCount;
 232  uint8_t          rxBlock[1024];
 233  uint32_t         loadSize;
 234  uint32_t         firstAddr;
 235  uint32_t         loadAddr;
 236  uint32_t         loadDiff = 0;
 237  Elf32_Ehdr    elfHeader;
 238  Elf32_Shdr    sectHeader[32];
 239  uint8_t*         getPtr;
 240  char          srecLine[128];
 241  char          *hdr_name;
 242
 243
 244  /* open file */
 245  if ((file = fopen(fileName,"rb")) == NULL) {
 246    fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno));
 247    return;
 248  } /* if */
 249
 250  /* read ELF header */
 251  rxCount = fread(rxBlock, 1, sizeof elfHeader, file);
 252  getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock);
 253  getPtr = ExtractWord(&elfHeader.e_type, getPtr);
 254  getPtr = ExtractWord(&elfHeader.e_machine, getPtr);
 255  getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr);
 256  getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr);
 257  getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr);
 258  getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr);
 259  getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr);
 260  getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr);
 261  getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr);
 262  getPtr = ExtractWord(&elfHeader.e_phnum, getPtr);
 263  getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr);
 264  getPtr = ExtractWord(&elfHeader.e_shnum, getPtr);
 265  getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr);
 266  if (    (rxCount              != sizeof elfHeader)
 267       || (elfHeader.e_ident[0] != ELFMAG0)
 268       || (elfHeader.e_ident[1] != ELFMAG1)
 269       || (elfHeader.e_ident[2] != ELFMAG2)
 270       || (elfHeader.e_ident[3] != ELFMAG3)
 271       || (elfHeader.e_type     != ET_EXEC)
 272     ) {
 273    fclose(file);
 274    fprintf (stderr, "*** illegal file format\n");
 275    return;
 276  } /* if */
 277
 278  /* read all section headers */
 279  fseek(file, elfHeader.e_shoff, SEEK_SET);
 280  for (i = 0; i < elfHeader.e_shnum; i++) {
 281    rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file);
 282    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_name, rxBlock);
 283    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_type, getPtr);
 284    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_flags, getPtr);
 285    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addr, getPtr);
 286    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_offset, getPtr);
 287    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_size, getPtr);
 288    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_link, getPtr);
 289    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_info, getPtr);
 290    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addralign, getPtr);
 291    getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_entsize, getPtr);
 292    if (rxCount != sizeof sectHeader[0]) {
 293      fclose(file);
 294      fprintf (stderr, "*** illegal file format\n");
 295      return;
 296    } /* if */
 297  } /* for */
 298
 299  if ((hdr_name = strrchr(fileName, '/')) == NULL) {
 300    hdr_name = fileName;
 301  } else {
 302    ++hdr_name;
 303  }
 304  /* write start record */
 305  (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name));
 306  printf("%s\r\n",srecLine);
 307
 308  /* write data records */
 309  firstAddr = ~0;
 310  loadAddr  =  0;
 311  for (i = 0; i < elfHeader.e_shnum; i++) {
 312    if (    (sectHeader[i].sh_type == SHT_PROGBITS)
 313         && (sectHeader[i].sh_size != 0)
 314         ) {
 315      loadSize = sectHeader[i].sh_size;
 316      if (sectHeader[i].sh_flags != 0) {
 317        loadAddr = sectHeader[i].sh_addr;
 318        loadDiff = loadAddr - sectHeader[i].sh_offset;
 319      } /* if */
 320      else {
 321        loadAddr = sectHeader[i].sh_offset + loadDiff;
 322      } /* else */
 323
 324      if (loadAddr < firstAddr)
 325        firstAddr = loadAddr;
 326
 327      /* build s-records */
 328      loadSize = sectHeader[i].sh_size;
 329      fseek(file, sectHeader[i].sh_offset, SEEK_SET);
 330      while (loadSize) {
 331        rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file);
 332        if (rxCount < 0) {
 333          fclose(file);
 334          fprintf (stderr, "*** illegal file format\n");
 335        return;
 336        } /* if */
 337        (void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount);
 338        loadSize -= rxCount;
 339        loadAddr += rxCount;
 340        printf("%s\r\n",srecLine);
 341      } /* while */
 342    } /* if */
 343  } /* for */
 344
 345  /* add end record */
 346  (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0);
 347  printf("%s\r\n",srecLine);
 348  fclose(file);
 349} /* ConvertELF */
 350
 351
 352/*************************************************************************
 353|  MAIN
 354|*************************************************************************/
 355
 356int main( int argc, char *argv[ ])
 357{
 358  uint32_t offset;
 359
 360  if (argc == 2) {
 361    ConvertELF(argv[1], 0);
 362  } /* if */
 363  else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) {
 364    ExtractNumber(&offset, argv[2]);
 365    ConvertELF(argv[3], offset);
 366  } /* if */
 367  else {
 368    fprintf (stderr, "Usage: img2srec [-o offset] <image>\n");
 369  } /* if */
 370
 371  return 0;
 372} /* main */
 373