Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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 *
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
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*
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
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
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
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
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
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
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
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
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
680
mathover(Ureg*, void*)
681
{
682
	pexit("math overrun", 0);
683
}
684
 
685
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
699
procsetup(Proc*p)
700
{
701
	p->fpstate = FPinit;
702
	fpoff();
703
}
704
 
705
void
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
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
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
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
876
exit(int ispanic)
877
{
878
	shutdown(ispanic);
879
	arch->reset();
880
}
881
 
882
int
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
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
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
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
}