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

📄 flash.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* flash.c:
 *	This file contains the portions of the flash code that are device
 *	independent.  Refer to the appropriate device sub-directory for the
 *	code that is specific to the flash device on the target.
 *
 *	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"
#if INCLUDE_FLASH
#include "cpu.h"
#include "flash.h"
#include "genlib.h"
#include "ctype.h"
#include "stddefs.h"
#include "tfs.h"
#include "tfsprivate.h"
#include "cli.h"

extern struct flashdesc FlashNamId[];

int		FlashTrace = 1;
int		FlashCurrentBank;
char 	*boot_device_name;
int		sectortoaddr(int,int *,uchar **);

#define	SRANGE_ERROR	-1
#define	SRANGE_SINGLE	1
#define	SRANGE_RANGE	2
#define	SRANGE_ALL		3
	
/* FlashProtectWindow:
 *	Must be set to allow any flash operation to be done on space assumed
 *	to be software protected.
 */
int FlashProtectWindow;

/* FlashBank[]:
 *	This table contains all of the information that is needed to keep the
 *	flash code somewhat generic across multiple flash devices.
 */
struct	flashinfo FlashBank[FLASHBANKS];

#ifdef DISABLE_INTERRUPTS_DURING_FLASHOPS
#define FLASH_INTSOFF()				intsoff()
#define FLASH_INTSRESTORE(ival)		intsrestore(ival)
#else
#define FLASH_INTSOFF()				0
#define FLASH_INTSRESTORE(ival)
#endif

/* showlockop():
 * Return a string that verbosely represents the flash lock
 * operation...
 */
char *
showlockop(int operation)
{
	switch(operation) {
		case FLASH_LOCK:
			return("lock");
		case FLASH_UNLOCK:
			return("unlock");
		case FLASH_LOCKDWN:
			return("lock_down");
		case FLASH_LOCKQRY:
			return("lock_qry");
		case FLASH_LOCKABLE:
			return("lockable");
		default:
			return("???");
	}
}

/* showflashtype():
 *	Find a match between the incoming id and an entry in the FlashNamId[]
 *	table.  The FlashNamId[] table is part of the device-specific code.
 */
int
showflashtype(ulong id, int showid)
{
	struct flashdesc *fdp;

	if (showid)
		printf("Flash ID: 0x%lx\n",id);

	fdp = FlashNamId;
	while(fdp->desc) {
		if (id == fdp->id) {
			printf("Device = %s\n",fdp->desc);
			return(0);
		}
		fdp++;
	}
	if (id == FLASHRAM) {
		printf("Device = FLASH-RAM\n");
		return(0);
	}
	printf("Flash id 0x%lx not recognized\n",id);
	return(-1);
}

void
showflashtotal(void)
{
#if FLASHBANKS > 1
	printf("Total of %d banks (0-%d), current default bank: %d\n",
		FLASHBANKS,FLASHBANKS-1,FlashCurrentBank);
#else
	printf("Current flash bank: 0\n");
#endif
}

/* showflashinfo():
 * Dump information about specified flash device.
 */
int
showflashinfo(char *range)
{
	uchar	*base;
	struct	sectorinfo *sp;
	struct	flashinfo *fdev;
	int		first_sector_of_device;
	int		rc, locksupported, sector, lastsector, hdrprinted;

	rc = 0;
	hdrprinted = 0;
	lastsector = lastflashsector();

	/* An incoming NULL range implies "any" sector...
	 */
	if (range == 0) {
		showflashtotal();
		range = "any";
	}

	/* Loop through all sectors on all devices, picking only those
	 * sectors that fall in the specified range. 
	 */
	for(sector = 0; sector <= lastsector; sector++) {
		if (!inRange(range,sector))
			continue;

		//if (!(fdev = snumtofdev(sector)))
		if (!(fdev = nametofdev(boot_device_name)))
			return(-1);

		first_sector_of_device = fdev->sectors[0].snum;

		if (flashlock(first_sector_of_device,FLASH_LOCKABLE) > 0)
			locksupported = 1;
		else
			locksupported = 0;

		/* If sector is first sector of a device, then print
		 * device info also...
		 */
		if ((sector == first_sector_of_device) && (!strcmp(range,"any"))) {
			if (showflashtype(fdev->id,0) < 0)
				return(-1);
			printf(" Bank width  : %d\n",fdev->width);
			printf(" Sectors     : %d\n",fdev->sectorcnt);
			printf(" Base addr   : 0x%08lx\n",(ulong)(fdev->base));
			hdrprinted = 0;
		}

		if (!hdrprinted) {
			printf(" Sctno    Begin       End         Size    %s  %s",
				"SWProt?",locksupported ? "  Locked?\n" : "\n");
			hdrprinted = 1;
		}

		sp = &fdev->sectors[sector - first_sector_of_device];
		sectortoaddr(sp->snum,0,base);
		if ((range == 0) || inRange(range,sp->snum)) {
			printf(" %3d   0x%08lx  0x%08lx  0x%06lx   %s",
				sp->snum,
			    (ulong)(sp->begin), (ulong)(sp->end), sp->size,
			    sp->protected ? "yes" : " no");
			if (locksupported) {
				switch(flashlock(sp->snum,FLASH_LOCKQRY)) {
					case -1:
						printf("???");
						break;
					case 1:
						printf("yes");
						break;
					case 0:
						printf(" no");
						break;
				}
			}
			printf("\n");
		}
	}
	return(0);
}

