tfsclean1.c
来自「umon bootloader source code, support mip」· C语言 代码 · 共 2,107 行 · 第 1/5 页
C
2,107 行
/* tfsclean1.c:
* This is one of several different versions of tfsclean(). This version
* is by far the most complex, but offers power-hit safety and minimal
* flash overhead. It uses a "spare" sector to backup the
* "one-sector-at-a-time" defragmentation process.
*
* General notice:
* This code is part of a boot-monitor package developed as a generic base
* platform for embedded system designs. As such, it is likely to be
* distributed to various projects beyond the control of the original
* author. Please notify the author of any enhancements made or bugs found
* so that all may benefit from the changes. In addition, notification back
* to the author will allow the new user to pick up changes that may have
* been made by other users after this version of the code was distributed.
*
* Note1: the majority of this code was edited with 4-space tabs.
* Note2: as more and more contributions are accepted, the term "author"
* is becoming a mis-representation of credit.
*
* Original author: Ed Sutter
* Email: esutter@lucent.com
* Phone: 908-582-2351
*/
#include "config.h"
#include "cpu.h"
#include "stddefs.h"
#include "genlib.h"
#include "tfs.h"
#include "tfsprivate.h"
#include "flash.h"
#include "monflags.h"
#include "warmstart.h"
#if INCLUDE_TFS
#if DEFRAG_TEST_ENABLED
void
defragExitTestPoint(int val)
{
if ((DefragTestType == DEFRAG_TEST_EXIT) && (DefragTestPoint == val)) {
printf("\n+++++++++ EXIT @ TEST POINT(%d)\n",val);
CommandLoop();
}
}
#else
#define defragExitTestPoint(val)
#endif
/* Variables for testing tfsclean():
* They are set up through arguments to "tfs clean" in tfscli.c.
*/
int DefragTestType;
int DefragTestPoint;
int DefragTestSector;
/* defragTick():
* Used to show progress, just to let the user know that we aren't
* dead in the water.
*/
static void
defragTick(int verbose)
{
static int tick;
static char clockhand[] = { '|', '/', '-', '\\' };
if (!verbose && (!MFLAGS_NODEFRAGPRN())) {
if (tick > 3)
tick = 0;
printf("%c\b",clockhand[tick++]);
}
}
/* defragCrcTable():
* Return a pointer to the crc table for the specified TFS device.
*/
struct sectorcrc *
defragCrcTable(TDEV *tdp)
{
return((struct sectorcrc *)(tdp->end+1) - tdp->sectorcount);
}
/* defragSerase():
* Common function to call from within tfsclean() to erase a sector
* and generate an error message if necessary.
*
* If DEFRAG_TEST_ENABLED is defined and the type/sector/point criteria
* is met, then instead of erasing the sector; just change the first non-zero
* byte to zero to corrupt it. This essentially makes it a corrupted erase.
*/
static int
defragSerase(int tag, int snum)
{
int ret = 0;
#if DEFRAG_TEST_ENABLED
int ssize;
uchar *sbase, *send, zero;
printf(" serase_%02d(%02d)\n",tag,snum);
if ((DefragTestType == DEFRAG_TEST_SERASE) &&
(DefragTestSector == snum) && (DefragTestPoint == tag)) {
sectortoaddr(snum,&ssize,&sbase);
send = sbase+ssize;
zero = 0;
while(sbase < send) {
if (*sbase != 0) {
tfsflashwrite((ulong *)sbase,(ulong *)&zero,1);
break;
}
sbase++;
}
printf("DEFRAG_TEST_SERASE activated @ %d sector %d\n",tag,snum);
CommandLoop();
}
else
#endif
ret = tfsflasherase(snum);
if (ret <= 0) {
printf("tfsclean() serase erase failed: %d,%d,%d\n",snum,tag,ret);
}
return(ret);
}
/* defragFwrite():
* Common function to call from within tfsclean() to write to flash
* and generate an error message if necessary.
* If DEFRAG_TEST_ENABLED is defined and the test type is set to
* DEFRAG_TEST_FWRITE, then use APPRAMBASE as the source of the data
* so that the end result is an errored flash write.
*/
static int
defragFwrite(int tag, uchar *dest,uchar *src,int size)
{
int ret = 0;
#if DEFRAG_TEST_ENABLED
int snum;
addrtosector((char *)dest,&snum,0,0);
printf(" fwrite_%02d(%d,0x%lx,0x%lx,%d)\n",
tag,snum,(ulong)dest,(ulong)src,size);
if ((DefragTestType == DEFRAG_TEST_FWRITE) &&
(DefragTestSector == snum) && (DefragTestPoint == tag)) {
tfsflashwrite((ulong *)dest,(ulong *)getAppRamStart(),size/2);
printf("DEFRAG_TEST_FWRITE activated @ %d sector %d\n",tag,snum);
CommandLoop();
}
else
#endif
ret = tfsflashwrite(dest,src,size);
if (ret != TFS_OKAY) {
printf("tfsclean() fwrite failed: 0x%lx,0x%lx,%d,%d\n",
(ulong)dest,(ulong)src,size,tag);
}
return(ret);
}
/* defragGetSpantype():
* With the incoming sector base and end (s_base, s_end),
* determine the type of span that the incoming file (f_base, f_end)
* has across it. There are six different ways the spanning can
* occur:
* 1. begin and end in previous active sector (bpep);
* 2. begin in previously active sector, end in this one (bpec);
* 3. begin in previously active sector, end in later one (bpel);
* 4. begin and end in this active sector (bcec);
* 5. begin in this active sector, end in later one (bcel);
* 6. begin and end in later active sector (blel);
*/
static int
defragGetSpantype(char *s_base,char *s_end,char *f_base,char *f_end)
{
int spantype;
if (f_base < s_base) {
if ((f_end > s_base) && (f_end <= s_end))
spantype = SPANTYPE_BPEC;
else if (f_end > s_end)
spantype = SPANTYPE_BPEL;
else
spantype = SPANTYPE_BPEP;
}
else {
if (f_base > s_end)
spantype = SPANTYPE_BLEL;
else if (f_end <= s_end)
spantype = SPANTYPE_BCEC;
else
spantype = SPANTYPE_BCEL;
}
return(spantype);
}
/* defragGetSpantypeStr():
* Return a string that corresponds to the incoming state value.
*/
static char *
defragGetSpantypeStr(int spantype)
{
char *str;
switch(spantype) {
case SPANTYPE_BPEC:
str = "BPEC";
break;
case SPANTYPE_BLEL:
str = "BLEL";
break;
case SPANTYPE_BPEL:
str = "BPEL";
break;
case SPANTYPE_BPEP:
str = "BPEP";
break;
case SPANTYPE_BCEC:
str = "BCEC";
break;
case SPANTYPE_BCEL:
str = "BCEL";
break;
default:
str = "???";
break;
}
return(str);
}
/* defragEraseSpare():
* Erase the spare sector associated with the incoming TFS device.
* The underlying flash driver SHOULD have a check so that it only
* erases the sector if the sector is not already erased, so this
* extra check (call to flasherased()) may not be necessary in
* most cases.
*/
static int
defragEraseSpare(TDEV *tdp)
{
int snum, ssize;
uchar *sbase;
if (addrtosector((char *)tdp->spare,&snum,&ssize,&sbase) < 0)
return(TFSERR_FLASHFAILURE);
if (!flasherased(sbase,sbase+(ssize-1))) {
if (defragSerase(1,snum) < 0) {
return(TFSERR_FLASHFAILURE);
}
}
return(TFS_OKAY);
}
/* defragValidDSI():
* Test to see if we have a valid defrag state information (DSI)
* area. The DSI area, working back from tdp->end, consists of a
* table of 32-bit crcs (one per sector), a table of defraghdr
* structures (one per active file) and a 32-bit crc of the DSI
* itself. Knowing this format, we can easily step backwards into
* the DSI space to see if it all makes sense.
* If the table is 100% valid, then we will be able to step
* backwards through the DSI to find the 32-bit crc of the DSI area.
* If it matches, then we can be sure that the DSI is valid.
* Return total number of files in header if the defrag header
* table appears to be sane, else 0.
*/
static int
defragValidDSI(TDEV *tdp, struct sectorcrc **scp)
{
int ftot, valid, lastssize;
uchar *lastsbase;
struct sectorcrc *crctbl;
ulong hdrcrc, *crc;
struct defraghdr *dhp, dfhcpy;
ftot = valid = 0;
crctbl = defragCrcTable(tdp);
dhp = (struct defraghdr *)crctbl - 1;
dfhcpy = *dhp;
hdrcrc = dfhcpy.crc;
dfhcpy.crc = 0;
if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) {
ftot = dhp->idx + 1;
dhp = (struct defraghdr *)crctbl - ftot;
crc = (ulong *)dhp - 1;
if (crc32((uchar *)dhp,(uchar *)tdp->end-(uchar *)dhp) == *crc) {
if (scp)
*scp = crctbl;
return(ftot);
}
}
/* It's possible that the DSI space has been relocated to the spare
* sector, so check for that here...
*/
addrtosector((char *)tdp->end,0,&lastssize,&lastsbase);
crctbl = ((struct sectorcrc *)(tdp->spare+lastssize) - tdp->sectorcount);
dhp = (struct defraghdr *)crctbl - 1;
dfhcpy = *dhp;
hdrcrc = dfhcpy.crc;
dfhcpy.crc = 0;
if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) {
ftot = dhp->idx + 1;
dhp = (struct defraghdr *)crctbl - ftot;
crc = (ulong *)dhp - 1;
if (crc32((uchar *)dhp,
(uchar *)(tdp->spare+lastssize-1) - (uchar *)dhp) == *crc) {
#if DEFRAG_TEST_ENABLED
printf("TFS: DSI in spare\n");
#endif
if (scp)
*scp = crctbl;
return(ftot);
}
}
return(0);
}
/* defragSectorInSpare():
* For each sector, run a CRC32 on the content of the spare
* using the size of the sector in question. If the calculated
* crc matches that of the table, then we have located the sector
* that has been copied to the spare.
* This is a pain in the butt because we can't just run a CRC32 on
* the spare sector itself because the size of the spare may not match
* the size of the sector that was copied to it. The source sector
* might have been smaller; hence when we calculate the CRC32, we need
* to use the size of the potential source sector.
*/
static int
defragSectorInSpare(TDEV *tdp, struct sectorcrc *crctbl)
{
uchar *sbase;
struct defraghdr *dhp;
int i, ssize, snum, ftot;
sbase = (uchar *)tdp->start;
dhp = (struct defraghdr *)crctbl - 1;
ftot = dhp->idx + 1;
for(i=0;i<tdp->sectorcount;i++) {
addrtosector(sbase,&snum,&ssize,0);
if (i == tdp->sectorcount - 1) {
ssize -= /* CRC table */
(tdp->sectorcount * sizeof(struct sectorcrc));
ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */
ssize -= 4; /* Crc of the tables */
}
if (crc32((uchar *)tdp->spare,ssize) == crctbl[i].precrc)
return(snum);
sbase += ssize;
}
return(-1);
}
/* defragTouchedSectors():
* Step through the crc table and TFS flash space to find the first
* and last sectors that have been touched by defragmentation.
* This is used by defragGetState() to recover from an interrupted
* defragmentation, so a few verbose messages are useful to indicate
* status to the user.
*/
void
defragTouchedSectors(TDEV *tdp,int *first, int *last)
{
uchar *sbase;
struct defraghdr *dhp;
struct sectorcrc *crctbl;
int i, ssize, snum, ftot;
*first = -1;
*last = -1;
sbase = (uchar *)tdp->start;
crctbl = defragCrcTable(tdp);
dhp = (struct defraghdr *)crctbl - 1;
ftot = dhp->idx + 1;
printf("TFS: calculating per-sector crcs... ");
for(i=0;i<tdp->sectorcount;i++) {
addrtosector(sbase,&snum,&ssize,0);
if (i == tdp->sectorcount - 1) {
ssize -= /* CRC table */
(tdp->sectorcount * sizeof(struct sectorcrc));
ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */
ssize -= 4; /* Crc of the tables */
}
if (crc32(sbase,ssize) != crctbl[i].precrc) {
if (*first == -1)
*first = snum;
*last = snum;
}
sbase += ssize;
defragTick(0);
}
printf("done\n");
return;
}
/* defragPostCrcCheck():
* Return 1 if the post-crc check of the incoming sector number passes;
* else 0.
*/
int
defragPostCrcCheck(TDEV *tdp, int isnum)
{
uchar *sbase;
struct defraghdr *dhp;
struct sectorcrc *crctbl;
int ftot, i, snum, ssize, lastsnum, lastssize;
sbase = (uchar *)tdp->start;
crctbl = defragCrcTable(tdp);
dhp = (struct defraghdr *)crctbl - 1;
ftot = dhp->idx + 1;
addrtosector((uchar *)tdp->end,&lastsnum,&lastssize,0);
for(i=0;i<tdp->sectorcount;i++) {
addrtosector(sbase,&snum,&ssize,0);
if (snum == isnum)
break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?