henesyinit from p9fd787fda5 years agoHistory
876 lines · 16.4 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"../port/error.h" /* *  on the bitsy, all 32 bit accesses to flash are mapped to two 16 bit *  accesses, one to the low half of the chip and the other to the high *  half.  Therefore for all command accesses, ushort indices in the *  manuals turn into ulong indices in our code.  Also, by copying all *  16 bit commands to both halves of a 32 bit command, we erase 2 *  sectors for each request erase request. */ #define mirror(x) (((x)<<16)|(x)) /* this defines a contiguous set of erase blocks of one size */typedef struct FlashRegion FlashRegion;struct FlashRegion{	ulong	addr;		/* start of region */	ulong	end;		/* end of region + 1 */	ulong	n;		/* number of blocks */	ulong	size;		/* size of each block */}; /* this defines a particular access algorithm */typedef struct FlashAlg FlashAlg;struct FlashAlg{	int	id;	char	*name;	void	(*identify)(void);	/* identify device */	void	(*erase)(ulong);	/* erase a region */	void	(*write)(void*, long, ulong);	/* write a region */}; static void	ise_id(void);static void	ise_erase(ulong);static void	ise_write(void*, long, ulong); static void	afs_id(void);static void	afs_erase(ulong);static void	afs_write(void*, long, ulong); static ulong	blockstart(ulong);static ulong	blockend(ulong); FlashAlg falg[] ={	{ 1,	"Intel/Sharp Extended",	ise_id, ise_erase, ise_write	},	{ 2,	"AMD/Fujitsu Standard",	afs_id, afs_erase, afs_write	},}; struct{	RWlock;	ulong		*p;	ushort		algid;		/* access algorithm */	FlashAlg	*alg;	ushort		manid;		/* manufacturer id */	ushort		devid;		/* device id */	ulong		size;		/* size in bytes */	int		wbsize;		/* size of write buffer */ 	ulong		nr;		/* number of regions */	uchar		bootprotect;	FlashRegion	r[32];} flash; enum{	Maxwchunk=	1024,	/* maximum chunk written by one call to falg->write */}; /* *  common flash interface */static ucharcfigetc(int off){	uchar rv; 	flash.p[0x55] = mirror(0x98);	rv = flash.p[off];	flash.p[0x55] = mirror(0xFF);	return rv;} static ushortcfigets(int off){	return (cfigetc(off+1)<<8)|cfigetc(off);} static ulongcfigetl(int off){	return (cfigetc(off+3)<<24)|(cfigetc(off+2)<<16)|		(cfigetc(off+1)<<8)|cfigetc(off);} static voidcfiquery(void){	uchar q, r, y;	ulong x, addr; 	q = cfigetc(0x10);	r = cfigetc(0x11);	y = cfigetc(0x12);	if(q != 'Q' || r != 'R' || y != 'Y'){		print("cfi query failed: %ux %ux %ux\n", q, r, y);		return;	}	flash.algid = cfigetc(0x13);	flash.size = 1<<(cfigetc(0x27)+1);	flash.wbsize = 1<<(cfigetc(0x2a)+1);	flash.nr = cfigetc(0x2c);	if(flash.nr > nelem(flash.r)){		print("cfi reports > %d regions\n", nelem(flash.r));		flash.nr = nelem(flash.r);	}	addr = 0;	for(q = 0; q < flash.nr; q++){		x = cfigetl(q+0x2d);		flash.r[q].size = 2*256*(x>>16);		flash.r[q].n = (x&0xffff)+1;		flash.r[q].addr = addr;		addr += flash.r[q].size*flash.r[q].n;		flash.r[q].end = addr;	}} /* *  flash device interface */ enum{	Qtopdir,	Q2nddir,	Qfctl,	Qfdata, 	Maxpart= 8,};  typedef struct FPart FPart;struct FPart{	char	*name;	char	*ctlname;	ulong	start;	ulong	end;};static FPart	part[Maxpart]; #define FQID(p,q)	((p)<<8|(q))#define FTYPE(q)	((q) & 0xff)#define FPART(q)	(&part[(q) >>8]) static intgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp){	Qid q;	FPart *fp; 	q.vers = 0; 	/* top level directory contains the name of the network */	if(c->qid.path == Qtopdir){		switch(i){		case DEVDOTDOT:			q.path = Qtopdir;			q.type = QTDIR;			devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);			break;		case 0:			q.path = Q2nddir;			q.type = QTDIR;			devdir(c, q, "flash", 0, eve, DMDIR|0555, dp);			break;		default:			return -1;		}		return 1;	} 	/* second level contains all partitions and their control files */	switch(i) {	case DEVDOTDOT:		q.path = Qtopdir;		q.type = QTDIR;		devdir(c, q, "#F", 0, eve, DMDIR|0555, dp);		break;	default:		if(i >= 2*Maxpart)			return -1;		fp = &part[i>>1];		if(fp->name == nil)			return 0;		if(i & 1){			q.path = FQID(i>>1, Qfdata);			q.type = QTFILE;			devdir(c, q, fp->name, fp->end-fp->start, eve, 0660, dp);		} else {			q.path = FQID(i>>1, Qfctl);			q.type = QTFILE;			devdir(c, q, fp->ctlname, 0, eve, 0660, dp);		}		break;	}	return 1;} static FPart*findpart(char *name){	int i; 	for(i = 0; i < Maxpart; i++)		if(part[i].name != nil && strcmp(name, part[i].name) == 0)			break;	if(i >= Maxpart)		return nil;	return &part[i];} static voidaddpart(FPart *fp, char *name, ulong start, ulong end){	int i;	char ctlname[64]; 	if(fp == nil){		if(start >= flash.size || end > flash.size)			error(Ebadarg);	} else {		start += fp->start;		end += fp->start;		if(start >= fp->end || end > fp->end)			error(Ebadarg);	}	if(blockstart(start) != start)		error("must start on erase boundary");	if(blockstart(end) != end && end != flash.size)		error("must end on erase boundary"); 	fp = findpart(name);	if(fp != nil)		error(Eexist);	for(i = 0; i < Maxpart; i++)		if(part[i].name == nil)			break;	if(i == Maxpart)		error("no more partitions");	fp = &part[i];	kstrdup(&fp->name, name);	snprint(ctlname, sizeof ctlname, "%sctl", name);	kstrdup(&fp->ctlname, ctlname);	fp->start = start;	fp->end = end;} static voidrempart(FPart *fp){	char *p, *cp; 	p = fp->name;	fp->name = nil;	cp = fp->ctlname;	fp->ctlname = nil;	free(p);	free(cp);} voidflashinit(void){	int i; 	flash.p = (ulong*)FLASHZERO;	cfiquery();	for(i = 0; i < nelem(falg); i++)		if(flash.algid == falg[i].id){			flash.alg = &falg[i];			(*flash.alg->identify)();			break;		}	flash.bootprotect = 1; 	addpart(nil, "flash", 0, flash.size);} static Chan*flashattach(char* spec){	return devattach('F', spec);} static Walkqid*flashwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, nil, 0, gen);} static int	 flashstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, nil, 0, gen);} static Chan*flashopen(Chan* c, int omode){	omode = openmode(omode);	if(strcmp(up->user, eve)!=0)		error(Eperm);	return devopen(c, omode, nil, 0, gen);} static void	 flashclose(Chan*){} static longflashctlread(FPart *fp, void* a, long n, vlong off){	char *buf, *p, *e;	int i;	ulong addr, end; 	buf = smalloc(1024);	e = buf + 1024;	p = seprint(buf, e, "0x%-9lux 0x%-9x 0x%-9ux 0x%-9ux\n", fp->end-fp->start,		flash.wbsize, flash.manid, flash.devid);	addr = fp->start;	for(i = 0; i < flash.nr && addr < fp->end; i++)		if(flash.r[i].addr <= addr && flash.r[i].end > addr){			if(fp->end <= flash.r[i].end)				end = fp->end;			else				end = flash.r[i].end;			p = seprint(p, e, "0x%-9lux 0x%-9lux 0x%-9lux\n", addr,				(end-addr)/flash.r[i].size, flash.r[i].size);			addr = end;		}	n = readstr(off, a, n, buf);	free(buf);	return n;} static longflashdataread(FPart *fp, void* a, long n, vlong off){	rlock(&flash);	if(waserror()){		runlock(&flash);		nexterror();	}	if(fp->name == nil)		error("partition vanished");	if(!iseve())		error(Eperm);	off += fp->start;	if(off >= fp->end)		n = 0;	if(off+n >= fp->end)		n = fp->end - off;	if(n > 0)		memmove(a, ((uchar*)FLASHZERO)+off, n);	runlock(&flash);	poperror(); 	return n;} static long	 flashread(Chan* c, void* a, long n, vlong off){	int t; 	if(c->qid.type == QTDIR)		return devdirread(c, a, n, nil, 0, gen);	t = FTYPE(c->qid.path);	switch(t){	default:		error(Eperm);	case Qfctl:		n = flashctlread(FPART(c->qid.path), a, n, off);		break;	case Qfdata:		n = flashdataread(FPART(c->qid.path), a, n, off);		break;	}	return n;} static voidbootprotect(ulong addr){	FlashRegion *r; 	if(flash.bootprotect == 0)		return;	if(flash.nr == 0)		error("writing over boot loader disallowed");	r = flash.r;	if(addr >= r->addr && addr < r->addr + r->size)		error("writing over boot loader disallowed");} static ulongblockstart(ulong addr){	FlashRegion *r, *e;	ulong x; 	r = flash.r;	for(e = &flash.r[flash.nr]; r < e; r++)		if(addr >= r->addr && addr < r->end){			x = addr - r->addr;			x /= r->size;			return r->addr + x*r->size;		}				return (ulong)-1;} static ulongblockend(ulong addr){	FlashRegion *r, *e;	ulong x; 	r = flash.r;	for(e = &flash.r[flash.nr]; r < e; r++)		if(addr >= r->addr && addr < r->end){			x = addr - r->addr;			x /= r->size;			return r->addr + (x+1)*r->size;		}				return (ulong)-1;} static longflashctlwrite(FPart *fp, char *p, long n){	Cmdbuf *cmd;	ulong off; 	if(fp == nil)		panic("flashctlwrite"); 	cmd = parsecmd(p, n);	wlock(&flash);	if(waserror()){		wunlock(&flash);		nexterror();	}	if(strcmp(cmd->f[0], "erase") == 0){		switch(cmd->nf){		case 2:			/* erase a single block in the partition */			off = atoi(cmd->f[1]);			off += fp->start;			if(off >= fp->end)				error("region not in partition");			if(off != blockstart(off))				error("erase must be a block boundary");			bootprotect(off);			(*flash.alg->erase)(off);			break;		case 1:			/* erase the whole partition */			bootprotect(fp->start);			for(off = fp->start; off < fp->end; off = blockend(off))				(*flash.alg->erase)(off);			break;		default:			error(Ebadarg);		}	} else if(strcmp(cmd->f[0], "add") == 0){		if(cmd->nf != 4)			error(Ebadarg);		addpart(fp, cmd->f[1], strtoul(cmd->f[2], nil, 0), strtoul(cmd->f[3], nil, 0));	} else if(strcmp(cmd->f[0], "remove") == 0){		rempart(fp);	} else if(strcmp(cmd->f[0], "protectboot") == 0){		if(cmd->nf == 0 || strcmp(cmd->f[1], "off") != 0)			flash.bootprotect = 1;		else			flash.bootprotect = 0;

Lines 1–500 of 876.