/* flashopload():
 *	Copy flash operation to ram space.  
 *	Note that this function assumes that cache is disabled at this point.
 *	This is important because we are copying text into bss space and if
 *	cache was on, there could be a coherency problem.
 */
int
flashopload(ulong *begin,ulong *end,ulong *copy,int size)
{
	volatile ulong	*bp;
	int	ret;

	/* Verify space availability: */
	if (((int)end - (int)begin) >= size) {
		printf("flashopload overflow ((0x%lx-0x%lx) > 0x%x)\n",
			(ulong)end,(ulong)begin,size);
		return(-1);
	}

	/* Initially fill the copy space with 0xff so that the space
	 * remaining is viewable...
	 */
	memset((char *)copy,0xff,size);

	ret = 0;
	/* Copy function() to RAM, then verify: */
	bp = begin;
	while(bp <= end) {
		*copy = *bp;
		if (*copy++ != *bp++) {
			printf("flashopload failed\n");
			ret = -1;
			break;
		}
	}

	return(ret);
}

/* flashtype():
 *	Use the device-specific function pointer to call the routine
 *	relocated to RAM space.
 */
int
flashtype(struct flashinfo *fdev)
{
	return(fdev->fltype(fdev));
}

/* flasherased():
 * Return 1 if range of memory is all 0xff; else 0.
 * Scan through the range of memory specified by begin-end (inclusive)
 * looking for anything that is not 0xff.  Do this in three sections so
 * that the pointers can be 4-byte aligned for the bulk of the comparison
 * range...
 * The beginning steps through as a char pointer until aligned on a 4-byte
 * boundary.  Then do ulong * comparisons until the just before the end
 * where we once again use char pointers to align on the last few
 * non-aligned bytes (if any).
 */
int
flasherased(uchar *begin, uchar *end)
{
	ulong *lp, *lp1, ltmp;
	uchar *data;

	/* If begin is greater than end, the range is illegal.  The only
	 * exception to this is the case where end may be zero.  This is
	 * considered an exception because in cases where we are dealing
	 * with the last sector of a device that sits at the end of memory
	 * space, the end point will wrap.
	 */
	if ((begin > end) && (end != 0)) {
		printf("flasherased(): bad range\n");
		return(0);
	}

	WATCHDOG_MACRO;

	/* Get pointers aligned so that we can do the bulk of the comparison
	 * with long pointers...
	 */
	 
	while(((long)(begin) & 3) && (begin <= end)) {
		//NorFlashRdData(begin,data,1);
		if (*data != 0xff)
			return(0);
		begin++;
	}
	if (begin > end)
		return(1);

	lp = (ulong *)begin;
	ltmp = (ulong)end;
	ltmp &= ~3;
	lp1 = (ulong *)ltmp;

	while(lp != lp1) {
		if (*lp != 0xffffffff) 
			return(0);
		lp++;
	}
	if (lp > (ulong *)end)
		return(1);
	
	begin = (uchar *)lp;
	do {
		if (*begin != 0xff) 
			return(0);
	} while(begin++ != end);
	return(*end == 0xff);
}

