⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flasher.c

📁 采用ST20 CPU的机顶盒的烧写程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * File     : flasher.c
 * Synopsys : Target-side flashing utility.
 *
 * Copyright (c) 2003-2007 STMicroelectronics Limited. All right reserved.
 *
 * This program is used to update the FLASH memory on ST reference boards.
 * The layout of the FLASH is as follows on non-STi5528 boards:
 *
 *  0x00000000 - 0x0000003F  Boot vector for CPU 0
 *  0x00000040 - 0x0000007F  Boot vector for CPU 1
 *  ...
 *  0x000001C0 - 0x000001FF  Boot vector for CPU 7
 *  0x00000200 - 0x0000021F  ASCIIZ description for bootvector 0
 *  0x00000220 - 0x0000023F  ASCIIZ description for bootvector 1
 *  ...
 *  0x000002E0 - 0x000002FF  ASCIIZ description for bootvector 7
 *  0x00000300 - 0x0000043F  Bootstrap descriptors for CPUs 0 - 7 (see below)
 *  0x00000440 - 0x00000443  Pointer to main application image control directory
 *  0x00000444 - 0x0000053B  Fail-safe image control structure
 *  0x0000053C - 0x0000053F  CRC for 0x00000000-0x0000053F
 *  <bootstrap and fail-safe application image sections>
 *      X      -     Y       Padding to end of highest used FLASH block if
 *                           -bootsep option is used (anything below Y could be
 *                           considered non-updatable).
 *      Y      - Y + 0xFF    Main image control directory
 *  Y + 0x100  - Y + 0x37FB  Main image control structures
 *  Y + 0x37FC - Y + 0x3800  CRC for Y to Y + 0x37FB
 *
 *  On STi5528 boards the layout is the same except that the first 1024 bytes
 *  are reserved and the layout starts at 0x400. The reserved bytes include some
 *  ST40 code to jump from the start of FLASH to the boot vector at 0x400.
 *
 * The image control directory consists of 64 pointers to image control
 * structures. Unused entries are NULL.
 *
 * The format of a bootstrap descriptor is:
 *
 *    0x0000 - 0x0003 Entry point
 *    0x0004 - 0x0007 Size of bootstrap
 *    0x0008 - 0x0027 ASCIIZ description
 *
 * The format of an image control structure is:
 *
 *    0x0000 - 0x001F ASCIIZ description
 *    0x0020 - 0x0023 CPU number (0-7). Top bit set if boot image.
 *    0x0024 - 0x0027 Stack address
 *    0x0028 - 0x002B Entry point
 *    0x002C - 0x002F Number of sections which follow
 *    0x0030+N*0x10 - 0x0033+N*0x10 Type (copy, zeroed, etc)
 *    0x0034+N*0x10 - 0x0037+N*0x10 Type source address in FLASH
 *    0x0038+N*0x10 - 0x003B+N*0x10 Type destination address in RAM
 *    0x003C+N*0x10 - 0x003F+N*0x10 Type length in bytes (of source)
 *
 * This program is able to:
 *
 *  Change boot vector programs
 *  Change bootstrap programs
 *  Install, remove and change application images
 *  Erase the FLASH.
 *
 * No error conditions are propagated in this program. If something
 * fails, then the program aborts immediately.
 */

#ifdef FLASHERPLATFORM
#define _stringify(s) #s
#define STRINGIFY(s) _stringify(s)
#define DEFAULTPLATFORM STRINGIFY(FLASHERPLATFORM)
#else
#error FLASHERPLATFORM undefined
#endif

#undef __STRICT_ANSI__

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>

#include "flash.h"

/*
 * Minimum section alignment which by default is the typical cache line size but
 * may be overridden.
 */
#ifndef MIN_SECTION_ALIGNMENT
#define MIN_SECTION_ALIGNMENT 64
#endif

#define FAILSAFE_SLOT (-1)
#define ANY_SLOT      (-2)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))

/* ELF Relocation info */
#define R_LX_32       2
#define R_LX_REL32    9
#define R_LX_JMP_SLOT 25
#define R_SH_DIR32    1
#define R_SH_RELATIVE 165

typedef struct
{
  unsigned int offset;
  unsigned int info;
  unsigned int addend;

} reloc_t;

typedef struct
{
  unsigned int name;
  unsigned int value;
  unsigned int size;
  unsigned char info;
  unsigned char other;
  unsigned short shndx;
} symb_t;

typedef enum
{
  MEM_FREE,
  MEM_USED,
  MEM_INVALID
} memtype_t;

