?? tfs.c
字號:
/* tfs.c: * Tiny File System * TFS supports the ability to store/access files in flash. The TFS * functions provide a command at the monitor's user interface (the * "tfs" command) as well as a library of functions that are available to * the monitor/application code on this target (TFS api). * * The code that supports TFS in the MicroMonitor package spans across * several files. This is done so that various pieces of TFS can optionally * be compiled in or out (using INCLUDE_XXX macros in config.h) of the * monitor package... * * tfs.c: * Core TFS code that cannot be optionally omitted without eliminating * the TFS facility from the monitor. * * tfsapi.c: * This file contains the code that supports the application's ability * to use the TFS api. Since some of the api is used by the monitor * itself, not all of the api-specific code is there, some of it is * in tfs.c. * * tfscleanX.c: * TFS can be configured with one of several different flash defrag * mechanisms. Currently, tfsclean[123].c are available. * * tfscli.c: * If you don't need the "tfs" command in your command line interface, * then the code in this file can be omitted. * * tfsloader.c: * TFS can support COFF, ELF or A.OUT binary file formats. The code * to load each of these formats from flash to RAM is here. * * tfslog.c: * If there is a need to log flash interaction to a file, then this * file contains code to support that. * * * NOTES: * * Dealing with multiple task access: * Since the monitor is inherently a single threaded program * potentially being used in a multi-tasking environment, the monitor's * access functions (API) must be provided with a lock/unlock * wrapper that will guarantee sequential access to all of the monitor * facilities. Refer to monlib.c to see this implementation. This * provides the protection needed by TFS to keep multiple "mon_" * functions from being executed by different tasks. * Note that originally this was supported with tfsctrl(TFS_MUTEX ) and * it only protected the tfs API functions. This turned out to be * insufficient because it did not prevent other tasks from calling * other non-tfs functions in the monitor while tfs access (and * potentially, flash update) was in progress. This meant that a flash * update could be in progress and some other task could call mon_getenv() * (for example). This could screw up the flash update because * mon_getenv() might be fetched out of the same flash device that * the TFS operation is being performed on. * * * Dealing with cache coherency: * I believe the only concern here is that Icache must be invalidated * and Dcache must be flushed whenever TFS does a memory copy that may * ultimately be executable code. This is handled at the end of the * tfsmemcpy function by calling flushDcache() and invalidateIcache(). * It is the application's responsibility to give the monitor the * appropriate functions (see assigncachefuncs()) if necessary. * * * Configuring a device to run as TFS memory: * Assuming you are using power-safe cleanup... * TFS expects that on any given device used for storage of files, the * device is broken up into some number of sectors with the last sector * being the largest and used as the spare sector for defragmentation. * All other sector sizes must be smaller than the SPARE sector and the * sector just prior to the spare is used for defragmentation state * overhead. This sector should be large enough to allow the overhead * space to grow down from the top without filling the sector. For most * flash devices, these two sectors (spare and overhead) are usually the * same size and are large. For FlashRam, the device should be configured * so that these two sectors are large. The spare sector will never be * allowed to contain any file information (because it is 100% dedicated to * the defragmentation process) and the sector next to this can have files * in it, but the overhead space is also in this sector. * * * Testing TFS: * There are three files dedicated to testing the file system. Two of them * (tfstestscript & tfstestscript1) are scripts that are put into the * file system and run. The third file (tfstest.c) is a piece of code * that can be built into a small application that runs out of TFS to test * all of the API functionality. * - tfstestscript: * This script is used to simply bang on normal defragmentation. It * builds files with sizes and names based on the content of memory * starting at $APPRAMBASE. Changing the content of memory starting at * $APPRAMBASE will change the characteristics of this test so it is * somewhat random. It is not 100% generic, but can be used as a * base for testing TFS on various systems. * - tfstestscript1: * This script is used to bang on the power-safe defragmentation of * TFS. It simulates power hits that might occur during defragmentation. * This script assumes that the monitor has been built with the * DEFRAG_TEST_ENABLED flag set. * - tfstest.c: * This code can be built into a small application that will thoroughly * exercise the TFS API. This file can also be used as a reference for * some examples of TFS api usage. * * 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 "tfsdev.h"#include "flash.h"#include "frmwrk.h"//#include "cli.h"#if INCLUDE_TFSchar *(*tfsGetAtime)(long,char *,int);long (*tfsGetLtime)(void);int (*tfsDocommand)(char *,int);TDEV tfsDeviceTbl[TFSDEVTOT];TFILE **tfsAlist;struct tfsdat tfsSlots[TFS_MAXOPEN];long tfsTrace;int TfsCleanEnable;static long tfsFmodCount;static int tfsAlistSize, tfsOldDelFlagCheckActive;#define APPLICATION_RAMSTART SDRAM_SADDR/* tfsflgtbl & tfserrtbl: * Tables that establish an easy lookup mechanism to convert from * bitfield to string or character. * Note that TFS_ULVL0 is commented out. I leave it in here as a place * holder (comment), but it actually is not needed becasue ulvl_0 is the * default if no other ulvl is specified. */struct tfsflg tfsflgtbl[] = { { TFS_BRUN, 'b', "run_at_boot", TFS_BRUN }, { TFS_QRYBRUN, 'B', "qry_run_at_boot", TFS_QRYBRUN }, { TFS_EXEC, 'e', "executable", TFS_EXEC }, { TFS_SYMLINK, 'l', "symbolic link", TFS_SYMLINK }, { TFS_EBIN, 'E', TFS_EBIN_NAME, TFS_EBIN }, { TFS_IPMOD, 'i', "inplace_modifiable", TFS_IPMOD }, { TFS_UNREAD, 'u', "ulvl_unreadable", TFS_UNREAD },/* { TFS_ULVL0, '0', "ulvl_0", TFS_ULVLMSK }, */ { TFS_ULVL1, '1', "ulvl_1", TFS_ULVLMSK }, { TFS_ULVL2, '2', "ulvl_2", TFS_ULVLMSK }, { TFS_ULVL3, '3', "ulvl_3", TFS_ULVLMSK }, { TFS_CPRS, 'c', "compressed", TFS_CPRS }, { 0, 0, 0, 0 }};static struct tfserr tfserrtbl[] = { { TFS_OKAY, "no error" }, { TFSERR_NOFILE, "file not found" }, { TFSERR_NOSLOT, "max fps opened" }, { TFSERR_EOF, "end of file" }, { TFSERR_BADARG, "bad argument" }, { TFSERR_NOTEXEC, "not executable" }, { TFSERR_BADCRC, "bad crc" }, { TFSERR_FILEEXISTS, "file already exists" }, { TFSERR_FLASHFAILURE, "flash operation failed" }, { TFSERR_WRITEMAX, "max write count exceeded" }, { TFSERR_RDONLY, "file is read-only" }, { TFSERR_BADFD, "invalid descriptor" }, { TFSERR_BADHDR, "bad binary executable header" }, { TFSERR_CORRUPT, "corrupt file" }, { TFSERR_MEMFAIL, "memory failure" }, { TFSERR_NOTIPMOD, "file is not in-place-modifiable" }, { TFSERR_FLASHFULL, "out of flash space" }, { TFSERR_USERDENIED, "user level access denied" }, { TFSERR_NAMETOOBIG, "name or info field too big" }, { TFSERR_FILEINUSE, "file in use" }, { TFSERR_SCRIPTINSUB, "can't put script in subroutine" }, { TFSERR_NOTAVAILABLE, "tfs facility not available" }, { TFSERR_BADFLAG, "bad flag" }, { TFSERR_CLEANOFF, "defragmentation is disabled" }, { TFSERR_FLAKEYSOURCE, "dynamic source data" }, { 0,0 }};/* getAppRamStart(): * First looks for the content of APPRAMBASE shell variable; * if present, that string is converted to a long and returned, * else the value of APPLICATION_RAMSTART is returned. */ulonggetAppRamStart(void){ char *apprambase; ulong value; apprambase = getenv("APPRAMBASE"); if (apprambase) value = strtoul(apprambase,0,0); else value = APPLICATION_RAMSTART; return(value);}/* dummyAtime() & dummyLtime(): * These two functions are loaded into the function pointers as defaults * for the time-retrieval stuff used in TFS. */static char *dummyAtime(long tval,char *buf,int buflen){/* strcpy(buf,"Fri Sep 13 00:00:00 1986"); */ *buf = 0; return(buf);}static longdummyLtime(void){ return(TIME_UNDEFINED);}/* getdfsdev(): * Input is a file pointer; based on that pointer return the appropriate * device header pointer. If error, just return 0. * A "device" in TFS is some block of some type of memory that is assumed * to be contiguous space that can be configured as a block of sectors (to * look like flash). For most systems, there is only one (the flash); * other systems may have battery-backed RAM, etc... * Note that this is not fully implemented. */static TDEV *gettfsdev(TFILE *fp){ TDEV *tdp; for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { if ((fp >= (TFILE *)tdp->start) && (fp < (TFILE *)tdp->end)) return(tdp); } return(0);}TDEV *gettfsdev_fromprefix(char * prefix, int verbose){ TDEV *tdp; for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { if (!strcmp(prefix,tdp->prefix)) return(tdp); } if (verbose) printf("Bad device prefix: %s\n",prefix); return(0);}/* tfsflasherase(), tfsflasheraseall() & tfsflashwrite(): * Wrappers for corresponding flash operations. The wrappers are used * to provide one place for the incrmentation of tfsFmodCount. */inttfsflasheraseall(TDEV *tdp){ int snum, last; if (tfsTrace > 2) printf(" tfsflasheraseall(%s)\n",tdp->prefix); tfsFmodCount++; /* Erase the sectors within the device that are used for file store... */ if (addrtosector((uchar *)tdp->start,&snum,0,0) < 0) return(TFSERR_MEMFAIL); last = snum + tdp->sectorcount; while(snum < last) { if (AppFlashErase(snum++) == -1) return(TFSERR_MEMFAIL); } /* Erase the spare (if there is one)... * (if this system is configured with tfsclean2.c, then * there is no need for a spare sector). */ if (tdp->spare) { if (addrtosector((uchar *)tdp->spare,&snum,0,0) < 0) return(TFSERR_MEMFAIL); if (AppFlashErase(snum) == -1) return(TFSERR_MEMFAIL); } return(TFS_OKAY);}inttfsflasherase(int snum){ if (tfsTrace > 2) printf(" tfsflasherase(%d)\n",snum); tfsFmodCount++; return(AppFlashErase(snum));}inttfsflashwrite(ulong *dest,ulong *src,long bytecnt){ if (tfsTrace > 2) printf(" tfsflashwrite(0x%lx,0x%lx,%ld)\n", (ulong)dest,(ulong)src,bytecnt); if (bytecnt < 0) return(-1); tfsFmodCount++; return(AppFlashWrite(dest,src,bytecnt));}/* tfserrmsg(): * Return the error message string that corresponds to the incoming * tfs error number. */char *tfserrmsg(int errno){ struct tfserr *tep; tep = tfserrtbl; while(tep->msg) { if (errno == tep->err) return(tep->msg); tep++; } return("unknown tfs errno");}/* tfsmakeStale(): * Modify the state of a file to be stale. * Do this by clearing the TFS_NOTSTALE flag in the tfs header. * This function is used by tfsadd() when in the process of * updating a file that already exists in the flash. * See comments above tfsadd() for more details on the TFS_NOTSTALE flag. */static inttfsmakeStale(TFILE *tfp){ ulong flags; flags = TFS_FLAGS(tfp) & ~TFS_NSTALE; if (tfsflashwrite((ulong *)&tfp->flags,&flags,(long)sizeof(long)) < 0) return(TFSERR_FLASHFAILURE); return(TFS_OKAY);}/* tfsflagsbtoa(): * Convert binary flags to ascii and return the string. */char *tfsflagsbtoa(long flags,char *fstr){ int i; struct tfsflg *tfp; if ((!flags) || (!fstr)) return((char *)0); i = 0; tfp = tfsflgtbl; *fstr = 0; while(tfp->sdesc) { if ((flags & tfp->mask) == tfp->flag) fstr[i++] = tfp->sdesc; tfp++; } fstr[i] = 0; return(fstr);}/* tfsflagsatob(): * Convert ascii flags to binary and return the long. */static inttfsflagsatob(char *fstr, long *flag){ struct tfsflg *tfp; *flag = 0; if (!fstr) return(TFSERR_BADFLAG);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -