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