/*
 * An image_t is used to describe the user image files that we'll be storing
 * into FLASH.
 */
typedef struct image_s image_t;
struct image_s
{
  image_t* next; /* Next image in list */
  image_t* prev; /* Prev image in list */
  const char* fileName; /* File name of image file */
  int slot; /* Which slot it is destined for */
  imageControl_t* controlStruct; /* Image control struct ptr */
};

/*
 * buffer_t's are used to describe memory regions in the FLASH. They are used to
 * manage both the list of updates we've been asked to do, and the allocation
 * map of the FLASH.
 */
typedef struct buffer_s buffer_t;
struct buffer_s
{
  buffer_t* next;
  buffer_t* prev;

  unsigned int address;
  unsigned int length;
  union
  {
    memtype_t type;
    unsigned char* data;
  }
  info;
};

static image_t bootVectors = { &bootVectors, &bootVectors };
static image_t bootStraps = { &bootStraps, &bootStraps };
static image_t images = { &images, &images };
static buffer_t updateList = { &updateList, &updateList, 0, 0, {MEM_INVALID} };
static buffer_t flashMap = { &flashMap, &flashMap, 0, 0, {MEM_INVALID} };
static buffer_t controlMap = { &controlMap, &controlMap, 0, 0, {MEM_INVALID} };
static int eraseFlag = 0;
static int slotsToDelete = 0;
static int* deleteList = NULL;
static int* bootList = NULL;
static int slotsToMakeBootable = 0;
static const char* romFile = NULL;
static int binDump = 0;
static int romProgram = 0;
static image_t* failsafeImage = NULL;
static unsigned int binaryBaseAddr = 0;
static int separateBootAndAppFlashBlocks = 0;
#ifndef SFXIMAGENAME
static const char* optionFile = NULL;
static int optionFileArgc = 0;
static char** optionFileArgv = NULL;
#endif /* !SFXIMAGENAME */
static flashTarget_t* target = NULL;

#ifdef SFXIMAGENAME
#define __concat(a, b) a##b
#define _concat(a, b) __concat(a, b)
#ifdef __ST200__
#define SFXNAME(s) _concat(_, _concat(SFXIMAGENAME, s))
#else /* !__ST200__ */
#define SFXNAME(s) _concat(SFXIMAGENAME, s)
#endif /* __ST200__ */
extern void* SFXNAME(_start);
extern void* SFXNAME(_size);
static unsigned char* const romImageStart = (unsigned char*)&SFXNAME(_start);
static const size_t romImageSize = (size_t)&SFXNAME(_size);
#else /* !SFXIMAGENAME */
static unsigned char* romImageStart = NULL;
static size_t romImageSize = 0;
#endif /* SFXIMAGENAME */

/*
 * getopt () prototypes & globals.
 */
extern int getopt(int argc, char* const* argv, const char* optstring);
extern char* optarg;
extern int optind;

/*
 * Routine to show progress as a percentage.
 */
static void showProgress(unsigned int done, unsigned int total)
{
  printf("Progress: %-3d%%\r", (done * 100) / total);
  if (done == total)
  {
    printf("\n");
  }
  fflush(stdout);
}

/*
 * Routine to allocate memory and zero it.
 * If the allocation fails, the program aborts.
 */
static void* allocate(size_t size)
{
  void* ptr;

  if ((ptr = calloc(1, size)) == NULL)
  {
    fprintf(stderr, "flasher: Failed to allocate memory\n");
    exit(1);
  }

  return ptr;
}

#ifndef SFXIMAGENAME
/*
 * Routine to re-allocate memory.
 * If the allocation fails, the program aborts.
 */
static void* reallocate(void* oldptr, size_t size)
{
  void* ptr;

  if ((ptr = realloc(oldptr, size)) == NULL)
  {
    fprintf(stderr, "flasher: Failed to allocate memory\n");
    exit(1);
  }

  return ptr;
}
#endif /* !SFXIMAGENAME */

/*
 * Routine to insert a buffer before another one in a list.
 */
static void insertBefore(buffer_t* new, buffer_t* listNode)
{
  new->next = listNode;
  new->prev = listNode->prev;
  listNode->prev->next = new;
  listNode->prev = new;
}

/*
 * Routine to insert a buffer in the correct place on a list. This lists are
 * maintained in ascending address order.
 */
static void addBuffer(buffer_t* buffer, buffer_t* list)
{
  buffer_t* ptr;

  for (ptr = list->next; ptr != list; ptr = ptr->next)
  {
    if (ptr->address > buffer->address)
    {
      break;
    }
  }

  insertBefore(buffer, ptr);
}

