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

📄 devflash.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	FlashRegion *r;	Flash *flash;	flash = findflash(addr);	if (flash == nil)		error(Ebadarg);	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(Flash *flash, 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(Flash *flash, 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;	Flash *flash;	if(fp == nil)		panic("flashctlwrite");	flash = fp->flash;	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(flash, off))				error("erase must be a block boundary");			bootprotect(off);			(*flash->alg->erase)(flash, off);			break;		case 1:			/* erase the whole partition */			bootprotect(fp->start);			for(off = fp->start; off < fp->end; off = blockend(flash, off))				(*flash->alg->erase)(flash, 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;	} else		error(Ebadarg);	poperror();	wunlock(flash);	free(cmd);	return n;}static longflashdatawrite(FPart *fp, uchar *p, long n, long off){	uchar *end;	int m;	int on;	long ooff;	uchar *buf;	Flash *flash;	if(fp == nil)		panic("flashdatawrite");	flash = fp->flash;	buf = nil;	wlock(flash);	if(waserror()){		wunlock(flash);		if(buf != nil)			free(buf);		nexterror();	}	if(fp->name == nil)		error("partition vanished");	if(!iseve())		error(Eperm);	/* can't cross partition boundaries */	off += fp->start;	if(off >= fp->end || off+n > fp->end || n <= 0)		error(Ebadarg);	/* make sure we're not writing the boot sector */	bootprotect(off);	on = n;	/*	 *  get the data into kernel memory to avoid faults during writing.	 *  if write is not on a quad boundary or not a multiple of 4 bytes,	 *  extend with data already in flash.	 */	buf = smalloc(n+8);	m = off & 3;	if(m){		*(ulong*)buf = flash->p[off>>Wshift];		n += m;		off -= m;	}	if(n & 3){		n -= n & 3;		*(ulong*)(&buf[n]) = flash->p[(off+n)>>Wshift];		n += 4;	}	memmove(&buf[m], p, on);	/* (*flash->alg->write) can't cross blocks */	ooff = off;	p = buf;	for(end = p + n; p < end; p += m){		m = blockend(flash, off) - off;		if(m > end - p)			m = end - p;		if(m > Maxwchunk)			m = Maxwchunk;		(*flash->alg->write)(flash, p, m, off);		off += m;	}	/* make sure write succeeded */	if(memcmp(buf, &flash->p[ooff>>Wshift], n) != 0)		error("written bytes don't match");	wunlock(flash);	free(buf);	poperror();	return on;}static long	 flashwrite(Chan* c, void* a, long n, vlong off){	int t;	if(c->qid.type == QTDIR)		error(Eperm);	if(!iseve())		error(Eperm);	t = FTYPE(c->qid.path);	switch(t){	default:		panic("flashwrite");	case Qfctl:		n = flashctlwrite(FPART(c->qid.path), a, n);		break;	case Qfdata:		n = flashdatawrite(FPART(c->qid.path), a, n, off);		break;	}	return n;}Dev flashdevtab = {	'F',	"flash",	devreset,	flashinit,	devshutdown,	flashattach,	flashwalk,	flashstat,	flashopen,	devcreate,	flashclose,	flashread,	devbread,	flashwrite,	devbwrite,	devremove,	devwstat,};enum{	/* status register */	ISEs_lockerr=		1<<1,	ISEs_powererr=		1<<3,	ISEs_progerr=		1<<4,	ISEs_eraseerr=		1<<5,	ISEs_ready=		1<<7,	ISEs_err= (ISEs_lockerr|ISEs_powererr|ISEs_progerr|ISEs_eraseerr),	/* extended status register */	ISExs_bufavail=		1<<7,};/* intel/sharp extended command set */static voidise_reset(Flash* flash){	flash->p[reg(0xaa)] = mirror(0xff);	/* reset */}static voidise_id(Flash* flash){	ise_reset(flash);	flash->p[reg(0xaaa)] = mirror(0x90);	/* uncover vendor info */	flash->manid = fromendian(flash->p[reg(0x0)]);	flash->devid = fromendian(flash->p[reg(0x1)]);	ise_reset(flash);}static voidise_clearerror(Flash* flash){	flash->p[reg(0x200)] = mirror(0x50);}static voidise_error(int bank, ulong status){	char err[64];	if(status & (ISEs_lockerr)){		sprint(err, "flash%d: block locked %lux", bank, status);		error(err);	}	if(status & (ISEs_powererr)){		sprint(err, "flash%d: low prog voltage %lux", bank, status);		error(err);	}	if(status & (ISEs_progerr|ISEs_eraseerr)){		sprint(err, "flash%d: i/o error %lux", bank, status);		error(err);	}}static voidise_erase(Flash *flash, ulong addr){	ulong start;	ulong x;	addr >>= Wshift;	flashprogpower(1);	flash->p[addr] = mirror(0x20);	flash->p[addr] = mirror(0xd0);	start = m->ticks;	do {		x = fromendian(flash->p[addr]);		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))			break;	} while(TK2MS(m->ticks-start) < 1500);	flashprogpower(0);	ise_clearerror(flash);	ise_error(0, x);	ise_error(1, x>>16);	ise_reset(flash);}/* *  the flash spec claimes writing goes faster if we use *  the write buffer.  We fill the write buffer and then *  issue the write request.  After the write request, *  subsequent reads will yield the status register. * *  returns the status, even on timeouts. * *  NOTE: I tried starting back to back buffered writes *	without reading the status in between, as the *	flowchart in the intel data sheet suggests. *	However, it always responded with an illegal *	command sequence, so I must be missing something. *	If someone learns better, please email me, though *	I doubt it will be much faster. -  presotto@bell-labs.com */static longise_wbwrite(Flash *flash, Fword *p, int n, ulong off, ulong baddr, ulong *status){	Fword x;	ulong start;	int i;	int s;	/* put flash into write buffer mode */	start = m->ticks;	for(;;) {		s = splhi();		/* request write buffer mode */		flash->p[baddr] = mirror(0xe8);		/* look at extended status reg for status */		if((flash->p[baddr] & mirror(1<<7)) == mirror(1<<7))			break;		splx(s);		/* didn't work, keep trying for 2 secs */		if(TK2MS(m->ticks-start) > 2000){			/* set up to read status */			flash->p[baddr] = mirror(0x70);			*status = fromendian(flash->p[baddr]);			pprint("write buffered cmd timed out\n");			return -1;		}	}	/* fill write buffer */	flash->p[baddr] = mirror(n-1);	for(i = 0; i < n; i++)		flash->p[off+i] = *p++;	/* program from buffer */	flash->p[baddr] = mirror(0xd0);	splx(s);	/* wait till the programming is done */	start = m->ticks;	for(;;) {		x = flash->p[baddr];	/* read status register */		*status = fromendian(x);		if((x & mirror(ISEs_ready)) == mirror(ISEs_ready))			break;		if(TK2MS(m->ticks-start) > 2000){			pprint("read status timed out\n");			return -1;		}	}	if(x & mirror(ISEs_err))		return -1;	return n;}static voidise_write(Flash *flash, void *a, long n, ulong off){	Fword *p, *end;	int i, wbsize;	ulong x, baddr; 	/* everything in terms of Fwords */	wbsize = flash->wbsize >> Wshift;	baddr = blockstart(flash, off) >> Wshift;	off >>= Wshift;	n >>= Wshift;	p = a;	/* first see if write will succeed */	for(i = 0; i < n; i++)		if((p[i] & flash->p[off+i]) != p[i])			error("flash needs erase");	if(waserror()){		ise_reset(flash);		flashprogpower(0);		nexterror();	}	flashprogpower(1);	/*	 *  use the first write to reach 	 *  a write buffer boundary.  the intel maunal	 *  says writes starting at wb boundaries	 *  maximize speed.	 */	i = wbsize - (off & (wbsize-1));	for(end = p + n; p < end;){		if(i > end - p)			i = end - p;		if(ise_wbwrite(flash, p, i, off, baddr, &x) < 0)			break;		off += i;		p += i;		i = wbsize;	}	ise_clearerror(flash);	ise_error(0, x);	ise_error(1, x>>16);	ise_reset(flash);	flashprogpower(0);	poperror();}/* amd/fujitsu standard command set *	I don't have an amd chipset to work with *	so I'm loathe to write this yet.  If someone *	else does, please send it to me and I'll *	incorporate it -- presotto@bell-labs.com */static voidafs_reset(Flash *flash){	flash->p[reg(0xaa)] = mirror(0xf0);	/* reset */}static voidafs_id(Flash *flash){	afs_reset(flash);	flash->p[reg(0xaa)] = mirror(0xf0);	/* reset */	flash->p[reg(0xaaa)] = mirror(0xaa);	/* query vendor block */	flash->p[reg(0x554)] = mirror(0x55);	flash->p[reg(0xaaa)] = mirror(0x90);	flash->manid = fromendian(flash->p[reg(0x00)]);	afs_reset(flash);	flash->p[reg(0xaaa)] = mirror(0xaa);	/* query vendor block */	flash->p[reg(0x554)] = mirror(0x55);	flash->p[reg(0xaaa)] = mirror(0x90);	flash->devid = fromendian(flash->p[reg(0x02)]);	afs_reset(flash);}static voidafs_erase(Flash*, ulong){	error("amd/fujistsu erase not implemented");}static voidafs_write(Flash*, void*, long, ulong){	error("amd/fujistsu write not implemented");}

⌨️ 快捷键说明

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