/* flasherase():
 *	Use the device-specific function pointer to call the routine
 *	relocated to RAM space.
 *	Note that flasherase() is called with a sector number.  The sector
 *	number is relative to the entire system, not just the particular device.
 *	This means that if there is more than one flash device in the system that
 *	the actual sector number (relative to the device) may not be the same
 *	value.  This adjustment is made here so that the underlying code that is
 *	pumped into ram for execution does not have to be aware of this.
 * Return...
 *  1 if successful
 * -1 if failure
 *  0 if sector is protected or locked
 */
int
flasherase(int snum)
{
	uchar *tmp;
	ulong *base, *end;
	int	size, rc, dev_snum;
	struct flashinfo *fdev;
	struct sectorinfo *sinfo;

	if (FlashTrace)
		printf("flasherase(%d)\n",snum);
	//printf("deveice name : %s\n",);
	if (!(fdev = nametofdev(boot_device_name)))
		return(-1);
	/* If the sector is soft-protected or locked, return negative
	 * and print failure.  If the sector is already erased, then
	 * there is no need to issue the device-specific erase algorithm.
	 */
	if(snum > fdev->sectorcnt)
	{
		printf("sector number out of range!\n");
		return -1;
	}
	//dev_snum = snum - fdev->sectors[0].snum;
	sinfo = &fdev->sectors[snum];
	//if (!flasherased(sinfo->begin,sinfo->end)) {
	if ((!FlashProtectWindow) && (sinfo->protected)) {
		printf("Sector %d protected\n",snum);
		return(0);
	}
	if (flashlocked(snum,1)) 
		return(0);
	rc = fdev->flerase(fdev,snum);
	if (rc < 0)
		return(rc);
	//}
	return(1);
}


/* flashwrite():
 *	Use the device-specific function pointer to call the routine
 *	relocated to RAM space.
 *	First make a few checks on the request, then write to flash if all
 *	checks succeed.
 */
int
flashwrite(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt)
{
	int	j, lowsector, highsector, rc, first_sector_of_device;
	register uchar	*dp, *sp, *edp;

	if (FlashTrace)
		printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);

	dp = dest;
	sp = src;
	edp = (dest + bytecnt) - 1;
	first_sector_of_device = fdev->sectors[0].snum;

	// If outside the devices space, return failed.. 
	if ((edp < fdev->sectors[0].begin) ||
	    (dp > fdev->sectors[fdev->sectorcnt-1].end)) {
		printf("flashwrite() failed: dest out of flash range\n");
		return(-1);
	}

	// Make sure the destination is not within a protected sector
	if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) {

		// First determine the sectors that overlap with the
		// flash space to be written...
		 //

		lowsector = highsector = -1;
		for(j=0;j<fdev->sectorcnt;j++) {
			if ((dp >= fdev->sectors[j].begin) &&
			    (dp <= fdev->sectors[j].end))
				lowsector = j;
		}
		for(j=0;j<fdev->sectorcnt;j++) {
			if ((edp >= fdev->sectors[j].begin) &&
			    (edp <= fdev->sectors[j].end))
				highsector = j;
		}
		if ((lowsector == -1) || (highsector == -1)) {
			printf("flashwrite() failed: can't find sector\n");
			return(-1);
		}

		// Now that the range of affected sectors is known,
		// verify that those sectors are not protected or locked...
		//
		for(j=lowsector;j<=highsector;j++) {
			if (fdev->sectors[j].protected) {
				printf("flashwrite() failed: sector protected\n");
				return(-1);
			}
			if (flashlocked(j+first_sector_of_device,1))
				return(-1);
		}
	}


	rc = fdev->flwrite(fdev,dest,src,bytecnt);
	if (rc < 0)
		return(rc);

	// Assuming everything else appears to have passed, make sure the
	 // source and destination addresses match...
	return(0);
}


/* flashread():
 *	Use the device-specific function pointer to call the routine
 *	relocated to RAM space.
 *	First make a few checks on the request, then write to flash if all
 *	checks succeed.
 */
