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