xref: /plan9-contrib/sys/src/nboot/efi/sub.c (revision 529c1f209803c78c4f2cda11b13818a57f01c872)
1*529c1f20SDavid du Colombier #include <u.h>
2*529c1f20SDavid du Colombier #include <a.out.h>
3*529c1f20SDavid du Colombier #include "fns.h"
4*529c1f20SDavid du Colombier #include "mem.h"
5*529c1f20SDavid du Colombier 
6*529c1f20SDavid du Colombier char hex[] = "0123456789abcdef";
7*529c1f20SDavid du Colombier 
8*529c1f20SDavid du Colombier void
print(char * s)9*529c1f20SDavid du Colombier print(char *s)
10*529c1f20SDavid du Colombier {
11*529c1f20SDavid du Colombier 	while(*s != 0){
12*529c1f20SDavid du Colombier 		if(*s == '\n')
13*529c1f20SDavid du Colombier 			putc('\r');
14*529c1f20SDavid du Colombier 		putc(*s++);
15*529c1f20SDavid du Colombier 	}
16*529c1f20SDavid du Colombier }
17*529c1f20SDavid du Colombier 
18*529c1f20SDavid du Colombier int
readn(void * f,void * data,int len)19*529c1f20SDavid du Colombier readn(void *f, void *data, int len)
20*529c1f20SDavid du Colombier {
21*529c1f20SDavid du Colombier 	uchar *p, *e;
22*529c1f20SDavid du Colombier 
23*529c1f20SDavid du Colombier 	p = data;
24*529c1f20SDavid du Colombier 	e = p + len;
25*529c1f20SDavid du Colombier 	while(p < e){
26*529c1f20SDavid du Colombier 		if((len = read(f, p, e - p)) <= 0)
27*529c1f20SDavid du Colombier 			break;
28*529c1f20SDavid du Colombier 		p += len;
29*529c1f20SDavid du Colombier 	}
30*529c1f20SDavid du Colombier 
31*529c1f20SDavid du Colombier 	return p - (uchar*)data;
32*529c1f20SDavid du Colombier }
33*529c1f20SDavid du Colombier 
34*529c1f20SDavid du Colombier void
memmove(void * dst,void * src,int n)35*529c1f20SDavid du Colombier memmove(void *dst, void *src, int n)
36*529c1f20SDavid du Colombier {
37*529c1f20SDavid du Colombier 	uchar *d = dst;
38*529c1f20SDavid du Colombier 	uchar *s = src;
39*529c1f20SDavid du Colombier 
40*529c1f20SDavid du Colombier 	if(d < s){
41*529c1f20SDavid du Colombier 		while(n-- > 0)
42*529c1f20SDavid du Colombier 			*d++ = *s++;
43*529c1f20SDavid du Colombier 	} else if(d > s){
44*529c1f20SDavid du Colombier 		s += n;
45*529c1f20SDavid du Colombier 		d += n;
46*529c1f20SDavid du Colombier 		while(n-- > 0)
47*529c1f20SDavid du Colombier 			*--d = *--s;
48*529c1f20SDavid du Colombier 	}
49*529c1f20SDavid du Colombier }
50*529c1f20SDavid du Colombier 
51*529c1f20SDavid du Colombier int
memcmp(void * src,void * dst,int n)52*529c1f20SDavid du Colombier memcmp(void *src, void *dst, int n)
53*529c1f20SDavid du Colombier {
54*529c1f20SDavid du Colombier 	uchar *d = dst;
55*529c1f20SDavid du Colombier 	uchar *s = src;
56*529c1f20SDavid du Colombier 	int r = 0;
57*529c1f20SDavid du Colombier 
58*529c1f20SDavid du Colombier 	while(n-- > 0){
59*529c1f20SDavid du Colombier 		r = *d++ - *s++;
60*529c1f20SDavid du Colombier 		if(r != 0)
61*529c1f20SDavid du Colombier 			break;
62*529c1f20SDavid du Colombier 	}
63*529c1f20SDavid du Colombier 
64*529c1f20SDavid du Colombier 	return r;
65*529c1f20SDavid du Colombier }
66*529c1f20SDavid du Colombier 
67*529c1f20SDavid du Colombier int
strlen(char * s)68*529c1f20SDavid du Colombier strlen(char *s)
69*529c1f20SDavid du Colombier {
70*529c1f20SDavid du Colombier 	char *p = s;
71*529c1f20SDavid du Colombier 
72*529c1f20SDavid du Colombier 	while(*p != '\0')
73*529c1f20SDavid du Colombier 		p++;
74*529c1f20SDavid du Colombier 
75*529c1f20SDavid du Colombier 	return p - s;
76*529c1f20SDavid du Colombier }
77*529c1f20SDavid du Colombier 
78*529c1f20SDavid du Colombier char*
strchr(char * s,int c)79*529c1f20SDavid du Colombier strchr(char *s, int c)
80*529c1f20SDavid du Colombier {
81*529c1f20SDavid du Colombier 	for(; *s != 0; s++)
82*529c1f20SDavid du Colombier 		if(*s == c)
83*529c1f20SDavid du Colombier 			return s;
84*529c1f20SDavid du Colombier 
85*529c1f20SDavid du Colombier 	return nil;
86*529c1f20SDavid du Colombier }
87*529c1f20SDavid du Colombier 
88*529c1f20SDavid du Colombier void
memset(void * dst,int v,int n)89*529c1f20SDavid du Colombier memset(void *dst, int v, int n)
90*529c1f20SDavid du Colombier {
91*529c1f20SDavid du Colombier 	uchar *d = dst;
92*529c1f20SDavid du Colombier 
93*529c1f20SDavid du Colombier 	while(n > 0){
94*529c1f20SDavid du Colombier 		*d++ = v;
95*529c1f20SDavid du Colombier 		n--;
96*529c1f20SDavid du Colombier 	}
97*529c1f20SDavid du Colombier }
98*529c1f20SDavid du Colombier 
99*529c1f20SDavid du Colombier static int
readline(void * f,char * buf)100*529c1f20SDavid du Colombier readline(void *f, char *buf)
101*529c1f20SDavid du Colombier {
102*529c1f20SDavid du Colombier 	static char white[] = "\t ";
103*529c1f20SDavid du Colombier 	char *p;
104*529c1f20SDavid du Colombier 
105*529c1f20SDavid du Colombier 	p = buf;
106*529c1f20SDavid du Colombier 	do{
107*529c1f20SDavid du Colombier 		if(f == nil)
108*529c1f20SDavid du Colombier 			putc('>');
109*529c1f20SDavid du Colombier 		for(;;){
110*529c1f20SDavid du Colombier 			if(f == nil){
111*529c1f20SDavid du Colombier 				while((*p = getc()) == 0)
112*529c1f20SDavid du Colombier 					;
113*529c1f20SDavid du Colombier 				if(p == buf && (*p == '\b' || strchr(white, *p) != nil))
114*529c1f20SDavid du Colombier 					continue;
115*529c1f20SDavid du Colombier 				putc(*p);
116*529c1f20SDavid du Colombier 				if(*p == '\r')
117*529c1f20SDavid du Colombier 					putc('\n');
118*529c1f20SDavid du Colombier 				else if(*p == '\b'){
119*529c1f20SDavid du Colombier 					p--;
120*529c1f20SDavid du Colombier 					putc(' ');
121*529c1f20SDavid du Colombier 					putc('\b');
122*529c1f20SDavid du Colombier 					continue;
123*529c1f20SDavid du Colombier 				}
124*529c1f20SDavid du Colombier 			}else if(read(f, p, 1) <= 0)
125*529c1f20SDavid du Colombier 				return 0;
126*529c1f20SDavid du Colombier 			if(strchr("\r\n", *p) != nil)
127*529c1f20SDavid du Colombier 				break;
128*529c1f20SDavid du Colombier 			if(p == buf && strchr(white, *p) != nil)
129*529c1f20SDavid du Colombier 				continue;	/* whitespace on start of line */
130*529c1f20SDavid du Colombier 			p++;
131*529c1f20SDavid du Colombier 		}
132*529c1f20SDavid du Colombier 		while(p > buf && strchr(white, p[-1]))
133*529c1f20SDavid du Colombier 			p--;
134*529c1f20SDavid du Colombier 	}while(p == buf);
135*529c1f20SDavid du Colombier 	*p = 0;
136*529c1f20SDavid du Colombier 
137*529c1f20SDavid du Colombier 	return p - buf;
138*529c1f20SDavid du Colombier }
139*529c1f20SDavid du Colombier 
140*529c1f20SDavid du Colombier static int
timeout(int ms)141*529c1f20SDavid du Colombier timeout(int ms)
142*529c1f20SDavid du Colombier {
143*529c1f20SDavid du Colombier 	while(ms > 0){
144*529c1f20SDavid du Colombier 		if(getc() != 0)
145*529c1f20SDavid du Colombier 			return 1;
146*529c1f20SDavid du Colombier 		usleep(100000);
147*529c1f20SDavid du Colombier 		ms -= 100;
148*529c1f20SDavid du Colombier 	}
149*529c1f20SDavid du Colombier 	return 0;
150*529c1f20SDavid du Colombier }
151*529c1f20SDavid du Colombier 
152*529c1f20SDavid du Colombier #define BOOTLINE	((char*)CONFADDR)
153*529c1f20SDavid du Colombier #define BOOTLINELEN	64
154*529c1f20SDavid du Colombier #define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
155*529c1f20SDavid du Colombier #define	BOOTARGSLEN	(4096-0x200-BOOTLINELEN)
156*529c1f20SDavid du Colombier 
157*529c1f20SDavid du Colombier char *confend;
158*529c1f20SDavid du Colombier 
159*529c1f20SDavid du Colombier static char*
getconf(char * s,char * buf)160*529c1f20SDavid du Colombier getconf(char *s, char *buf)
161*529c1f20SDavid du Colombier {
162*529c1f20SDavid du Colombier 	char *p, *e;
163*529c1f20SDavid du Colombier 	int n;
164*529c1f20SDavid du Colombier 
165*529c1f20SDavid du Colombier 	n = strlen(s);
166*529c1f20SDavid du Colombier 	for(p = BOOTARGS; p < confend; p = e+1){
167*529c1f20SDavid du Colombier 		for(e = p+1; e < confend; e++)
168*529c1f20SDavid du Colombier 			if(*e == '\n')
169*529c1f20SDavid du Colombier 				break;
170*529c1f20SDavid du Colombier 		if(memcmp(p, s, n) == 0){
171*529c1f20SDavid du Colombier 			p += n;
172*529c1f20SDavid du Colombier 			n = e - p;
173*529c1f20SDavid du Colombier 			buf[n] = 0;
174*529c1f20SDavid du Colombier 			memmove(buf, p, n);
175*529c1f20SDavid du Colombier 			return buf;
176*529c1f20SDavid du Colombier 		}
177*529c1f20SDavid du Colombier 	}
178*529c1f20SDavid du Colombier 	return nil;
179*529c1f20SDavid du Colombier }
180*529c1f20SDavid du Colombier 
181*529c1f20SDavid du Colombier static int
delconf(char * s)182*529c1f20SDavid du Colombier delconf(char *s)
183*529c1f20SDavid du Colombier {
184*529c1f20SDavid du Colombier 	char *p, *e;
185*529c1f20SDavid du Colombier 
186*529c1f20SDavid du Colombier 	for(p = BOOTARGS; p < confend; p = e){
187*529c1f20SDavid du Colombier 		for(e = p+1; e < confend; e++){
188*529c1f20SDavid du Colombier 			if(*e == '\n'){
189*529c1f20SDavid du Colombier 				e++;
190*529c1f20SDavid du Colombier 				break;
191*529c1f20SDavid du Colombier 			}
192*529c1f20SDavid du Colombier 		}
193*529c1f20SDavid du Colombier 		if(memcmp(p, s, strlen(s)) == 0){
194*529c1f20SDavid du Colombier 			memmove(p, e, confend - e);
195*529c1f20SDavid du Colombier 			confend -= e - p;
196*529c1f20SDavid du Colombier 			*confend = 0;
197*529c1f20SDavid du Colombier 			return 1;
198*529c1f20SDavid du Colombier 		}
199*529c1f20SDavid du Colombier 	}
200*529c1f20SDavid du Colombier 	return 0;
201*529c1f20SDavid du Colombier }
202*529c1f20SDavid du Colombier 
203*529c1f20SDavid du Colombier char*
configure(void * f,char * path)204*529c1f20SDavid du Colombier configure(void *f, char *path)
205*529c1f20SDavid du Colombier {
206*529c1f20SDavid du Colombier 	char *line, *kern, *s, *p;
207*529c1f20SDavid du Colombier 	int inblock, nowait, n;
208*529c1f20SDavid du Colombier 	static int once = 1;
209*529c1f20SDavid du Colombier 
210*529c1f20SDavid du Colombier 	if(once){
211*529c1f20SDavid du Colombier 		once = 0;
212*529c1f20SDavid du Colombier Clear:
213*529c1f20SDavid du Colombier 		memset(BOOTLINE, 0, BOOTLINELEN);
214*529c1f20SDavid du Colombier 
215*529c1f20SDavid du Colombier 		confend = BOOTARGS;
216*529c1f20SDavid du Colombier 		memset(confend, 0, BOOTARGSLEN);
217*529c1f20SDavid du Colombier 		eficonfig(&confend);
218*529c1f20SDavid du Colombier 	}
219*529c1f20SDavid du Colombier 	nowait = 1;
220*529c1f20SDavid du Colombier 	inblock = 0;
221*529c1f20SDavid du Colombier Loop:
222*529c1f20SDavid du Colombier 	while(readline(f, line = confend+1) > 0){
223*529c1f20SDavid du Colombier 		if(*line == 0 || strchr("#;=", *line) != nil)
224*529c1f20SDavid du Colombier 			continue;
225*529c1f20SDavid du Colombier 		if(*line == '['){
226*529c1f20SDavid du Colombier 			inblock = memcmp("[common]", line, 8) != 0;
227*529c1f20SDavid du Colombier 			continue;
228*529c1f20SDavid du Colombier 		}
229*529c1f20SDavid du Colombier 		if(memcmp("boot", line, 5) == 0){
230*529c1f20SDavid du Colombier 			nowait=1;
231*529c1f20SDavid du Colombier 			break;
232*529c1f20SDavid du Colombier 		}
233*529c1f20SDavid du Colombier 		if(memcmp("wait", line, 5) == 0){
234*529c1f20SDavid du Colombier 			nowait=0;
235*529c1f20SDavid du Colombier 			continue;
236*529c1f20SDavid du Colombier 		}
237*529c1f20SDavid du Colombier 		if(memcmp("show", line, 5) == 0){
238*529c1f20SDavid du Colombier 			print(BOOTARGS);
239*529c1f20SDavid du Colombier 			continue;
240*529c1f20SDavid du Colombier 		}
241*529c1f20SDavid du Colombier 		if(memcmp("clear", line, 5) == 0){
242*529c1f20SDavid du Colombier 			if(line[5] == '\0'){
243*529c1f20SDavid du Colombier 				print("ok\n");
244*529c1f20SDavid du Colombier 				goto Clear;
245*529c1f20SDavid du Colombier 			} else if(line[5] == ' ' && delconf(line+6))
246*529c1f20SDavid du Colombier 				print("ok\n");
247*529c1f20SDavid du Colombier 			continue;
248*529c1f20SDavid du Colombier 		}
249*529c1f20SDavid du Colombier 		if(inblock != 0 || (p = strchr(line, '=')) == nil)
250*529c1f20SDavid du Colombier 			continue;
251*529c1f20SDavid du Colombier 		*p++ = 0;
252*529c1f20SDavid du Colombier 		delconf(line);
253*529c1f20SDavid du Colombier 		s = confend;
254*529c1f20SDavid du Colombier 		memmove(confend, line, n = strlen(line)); confend += n;
255*529c1f20SDavid du Colombier 		*confend++ = '=';
256*529c1f20SDavid du Colombier 		memmove(confend, p, n = strlen(p)); confend += n;
257*529c1f20SDavid du Colombier 		*confend++ = '\n';
258*529c1f20SDavid du Colombier 		*confend = 0;
259*529c1f20SDavid du Colombier 		print(s);
260*529c1f20SDavid du Colombier 	}
261*529c1f20SDavid du Colombier 	kern = getconf("bootfile=", path);
262*529c1f20SDavid du Colombier 
263*529c1f20SDavid du Colombier 	if(f != nil){
264*529c1f20SDavid du Colombier 		close(f);
265*529c1f20SDavid du Colombier 		f = nil;
266*529c1f20SDavid du Colombier 
267*529c1f20SDavid du Colombier 		if(kern != nil && (nowait==0 || timeout(1000)))
268*529c1f20SDavid du Colombier 			goto Loop;
269*529c1f20SDavid du Colombier 	}
270*529c1f20SDavid du Colombier 
271*529c1f20SDavid du Colombier 	if(kern == nil){
272*529c1f20SDavid du Colombier 		print("no bootfile\n");
273*529c1f20SDavid du Colombier 		goto Loop;
274*529c1f20SDavid du Colombier 	}
275*529c1f20SDavid du Colombier 	while((p = strchr(kern, '!')) != nil)
276*529c1f20SDavid du Colombier 		kern = p+1;
277*529c1f20SDavid du Colombier 
278*529c1f20SDavid du Colombier 	return kern;
279*529c1f20SDavid du Colombier }
280*529c1f20SDavid du Colombier 
281*529c1f20SDavid du Colombier static char*
numfmt(char * s,ulong b,ulong i,ulong a)282*529c1f20SDavid du Colombier numfmt(char *s, ulong b, ulong i, ulong a)
283*529c1f20SDavid du Colombier {
284*529c1f20SDavid du Colombier 	char *r;
285*529c1f20SDavid du Colombier 
286*529c1f20SDavid du Colombier 	if(i == 0){
287*529c1f20SDavid du Colombier 		ulong v = a;
288*529c1f20SDavid du Colombier 		while(v != 0){
289*529c1f20SDavid du Colombier 			v /= b;
290*529c1f20SDavid du Colombier 			i++;
291*529c1f20SDavid du Colombier 		}
292*529c1f20SDavid du Colombier 		if(i == 0)
293*529c1f20SDavid du Colombier 			i = 1;
294*529c1f20SDavid du Colombier 	}
295*529c1f20SDavid du Colombier 
296*529c1f20SDavid du Colombier 	s += i;
297*529c1f20SDavid du Colombier 	r = s;
298*529c1f20SDavid du Colombier 	while(i > 0){
299*529c1f20SDavid du Colombier 		*--s = hex[a % b];
300*529c1f20SDavid du Colombier 		a /= b;
301*529c1f20SDavid du Colombier 		i--;
302*529c1f20SDavid du Colombier 	}
303*529c1f20SDavid du Colombier 	return r;
304*529c1f20SDavid du Colombier }
305*529c1f20SDavid du Colombier 
306*529c1f20SDavid du Colombier char*
hexfmt(char * s,int i,uvlong a)307*529c1f20SDavid du Colombier hexfmt(char *s, int i, uvlong a)
308*529c1f20SDavid du Colombier {
309*529c1f20SDavid du Colombier 	if(i > 8 || i == 0 && (a>>32) != 0){
310*529c1f20SDavid du Colombier 		s = numfmt(s, 16, i ? i-8 : 0, a>>32);
311*529c1f20SDavid du Colombier 		i = 8;
312*529c1f20SDavid du Colombier 	}
313*529c1f20SDavid du Colombier 	return numfmt(s, 16, i, a);
314*529c1f20SDavid du Colombier }
315*529c1f20SDavid du Colombier 
316*529c1f20SDavid du Colombier char*
decfmt(char * s,int i,ulong a)317*529c1f20SDavid du Colombier decfmt(char *s, int i, ulong a)
318*529c1f20SDavid du Colombier {
319*529c1f20SDavid du Colombier 	return numfmt(s, 10, i, a);
320*529c1f20SDavid du Colombier }
321*529c1f20SDavid du Colombier 
322*529c1f20SDavid du Colombier static ulong
beswal(ulong l)323*529c1f20SDavid du Colombier beswal(ulong l)
324*529c1f20SDavid du Colombier {
325*529c1f20SDavid du Colombier 	uchar *p = (uchar*)&l;
326*529c1f20SDavid du Colombier 	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
327*529c1f20SDavid du Colombier }
328*529c1f20SDavid du Colombier 
329*529c1f20SDavid du Colombier char*
bootkern(void * f)330*529c1f20SDavid du Colombier bootkern(void *f)
331*529c1f20SDavid du Colombier {
332*529c1f20SDavid du Colombier 	uchar *e, *d, *t;
333*529c1f20SDavid du Colombier 	ulong n;
334*529c1f20SDavid du Colombier 	Exec ex;
335*529c1f20SDavid du Colombier 
336*529c1f20SDavid du Colombier 	if(readn(f, &ex, sizeof(ex)) != sizeof(ex))
337*529c1f20SDavid du Colombier 		return "bad header";
338*529c1f20SDavid du Colombier 
339*529c1f20SDavid du Colombier 	e = (uchar*)(beswal(ex.entry) & ~0xF0000000UL);
340*529c1f20SDavid du Colombier 	switch(beswal(ex.magic)){
341*529c1f20SDavid du Colombier 	case S_MAGIC:
342*529c1f20SDavid du Colombier 		if(readn(f, e, 8) != 8)
343*529c1f20SDavid du Colombier 			goto Error;
344*529c1f20SDavid du Colombier 	case I_MAGIC:
345*529c1f20SDavid du Colombier 		break;
346*529c1f20SDavid du Colombier 	default:
347*529c1f20SDavid du Colombier 		return "bad magic";
348*529c1f20SDavid du Colombier 	}
349*529c1f20SDavid du Colombier 
350*529c1f20SDavid du Colombier 	t = e;
351*529c1f20SDavid du Colombier 	n = beswal(ex.text);
352*529c1f20SDavid du Colombier 	if(readn(f, t, n) != n)
353*529c1f20SDavid du Colombier 		goto Error;
354*529c1f20SDavid du Colombier 	t += n;
355*529c1f20SDavid du Colombier 	d = (uchar*)PGROUND((uintptr)t);
356*529c1f20SDavid du Colombier 	memset(t, 0, d - t);
357*529c1f20SDavid du Colombier 	n = beswal(ex.data);
358*529c1f20SDavid du Colombier 	if(readn(f, d, n) != n)
359*529c1f20SDavid du Colombier 		goto Error;
360*529c1f20SDavid du Colombier 	d += n;
361*529c1f20SDavid du Colombier 	t = (uchar*)PGROUND((uintptr)d);
362*529c1f20SDavid du Colombier 	t += PGROUND(beswal(ex.bss));
363*529c1f20SDavid du Colombier 	memset(d, 0, t - d);
364*529c1f20SDavid du Colombier 
365*529c1f20SDavid du Colombier 	close(f);
366*529c1f20SDavid du Colombier 	print("boot\n");
367*529c1f20SDavid du Colombier 	unload();
368*529c1f20SDavid du Colombier 
369*529c1f20SDavid du Colombier 	jump(e);
370*529c1f20SDavid du Colombier 
371*529c1f20SDavid du Colombier Error:
372*529c1f20SDavid du Colombier 	return "i/o error";
373*529c1f20SDavid du Colombier }
374