xref: /plan9/sys/src/9/pcboot/main.c (revision 084126e8a4f119eb0ee0e36d1d73ebf0b5608c3b)
125210b06SDavid du Colombier /*
225210b06SDavid du Colombier  * 9boot - load next 386 or amd64 kernel from disk and start it
325210b06SDavid du Colombier  *	and
425210b06SDavid du Colombier  * 9load - load next 386 or amd64 kernel via pxe (bootp, tftp) and start it
525210b06SDavid du Colombier  *
625210b06SDavid du Colombier  * intel says that pxe can only load into the bottom 640K, and
725210b06SDavid du Colombier  * intel's pxe boot agent takes 128K, leaving only 512K for 9boot.
825210b06SDavid du Colombier  */
925210b06SDavid du Colombier #include	"u.h"
1025210b06SDavid du Colombier #include	"../port/lib.h"
1125210b06SDavid du Colombier #include	"mem.h"
1225210b06SDavid du Colombier #include	"dat.h"
1325210b06SDavid du Colombier #include	"fns.h"
1425210b06SDavid du Colombier #include	"io.h"
1525210b06SDavid du Colombier #include	"ureg.h"
1625210b06SDavid du Colombier #include	"pool.h"
1725210b06SDavid du Colombier #include	"reboot.h"
1825210b06SDavid du Colombier #include	"ip.h"		/* for eipfmt */
1923a96966SDavid du Colombier #include	<tos.h>
2025210b06SDavid du Colombier 
2125210b06SDavid du Colombier enum {
2225210b06SDavid du Colombier 	Datamagic = 0xbabeabed,
2325210b06SDavid du Colombier };
2425210b06SDavid du Colombier 
2525210b06SDavid du Colombier Mach *m;
2625210b06SDavid du Colombier 
2725210b06SDavid du Colombier ulong* mach0pdb;
2825210b06SDavid du Colombier Mach* mach0m;
2925210b06SDavid du Colombier Segdesc* mach0gdt;
3025210b06SDavid du Colombier u32int memstart;
3125210b06SDavid du Colombier u32int memend;
3225210b06SDavid du Colombier int noclock;
3325210b06SDavid du Colombier 
3425210b06SDavid du Colombier extern int pcivga;
3525210b06SDavid du Colombier extern char hellomsg[];
3625210b06SDavid du Colombier 
3725210b06SDavid du Colombier /*
3825210b06SDavid du Colombier  * Where configuration info is left for the loaded programme.
3925210b06SDavid du Colombier  */
4025210b06SDavid du Colombier char bootdisk[KNAMELEN];
4125210b06SDavid du Colombier Conf conf;
4225210b06SDavid du Colombier 
4325210b06SDavid du Colombier uchar *sp;	/* user stack of init proc */
4425210b06SDavid du Colombier int delaylink;
4525210b06SDavid du Colombier int debug;
4625210b06SDavid du Colombier int v_flag;
4725210b06SDavid du Colombier 
4825210b06SDavid du Colombier static void
sanity(void)4925210b06SDavid du Colombier sanity(void)
5025210b06SDavid du Colombier {
5125210b06SDavid du Colombier 	uintptr cr3;
5225210b06SDavid du Colombier 
5325210b06SDavid du Colombier 	cr3 = (uintptr)KADDR(getcr3());
5425210b06SDavid du Colombier 	if (cr3 == 0)
5525210b06SDavid du Colombier 		panic("zero cr3");
5625210b06SDavid du Colombier 	if ((uintptr)m->pdb != cr3 || (uintptr)mach0pdb != cr3)
5725210b06SDavid du Colombier 		panic("not all same: cr3 %#p m->pdb %#p mach0pdb %#p",
5825210b06SDavid du Colombier 			cr3, m->pdb, mach0pdb);
5925210b06SDavid du Colombier 	if (m != mach0m)
6025210b06SDavid du Colombier 		panic("m %#p != mach0m %#p", m, mach0m);
6125210b06SDavid du Colombier 	if (m->gdt != mach0gdt)
6225210b06SDavid du Colombier 		panic("m->gdt %#p != mach0gdt %#p", m->gdt, mach0gdt);
6325210b06SDavid du Colombier 	if (0)
6425210b06SDavid du Colombier 		iprint("m->pdb %#p m %#p sp %#p m->gdt %#p\n",
6525210b06SDavid du Colombier 			m->pdb, m, &cr3, m->gdt);
6625210b06SDavid du Colombier }
6725210b06SDavid du Colombier 
6825210b06SDavid du Colombier enum {
6925210b06SDavid du Colombier 	/* system control port a */
7025210b06SDavid du Colombier 	Sysctla=	0x92,
7125210b06SDavid du Colombier 	 Sysctlreset=	1<<0,
7225210b06SDavid du Colombier 	 Sysctla20ena=	1<<1,
7325210b06SDavid du Colombier };
7425210b06SDavid du Colombier 
7525210b06SDavid du Colombier static int
isa20on(void)7625210b06SDavid du Colombier isa20on(void)
7725210b06SDavid du Colombier {
7825210b06SDavid du Colombier 	int r;
7925210b06SDavid du Colombier 	ulong o;
8025210b06SDavid du Colombier 	ulong *zp, *mb1p;
8125210b06SDavid du Colombier 
8225210b06SDavid du Colombier 	zp = 0;
8325210b06SDavid du Colombier 	mb1p = (ulong *)MB;
8425210b06SDavid du Colombier 	o = *zp;
8525210b06SDavid du Colombier 
8625210b06SDavid du Colombier 	*zp = 0x1234;
8725210b06SDavid du Colombier 	*mb1p = 0x8765;
8825210b06SDavid du Colombier 	mb586();
8925210b06SDavid du Colombier 	wbinvd();
9025210b06SDavid du Colombier 	r = *zp != *mb1p;
9125210b06SDavid du Colombier 
9225210b06SDavid du Colombier 	*zp = o;
9325210b06SDavid du Colombier 	return r;
9425210b06SDavid du Colombier }
9525210b06SDavid du Colombier 
9625210b06SDavid du Colombier void
a20init(void)9725210b06SDavid du Colombier a20init(void)
9825210b06SDavid du Colombier {
9925210b06SDavid du Colombier 	int b;
10025210b06SDavid du Colombier 
10125210b06SDavid du Colombier 	if (isa20on())
10225210b06SDavid du Colombier 		return;
10325210b06SDavid du Colombier 
10425210b06SDavid du Colombier 	i8042a20();			/* original method, via kbd ctlr */
10525210b06SDavid du Colombier 	if (isa20on())
10625210b06SDavid du Colombier 		return;
10725210b06SDavid du Colombier 
10825210b06SDavid du Colombier 	/* newer method, last resort */
10925210b06SDavid du Colombier 	b = inb(Sysctla);
11025210b06SDavid du Colombier 	if (!(b & Sysctla20ena))
11125210b06SDavid du Colombier 		outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena);
112*084126e8SDavid du Colombier 	if (!isa20on()){
11325210b06SDavid du Colombier 		iprint("a20 didn't come on!\n");
114*084126e8SDavid du Colombier 		for(;;)
115*084126e8SDavid du Colombier 			;
116*084126e8SDavid du Colombier 	}
11725210b06SDavid du Colombier }
11825210b06SDavid du Colombier 
11925210b06SDavid du Colombier void
main(void)12025210b06SDavid du Colombier main(void)
12125210b06SDavid du Colombier {
12225210b06SDavid du Colombier 	Proc *savup;
12325210b06SDavid du Colombier 	static ulong vfy = Datamagic;
12425210b06SDavid du Colombier 	static char novga[] = "\nno vga; serial console only\n";
12525210b06SDavid du Colombier 
12625210b06SDavid du Colombier 	savup = up;
12725210b06SDavid du Colombier 	up = nil;
12825210b06SDavid du Colombier 	/* m has been set by l32v.s */
12925210b06SDavid du Colombier 
13025210b06SDavid du Colombier 	/*
13125210b06SDavid du Colombier 	 * disable address wraps at 1MB boundaries.
13225210b06SDavid du Colombier 	 * if we're 9boot, ldecomp.s already did this.
13325210b06SDavid du Colombier 	 */
13425210b06SDavid du Colombier 	a20init();
13525210b06SDavid du Colombier 
13625210b06SDavid du Colombier 	mach0init();
13725210b06SDavid du Colombier //	options();		/* we don't get options passed to us */
13825210b06SDavid du Colombier 	ioinit();
13925210b06SDavid du Colombier 	/* we later call i8250console after plan9.ini has been read */
14025210b06SDavid du Colombier 	i8250config("0");	/* configure serial port 0 with defaults */
14125210b06SDavid du Colombier 	quotefmtinstall();
14225210b06SDavid du Colombier  	fmtinstall('i', eipfmt);
14325210b06SDavid du Colombier  	fmtinstall('I', eipfmt);
14425210b06SDavid du Colombier  	fmtinstall('E', eipfmt);
14525210b06SDavid du Colombier  	fmtinstall('V', eipfmt);
14625210b06SDavid du Colombier  	fmtinstall('M', eipfmt);
14725210b06SDavid du Colombier 	screeninit();			/* cga setup */
14825210b06SDavid du Colombier 	cgapost(0xc);
14925210b06SDavid du Colombier 
15025210b06SDavid du Colombier 	trapinit0();
15125210b06SDavid du Colombier 	mmuinit0();
15225210b06SDavid du Colombier 
15325210b06SDavid du Colombier 	kbdinit();
15425210b06SDavid du Colombier 	i8253init();
15525210b06SDavid du Colombier 	cpuidentify();
15625210b06SDavid du Colombier 	readlsconf();
15725210b06SDavid du Colombier 	meminit();
15825210b06SDavid du Colombier 	confinit();
15925210b06SDavid du Colombier 	archinit();
16025210b06SDavid du Colombier 	xinit();
16125210b06SDavid du Colombier 	if(i8237alloc != nil)
16225210b06SDavid du Colombier 		i8237alloc();		/* dma (for floppy) init */
16325210b06SDavid du Colombier 	trapinit();
16425210b06SDavid du Colombier 	printinit();
16525210b06SDavid du Colombier 	sanity();
16625210b06SDavid du Colombier 	cgapost(1);
16725210b06SDavid du Colombier 
16825210b06SDavid du Colombier 	/*
16925210b06SDavid du Colombier 	 * soekris servers have no built-in video but each has a serial port.
17025210b06SDavid du Colombier 	 * they must see serial output, if any, before cga output because
17125210b06SDavid du Colombier 	 * otherwise the soekris bios will translate cga output to serial
17225210b06SDavid du Colombier 	 * output, which will garble serial console output.
17325210b06SDavid du Colombier 	 */
17425210b06SDavid du Colombier 	pcimatch(nil, 0, 0);		/* force scan of pci table */
17525210b06SDavid du Colombier 	if (!pcivga) {
17625210b06SDavid du Colombier 		screenputs = nil;
17725210b06SDavid du Colombier 		uartputs(novga, sizeof novga - 1);
17825210b06SDavid du Colombier 	}
17925210b06SDavid du Colombier 	print(" %s\n\n", hellomsg);
18025210b06SDavid du Colombier 
18125210b06SDavid du Colombier 	if (vfy != Datamagic)
18225210b06SDavid du Colombier 		panic("data segment incorrectly aligned or loaded");
18325210b06SDavid du Colombier 	if (savup)
18425210b06SDavid du Colombier 		print("up was non-nil (%#p) upon entry to main; bss wasn't zeroed!\n",
18525210b06SDavid du Colombier 			savup);
18625210b06SDavid du Colombier 
18725210b06SDavid du Colombier //	xsummary();
18825210b06SDavid du Colombier 	cpuidprint();
18925210b06SDavid du Colombier 	mmuinit();
19025210b06SDavid du Colombier 	if(arch->intrinit)	/* launches other processors on an mp */
19125210b06SDavid du Colombier 		arch->intrinit();
19225210b06SDavid du Colombier 	timersinit();
19325210b06SDavid du Colombier 	mathinit();
19425210b06SDavid du Colombier 	kbdenable();
19525210b06SDavid du Colombier 	/*
19625210b06SDavid du Colombier 	 * 9loadusb runs much faster if we don't use the clock.
19725210b06SDavid du Colombier 	 * perhaps we're competing with the bios for the use of it?
19825210b06SDavid du Colombier 	 */
19925210b06SDavid du Colombier 	if(!noclock && arch->clockenable)
20025210b06SDavid du Colombier 		arch->clockenable();
20125210b06SDavid du Colombier 	procinit0();
20225210b06SDavid du Colombier 	initseg();
20325210b06SDavid du Colombier 	if(delaylink){
20425210b06SDavid du Colombier 		bootlinks();
20525210b06SDavid du Colombier 		pcimatch(0, 0, 0);
20625210b06SDavid du Colombier 	}else
20725210b06SDavid du Colombier 		links();
20825210b06SDavid du Colombier 	conf.monitor = 1;
20925210b06SDavid du Colombier 	cgapost(0xcd);
21025210b06SDavid du Colombier 	chandevreset();
21125210b06SDavid du Colombier 	cgapost(2);
21225210b06SDavid du Colombier 	pageinit();	/* must follow xinit, and conf.mem must be populated */
21325210b06SDavid du Colombier 	i8253link();
21425210b06SDavid du Colombier 	userinit();
21525210b06SDavid du Colombier 
21625210b06SDavid du Colombier 	active.thunderbirdsarego = 1;
21725210b06SDavid du Colombier 	cgapost(0xb0);
21825210b06SDavid du Colombier 	schedinit();
21925210b06SDavid du Colombier }
22025210b06SDavid du Colombier 
22125210b06SDavid du Colombier void
mach0init(void)22225210b06SDavid du Colombier mach0init(void)
22325210b06SDavid du Colombier {
22425210b06SDavid du Colombier 	conf.nmach = 1;
22525210b06SDavid du Colombier 	MACHP(0) = mach0m;
22625210b06SDavid du Colombier 	m->machno = 0;
22725210b06SDavid du Colombier 	m->pdb = mach0pdb;
22825210b06SDavid du Colombier 	m->gdt = mach0gdt;
22925210b06SDavid du Colombier 
23025210b06SDavid du Colombier 	machinit();
23125210b06SDavid du Colombier 
23225210b06SDavid du Colombier 	active.machs = 1;
23325210b06SDavid du Colombier 	active.exiting = 0;
23425210b06SDavid du Colombier }
23525210b06SDavid du Colombier 
23625210b06SDavid du Colombier void
machinit(void)23725210b06SDavid du Colombier machinit(void)
23825210b06SDavid du Colombier {
23925210b06SDavid du Colombier 	int machno;
24025210b06SDavid du Colombier 	ulong *pdb;
24125210b06SDavid du Colombier 	Segdesc *gdt;
24225210b06SDavid du Colombier 
24325210b06SDavid du Colombier 	machno = m->machno;
24425210b06SDavid du Colombier 	pdb = m->pdb;
24525210b06SDavid du Colombier 	gdt = m->gdt;
24625210b06SDavid du Colombier 	memset(m, 0, sizeof(Mach));
24725210b06SDavid du Colombier 	m->machno = machno;
24825210b06SDavid du Colombier 	m->pdb = pdb;
24925210b06SDavid du Colombier 	m->gdt = gdt;
25025210b06SDavid du Colombier 	m->perf.period = 1;
25125210b06SDavid du Colombier 
25225210b06SDavid du Colombier 	/*
25325210b06SDavid du Colombier 	 * For polled uart output at boot, need
25425210b06SDavid du Colombier 	 * a default delay constant. 100000 should
25525210b06SDavid du Colombier 	 * be enough for a while. Cpuidentify will
25625210b06SDavid du Colombier 	 * calculate the real value later.
25725210b06SDavid du Colombier 	 */
25825210b06SDavid du Colombier 	m->loopconst = 100000;
25925210b06SDavid du Colombier }
26025210b06SDavid du Colombier 
26125210b06SDavid du Colombier void
init0(void)26225210b06SDavid du Colombier init0(void)
26325210b06SDavid du Colombier {
26425210b06SDavid du Colombier 	int i;
26525210b06SDavid du Colombier 	char buf[2*KNAMELEN];
26625210b06SDavid du Colombier 
26725210b06SDavid du Colombier 	up->nerrlab = 0;
26825210b06SDavid du Colombier 
26925210b06SDavid du Colombier 	spllo();
27025210b06SDavid du Colombier 
27125210b06SDavid du Colombier 	/*
27225210b06SDavid du Colombier 	 * These are o.k. because rootinit is null.
27325210b06SDavid du Colombier 	 * Then early kproc's will have a root and dot.
27425210b06SDavid du Colombier 	 */
27525210b06SDavid du Colombier 	up->slash = namec("#/", Atodir, 0, 0);
27625210b06SDavid du Colombier 	pathclose(up->slash->path);
27725210b06SDavid du Colombier 	up->slash->path = newpath("/");
27825210b06SDavid du Colombier 	up->dot = cclone(up->slash);
27925210b06SDavid du Colombier 
28025210b06SDavid du Colombier 	chandevinit();
28125210b06SDavid du Colombier 
28225210b06SDavid du Colombier 	if(0 && !waserror()){			/* not needed by boot */
28325210b06SDavid du Colombier 		snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
28425210b06SDavid du Colombier 		ksetenv("terminal", buf, 0);
28525210b06SDavid du Colombier 		ksetenv("cputype", "386", 0);
28625210b06SDavid du Colombier 		if(cpuserver)
28725210b06SDavid du Colombier 			ksetenv("service", "cpu", 0);
28825210b06SDavid du Colombier 		else
28925210b06SDavid du Colombier 			ksetenv("service", "terminal", 0);
29025210b06SDavid du Colombier 		for(i = 0; i < nconf; i++){
29125210b06SDavid du Colombier 			if(confname[i][0] != '*')
29225210b06SDavid du Colombier 				ksetenv(confname[i], confval[i], 0);
29325210b06SDavid du Colombier 			ksetenv(confname[i], confval[i], 1);
29425210b06SDavid du Colombier 		}
29525210b06SDavid du Colombier 		poperror();
29625210b06SDavid du Colombier 	}
29725210b06SDavid du Colombier 	kproc("alarm", alarmkproc, 0);
298c1e5ebd3SDavid du Colombier 
299c1e5ebd3SDavid du Colombier 	conschan = enamecopen("#c/cons", ORDWR);
300e4575fb1SDavid du Colombier 	bootloadproc(0);
301e4575fb1SDavid du Colombier 	panic("bootloadproc returned");
30225210b06SDavid du Colombier }
30325210b06SDavid du Colombier 
30425210b06SDavid du Colombier void
userinit(void)30525210b06SDavid du Colombier userinit(void)
30625210b06SDavid du Colombier {
30725210b06SDavid du Colombier 	Proc *p;
30825210b06SDavid du Colombier 
30925210b06SDavid du Colombier 	p = newproc();
31025210b06SDavid du Colombier 	p->pgrp = newpgrp();
31125210b06SDavid du Colombier 	p->egrp = smalloc(sizeof(Egrp));
31225210b06SDavid du Colombier 	p->egrp->ref = 1;
31325210b06SDavid du Colombier 	p->fgrp = dupfgrp(nil);
31425210b06SDavid du Colombier 	p->rgrp = newrgrp();
31525210b06SDavid du Colombier 	p->procmode = 0640;
31625210b06SDavid du Colombier 
31725210b06SDavid du Colombier 	kstrdup(&eve, "");
31825210b06SDavid du Colombier 	kstrdup(&p->text, "*init*");
31925210b06SDavid du Colombier 	kstrdup(&p->user, eve);
32025210b06SDavid du Colombier 
32125210b06SDavid du Colombier 	p->fpstate = FPinit;
32225210b06SDavid du Colombier 	fpoff();
32325210b06SDavid du Colombier 
32425210b06SDavid du Colombier 	/*
32525210b06SDavid du Colombier 	 * Kernel Stack
32625210b06SDavid du Colombier 	 *
32725210b06SDavid du Colombier 	 * N.B. make sure there's enough space for syscall to check
32825210b06SDavid du Colombier 	 *	for valid args and
32925210b06SDavid du Colombier 	 *	4 bytes for gotolabel's return PC
33025210b06SDavid du Colombier 	 */
33125210b06SDavid du Colombier 	p->sched.pc = (ulong)init0;
33225210b06SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
33325210b06SDavid du Colombier 
33425210b06SDavid du Colombier 	/* NB: no user stack nor text segments are set up */
33525210b06SDavid du Colombier 
33625210b06SDavid du Colombier 	ready(p);
33725210b06SDavid du Colombier }
33825210b06SDavid du Colombier 
33925210b06SDavid du Colombier void
confinit(void)34025210b06SDavid du Colombier confinit(void)
34125210b06SDavid du Colombier {
34225210b06SDavid du Colombier 	int i, userpcnt;
34325210b06SDavid du Colombier 	ulong kpages;
34425210b06SDavid du Colombier 
34525210b06SDavid du Colombier 	userpcnt = 0;			/* bootstrap; no user mode  */
34625210b06SDavid du Colombier 	conf.npage = 0;
34725210b06SDavid du Colombier 	for(i=0; i<nelem(conf.mem); i++)
34825210b06SDavid du Colombier 		conf.npage += conf.mem[i].npage;
34925210b06SDavid du Colombier 
35025210b06SDavid du Colombier 	conf.npage = MemMax / BY2PG;
35125210b06SDavid du Colombier 	conf.nproc = 20;		/* need a few kprocs */
35225210b06SDavid du Colombier 	if(cpuserver)
35325210b06SDavid du Colombier 		conf.nproc *= 3;
35425210b06SDavid du Colombier 	if(conf.nproc > 2000)
35525210b06SDavid du Colombier 		conf.nproc = 2000;
35625210b06SDavid du Colombier 	conf.nimage = 40;
35725210b06SDavid du Colombier 	conf.nswap = conf.nproc*80;
35825210b06SDavid du Colombier 	conf.nswppo = 4096;
35925210b06SDavid du Colombier 
36025210b06SDavid du Colombier 	kpages = conf.npage - (conf.npage*userpcnt)/100;
36125210b06SDavid du Colombier 
36225210b06SDavid du Colombier 	/*
36325210b06SDavid du Colombier 	 * can't go past the end of virtual memory
36425210b06SDavid du Colombier 	 * (ulong)-KZERO is 2^32 - KZERO
36525210b06SDavid du Colombier 	 */
36625210b06SDavid du Colombier 	if(kpages > ((ulong)-KZERO)/BY2PG)
36725210b06SDavid du Colombier 		kpages = ((ulong)-KZERO)/BY2PG;
36825210b06SDavid du Colombier 
36925210b06SDavid du Colombier 	conf.upages = conf.npage - kpages;
37025210b06SDavid du Colombier 	conf.ialloc = (kpages/2)*BY2PG;
37125210b06SDavid du Colombier 
37225210b06SDavid du Colombier 	/*
37325210b06SDavid du Colombier 	 * Guess how much is taken by the large permanent
37425210b06SDavid du Colombier 	 * datastructures. Mntcache and Mntrpc are not accounted for
37525210b06SDavid du Colombier 	 * (probably ~300KB).
37625210b06SDavid du Colombier 	 */
37725210b06SDavid du Colombier 	kpages *= BY2PG;
37825210b06SDavid du Colombier 	kpages -= conf.upages*sizeof(Page)
37925210b06SDavid du Colombier 		+ conf.nproc*sizeof(Proc)
38025210b06SDavid du Colombier 		+ conf.nimage*sizeof(Image)
38125210b06SDavid du Colombier 		+ conf.nswap
38225210b06SDavid du Colombier 		+ conf.nswppo*sizeof(Page);
38325210b06SDavid du Colombier 	mainmem->maxsize = kpages;
38425210b06SDavid du Colombier 	if(!cpuserver){
38525210b06SDavid du Colombier 		/*
38625210b06SDavid du Colombier 		 * give terminals lots of image memory, too; the dynamic
38725210b06SDavid du Colombier 		 * allocation will balance the load properly, hopefully.
38825210b06SDavid du Colombier 		 * be careful with 32-bit overflow.
38925210b06SDavid du Colombier 		 */
39025210b06SDavid du Colombier 		imagmem->maxsize = kpages;
39125210b06SDavid du Colombier 	}
39225210b06SDavid du Colombier }
39325210b06SDavid du Colombier 
39425210b06SDavid du Colombier /*
39525210b06SDavid du Colombier  *  math coprocessor segment overrun
39625210b06SDavid du Colombier  */
39725210b06SDavid du Colombier static void
mathover(Ureg *,void *)39825210b06SDavid du Colombier mathover(Ureg*, void*)
39925210b06SDavid du Colombier {
40025210b06SDavid du Colombier 	pexit("math overrun", 0);
40125210b06SDavid du Colombier }
40225210b06SDavid du Colombier 
40325210b06SDavid du Colombier void
mathinit(void)40425210b06SDavid du Colombier mathinit(void)
40525210b06SDavid du Colombier {
40625210b06SDavid du Colombier }
40725210b06SDavid du Colombier 
40825210b06SDavid du Colombier /*
40925210b06SDavid du Colombier  *  set up floating point for a new process
41025210b06SDavid du Colombier  */
41125210b06SDavid du Colombier void
procsetup(Proc * p)41225210b06SDavid du Colombier procsetup(Proc*p)
41325210b06SDavid du Colombier {
41425210b06SDavid du Colombier 	p->fpstate = FPinit;
41525210b06SDavid du Colombier 	fpoff();
41625210b06SDavid du Colombier }
41725210b06SDavid du Colombier 
41825210b06SDavid du Colombier void
procrestore(Proc * p)41925210b06SDavid du Colombier procrestore(Proc *p)
42025210b06SDavid du Colombier {
42125210b06SDavid du Colombier 	uvlong t;
42225210b06SDavid du Colombier 
42325210b06SDavid du Colombier 	if(p->kp)
42425210b06SDavid du Colombier 		return;
42525210b06SDavid du Colombier 	cycles(&t);
42625210b06SDavid du Colombier 	p->pcycles -= t;
42725210b06SDavid du Colombier }
42825210b06SDavid du Colombier 
42925210b06SDavid du Colombier /*
43025210b06SDavid du Colombier  *  Save the mach dependent part of the process state.
43125210b06SDavid du Colombier  */
43225210b06SDavid du Colombier void
procsave(Proc * p)43325210b06SDavid du Colombier procsave(Proc *p)
43425210b06SDavid du Colombier {
43525210b06SDavid du Colombier 	uvlong t;
43625210b06SDavid du Colombier 
43725210b06SDavid du Colombier 	cycles(&t);
43825210b06SDavid du Colombier 	p->pcycles += t;
43925210b06SDavid du Colombier 
44025210b06SDavid du Colombier 	/*
44125210b06SDavid du Colombier 	 * While this processor is in the scheduler, the process could run
44225210b06SDavid du Colombier 	 * on another processor and exit, returning the page tables to
44325210b06SDavid du Colombier 	 * the free list where they could be reallocated and overwritten.
44425210b06SDavid du Colombier 	 * When this processor eventually has to get an entry from the
44525210b06SDavid du Colombier 	 * trashed page tables it will crash.
44625210b06SDavid du Colombier 	 *
44725210b06SDavid du Colombier 	 * If there's only one processor, this can't happen.
44825210b06SDavid du Colombier 	 * You might think it would be a win not to do this in that case,
44925210b06SDavid du Colombier 	 * especially on VMware, but it turns out not to matter.
45025210b06SDavid du Colombier 	 */
45125210b06SDavid du Colombier 	mmuflushtlb(PADDR(m->pdb));
45225210b06SDavid du Colombier }
45325210b06SDavid du Colombier 
45425210b06SDavid du Colombier static void
shutdown(int ispanic)45525210b06SDavid du Colombier shutdown(int ispanic)
45625210b06SDavid du Colombier {
45725210b06SDavid du Colombier 	int ms, once;
45825210b06SDavid du Colombier 
45925210b06SDavid du Colombier 	lock(&active);
46025210b06SDavid du Colombier 	if(ispanic)
46125210b06SDavid du Colombier 		active.ispanic = ispanic;
46225210b06SDavid du Colombier 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
46325210b06SDavid du Colombier 		active.ispanic = 0;
46425210b06SDavid du Colombier 	once = active.machs & (1<<m->machno);
46525210b06SDavid du Colombier 	/*
46625210b06SDavid du Colombier 	 * setting exiting will make hzclock() on each processor call exit(0),
46725210b06SDavid du Colombier 	 * which calls shutdown(0) and arch->reset(), which on mp systems is
46825210b06SDavid du Colombier 	 * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap
46925210b06SDavid du Colombier 	 * processors (to permit a reboot).  clearing our bit in machs avoids
47025210b06SDavid du Colombier 	 * calling exit(0) from hzclock() on this processor.
47125210b06SDavid du Colombier 	 */
47225210b06SDavid du Colombier 	active.machs &= ~(1<<m->machno);
47325210b06SDavid du Colombier 	active.exiting = 1;
47425210b06SDavid du Colombier 	unlock(&active);
47525210b06SDavid du Colombier 
47625210b06SDavid du Colombier 	if(once)
47725210b06SDavid du Colombier 		iprint("cpu%d: exiting\n", m->machno);
47825210b06SDavid du Colombier 
47925210b06SDavid du Colombier 	/* wait for any other processors to shutdown */
48025210b06SDavid du Colombier 	spllo();
48125210b06SDavid du Colombier 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
48225210b06SDavid du Colombier 		delay(TK2MS(2));
48325210b06SDavid du Colombier 		if(active.machs == 0 && consactive() == 0)
48425210b06SDavid du Colombier 			break;
48525210b06SDavid du Colombier 	}
48625210b06SDavid du Colombier 
48725210b06SDavid du Colombier 	if(active.ispanic){
48825210b06SDavid du Colombier 		if(!cpuserver)
48925210b06SDavid du Colombier 			for(;;)
49025210b06SDavid du Colombier 				halt();
49125210b06SDavid du Colombier 		if(getconf("*debug"))
49225210b06SDavid du Colombier 			delay(5*60*1000);
49325210b06SDavid du Colombier 		else
49425210b06SDavid du Colombier 			delay(10000);
49525210b06SDavid du Colombier 	}else
49625210b06SDavid du Colombier 		delay(1000);
49725210b06SDavid du Colombier }
49825210b06SDavid du Colombier 
49925210b06SDavid du Colombier void
reboot(void * entry,void * code,ulong size)50025210b06SDavid du Colombier reboot(void *entry, void *code, ulong size)
50125210b06SDavid du Colombier {
50225210b06SDavid du Colombier 	int i;
50325210b06SDavid du Colombier 	void (*f)(ulong, ulong, ulong);
50425210b06SDavid du Colombier 	ulong *pdb;
50525210b06SDavid du Colombier 
50625210b06SDavid du Colombier 	/* we do pass options to the kernel we loaded, however, at CONFADDR. */
50725210b06SDavid du Colombier 	// writeconf();
50825210b06SDavid du Colombier 
50925210b06SDavid du Colombier 	/*
51025210b06SDavid du Colombier 	 * the boot processor is cpu0.  execute this function on it
51125210b06SDavid du Colombier 	 * so that the new kernel has the same cpu0.  this only matters
51225210b06SDavid du Colombier 	 * because the hardware has a notion of which processor was the
51325210b06SDavid du Colombier 	 * boot processor and we look at it at start up.
51425210b06SDavid du Colombier 	 */
51525210b06SDavid du Colombier 	if (m->machno != 0) {
51625210b06SDavid du Colombier 		procwired(up, 0);
51725210b06SDavid du Colombier 		sched();
51825210b06SDavid du Colombier 	}
51925210b06SDavid du Colombier 
52025210b06SDavid du Colombier 	if(conf.nmach > 1) {
52125210b06SDavid du Colombier 		/*
52225210b06SDavid du Colombier 		 * the other cpus could be holding locks that will never get
52325210b06SDavid du Colombier 		 * released (e.g., in the print path) if we put them into
52425210b06SDavid du Colombier 		 * reset now, so force them to shutdown gracefully first.
52525210b06SDavid du Colombier 		 */
52625210b06SDavid du Colombier 		lock(&active);
52725210b06SDavid du Colombier 		active.rebooting = 1;
52825210b06SDavid du Colombier 		unlock(&active);
52925210b06SDavid du Colombier 		shutdown(0);
53025210b06SDavid du Colombier 		if(arch->resetothers)
53125210b06SDavid du Colombier 			arch->resetothers();
53225210b06SDavid du Colombier 		delay(20);
53325210b06SDavid du Colombier 	}
53425210b06SDavid du Colombier 
53525210b06SDavid du Colombier 	/*
53625210b06SDavid du Colombier 	 * should be the only processor running now
53725210b06SDavid du Colombier 	 */
53825210b06SDavid du Colombier 	active.machs = 0;
53925210b06SDavid du Colombier 	if (m->machno != 0)
54025210b06SDavid du Colombier 		print("on cpu%d (not 0)!\n", m->machno);
54125210b06SDavid du Colombier 
54225210b06SDavid du Colombier 	print("shutting down...\n");
54325210b06SDavid du Colombier 	delay(200);
54425210b06SDavid du Colombier 
54525210b06SDavid du Colombier 	splhi();
54625210b06SDavid du Colombier 
54725210b06SDavid du Colombier 	/* turn off buffered serial console */
54825210b06SDavid du Colombier 	serialoq = nil;
54925210b06SDavid du Colombier 
55025210b06SDavid du Colombier 	/* shutdown devices */
55125210b06SDavid du Colombier 	chandevshutdown();
55225210b06SDavid du Colombier 	arch->introff();
55325210b06SDavid du Colombier 
55425210b06SDavid du Colombier 	/*
55525210b06SDavid du Colombier 	 * Modify the machine page table to directly map low memory
55625210b06SDavid du Colombier 	 * This allows the reboot code to turn off the page mapping
55725210b06SDavid du Colombier 	 */
55825210b06SDavid du Colombier 	pdb = m->pdb;
55925210b06SDavid du Colombier 	for (i = 0; i < LOWPTEPAGES; i++)
56025210b06SDavid du Colombier 		pdb[PDX(i*4*MB)] = pdb[PDX(KZERO + i*4*MB)];
56125210b06SDavid du Colombier 	mmuflushtlb(PADDR(pdb));
56225210b06SDavid du Colombier 
56325210b06SDavid du Colombier 	/* setup reboot trampoline function */
56425210b06SDavid du Colombier 	f = (void*)REBOOTADDR;
56525210b06SDavid du Colombier 	memmove(f, rebootcode, sizeof(rebootcode));
56625210b06SDavid du Colombier 
56725210b06SDavid du Colombier 	print("rebooting...\n");
56825210b06SDavid du Colombier 
56925210b06SDavid du Colombier 	/* off we go - never to return */
57025210b06SDavid du Colombier 	coherence();
57125210b06SDavid du Colombier 	(*f)(PADDR(entry), PADDR(code), size);
57225210b06SDavid du Colombier }
57325210b06SDavid du Colombier 
57425210b06SDavid du Colombier 
57525210b06SDavid du Colombier void
exit(int ispanic)57625210b06SDavid du Colombier exit(int ispanic)
57725210b06SDavid du Colombier {
57825210b06SDavid du Colombier 	shutdown(ispanic);
57925210b06SDavid du Colombier 	spllo();
58025210b06SDavid du Colombier 	arch->reset();
58125210b06SDavid du Colombier }
58225210b06SDavid du Colombier 
58325210b06SDavid du Colombier int
isaconfig(char * class,int ctlrno,ISAConf * isa)58425210b06SDavid du Colombier isaconfig(char *class, int ctlrno, ISAConf *isa)
58525210b06SDavid du Colombier {
58625210b06SDavid du Colombier 	char cc[32], *p;
58725210b06SDavid du Colombier 	int i;
58825210b06SDavid du Colombier 
58925210b06SDavid du Colombier 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
59025210b06SDavid du Colombier 	p = getconf(cc);
59125210b06SDavid du Colombier 	if(p == nil)
59225210b06SDavid du Colombier 		return 0;
59325210b06SDavid du Colombier 
59425210b06SDavid du Colombier 	isa->type = "";
59525210b06SDavid du Colombier 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
59625210b06SDavid du Colombier 	for(i = 0; i < isa->nopt; i++){
59725210b06SDavid du Colombier 		p = isa->opt[i];
59825210b06SDavid du Colombier 		if(cistrncmp(p, "type=", 5) == 0)
59925210b06SDavid du Colombier 			isa->type = p + 5;
60025210b06SDavid du Colombier 		else if(cistrncmp(p, "port=", 5) == 0)
60125210b06SDavid du Colombier 			isa->port = strtoul(p+5, &p, 0);
60225210b06SDavid du Colombier 		else if(cistrncmp(p, "irq=", 4) == 0)
60325210b06SDavid du Colombier 			isa->irq = strtoul(p+4, &p, 0);
60425210b06SDavid du Colombier 		else if(cistrncmp(p, "dma=", 4) == 0)
60525210b06SDavid du Colombier 			isa->dma = strtoul(p+4, &p, 0);
60625210b06SDavid du Colombier 		else if(cistrncmp(p, "mem=", 4) == 0)
60725210b06SDavid du Colombier 			isa->mem = strtoul(p+4, &p, 0);
60825210b06SDavid du Colombier 		else if(cistrncmp(p, "size=", 5) == 0)
60925210b06SDavid du Colombier 			isa->size = strtoul(p+5, &p, 0);
61025210b06SDavid du Colombier 		else if(cistrncmp(p, "freq=", 5) == 0)
61125210b06SDavid du Colombier 			isa->freq = strtoul(p+5, &p, 0);
61225210b06SDavid du Colombier 	}
61325210b06SDavid du Colombier 	return 1;
61425210b06SDavid du Colombier }
61525210b06SDavid du Colombier 
61625210b06SDavid du Colombier int
cistrcmp(char * a,char * b)61725210b06SDavid du Colombier cistrcmp(char *a, char *b)
61825210b06SDavid du Colombier {
61925210b06SDavid du Colombier 	int ac, bc;
62025210b06SDavid du Colombier 
62125210b06SDavid du Colombier 	for(;;){
62225210b06SDavid du Colombier 		ac = *a++;
62325210b06SDavid du Colombier 		bc = *b++;
62425210b06SDavid du Colombier 
62525210b06SDavid du Colombier 		if(ac >= 'A' && ac <= 'Z')
62625210b06SDavid du Colombier 			ac = 'a' + (ac - 'A');
62725210b06SDavid du Colombier 		if(bc >= 'A' && bc <= 'Z')
62825210b06SDavid du Colombier 			bc = 'a' + (bc - 'A');
62925210b06SDavid du Colombier 		ac -= bc;
63025210b06SDavid du Colombier 		if(ac)
63125210b06SDavid du Colombier 			return ac;
63225210b06SDavid du Colombier 		if(bc == 0)
63325210b06SDavid du Colombier 			break;
63425210b06SDavid du Colombier 	}
63525210b06SDavid du Colombier 	return 0;
63625210b06SDavid du Colombier }
63725210b06SDavid du Colombier 
63825210b06SDavid du Colombier int
cistrncmp(char * a,char * b,int n)63925210b06SDavid du Colombier cistrncmp(char *a, char *b, int n)
64025210b06SDavid du Colombier {
64125210b06SDavid du Colombier 	unsigned ac, bc;
64225210b06SDavid du Colombier 
64325210b06SDavid du Colombier 	while(n > 0){
64425210b06SDavid du Colombier 		ac = *a++;
64525210b06SDavid du Colombier 		bc = *b++;
64625210b06SDavid du Colombier 		n--;
64725210b06SDavid du Colombier 
64825210b06SDavid du Colombier 		if(ac >= 'A' && ac <= 'Z')
64925210b06SDavid du Colombier 			ac = 'a' + (ac - 'A');
65025210b06SDavid du Colombier 		if(bc >= 'A' && bc <= 'Z')
65125210b06SDavid du Colombier 			bc = 'a' + (bc - 'A');
65225210b06SDavid du Colombier 
65325210b06SDavid du Colombier 		ac -= bc;
65425210b06SDavid du Colombier 		if(ac)
65525210b06SDavid du Colombier 			return ac;
65625210b06SDavid du Colombier 		if(bc == 0)
65725210b06SDavid du Colombier 			break;
65825210b06SDavid du Colombier 	}
65925210b06SDavid du Colombier 
66025210b06SDavid du Colombier 	return 0;
66125210b06SDavid du Colombier }
66225210b06SDavid du Colombier 
66325210b06SDavid du Colombier int less_power_slower;
66425210b06SDavid du Colombier 
66525210b06SDavid du Colombier /*
66625210b06SDavid du Colombier  *  put the processor in the halt state if we've no processes to run.
66725210b06SDavid du Colombier  *  an interrupt will get us going again.
66825210b06SDavid du Colombier  */
66925210b06SDavid du Colombier void
idlehands(void)67025210b06SDavid du Colombier idlehands(void)
67125210b06SDavid du Colombier {
67225210b06SDavid du Colombier 	/*
67325210b06SDavid du Colombier 	 * we used to halt only on single-core setups. halting in an smp system
67425210b06SDavid du Colombier 	 * can result in a startup latency for processes that become ready.
67525210b06SDavid du Colombier 	 * if less_power_slower is true, we care more about saving energy
67625210b06SDavid du Colombier 	 * than reducing this latency.
67725210b06SDavid du Colombier 	 */
67825210b06SDavid du Colombier 	if(conf.nmach == 1 || less_power_slower)
67925210b06SDavid du Colombier 		halt();
68025210b06SDavid du Colombier }
68125210b06SDavid du Colombier 
68225210b06SDavid du Colombier void
trimnl(char * s)68325210b06SDavid du Colombier trimnl(char *s)
68425210b06SDavid du Colombier {
68525210b06SDavid du Colombier 	char *nl;
68625210b06SDavid du Colombier 
68725210b06SDavid du Colombier 	nl = strchr(s, '\n');
68825210b06SDavid du Colombier 	if (nl != nil)
68925210b06SDavid du Colombier 		*nl = '\0';
69025210b06SDavid du Colombier }
691