forsyth20121205-174063a80cc13 years agoHistory
212 lines · 4.2 KB · C
RawDownload
#include "boot.h" typedef struct Flashdev Flashdev;struct Flashdev {	uchar*	base;	int	size;	uchar*	exec;	char*	config;	int	conflen;}; enum {	FLASHSEG = 256*1024,	CONFIGLIM = FLASHSEG,	BOOTOFF = FLASHSEG,	BOOTLEN = 3*FLASHSEG,	/* third segment might be filsys */	/* rest of flash is free */}; static Flashdev flash; /* * configuration data is written between the bootstrap and * the end of region 0. the region ends with allocation descriptors * of the following form: * * byte order is big endian * * the last valid region found that starts with the string "#plan9.ini\n" is plan9.ini */typedef struct Flalloc Flalloc;struct Flalloc {	ulong	check;	/* checksum of data, or ~0 */	ulong	base;	/* base of region; ~0 if unallocated, 0 if deleted */	uchar	len[3];	uchar	tag;		/* see below */	uchar	sig[4];}; enum {	/* tags */	Tdead=	0,	Tboot=	0x01,	/* space reserved for boot */	Tconf=	0x02,	/* configuration data */	Tnone=	0xFF, 	Noval=	~0,}; static char flashsig[] = {0xF1, 0xA5, 0x5A, 0x1F};static char conftag[] = "#plan9.ini\n"; static ulongchecksum(uchar* p, int n){	ulong s; 	for(s=0; --n >= 0;)		s += *p++;	return s;} static intvalidptr(Flalloc *ap, uchar *p){	return p > (uchar*)&end && p < (uchar*)ap;} static intflashcheck(Flalloc *ap, char **val, int *len){	uchar *base;	int n; 	if(ap->base == Noval || ap->base >= FLASHSEG || ap->tag == Tnone)		return 0;	base = flash.base+ap->base;	if(!validptr(ap, base))		return 0;	n = (((ap->len[0]<<8)|ap->len[1])<<8)|ap->len[2];	if(n == 0xFFFFFF)		n = 0;	if(n < 0)		return 0;	if(n > 0 && !validptr(ap, base+n-1))		return 0;	if(ap->check != Noval && checksum(base, n) != ap->check){		print("flash: bad checksum\n");		return 0;	}	*val = (char*)base;	*len = n;	return 1;} intflashinit(void){	int len;	char *val;	Flalloc *ap;	void *addr;	long mbytes;	char type[20]; 	flash.base = 0;	flash.exec = 0;	flash.size = 0;	if(archflashreset(type, &addr, &mbytes) < 0){		print("flash: flash not present or not enabled\n");	/* shouldn't happen */		return 0;	}	flash.size = mbytes;	flash.base = addr;	flash.exec = flash.base + BOOTOFF;	flash.config = nil;	flash.conflen = 0; 	for(ap = (Flalloc*)(flash.base+CONFIGLIM)-1; memcmp(ap->sig, flashsig, 4) == 0; ap--){		if(0)			print("conf #%8.8lux: #%x #%6.6lux\n", ap, ap->tag, ap->base);		if(ap->tag == Tconf &&		   flashcheck(ap, &val, &len) &&		   len >= sizeof(conftag)-1 &&		   memcmp(val, conftag, sizeof(conftag)-1) == 0){			flash.config = val;			flash.conflen = len;			if(0)				print("flash: found config %8.8lux(%d):\n%s\n", val, len, val);		}	}	if(flash.config == nil)		print("flash: no config\n");	else		print("flash config %8.8lux(%d):\n%s\n", flash.config, flash.conflen, flash.config);	if(issqueezed(flash.exec) == Q_MAGIC){		print("flash: squeezed powerpc kernel installed\n");		return 1<<0;	}	if(GLLONG(flash.exec) == Q_MAGIC){		print("flash: unsqueezed powerpc kernel installed\n");		return 1<<0;	}	flash.exec = 0;	print("flash: no powerpc kernel in Flash\n");	return 0;} char*flashconfig(int){	return flash.config;} intflashbootable(int){	return flash.exec != nil && (issqueezed(flash.exec) || GLLONG(flash.exec) == Q_MAGIC);} intflashboot(int){	ulong entry, addr;	void (*b)(void);	Exec *ep;	Block in;	long n;	uchar *p; 	if(flash.exec == 0)		return -1;	p = flash.exec;	if(GLLONG(p) == Q_MAGIC){		/* unsqueezed: copy data and perhaps text, then jump to it */		ep = (Exec*)p;		entry = PADDR(GLLONG(ep->entry));		p += sizeof(Exec);		addr = entry;		n = GLLONG(ep->text);		if(addr != (ulong)p){			memmove((void*)addr, p, n);			print("text: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);		}		p += n;		if(entry >= FLASHMEM)			addr = 3*BY2PG;	/* kernel text is in Flash, data in RAM */		else			addr = PGROUND(addr+n);		n = GLLONG(ep->data);		memmove((void*)addr, p, n);		print("data: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);	}else{		in.data = p;		in.rp = in.data;		in.lim = p+BOOTLEN;		in.wp = in.lim;		n = unsqueezef(&in, &entry);		if(n < 0)			return -1;	}	print("entry=0x%lux\n", entry);	uartwait();	scc2stop();	/*	 *  Go to new code. It's up to the program to get its PC relocated to	 *  the right place.	 */	b = (void (*)(void))KADDR(PADDR(entry));	(*b)();	return -1;}