/*
 * Routine to coalesce neighbouring regions of the same type in a memory map.
 */
static void coalesceMemMap(buffer_t* memRoot)
{
  buffer_t* ptr;
  /*
   * Simple minded coalesce - sweep & join like minded adjacent buffers.
   */
  for (ptr = memRoot->next; ptr != memRoot; ptr = ptr->next)
  {
    while ((ptr->info.type == (ptr->next)->info.type) && ((ptr->address + ptr->length) == (ptr->next)->address))
    {
      buffer_t* coalesced = ptr->next;

      ptr->length += coalesced->length;
      ptr->next = coalesced->next;
      coalesced->next->prev = ptr;

      free(coalesced);
    }
  }
}

/*
 * Force an address range in a memory map to a particular type, replacing,
 * splitting or truncating any existing buffers that overlap that range.
 */
static void forceRangeInMemMap(unsigned int address, unsigned int length, memtype_t type, buffer_t* memRoot)
{
  buffer_t* ptr;
  buffer_t* buffer;
  for (ptr = memRoot->next; ptr != memRoot; ptr = ptr->next)
  {
    if (ptr->address < address && ptr->address + ptr->length > address)
    {
      /* Overlaps start of region  - end also? */
      if (ptr->address + ptr->length > address + length)
      {
        /* We are splitting a buffer in 2 */
        buffer = (buffer_t*)allocate(sizeof(buffer_t));
      
        buffer->address = address + length;
        buffer->length = (ptr->address + ptr->length) - (address + length);
        buffer->info.type = ptr->info.type;
        
        addBuffer(buffer, memRoot);
      }
      else
      {
        /* Truncate */
        ptr->length = address - ptr->address;
      }
    }
    else if (ptr->address >= address && ptr->address < address + length)
    {
      /* Starts in middle of region - ends in region too? */
      if (ptr->address + ptr->length <= address + length)
      {
        /* Wholly in region - remove it by giving it same address and 0 length */
        ptr->address = address;
        ptr->length = 0;
        ptr->info.type = type;
      }
      else
      {
        /* Move base up and adjust length */
        ptr->length -= (address + length - ptr->address);
        ptr->address = address + length;
      }
    }
  }

  buffer = (buffer_t*)allocate(sizeof(buffer_t));

  buffer->address = address;
  buffer->length = length;
  buffer->info.type = type;
  
  addBuffer(buffer, memRoot);
  
  coalesceMemMap(memRoot);
}

/*
 * Routine to allocate/free memory from the FLASH.
 * A buffer describing the region is passed in, and incorporated into the memory
 * map given as the 2nd param.
 * The allocation list is maintained so that it is always coalesced.
 */
static void updateMemMap(buffer_t* buffer, buffer_t* memRoot)
{
  buffer_t* ptr;
  memtype_t otherType;

  if (buffer->info.type == MEM_USED)
  {
    otherType = MEM_FREE;
  }
  else
  {
    otherType = MEM_USED;
  }

  /*
   * Scan the FLASH memory map, looking for a block which encompasses the region
   * described. The buffer that was passed must coincide with precisely one
   * buffer on the allocation list, and that list buffer must be of the opposite
   * type to that specified in the incoming request (i.e. can only free
   * allocated memory, can only allocate from free memory).
   */
  for (ptr = memRoot->next; ptr != memRoot; ptr = ptr->next)
  {
    /*
     * See if this element on the allocation list describes the region that was
     * passed in (or encompasses it).
     */
    if ((ptr->address <= buffer->address) && ((ptr->address + ptr->length) >= (buffer->address + buffer->length)))
    {
      if (ptr->info.type != otherType)
      {
        fprintf(stderr, "flasher: Memory @ 0x%08x cannot be %s\n", buffer->address,
                otherType == MEM_FREE ? "allocated" : "freed");
        exit(1);
      }

      /*
       * If they both start at the same address then the new buffer must be an
       * exact replacement, or shorter than the list buffer.
       */
      if (ptr->address == buffer->address)
      {
        /*
         * If it is an exact match simply change the type of the list buffer and
         * free off the new buffer.
         */
        if (ptr->length == buffer->length)
        {
          ptr->info.type = buffer->info.type;
          free(buffer);
          break;
        }
        else
        {
          /*
           * Cannot straddle into next buffer!
           */
          if (buffer->length > ptr->length)
          {
            fprintf(stderr, "flasher: Memory @ 0x%08x cannot be %s\n", buffer->address,
                    otherType == MEM_FREE ? "allocated" : "freed");
            exit(1);
          }

          /*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -