]> git.lizzy.rs Git - plan9front.git/blob - sys/src/boot/pc/sub.c
kernel: implement portable userinit() and simplify process creation
[plan9front.git] / sys / src / boot / pc / sub.c
1 #include <u.h>
2 #include <a.out.h>
3 #include "fns.h"
4 #include "mem.h"
5
6 void
7 putc(int c)
8 {
9         cgaputc(c);
10         if(uart != -1)
11                 uartputc(uart, c);
12 }
13
14 void
15 print(char *s)
16 {
17         while(*s != 0){
18                 if(*s == '\n')
19                         putc('\r');
20                 putc(*s++);
21         }
22 }
23
24 int
25 readn(void *f, void *data, int len)
26 {
27         uchar *p, *e;
28
29         putc(' ');
30         p = data;
31         e = p + len;
32         while(p < e){
33                 if(((ulong)p & 0xF000) == 0){
34                         putc('\b');
35                         putc(hex[((ulong)p>>16)&0xF]);
36                 }
37                 if((len = read(f, p, e - p)) <= 0)
38                         break;
39                 p += len;
40         }
41         putc('\b');
42
43         return p - (uchar*)data;
44 }
45
46 void
47 memmove(void *dst, void *src, int n)
48 {
49         uchar *d = dst;
50         uchar *s = src;
51
52         if(d < s){
53                 while(n-- > 0)
54                         *d++ = *s++;
55         } else if(d > s){
56                 s += n;
57                 d += n;
58                 while(n-- > 0)
59                         *--d = *--s;
60         }
61 }
62
63 int
64 memcmp(void *src, void *dst, int n)
65 {
66         uchar *d = dst;
67         uchar *s = src;
68         int r = 0;
69
70         while(n-- > 0){
71                 r = *d++ - *s++;
72                 if(r != 0)
73                         break;
74         }
75
76         return r;
77 }
78
79 int
80 strlen(char *s)
81 {
82         char *p = s;
83
84         while(*p != '\0')
85                 p++;
86
87         return p - s;
88 }
89
90 char*
91 strchr(char *s, int c)
92 {
93         for(; *s != 0; s++)
94                 if(*s == c)
95                         return s;
96
97         return nil;
98 }
99
100 void
101 memset(void *dst, int v, int n)
102 {
103         uchar *d = dst;
104
105         while(n > 0){
106                 *d++ = v;
107                 n--;
108         }
109 }
110
111 int
112 getc(void)
113 {
114         int c;
115
116         c = kbdgetc();
117         if(c == 0 && uart != -1)
118                 c = uartgetc(uart);
119         return c;
120 }
121
122 static int
123 readline(void *f, char *buf)
124 {
125         static char white[] = "\t ";
126         char *p;
127
128         p = buf;
129         do{
130                 if(f == nil)
131                         putc('>');
132                 for(;;){
133                         if(f == nil){
134                                 while((*p = getc()) == 0)
135                                         ;
136                                 if(p == buf && (*p == '\b' || strchr(white, *p) != nil))
137                                         continue;
138                                 putc(*p);
139                                 if(*p == '\r')
140                                         putc('\n');
141                                 else if(*p == '\b'){
142                                         p--;
143                                         putc(' ');
144                                         putc('\b');
145                                         continue;
146                                 }
147                         }else if(read(f, p, 1) <= 0)
148                                 return 0;
149                         if(strchr("\r\n", *p) != nil)
150                                 break;
151                         if(p == buf && strchr(white, *p) != nil)
152                                 continue;       /* whitespace on start of line */
153                         p++;
154                 }
155                 while(p > buf && strchr(white, p[-1]))
156                         p--;
157         }while(p == buf);
158         *p = 0;
159
160         return p - buf;
161 }
162
163 static int
164 timeout(int ms)
165 {
166         while(ms > 0){
167                 if(getc() != 0)
168                         return 1;
169                 usleep(100000);
170                 ms -= 100;
171         }
172         return 0;
173 }
174
175 #define BOOTLINE        ((char*)CONFADDR)
176 #define BOOTLINELEN     64
177 #define BOOTARGS        ((char*)(CONFADDR+BOOTLINELEN))
178 #define BOOTARGSLEN     (4096-0x200-BOOTLINELEN)
179
180 char *confend;
181
182 static void apmconf(int);
183 static void e820conf(void);
184 static void ramdiskconf(int);
185 static void uartconf(char*);
186
187 static char*
188 getconf(char *s, char *buf)
189 {
190         char *p, *e;
191         int n;
192
193         n = strlen(s);
194         for(p = BOOTARGS; p < confend; p = e+1){
195                 for(e = p+1; e < confend; e++)
196                         if(*e == '\n')
197                                 break;
198                 if(memcmp(p, s, n) == 0){
199                         p += n;
200                         n = e - p;
201                         buf[n] = 0;
202                         memmove(buf, p, n);
203                         return buf;
204                 }
205         }
206         return nil;
207 }
208
209 static int
210 delconf(char *s)
211 {
212         char *p, *e;
213
214         for(p = BOOTARGS; p < confend; p = e){
215                 for(e = p+1; e < confend; e++){
216                         if(*e == '\n'){
217                                 e++;
218                                 break;
219                         }
220                 }
221                 if(memcmp(p, s, strlen(s)) == 0){
222                         memmove(p, e, confend - e);
223                         confend -= e - p;
224                         *confend = 0;
225                         return 1;
226                 }
227         }
228         return 0;
229 }
230
231 char*
232 configure(void *f, char *path)
233 {
234         char *line, *kern, *s, *p;
235         int inblock, nowait, n;
236         static int once = 1;
237
238         if(once){
239                 once = 0;
240 Clear:
241                 memset(BOOTLINE, 0, BOOTLINELEN);
242
243                 confend = BOOTARGS;
244                 memset(confend, 0, BOOTARGSLEN);
245
246                 e820conf();
247                 ramdiskconf(0);
248         }
249         nowait = 1;
250         inblock = 0;
251 Loop:
252         while(readline(f, line = confend+1) > 0){
253                 if(*line == 0 || strchr("#;=", *line) != nil)
254                         continue;
255                 if(*line == '['){
256                         inblock = memcmp("[common]", line, 8) != 0;
257                         continue;
258                 }
259                 if(memcmp("boot", line, 5) == 0){
260                         nowait=1;
261                         break;
262                 }
263                 if(memcmp("wait", line, 5) == 0){
264                         nowait=0;
265                         continue;
266                 }
267                 if(memcmp("show", line, 5) == 0){
268                         print(BOOTARGS);
269                         continue;
270                 }
271                 if(memcmp("clear", line, 5) == 0){
272                         if(line[5] == '\0'){
273                                 print("ok\n");
274                                 goto Clear;
275                         } else if(line[5] == ' ' && delconf(line+6))
276                                 print("ok\n");
277                         continue;
278                 }
279                 if(inblock != 0 || (p = strchr(line, '=')) == nil)
280                         continue;
281                 *p++ = 0;
282                 delconf(line);
283                 if(memcmp("apm", line, 3) == 0){
284                         apmconf(line[3] - '0');
285                         continue;
286                 }
287                 if(memcmp("console", line, 8) == 0)
288                         uartconf(p);
289
290                 s = confend;
291                 memmove(confend, line, n = strlen(line)); confend += n;
292                 *confend++ = '=';
293                 memmove(confend, p, n = strlen(p)); confend += n;
294                 *confend++ = '\n';
295                 *confend = 0;
296                 print(s);
297         }
298         kern = getconf("bootfile=", path);
299
300         if(f != nil){
301                 close(f);
302                 f = nil;
303
304                 if(kern != nil && (nowait==0 || timeout(1000)))
305                         goto Loop;
306         }
307
308         if(kern == nil){
309                 print("no bootfile\n");
310                 goto Loop;
311         }
312         while((p = strchr(kern, '!')) != nil)
313                 kern = p+1;
314
315         return kern;
316 }
317
318
319 static void
320 hexfmt(char *s, int i, ulong a)
321 {
322         s += i;
323         while(i > 0){
324                 *--s = hex[a&15];
325                 a >>= 4;
326                 i--;
327         }
328 }
329
330 static void
331 addconfx(char *s, int w, ulong v)
332 {
333         int n;
334
335         n = strlen(s);
336         memmove(confend, s, n);
337         hexfmt(confend+n, w, v);
338         confend += n+w;
339         *confend = 0;
340 }
341
342 static void
343 apmconf(int id)
344 {
345         uchar *a;
346         char *s;
347
348         a = (uchar*)CONFADDR;
349         memset(a, 0, 20);
350
351         apm(id);
352         if(memcmp(a, "APM", 4) != 0)
353                 return;
354
355         s = confend;
356
357         addconfx("apm", 1, id);
358         addconfx("=ax=", 4, *((ushort*)(a+4)));
359         addconfx(" ebx=", 8, *((ulong*)(a+12)));
360         addconfx(" cx=", 4, *((ushort*)(a+6)));
361         addconfx(" dx=", 4, *((ushort*)(a+8)));
362         addconfx(" di=", 4, *((ushort*)(a+10)));
363         addconfx(" esi=", 8, *((ulong*)(a+16)));
364
365         *confend++ = '\n';
366         *confend = 0;
367
368         print(s);
369 }
370
371 static void
372 e820conf(void)
373 {
374         struct {
375                 uvlong  base;
376                 uvlong  len;
377                 ulong   typ;
378                 ulong   ext;
379         } e;
380         uvlong v;
381         ulong bx;
382         char *s;
383
384         bx=0;
385         s = confend;
386
387         do{
388                 bx = e820(bx, &e);
389                 if(e.len != 0 && (e.ext & 3) == 1){
390                         if(confend == s){
391                                 /* single entry <= 1MB is useless */
392                                 if(bx == 0 && e.typ == 1 && e.len <= 0x100000)
393                                         break;
394                                 memmove(confend, "*e820=", 6);
395                                 confend += 6;
396                         }
397                         addconfx("", 1, e.typ);
398                         v = e.base;
399                         addconfx(" 0x", 8, v>>32);
400                         addconfx("", 8, v&0xffffffff);
401                         v += e.len;
402                         addconfx(" 0x", 8, v>>32);
403                         addconfx("", 8, v&0xffffffff);
404                         *confend++ = ' ';
405                 }
406         } while(bx);
407
408         if(confend == s)
409                 return;
410
411         *confend++ = '\n';
412         *confend = 0;
413
414         print(s);
415 }
416
417 static int
418 checksum(void *v, int n)
419 {
420         uchar *p, s;
421
422         s = 0;
423         p = v;
424         while(n-- > 0)
425                 s += *p++;
426         return s;
427 }
428
429 static void
430 ramdiskconf(int id)
431 {
432         struct {
433                 /* ACPI header */
434                 char    sig[4];
435                 u32int  len;
436                 uchar   revision;
437                 uchar   csum;
438                 char    oem_id[6];
439                 char    oem_table_id[8];
440                 u32int  oem_revision;
441                 char    asl_compiler_id[4];
442                 u32int  asl_compiler_revision;
443
444                 u32int  safe_hook;
445
446                 /* MDI structure */
447                 u16int  bytes;
448                 uchar   version_minor;
449                 uchar   version_major;
450                 u32int  diskbuf;
451                 u32int  disksize;
452                 u32int  cmdline;
453                 u32int  oldint13;
454                 u32int  oldint15;
455                 u16int  olddosmem;
456                 uchar   bootloaderid;
457                 uchar   sector_shift;
458                 u16int  dpt_ptr;
459         } *mbft;
460         int shift;
461         char *s;
462
463 #define BDA     ((uchar*)0x400)
464         mbft = (void*)((((BDA[0x14]<<8) | BDA[0x13])<<10) - 1024);
465         for(; (ulong)&mbft->sector_shift < 0xA0000; mbft = (void*)((ulong)mbft + 16)){
466                 if(memcmp("mBFT", mbft, 4) == 0
467                 && mbft->len < 1024 && (uchar*)mbft + mbft->len > &mbft->sector_shift
468                 && checksum(mbft, mbft->len) == 0)
469                         goto Found;
470         }
471         return;
472 Found:
473         shift = mbft->sector_shift;
474         if(shift == 0)
475                 shift = 9;
476
477         s = confend;
478         addconfx("ramdisk", 1, id);
479         addconfx("=0x", 8, mbft->diskbuf);
480         addconfx(" 0x", 8, mbft->disksize<<shift);
481         addconfx(" 0x", 8, 1UL<<shift);
482
483         *confend++ = '\n';
484         *confend = 0;
485
486         print(s);
487 }
488
489 static void
490 uartconf(char *s)
491 {
492         if(*s >= '0' && *s <= '3'){
493                 uart = *s - '0';
494                 uartinit(uart, (7<<5) | 3);     /* b9660 l8 s1 */
495         } else
496                 uart = -1;
497 }
498
499 static ulong
500 beswal(ulong l)
501 {
502         uchar *p = (uchar*)&l;
503         return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
504 }
505
506 char*
507 bootkern(void *f)
508 {
509         uchar *e, *d, *t;
510         ulong n;
511         Exec ex;
512
513         while(a20() < 0)
514                 print("a20 enable failed\n");
515
516         if(readn(f, &ex, sizeof(ex)) != sizeof(ex))
517                 return "bad header";
518
519         e = (uchar*)(beswal(ex.entry) & ~0xF0000000UL);
520         switch(beswal(ex.magic)){
521         case S_MAGIC:
522                 if(readn(f, e, 8) != 8)
523                         goto Error;
524         case I_MAGIC:
525                 break;
526         default:
527                 return "bad magic";
528         }
529
530         t = e;
531         n = beswal(ex.text);
532         if(readn(f, t, n) != n)
533                 goto Error;
534         t += n;
535         d = (uchar*)PGROUND((ulong)t);
536         memset(t, 0, d - t);
537         n = beswal(ex.data);
538         if(readn(f, d, n) != n)
539                 goto Error;
540         d += n;
541         t = (uchar*)PGROUND((ulong)d);
542         t += PGROUND(beswal(ex.bss));
543         memset(d, 0, t - d);
544
545         close(f);
546         unload();
547
548         print("boot\n");
549
550         jump(e);
551
552 Error:          
553         return "i/o error";
554 }