int
flashread(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt)
{
	int	j, lowsector, highsector, rc, first_sector_of_device;
	register uchar	*dp, *sp, *edp;

	if (FlashTrace)
		printf("flashread(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);

	dp = src;
	sp = dest;
	edp = (src + bytecnt) - 1;
	first_sector_of_device = fdev->sectors[0].snum;

	// If outside the devices space, return failed.. 
	if ((edp < fdev->sectors[0].begin) ||
	    (dp > fdev->sectors[fdev->sectorcnt-1].end)) {
		printf("flashread() failed: srcout of flash range\n");
		return(-1);
	}

	// Make sure the destination is not within a protected sector
	printf("flashread :%s\n",fdev->device_name);
	rc = fdev->flread(fdev,dest,src,bytecnt);
	if (rc < 0)
		return(rc);

	// Assuming everything else appears to have passed, make sure the
	 // source and destination addresses match...
	return(0);
}

/* flashewrite():
 *	Use the device-specific function pointer to call the routine
 *	relocated to RAM space.
 */
int
flashewrite(uchar *dest,uchar *src,long bytecnt)
{
	int	i;
	struct flashinfo *fdev;

	if (FlashTrace)
		printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt);

	if ((fdev = addrtobank(dest)) == 0)
		return(-1);

	/* Source and destination addresses must be long-aligned. */
	if (((int)src & 3) || ((int)dest & 3))
		return(-1);

	/* If the protection window is closed, then verify that no protected
	 * sectors will be written over...
	 */
	if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) {
		for (i=0;i<fdev->sectorcnt;i++) {
			if((((uchar *)dest) > (fdev->sectors[i].end)) ||
			    (((uchar *)dest+bytecnt) < (fdev->sectors[i].begin)))
				continue;
			else
				if (fdev->sectors[i].protected)
					return(-1);
		}
	}
	return(fdev->flewrite(fdev,dest,src,bytecnt));
}

/* flashlock():
   Use a function pointer to call the routine relocated to RAM space.
*/
int
flashlock(int snum,int operation)
{
	int dev_snum;
	struct flashinfo *fdev;

	if (FlashTrace)
		printf("flashlock(%d,%s)\n",snum,showlockop(operation));

	fdev = snumtofdev(snum);
	dev_snum = snum - fdev->sectors[0].snum;
	return(fdev->fllock(fdev,dev_snum,operation));
}

int
flashlocked(int snum, int verbose)
{
	if ((flashlock(snum,FLASH_LOCKABLE) > 0) &&
		(flashlock(snum,FLASH_LOCKQRY) == 1)) {
			if (verbose)
				printf("Sector %d locked\n",snum);
			return(1);
	}
	return(0);
}

/* snumtofdev():
 * Return the flash device pointer that corresponds to the incoming
 * sector number.
 */
struct flashinfo *
snumtofdev(int snum)
{
	int dev;
	struct flashinfo *fbnk;

	fbnk = FlashBank;
	for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
		if ((snum >= fbnk->sectors[0].snum) &&
			(snum <= fbnk->sectors[fbnk->sectorcnt-1].snum))
			return(fbnk);
	}
	printf("snumtfdev(%d) failed\n",snum);
	return(0);
}

/* snumtofdev():
 * Return the flash device pointer that corresponds to the incoming
 * sector number.
 */
struct flashinfo *
nametofdev(char *device_name)
{
	int dev;
	struct flashinfo *fbnk;

	fbnk = FlashBank;
	for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
		if(strcmp(fbnk->device_name,device_name) == 0)
		{
			//printf("namettodev(%s) get bank,%s\n",device_name,fbnk->device_name);
			return(fbnk);
		}
	}
	printf("namettodev(%s) failed,no this device\n",device_name);
	return(0);
}
/* addrtosector():
 *	Incoming address is translated to sector number, size of sector
 *	and base of sector.
 *	Return 0 if successful; else -1.
 */
int
addrtosector(uchar *addr,int *sector,int *size,uchar **base)
{
	struct flashinfo *fbnk;
	struct	sectorinfo *sinfo;
	int		dev, sec, i;

	fbnk = FlashBank;
	sec = 0;
	for(dev=0;dev<FLASHBANKS;dev++,fbnk++) {
		for(i=0;i<fbnk->sectorcnt;i++,sec++) {
			sinfo = &fbnk->sectors[i];
			if ((addr >= sinfo->begin) && (addr <= sinfo->end)) {
				if (sector) {

⌨️ 快捷键说明

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