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

📄 tfs.c

📁 uCOS-II for AT91M55800A完整实例
💻 C
📖 第 1 页 / 共 4 页
字号:
/* 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. * *	tfsclean.c: *		TFS can be configured to have a robust power-hit-safe cleanup *		mechanism which requires a significant amount of flash, or a simple, *		non-power-hit-safe mechanism.  Both implementations are in tfsclean.c. * *	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. * *	Author:	Ed Sutter *	email:	esutter@lucent.com		(home: lesutter@worldnet.att.net) *	phone:	908-582-2351			(home: 908-889-5161) */#include "config.h"#include "cpu.h"#include "stddefs.h"#include "genlib.h"#include "tfs.h"#include "tfsdev.h"#include "flash.h"#if INCLUDE_TFSchar	*(*tfsGetAtime)(long,char *,int);long	(*tfsGetLtime)(void);void	(*tfsDocommand)(char *,int);TDEV	tfsDeviceTbl[TFSDEVTOT];TFILE	**tfsAlist;int		ScriptExitFlag;struct	tfsdat tfsSlots[TFS_MAXOPEN];long	tfsTrace;static long		tfsFmodCount;static int		tfsAlistSize, tfsOldDelFlagCheckActive;/* 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_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" },	{ 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 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((char *)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 (addrtosector((char *)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(&tfp->flags,&flags,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);	while(*fstr) {		tfp = tfsflgtbl;		while(tfp->sdesc) {			if (*fstr == tfp->sdesc) {				*flag |= tfp->flag;				break;			}			tfp++;		}		if (!tfp->flag)			return(TFSERR_BADFLAG);		fstr++;	}	return(TFS_OKAY);}/* validtfshdr(): *	Return 1 if the header pointed to by the incoming header pointer is valid. *	Else return 0.  The header crc is calculated based on the hdrcrc *	and next members of the structure being zero. *	Note that if the file is deleted, then just ignore the crc and return 1. */intvalidtfshdr(TFILE *hdr){	TFILE hdrcpy;	ulong hdrcrc;	/* A few quick checks... */	if (!hdr || hdr->hdrsize == ERASED16)		return(0);	/* Run a crc32 test...	 * The header crc was originally calculated (in tfsadd()) with the	 * header crc and next pointer nulled out; so a copy must be made and	 * these two fields cleared.  Also, note that the TFS_NSTALE and	 * TFS_ACTIVE flags are forced to be set in the copy.  This is done	 * because it is possible that either of these bits may have been 	 * cleared due to other TFS interaction; hence, they need to be set	 * prior to crc validateion.	 * Note also that earlier versions of TFS deleted a file by clearing	 * the entire flags field.  This made it impossible to do a header crc	 * check on a deleted file; deletion has been changed to simply clear	 * the TFS_ACTIVE bit in the flags, so now a deleted file's header can	 * can be crc tested by simply forcing the TFS_ACTIVE bit high as was	 * mentioned above.	 */	hdrcpy = *hdr;	hdrcrc = hdr->hdrcrc;	hdrcpy.next = 0;	hdrcpy.hdrcrc = 0;	hdrcpy.flags |= (TFS_NSTALE | TFS_ACTIVE);	if (crc32((uchar *)&hdrcpy,TFSHDRSIZ) == hdrcrc)		return(1);	else {		/* Support transition to new deletion flag method... */		if ((hdr->flags == 0) && tfsOldDelFlagCheckActive)			return(1);							printf("Bad TFS hdr crc @ 0x%lx\n",(ulong)hdr);		return(0);	}}/* nextfp(): *	Used as a common means of retrieving the next file header pointer.  It *	does some sanity checks based on the fact that all pointers must fall *	within the TFSSTART<->TFSEND memory range and since each file is placed *	just after the previous one in linear memory space, fp->next should *	always be greater than fp. */TFILE *nextfp(TFILE *fp, TDEV *tdp){	if (!tdp)		tdp = gettfsdev(fp);	/* Make some basic in-range checks... */	if ((!tdp) || (fp < (TFILE *)tdp->start) || (fp > (TFILE *)tdp->end) ||		(fp->next < (TFILE *)tdp->start) || (fp->next > (TFILE *)tdp->end)  ||		(fp->next <= fp)) {		printf("Bad TFS hdr ptr @ 0x%lx\n",(ulong)fp);		return(0);	}	return(fp->next);}/* tfsflasherased(): *	Jump to the point in flash after the last file in TFS, then verify *	that all remaining flash  that is dedicated to TFS is erased (0xff). *	If erased, return 1; else return 0. */inttfsflasherased(TDEV *tdp, int verbose){	ulong	*lp;	TFILE	*tfp;	tfp = (TFILE *)tdp->start;	while(validtfshdr(tfp))		tfp = nextfp(tfp,tdp);	lp = (ulong *)tfp;	while (lp < (ulong *)tdp->end) {		if (*lp != ERASED32) {			if (verbose)				printf("End of TFS on %s not erased at 0x%lx\n",					tdp->prefix,(ulong)lp);			return(0);		}#ifdef WATCHDOG_MACRO		WATCHDOG_MACRO();#endif		lp++;	}	return(1);}/* tfsmemuse(): *	Step through one (or all) TFS devices and tally up various memory usage *	totals.  See definition of tfsmem structure for more details. *	If incoming tdpin pointer is NULL, then tally up for all TFS devices; *	otherwise, tally up for only the one device pointed to by tdpin. */inttfsmemuse(TDEV *tdpin, TINFO *tinfo, int verbose){	int		devtot;	TFILE	*tfp;	TDEV	*tdp;	/* Start by clearing incoming structure... */	tinfo->pso = 0;	tinfo->sos = 0;	tinfo->memtot = 0;	tinfo->liveftot = 0;	tinfo->deadftot = 0;	tinfo->livedata = 0;	tinfo->deaddata = 0;	tinfo->liveovrhd = 0;	tinfo->deadovrhd = 0;	if (verbose) {		printf("TFS Memory Usage...\n     ");		printf(" name    start       end       spare     spsize  scnt type\n");	}	devtot = 0;	for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {		if (!tdpin || (tdpin == tdp)) {			devtot++;			tfp = (TFILE *)tdp->start;			if (verbose) {				printf("%10s: 0x%08lx|0x%08lx|0x%08lx|0x%06lx|%4ld|0x%lx\n",					tdp->prefix,(ulong)(tdp->start),(ulong)(tdp->end),					(ulong)(tdp->spare),tdp->sparesize,					tdp->sectorcount,(ulong)(tdp->devinfo));			}			tinfo->memtot += ((tdp->end - tdp->start) + 1) + tdp->sparesize;			tinfo->pso += (tdp->sectorcount * 4) + 16;			tinfo->sos += tdp->sparesize;			while(validtfshdr(tfp)) {				if (TFS_FILEEXISTS(tfp)) {					tinfo->liveftot++;					tinfo->livedata += TFS_SIZE(tfp);					tinfo->liveovrhd += (TFSHDRSIZ + sizeof(struct defraghdr));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -