xref: /inferno-os/os/boot/pc/load.c (revision 8a8c2d742b51525f66c2210e3c8a251de10022ff)
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