📄 tfsclean1.c
字号:
/* 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"#if INCLUDE_TFS#if DEFRAG_TEST_ENABLEDvoiddefragExitTestPoint(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 voiddefragTick(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 intdefragSerase(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 intdefragFwrite(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((ulong *)dest,(ulong *)src,size); if (ret < 0) { 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 intdefragGetSpantype(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 intdefragEraseSpare(TDEV *tdp){ int snum, ssize; uchar *sbase; if (addrtosector((char *)tdp->spare,&snum,&ssize,&sbase) < 0) return(TFSERR_FLASHFAILURE); if (!flasherased(sbase,sbase+ssize)) { 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 intdefragValidDSI(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 intdefragSectorInSpare(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. */voiddefragTouchedSectors(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -