⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tfs.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -