📄 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 "cli.h"
#if INCLUDE_TFS
int tfsrun_abortableautoboot(char **arglist,int verbose);
char *(*tfsGetAtime)(long,char *,int);
long (*tfsGetLtime)(void);
int (*tfsDocommand)(char *,int);
TDEV tfsDeviceTbl[TFSDEVTOT+1]; /* See notes above tfsramdevice() */
TFILE **tfsAlist;
struct tfsdat tfsSlots[TFS_MAXOPEN];
long tfsTrace;
int TfsCleanEnable;
static long tfsFmodCount;
static int tfsAlistSize, tfsOldDelFlagCheckActive;
static int tfsMonrcActive;
/* alt_tfsdevtbl[]:
* This pre-initialized table of "flash-empty" tfsdev structures allows
* the user to override the default configuration of TFS as it is defined
* in tfsdev.h in the port directory. This is primarily useful for cases
* where uMon is being deployed on an evaluation board and the users have
* varying needs for TFS and it's use of the on-board flash memory.
*
* Note that the following initialized arrays use a GNU-extension to
* force an array of structures and an array of arrays be initialized
* to 0xff in flash. This may break for other compilers. This syntax
* is discussed in gcc.gnu.org online documentation under the topic
* "Designated Initializers". If, just in case you need to do this with
* some compiler that doesn't support this syntax, define the macro
* CANT_DEAL_WITH_ALT_TFSDEV_SYNTAX and build your own alt_tfsdev.h file...
*/
#ifdef CANT_DEAL_WITH_ALT_TFSDEV_SYNTAX
#include "alt_tfsdev.h"
#else
struct tfsdev alt_tfsdevtbl[TFSDEVTOT] = {
[0 ... (TFSDEVTOT-1)] =
{ (char *)0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
};
char alt_devnames[TFSDEVTOT][TFSNAMESIZE] = {
[0 ... (TFSDEVTOT-1)] =
{ [0 ... (TFSNAMESIZE-1)] = 0xff }
};
#endif
/* 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_NOTCPRS, "file is not compressed" },
{ TFSERR_NOTAVAILABLE, "tfs facility not available" },
{ TFSERR_BADFLAG, "bad flag" },
{ TFSERR_CLEANOFF, "defragmentation is disabled" },
{ TFSERR_FLAKEYSOURCE, "dynamic source data" },
{ TFSERR_BADEXTENSION, "invalid file extension" },
{ TFSERR_LINKERROR, "file link error" },
{ TFSERR_BADPREFIX, "invalid device prefix" },
{ TFSERR_ALTINUSE, "alternate devcfg in use" },
{ TFSERR_NORUNMONRC, "can't run from monrc" },
{ 0,0 }
};
/* 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 long
dummyLtime(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);
}
/* tfsspace():
* Return 1 if the incoming address is within TFS space; else
* return 0.
*/
int
tfsspace(char *addr)
{
TDEV *tdp;
for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
if ((*addr >= (char *)tdp->start) &&
(*addr <= (char *)tdp->end))
return(1);
if ((*addr >= (char *)tdp->spare) &&
(*addr < (char *)(tdp->spare+tdp->sparesize)))
return(1);
}
return(0);
}
/* tfsflasherase(), tfsflasheraseall() & tfsflashwrite():
* Wrappers for corresponding flash operations. The wrappers are used
* to provide one place for the incrmentation of tfsFmodCount.
*/
int
tfsflasheraseall(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((char *)tdp->start,&snum,0,0) < 0)
return(TFSERR_MEMFAIL);
last = snum + tdp->sectorcount;
while(snum < last) {
if (AppFlashErase(snum++) <= 0)
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((char *)tdp->spare,&snum,0,0) < 0)
return(TFSERR_MEMFAIL);
if (AppFlashErase(snum) <= 0)
return(TFSERR_MEMFAIL);
}
return(TFS_OKAY);
}
int
tfsflasherase(int snum)
{
if (tfsTrace > 2)
printf(" tfsflasherase(%d)\n",snum);
tfsFmodCount++;
return(AppFlashErase(snum));
}
int
tfsflashwrite(uchar *dest,uchar *src,long bytecnt)
{
if (tfsTrace > 2)
printf(" tfsflashwrite(0x%lx,0x%lx,%ld)\n",
(ulong)dest,(ulong)src,bytecnt);
if (bytecnt < 0)
return(TFSERR_BADARG);
tfsFmodCount++;
if (AppFlashWrite(dest,src,bytecnt) == 0)
return(TFS_OKAY);
else
return(TFSERR_FLASHFAILURE);
}
/* 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 int
tfsmakeStale(TFILE *tfp)
{
ulong flags;
flags = TFS_FLAGS(tfp) & ~TFS_NSTALE;
return(tfsflashwrite((uchar *)&tfp->flags,(uchar *)&flags,
(long)sizeof(long)));
}
/* 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 int
tfsflagsatob(char *fstr, long *flag)
{
struct tfsflg *tfp;
*flag = 0;
if (!fstr)
return(TFSERR_BADFLAG);
while(*fstr) {
tfp = tfsflgtbl;
while(tfp->sdesc) {
if (*fstr == tfp->sdesc) {
*flag |= tfp->flag;
break;
}
tfp++;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -