xref: /plan9/sys/src/9/pc/main.c (revision 217e9e83c7f9cc6fb27d97dda90c8339b6f98728)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"io.h"
7 #include	"ureg.h"
8 #include	"init.h"
9 #include	"pool.h"
10 #include	"reboot.h"
11 #include	"mp.h"
12 #include	<tos.h>
13 
14 Mach *m;
15 
16 /*
17  * Where configuration info is left for the loaded programme.
18  * This will turn into a structure as more is done by the boot loader
19  * (e.g. why parse the .ini file twice?).
20  * There are 3584 bytes available at CONFADDR.
21  */
22 #define BOOTLINE	((char*)CONFADDR)
23 #define BOOTLINELEN	64
24 #define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
25 #define	BOOTARGSLEN	(4096-0x200-BOOTLINELEN)
26 #define	MAXCONF		64
27 
28 enum {
29 	/* space for syscall args, return PC, top-of-stack struct */
30 	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
31 };
32 
33 char bootdisk[KNAMELEN];
34 Conf conf;
35 char *confname[MAXCONF];
36 char *confval[MAXCONF];
37 int nconf;
38 uchar *sp;	/* user stack of init proc */
39 int delaylink;
40 int idle_spin, idle_if_nproc;
41 
42 static void
options(void)43 options(void)
44 {
45 	long i, n;
46 	char *cp, *line[MAXCONF], *p, *q;
47 
48 	/*
49 	 *  parse configuration args from dos file plan9.ini
50 	 */
51 	cp = BOOTARGS;	/* where b.com leaves its config */
52 	cp[BOOTARGSLEN-1] = 0;
53 
54 	/*
55 	 * Strip out '\r', change '\t' -> ' '.
56 	 */
57 	p = cp;
58 	for(q = cp; *q; q++){
59 		if(*q == '\r')
60 			continue;
61 		if(*q == '\t')
62 			*q = ' ';
63 		*p++ = *q;
64 	}
65 	*p = 0;
66 
67 	n = getfields(cp, line, MAXCONF, 1, "\n");
68 	for(i = 0; i < n; i++){
69 		if(*line[i] == '#')
70 			continue;
71 		cp = strchr(line[i], '=');
72 		if(cp == nil)
73 			continue;
74 		*cp++ = '\0';
75 		confname[nconf] = line[i];
76 		confval[nconf] = cp;
77 		nconf++;
78 	}
79 }
80 
81 extern void mmuinit0(void);
82 extern void (*i8237alloc)(void);
83 
84 void
fpsavealloc(void)85 fpsavealloc(void)
86 {
87 	m->fpsavalign = mallocalign(sizeof(FPssestate), FPalign, 0, 0);
88 	if (m->fpsavalign == nil)
89 		panic("cpu%d: can't allocate fpsavalign", m->machno);
90 }
91 
92 static int
isa20on(void)93 isa20on(void)
94 {
95 	int r;
96 	ulong o;
97 	ulong *zp, *mb1p;
98 
99 	zp = (ulong *)KZERO;
100 	mb1p = (ulong *)(KZERO|MB);
101 	o = *zp;
102 
103 	*zp = 0x1234;
104 	*mb1p = 0x8765;
105 	coherence();
106 	wbinvd();
107 	r = *zp != *mb1p;
108 
109 	*zp = o;
110 	return r;
111 }
112 
113 void
main(void)114 main(void)
115 {
116 	cgapost(0);
117 	mach0init();
118 	options();
119 	ioinit();
120 	i8250console();
121 	quotefmtinstall();
122 	screeninit();
123 
124 	print("\nPlan 9\n");
125 
126 	trapinit0();
127 	mmuinit0();
128 
129 	kbdinit();
130 	i8253init();
131 	cpuidentify();
132 	meminit();
133 	confinit();
134 	archinit();
135 	if(!isa20on())
136 		panic("bootstrap didn't leave a20 address line enabled");
137 	xinit();
138 	if(i8237alloc != nil)
139 		i8237alloc();
140 	trapinit();
141 	printinit();
142 	cpuidprint();
143 	mmuinit();
144 	fpsavealloc();
145 	if(arch->intrinit)	/* launches other processors on an mp */
146 		arch->intrinit();
147 	timersinit();
148 	mathinit();
149 	kbdenable();
150 	if(arch->clockenable)
151 		arch->clockenable();
152 	procinit0();
153 	initseg();
154 	if(delaylink){
155 		bootlinks();
156 		pcimatch(0, 0, 0);
157 	}else
158 		links();
159 	conf.monitor = 1;
160 	chandevreset();
161 	cgapost(0xcd);
162 
163 	pageinit();
164 	i8253link();
165 	swapinit();
166 	userinit();
167 	active.thunderbirdsarego = 1;
168 
169 	cgapost(0x99);
170 	schedinit();
171 }
172 
173 void
mach0init(void)174 mach0init(void)
175 {
176 	conf.nmach = 1;
177 	MACHP(0) = (Mach*)CPU0MACH;
178 	m->pdb = (ulong*)CPU0PDB;
179 	m->gdt = (Segdesc*)CPU0GDT;
180 
181 	machinit();
182 
183 	active.machs = 1;
184 	active.exiting = 0;
185 }
186 
187 void
machinit(void)188 machinit(void)
189 {
190 	int machno;
191 	ulong *pdb;
192 	Segdesc *gdt;
193 
194 	machno = m->machno;
195 	pdb = m->pdb;
196 	gdt = m->gdt;
197 	memset(m, 0, sizeof(Mach));
198 	m->machno = machno;
199 	m->pdb = pdb;
200 	m->gdt = gdt;
201 	m->perf.period = 1;
202 
203 	/*
204 	 * For polled uart output at boot, need
205 	 * a default delay constant. 100000 should
206 	 * be enough for a while. Cpuidentify will
207 	 * calculate the real value later.
208 	 */
209 	m->loopconst = 100000;
210 }
211 
212 void
init0(void)213 init0(void)
214 {
215 	int i;
216 	char buf[2*KNAMELEN];
217 
218 	up->nerrlab = 0;
219 
220 	spllo();
221 
222 	/*
223 	 * These are o.k. because rootinit is null.
224 	 * Then early kproc's will have a root and dot.
225 	 */
226 	up->slash = namec("#/", Atodir, 0, 0);
227 	pathclose(up->slash->path);
228 	up->slash->path = newpath("/");
229 	up->dot = cclone(up->slash);
230 
231 	chandevinit();
232 
233 	if(!waserror()){
234 		snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
235 		ksetenv("terminal", buf, 0);
236 		ksetenv("cputype", "386", 0);
237 		if(cpuserver)
238 			ksetenv("service", "cpu", 0);
239 		else
240 			ksetenv("service", "terminal", 0);
241 		for(i = 0; i < nconf; i++){
242 			if(confname[i][0] != '*')
243 				ksetenv(confname[i], confval[i], 0);
244 			ksetenv(confname[i], confval[i], 1);
245 		}
246 		poperror();
247 	}
248 	kproc("alarm", alarmkproc, 0);
249 	cgapost(0x9);
250 	touser(sp);
251 }
252 
253 void
userinit(void)254 userinit(void)
255 {
256 	void *v;
257 	Proc *p;
258 	Segment *s;
259 	Page *pg;
260 
261 	p = newproc();
262 	p->pgrp = newpgrp();
263 	p->egrp = smalloc(sizeof(Egrp));
264 	p->egrp->ref = 1;
265 	p->fgrp = dupfgrp(nil);
266 	p->rgrp = newrgrp();
267 	p->procmode = 0640;
268 
269 	kstrdup(&eve, "");
270 	kstrdup(&p->text, "*init*");
271 	kstrdup(&p->user, eve);
272 
273 	p->fpstate = FPinit;
274 	fpoff();
275 
276 	/*
277 	 * Kernel Stack
278 	 *
279 	 * N.B. make sure there's enough space for syscall to check
280 	 *	for valid args and
281 	 *	4 bytes for gotolabel's return PC
282 	 */
283 	p->sched.pc = (ulong)init0;
284 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
285 
286 	/*
287 	 * User Stack
288 	 *
289 	 * N.B. cannot call newpage() with clear=1, because pc kmap
290 	 * requires up != nil.  use tmpmap instead.
291 	 */
292 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
293 	p->seg[SSEG] = s;
294 	pg = newpage(0, 0, USTKTOP-BY2PG);
295 	v = tmpmap(pg);
296 	memset(v, 0, BY2PG);
297 	segpage(s, pg);
298 	bootargs(v);
299 	tmpunmap(v);
300 
301 	/*
302 	 * Text
303 	 */
304 	s = newseg(SG_TEXT, UTZERO, 1);
305 	s->flushme++;
306 	p->seg[TSEG] = s;
307 	pg = newpage(0, 0, UTZERO);
308 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
309 	segpage(s, pg);
310 	v = tmpmap(pg);
311 	memset(v, 0, BY2PG);
312 	memmove(v, initcode, sizeof initcode);
313 	tmpunmap(v);
314 
315 	ready(p);
316 }
317 
318 uchar *
pusharg(char * p)319 pusharg(char *p)
320 {
321 	int n;
322 
323 	n = strlen(p)+1;
324 	sp -= n;
325 	memmove(sp, p, n);
326 	return sp;
327 }
328 
329 void
bootargs(void * base)330 bootargs(void *base)
331 {
332  	int i, ac;
333 	uchar *av[32];
334 	uchar **lsp;
335 	char *cp = BOOTLINE;
336 	char buf[64];
337 
338 	sp = (uchar*)base + BY2PG - Ustkheadroom;
339 
340 	ac = 0;
341 	av[ac++] = pusharg("/386/9dos");
342 
343 	/* when boot is changed to only use rc, this code can go away */
344 	cp[BOOTLINELEN-1] = 0;
345 	buf[0] = 0;
346 	if(strncmp(cp, "fd", 2) == 0){
347 		snprint(buf, sizeof buf, "local!#f/fd%lddisk",
348 			strtol(cp+2, 0, 0));
349 		av[ac++] = pusharg(buf);
350 	} else if(strncmp(cp, "sd", 2) == 0){
351 		snprint(buf, sizeof buf, "local!#S/sd%c%c/fs", *(cp+2), *(cp+3));
352 		av[ac++] = pusharg(buf);
353 	} else if(strncmp(cp, "ether", 5) == 0)
354 		av[ac++] = pusharg("-n");
355 
356 	/* 4 byte word align stack */
357 	sp = (uchar*)((ulong)sp & ~3);
358 
359 	/* build argc, argv on stack */
360 	sp -= (ac+1)*sizeof(sp);
361 	lsp = (uchar**)sp;
362 	for(i = 0; i < ac; i++)
363 		*lsp++ = av[i] + ((USTKTOP - BY2PG) - (ulong)base);
364 	*lsp = 0;
365 	sp += (USTKTOP - BY2PG) - (ulong)base - sizeof(ulong);
366 }
367 
368 char*
getconf(char * name)369 getconf(char *name)
370 {
371 	int i;
372 
373 	for(i = 0; i < nconf; i++)
374 		if(cistrcmp(confname[i], name) == 0)
375 			return confval[i];
376 	return 0;
377 }
378 
379 static void
writeconf(void)380 writeconf(void)
381 {
382 	char *p, *q;
383 	int n;
384 
385 	p = getconfenv();
386 
387 	if(waserror()) {
388 		free(p);
389 		nexterror();
390 	}
391 
392 	/* convert to name=value\n format */
393 	for(q=p; *q; q++) {
394 		q += strlen(q);
395 		*q = '=';
396 		q += strlen(q);
397 		*q = '\n';
398 	}
399 	n = q - p + 1;
400 	if(n >= BOOTARGSLEN)
401 		error("kernel configuration too large");
402 	memset(BOOTLINE, 0, BOOTLINELEN);
403 	memmove(BOOTARGS, p, n);
404 	poperror();
405 	free(p);
406 }
407 
408 void
confinit(void)409 confinit(void)
410 {
411 	char *p;
412 	int i, userpcnt;
413 	unsigned mb;
414 	ulong kpages, ksize;
415 
416 	if(p = getconf("*kernelpercent"))
417 		userpcnt = 100 - strtol(p, 0, 0);
418 	else
419 		userpcnt = 0;
420 
421 	conf.npage = 0;
422 	for(i=0; i<nelem(conf.mem); i++)
423 		conf.npage += conf.mem[i].npage;
424 
425 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
426 	if(cpuserver)
427 		conf.nproc *= 3;
428 	if(conf.nproc > 2000)
429 		conf.nproc = 2000;
430 	conf.nimage = 200;
431 	conf.nswap = conf.nproc*80;
432 	conf.nswppo = 4096;
433 
434 	if(cpuserver) {
435 		if(userpcnt < 10)
436 			userpcnt = 70;
437 		kpages = conf.npage - (conf.npage*userpcnt)/100;
438 
439 		/*
440 		 * Hack for the big boys. Only good while physmem < 4GB.
441 		 * Give the kernel fixed max + enough to allocate the
442 		 * page pool.
443 		 * This is an overestimate as conf.upages < conf.npages.
444 		 * The patch of nimage is a band-aid, scanning the whole
445 		 * page list in imagereclaim just takes too long.
446 		 */
447 		for (mb = 400; mb >= 100; mb /= 2) {
448 			ksize = mb*MB + conf.npage*sizeof(Page);
449 			if(kpages > ksize/BY2PG && cankaddr(ksize)) {
450 				kpages = ksize/BY2PG + (conf.nproc*KSTACK)/BY2PG;
451 				conf.nimage = 2000;
452 				break;
453 			}
454 		}
455 	} else {
456 		if(userpcnt < 10) {
457 			if(conf.npage*BY2PG < 16*MB)
458 				userpcnt = 40;
459 			else
460 				userpcnt = 60;
461 		}
462 		kpages = conf.npage - (conf.npage*userpcnt)/100;
463 
464 		/*
465 		 * Make sure terminals with low memory get at least
466 		 * 4MB on the first Image chunk allocation.
467 		 */
468 		if(conf.npage*BY2PG < 16*MB)
469 			imagmem->minarena = 4*1024*1024;
470 	}
471 
472 	/*
473 	 * can't go past the end of virtual memory
474 	 * (ulong)-KZERO is 2^32 - KZERO
475 	 */
476 	if(kpages > ((ulong)-KZERO)/BY2PG)
477 		kpages = ((ulong)-KZERO)/BY2PG;
478 
479 	conf.upages = conf.npage - kpages;
480 	conf.ialloc = (kpages/2)*BY2PG;
481 
482 	/*
483 	 * Guess how much is taken by the large permanent
484 	 * datastructures. Mntcache and Mntrpc are not accounted for
485 	 * (probably ~300KB).
486 	 */
487 	kpages *= BY2PG;
488 	kpages -= conf.upages*sizeof(Page)
489 		+ conf.nproc*sizeof(Proc)
490 		+ conf.nimage*sizeof(Image)
491 		+ conf.nswap
492 		+ conf.nswppo*sizeof(Page);
493 	mainmem->maxsize = kpages;
494 	if(!cpuserver){
495 		/*
496 		 * give terminals lots of image memory, too; the dynamic
497 		 * allocation will balance the load properly, hopefully.
498 		 * be careful with 32-bit overflow.
499 		 */
500 		imagmem->maxsize = kpages;
501 	}
502 }
503 
504 static char* mathmsg[] =
505 {
506 	nil,	/* handled below */
507 	"denormalized operand",
508 	"division by zero",
509 	"numeric overflow",
510 	"numeric underflow",
511 	"precision loss",
512 };
513 
514 static void
mathstate(ulong * stsp,ulong * pcp,ulong * ctlp)515 mathstate(ulong *stsp, ulong *pcp, ulong *ctlp)
516 {
517 	ulong sts, fpc, ctl;
518 	FPsave *f = &up->fpsave;
519 
520 	if(fpsave == fpx87save){
521 		sts = f->status;
522 		fpc = f->pc;
523 		ctl = f->control;
524 	} else {
525 		sts = f->fsw;
526 		fpc = f->fpuip;
527 		ctl = f->fcw;
528 	}
529 	if(stsp)
530 		*stsp = sts;
531 	if(pcp)
532 		*pcp = fpc;
533 	if(ctlp)
534 		*ctlp = ctl;
535 }
536 
537 static void
mathnote(void)538 mathnote(void)
539 {
540 	int i;
541 	ulong status, pc;
542 	char *msg, note[ERRMAX];
543 
544 	mathstate(&status, &pc, nil);
545 
546 	/*
547 	 * Some attention should probably be paid here to the
548 	 * exception masks and error summary.
549 	 */
550 	msg = "unknown exception";
551 	for(i = 1; i <= 5; i++){
552 		if(!((1<<i) & status))
553 			continue;
554 		msg = mathmsg[i];
555 		break;
556 	}
557 	if(status & 0x01){
558 		if(status & 0x40){
559 			if(status & 0x200)
560 				msg = "stack overflow";
561 			else
562 				msg = "stack underflow";
563 		}else
564 			msg = "invalid operation";
565 	}
566 	snprint(note, sizeof note, "sys: fp: %s fppc=%#lux status=%#lux",
567 		msg, pc, status);
568 	postnote(up, 1, note, NDebug);
569 }
570 
571 /*
572  * sse fp save and restore buffers have to be 16-byte (FPalign) aligned,
573  * so we shuffle the data down as needed or make copies.
574  */
575 
576 void
fpssesave(FPsave * fps)577 fpssesave(FPsave *fps)
578 {
579 	FPsave *afps;
580 
581 	fps->magic = 0x1234;
582 	afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
583 	fpssesave0(afps);
584 	if (fps != afps)  /* not aligned? shuffle down from aligned buffer */
585 		memmove(fps, afps, sizeof(FPssestate));
586 	if (fps->magic != 0x1234)
587 		print("fpssesave: magic corrupted\n");
588 }
589 
590 void
fpsserestore(FPsave * fps)591 fpsserestore(FPsave *fps)
592 {
593 	FPsave *afps;
594 
595 	fps->magic = 0x4321;
596 	afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
597 	if (fps != afps) {
598 		afps = m->fpsavalign;
599 		memmove(afps, fps, sizeof(FPssestate));	/* make aligned copy */
600 	}
601 	fpsserestore0(afps);
602 	if (fps->magic != 0x4321)
603 		print("fpsserestore: magic corrupted\n");
604 }
605 
606 /*
607  *  math coprocessor error
608  */
609 static void
matherror(Ureg * ur,void *)610 matherror(Ureg *ur, void*)
611 {
612 	ulong status, pc;
613 
614 	/*
615 	 *  a write cycle to port 0xF0 clears the interrupt latch attached
616 	 *  to the error# line from the 387
617 	 */
618 	if(!(m->cpuiddx & Fpuonchip))
619 		outb(0xF0, 0xFF);
620 
621 	/*
622 	 *  save floating point state to check out error
623 	 */
624 	fpenv(&up->fpsave);	/* result ignored, but masks fp exceptions */
625 	fpsave(&up->fpsave);		/* also turns fpu off */
626 	fpon();
627 	mathnote();
628 
629 	if((ur->pc & 0xf0000000) == KZERO){
630 		mathstate(&status, &pc, nil);
631 		panic("fp: status %#lux fppc=%#lux pc=%#lux", status, pc, ur->pc);
632 	}
633 }
634 
635 /*
636  *  math coprocessor emulation fault
637  */
638 static void
mathemu(Ureg * ureg,void *)639 mathemu(Ureg *ureg, void*)
640 {
641 	ulong status, control;
642 
643 	if(up->fpstate & FPillegal){
644 		/* someone did floating point in a note handler */
645 		postnote(up, 1, "sys: floating point in note handler", NDebug);
646 		return;
647 	}
648 	switch(up->fpstate){
649 	case FPinit:
650 		fpinit();
651 		up->fpstate = FPactive;
652 		break;
653 	case FPinactive:
654 		/*
655 		 * Before restoring the state, check for any pending
656 		 * exceptions, there's no way to restore the state without
657 		 * generating an unmasked exception.
658 		 * More attention should probably be paid here to the
659 		 * exception masks and error summary.
660 		 */
661 		mathstate(&status, nil, &control);
662 		if((status & ~control) & 0x07F){
663 			mathnote();
664 			break;
665 		}
666 		fprestore(&up->fpsave);
667 		up->fpstate = FPactive;
668 		break;
669 	case FPactive:
670 		panic("math emu pid %ld %s pc %#lux",
671 			up->pid, up->text, ureg->pc);
672 		break;
673 	}
674 }
675 
676 /*
677  *  math coprocessor segment overrun
678  */
679 static void
mathover(Ureg *,void *)680 mathover(Ureg*, void*)
681 {
682 	pexit("math overrun", 0);
683 }
684 
685 void
mathinit(void)686 mathinit(void)
687 {
688 	trapenable(VectorCERR, matherror, 0, "matherror");
689 	if(X86FAMILY(m->cpuidax) == 3)
690 		intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
691 	trapenable(VectorCNA, mathemu, 0, "mathemu");
692 	trapenable(VectorCSO, mathover, 0, "mathover");
693 }
694 
695 /*
696  *  set up floating point for a new process
697  */
698 void
procsetup(Proc * p)699 procsetup(Proc*p)
700 {
701 	p->fpstate = FPinit;
702 	fpoff();
703 }
704 
705 void
procrestore(Proc * p)706 procrestore(Proc *p)
707 {
708 	uvlong t;
709 
710 	if(p->kp)
711 		return;
712 	cycles(&t);
713 	p->pcycles -= t;
714 }
715 
716 /*
717  *  Save the mach dependent part of the process state.
718  */
719 void
procsave(Proc * p)720 procsave(Proc *p)
721 {
722 	uvlong t;
723 
724 	cycles(&t);
725 	p->pcycles += t;
726 	if(p->fpstate == FPactive){
727 		if(p->state == Moribund)
728 			fpclear();
729 		else{
730 			/*
731 			 * Fpsave() stores without handling pending
732 			 * unmasked exeptions. Postnote() can't be called
733 			 * here as sleep() already has up->rlock, so
734 			 * the handling of pending exceptions is delayed
735 			 * until the process runs again and generates an
736 			 * emulation fault to activate the FPU.
737 			 */
738 			fpsave(&p->fpsave);
739 		}
740 		p->fpstate = FPinactive;
741 	}
742 
743 	/*
744 	 * While this processor is in the scheduler, the process could run
745 	 * on another processor and exit, returning the page tables to
746 	 * the free list where they could be reallocated and overwritten.
747 	 * When this processor eventually has to get an entry from the
748 	 * trashed page tables it will crash.
749 	 *
750 	 * If there's only one processor, this can't happen.
751 	 * You might think it would be a win not to do this in that case,
752 	 * especially on VMware, but it turns out not to matter.
753 	 */
754 	mmuflushtlb(PADDR(m->pdb));
755 }
756 
757 static void
shutdown(int ispanic)758 shutdown(int ispanic)
759 {
760 	int ms, once;
761 
762 	lock(&active);
763 	if(ispanic)
764 		active.ispanic = ispanic;
765 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
766 		active.ispanic = 0;
767 	once = active.machs & (1<<m->machno);
768 	/*
769 	 * setting exiting will make hzclock() on each processor call exit(0),
770 	 * which calls shutdown(0) and arch->reset(), which on mp systems is
771 	 * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap
772 	 * processors (to permit a reboot).  clearing our bit in machs avoids
773 	 * calling exit(0) from hzclock() on this processor.
774 	 */
775 	active.machs &= ~(1<<m->machno);
776 	active.exiting = 1;
777 	unlock(&active);
778 
779 	if(once)
780 		iprint("cpu%d: exiting\n", m->machno);
781 
782 	/* wait for any other processors to shutdown */
783 	spllo();
784 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
785 		delay(TK2MS(2));
786 		if(active.machs == 0 && consactive() == 0)
787 			break;
788 	}
789 
790 	if(active.ispanic){
791 		if(!cpuserver)
792 			for(;;)
793 				halt();
794 		if(getconf("*debug"))
795 			delay(5*60*1000);
796 		else
797 			delay(10000);
798 	}else
799 		delay(1000);
800 }
801 
802 void
reboot(void * entry,void * code,ulong size)803 reboot(void *entry, void *code, ulong size)
804 {
805 	void (*f)(ulong, ulong, ulong);
806 	ulong *pdb;
807 
808 	writeconf();
809 
810 	/*
811 	 * the boot processor is cpu0.  execute this function on it
812 	 * so that the new kernel has the same cpu0.  this only matters
813 	 * because the hardware has a notion of which processor was the
814 	 * boot processor and we look at it at start up.
815 	 */
816 	if (m->machno != 0) {
817 		procwired(up, 0);
818 		sched();
819 	}
820 
821 	if(conf.nmach > 1) {
822 		/*
823 		 * the other cpus could be holding locks that will never get
824 		 * released (e.g., in the print path) if we put them into
825 		 * reset now, so force them to shutdown gracefully first.
826 		 */
827 		lock(&active);
828 		active.rebooting = 1;
829 		unlock(&active);
830 		shutdown(0);
831 		if(arch->resetothers)
832 			arch->resetothers();
833 		delay(20);
834 	}
835 
836 	/*
837 	 * should be the only processor running now
838 	 */
839 	active.machs = 0;
840 	if (m->machno != 0)
841 		print("on cpu%d (not 0)!\n", m->machno);
842 
843 	print("shutting down...\n");
844 	delay(200);
845 
846 	splhi();
847 
848 	/* turn off buffered serial console */
849 	serialoq = nil;
850 
851 	/* shutdown devices */
852 	chandevshutdown();
853 	arch->introff();
854 
855 	/*
856 	 * Modify the machine page table to directly map the low 4MB of memory
857 	 * This allows the reboot code to turn off the page mapping
858 	 */
859 	pdb = m->pdb;
860 	pdb[PDX(0)] = pdb[PDX(KZERO)];
861 	mmuflushtlb(PADDR(pdb));
862 
863 	/* setup reboot trampoline function */
864 	f = (void*)REBOOTADDR;
865 	memmove(f, rebootcode, sizeof(rebootcode));
866 
867 	print("rebooting...\n");
868 
869 	/* off we go - never to return */
870 	coherence();
871 	(*f)(PADDR(entry), PADDR(code), size);
872 }
873 
874 
875 void
exit(int ispanic)876 exit(int ispanic)
877 {
878 	shutdown(ispanic);
879 	arch->reset();
880 }
881 
882 int
isaconfig(char * class,int ctlrno,ISAConf * isa)883 isaconfig(char *class, int ctlrno, ISAConf *isa)
884 {
885 	char cc[32], *p;
886 	int i;
887 
888 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
889 	p = getconf(cc);
890 	if(p == nil)
891 		return 0;
892 
893 	isa->type = "";
894 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
895 	for(i = 0; i < isa->nopt; i++){
896 		p = isa->opt[i];
897 		if(cistrncmp(p, "type=", 5) == 0)
898 			isa->type = p + 5;
899 		else if(cistrncmp(p, "port=", 5) == 0)
900 			isa->port = strtoul(p+5, &p, 0);
901 		else if(cistrncmp(p, "irq=", 4) == 0)
902 			isa->irq = strtoul(p+4, &p, 0);
903 		else if(cistrncmp(p, "dma=", 4) == 0)
904 			isa->dma = strtoul(p+4, &p, 0);
905 		else if(cistrncmp(p, "mem=", 4) == 0)
906 			isa->mem = strtoul(p+4, &p, 0);
907 		else if(cistrncmp(p, "size=", 5) == 0)
908 			isa->size = strtoul(p+5, &p, 0);
909 		else if(cistrncmp(p, "freq=", 5) == 0)
910 			isa->freq = strtoul(p+5, &p, 0);
911 	}
912 	return 1;
913 }
914 
915 int
cistrcmp(char * a,char * b)916 cistrcmp(char *a, char *b)
917 {
918 	int ac, bc;
919 
920 	for(;;){
921 		ac = *a++;
922 		bc = *b++;
923 
924 		if(ac >= 'A' && ac <= 'Z')
925 			ac = 'a' + (ac - 'A');
926 		if(bc >= 'A' && bc <= 'Z')
927 			bc = 'a' + (bc - 'A');
928 		ac -= bc;
929 		if(ac)
930 			return ac;
931 		if(bc == 0)
932 			break;
933 	}
934 	return 0;
935 }
936 
937 int
cistrncmp(char * a,char * b,int n)938 cistrncmp(char *a, char *b, int n)
939 {
940 	unsigned ac, bc;
941 
942 	while(n > 0){
943 		ac = *a++;
944 		bc = *b++;
945 		n--;
946 
947 		if(ac >= 'A' && ac <= 'Z')
948 			ac = 'a' + (ac - 'A');
949 		if(bc >= 'A' && bc <= 'Z')
950 			bc = 'a' + (bc - 'A');
951 
952 		ac -= bc;
953 		if(ac)
954 			return ac;
955 		if(bc == 0)
956 			break;
957 	}
958 
959 	return 0;
960 }
961 
962 /*
963  *  put the processor in the halt state if we've no processes to run.
964  *  an interrupt will get us going again.
965  */
966 void
idlehands(void)967 idlehands(void)
968 {
969 	/*
970 	 * we used to halt only on single-core setups. halting in an smp system
971 	 * can result in a startup latency for processes that become ready.
972 	 * if idle_spin is zero, we care more about saving energy
973 	 * than reducing this latency.
974 	 *
975 	 * the performance loss with idle_spin == 0 seems to be slight
976 	 * and it reduces lock contention (thus system time and real time)
977 	 * on many-core systems with large values of NPROC.
978 	 */
979 	if(conf.nmach == 1 || idle_spin == 0 ||
980 	    idle_if_nproc && conf.nmach >= idle_if_nproc)
981 		halt();
982 }
983