📄 flasher.c
字号:
/*
* 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 + -