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 + -
显示快捷键?