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