xref: /plan9/sys/src/9/pc/main.c (revision 217e9e83c7f9cc6fb27d97dda90c8339b6f98728)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"io.h"
73e12c5d1SDavid du Colombier #include	"ureg.h"
83e12c5d1SDavid du Colombier #include	"init.h"
97dd7cddfSDavid du Colombier #include	"pool.h"
109a747e4fSDavid du Colombier #include	"reboot.h"
11e332dd3eSDavid du Colombier #include	"mp.h"
1223a96966SDavid du Colombier #include	<tos.h>
133e12c5d1SDavid du Colombier 
147dd7cddfSDavid du Colombier Mach *m;
153e12c5d1SDavid du Colombier 
167dd7cddfSDavid du Colombier /*
177dd7cddfSDavid du Colombier  * Where configuration info is left for the loaded programme.
187dd7cddfSDavid du Colombier  * This will turn into a structure as more is done by the boot loader
197dd7cddfSDavid du Colombier  * (e.g. why parse the .ini file twice?).
209a747e4fSDavid du Colombier  * There are 3584 bytes available at CONFADDR.
217dd7cddfSDavid du Colombier  */
227dd7cddfSDavid du Colombier #define BOOTLINE	((char*)CONFADDR)
237dd7cddfSDavid du Colombier #define BOOTLINELEN	64
247dd7cddfSDavid du Colombier #define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
2559cc4ca5SDavid du Colombier #define	BOOTARGSLEN	(4096-0x200-BOOTLINELEN)
269a747e4fSDavid du Colombier #define	MAXCONF		64
27219b2ee8SDavid du Colombier 
2823a96966SDavid du Colombier enum {
2923a96966SDavid du Colombier 	/* space for syscall args, return PC, top-of-stack struct */
3023a96966SDavid du Colombier 	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
3123a96966SDavid du Colombier };
3223a96966SDavid du Colombier 
339a747e4fSDavid du Colombier char bootdisk[KNAMELEN];
349a747e4fSDavid du Colombier Conf conf;
35219b2ee8SDavid du Colombier char *confname[MAXCONF];
36219b2ee8SDavid du Colombier char *confval[MAXCONF];
37219b2ee8SDavid du Colombier int nconf;
389a747e4fSDavid du Colombier uchar *sp;	/* user stack of init proc */
394de34a7eSDavid du Colombier int delaylink;
40d3993254SDavid du Colombier int idle_spin, idle_if_nproc;
41219b2ee8SDavid du Colombier 
427dd7cddfSDavid du Colombier static void
options(void)437dd7cddfSDavid du Colombier options(void)
447dd7cddfSDavid du Colombier {
457dd7cddfSDavid du Colombier 	long i, n;
467dd7cddfSDavid du Colombier 	char *cp, *line[MAXCONF], *p, *q;
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier 	/*
497dd7cddfSDavid du Colombier 	 *  parse configuration args from dos file plan9.ini
507dd7cddfSDavid du Colombier 	 */
517dd7cddfSDavid du Colombier 	cp = BOOTARGS;	/* where b.com leaves its config */
527dd7cddfSDavid du Colombier 	cp[BOOTARGSLEN-1] = 0;
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier 	/*
557dd7cddfSDavid du Colombier 	 * Strip out '\r', change '\t' -> ' '.
567dd7cddfSDavid du Colombier 	 */
577dd7cddfSDavid du Colombier 	p = cp;
587dd7cddfSDavid du Colombier 	for(q = cp; *q; q++){
597dd7cddfSDavid du Colombier 		if(*q == '\r')
607dd7cddfSDavid du Colombier 			continue;
617dd7cddfSDavid du Colombier 		if(*q == '\t')
627dd7cddfSDavid du Colombier 			*q = ' ';
637dd7cddfSDavid du Colombier 		*p++ = *q;
647dd7cddfSDavid du Colombier 	}
657dd7cddfSDavid du Colombier 	*p = 0;
667dd7cddfSDavid du Colombier 
679a747e4fSDavid du Colombier 	n = getfields(cp, line, MAXCONF, 1, "\n");
687dd7cddfSDavid du Colombier 	for(i = 0; i < n; i++){
697dd7cddfSDavid du Colombier 		if(*line[i] == '#')
707dd7cddfSDavid du Colombier 			continue;
717dd7cddfSDavid du Colombier 		cp = strchr(line[i], '=');
729a747e4fSDavid du Colombier 		if(cp == nil)
737dd7cddfSDavid du Colombier 			continue;
749a747e4fSDavid du Colombier 		*cp++ = '\0';
757dd7cddfSDavid du Colombier 		confname[nconf] = line[i];
767dd7cddfSDavid du Colombier 		confval[nconf] = cp;
777dd7cddfSDavid du Colombier 		nconf++;
787dd7cddfSDavid du Colombier 	}
797dd7cddfSDavid du Colombier }
80219b2ee8SDavid du Colombier 
81425afbabSDavid du Colombier extern void mmuinit0(void);
82425afbabSDavid du Colombier extern void (*i8237alloc)(void);
83425afbabSDavid du Colombier 
843e12c5d1SDavid du Colombier void
fpsavealloc(void)854e3613abSDavid du Colombier fpsavealloc(void)
864e3613abSDavid du Colombier {
874e3613abSDavid du Colombier 	m->fpsavalign = mallocalign(sizeof(FPssestate), FPalign, 0, 0);
884e3613abSDavid du Colombier 	if (m->fpsavalign == nil)
894e3613abSDavid du Colombier 		panic("cpu%d: can't allocate fpsavalign", m->machno);
904e3613abSDavid du Colombier }
914e3613abSDavid du Colombier 
92*217e9e83SDavid du Colombier static int
isa20on(void)93*217e9e83SDavid du Colombier isa20on(void)
94*217e9e83SDavid du Colombier {
95*217e9e83SDavid du Colombier 	int r;
96*217e9e83SDavid du Colombier 	ulong o;
97*217e9e83SDavid du Colombier 	ulong *zp, *mb1p;
98*217e9e83SDavid du Colombier 
99*217e9e83SDavid du Colombier 	zp = (ulong *)KZERO;
100*217e9e83SDavid du Colombier 	mb1p = (ulong *)(KZERO|MB);
101*217e9e83SDavid du Colombier 	o = *zp;
102*217e9e83SDavid du Colombier 
103*217e9e83SDavid du Colombier 	*zp = 0x1234;
104*217e9e83SDavid du Colombier 	*mb1p = 0x8765;
105*217e9e83SDavid du Colombier 	coherence();
106*217e9e83SDavid du Colombier 	wbinvd();
107*217e9e83SDavid du Colombier 	r = *zp != *mb1p;
108*217e9e83SDavid du Colombier 
109*217e9e83SDavid du Colombier 	*zp = o;
110*217e9e83SDavid du Colombier 	return r;
111*217e9e83SDavid du Colombier }
112*217e9e83SDavid du Colombier 
1134e3613abSDavid du Colombier void
main(void)1143e12c5d1SDavid du Colombier main(void)
1153e12c5d1SDavid du Colombier {
116d3993254SDavid du Colombier 	cgapost(0);
1179a747e4fSDavid du Colombier 	mach0init();
1187dd7cddfSDavid du Colombier 	options();
1199a747e4fSDavid du Colombier 	ioinit();
1209a747e4fSDavid du Colombier 	i8250console();
1219a747e4fSDavid du Colombier 	quotefmtinstall();
122fe853e23SDavid du Colombier 	screeninit();
1239a747e4fSDavid du Colombier 
1249a747e4fSDavid du Colombier 	print("\nPlan 9\n");
1259a747e4fSDavid du Colombier 
1264de34a7eSDavid du Colombier 	trapinit0();
1274de34a7eSDavid du Colombier 	mmuinit0();
1284de34a7eSDavid du Colombier 
1299a747e4fSDavid du Colombier 	kbdinit();
1309a747e4fSDavid du Colombier 	i8253init();
1317dd7cddfSDavid du Colombier 	cpuidentify();
1329a747e4fSDavid du Colombier 	meminit();
1337dd7cddfSDavid du Colombier 	confinit();
134fe853e23SDavid du Colombier 	archinit();
135*217e9e83SDavid du Colombier 	if(!isa20on())
136*217e9e83SDavid du Colombier 		panic("bootstrap didn't leave a20 address line enabled");
1377dd7cddfSDavid du Colombier 	xinit();
138425afbabSDavid du Colombier 	if(i8237alloc != nil)
139425afbabSDavid du Colombier 		i8237alloc();
1403e12c5d1SDavid du Colombier 	trapinit();
1417dd7cddfSDavid du Colombier 	printinit();
1427dd7cddfSDavid du Colombier 	cpuidprint();
1437dd7cddfSDavid du Colombier 	mmuinit();
1444e3613abSDavid du Colombier 	fpsavealloc();
145fe853e23SDavid du Colombier 	if(arch->intrinit)	/* launches other processors on an mp */
1467dd7cddfSDavid du Colombier 		arch->intrinit();
1479a747e4fSDavid du Colombier 	timersinit();
1483e12c5d1SDavid du Colombier 	mathinit();
1499a747e4fSDavid du Colombier 	kbdenable();
1507dd7cddfSDavid du Colombier 	if(arch->clockenable)
1517dd7cddfSDavid du Colombier 		arch->clockenable();
1523e12c5d1SDavid du Colombier 	procinit0();
1533e12c5d1SDavid du Colombier 	initseg();
1544de34a7eSDavid du Colombier 	if(delaylink){
1554de34a7eSDavid du Colombier 		bootlinks();
1564de34a7eSDavid du Colombier 		pcimatch(0, 0, 0);
1574de34a7eSDavid du Colombier 	}else
1587dd7cddfSDavid du Colombier 		links();
1597dd7cddfSDavid du Colombier 	conf.monitor = 1;
160219b2ee8SDavid du Colombier 	chandevreset();
161d3993254SDavid du Colombier 	cgapost(0xcd);
162d3993254SDavid du Colombier 
1637dd7cddfSDavid du Colombier 	pageinit();
164dc5a79c1SDavid du Colombier 	i8253link();
1653e12c5d1SDavid du Colombier 	swapinit();
1663e12c5d1SDavid du Colombier 	userinit();
167da51d93aSDavid du Colombier 	active.thunderbirdsarego = 1;
168d3993254SDavid du Colombier 
169d3993254SDavid du Colombier 	cgapost(0x99);
1703e12c5d1SDavid du Colombier 	schedinit();
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier void
mach0init(void)1749a747e4fSDavid du Colombier mach0init(void)
1759a747e4fSDavid du Colombier {
1769a747e4fSDavid du Colombier 	conf.nmach = 1;
1779a747e4fSDavid du Colombier 	MACHP(0) = (Mach*)CPU0MACH;
1789a747e4fSDavid du Colombier 	m->pdb = (ulong*)CPU0PDB;
1799a747e4fSDavid du Colombier 	m->gdt = (Segdesc*)CPU0GDT;
1809a747e4fSDavid du Colombier 
1819a747e4fSDavid du Colombier 	machinit();
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	active.machs = 1;
1849a747e4fSDavid du Colombier 	active.exiting = 0;
1859a747e4fSDavid du Colombier }
1869a747e4fSDavid du Colombier 
1879a747e4fSDavid du Colombier void
machinit(void)1883e12c5d1SDavid du Colombier machinit(void)
1893e12c5d1SDavid du Colombier {
1907dd7cddfSDavid du Colombier 	int machno;
1917dd7cddfSDavid du Colombier 	ulong *pdb;
1929a747e4fSDavid du Colombier 	Segdesc *gdt;
1933e12c5d1SDavid du Colombier 
1947dd7cddfSDavid du Colombier 	machno = m->machno;
1957dd7cddfSDavid du Colombier 	pdb = m->pdb;
1969a747e4fSDavid du Colombier 	gdt = m->gdt;
1973e12c5d1SDavid du Colombier 	memset(m, 0, sizeof(Mach));
1987dd7cddfSDavid du Colombier 	m->machno = machno;
1997dd7cddfSDavid du Colombier 	m->pdb = pdb;
2009a747e4fSDavid du Colombier 	m->gdt = gdt;
201d9306527SDavid du Colombier 	m->perf.period = 1;
2023e12c5d1SDavid du Colombier 
2039a747e4fSDavid du Colombier 	/*
2049a747e4fSDavid du Colombier 	 * For polled uart output at boot, need
2059a747e4fSDavid du Colombier 	 * a default delay constant. 100000 should
2069a747e4fSDavid du Colombier 	 * be enough for a while. Cpuidentify will
2079a747e4fSDavid du Colombier 	 * calculate the real value later.
2089a747e4fSDavid du Colombier 	 */
2099a747e4fSDavid du Colombier 	m->loopconst = 100000;
2107dd7cddfSDavid du Colombier }
2113e12c5d1SDavid du Colombier 
2123e12c5d1SDavid du Colombier void
init0(void)2133e12c5d1SDavid du Colombier init0(void)
2143e12c5d1SDavid du Colombier {
215219b2ee8SDavid du Colombier 	int i;
2169a747e4fSDavid du Colombier 	char buf[2*KNAMELEN];
2173e12c5d1SDavid du Colombier 
2187dd7cddfSDavid du Colombier 	up->nerrlab = 0;
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier 	spllo();
2213e12c5d1SDavid du Colombier 
2223e12c5d1SDavid du Colombier 	/*
2233e12c5d1SDavid du Colombier 	 * These are o.k. because rootinit is null.
2243e12c5d1SDavid du Colombier 	 * Then early kproc's will have a root and dot.
2253e12c5d1SDavid du Colombier 	 */
2267dd7cddfSDavid du Colombier 	up->slash = namec("#/", Atodir, 0, 0);
2274afe124fSDavid du Colombier 	pathclose(up->slash->path);
2284afe124fSDavid du Colombier 	up->slash->path = newpath("/");
2299a747e4fSDavid du Colombier 	up->dot = cclone(up->slash);
2303e12c5d1SDavid du Colombier 
2313e12c5d1SDavid du Colombier 	chandevinit();
2323e12c5d1SDavid du Colombier 
2333e12c5d1SDavid du Colombier 	if(!waserror()){
2349a747e4fSDavid du Colombier 		snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
2359a747e4fSDavid du Colombier 		ksetenv("terminal", buf, 0);
2369a747e4fSDavid du Colombier 		ksetenv("cputype", "386", 0);
2377dd7cddfSDavid du Colombier 		if(cpuserver)
2389a747e4fSDavid du Colombier 			ksetenv("service", "cpu", 0);
2397dd7cddfSDavid du Colombier 		else
2409a747e4fSDavid du Colombier 			ksetenv("service", "terminal", 0);
2419a747e4fSDavid du Colombier 		for(i = 0; i < nconf; i++){
2429a747e4fSDavid du Colombier 			if(confname[i][0] != '*')
2439a747e4fSDavid du Colombier 				ksetenv(confname[i], confval[i], 0);
2449a747e4fSDavid du Colombier 			ksetenv(confname[i], confval[i], 1);
2459a747e4fSDavid du Colombier 		}
2463e12c5d1SDavid du Colombier 		poperror();
2473e12c5d1SDavid du Colombier 	}
2487dd7cddfSDavid du Colombier 	kproc("alarm", alarmkproc, 0);
249d3993254SDavid du Colombier 	cgapost(0x9);
2503e12c5d1SDavid du Colombier 	touser(sp);
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier 
2533e12c5d1SDavid du Colombier void
userinit(void)2543e12c5d1SDavid du Colombier userinit(void)
2553e12c5d1SDavid du Colombier {
2564de34a7eSDavid du Colombier 	void *v;
2573e12c5d1SDavid du Colombier 	Proc *p;
2583e12c5d1SDavid du Colombier 	Segment *s;
2593e12c5d1SDavid du Colombier 	Page *pg;
2603e12c5d1SDavid du Colombier 
2613e12c5d1SDavid du Colombier 	p = newproc();
2623e12c5d1SDavid du Colombier 	p->pgrp = newpgrp();
2633e12c5d1SDavid du Colombier 	p->egrp = smalloc(sizeof(Egrp));
2643e12c5d1SDavid du Colombier 	p->egrp->ref = 1;
2657dd7cddfSDavid du Colombier 	p->fgrp = dupfgrp(nil);
2667dd7cddfSDavid du Colombier 	p->rgrp = newrgrp();
2673e12c5d1SDavid du Colombier 	p->procmode = 0640;
2683e12c5d1SDavid du Colombier 
2699a747e4fSDavid du Colombier 	kstrdup(&eve, "");
2709a747e4fSDavid du Colombier 	kstrdup(&p->text, "*init*");
2719a747e4fSDavid du Colombier 	kstrdup(&p->user, eve);
2729a747e4fSDavid du Colombier 
2733e12c5d1SDavid du Colombier 	p->fpstate = FPinit;
2743e12c5d1SDavid du Colombier 	fpoff();
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier 	/*
2773e12c5d1SDavid du Colombier 	 * Kernel Stack
2783e12c5d1SDavid du Colombier 	 *
27959cc4ca5SDavid du Colombier 	 * N.B. make sure there's enough space for syscall to check
28059cc4ca5SDavid du Colombier 	 *	for valid args and
2813e12c5d1SDavid du Colombier 	 *	4 bytes for gotolabel's return PC
2823e12c5d1SDavid du Colombier 	 */
2833e12c5d1SDavid du Colombier 	p->sched.pc = (ulong)init0;
28459cc4ca5SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
2853e12c5d1SDavid du Colombier 
2863e12c5d1SDavid du Colombier 	/*
2873e12c5d1SDavid du Colombier 	 * User Stack
2884de34a7eSDavid du Colombier 	 *
2894de34a7eSDavid du Colombier 	 * N.B. cannot call newpage() with clear=1, because pc kmap
2904de34a7eSDavid du Colombier 	 * requires up != nil.  use tmpmap instead.
2913e12c5d1SDavid du Colombier 	 */
2927dd7cddfSDavid du Colombier 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
2933e12c5d1SDavid du Colombier 	p->seg[SSEG] = s;
2944de34a7eSDavid du Colombier 	pg = newpage(0, 0, USTKTOP-BY2PG);
2954de34a7eSDavid du Colombier 	v = tmpmap(pg);
2964de34a7eSDavid du Colombier 	memset(v, 0, BY2PG);
2973e12c5d1SDavid du Colombier 	segpage(s, pg);
2984de34a7eSDavid du Colombier 	bootargs(v);
2994de34a7eSDavid du Colombier 	tmpunmap(v);
3003e12c5d1SDavid du Colombier 
3013e12c5d1SDavid du Colombier 	/*
3023e12c5d1SDavid du Colombier 	 * Text
3033e12c5d1SDavid du Colombier 	 */
3043e12c5d1SDavid du Colombier 	s = newseg(SG_TEXT, UTZERO, 1);
3057dd7cddfSDavid du Colombier 	s->flushme++;
3063e12c5d1SDavid du Colombier 	p->seg[TSEG] = s;
3074de34a7eSDavid du Colombier 	pg = newpage(0, 0, UTZERO);
3087dd7cddfSDavid du Colombier 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
3097dd7cddfSDavid du Colombier 	segpage(s, pg);
3104de34a7eSDavid du Colombier 	v = tmpmap(pg);
3114de34a7eSDavid du Colombier 	memset(v, 0, BY2PG);
3124de34a7eSDavid du Colombier 	memmove(v, initcode, sizeof initcode);
3134de34a7eSDavid du Colombier 	tmpunmap(v);
3143e12c5d1SDavid du Colombier 
3153e12c5d1SDavid du Colombier 	ready(p);
3163e12c5d1SDavid du Colombier }
3173e12c5d1SDavid du Colombier 
3183e12c5d1SDavid du Colombier uchar *
pusharg(char * p)3193e12c5d1SDavid du Colombier pusharg(char *p)
3203e12c5d1SDavid du Colombier {
3213e12c5d1SDavid du Colombier 	int n;
3223e12c5d1SDavid du Colombier 
3233e12c5d1SDavid du Colombier 	n = strlen(p)+1;
3243e12c5d1SDavid du Colombier 	sp -= n;
3253e12c5d1SDavid du Colombier 	memmove(sp, p, n);
3263e12c5d1SDavid du Colombier 	return sp;
3273e12c5d1SDavid du Colombier }
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier void
bootargs(void * base)3304de34a7eSDavid du Colombier bootargs(void *base)
3313e12c5d1SDavid du Colombier {
3323e12c5d1SDavid du Colombier  	int i, ac;
3333e12c5d1SDavid du Colombier 	uchar *av[32];
3343e12c5d1SDavid du Colombier 	uchar **lsp;
3353e12c5d1SDavid du Colombier 	char *cp = BOOTLINE;
3363e12c5d1SDavid du Colombier 	char buf[64];
3373e12c5d1SDavid du Colombier 
33823a96966SDavid du Colombier 	sp = (uchar*)base + BY2PG - Ustkheadroom;
3393e12c5d1SDavid du Colombier 
3403e12c5d1SDavid du Colombier 	ac = 0;
3417dd7cddfSDavid du Colombier 	av[ac++] = pusharg("/386/9dos");
3429a747e4fSDavid du Colombier 
3439a747e4fSDavid du Colombier 	/* when boot is changed to only use rc, this code can go away */
3447dd7cddfSDavid du Colombier 	cp[BOOTLINELEN-1] = 0;
345219b2ee8SDavid du Colombier 	buf[0] = 0;
3467dd7cddfSDavid du Colombier 	if(strncmp(cp, "fd", 2) == 0){
3474e3613abSDavid du Colombier 		snprint(buf, sizeof buf, "local!#f/fd%lddisk",
3484e3613abSDavid du Colombier 			strtol(cp+2, 0, 0));
3493e12c5d1SDavid du Colombier 		av[ac++] = pusharg(buf);
3507dd7cddfSDavid du Colombier 	} else if(strncmp(cp, "sd", 2) == 0){
3514e3613abSDavid du Colombier 		snprint(buf, sizeof buf, "local!#S/sd%c%c/fs", *(cp+2), *(cp+3));
3523e12c5d1SDavid du Colombier 		av[ac++] = pusharg(buf);
3537dd7cddfSDavid du Colombier 	} else if(strncmp(cp, "ether", 5) == 0)
3547dd7cddfSDavid du Colombier 		av[ac++] = pusharg("-n");
3553e12c5d1SDavid du Colombier 
3563e12c5d1SDavid du Colombier 	/* 4 byte word align stack */
3573e12c5d1SDavid du Colombier 	sp = (uchar*)((ulong)sp & ~3);
3583e12c5d1SDavid du Colombier 
3593e12c5d1SDavid du Colombier 	/* build argc, argv on stack */
3603e12c5d1SDavid du Colombier 	sp -= (ac+1)*sizeof(sp);
3613e12c5d1SDavid du Colombier 	lsp = (uchar**)sp;
3623e12c5d1SDavid du Colombier 	for(i = 0; i < ac; i++)
3634de34a7eSDavid du Colombier 		*lsp++ = av[i] + ((USTKTOP - BY2PG) - (ulong)base);
3643e12c5d1SDavid du Colombier 	*lsp = 0;
3654de34a7eSDavid du Colombier 	sp += (USTKTOP - BY2PG) - (ulong)base - sizeof(ulong);
3663e12c5d1SDavid du Colombier }
3673e12c5d1SDavid du Colombier 
368219b2ee8SDavid du Colombier char*
getconf(char * name)369219b2ee8SDavid du Colombier getconf(char *name)
370219b2ee8SDavid du Colombier {
371219b2ee8SDavid du Colombier 	int i;
372219b2ee8SDavid du Colombier 
373219b2ee8SDavid du Colombier 	for(i = 0; i < nconf; i++)
3747dd7cddfSDavid du Colombier 		if(cistrcmp(confname[i], name) == 0)
375219b2ee8SDavid du Colombier 			return confval[i];
376219b2ee8SDavid du Colombier 	return 0;
377219b2ee8SDavid du Colombier }
378219b2ee8SDavid du Colombier 
3799a747e4fSDavid du Colombier static void
writeconf(void)3809a747e4fSDavid du Colombier writeconf(void)
3819a747e4fSDavid du Colombier {
3829a747e4fSDavid du Colombier 	char *p, *q;
3839a747e4fSDavid du Colombier 	int n;
3849a747e4fSDavid du Colombier 
3859a747e4fSDavid du Colombier 	p = getconfenv();
3869a747e4fSDavid du Colombier 
3879a747e4fSDavid du Colombier 	if(waserror()) {
3889a747e4fSDavid du Colombier 		free(p);
3899a747e4fSDavid du Colombier 		nexterror();
3909a747e4fSDavid du Colombier 	}
3919a747e4fSDavid du Colombier 
3929a747e4fSDavid du Colombier 	/* convert to name=value\n format */
3939a747e4fSDavid du Colombier 	for(q=p; *q; q++) {
3949a747e4fSDavid du Colombier 		q += strlen(q);
3959a747e4fSDavid du Colombier 		*q = '=';
3969a747e4fSDavid du Colombier 		q += strlen(q);
3979a747e4fSDavid du Colombier 		*q = '\n';
3989a747e4fSDavid du Colombier 	}
3999a747e4fSDavid du Colombier 	n = q - p + 1;
4009a747e4fSDavid du Colombier 	if(n >= BOOTARGSLEN)
4019a747e4fSDavid du Colombier 		error("kernel configuration too large");
4029a747e4fSDavid du Colombier 	memset(BOOTLINE, 0, BOOTLINELEN);
4039a747e4fSDavid du Colombier 	memmove(BOOTARGS, p, n);
4049a747e4fSDavid du Colombier 	poperror();
4059a747e4fSDavid du Colombier 	free(p);
4069a747e4fSDavid du Colombier }
4079a747e4fSDavid du Colombier 
408219b2ee8SDavid du Colombier void
confinit(void)4093e12c5d1SDavid du Colombier confinit(void)
4103e12c5d1SDavid du Colombier {
4117dd7cddfSDavid du Colombier 	char *p;
4124de34a7eSDavid du Colombier 	int i, userpcnt;
413*217e9e83SDavid du Colombier 	unsigned mb;
414*217e9e83SDavid du Colombier 	ulong kpages, ksize;
415219b2ee8SDavid du Colombier 
4167dd7cddfSDavid du Colombier 	if(p = getconf("*kernelpercent"))
4177dd7cddfSDavid du Colombier 		userpcnt = 100 - strtol(p, 0, 0);
4187dd7cddfSDavid du Colombier 	else
4197dd7cddfSDavid du Colombier 		userpcnt = 0;
4203e12c5d1SDavid du Colombier 
4214de34a7eSDavid du Colombier 	conf.npage = 0;
4224de34a7eSDavid du Colombier 	for(i=0; i<nelem(conf.mem); i++)
4234de34a7eSDavid du Colombier 		conf.npage += conf.mem[i].npage;
424219b2ee8SDavid du Colombier 
4257dd7cddfSDavid du Colombier 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
4267dd7cddfSDavid du Colombier 	if(cpuserver)
4277dd7cddfSDavid du Colombier 		conf.nproc *= 3;
4287dd7cddfSDavid du Colombier 	if(conf.nproc > 2000)
4297dd7cddfSDavid du Colombier 		conf.nproc = 2000;
4307dd7cddfSDavid du Colombier 	conf.nimage = 200;
4313e12c5d1SDavid du Colombier 	conf.nswap = conf.nproc*80;
4327dd7cddfSDavid du Colombier 	conf.nswppo = 4096;
4337dd7cddfSDavid du Colombier 
4347dd7cddfSDavid du Colombier 	if(cpuserver) {
4357dd7cddfSDavid du Colombier 		if(userpcnt < 10)
4367dd7cddfSDavid du Colombier 			userpcnt = 70;
4377dd7cddfSDavid du Colombier 		kpages = conf.npage - (conf.npage*userpcnt)/100;
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier 		/*
4407dd7cddfSDavid du Colombier 		 * Hack for the big boys. Only good while physmem < 4GB.
44114414594SDavid du Colombier 		 * Give the kernel fixed max + enough to allocate the
4427dd7cddfSDavid du Colombier 		 * page pool.
4437dd7cddfSDavid du Colombier 		 * This is an overestimate as conf.upages < conf.npages.
4447dd7cddfSDavid du Colombier 		 * The patch of nimage is a band-aid, scanning the whole
4457dd7cddfSDavid du Colombier 		 * page list in imagereclaim just takes too long.
4467dd7cddfSDavid du Colombier 		 */
447*217e9e83SDavid du Colombier 		for (mb = 400; mb >= 100; mb /= 2) {
448*217e9e83SDavid du Colombier 			ksize = mb*MB + conf.npage*sizeof(Page);
449*217e9e83SDavid du Colombier 			if(kpages > ksize/BY2PG && cankaddr(ksize)) {
450*217e9e83SDavid du Colombier 				kpages = ksize/BY2PG + (conf.nproc*KSTACK)/BY2PG;
4517dd7cddfSDavid du Colombier 				conf.nimage = 2000;
452*217e9e83SDavid du Colombier 				break;
453*217e9e83SDavid du Colombier 			}
454219b2ee8SDavid du Colombier 		}
4557dd7cddfSDavid du Colombier 	} else {
4567dd7cddfSDavid du Colombier 		if(userpcnt < 10) {
4577dd7cddfSDavid du Colombier 			if(conf.npage*BY2PG < 16*MB)
4587dd7cddfSDavid du Colombier 				userpcnt = 40;
4597dd7cddfSDavid du Colombier 			else
4607dd7cddfSDavid du Colombier 				userpcnt = 60;
4617dd7cddfSDavid du Colombier 		}
4627dd7cddfSDavid du Colombier 		kpages = conf.npage - (conf.npage*userpcnt)/100;
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier 		/*
4657dd7cddfSDavid du Colombier 		 * Make sure terminals with low memory get at least
4667dd7cddfSDavid du Colombier 		 * 4MB on the first Image chunk allocation.
4677dd7cddfSDavid du Colombier 		 */
4687dd7cddfSDavid du Colombier 		if(conf.npage*BY2PG < 16*MB)
4697dd7cddfSDavid du Colombier 			imagmem->minarena = 4*1024*1024;
4707dd7cddfSDavid du Colombier 	}
4714de34a7eSDavid du Colombier 
4724de34a7eSDavid du Colombier 	/*
4734de34a7eSDavid du Colombier 	 * can't go past the end of virtual memory
4744de34a7eSDavid du Colombier 	 * (ulong)-KZERO is 2^32 - KZERO
4754de34a7eSDavid du Colombier 	 */
4764de34a7eSDavid du Colombier 	if(kpages > ((ulong)-KZERO)/BY2PG)
4774de34a7eSDavid du Colombier 		kpages = ((ulong)-KZERO)/BY2PG;
4784de34a7eSDavid du Colombier 
4797dd7cddfSDavid du Colombier 	conf.upages = conf.npage - kpages;
4807dd7cddfSDavid du Colombier 	conf.ialloc = (kpages/2)*BY2PG;
4817dd7cddfSDavid du Colombier 
4827dd7cddfSDavid du Colombier 	/*
4837dd7cddfSDavid du Colombier 	 * Guess how much is taken by the large permanent
4847dd7cddfSDavid du Colombier 	 * datastructures. Mntcache and Mntrpc are not accounted for
4857dd7cddfSDavid du Colombier 	 * (probably ~300KB).
4867dd7cddfSDavid du Colombier 	 */
4877dd7cddfSDavid du Colombier 	kpages *= BY2PG;
4887dd7cddfSDavid du Colombier 	kpages -= conf.upages*sizeof(Page)
4897dd7cddfSDavid du Colombier 		+ conf.nproc*sizeof(Proc)
4907dd7cddfSDavid du Colombier 		+ conf.nimage*sizeof(Image)
4917dd7cddfSDavid du Colombier 		+ conf.nswap
4927dd7cddfSDavid du Colombier 		+ conf.nswppo*sizeof(Page);
4937dd7cddfSDavid du Colombier 	mainmem->maxsize = kpages;
4947dd7cddfSDavid du Colombier 	if(!cpuserver){
4957dd7cddfSDavid du Colombier 		/*
4967dd7cddfSDavid du Colombier 		 * give terminals lots of image memory, too; the dynamic
4977dd7cddfSDavid du Colombier 		 * allocation will balance the load properly, hopefully.
4987dd7cddfSDavid du Colombier 		 * be careful with 32-bit overflow.
4997dd7cddfSDavid du Colombier 		 */
5007dd7cddfSDavid du Colombier 		imagmem->maxsize = kpages;
5017dd7cddfSDavid du Colombier 	}
5023e12c5d1SDavid du Colombier }
5033e12c5d1SDavid du Colombier 
5047dd7cddfSDavid du Colombier static char* mathmsg[] =
5053e12c5d1SDavid du Colombier {
5063ff48bf5SDavid du Colombier 	nil,	/* handled below */
5073ff48bf5SDavid du Colombier 	"denormalized operand",
5083ff48bf5SDavid du Colombier 	"division by zero",
5093ff48bf5SDavid du Colombier 	"numeric overflow",
5103ff48bf5SDavid du Colombier 	"numeric underflow",
5113ff48bf5SDavid du Colombier 	"precision loss",
5123e12c5d1SDavid du Colombier };
5133e12c5d1SDavid du Colombier 
5147dd7cddfSDavid du Colombier static void
mathstate(ulong * stsp,ulong * pcp,ulong * ctlp)515401314a3SDavid du Colombier mathstate(ulong *stsp, ulong *pcp, ulong *ctlp)
51691e577b2SDavid du Colombier {
51791e577b2SDavid du Colombier 	ulong sts, fpc, ctl;
518401314a3SDavid du Colombier 	FPsave *f = &up->fpsave;
51991e577b2SDavid du Colombier 
52091e577b2SDavid du Colombier 	if(fpsave == fpx87save){
52191e577b2SDavid du Colombier 		sts = f->status;
52291e577b2SDavid du Colombier 		fpc = f->pc;
52391e577b2SDavid du Colombier 		ctl = f->control;
52491e577b2SDavid du Colombier 	} else {
52591e577b2SDavid du Colombier 		sts = f->fsw;
52691e577b2SDavid du Colombier 		fpc = f->fpuip;
52791e577b2SDavid du Colombier 		ctl = f->fcw;
52891e577b2SDavid du Colombier 	}
529401314a3SDavid du Colombier 	if(stsp)
530401314a3SDavid du Colombier 		*stsp = sts;
531401314a3SDavid du Colombier 	if(pcp)
532401314a3SDavid du Colombier 		*pcp = fpc;
533401314a3SDavid du Colombier 	if(ctlp)
534401314a3SDavid du Colombier 		*ctlp = ctl;
53591e577b2SDavid du Colombier }
53691e577b2SDavid du Colombier 
53791e577b2SDavid du Colombier static void
mathnote(void)5387dd7cddfSDavid du Colombier mathnote(void)
5397dd7cddfSDavid du Colombier {
5407dd7cddfSDavid du Colombier 	int i;
54191e577b2SDavid du Colombier 	ulong status, pc;
5429a747e4fSDavid du Colombier 	char *msg, note[ERRMAX];
5437dd7cddfSDavid du Colombier 
54491e577b2SDavid du Colombier 	mathstate(&status, &pc, nil);
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier 	/*
5477dd7cddfSDavid du Colombier 	 * Some attention should probably be paid here to the
5487dd7cddfSDavid du Colombier 	 * exception masks and error summary.
5497dd7cddfSDavid du Colombier 	 */
5503ff48bf5SDavid du Colombier 	msg = "unknown exception";
5513ff48bf5SDavid du Colombier 	for(i = 1; i <= 5; i++){
5527dd7cddfSDavid du Colombier 		if(!((1<<i) & status))
5537dd7cddfSDavid du Colombier 			continue;
5547dd7cddfSDavid du Colombier 		msg = mathmsg[i];
5557dd7cddfSDavid du Colombier 		break;
5567dd7cddfSDavid du Colombier 	}
5573ff48bf5SDavid du Colombier 	if(status & 0x01){
558f15b2559SDavid du Colombier 		if(status & 0x40){
5593ff48bf5SDavid du Colombier 			if(status & 0x200)
5603ff48bf5SDavid du Colombier 				msg = "stack overflow";
5613ff48bf5SDavid du Colombier 			else
5623ff48bf5SDavid du Colombier 				msg = "stack underflow";
5633ff48bf5SDavid du Colombier 		}else
5643ff48bf5SDavid du Colombier 			msg = "invalid operation";
5653ff48bf5SDavid du Colombier 	}
566401314a3SDavid du Colombier 	snprint(note, sizeof note, "sys: fp: %s fppc=%#lux status=%#lux",
56791e577b2SDavid du Colombier 		msg, pc, status);
5687dd7cddfSDavid du Colombier 	postnote(up, 1, note, NDebug);
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier 
571d7e44d0dSDavid du Colombier /*
572d7e44d0dSDavid du Colombier  * sse fp save and restore buffers have to be 16-byte (FPalign) aligned,
5734e3613abSDavid du Colombier  * so we shuffle the data down as needed or make copies.
574d7e44d0dSDavid du Colombier  */
57591e577b2SDavid du Colombier 
576401314a3SDavid du Colombier void
fpssesave(FPsave * fps)577401314a3SDavid du Colombier fpssesave(FPsave *fps)
57891e577b2SDavid du Colombier {
579d7e44d0dSDavid du Colombier 	FPsave *afps;
580401314a3SDavid du Colombier 
5814e3613abSDavid du Colombier 	fps->magic = 0x1234;
582d7e44d0dSDavid du Colombier 	afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
583401314a3SDavid du Colombier 	fpssesave0(afps);
584d7e44d0dSDavid du Colombier 	if (fps != afps)  /* not aligned? shuffle down from aligned buffer */
5854e3613abSDavid du Colombier 		memmove(fps, afps, sizeof(FPssestate));
5864e3613abSDavid du Colombier 	if (fps->magic != 0x1234)
5874e3613abSDavid du Colombier 		print("fpssesave: magic corrupted\n");
58891e577b2SDavid du Colombier }
589401314a3SDavid du Colombier 
590401314a3SDavid du Colombier void
fpsserestore(FPsave * fps)591401314a3SDavid du Colombier fpsserestore(FPsave *fps)
592401314a3SDavid du Colombier {
593d7e44d0dSDavid du Colombier 	FPsave *afps;
594401314a3SDavid du Colombier 
5954e3613abSDavid du Colombier 	fps->magic = 0x4321;
596d7e44d0dSDavid du Colombier 	afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
597d7e44d0dSDavid du Colombier 	if (fps != afps) {
598d7e44d0dSDavid du Colombier 		afps = m->fpsavalign;
5994e3613abSDavid du Colombier 		memmove(afps, fps, sizeof(FPssestate));	/* make aligned copy */
600d7e44d0dSDavid du Colombier 	}
601401314a3SDavid du Colombier 	fpsserestore0(afps);
6024e3613abSDavid du Colombier 	if (fps->magic != 0x4321)
6034e3613abSDavid du Colombier 		print("fpsserestore: magic corrupted\n");
60491e577b2SDavid du Colombier }
60591e577b2SDavid du Colombier 
6063e12c5d1SDavid du Colombier /*
6073e12c5d1SDavid du Colombier  *  math coprocessor error
6083e12c5d1SDavid du Colombier  */
6097dd7cddfSDavid du Colombier static void
matherror(Ureg * ur,void *)6107dd7cddfSDavid du Colombier matherror(Ureg *ur, void*)
6113e12c5d1SDavid du Colombier {
61291e577b2SDavid du Colombier 	ulong status, pc;
61391e577b2SDavid du Colombier 
6143e12c5d1SDavid du Colombier 	/*
6153e12c5d1SDavid du Colombier 	 *  a write cycle to port 0xF0 clears the interrupt latch attached
6163e12c5d1SDavid du Colombier 	 *  to the error# line from the 387
6173e12c5d1SDavid du Colombier 	 */
61861fd6f66SDavid du Colombier 	if(!(m->cpuiddx & Fpuonchip))
6193e12c5d1SDavid du Colombier 		outb(0xF0, 0xFF);
6203e12c5d1SDavid du Colombier 
6213e12c5d1SDavid du Colombier 	/*
6223e12c5d1SDavid du Colombier 	 *  save floating point state to check out error
6233e12c5d1SDavid du Colombier 	 */
624781103c4SDavid du Colombier 	fpenv(&up->fpsave);	/* result ignored, but masks fp exceptions */
625781103c4SDavid du Colombier 	fpsave(&up->fpsave);		/* also turns fpu off */
626781103c4SDavid du Colombier 	fpon();
6277dd7cddfSDavid du Colombier 	mathnote();
6283e12c5d1SDavid du Colombier 
62991e577b2SDavid du Colombier 	if((ur->pc & 0xf0000000) == KZERO){
63091e577b2SDavid du Colombier 		mathstate(&status, &pc, nil);
63191e577b2SDavid du Colombier 		panic("fp: status %#lux fppc=%#lux pc=%#lux", status, pc, ur->pc);
63291e577b2SDavid du Colombier 	}
6333e12c5d1SDavid du Colombier }
6343e12c5d1SDavid du Colombier 
6353e12c5d1SDavid du Colombier /*
6363e12c5d1SDavid du Colombier  *  math coprocessor emulation fault
6373e12c5d1SDavid du Colombier  */
6387dd7cddfSDavid du Colombier static void
mathemu(Ureg * ureg,void *)6394de34a7eSDavid du Colombier mathemu(Ureg *ureg, void*)
6403e12c5d1SDavid du Colombier {
64191e577b2SDavid du Colombier 	ulong status, control;
64291e577b2SDavid du Colombier 
6433ff48bf5SDavid du Colombier 	if(up->fpstate & FPillegal){
6443ff48bf5SDavid du Colombier 		/* someone did floating point in a note handler */
6453ff48bf5SDavid du Colombier 		postnote(up, 1, "sys: floating point in note handler", NDebug);
6463ff48bf5SDavid du Colombier 		return;
6473ff48bf5SDavid du Colombier 	}
6487dd7cddfSDavid du Colombier 	switch(up->fpstate){
6493e12c5d1SDavid du Colombier 	case FPinit:
6503e12c5d1SDavid du Colombier 		fpinit();
6517dd7cddfSDavid du Colombier 		up->fpstate = FPactive;
6523e12c5d1SDavid du Colombier 		break;
6533e12c5d1SDavid du Colombier 	case FPinactive:
6547dd7cddfSDavid du Colombier 		/*
6557dd7cddfSDavid du Colombier 		 * Before restoring the state, check for any pending
6567dd7cddfSDavid du Colombier 		 * exceptions, there's no way to restore the state without
6577dd7cddfSDavid du Colombier 		 * generating an unmasked exception.
6587dd7cddfSDavid du Colombier 		 * More attention should probably be paid here to the
6597dd7cddfSDavid du Colombier 		 * exception masks and error summary.
6607dd7cddfSDavid du Colombier 		 */
66191e577b2SDavid du Colombier 		mathstate(&status, nil, &control);
66291e577b2SDavid du Colombier 		if((status & ~control) & 0x07F){
6637dd7cddfSDavid du Colombier 			mathnote();
6647dd7cddfSDavid du Colombier 			break;
6657dd7cddfSDavid du Colombier 		}
6667dd7cddfSDavid du Colombier 		fprestore(&up->fpsave);
6677dd7cddfSDavid du Colombier 		up->fpstate = FPactive;
6683e12c5d1SDavid du Colombier 		break;
6693e12c5d1SDavid du Colombier 	case FPactive:
670401314a3SDavid du Colombier 		panic("math emu pid %ld %s pc %#lux",
6714de34a7eSDavid du Colombier 			up->pid, up->text, ureg->pc);
6723e12c5d1SDavid du Colombier 		break;
6733e12c5d1SDavid du Colombier 	}
6743e12c5d1SDavid du Colombier }
6753e12c5d1SDavid du Colombier 
6763e12c5d1SDavid du Colombier /*
6773e12c5d1SDavid du Colombier  *  math coprocessor segment overrun
6783e12c5d1SDavid du Colombier  */
6797dd7cddfSDavid du Colombier static void
mathover(Ureg *,void *)6807dd7cddfSDavid du Colombier mathover(Ureg*, void*)
6813e12c5d1SDavid du Colombier {
6823e12c5d1SDavid du Colombier 	pexit("math overrun", 0);
6833e12c5d1SDavid du Colombier }
6843e12c5d1SDavid du Colombier 
6853e12c5d1SDavid du Colombier void
mathinit(void)6863e12c5d1SDavid du Colombier mathinit(void)
6873e12c5d1SDavid du Colombier {
6887dd7cddfSDavid du Colombier 	trapenable(VectorCERR, matherror, 0, "matherror");
6897dd7cddfSDavid du Colombier 	if(X86FAMILY(m->cpuidax) == 3)
6907dd7cddfSDavid du Colombier 		intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
6917dd7cddfSDavid du Colombier 	trapenable(VectorCNA, mathemu, 0, "mathemu");
6927dd7cddfSDavid du Colombier 	trapenable(VectorCSO, mathover, 0, "mathover");
6933e12c5d1SDavid du Colombier }
6943e12c5d1SDavid du Colombier 
6953e12c5d1SDavid du Colombier /*
6963e12c5d1SDavid du Colombier  *  set up floating point for a new process
6973e12c5d1SDavid du Colombier  */
6983e12c5d1SDavid du Colombier void
procsetup(Proc * p)6993e12c5d1SDavid du Colombier procsetup(Proc*p)
7003e12c5d1SDavid du Colombier {
7013e12c5d1SDavid du Colombier 	p->fpstate = FPinit;
7023e12c5d1SDavid du Colombier 	fpoff();
7033e12c5d1SDavid du Colombier }
7043e12c5d1SDavid du Colombier 
705e288d156SDavid du Colombier void
procrestore(Proc * p)706e288d156SDavid du Colombier procrestore(Proc *p)
707e288d156SDavid du Colombier {
708e288d156SDavid du Colombier 	uvlong t;
709e288d156SDavid du Colombier 
710179dd269SDavid du Colombier 	if(p->kp)
711e288d156SDavid du Colombier 		return;
712e288d156SDavid du Colombier 	cycles(&t);
713e288d156SDavid du Colombier 	p->pcycles -= t;
714e288d156SDavid du Colombier }
715e288d156SDavid du Colombier 
7163e12c5d1SDavid du Colombier /*
7173e12c5d1SDavid du Colombier  *  Save the mach dependent part of the process state.
7183e12c5d1SDavid du Colombier  */
7193e12c5d1SDavid du Colombier void
procsave(Proc * p)7203e12c5d1SDavid du Colombier procsave(Proc *p)
7213e12c5d1SDavid du Colombier {
722e288d156SDavid du Colombier 	uvlong t;
723e288d156SDavid du Colombier 
724e288d156SDavid du Colombier 	cycles(&t);
725e288d156SDavid du Colombier 	p->pcycles += t;
7263e12c5d1SDavid du Colombier 	if(p->fpstate == FPactive){
7273e12c5d1SDavid du Colombier 		if(p->state == Moribund)
7289d1c31b1SDavid du Colombier 			fpclear();
7297dd7cddfSDavid du Colombier 		else{
7307dd7cddfSDavid du Colombier 			/*
7317dd7cddfSDavid du Colombier 			 * Fpsave() stores without handling pending
7327dd7cddfSDavid du Colombier 			 * unmasked exeptions. Postnote() can't be called
7337dd7cddfSDavid du Colombier 			 * here as sleep() already has up->rlock, so
7347dd7cddfSDavid du Colombier 			 * the handling of pending exceptions is delayed
7357dd7cddfSDavid du Colombier 			 * until the process runs again and generates an
7367dd7cddfSDavid du Colombier 			 * emulation fault to activate the FPU.
7377dd7cddfSDavid du Colombier 			 */
7387e2bd6dcSDavid du Colombier 			fpsave(&p->fpsave);
7397dd7cddfSDavid du Colombier 		}
7403e12c5d1SDavid du Colombier 		p->fpstate = FPinactive;
7413e12c5d1SDavid du Colombier 	}
7427dd7cddfSDavid du Colombier 
7437dd7cddfSDavid du Colombier 	/*
7447dd7cddfSDavid du Colombier 	 * While this processor is in the scheduler, the process could run
7457dd7cddfSDavid du Colombier 	 * on another processor and exit, returning the page tables to
7467dd7cddfSDavid du Colombier 	 * the free list where they could be reallocated and overwritten.
7477dd7cddfSDavid du Colombier 	 * When this processor eventually has to get an entry from the
7487dd7cddfSDavid du Colombier 	 * trashed page tables it will crash.
749fb7f0c93SDavid du Colombier 	 *
750fb7f0c93SDavid du Colombier 	 * If there's only one processor, this can't happen.
751fb7f0c93SDavid du Colombier 	 * You might think it would be a win not to do this in that case,
752fb7f0c93SDavid du Colombier 	 * especially on VMware, but it turns out not to matter.
7537dd7cddfSDavid du Colombier 	 */
7547dd7cddfSDavid du Colombier 	mmuflushtlb(PADDR(m->pdb));
7553e12c5d1SDavid du Colombier }
7563e12c5d1SDavid du Colombier 
7579a747e4fSDavid du Colombier static void
shutdown(int ispanic)7589a747e4fSDavid du Colombier shutdown(int ispanic)
7593e12c5d1SDavid du Colombier {
7607dd7cddfSDavid du Colombier 	int ms, once;
7617dd7cddfSDavid du Colombier 
7627dd7cddfSDavid du Colombier 	lock(&active);
7637dd7cddfSDavid du Colombier 	if(ispanic)
7647dd7cddfSDavid du Colombier 		active.ispanic = ispanic;
7657dd7cddfSDavid du Colombier 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
7667dd7cddfSDavid du Colombier 		active.ispanic = 0;
7677dd7cddfSDavid du Colombier 	once = active.machs & (1<<m->machno);
768c8cbc0e9SDavid du Colombier 	/*
769c8cbc0e9SDavid du Colombier 	 * setting exiting will make hzclock() on each processor call exit(0),
770c8cbc0e9SDavid du Colombier 	 * which calls shutdown(0) and arch->reset(), which on mp systems is
771dadaab63SDavid du Colombier 	 * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap
772dadaab63SDavid du Colombier 	 * processors (to permit a reboot).  clearing our bit in machs avoids
773dadaab63SDavid du Colombier 	 * calling exit(0) from hzclock() on this processor.
774c8cbc0e9SDavid du Colombier 	 */
7757dd7cddfSDavid du Colombier 	active.machs &= ~(1<<m->machno);
7767dd7cddfSDavid du Colombier 	active.exiting = 1;
7777dd7cddfSDavid du Colombier 	unlock(&active);
7787dd7cddfSDavid du Colombier 
7797dd7cddfSDavid du Colombier 	if(once)
7805979f962SDavid du Colombier 		iprint("cpu%d: exiting\n", m->machno);
781c8cbc0e9SDavid du Colombier 
782c8cbc0e9SDavid du Colombier 	/* wait for any other processors to shutdown */
7837dd7cddfSDavid du Colombier 	spllo();
7847dd7cddfSDavid du Colombier 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
7857dd7cddfSDavid du Colombier 		delay(TK2MS(2));
7867dd7cddfSDavid du Colombier 		if(active.machs == 0 && consactive() == 0)
7877dd7cddfSDavid du Colombier 			break;
7887dd7cddfSDavid du Colombier 	}
7897dd7cddfSDavid du Colombier 
79051feb878SDavid du Colombier 	if(active.ispanic){
79151feb878SDavid du Colombier 		if(!cpuserver)
792dc5a79c1SDavid du Colombier 			for(;;)
793dc5a79c1SDavid du Colombier 				halt();
794c8cbc0e9SDavid du Colombier 		if(getconf("*debug"))
795c8cbc0e9SDavid du Colombier 			delay(5*60*1000);
796c8cbc0e9SDavid du Colombier 		else
79751feb878SDavid du Colombier 			delay(10000);
79851feb878SDavid du Colombier 	}else
7997dd7cddfSDavid du Colombier 		delay(1000);
8009a747e4fSDavid du Colombier }
8013e12c5d1SDavid du Colombier 
8029a747e4fSDavid du Colombier void
reboot(void * entry,void * code,ulong size)8039a747e4fSDavid du Colombier reboot(void *entry, void *code, ulong size)
8049a747e4fSDavid du Colombier {
8059a747e4fSDavid du Colombier 	void (*f)(ulong, ulong, ulong);
8069a747e4fSDavid du Colombier 	ulong *pdb;
8079a747e4fSDavid du Colombier 
8089a747e4fSDavid du Colombier 	writeconf();
8099a747e4fSDavid du Colombier 
810c8cbc0e9SDavid du Colombier 	/*
811c8cbc0e9SDavid du Colombier 	 * the boot processor is cpu0.  execute this function on it
812c8cbc0e9SDavid du Colombier 	 * so that the new kernel has the same cpu0.  this only matters
813c8cbc0e9SDavid du Colombier 	 * because the hardware has a notion of which processor was the
814c8cbc0e9SDavid du Colombier 	 * boot processor and we look at it at start up.
815c8cbc0e9SDavid du Colombier 	 */
816c8cbc0e9SDavid du Colombier 	if (m->machno != 0) {
817c8cbc0e9SDavid du Colombier 		procwired(up, 0);
818c8cbc0e9SDavid du Colombier 		sched();
819c8cbc0e9SDavid du Colombier 	}
820c8cbc0e9SDavid du Colombier 
821e332dd3eSDavid du Colombier 	if(conf.nmach > 1) {
822dadaab63SDavid du Colombier 		/*
823dadaab63SDavid du Colombier 		 * the other cpus could be holding locks that will never get
824dadaab63SDavid du Colombier 		 * released (e.g., in the print path) if we put them into
825dadaab63SDavid du Colombier 		 * reset now, so force them to shutdown gracefully first.
826dadaab63SDavid du Colombier 		 */
827dadaab63SDavid du Colombier 		lock(&active);
828dadaab63SDavid du Colombier 		active.rebooting = 1;
829dadaab63SDavid du Colombier 		unlock(&active);
830dadaab63SDavid du Colombier 		shutdown(0);
8311206f3fcSDavid du Colombier 		if(arch->resetothers)
8321206f3fcSDavid du Colombier 			arch->resetothers();
833e332dd3eSDavid du Colombier 		delay(20);
834e332dd3eSDavid du Colombier 	}
8359a747e4fSDavid du Colombier 
8369a747e4fSDavid du Colombier 	/*
8379a747e4fSDavid du Colombier 	 * should be the only processor running now
8389a747e4fSDavid du Colombier 	 */
839e332dd3eSDavid du Colombier 	active.machs = 0;
840c8cbc0e9SDavid du Colombier 	if (m->machno != 0)
841c8cbc0e9SDavid du Colombier 		print("on cpu%d (not 0)!\n", m->machno);
8429a747e4fSDavid du Colombier 
8439a747e4fSDavid du Colombier 	print("shutting down...\n");
8449a747e4fSDavid du Colombier 	delay(200);
8459a747e4fSDavid du Colombier 
8469a747e4fSDavid du Colombier 	splhi();
8479a747e4fSDavid du Colombier 
8489a747e4fSDavid du Colombier 	/* turn off buffered serial console */
8499a747e4fSDavid du Colombier 	serialoq = nil;
8509a747e4fSDavid du Colombier 
8519a747e4fSDavid du Colombier 	/* shutdown devices */
8529a747e4fSDavid du Colombier 	chandevshutdown();
853c8cbc0e9SDavid du Colombier 	arch->introff();
8549a747e4fSDavid du Colombier 
8559a747e4fSDavid du Colombier 	/*
8569a747e4fSDavid du Colombier 	 * Modify the machine page table to directly map the low 4MB of memory
8579a747e4fSDavid du Colombier 	 * This allows the reboot code to turn off the page mapping
8589a747e4fSDavid du Colombier 	 */
8599a747e4fSDavid du Colombier 	pdb = m->pdb;
8609a747e4fSDavid du Colombier 	pdb[PDX(0)] = pdb[PDX(KZERO)];
8619a747e4fSDavid du Colombier 	mmuflushtlb(PADDR(pdb));
8629a747e4fSDavid du Colombier 
8639a747e4fSDavid du Colombier 	/* setup reboot trampoline function */
8649a747e4fSDavid du Colombier 	f = (void*)REBOOTADDR;
8659a747e4fSDavid du Colombier 	memmove(f, rebootcode, sizeof(rebootcode));
8669a747e4fSDavid du Colombier 
8679a747e4fSDavid du Colombier 	print("rebooting...\n");
8689a747e4fSDavid du Colombier 
8699a747e4fSDavid du Colombier 	/* off we go - never to return */
8703b86f2f8SDavid du Colombier 	coherence();
8719a747e4fSDavid du Colombier 	(*f)(PADDR(entry), PADDR(code), size);
8729a747e4fSDavid du Colombier }
8739a747e4fSDavid du Colombier 
8749a747e4fSDavid du Colombier 
8759a747e4fSDavid du Colombier void
exit(int ispanic)8769a747e4fSDavid du Colombier exit(int ispanic)
8779a747e4fSDavid du Colombier {
8789a747e4fSDavid du Colombier 	shutdown(ispanic);
8797dd7cddfSDavid du Colombier 	arch->reset();
880219b2ee8SDavid du Colombier }
881219b2ee8SDavid du Colombier 
882219b2ee8SDavid du Colombier int
isaconfig(char * class,int ctlrno,ISAConf * isa)883219b2ee8SDavid du Colombier isaconfig(char *class, int ctlrno, ISAConf *isa)
884219b2ee8SDavid du Colombier {
8859a747e4fSDavid du Colombier 	char cc[32], *p;
8869a747e4fSDavid du Colombier 	int i;
887219b2ee8SDavid du Colombier 
8889a747e4fSDavid du Colombier 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
8899a747e4fSDavid du Colombier 	p = getconf(cc);
8909a747e4fSDavid du Colombier 	if(p == nil)
8919a747e4fSDavid du Colombier 		return 0;
8929a747e4fSDavid du Colombier 
893c27b0bc9SDavid du Colombier 	isa->type = "";
8949a747e4fSDavid du Colombier 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
8959a747e4fSDavid du Colombier 	for(i = 0; i < isa->nopt; i++){
8969a747e4fSDavid du Colombier 		p = isa->opt[i];
8979a747e4fSDavid du Colombier 		if(cistrncmp(p, "type=", 5) == 0)
8989a747e4fSDavid du Colombier 			isa->type = p + 5;
8997dd7cddfSDavid du Colombier 		else if(cistrncmp(p, "port=", 5) == 0)
900219b2ee8SDavid du Colombier 			isa->port = strtoul(p+5, &p, 0);
9017dd7cddfSDavid du Colombier 		else if(cistrncmp(p, "irq=", 4) == 0)
902219b2ee8SDavid du Colombier 			isa->irq = strtoul(p+4, &p, 0);
9037dd7cddfSDavid du Colombier 		else if(cistrncmp(p, "dma=", 4) == 0)
904219b2ee8SDavid du Colombier 			isa->dma = strtoul(p+4, &p, 0);
9057dd7cddfSDavid du Colombier 		else if(cistrncmp(p, "mem=", 4) == 0)
9067dd7cddfSDavid du Colombier 			isa->mem = strtoul(p+4, &p, 0);
9077dd7cddfSDavid du Colombier 		else if(cistrncmp(p, "size=", 5) == 0)
9087dd7cddfSDavid du Colombier 			isa->size = strtoul(p+5, &p, 0);
9097dd7cddfSDavid du Colombier 		else if(cistrncmp(p, "freq=", 5) == 0)
9107dd7cddfSDavid du Colombier 			isa->freq = strtoul(p+5, &p, 0);
911219b2ee8SDavid du Colombier 	}
912219b2ee8SDavid du Colombier 	return 1;
913219b2ee8SDavid du Colombier }
914219b2ee8SDavid du Colombier 
915219b2ee8SDavid du Colombier int
cistrcmp(char * a,char * b)916219b2ee8SDavid du Colombier cistrcmp(char *a, char *b)
917219b2ee8SDavid du Colombier {
918219b2ee8SDavid du Colombier 	int ac, bc;
919219b2ee8SDavid du Colombier 
920219b2ee8SDavid du Colombier 	for(;;){
921219b2ee8SDavid du Colombier 		ac = *a++;
922219b2ee8SDavid du Colombier 		bc = *b++;
923219b2ee8SDavid du Colombier 
924219b2ee8SDavid du Colombier 		if(ac >= 'A' && ac <= 'Z')
925219b2ee8SDavid du Colombier 			ac = 'a' + (ac - 'A');
926219b2ee8SDavid du Colombier 		if(bc >= 'A' && bc <= 'Z')
927219b2ee8SDavid du Colombier 			bc = 'a' + (bc - 'A');
928219b2ee8SDavid du Colombier 		ac -= bc;
929219b2ee8SDavid du Colombier 		if(ac)
930219b2ee8SDavid du Colombier 			return ac;
931219b2ee8SDavid du Colombier 		if(bc == 0)
932219b2ee8SDavid du Colombier 			break;
933219b2ee8SDavid du Colombier 	}
934219b2ee8SDavid du Colombier 	return 0;
935219b2ee8SDavid du Colombier }
9367dd7cddfSDavid du Colombier 
9377dd7cddfSDavid du Colombier int
cistrncmp(char * a,char * b,int n)9387dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n)
9397dd7cddfSDavid du Colombier {
9407dd7cddfSDavid du Colombier 	unsigned ac, bc;
9417dd7cddfSDavid du Colombier 
9427dd7cddfSDavid du Colombier 	while(n > 0){
9437dd7cddfSDavid du Colombier 		ac = *a++;
9447dd7cddfSDavid du Colombier 		bc = *b++;
9457dd7cddfSDavid du Colombier 		n--;
9467dd7cddfSDavid du Colombier 
9477dd7cddfSDavid du Colombier 		if(ac >= 'A' && ac <= 'Z')
9487dd7cddfSDavid du Colombier 			ac = 'a' + (ac - 'A');
9497dd7cddfSDavid du Colombier 		if(bc >= 'A' && bc <= 'Z')
9507dd7cddfSDavid du Colombier 			bc = 'a' + (bc - 'A');
9517dd7cddfSDavid du Colombier 
9527dd7cddfSDavid du Colombier 		ac -= bc;
9537dd7cddfSDavid du Colombier 		if(ac)
9547dd7cddfSDavid du Colombier 			return ac;
9557dd7cddfSDavid du Colombier 		if(bc == 0)
9567dd7cddfSDavid du Colombier 			break;
9577dd7cddfSDavid du Colombier 	}
9587dd7cddfSDavid du Colombier 
9597dd7cddfSDavid du Colombier 	return 0;
9607dd7cddfSDavid du Colombier }
96180ee5cbfSDavid du Colombier 
96280ee5cbfSDavid du Colombier /*
96380ee5cbfSDavid du Colombier  *  put the processor in the halt state if we've no processes to run.
96480ee5cbfSDavid du Colombier  *  an interrupt will get us going again.
96580ee5cbfSDavid du Colombier  */
96680ee5cbfSDavid du Colombier void
idlehands(void)96780ee5cbfSDavid du Colombier idlehands(void)
96880ee5cbfSDavid du Colombier {
96923173ec1SDavid du Colombier 	/*
97023173ec1SDavid du Colombier 	 * we used to halt only on single-core setups. halting in an smp system
97123173ec1SDavid du Colombier 	 * can result in a startup latency for processes that become ready.
972d3993254SDavid du Colombier 	 * if idle_spin is zero, we care more about saving energy
97323173ec1SDavid du Colombier 	 * than reducing this latency.
9742f2115d0SDavid du Colombier 	 *
975d3993254SDavid du Colombier 	 * the performance loss with idle_spin == 0 seems to be slight
9762f2115d0SDavid du Colombier 	 * and it reduces lock contention (thus system time and real time)
9772f2115d0SDavid du Colombier 	 * on many-core systems with large values of NPROC.
97823173ec1SDavid du Colombier 	 */
979d3993254SDavid du Colombier 	if(conf.nmach == 1 || idle_spin == 0 ||
980d3993254SDavid du Colombier 	    idle_if_nproc && conf.nmach >= idle_if_nproc)
98180ee5cbfSDavid du Colombier 		halt();
98280ee5cbfSDavid du Colombier }
983