xref: /plan9/sys/src/9/omap/main.c (revision 23a969667fc2f16f64e45b0a4135d6dd31daef7a)
18e32b400SDavid du Colombier #include "u.h"
28e32b400SDavid du Colombier #include "../port/lib.h"
38e32b400SDavid du Colombier #include "mem.h"
48e32b400SDavid du Colombier #include "dat.h"
58e32b400SDavid du Colombier #include "fns.h"
68e32b400SDavid du Colombier #include "io.h"
78e32b400SDavid du Colombier 
88e32b400SDavid du Colombier #include "init.h"
98e32b400SDavid du Colombier #include <pool.h>
10*23a96966SDavid du Colombier #include <tos.h>
118e32b400SDavid du Colombier 
128e32b400SDavid du Colombier #include "reboot.h"
138e32b400SDavid du Colombier 
148e32b400SDavid du Colombier /*
158e32b400SDavid du Colombier  * Where configuration info is left for the loaded programme.
168e32b400SDavid du Colombier  * This will turn into a structure as more is done by the boot loader
178e32b400SDavid du Colombier  * (e.g. why parse the .ini file twice?).
188e32b400SDavid du Colombier  * There are 3584 bytes available at CONFADDR.
198e32b400SDavid du Colombier  */
208e32b400SDavid du Colombier #define BOOTARGS	((char*)CONFADDR)
218e32b400SDavid du Colombier #define	BOOTARGSLEN	(16*KiB)		/* limit in devenv.c */
228e32b400SDavid du Colombier #define	MAXCONF		64
238e32b400SDavid du Colombier #define MAXCONFLINE	160
248e32b400SDavid du Colombier 
25add6b5c5SDavid du Colombier enum {
26add6b5c5SDavid du Colombier 	Minmem	= 256*MB,			/* conservative default */
27*23a96966SDavid du Colombier 
28*23a96966SDavid du Colombier 	/* space for syscall args, return PC, top-of-stack struct */
29*23a96966SDavid du Colombier 	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
30add6b5c5SDavid du Colombier };
31add6b5c5SDavid du Colombier 
32*23a96966SDavid du Colombier 
338e32b400SDavid du Colombier #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
348e32b400SDavid du Colombier 
358e32b400SDavid du Colombier uintptr kseg0 = KZERO;
368e32b400SDavid du Colombier Mach* machaddr[MAXMACH];
378e32b400SDavid du Colombier 
388e32b400SDavid du Colombier /*
398e32b400SDavid du Colombier  * Option arguments from the command line.
408e32b400SDavid du Colombier  * oargv[0] is the boot file.
418e32b400SDavid du Colombier  * Optionsinit() is called from multiboot()
428e32b400SDavid du Colombier  * or some other machine-dependent place
438e32b400SDavid du Colombier  * to set it all up.
448e32b400SDavid du Colombier  */
458e32b400SDavid du Colombier static int oargc;
468e32b400SDavid du Colombier static char* oargv[20];
478e32b400SDavid du Colombier static char oargb[128];
488e32b400SDavid du Colombier static int oargblen;
498e32b400SDavid du Colombier static char oenv[4096];
508e32b400SDavid du Colombier 
518e32b400SDavid du Colombier static uintptr sp;		/* XXX - must go - user stack of init proc */
528e32b400SDavid du Colombier 
538e32b400SDavid du Colombier int vflag;
548e32b400SDavid du Colombier int normalprint;
558e32b400SDavid du Colombier char debug[256];
568e32b400SDavid du Colombier 
578e32b400SDavid du Colombier /* store plan9.ini contents here at least until we stash them in #ec */
588e32b400SDavid du Colombier static char confname[MAXCONF][KNAMELEN];
598e32b400SDavid du Colombier static char confval[MAXCONF][MAXCONFLINE];
608e32b400SDavid du Colombier static int nconf;
618e32b400SDavid du Colombier 
628e32b400SDavid du Colombier static int
findconf(char * name)638e32b400SDavid du Colombier findconf(char *name)
648e32b400SDavid du Colombier {
658e32b400SDavid du Colombier 	int i;
668e32b400SDavid du Colombier 
678e32b400SDavid du Colombier 	for(i = 0; i < nconf; i++)
688e32b400SDavid du Colombier 		if(cistrcmp(confname[i], name) == 0)
698e32b400SDavid du Colombier 			return i;
708e32b400SDavid du Colombier 	return -1;
718e32b400SDavid du Colombier }
728e32b400SDavid du Colombier 
738e32b400SDavid du Colombier char*
getconf(char * name)748e32b400SDavid du Colombier getconf(char *name)
758e32b400SDavid du Colombier {
768e32b400SDavid du Colombier 	int i;
778e32b400SDavid du Colombier 
788e32b400SDavid du Colombier 	i = findconf(name);
798e32b400SDavid du Colombier 	if(i >= 0)
808e32b400SDavid du Colombier 		return confval[i];
818e32b400SDavid du Colombier 	return nil;
828e32b400SDavid du Colombier }
838e32b400SDavid du Colombier 
848e32b400SDavid du Colombier void
addconf(char * name,char * val)858e32b400SDavid du Colombier addconf(char *name, char *val)
868e32b400SDavid du Colombier {
878e32b400SDavid du Colombier 	int i;
888e32b400SDavid du Colombier 
898e32b400SDavid du Colombier 	i = findconf(name);
908e32b400SDavid du Colombier 	if(i < 0){
918e32b400SDavid du Colombier 		if(val == nil || nconf >= MAXCONF)
928e32b400SDavid du Colombier 			return;
938e32b400SDavid du Colombier 		i = nconf++;
948e32b400SDavid du Colombier 		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
958e32b400SDavid du Colombier 	}
968e32b400SDavid du Colombier //	confval[i] = val;
978e32b400SDavid du Colombier 	strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
988e32b400SDavid du Colombier }
998e32b400SDavid du Colombier 
1008e32b400SDavid du Colombier static void
writeconf(void)1018e32b400SDavid du Colombier writeconf(void)
1028e32b400SDavid du Colombier {
1038e32b400SDavid du Colombier 	char *p, *q;
1048e32b400SDavid du Colombier 	int n;
1058e32b400SDavid du Colombier 
1068e32b400SDavid du Colombier 	p = getconfenv();
1078e32b400SDavid du Colombier 
1088e32b400SDavid du Colombier 	if(waserror()) {
1098e32b400SDavid du Colombier 		free(p);
1108e32b400SDavid du Colombier 		nexterror();
1118e32b400SDavid du Colombier 	}
1128e32b400SDavid du Colombier 
1138e32b400SDavid du Colombier 	/* convert to name=value\n format */
1148e32b400SDavid du Colombier 	for(q=p; *q; q++) {
1158e32b400SDavid du Colombier 		q += strlen(q);
1168e32b400SDavid du Colombier 		*q = '=';
1178e32b400SDavid du Colombier 		q += strlen(q);
1188e32b400SDavid du Colombier 		*q = '\n';
1198e32b400SDavid du Colombier 	}
1208e32b400SDavid du Colombier 	n = q - p + 1;
1218e32b400SDavid du Colombier 	if(n >= BOOTARGSLEN)
1228e32b400SDavid du Colombier 		error("kernel configuration too large");
1238e32b400SDavid du Colombier 	memmove(BOOTARGS, p, n);
12493631029SDavid du Colombier 	memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
1258e32b400SDavid du Colombier 	poperror();
1268e32b400SDavid du Colombier 	free(p);
1278e32b400SDavid du Colombier }
1288e32b400SDavid du Colombier 
1298e32b400SDavid du Colombier /*
1308e32b400SDavid du Colombier  * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
1318e32b400SDavid du Colombier  * tftp in u-boot.  no longer uses malloc, so can be called early.
1328e32b400SDavid du Colombier  */
1338e32b400SDavid du Colombier static void
plan9iniinit(void)1348e32b400SDavid du Colombier plan9iniinit(void)
1358e32b400SDavid du Colombier {
1368e32b400SDavid du Colombier 	char *k, *v, *next;
1378e32b400SDavid du Colombier 
1388e32b400SDavid du Colombier 	k = (char *)CONFADDR;
1398e32b400SDavid du Colombier 	if(!isascii(*k))
1408e32b400SDavid du Colombier 		return;
1418e32b400SDavid du Colombier 
1428e32b400SDavid du Colombier 	for(; k && *k != '\0'; k = next) {
1438e32b400SDavid du Colombier 		if (!isascii(*k))		/* sanity check */
1448e32b400SDavid du Colombier 			break;
1458e32b400SDavid du Colombier 		next = strchr(k, '\n');
1468e32b400SDavid du Colombier 		if (next)
1478e32b400SDavid du Colombier 			*next++ = '\0';
1488e32b400SDavid du Colombier 
1498e32b400SDavid du Colombier 		if (*k == '\0' || *k == '\n' || *k == '#')
1508e32b400SDavid du Colombier 			continue;
1518e32b400SDavid du Colombier 		v = strchr(k, '=');
1528e32b400SDavid du Colombier 		if(v == nil)
1538e32b400SDavid du Colombier 			continue;		/* mal-formed line */
1548e32b400SDavid du Colombier 		*v++ = '\0';
1558e32b400SDavid du Colombier 
1568e32b400SDavid du Colombier 		addconf(k, v);
1578e32b400SDavid du Colombier 	}
1588e32b400SDavid du Colombier }
1598e32b400SDavid du Colombier 
1608e32b400SDavid du Colombier static void
optionsinit(char * s)1618e32b400SDavid du Colombier optionsinit(char* s)
1628e32b400SDavid du Colombier {
1638e32b400SDavid du Colombier 	char *o;
1648e32b400SDavid du Colombier 
1658e32b400SDavid du Colombier 	strcpy(oenv, "");
1668e32b400SDavid du Colombier 	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
1678e32b400SDavid du Colombier 	if(getenv("bootargs", o, o - oargb) != nil)
1688e32b400SDavid du Colombier 		*(o-1) = ' ';
1698e32b400SDavid du Colombier 
1708e32b400SDavid du Colombier 	oargblen = strlen(oargb);
1718e32b400SDavid du Colombier 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
1728e32b400SDavid du Colombier 	oargv[oargc] = nil;
1738e32b400SDavid du Colombier }
1748e32b400SDavid du Colombier 
1758e32b400SDavid du Colombier char*
getenv(char * name,char * buf,int n)1768e32b400SDavid du Colombier getenv(char* name, char* buf, int n)
1778e32b400SDavid du Colombier {
1788e32b400SDavid du Colombier 	char *e, *p, *q;
1798e32b400SDavid du Colombier 
1808e32b400SDavid du Colombier 	p = oenv;
1818e32b400SDavid du Colombier 	while(*p != 0){
1828e32b400SDavid du Colombier 		if((e = strchr(p, '=')) == nil)
1838e32b400SDavid du Colombier 			break;
1848e32b400SDavid du Colombier 		for(q = name; p < e; p++){
1858e32b400SDavid du Colombier 			if(*p != *q)
1868e32b400SDavid du Colombier 				break;
1878e32b400SDavid du Colombier 			q++;
1888e32b400SDavid du Colombier 		}
1898e32b400SDavid du Colombier 		if(p == e && *q == 0){
1908e32b400SDavid du Colombier 			strecpy(buf, buf+n, e+1);
1918e32b400SDavid du Colombier 			return buf;
1928e32b400SDavid du Colombier 		}
1938e32b400SDavid du Colombier 		p += strlen(p)+1;
1948e32b400SDavid du Colombier 	}
1958e32b400SDavid du Colombier 
1968e32b400SDavid du Colombier 	return nil;
1978e32b400SDavid du Colombier }
1988e32b400SDavid du Colombier 
1998e32b400SDavid du Colombier void
main(void)2008e32b400SDavid du Colombier main(void)
2018e32b400SDavid du Colombier {
2028e32b400SDavid du Colombier //	int i;
2038e32b400SDavid du Colombier 	extern char bdata[], edata[], end[], etext[];
2048e32b400SDavid du Colombier 	static ulong vfy = 0xcafebabe;
2058e32b400SDavid du Colombier 
2068e32b400SDavid du Colombier 	/* l.s has already printed "Plan 9 from Be" */
2078e32b400SDavid du Colombier //	m = mach;					/* now done in l.s */
2088e32b400SDavid du Colombier 
2098e32b400SDavid du Colombier 	/* realign data seg; apparently -H0 -R4096 does not pad the text seg */
2108e32b400SDavid du Colombier 	if (vfy != 0xcafebabe) {
2118e32b400SDavid du Colombier //		wave('<'); wave('-');
2128e32b400SDavid du Colombier 		memmove(bdata, etext, edata - bdata);
2138e32b400SDavid du Colombier 	}
2148e32b400SDavid du Colombier 	/*
2158e32b400SDavid du Colombier 	 * once data segment is in place, always zero bss since we may
2168e32b400SDavid du Colombier 	 * have been loaded by another Plan 9 kernel.
2178e32b400SDavid du Colombier 	 */
2188e32b400SDavid du Colombier 	memset(edata, 0, end - edata);		/* zero BSS */
2198e32b400SDavid du Colombier 	cacheuwbinv();
2208e32b400SDavid du Colombier 	l2cacheuwbinv();
2218e32b400SDavid du Colombier 
2228e32b400SDavid du Colombier 	if (vfy != 0xcafebabe)
2238e32b400SDavid du Colombier 		panic("data segment misaligned");
2248e32b400SDavid du Colombier 	vfy = 0;
2258e32b400SDavid du Colombier 
2268e32b400SDavid du Colombier wave('l');
2278e32b400SDavid du Colombier 	machinit();
2288e32b400SDavid du Colombier 	mmuinit();
2298e32b400SDavid du Colombier 
2308e32b400SDavid du Colombier 	optionsinit("/boot/boot boot");
2318e32b400SDavid du Colombier 	quotefmtinstall();
2328e32b400SDavid du Colombier 
2338e32b400SDavid du Colombier 	/* want plan9.ini to be able to affect memory sizing in confinit */
2348e32b400SDavid du Colombier 	plan9iniinit();		/* before we step on plan9.ini in low memory */
2358e32b400SDavid du Colombier 
236add6b5c5SDavid du Colombier 	trapinit();		/* so confinit can probe memory to size it */
237add6b5c5SDavid du Colombier 	confinit();		/* figures out amount of memory */
2388e32b400SDavid du Colombier 	/* xinit prints (if it can), so finish up the banner here. */
23993631029SDavid du Colombier 	delay(500);
2408e32b400SDavid du Colombier 	iprint("l Labs\n\n");
24193631029SDavid du Colombier 	delay(500);
2428e32b400SDavid du Colombier 	xinit();
2438e32b400SDavid du Colombier 
244add6b5c5SDavid du Colombier 	mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
245add6b5c5SDavid du Colombier 
2468e32b400SDavid du Colombier 	/*
2478e32b400SDavid du Colombier 	 * Printinit will cause the first malloc call.
2488e32b400SDavid du Colombier 	 * (printinit->qopen->malloc) unless any of the
2498e32b400SDavid du Colombier 	 * above (like clockinit) do an irqenable, which
2508e32b400SDavid du Colombier 	 * will call malloc.
2518e32b400SDavid du Colombier 	 * If the system dies here it's probably due
2528e32b400SDavid du Colombier 	 * to malloc(->xalloc) not being initialised
2538e32b400SDavid du Colombier 	 * correctly, or the data segment is misaligned
2548e32b400SDavid du Colombier 	 * (it's amazing how far you can get with
2558e32b400SDavid du Colombier 	 * things like that completely broken).
2568e32b400SDavid du Colombier 	 *
2578e32b400SDavid du Colombier 	 * (Should be) boilerplate from here on.
2588e32b400SDavid du Colombier 	 */
2598e32b400SDavid du Colombier 
26093631029SDavid du Colombier 	archreset();			/* configure clock signals */
2618e32b400SDavid du Colombier 	clockinit();			/* start clocks */
2628e32b400SDavid du Colombier 	timersinit();
2638e32b400SDavid du Colombier 	watchdoginit();
2648e32b400SDavid du Colombier 
26593631029SDavid du Colombier 	delay(250);			/* let uart catch up */
2668e32b400SDavid du Colombier 	printinit();
26793631029SDavid du Colombier 	kbdenable();
2688bfb44c2SDavid du Colombier 
2698bfb44c2SDavid du Colombier 	cpuidprint();
2708bfb44c2SDavid du Colombier //	chkmissing();
2718e32b400SDavid du Colombier 
2728e32b400SDavid du Colombier 	procinit0();
2738e32b400SDavid du Colombier 	initseg();
2748e32b400SDavid du Colombier 
2758e32b400SDavid du Colombier 	dmainit();
2768e32b400SDavid du Colombier 	links();
27793631029SDavid du Colombier 	conf.monitor = 1;
27893631029SDavid du Colombier 	screeninit();
27993631029SDavid du Colombier 	chandevreset();			/* most devices are discovered here */
28093631029SDavid du Colombier 
28193631029SDavid du Colombier //	i8250console();			/* too early; see init0 */
2828e32b400SDavid du Colombier 
2838e32b400SDavid du Colombier 	pageinit();
2848e32b400SDavid du Colombier 	swapinit();
2858e32b400SDavid du Colombier 	userinit();
2868e32b400SDavid du Colombier 	schedinit();
2878e32b400SDavid du Colombier }
2888e32b400SDavid du Colombier 
2898e32b400SDavid du Colombier void
machinit(void)2908e32b400SDavid du Colombier machinit(void)
2918e32b400SDavid du Colombier {
2928e32b400SDavid du Colombier 	if (m == 0)
2938e32b400SDavid du Colombier 		wave('?');
2948e32b400SDavid du Colombier //	memset(m, 0, sizeof(Mach));	/* done by l.s, now contains stack */
2958e32b400SDavid du Colombier 	m->machno = 0;
2968e32b400SDavid du Colombier 	machaddr[m->machno] = m;
2978e32b400SDavid du Colombier 
2988e32b400SDavid du Colombier 	m->ticks = 1;
2998e32b400SDavid du Colombier 	m->perf.period = 1;
3008e32b400SDavid du Colombier 
3018e32b400SDavid du Colombier 	conf.nmach = 1;
3028e32b400SDavid du Colombier 
3038e32b400SDavid du Colombier 	active.machs = 1;
3048e32b400SDavid du Colombier 	active.exiting = 0;
3058e32b400SDavid du Colombier 
3068e32b400SDavid du Colombier 	up = nil;
3078e32b400SDavid du Colombier }
3088e32b400SDavid du Colombier 
3098e32b400SDavid du Colombier static void
shutdown(int ispanic)3108e32b400SDavid du Colombier shutdown(int ispanic)
3118e32b400SDavid du Colombier {
3128e32b400SDavid du Colombier 	int ms, once;
3138e32b400SDavid du Colombier 
3148e32b400SDavid du Colombier 	lock(&active);
3158e32b400SDavid du Colombier 	if(ispanic)
3168e32b400SDavid du Colombier 		active.ispanic = ispanic;
3178e32b400SDavid du Colombier 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
3188e32b400SDavid du Colombier 		active.ispanic = 0;
3198e32b400SDavid du Colombier 	once = active.machs & (1<<m->machno);
3208e32b400SDavid du Colombier 	active.machs &= ~(1<<m->machno);
3218e32b400SDavid du Colombier 	active.exiting = 1;
3228e32b400SDavid du Colombier 	unlock(&active);
3238e32b400SDavid du Colombier 
3248e32b400SDavid du Colombier 	if(once)
3258e32b400SDavid du Colombier 		iprint("cpu%d: exiting\n", m->machno);
3268e32b400SDavid du Colombier 	spllo();
3278e32b400SDavid du Colombier 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
3288e32b400SDavid du Colombier 		delay(TK2MS(2));
3298e32b400SDavid du Colombier 		if(active.machs == 0 && consactive() == 0)
3308e32b400SDavid du Colombier 			break;
3318e32b400SDavid du Colombier 	}
3328e32b400SDavid du Colombier 	delay(1000);
3338e32b400SDavid du Colombier }
3348e32b400SDavid du Colombier 
3358e32b400SDavid du Colombier /*
3368e32b400SDavid du Colombier  *  exit kernel either on a panic or user request
3378e32b400SDavid du Colombier  */
3388e32b400SDavid du Colombier void
exit(int code)3398e32b400SDavid du Colombier exit(int code)
3408e32b400SDavid du Colombier {
3418e32b400SDavid du Colombier 	shutdown(code);
3428e32b400SDavid du Colombier 	splhi();
3438e32b400SDavid du Colombier 	archreboot();
3448e32b400SDavid du Colombier }
3458e32b400SDavid du Colombier 
3468e32b400SDavid du Colombier int
isaconfig(char * class,int ctlrno,ISAConf * isa)3478e32b400SDavid du Colombier isaconfig(char *class, int ctlrno, ISAConf *isa)
3488e32b400SDavid du Colombier {
3498e32b400SDavid du Colombier 	char cc[32], *p;
3508e32b400SDavid du Colombier 	int i;
3518e32b400SDavid du Colombier 
3528e32b400SDavid du Colombier 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
3538e32b400SDavid du Colombier 	p = getconf(cc);
3548e32b400SDavid du Colombier 	if(p == nil)
3558e32b400SDavid du Colombier 		return 0;
3568e32b400SDavid du Colombier 
3578e32b400SDavid du Colombier 	isa->type = "";
3588e32b400SDavid du Colombier 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
3598e32b400SDavid du Colombier 	for(i = 0; i < isa->nopt; i++){
3608e32b400SDavid du Colombier 		p = isa->opt[i];
3618e32b400SDavid du Colombier 		if(cistrncmp(p, "type=", 5) == 0)
3628e32b400SDavid du Colombier 			isa->type = p + 5;
3638e32b400SDavid du Colombier 		else if(cistrncmp(p, "port=", 5) == 0)
3648e32b400SDavid du Colombier 			isa->port = strtoul(p+5, &p, 0);
3658e32b400SDavid du Colombier 		else if(cistrncmp(p, "irq=", 4) == 0)
3668e32b400SDavid du Colombier 			isa->irq = strtoul(p+4, &p, 0);
3678e32b400SDavid du Colombier 		else if(cistrncmp(p, "dma=", 4) == 0)
3688e32b400SDavid du Colombier 			isa->dma = strtoul(p+4, &p, 0);
3698e32b400SDavid du Colombier 		else if(cistrncmp(p, "mem=", 4) == 0)
3708e32b400SDavid du Colombier 			isa->mem = strtoul(p+4, &p, 0);
3718e32b400SDavid du Colombier 		else if(cistrncmp(p, "size=", 5) == 0)
3728e32b400SDavid du Colombier 			isa->size = strtoul(p+5, &p, 0);
3738e32b400SDavid du Colombier 		else if(cistrncmp(p, "freq=", 5) == 0)
3748e32b400SDavid du Colombier 			isa->freq = strtoul(p+5, &p, 0);
3758e32b400SDavid du Colombier 	}
3768e32b400SDavid du Colombier 	return 1;
3778e32b400SDavid du Colombier }
3788e32b400SDavid du Colombier 
3798e32b400SDavid du Colombier /*
3808e32b400SDavid du Colombier  * the new kernel is already loaded at address `code'
3818e32b400SDavid du Colombier  * of size `size' and entry point `entry'.
3828e32b400SDavid du Colombier  */
3838e32b400SDavid du Colombier void
reboot(void * entry,void * code,ulong size)3848e32b400SDavid du Colombier reboot(void *entry, void *code, ulong size)
3858e32b400SDavid du Colombier {
3868e32b400SDavid du Colombier 	void (*f)(ulong, ulong, ulong);
3878e32b400SDavid du Colombier 
3888e32b400SDavid du Colombier 	print("starting reboot...");
3898e32b400SDavid du Colombier 	writeconf();
3908e32b400SDavid du Colombier 	shutdown(0);
3918e32b400SDavid du Colombier 
3928e32b400SDavid du Colombier 	/*
3938e32b400SDavid du Colombier 	 * should be the only processor running now
3948e32b400SDavid du Colombier 	 */
3958e32b400SDavid du Colombier 
3968e32b400SDavid du Colombier 	print("reboot entry %#lux code %#lux size %ld\n",
3978e32b400SDavid du Colombier 		PADDR(entry), PADDR(code), size);
3988e32b400SDavid du Colombier 	delay(100);
3998e32b400SDavid du Colombier 
4008e32b400SDavid du Colombier 	/* turn off buffered serial console */
4018e32b400SDavid du Colombier 	serialoq = nil;
4028e32b400SDavid du Colombier 	kprintoq = nil;
4038e32b400SDavid du Colombier 	screenputs = nil;
4048e32b400SDavid du Colombier 
4058e32b400SDavid du Colombier 	/* shutdown devices */
4068e32b400SDavid du Colombier 	chandevshutdown();
4078e32b400SDavid du Colombier 
4088e32b400SDavid du Colombier 	/* call off the dog */
4098e32b400SDavid du Colombier 	clockshutdown();
4108e32b400SDavid du Colombier 
4118e32b400SDavid du Colombier 	splhi();
4128e32b400SDavid du Colombier 	intrsoff();
4138e32b400SDavid du Colombier 
4148e32b400SDavid du Colombier 	/* setup reboot trampoline function */
4158e32b400SDavid du Colombier 	f = (void*)REBOOTADDR;
4168e32b400SDavid du Colombier 	memmove(f, rebootcode, sizeof(rebootcode));
4178e32b400SDavid du Colombier 	cacheuwbinv();
4188e32b400SDavid du Colombier 	l2cacheuwbinv();
4198e32b400SDavid du Colombier 
4208e32b400SDavid du Colombier 	/* off we go - never to return */
4218e32b400SDavid du Colombier 	(*f)(PADDR(entry), PADDR(code), size);
4228e32b400SDavid du Colombier 
4238e32b400SDavid du Colombier 	iprint("loaded kernel returned!\n");
4248e32b400SDavid du Colombier 	delay(1000);
4258e32b400SDavid du Colombier 	archreboot();
4268e32b400SDavid du Colombier }
4278e32b400SDavid du Colombier 
4288e32b400SDavid du Colombier /*
4298e32b400SDavid du Colombier  *  starting place for first process
4308e32b400SDavid du Colombier  */
4318e32b400SDavid du Colombier void
init0(void)4328e32b400SDavid du Colombier init0(void)
4338e32b400SDavid du Colombier {
4348e32b400SDavid du Colombier 	int i;
4358e32b400SDavid du Colombier 	char buf[2*KNAMELEN];
4368e32b400SDavid du Colombier 
4378e32b400SDavid du Colombier 	up->nerrlab = 0;
4388e32b400SDavid du Colombier 	coherence();
4398e32b400SDavid du Colombier 	spllo();
4408e32b400SDavid du Colombier 
4418e32b400SDavid du Colombier 	/*
4428e32b400SDavid du Colombier 	 * These are o.k. because rootinit is null.
4438e32b400SDavid du Colombier 	 * Then early kproc's will have a root and dot.
4448e32b400SDavid du Colombier 	 */
4458e32b400SDavid du Colombier 	up->slash = namec("#/", Atodir, 0, 0);
4468e32b400SDavid du Colombier 	pathclose(up->slash->path);
4478e32b400SDavid du Colombier 	up->slash->path = newpath("/");
4488e32b400SDavid du Colombier 	up->dot = cclone(up->slash);
4498e32b400SDavid du Colombier 
4508e32b400SDavid du Colombier 	dmatest();		/* needs `up' set, so can't do it earlier */
4518e32b400SDavid du Colombier 	chandevinit();
45293631029SDavid du Colombier 	i8250console();		/* might be redundant, but harmless */
45393631029SDavid du Colombier 	if(kbdq == nil)
45493631029SDavid du Colombier 		panic("init0: nil kbdq");
45593631029SDavid du Colombier 	if(serialoq == nil)
45693631029SDavid du Colombier 		panic("init0: nil serialoq");
457bacfa46cSDavid du Colombier 	normalprint = 1;
4588e32b400SDavid du Colombier 
4598e32b400SDavid du Colombier 	if(!waserror()){
4608e32b400SDavid du Colombier 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
4618e32b400SDavid du Colombier 		ksetenv("terminal", buf, 0);
4628e32b400SDavid du Colombier 		ksetenv("cputype", "arm", 0);
4638e32b400SDavid du Colombier 		if(cpuserver)
4648e32b400SDavid du Colombier 			ksetenv("service", "cpu", 0);
4658e32b400SDavid du Colombier 		else
4668e32b400SDavid du Colombier 			ksetenv("service", "terminal", 0);
4678e32b400SDavid du Colombier 
4688e32b400SDavid du Colombier 		/* convert plan9.ini variables to #e and #ec */
4698e32b400SDavid du Colombier 		for(i = 0; i < nconf; i++) {
4708e32b400SDavid du Colombier 			ksetenv(confname[i], confval[i], 0);
4718e32b400SDavid du Colombier 			ksetenv(confname[i], confval[i], 1);
4728e32b400SDavid du Colombier 		}
4738e32b400SDavid du Colombier 		poperror();
4748e32b400SDavid du Colombier 	}
4758e32b400SDavid du Colombier 	kproc("alarm", alarmkproc, 0);
4768e32b400SDavid du Colombier 	touser(sp);
4778e32b400SDavid du Colombier }
4788e32b400SDavid du Colombier 
4798e32b400SDavid du Colombier static void
bootargs(uintptr base)4808e32b400SDavid du Colombier bootargs(uintptr base)
4818e32b400SDavid du Colombier {
4828e32b400SDavid du Colombier 	int i;
4838e32b400SDavid du Colombier 	ulong ssize;
4848e32b400SDavid du Colombier 	char **av, *p;
4858e32b400SDavid du Colombier 
4868e32b400SDavid du Colombier 	/*
4878e32b400SDavid du Colombier 	 * Push the boot args onto the stack.
4888e32b400SDavid du Colombier 	 * The initial value of the user stack must be such
4898e32b400SDavid du Colombier 	 * that the total used is larger than the maximum size
4908e32b400SDavid du Colombier 	 * of the argument list checked in syscall.
4918e32b400SDavid du Colombier 	 */
4928e32b400SDavid du Colombier 	i = oargblen+1;
493*23a96966SDavid du Colombier 	p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
4948e32b400SDavid du Colombier 	memmove(p, oargb, i);
4958e32b400SDavid du Colombier 
4968e32b400SDavid du Colombier 	/*
4978e32b400SDavid du Colombier 	 * Now push argc and the argv pointers.
4988e32b400SDavid du Colombier 	 * This isn't strictly correct as the code jumped to by
4998e32b400SDavid du Colombier 	 * touser in init9.s calls startboot (port/initcode.c) which
5008e32b400SDavid du Colombier 	 * expects arguments
5018e32b400SDavid du Colombier 	 * 	startboot(char *argv0, char **argv)
5028e32b400SDavid du Colombier 	 * not the usual (int argc, char* argv[]), but argv0 is
5038e32b400SDavid du Colombier 	 * unused so it doesn't matter (at the moment...).
5048e32b400SDavid du Colombier 	 */
5058e32b400SDavid du Colombier 	av = (char**)(p - (oargc+2)*sizeof(char*));
506b1c4f505SDavid du Colombier 	ssize = base + BY2PG - PTR2UINT(av);
5078e32b400SDavid du Colombier 	*av++ = (char*)oargc;
5088e32b400SDavid du Colombier 	for(i = 0; i < oargc; i++)
5098e32b400SDavid du Colombier 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
5108e32b400SDavid du Colombier 	*av = nil;
5118e32b400SDavid du Colombier 
5128e32b400SDavid du Colombier 	/*
5138e32b400SDavid du Colombier 	 * Leave space for the return PC of the
5148e32b400SDavid du Colombier 	 * caller of initcode.
5158e32b400SDavid du Colombier 	 */
5168e32b400SDavid du Colombier 	sp = USTKTOP - ssize - sizeof(void*);
5178e32b400SDavid du Colombier }
5188e32b400SDavid du Colombier 
5198e32b400SDavid du Colombier /*
5208e32b400SDavid du Colombier  *  create the first process
5218e32b400SDavid du Colombier  */
5228e32b400SDavid du Colombier void
userinit(void)5238e32b400SDavid du Colombier userinit(void)
5248e32b400SDavid du Colombier {
5258e32b400SDavid du Colombier 	Proc *p;
5268e32b400SDavid du Colombier 	Segment *s;
5278e32b400SDavid du Colombier 	KMap *k;
5288e32b400SDavid du Colombier 	Page *pg;
5298e32b400SDavid du Colombier 
5308e32b400SDavid du Colombier 	/* no processes yet */
5318e32b400SDavid du Colombier 	up = nil;
5328e32b400SDavid du Colombier 
5338e32b400SDavid du Colombier 	p = newproc();
5348e32b400SDavid du Colombier 	p->pgrp = newpgrp();
5358e32b400SDavid du Colombier 	p->egrp = smalloc(sizeof(Egrp));
5368e32b400SDavid du Colombier 	p->egrp->ref = 1;
5378e32b400SDavid du Colombier 	p->fgrp = dupfgrp(nil);
5388e32b400SDavid du Colombier 	p->rgrp = newrgrp();
5398e32b400SDavid du Colombier 	p->procmode = 0640;
5408e32b400SDavid du Colombier 
5418e32b400SDavid du Colombier 	kstrdup(&eve, "");
5428e32b400SDavid du Colombier 	kstrdup(&p->text, "*init*");
5438e32b400SDavid du Colombier 	kstrdup(&p->user, eve);
5448e32b400SDavid du Colombier 
5458e32b400SDavid du Colombier 	/*
5468e32b400SDavid du Colombier 	 * Kernel Stack
5478e32b400SDavid du Colombier 	 */
5488e32b400SDavid du Colombier 	p->sched.pc = PTR2UINT(init0);
5498e32b400SDavid du Colombier 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
5508e32b400SDavid du Colombier 	p->sched.sp = STACKALIGN(p->sched.sp);
5518e32b400SDavid du Colombier 
5528e32b400SDavid du Colombier 	/*
5538e32b400SDavid du Colombier 	 * User Stack
5548e32b400SDavid du Colombier 	 *
5558e32b400SDavid du Colombier 	 * Technically, newpage can't be called here because it
5568e32b400SDavid du Colombier 	 * should only be called when in a user context as it may
5578e32b400SDavid du Colombier 	 * try to sleep if there are no pages available, but that
5588e32b400SDavid du Colombier 	 * shouldn't be the case here.
5598e32b400SDavid du Colombier 	 */
5608e32b400SDavid du Colombier 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
5618e32b400SDavid du Colombier 	s->flushme++;
5628e32b400SDavid du Colombier 	p->seg[SSEG] = s;
5638e32b400SDavid du Colombier 	pg = newpage(1, 0, USTKTOP-BY2PG);
5648e32b400SDavid du Colombier 	segpage(s, pg);
5658e32b400SDavid du Colombier 	k = kmap(pg);
5668e32b400SDavid du Colombier 	bootargs(VA(k));
5678e32b400SDavid du Colombier 	kunmap(k);
5688e32b400SDavid du Colombier 
5698e32b400SDavid du Colombier 	/*
5708e32b400SDavid du Colombier 	 * Text
5718e32b400SDavid du Colombier 	 */
5728e32b400SDavid du Colombier 	s = newseg(SG_TEXT, UTZERO, 1);
5738e32b400SDavid du Colombier 	p->seg[TSEG] = s;
5748e32b400SDavid du Colombier 	pg = newpage(1, 0, UTZERO);
5758e32b400SDavid du Colombier 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
5768e32b400SDavid du Colombier 	segpage(s, pg);
5778e32b400SDavid du Colombier 	k = kmap(s->map[0]->pages[0]);
5788e32b400SDavid du Colombier 	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
5798e32b400SDavid du Colombier 	kunmap(k);
5808e32b400SDavid du Colombier 
5818e32b400SDavid du Colombier 	ready(p);
5828e32b400SDavid du Colombier }
5838e32b400SDavid du Colombier 
5848e32b400SDavid du Colombier Conf conf;			/* XXX - must go - gag */
5858e32b400SDavid du Colombier 
5868e32b400SDavid du Colombier Confmem omapmem[nelem(conf.mem)] = {
5878e32b400SDavid du Colombier 	/*
5888e32b400SDavid du Colombier 	 * Memory available to Plan 9:
5898e32b400SDavid du Colombier 	 */
590add6b5c5SDavid du Colombier 	{ .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
5918e32b400SDavid du Colombier };
592add6b5c5SDavid du Colombier ulong memsize = Minmem;
593add6b5c5SDavid du Colombier 
594add6b5c5SDavid du Colombier static int
gotmem(uintptr sz)595add6b5c5SDavid du Colombier gotmem(uintptr sz)
596add6b5c5SDavid du Colombier {
597add6b5c5SDavid du Colombier 	uintptr addr;
598add6b5c5SDavid du Colombier 
599add6b5c5SDavid du Colombier 	addr = PHYSDRAM + sz - BY2WD;
600add6b5c5SDavid du Colombier 	mmuidmap(addr, 1);
601add6b5c5SDavid du Colombier 	if (probeaddr(addr) >= 0) {
602add6b5c5SDavid du Colombier 		memsize = sz;
603add6b5c5SDavid du Colombier 		return 0;
604add6b5c5SDavid du Colombier 	}
605add6b5c5SDavid du Colombier 	return -1;
606add6b5c5SDavid du Colombier }
6078e32b400SDavid du Colombier 
6088e32b400SDavid du Colombier void
confinit(void)6098e32b400SDavid du Colombier confinit(void)
6108e32b400SDavid du Colombier {
6118e32b400SDavid du Colombier 	int i;
6128e32b400SDavid du Colombier 	ulong kpages;
6138e32b400SDavid du Colombier 	uintptr pa;
6148e32b400SDavid du Colombier 	char *p;
6158e32b400SDavid du Colombier 
6168e32b400SDavid du Colombier 	/*
6178e32b400SDavid du Colombier 	 * Copy the physical memory configuration to Conf.mem.
6188e32b400SDavid du Colombier 	 */
6198e32b400SDavid du Colombier 	if(nelem(omapmem) > nelem(conf.mem)){
6208e32b400SDavid du Colombier 		iprint("memory configuration botch\n");
6218e32b400SDavid du Colombier 		exit(1);
6228e32b400SDavid du Colombier 	}
6238e32b400SDavid du Colombier 	if((p = getconf("*maxmem")) != nil) {
6248e32b400SDavid du Colombier 		memsize = strtoul(p, 0, 0) - PHYSDRAM;
6258e32b400SDavid du Colombier 		if (memsize < 16*MB)		/* sanity */
6268e32b400SDavid du Colombier 			memsize = 16*MB;
6278e32b400SDavid du Colombier 	}
6288e32b400SDavid du Colombier 
629add6b5c5SDavid du Colombier 	/*
630add6b5c5SDavid du Colombier 	 * see if all that memory exists; if not, find out how much does.
631add6b5c5SDavid du Colombier 	 * trapinit must have been called first.
632add6b5c5SDavid du Colombier 	 */
633add6b5c5SDavid du Colombier 	if (gotmem(memsize) < 0 && gotmem(256*MB) < 0 && gotmem(128*MB) < 0) {
634add6b5c5SDavid du Colombier 		iprint("can't find any memory, assuming %dMB\n", Minmem / MB);
635add6b5c5SDavid du Colombier 		memsize = Minmem;
636add6b5c5SDavid du Colombier 	}
637add6b5c5SDavid du Colombier 
6388e32b400SDavid du Colombier 	omapmem[0].limit = PHYSDRAM + memsize;
6398e32b400SDavid du Colombier 	memmove(conf.mem, omapmem, sizeof(omapmem));
6408e32b400SDavid du Colombier 
6418e32b400SDavid du Colombier 	conf.npage = 0;
6428e32b400SDavid du Colombier 	pa = PADDR(PGROUND(PTR2UINT(end)));
6438e32b400SDavid du Colombier 
6448e32b400SDavid du Colombier 	/*
6458e32b400SDavid du Colombier 	 *  we assume that the kernel is at the beginning of one of the
6468e32b400SDavid du Colombier 	 *  contiguous chunks of memory and fits therein.
6478e32b400SDavid du Colombier 	 */
6488e32b400SDavid du Colombier 	for(i=0; i<nelem(conf.mem); i++){
6498e32b400SDavid du Colombier 		/* take kernel out of allocatable space */
6508e32b400SDavid du Colombier 		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
6518e32b400SDavid du Colombier 			conf.mem[i].base = pa;
6528e32b400SDavid du Colombier 
6538e32b400SDavid du Colombier 		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
6548e32b400SDavid du Colombier 		conf.npage += conf.mem[i].npage;
6558e32b400SDavid du Colombier 	}
6568e32b400SDavid du Colombier 
6578e32b400SDavid du Colombier 	conf.upages = (conf.npage*80)/100;
6588e32b400SDavid du Colombier 	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
6598e32b400SDavid du Colombier 
6608e32b400SDavid du Colombier 	/* only one processor */
6618e32b400SDavid du Colombier 	conf.nmach = 1;
6628e32b400SDavid du Colombier 
6638e32b400SDavid du Colombier 	/* set up other configuration parameters */
6648e32b400SDavid du Colombier 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
6658e32b400SDavid du Colombier 	if(cpuserver)
6668e32b400SDavid du Colombier 		conf.nproc *= 3;
6678e32b400SDavid du Colombier 	if(conf.nproc > 2000)
6688e32b400SDavid du Colombier 		conf.nproc = 2000;
6698e32b400SDavid du Colombier 	conf.nswap = conf.npage*3;
6708e32b400SDavid du Colombier 	conf.nswppo = 4096;
6718e32b400SDavid du Colombier 	conf.nimage = 200;
6728e32b400SDavid du Colombier 
6738e32b400SDavid du Colombier 	conf.copymode = 0;		/* copy on write */
6748e32b400SDavid du Colombier 
6758e32b400SDavid du Colombier 	/*
6768e32b400SDavid du Colombier 	 * Guess how much is taken by the large permanent
6778e32b400SDavid du Colombier 	 * datastructures. Mntcache and Mntrpc are not accounted for
6788e32b400SDavid du Colombier 	 * (probably ~300KB).
6798e32b400SDavid du Colombier 	 */
6808e32b400SDavid du Colombier 	kpages = conf.npage - conf.upages;
6818e32b400SDavid du Colombier 	kpages *= BY2PG;
6828e32b400SDavid du Colombier 	kpages -= conf.upages*sizeof(Page)
6838e32b400SDavid du Colombier 		+ conf.nproc*sizeof(Proc)
6848e32b400SDavid du Colombier 		+ conf.nimage*sizeof(Image)
6858e32b400SDavid du Colombier 		+ conf.nswap
6868e32b400SDavid du Colombier 		+ conf.nswppo*sizeof(Page);
6878e32b400SDavid du Colombier 	mainmem->maxsize = kpages;
6888e32b400SDavid du Colombier 	if(!cpuserver)
6898e32b400SDavid du Colombier 		/*
6908e32b400SDavid du Colombier 		 * give terminals lots of image memory, too; the dynamic
6918e32b400SDavid du Colombier 		 * allocation will balance the load properly, hopefully.
6928e32b400SDavid du Colombier 		 * be careful with 32-bit overflow.
6938e32b400SDavid du Colombier 		 */
6948e32b400SDavid du Colombier 		imagmem->maxsize = kpages;
6958e32b400SDavid du Colombier 
6968e32b400SDavid du Colombier //	archconfinit();
6978e32b400SDavid du Colombier }
6988e32b400SDavid du Colombier 
6998e32b400SDavid du Colombier int
cmpswap(long * addr,long old,long new)7008e32b400SDavid du Colombier cmpswap(long *addr, long old, long new)
7018e32b400SDavid du Colombier {
7028e32b400SDavid du Colombier 	return cas32(addr, old, new);
7038e32b400SDavid du Colombier }
704