1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "sd.h"
8 #include "fs.h"
9
10 #ifndef VERBOSE
11 #define VERBOSE 0
12 #endif
13
14 /*
15 * "cache" must be in this list so that 9load will pass the definition of
16 * the cache partition into the kernel so that the disk named by the `cfs'
17 * variable in plan9.ini can be seen in all circumstances before termrc
18 * sets up all the disk partitions. In particular, if it's on an odd-ball
19 * disk like sd10 rather than sdC0, this is needed.
20 */
21 static char *diskparts[] = {
22 "dos", "9fat", "fs", "data", "cdboot", "cache", 0
23 };
24 static char *etherparts[] = { "*", 0 };
25
26 static char *diskinis[] = {
27 "plan9/plan9.ini",
28 "plan9.ini",
29 0
30 };
31 static char *etherinis[] = {
32 "/cfg/pxe/%E",
33 0
34 };
35
36 /* ordering: devbios must be called before devsd calls sdbios */
37 Type types[] = {
38 { Tfloppy,
39 Fini|Ffs,
40 floppyinit, floppyinitdev,
41 floppygetfspart, 0, floppyboot,
42 floppyprintdevs,
43 diskparts,
44 diskinis,
45 },
46 { Tether,
47 Fini|Fbootp,
48 etherinit, etherinitdev,
49 pxegetfspart, 0, bootpboot,
50 etherprintdevs,
51 etherparts,
52 etherinis,
53 },
54 { Tbios,
55 Fini|Ffs,
56 biosinit, biosinitdev,
57 biosgetfspart, nil, biosboot,
58 biosprintdevs,
59 diskparts,
60 diskinis,
61 },
62 { Tcd,
63 Fini|Ffs,
64 cdinit, sdinitdev,
65 sdgetfspart, sdaddconf, sdboot,
66 sdprintdevs,
67 diskparts,
68 diskinis,
69 },
70 { Tsd,
71 Fini|Ffs,
72 sdinit, sdinitdev,
73 sdgetfspart, sdaddconf, sdboot,
74 sdprintdevs,
75 diskparts,
76 diskinis,
77 },
78 { Tnil,
79 0,
80 nil, nil, nil, nil, nil, nil,
81 nil,
82 nil,
83 0,
84 nil,
85 },
86 };
87
88 static char *typenm[] = {
89 [Tnil] "nil",
90 [Tfloppy] "floppy",
91 [Tsd] "sd",
92 [Tether] "ether",
93 [Tcd] "cd",
94 [Tbios] "bios",
95 };
96
97 static char *
typename(int type)98 typename(int type)
99 {
100 if (type < 0 || type >= nelem(typenm) || typenm[type] == nil)
101 return "**gok**";
102 return typenm[type];
103 }
104
105 extern SDifc sdataifc;
106 extern SDifc sdiahciifc;
107 extern SDifc sdaoeifc;
108 extern SDifc sdbiosifc;
109
110 #ifdef NOSCSI
111
112 SDifc* sdifc[] = {
113 &sdataifc,
114 &sdiahciifc,
115 &sdbiosifc,
116 &sdaoeifc,
117 nil,
118 };
119
120 #else
121
122 extern SDifc sdmylexifc;
123 extern SDifc sd53c8xxifc;
124
125 SDifc* sdifc[] = {
126 &sdataifc,
127 &sdiahciifc,
128 &sdmylexifc,
129 &sd53c8xxifc,
130 &sdbiosifc,
131 &sdaoeifc,
132 nil,
133 };
134
135 #endif NOSCSI
136
137 typedef struct Mode Mode;
138
139 enum {
140 Maxdev = 7,
141 Dany = -1,
142 Nmedia = 16,
143 Nini = 10,
144 };
145
146 enum { /* mode */
147 Mauto = 0x00,
148 Mlocal = 0x01,
149 Manual = 0x02,
150 NMode = 0x03,
151 };
152
153 typedef struct Medium Medium;
154 struct Medium {
155 Type* type;
156 int flag;
157 int dev;
158 char name[NAMELEN];
159
160 Fs *inifs;
161 char *part;
162 char *ini;
163
164 Medium* next;
165 };
166
167 typedef struct Mode {
168 char* name;
169 int mode;
170 } Mode;
171
172 static Medium media[Nmedia];
173 static Medium *curmedium = media;
174
175 static Mode modes[NMode+1] = {
176 [Mauto] { "auto", Mauto, },
177 [Mlocal] { "local", Mlocal, },
178 [Manual] { "manual", Manual, },
179 };
180
181 char **ini;
182
183 int scsi0port;
184 char *defaultpartition;
185 int iniread;
186
187 int debugload;
188
189 static Medium*
parse(char * line,char ** file)190 parse(char *line, char **file)
191 {
192 char *p;
193 Type *tp;
194 Medium *mp;
195
196 if(p = strchr(line, '!')) {
197 *p++ = 0;
198 *file = p;
199 } else
200 *file = "";
201
202 for(tp = types; tp->type != Tnil; tp++)
203 for(mp = tp->media; mp; mp = mp->next)
204 if(strcmp(mp->name, line) == 0)
205 return mp;
206 if(p)
207 *--p = '!';
208 return nil;
209 }
210
211 static int
boot(Medium * mp,char * file)212 boot(Medium *mp, char *file)
213 {
214 Type *tp;
215 Medium *xmp;
216 static int didaddconf;
217 Boot b;
218
219 memset(&b, 0, sizeof b);
220 b.state = INITKERNEL;
221
222 if(didaddconf == 0) {
223 didaddconf = 1;
224 for(tp = types; tp->type != Tnil; tp++)
225 if(tp->addconf)
226 for(xmp = tp->media; xmp; xmp = xmp->next)
227 (*tp->addconf)(xmp->dev);
228 }
229
230 sprint(BOOTLINE, "%s!%s", mp->name, file);
231 print("booting %s!%s\n", mp->name, file);
232 return (*mp->type->boot)(mp->dev, file, &b);
233 }
234
235 static Medium*
allocm(Type * tp)236 allocm(Type *tp)
237 {
238 Medium **l;
239
240 if(curmedium >= &media[Nmedia])
241 return 0;
242
243 for(l = &tp->media; *l; l = &(*l)->next)
244 ;
245 *l = curmedium++;
246 return *l;
247 }
248
249 Medium*
probe(int type,int flag,int dev)250 probe(int type, int flag, int dev)
251 {
252 Type *tp;
253 int i;
254 Medium *mp;
255 File f;
256 Fs *fs;
257 char **partp;
258
259 for(tp = types; tp->type != Tnil; tp++){
260 if(type != Tany && type != tp->type)
261 continue;
262
263 if(flag != Fnone){
264 for(mp = tp->media; mp; mp = mp->next){
265 if((flag & mp->flag) && (dev == Dany || dev == mp->dev))
266 return mp;
267 }
268 }
269 if (debugload)
270 print("probing %s...", typename(tp->type));
271 if((tp->flag & Fprobe) == 0){
272 tp->flag |= Fprobe;
273 tp->mask = (*tp->init)();
274 }
275
276 for(i = 0; tp->mask; i++){
277 if((tp->mask & (1<<i)) == 0)
278 continue;
279 tp->mask &= ~(1<<i);
280
281 if((mp = allocm(tp)) == 0)
282 continue;
283
284 mp->dev = i;
285 mp->flag = tp->flag;
286 mp->type = tp;
287 (*tp->initdev)(i, mp->name);
288
289 if(mp->flag & Fini){
290 mp->flag &= ~Fini;
291 for(partp = tp->parts; *partp; partp++){
292 if((fs = (*tp->getfspart)(i, *partp, 0)) == nil)
293 continue;
294
295 for(ini = tp->inis; *ini; ini++){
296 if(fswalk(fs, *ini, &f) > 0){
297 mp->inifs = fs;
298 mp->part = *partp;
299 mp->ini = f.path;
300 mp->flag |= Fini;
301 goto Break2;
302 }
303 }
304 }
305 }
306 Break2:
307 if((flag & mp->flag) && (dev == Dany || dev == i))
308 return mp;
309 }
310 }
311
312 return 0;
313 }
314
315 void
main(void)316 main(void)
317 {
318 Medium *mp;
319 int flag, i, mode, tried;
320 char def[2*NAMELEN], line[80], *p, *file;
321 Type *tp;
322
323 i8042a20();
324 memset(m, 0, sizeof(Mach));
325 trapinit();
326 clockinit();
327 alarminit();
328 meminit(0);
329 spllo();
330 consinit("0", "9600");
331 kbdinit();
332 if((ulong)&end > (KZERO|(640*1024)))
333 panic("i'm too big\n");
334
335 readlsconf();
336 print("initial probe, to find plan9.ini...");
337 /* find and read plan9.ini, setting configuration variables */
338 for(tp = types; tp->type != Tnil; tp++){
339 /* skip bios until we have read plan9.ini */
340 if(!pxe && tp->type == Tether || tp->type == Tbios)
341 continue;
342 if (VERBOSE)
343 print("probing %s...", typename(tp->type));
344 if((mp = probe(tp->type, Fini, Dany)) && (mp->flag & Fini)){
345 print("using %s!%s!%s\n", mp->name, mp->part, mp->ini);
346 iniread = !dotini(mp->inifs);
347 break;
348 }
349 }
350 print("\n");
351 apminit();
352
353 debugload = getconf("*debugload") != nil;
354 if((p = getconf("console")) != nil)
355 consinit(p, getconf("baud"));
356
357 devpccardlink();
358 devi82365link();
359
360 /*
361 * Even after we find the ini file, we keep probing disks,
362 * because we have to collect the partition tables and
363 * have boot devices for parse.
364 */
365 probe(Tany, Fnone, Dany);
366 if (debugload)
367 print("end disk probe\n");
368 tried = 0;
369 mode = Mauto;
370
371 p = getconf("bootfile");
372
373 if(p != 0) {
374 mode = Manual;
375 for(i = 0; i < NMode; i++){
376 if(strcmp(p, modes[i].name) == 0){
377 mode = modes[i].mode;
378 goto done;
379 }
380 }
381 if((mp = parse(p, &file)) == nil) {
382 print("Unknown boot device: %s\n", p);
383 goto done;
384 }
385 tried = boot(mp, file);
386 }
387 done:
388 if(tried == 0 && mode != Manual){
389 flag = Fany;
390 if(mode == Mlocal)
391 flag &= ~Fbootp;
392 if((mp = probe(Tany, flag, Dany)) && mp->type->type != Tfloppy)
393 boot(mp, "");
394 if (debugload)
395 print("end auto probe\n");
396 }
397
398 def[0] = 0;
399 probe(Tany, Fnone, Dany);
400 if (debugload)
401 print("end final probe\n");
402 if(p = getconf("bootdef"))
403 strcpy(def, p);
404
405 flag = 0;
406 for(tp = types; tp->type != Tnil; tp++){
407 for(mp = tp->media; mp; mp = mp->next){
408 if(flag == 0){
409 flag = 1;
410 print("Boot devices:");
411 }
412 (*tp->printdevs)(mp->dev);
413 }
414 }
415 if(flag)
416 print("\n");
417
418 for(;;){
419 if(getstr("boot from", line, sizeof(line), def, (mode != Manual)*15) >= 0)
420 if(mp = parse(line, &file))
421 boot(mp, file);
422 def[0] = 0;
423 }
424 }
425
426 int
getfields(char * lp,char ** fields,int n,char sep)427 getfields(char *lp, char **fields, int n, char sep)
428 {
429 int i;
430
431 for(i = 0; lp && *lp && i < n; i++){
432 while(*lp == sep)
433 *lp++ = 0;
434 if(*lp == 0)
435 break;
436 fields[i] = lp;
437 while(*lp && *lp != sep){
438 if(*lp == '\\' && *(lp+1) == '\n')
439 *lp++ = ' ';
440 lp++;
441 }
442 }
443 return i;
444 }
445
446 int
cistrcmp(char * a,char * b)447 cistrcmp(char *a, char *b)
448 {
449 int ac, bc;
450
451 for(;;){
452 ac = *a++;
453 bc = *b++;
454
455 if(ac >= 'A' && ac <= 'Z')
456 ac = 'a' + (ac - 'A');
457 if(bc >= 'A' && bc <= 'Z')
458 bc = 'a' + (bc - 'A');
459 ac -= bc;
460 if(ac)
461 return ac;
462 if(bc == 0)
463 break;
464 }
465 return 0;
466 }
467
468 int
cistrncmp(char * a,char * b,int n)469 cistrncmp(char *a, char *b, int n)
470 {
471 unsigned ac, bc;
472
473 while(n > 0){
474 ac = *a++;
475 bc = *b++;
476 n--;
477
478 if(ac >= 'A' && ac <= 'Z')
479 ac = 'a' + (ac - 'A');
480 if(bc >= 'A' && bc <= 'Z')
481 bc = 'a' + (bc - 'A');
482
483 ac -= bc;
484 if(ac)
485 return ac;
486 if(bc == 0)
487 break;
488 }
489
490 return 0;
491 }
492
493 #define PSTART ( 8*1024*1024)
494 #define PEND (16*1024*1024)
495
496 ulong palloc = PSTART;
497
498 void*
ialloc(ulong n,int align)499 ialloc(ulong n, int align)
500 {
501 ulong p;
502 int a;
503
504 p = palloc;
505 if(align <= 0)
506 align = 4;
507 if(a = n % align)
508 n += align - a;
509 if(a = p % align)
510 p += align - a;
511
512
513 palloc = p+n;
514 if(palloc > PEND)
515 panic("ialloc(%lud, %d) called from %#p\n",
516 n, align, getcallerpc(&n));
517 return memset((void*)(p|KZERO), 0, n);
518 }
519
520 void*
xspanalloc(ulong size,int align,ulong span)521 xspanalloc(ulong size, int align, ulong span)
522 {
523 ulong a, v;
524
525 if((palloc + (size+align+span)) > PEND)
526 panic("xspanalloc(%lud, %d, 0x%lux) called from %#p\n",
527 size, align, span, getcallerpc(&size));
528
529 a = (ulong)ialloc(size+align+span, 0);
530
531 if(span > 2)
532 v = (a + span) & ~(span-1);
533 else
534 v = a;
535
536 if(align > 1)
537 v = (v + align) & ~(align-1);
538
539 return (void*)v;
540 }
541
542 static Block *allocbp;
543
544 Block*
allocb(int size)545 allocb(int size)
546 {
547 Block *bp, **lbp;
548 ulong addr;
549
550 lbp = &allocbp;
551 for(bp = *lbp; bp; bp = bp->next){
552 if((bp->lim - bp->base) >= size){
553 *lbp = bp->next;
554 break;
555 }
556 lbp = &bp->next;
557 }
558 if(bp == 0){
559 if((palloc + (sizeof(Block)+size+64)) > PEND)
560 panic("allocb(%d) called from %#p\n",
561 size, getcallerpc(&size));
562 bp = ialloc(sizeof(Block)+size+64, 0);
563 addr = (ulong)bp;
564 addr = ROUNDUP(addr + sizeof(Block), 8);
565 bp->base = (uchar*)addr;
566 bp->lim = ((uchar*)bp) + sizeof(Block)+size+64;
567 }
568
569 if(bp->flag)
570 panic("allocb reuse\n");
571
572 bp->rp = bp->base;
573 bp->wp = bp->rp;
574 bp->next = 0;
575 bp->flag = 1;
576
577 return bp;
578 }
579
580 void
freeb(Block * bp)581 freeb(Block* bp)
582 {
583 bp->next = allocbp;
584 allocbp = bp;
585
586 bp->flag = 0;
587 }
588
589 enum {
590 Paddr= 0x70, /* address port */
591 Pdata= 0x71, /* data port */
592 };
593
594 uchar
nvramread(int offset)595 nvramread(int offset)
596 {
597 outb(Paddr, offset);
598 return inb(Pdata);
599 }
600
601 void (*etherdetach)(void);
602 void (*floppydetach)(void);
603 void (*sddetach)(void);
604
605 void
warp9(ulong entry)606 warp9(ulong entry)
607 {
608 if(etherdetach)
609 etherdetach();
610 if(floppydetach)
611 floppydetach();
612 if(sddetach)
613 sddetach();
614 consdrain();
615
616 splhi();
617 trapdisable();
618
619 /*
620 * This is where to push things on the stack to
621 * boot *BSD systems, e.g.
622 (*(void(*)(void*, void*, void*, void*, ulong, ulong))(PADDR(entry)))(0, 0, 0, 0, 8196, 640);
623 * will enable NetBSD boot (the real memory size needs to
624 * go in the 5th argument).
625 */
626 (*(void(*)(void))(PADDR(entry)))();
627 }
628