xref: /inferno-os/os/boot/mpc/flash.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth #include "boot.h"
2*74a4d8c2SCharles.Forsyth 
3*74a4d8c2SCharles.Forsyth typedef struct Flashdev Flashdev;
4*74a4d8c2SCharles.Forsyth struct Flashdev {
5*74a4d8c2SCharles.Forsyth 	uchar*	base;
6*74a4d8c2SCharles.Forsyth 	int	size;
7*74a4d8c2SCharles.Forsyth 	uchar*	exec;
8*74a4d8c2SCharles.Forsyth 	char*	config;
9*74a4d8c2SCharles.Forsyth 	int	conflen;
10*74a4d8c2SCharles.Forsyth };
11*74a4d8c2SCharles.Forsyth 
12*74a4d8c2SCharles.Forsyth enum {
13*74a4d8c2SCharles.Forsyth 	FLASHSEG = 256*1024,
14*74a4d8c2SCharles.Forsyth 	CONFIGLIM = FLASHSEG,
15*74a4d8c2SCharles.Forsyth 	BOOTOFF = FLASHSEG,
16*74a4d8c2SCharles.Forsyth 	BOOTLEN = 3*FLASHSEG,	/* third segment might be filsys */
17*74a4d8c2SCharles.Forsyth 	/* rest of flash is free */
18*74a4d8c2SCharles.Forsyth };
19*74a4d8c2SCharles.Forsyth 
20*74a4d8c2SCharles.Forsyth static Flashdev flash;
21*74a4d8c2SCharles.Forsyth 
22*74a4d8c2SCharles.Forsyth /*
23*74a4d8c2SCharles.Forsyth  * configuration data is written between the bootstrap and
24*74a4d8c2SCharles.Forsyth  * the end of region 0. the region ends with allocation descriptors
25*74a4d8c2SCharles.Forsyth  * of the following form:
26*74a4d8c2SCharles.Forsyth  *
27*74a4d8c2SCharles.Forsyth  * byte order is big endian
28*74a4d8c2SCharles.Forsyth  *
29*74a4d8c2SCharles.Forsyth  * the last valid region found that starts with the string "#plan9.ini\n" is plan9.ini
30*74a4d8c2SCharles.Forsyth  */
31*74a4d8c2SCharles.Forsyth typedef struct Flalloc Flalloc;
32*74a4d8c2SCharles.Forsyth struct Flalloc {
33*74a4d8c2SCharles.Forsyth 	ulong	check;	/* checksum of data, or ~0 */
34*74a4d8c2SCharles.Forsyth 	ulong	base;	/* base of region; ~0 if unallocated, 0 if deleted */
35*74a4d8c2SCharles.Forsyth 	uchar	len[3];
36*74a4d8c2SCharles.Forsyth 	uchar	tag;		/* see below */
37*74a4d8c2SCharles.Forsyth 	uchar	sig[4];
38*74a4d8c2SCharles.Forsyth };
39*74a4d8c2SCharles.Forsyth 
40*74a4d8c2SCharles.Forsyth enum {
41*74a4d8c2SCharles.Forsyth 	/* tags */
42*74a4d8c2SCharles.Forsyth 	Tdead=	0,
43*74a4d8c2SCharles.Forsyth 	Tboot=	0x01,	/* space reserved for boot */
44*74a4d8c2SCharles.Forsyth 	Tconf=	0x02,	/* configuration data */
45*74a4d8c2SCharles.Forsyth 	Tnone=	0xFF,
46*74a4d8c2SCharles.Forsyth 
47*74a4d8c2SCharles.Forsyth 	Noval=	~0,
48*74a4d8c2SCharles.Forsyth };
49*74a4d8c2SCharles.Forsyth 
50*74a4d8c2SCharles.Forsyth static char flashsig[] = {0xF1, 0xA5, 0x5A, 0x1F};
51*74a4d8c2SCharles.Forsyth static char conftag[] = "#plan9.ini\n";
52*74a4d8c2SCharles.Forsyth 
53*74a4d8c2SCharles.Forsyth static ulong
checksum(uchar * p,int n)54*74a4d8c2SCharles.Forsyth checksum(uchar* p, int n)
55*74a4d8c2SCharles.Forsyth {
56*74a4d8c2SCharles.Forsyth 	ulong s;
57*74a4d8c2SCharles.Forsyth 
58*74a4d8c2SCharles.Forsyth 	for(s=0; --n >= 0;)
59*74a4d8c2SCharles.Forsyth 		s += *p++;
60*74a4d8c2SCharles.Forsyth 	return s;
61*74a4d8c2SCharles.Forsyth }
62*74a4d8c2SCharles.Forsyth 
63*74a4d8c2SCharles.Forsyth static int
validptr(Flalloc * ap,uchar * p)64*74a4d8c2SCharles.Forsyth validptr(Flalloc *ap, uchar *p)
65*74a4d8c2SCharles.Forsyth {
66*74a4d8c2SCharles.Forsyth 	return p > (uchar*)&end && p < (uchar*)ap;
67*74a4d8c2SCharles.Forsyth }
68*74a4d8c2SCharles.Forsyth 
69*74a4d8c2SCharles.Forsyth static int
flashcheck(Flalloc * ap,char ** val,int * len)70*74a4d8c2SCharles.Forsyth flashcheck(Flalloc *ap, char **val, int *len)
71*74a4d8c2SCharles.Forsyth {
72*74a4d8c2SCharles.Forsyth 	uchar *base;
73*74a4d8c2SCharles.Forsyth 	int n;
74*74a4d8c2SCharles.Forsyth 
75*74a4d8c2SCharles.Forsyth 	if(ap->base == Noval || ap->base >= FLASHSEG || ap->tag == Tnone)
76*74a4d8c2SCharles.Forsyth 		return 0;
77*74a4d8c2SCharles.Forsyth 	base = flash.base+ap->base;
78*74a4d8c2SCharles.Forsyth 	if(!validptr(ap, base))
79*74a4d8c2SCharles.Forsyth 		return 0;
80*74a4d8c2SCharles.Forsyth 	n = (((ap->len[0]<<8)|ap->len[1])<<8)|ap->len[2];
81*74a4d8c2SCharles.Forsyth 	if(n == 0xFFFFFF)
82*74a4d8c2SCharles.Forsyth 		n = 0;
83*74a4d8c2SCharles.Forsyth 	if(n < 0)
84*74a4d8c2SCharles.Forsyth 		return 0;
85*74a4d8c2SCharles.Forsyth 	if(n > 0 && !validptr(ap, base+n-1))
86*74a4d8c2SCharles.Forsyth 		return 0;
87*74a4d8c2SCharles.Forsyth 	if(ap->check != Noval && checksum(base, n) != ap->check){
88*74a4d8c2SCharles.Forsyth 		print("flash: bad checksum\n");
89*74a4d8c2SCharles.Forsyth 		return 0;
90*74a4d8c2SCharles.Forsyth 	}
91*74a4d8c2SCharles.Forsyth 	*val = (char*)base;
92*74a4d8c2SCharles.Forsyth 	*len = n;
93*74a4d8c2SCharles.Forsyth 	return 1;
94*74a4d8c2SCharles.Forsyth }
95*74a4d8c2SCharles.Forsyth 
96*74a4d8c2SCharles.Forsyth int
flashinit(void)97*74a4d8c2SCharles.Forsyth flashinit(void)
98*74a4d8c2SCharles.Forsyth {
99*74a4d8c2SCharles.Forsyth 	int len;
100*74a4d8c2SCharles.Forsyth 	char *val;
101*74a4d8c2SCharles.Forsyth 	Flalloc *ap;
102*74a4d8c2SCharles.Forsyth 	void *addr;
103*74a4d8c2SCharles.Forsyth 	long mbytes;
104*74a4d8c2SCharles.Forsyth 	char type[20];
105*74a4d8c2SCharles.Forsyth 
106*74a4d8c2SCharles.Forsyth 	flash.base = 0;
107*74a4d8c2SCharles.Forsyth 	flash.exec = 0;
108*74a4d8c2SCharles.Forsyth 	flash.size = 0;
109*74a4d8c2SCharles.Forsyth 	if(archflashreset(type, &addr, &mbytes) < 0){
110*74a4d8c2SCharles.Forsyth 		print("flash: flash not present or not enabled\n");	/* shouldn't happen */
111*74a4d8c2SCharles.Forsyth 		return 0;
112*74a4d8c2SCharles.Forsyth 	}
113*74a4d8c2SCharles.Forsyth 	flash.size = mbytes;
114*74a4d8c2SCharles.Forsyth 	flash.base = addr;
115*74a4d8c2SCharles.Forsyth 	flash.exec = flash.base + BOOTOFF;
116*74a4d8c2SCharles.Forsyth 	flash.config = nil;
117*74a4d8c2SCharles.Forsyth 	flash.conflen = 0;
118*74a4d8c2SCharles.Forsyth 
119*74a4d8c2SCharles.Forsyth 	for(ap = (Flalloc*)(flash.base+CONFIGLIM)-1; memcmp(ap->sig, flashsig, 4) == 0; ap--){
120*74a4d8c2SCharles.Forsyth 		if(0)
121*74a4d8c2SCharles.Forsyth 			print("conf #%8.8lux: #%x #%6.6lux\n", ap, ap->tag, ap->base);
122*74a4d8c2SCharles.Forsyth 		if(ap->tag == Tconf &&
123*74a4d8c2SCharles.Forsyth 		   flashcheck(ap, &val, &len) &&
124*74a4d8c2SCharles.Forsyth 		   len >= sizeof(conftag)-1 &&
125*74a4d8c2SCharles.Forsyth 		   memcmp(val, conftag, sizeof(conftag)-1) == 0){
126*74a4d8c2SCharles.Forsyth 			flash.config = val;
127*74a4d8c2SCharles.Forsyth 			flash.conflen = len;
128*74a4d8c2SCharles.Forsyth 			if(0)
129*74a4d8c2SCharles.Forsyth 				print("flash: found config %8.8lux(%d):\n%s\n", val, len, val);
130*74a4d8c2SCharles.Forsyth 		}
131*74a4d8c2SCharles.Forsyth 	}
132*74a4d8c2SCharles.Forsyth 	if(flash.config == nil)
133*74a4d8c2SCharles.Forsyth 		print("flash: no config\n");
134*74a4d8c2SCharles.Forsyth 	else
135*74a4d8c2SCharles.Forsyth 		print("flash config %8.8lux(%d):\n%s\n", flash.config, flash.conflen, flash.config);
136*74a4d8c2SCharles.Forsyth 	if(issqueezed(flash.exec) == Q_MAGIC){
137*74a4d8c2SCharles.Forsyth 		print("flash: squeezed powerpc kernel installed\n");
138*74a4d8c2SCharles.Forsyth 		return 1<<0;
139*74a4d8c2SCharles.Forsyth 	}
140*74a4d8c2SCharles.Forsyth 	if(GLLONG(flash.exec) == Q_MAGIC){
141*74a4d8c2SCharles.Forsyth 		print("flash: unsqueezed powerpc kernel installed\n");
142*74a4d8c2SCharles.Forsyth 		return 1<<0;
143*74a4d8c2SCharles.Forsyth 	}
144*74a4d8c2SCharles.Forsyth 	flash.exec = 0;
145*74a4d8c2SCharles.Forsyth 	print("flash: no powerpc kernel in Flash\n");
146*74a4d8c2SCharles.Forsyth 	return 0;
147*74a4d8c2SCharles.Forsyth }
148*74a4d8c2SCharles.Forsyth 
149*74a4d8c2SCharles.Forsyth char*
flashconfig(int)150*74a4d8c2SCharles.Forsyth flashconfig(int)
151*74a4d8c2SCharles.Forsyth {
152*74a4d8c2SCharles.Forsyth 	return flash.config;
153*74a4d8c2SCharles.Forsyth }
154*74a4d8c2SCharles.Forsyth 
155*74a4d8c2SCharles.Forsyth int
flashbootable(int)156*74a4d8c2SCharles.Forsyth flashbootable(int)
157*74a4d8c2SCharles.Forsyth {
158*74a4d8c2SCharles.Forsyth 	return flash.exec != nil && (issqueezed(flash.exec) || GLLONG(flash.exec) == Q_MAGIC);
159*74a4d8c2SCharles.Forsyth }
160*74a4d8c2SCharles.Forsyth 
161*74a4d8c2SCharles.Forsyth int
flashboot(int)162*74a4d8c2SCharles.Forsyth flashboot(int)
163*74a4d8c2SCharles.Forsyth {
164*74a4d8c2SCharles.Forsyth 	ulong entry, addr;
165*74a4d8c2SCharles.Forsyth 	void (*b)(void);
166*74a4d8c2SCharles.Forsyth 	Exec *ep;
167*74a4d8c2SCharles.Forsyth 	Block in;
168*74a4d8c2SCharles.Forsyth 	long n;
169*74a4d8c2SCharles.Forsyth 	uchar *p;
170*74a4d8c2SCharles.Forsyth 
171*74a4d8c2SCharles.Forsyth 	if(flash.exec == 0)
172*74a4d8c2SCharles.Forsyth 		return -1;
173*74a4d8c2SCharles.Forsyth 	p = flash.exec;
174*74a4d8c2SCharles.Forsyth 	if(GLLONG(p) == Q_MAGIC){
175*74a4d8c2SCharles.Forsyth 		/* unsqueezed: copy data and perhaps text, then jump to it */
176*74a4d8c2SCharles.Forsyth 		ep = (Exec*)p;
177*74a4d8c2SCharles.Forsyth 		entry = PADDR(GLLONG(ep->entry));
178*74a4d8c2SCharles.Forsyth 		p += sizeof(Exec);
179*74a4d8c2SCharles.Forsyth 		addr = entry;
180*74a4d8c2SCharles.Forsyth 		n = GLLONG(ep->text);
181*74a4d8c2SCharles.Forsyth 		if(addr != (ulong)p){
182*74a4d8c2SCharles.Forsyth 			memmove((void*)addr, p, n);
183*74a4d8c2SCharles.Forsyth 			print("text: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);
184*74a4d8c2SCharles.Forsyth 		}
185*74a4d8c2SCharles.Forsyth 		p += n;
186*74a4d8c2SCharles.Forsyth 		if(entry >= FLASHMEM)
187*74a4d8c2SCharles.Forsyth 			addr = 3*BY2PG;	/* kernel text is in Flash, data in RAM */
188*74a4d8c2SCharles.Forsyth 		else
189*74a4d8c2SCharles.Forsyth 			addr = PGROUND(addr+n);
190*74a4d8c2SCharles.Forsyth 		n = GLLONG(ep->data);
191*74a4d8c2SCharles.Forsyth 		memmove((void*)addr, p, n);
192*74a4d8c2SCharles.Forsyth 		print("data: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);
193*74a4d8c2SCharles.Forsyth 	}else{
194*74a4d8c2SCharles.Forsyth 		in.data = p;
195*74a4d8c2SCharles.Forsyth 		in.rp = in.data;
196*74a4d8c2SCharles.Forsyth 		in.lim = p+BOOTLEN;
197*74a4d8c2SCharles.Forsyth 		in.wp = in.lim;
198*74a4d8c2SCharles.Forsyth 		n = unsqueezef(&in, &entry);
199*74a4d8c2SCharles.Forsyth 		if(n < 0)
200*74a4d8c2SCharles.Forsyth 			return -1;
201*74a4d8c2SCharles.Forsyth 	}
202*74a4d8c2SCharles.Forsyth 	print("entry=0x%lux\n", entry);
203*74a4d8c2SCharles.Forsyth 	uartwait();
204*74a4d8c2SCharles.Forsyth 	scc2stop();
205*74a4d8c2SCharles.Forsyth 	/*
206*74a4d8c2SCharles.Forsyth 	 *  Go to new code. It's up to the program to get its PC relocated to
207*74a4d8c2SCharles.Forsyth 	 *  the right place.
208*74a4d8c2SCharles.Forsyth 	 */
209*74a4d8c2SCharles.Forsyth 	b = (void (*)(void))KADDR(PADDR(entry));
210*74a4d8c2SCharles.Forsyth 	(*b)();
211*74a4d8c2SCharles.Forsyth 	return -1;
212*74a4d8c2SCharles.Forsyth }
213