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