xref: /plan9/sys/src/9/teg2/main.c (revision 5c88beae5a9738eb333d417409242ad06a9c481a)
13de6a9c0SDavid du Colombier #include "u.h"
23de6a9c0SDavid du Colombier #include "../port/lib.h"
33de6a9c0SDavid du Colombier #include "mem.h"
43de6a9c0SDavid du Colombier #include "dat.h"
53de6a9c0SDavid du Colombier #include "fns.h"
63de6a9c0SDavid du Colombier #include "io.h"
73de6a9c0SDavid du Colombier 
83de6a9c0SDavid du Colombier #include "init.h"
93de6a9c0SDavid du Colombier #include <pool.h>
1023a96966SDavid du Colombier #include <tos.h>
113de6a9c0SDavid du Colombier 
123de6a9c0SDavid du Colombier #include "arm.h"
133de6a9c0SDavid du Colombier #include "reboot.h"
143de6a9c0SDavid du Colombier 
153de6a9c0SDavid du Colombier /*
163de6a9c0SDavid du Colombier  * Where configuration info is left for the loaded programme.
173de6a9c0SDavid du Colombier  * This will turn into a structure as more is done by the boot loader
183de6a9c0SDavid du Colombier  * (e.g. why parse the .ini file twice?).
193de6a9c0SDavid du Colombier  * There are 3584 bytes available at CONFADDR.
203de6a9c0SDavid du Colombier  */
213de6a9c0SDavid du Colombier #define BOOTARGS	((char*)CONFADDR)
223de6a9c0SDavid du Colombier #define	BOOTARGSLEN	(16*KiB)		/* limit in devenv.c */
233de6a9c0SDavid du Colombier #define	MAXCONF		64
243de6a9c0SDavid du Colombier #define MAXCONFLINE	160
253de6a9c0SDavid du Colombier 
263de6a9c0SDavid du Colombier enum {
273de6a9c0SDavid du Colombier 	Minmem	= 256*MB,			/* conservative default */
2823a96966SDavid du Colombier 
2923a96966SDavid du Colombier 	/* space for syscall args, return PC, top-of-stack struct */
3023a96966SDavid du Colombier 	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
313de6a9c0SDavid du Colombier };
323de6a9c0SDavid du Colombier 
333de6a9c0SDavid du Colombier #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
343de6a9c0SDavid du Colombier 
353de6a9c0SDavid du Colombier extern char bdata[], edata[], end[], etext[];
363de6a9c0SDavid du Colombier 
373de6a9c0SDavid du Colombier uintptr kseg0 = KZERO;
383de6a9c0SDavid du Colombier Mach* machaddr[MAXMACH];
393de6a9c0SDavid du Colombier uchar *l2pages;
403de6a9c0SDavid du Colombier 
413de6a9c0SDavid du Colombier Memcache cachel[8];		/* arm arch v7 supports 1-7 */
423de6a9c0SDavid du Colombier /*
433de6a9c0SDavid du Colombier  * these are used by the cache.v7.s routines.
443de6a9c0SDavid du Colombier  */
453de6a9c0SDavid du Colombier Lowmemcache *cacheconf;
463de6a9c0SDavid du Colombier 
473de6a9c0SDavid du Colombier /*
483de6a9c0SDavid du Colombier  * Option arguments from the command line.
493de6a9c0SDavid du Colombier  * oargv[0] is the boot file.
503de6a9c0SDavid du Colombier  * Optionsinit() is called from multiboot()
513de6a9c0SDavid du Colombier  * or some other machine-dependent place
523de6a9c0SDavid du Colombier  * to set it all up.
533de6a9c0SDavid du Colombier  */
543de6a9c0SDavid du Colombier static int oargc;
553de6a9c0SDavid du Colombier static char* oargv[20];
563de6a9c0SDavid du Colombier static char oargb[128];
573de6a9c0SDavid du Colombier static int oargblen;
583de6a9c0SDavid du Colombier static char oenv[4096];
593de6a9c0SDavid du Colombier 
603de6a9c0SDavid du Colombier static uintptr sp;		/* XXX - must go - user stack of init proc */
613de6a9c0SDavid du Colombier 
623de6a9c0SDavid du Colombier int vflag;
633de6a9c0SDavid du Colombier int normalprint;
643de6a9c0SDavid du Colombier char debug[256];
653de6a9c0SDavid du Colombier 
663de6a9c0SDavid du Colombier static Lock testlock;
673de6a9c0SDavid du Colombier 
683de6a9c0SDavid du Colombier /* store plan9.ini contents here at least until we stash them in #ec */
693de6a9c0SDavid du Colombier static char confname[MAXCONF][KNAMELEN];
703de6a9c0SDavid du Colombier static char confval[MAXCONF][MAXCONFLINE];
713de6a9c0SDavid du Colombier static int nconf;
723de6a9c0SDavid du Colombier 
733de6a9c0SDavid du Colombier static int
findconf(char * name)743de6a9c0SDavid du Colombier findconf(char *name)
753de6a9c0SDavid du Colombier {
763de6a9c0SDavid du Colombier 	int i;
773de6a9c0SDavid du Colombier 
783de6a9c0SDavid du Colombier 	for(i = 0; i < nconf; i++)
793de6a9c0SDavid du Colombier 		if(cistrcmp(confname[i], name) == 0)
803de6a9c0SDavid du Colombier 			return i;
813de6a9c0SDavid du Colombier 	return -1;
823de6a9c0SDavid du Colombier }
833de6a9c0SDavid du Colombier 
843de6a9c0SDavid du Colombier char*
getconf(char * name)853de6a9c0SDavid du Colombier getconf(char *name)
863de6a9c0SDavid du Colombier {
873de6a9c0SDavid du Colombier 	int i;
883de6a9c0SDavid du Colombier 
893de6a9c0SDavid du Colombier 	i = findconf(name);
903de6a9c0SDavid du Colombier 	if(i >= 0)
913de6a9c0SDavid du Colombier 		return confval[i];
923de6a9c0SDavid du Colombier 	return nil;
933de6a9c0SDavid du Colombier }
943de6a9c0SDavid du Colombier 
953de6a9c0SDavid du Colombier void
addconf(char * name,char * val)963de6a9c0SDavid du Colombier addconf(char *name, char *val)
973de6a9c0SDavid du Colombier {
983de6a9c0SDavid du Colombier 	int i;
993de6a9c0SDavid du Colombier 
1003de6a9c0SDavid du Colombier 	i = findconf(name);
1013de6a9c0SDavid du Colombier 	if(i < 0){
1023de6a9c0SDavid du Colombier 		if(val == nil || nconf >= MAXCONF)
1033de6a9c0SDavid du Colombier 			return;
1043de6a9c0SDavid du Colombier 		i = nconf++;
1053de6a9c0SDavid du Colombier 		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
1063de6a9c0SDavid du Colombier 	}
1073de6a9c0SDavid du Colombier //	confval[i] = val;
1083de6a9c0SDavid du Colombier 	strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
1093de6a9c0SDavid du Colombier }
1103de6a9c0SDavid du Colombier 
1113de6a9c0SDavid du Colombier static void
writeconf(void)1123de6a9c0SDavid du Colombier writeconf(void)
1133de6a9c0SDavid du Colombier {
1143de6a9c0SDavid du Colombier 	char *p, *q;
1153de6a9c0SDavid du Colombier 	int n;
1163de6a9c0SDavid du Colombier 
1173de6a9c0SDavid du Colombier 	p = getconfenv();
1183de6a9c0SDavid du Colombier 
1193de6a9c0SDavid du Colombier 	if(waserror()) {
1203de6a9c0SDavid du Colombier 		free(p);
1213de6a9c0SDavid du Colombier 		nexterror();
1223de6a9c0SDavid du Colombier 	}
1233de6a9c0SDavid du Colombier 
1243de6a9c0SDavid du Colombier 	/* convert to name=value\n format */
1253de6a9c0SDavid du Colombier 	for(q=p; *q; q++) {
1263de6a9c0SDavid du Colombier 		q += strlen(q);
1273de6a9c0SDavid du Colombier 		*q = '=';
1283de6a9c0SDavid du Colombier 		q += strlen(q);
1293de6a9c0SDavid du Colombier 		*q = '\n';
1303de6a9c0SDavid du Colombier 	}
1313de6a9c0SDavid du Colombier 	n = q - p + 1;
1323de6a9c0SDavid du Colombier 	if(n >= BOOTARGSLEN)
1333de6a9c0SDavid du Colombier 		error("kernel configuration too large");
1343de6a9c0SDavid du Colombier 	memmove(BOOTARGS, p, n);
1353de6a9c0SDavid du Colombier 	memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
1363de6a9c0SDavid du Colombier 	poperror();
1373de6a9c0SDavid du Colombier 	free(p);
1383de6a9c0SDavid du Colombier }
1393de6a9c0SDavid du Colombier 
1403de6a9c0SDavid du Colombier /*
1413de6a9c0SDavid du Colombier  * assumes that we have loaded our /cfg/pxe/mac file at CONFADDR
1423de6a9c0SDavid du Colombier  * (usually 0x1000) with tftp in u-boot.  no longer uses malloc, so
1433de6a9c0SDavid du Colombier  * can be called early.
1443de6a9c0SDavid du Colombier  */
1453de6a9c0SDavid du Colombier static void
plan9iniinit(void)1463de6a9c0SDavid du Colombier plan9iniinit(void)
1473de6a9c0SDavid du Colombier {
1483de6a9c0SDavid du Colombier 	char *k, *v, *next;
1493de6a9c0SDavid du Colombier 
1503de6a9c0SDavid du Colombier 	k = (char *)CONFADDR;
1513de6a9c0SDavid du Colombier 	if(!isascii(*k))
1523de6a9c0SDavid du Colombier 		return;
1533de6a9c0SDavid du Colombier 
1543de6a9c0SDavid du Colombier 	for(; k && *k != '\0'; k = next) {
1553de6a9c0SDavid du Colombier 		if (!isascii(*k))		/* sanity check */
1563de6a9c0SDavid du Colombier 			break;
1573de6a9c0SDavid du Colombier 		next = strchr(k, '\n');
1583de6a9c0SDavid du Colombier 		if (next)
1593de6a9c0SDavid du Colombier 			*next++ = '\0';
1603de6a9c0SDavid du Colombier 
1613de6a9c0SDavid du Colombier 		if (*k == '\0' || *k == '\n' || *k == '#')
1623de6a9c0SDavid du Colombier 			continue;
1633de6a9c0SDavid du Colombier 		v = strchr(k, '=');
1643de6a9c0SDavid du Colombier 		if(v == nil)
1653de6a9c0SDavid du Colombier 			continue;		/* mal-formed line */
1663de6a9c0SDavid du Colombier 		*v++ = '\0';
1673de6a9c0SDavid du Colombier 
1683de6a9c0SDavid du Colombier 		addconf(k, v);
1693de6a9c0SDavid du Colombier 	}
1703de6a9c0SDavid du Colombier }
1713de6a9c0SDavid du Colombier 
1723de6a9c0SDavid du Colombier static void
optionsinit(char * s)1733de6a9c0SDavid du Colombier optionsinit(char* s)
1743de6a9c0SDavid du Colombier {
1753de6a9c0SDavid du Colombier 	char *o;
1763de6a9c0SDavid du Colombier 
1773de6a9c0SDavid du Colombier 	strcpy(oenv, "");
1783de6a9c0SDavid du Colombier 	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
1793de6a9c0SDavid du Colombier 	if(getenv("bootargs", o, o - oargb) != nil)
1803de6a9c0SDavid du Colombier 		*(o-1) = ' ';
1813de6a9c0SDavid du Colombier 
1823de6a9c0SDavid du Colombier 	oargblen = strlen(oargb);
1833de6a9c0SDavid du Colombier 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
1843de6a9c0SDavid du Colombier 	oargv[oargc] = nil;
1853de6a9c0SDavid du Colombier }
1863de6a9c0SDavid du Colombier 
1873de6a9c0SDavid du Colombier char*
getenv(char * name,char * buf,int n)1883de6a9c0SDavid du Colombier getenv(char* name, char* buf, int n)
1893de6a9c0SDavid du Colombier {
1903de6a9c0SDavid du Colombier 	char *e, *p, *q;
1913de6a9c0SDavid du Colombier 
1923de6a9c0SDavid du Colombier 	p = oenv;
1933de6a9c0SDavid du Colombier 	while(*p != 0){
1943de6a9c0SDavid du Colombier 		if((e = strchr(p, '=')) == nil)
1953de6a9c0SDavid du Colombier 			break;
1963de6a9c0SDavid du Colombier 		for(q = name; p < e; p++){
1973de6a9c0SDavid du Colombier 			if(*p != *q)
1983de6a9c0SDavid du Colombier 				break;
1993de6a9c0SDavid du Colombier 			q++;
2003de6a9c0SDavid du Colombier 		}
2013de6a9c0SDavid du Colombier 		if(p == e && *q == 0){
2023de6a9c0SDavid du Colombier 			strecpy(buf, buf+n, e+1);
2033de6a9c0SDavid du Colombier 			return buf;
2043de6a9c0SDavid du Colombier 		}
2053de6a9c0SDavid du Colombier 		p += strlen(p)+1;
2063de6a9c0SDavid du Colombier 	}
2073de6a9c0SDavid du Colombier 
2083de6a9c0SDavid du Colombier 	return nil;
2093de6a9c0SDavid du Colombier }
2103de6a9c0SDavid du Colombier 
2113de6a9c0SDavid du Colombier /* enable scheduling of this cpu */
2123de6a9c0SDavid du Colombier void
machon(uint cpu)2133de6a9c0SDavid du Colombier machon(uint cpu)
2143de6a9c0SDavid du Colombier {
2153de6a9c0SDavid du Colombier 	ulong cpubit;
2163de6a9c0SDavid du Colombier 
2173de6a9c0SDavid du Colombier 	cpubit = 1 << cpu;
2183de6a9c0SDavid du Colombier 	lock(&active);
2193de6a9c0SDavid du Colombier 	if ((active.machs & cpubit) == 0) {	/* currently off? */
2203de6a9c0SDavid du Colombier 		conf.nmach++;
2213de6a9c0SDavid du Colombier 		active.machs |= cpubit;
2223de6a9c0SDavid du Colombier 	}
2233de6a9c0SDavid du Colombier 	unlock(&active);
2243de6a9c0SDavid du Colombier }
2253de6a9c0SDavid du Colombier 
2263de6a9c0SDavid du Colombier /* disable scheduling of this cpu */
2273de6a9c0SDavid du Colombier void
machoff(uint cpu)2283de6a9c0SDavid du Colombier machoff(uint cpu)
2293de6a9c0SDavid du Colombier {
2303de6a9c0SDavid du Colombier 	ulong cpubit;
2313de6a9c0SDavid du Colombier 
2323de6a9c0SDavid du Colombier 	cpubit = 1 << cpu;
2333de6a9c0SDavid du Colombier 	lock(&active);
2343de6a9c0SDavid du Colombier 	if (active.machs & cpubit) {		/* currently on? */
2353de6a9c0SDavid du Colombier 		conf.nmach--;
2363de6a9c0SDavid du Colombier 		active.machs &= ~cpubit;
2373de6a9c0SDavid du Colombier 	}
2383de6a9c0SDavid du Colombier 	unlock(&active);
2393de6a9c0SDavid du Colombier }
2403de6a9c0SDavid du Colombier 
2413de6a9c0SDavid du Colombier void
machinit(void)2423de6a9c0SDavid du Colombier machinit(void)
2433de6a9c0SDavid du Colombier {
2443de6a9c0SDavid du Colombier 	Mach *m0;
2453de6a9c0SDavid du Colombier 
2463de6a9c0SDavid du Colombier 	if (m == 0) {
2473de6a9c0SDavid du Colombier 		serialputc('?');
2483de6a9c0SDavid du Colombier 		serialputc('m');
2493de6a9c0SDavid du Colombier 		serialputc('0');
2503de6a9c0SDavid du Colombier 	}
2513de6a9c0SDavid du Colombier 	if(machaddr[m->machno] != m) {
2523de6a9c0SDavid du Colombier 		serialputc('?');
2533de6a9c0SDavid du Colombier 		serialputc('m');
2543de6a9c0SDavid du Colombier 		serialputc('m');
2553de6a9c0SDavid du Colombier 	}
2563de6a9c0SDavid du Colombier 
2573de6a9c0SDavid du Colombier 	if (canlock(&testlock)) {
2583de6a9c0SDavid du Colombier 		serialputc('?');
2593de6a9c0SDavid du Colombier 		serialputc('l');
2603de6a9c0SDavid du Colombier 		panic("cpu%d: locks don't work", m->machno);
2613de6a9c0SDavid du Colombier 	}
2623de6a9c0SDavid du Colombier 
2633de6a9c0SDavid du Colombier 	m->ticks = 1;
2643de6a9c0SDavid du Colombier 	m->perf.period = 1;
2653de6a9c0SDavid du Colombier 	m0 = MACHP(0);
2663de6a9c0SDavid du Colombier 	if (m->machno != 0) {
2673de6a9c0SDavid du Colombier 		/* synchronise with cpu 0 */
2683de6a9c0SDavid du Colombier 		m->ticks = m0->ticks;
2693de6a9c0SDavid du Colombier 		m->fastclock = m0->fastclock;
2703de6a9c0SDavid du Colombier 		m->cpuhz = m0->cpuhz;
2713de6a9c0SDavid du Colombier 		m->delayloop = m0->delayloop;
2723de6a9c0SDavid du Colombier 	}
2733de6a9c0SDavid du Colombier 	if (m->machno != 0 &&
2743de6a9c0SDavid du Colombier 	    (m->fastclock == 0 || m->cpuhz == 0 || m->delayloop == 0))
2753de6a9c0SDavid du Colombier 		panic("buggered cpu 0 Mach");
2763de6a9c0SDavid du Colombier 
2773de6a9c0SDavid du Colombier 	machon(m->machno);
2783de6a9c0SDavid du Colombier 	fpoff();
2793de6a9c0SDavid du Colombier }
2803de6a9c0SDavid du Colombier 
2813de6a9c0SDavid du Colombier /* l.s has already zeroed Mach, which now contains our stack. */
2823de6a9c0SDavid du Colombier void
mach0init(void)2833de6a9c0SDavid du Colombier mach0init(void)
2843de6a9c0SDavid du Colombier {
2853de6a9c0SDavid du Colombier 	if (m == 0) {
2863de6a9c0SDavid du Colombier 		serialputc('?');
2873de6a9c0SDavid du Colombier 		serialputc('m');
2883de6a9c0SDavid du Colombier 	}
2893de6a9c0SDavid du Colombier 	conf.nmach = 0;
2903de6a9c0SDavid du Colombier 
2913de6a9c0SDavid du Colombier 	m->machno = 0;
2923de6a9c0SDavid du Colombier 	machaddr[0] = m;
2933de6a9c0SDavid du Colombier 
2943de6a9c0SDavid du Colombier 	lock(&testlock);		/* hold this forever */
2953de6a9c0SDavid du Colombier 	machinit();
2963de6a9c0SDavid du Colombier 
2973de6a9c0SDavid du Colombier 	active.exiting = 0;
2983de6a9c0SDavid du Colombier 	l1cache->wbse(&active, sizeof active);
2993de6a9c0SDavid du Colombier 	up = nil;
3003de6a9c0SDavid du Colombier }
3013de6a9c0SDavid du Colombier 
3023de6a9c0SDavid du Colombier /*
3033de6a9c0SDavid du Colombier  *  count CPU's, set up their mach structures and l1 ptes.
3043de6a9c0SDavid du Colombier  *  we're running on cpu 0 and our data structures were
3053de6a9c0SDavid du Colombier  *  statically allocated.
3063de6a9c0SDavid du Colombier  */
3073de6a9c0SDavid du Colombier void
launchinit(void)3083de6a9c0SDavid du Colombier launchinit(void)
3093de6a9c0SDavid du Colombier {
3103de6a9c0SDavid du Colombier 	int mach;
3113de6a9c0SDavid du Colombier 	Mach *mm;
3123de6a9c0SDavid du Colombier 	PTE *l1;
3133de6a9c0SDavid du Colombier 
3143de6a9c0SDavid du Colombier 	for(mach = 1; mach < MAXMACH; mach++){
3153de6a9c0SDavid du Colombier 		machaddr[mach] = mm = mallocalign(MACHSIZE, MACHSIZE, 0, 0);
3163de6a9c0SDavid du Colombier 		l1 = mallocalign(L1SIZE, L1SIZE, 0, 0);
3173de6a9c0SDavid du Colombier 		if(mm == nil || l1 == nil)
3183de6a9c0SDavid du Colombier 			panic("launchinit");
3193de6a9c0SDavid du Colombier 		memset(mm, 0, MACHSIZE);
3203de6a9c0SDavid du Colombier 		mm->machno = mach;
3213de6a9c0SDavid du Colombier 
3223de6a9c0SDavid du Colombier 		memmove(l1, (void *)L1, L1SIZE);  /* clone cpu0's l1 table */
3233de6a9c0SDavid du Colombier 		l1cache->wbse(l1, L1SIZE);
3243de6a9c0SDavid du Colombier 
3253de6a9c0SDavid du Colombier 		mm->mmul1 = l1;
3263de6a9c0SDavid du Colombier 		l1cache->wbse(mm, MACHSIZE);
3273de6a9c0SDavid du Colombier 	}
3283de6a9c0SDavid du Colombier 	l1cache->wbse(machaddr, sizeof machaddr);
3293de6a9c0SDavid du Colombier 	conf.nmach = 1;
3303de6a9c0SDavid du Colombier }
3313de6a9c0SDavid du Colombier 
3323de6a9c0SDavid du Colombier void
dump(void * vaddr,int words)3333de6a9c0SDavid du Colombier dump(void *vaddr, int words)
3343de6a9c0SDavid du Colombier {
3353de6a9c0SDavid du Colombier 	ulong *addr;
3363de6a9c0SDavid du Colombier 
3373de6a9c0SDavid du Colombier 	addr = vaddr;
3383de6a9c0SDavid du Colombier 	while (words-- > 0)
3393de6a9c0SDavid du Colombier 		iprint("%.8lux%c", *addr++, words % 8 == 0? '\n': ' ');
3403de6a9c0SDavid du Colombier }
3413de6a9c0SDavid du Colombier 
3423de6a9c0SDavid du Colombier static void
cacheinit(void)3433de6a9c0SDavid du Colombier cacheinit(void)
3443de6a9c0SDavid du Colombier {
3453de6a9c0SDavid du Colombier 	allcacheinfo(cachel);
3463de6a9c0SDavid du Colombier 	cacheconf = (Lowmemcache *)CACHECONF;
3473de6a9c0SDavid du Colombier 	cacheconf->l1waysh = cachel[1].waysh;
3483de6a9c0SDavid du Colombier 	cacheconf->l1setsh = cachel[1].setsh;
3493de6a9c0SDavid du Colombier 	/* on the tegra 2, l2 is unarchitected */
3503de6a9c0SDavid du Colombier 	cacheconf->l2waysh = cachel[2].waysh;
3513de6a9c0SDavid du Colombier 	cacheconf->l2setsh = cachel[2].setsh;
3523de6a9c0SDavid du Colombier 
3533de6a9c0SDavid du Colombier 	l2pl310init();
3543de6a9c0SDavid du Colombier 	allcacheson();
3553de6a9c0SDavid du Colombier 	allcache->wb();
3563de6a9c0SDavid du Colombier }
3573de6a9c0SDavid du Colombier 
3583de6a9c0SDavid du Colombier void
l2pageinit(void)3593de6a9c0SDavid du Colombier l2pageinit(void)
3603de6a9c0SDavid du Colombier {
3613de6a9c0SDavid du Colombier 	l2pages = KADDR(PHYSDRAM + DRAMSIZE - RESRVDHIMEM);
3623de6a9c0SDavid du Colombier }
3633de6a9c0SDavid du Colombier 
3643de6a9c0SDavid du Colombier /*
3653de6a9c0SDavid du Colombier  * at entry, l.s has set m for cpu0 and printed "Plan 9 from Be"
3663de6a9c0SDavid du Colombier  * but has not zeroed bss.
3673de6a9c0SDavid du Colombier  */
3683de6a9c0SDavid du Colombier void
main(void)3693de6a9c0SDavid du Colombier main(void)
3703de6a9c0SDavid du Colombier {
3713de6a9c0SDavid du Colombier 	int cpu;
3723de6a9c0SDavid du Colombier 	static ulong vfy = 0xcafebabe;
3733de6a9c0SDavid du Colombier 
3743de6a9c0SDavid du Colombier 	up = nil;
3753de6a9c0SDavid du Colombier 	if (vfy != 0xcafebabe) {
3763de6a9c0SDavid du Colombier 		serialputc('?');
3773de6a9c0SDavid du Colombier 		serialputc('d');
3783de6a9c0SDavid du Colombier 		panic("data segment misaligned");
3793de6a9c0SDavid du Colombier 	}
3803de6a9c0SDavid du Colombier 
3813de6a9c0SDavid du Colombier 	memset(edata, 0, end - edata);
3823de6a9c0SDavid du Colombier 
3833de6a9c0SDavid du Colombier 	/*
3843de6a9c0SDavid du Colombier 	 * we can't lock until smpon has run, but we're supposed to wait
3853de6a9c0SDavid du Colombier 	 * until l1 & l2 are on.  too bad.  l1 is on, l2 will soon be.
3863de6a9c0SDavid du Colombier 	 */
3873de6a9c0SDavid du Colombier 	smpon();
3883de6a9c0SDavid du Colombier 	iprint("ll Labs ");
3893de6a9c0SDavid du Colombier 	cacheinit();
3903de6a9c0SDavid du Colombier 
3913de6a9c0SDavid du Colombier 	/*
3923de6a9c0SDavid du Colombier 	 * data segment is aligned, bss is zeroed, caches' characteristics
3933de6a9c0SDavid du Colombier 	 * are known.  begin initialisation.
3943de6a9c0SDavid du Colombier 	 */
3953de6a9c0SDavid du Colombier 	mach0init();
3963de6a9c0SDavid du Colombier 	l2pageinit();
3973de6a9c0SDavid du Colombier 	mmuinit();
3983de6a9c0SDavid du Colombier 
3993de6a9c0SDavid du Colombier 	optionsinit("/boot/boot boot");
4003de6a9c0SDavid du Colombier 	quotefmtinstall();
4013de6a9c0SDavid du Colombier 
4023de6a9c0SDavid du Colombier 	/* want plan9.ini to be able to affect memory sizing in confinit */
4033de6a9c0SDavid du Colombier 	plan9iniinit();		/* before we step on plan9.ini in low memory */
4043de6a9c0SDavid du Colombier 
4053de6a9c0SDavid du Colombier 	/* l2 looks for *l2off= in plan9.ini */
4063de6a9c0SDavid du Colombier 	l2cache->on();		/* l2->on requires locks to work, thus smpon */
4073de6a9c0SDavid du Colombier 	l2cache->info(&cachel[2]);
4083de6a9c0SDavid du Colombier 	allcache->on();
4093de6a9c0SDavid du Colombier 
4103de6a9c0SDavid du Colombier 	cortexa9cachecfg();
4113de6a9c0SDavid du Colombier 
4123de6a9c0SDavid du Colombier 	trapinit();		/* so confinit can probe memory to size it */
4133de6a9c0SDavid du Colombier 	confinit();		/* figures out amount of memory */
4143de6a9c0SDavid du Colombier 	/* xinit prints (if it can), so finish up the banner here. */
4153de6a9c0SDavid du Colombier 	delay(100);
4163de6a9c0SDavid du Colombier 	navailcpus = getncpus();
4173de6a9c0SDavid du Colombier 	iprint("(mp arm; %d cpus)\n\n", navailcpus);
4183de6a9c0SDavid du Colombier 	delay(100);
4193de6a9c0SDavid du Colombier 
4203de6a9c0SDavid du Colombier 	for (cpu = 1; cpu < navailcpus; cpu++)
4213de6a9c0SDavid du Colombier 		stopcpu(cpu);
4223de6a9c0SDavid du Colombier 
4233de6a9c0SDavid du Colombier 	xinit();
4243de6a9c0SDavid du Colombier 	irqtooearly = 0;	/* now that xinit and trapinit have run */
4253de6a9c0SDavid du Colombier 
4263de6a9c0SDavid du Colombier 	mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
4273de6a9c0SDavid du Colombier 
4283de6a9c0SDavid du Colombier 	/*
4293de6a9c0SDavid du Colombier 	 * Printinit will cause the first malloc call.
4303de6a9c0SDavid du Colombier 	 * (printinit->qopen->malloc) unless any of the
4313de6a9c0SDavid du Colombier 	 * above (like clockinit) do an irqenable, which
4323de6a9c0SDavid du Colombier 	 * will call malloc.
4333de6a9c0SDavid du Colombier 	 * If the system dies here it's probably due
4343de6a9c0SDavid du Colombier 	 * to malloc(->xalloc) not being initialised
4353de6a9c0SDavid du Colombier 	 * correctly, or the data segment is misaligned
4363de6a9c0SDavid du Colombier 	 * (it's amazing how far you can get with
4373de6a9c0SDavid du Colombier 	 * things like that completely broken).
4383de6a9c0SDavid du Colombier 	 *
4393de6a9c0SDavid du Colombier 	 * (Should be) boilerplate from here on.
4403de6a9c0SDavid du Colombier 	 */
4413de6a9c0SDavid du Colombier 
4423de6a9c0SDavid du Colombier 	archreset();			/* cfg clock signals, print cache cfg */
4433de6a9c0SDavid du Colombier 	clockinit();			/* start clocks */
4443de6a9c0SDavid du Colombier 	timersinit();
4453de6a9c0SDavid du Colombier 
4463de6a9c0SDavid du Colombier 	delay(50);			/* let uart catch up */
4473de6a9c0SDavid du Colombier 	printinit();
4483de6a9c0SDavid du Colombier 	kbdenable();
4493de6a9c0SDavid du Colombier 
4503de6a9c0SDavid du Colombier 	cpuidprint();
4513de6a9c0SDavid du Colombier 	chkmissing();
4523de6a9c0SDavid du Colombier 
4533de6a9c0SDavid du Colombier 	procinit0();
4543de6a9c0SDavid du Colombier 	initseg();
4553de6a9c0SDavid du Colombier 
4563de6a9c0SDavid du Colombier //	dmainit();
4573de6a9c0SDavid du Colombier 	links();
4583de6a9c0SDavid du Colombier 	conf.monitor = 1;
4593de6a9c0SDavid du Colombier //	screeninit();
4603de6a9c0SDavid du Colombier 
4613de6a9c0SDavid du Colombier 	iprint("pcireset...");
4623de6a9c0SDavid du Colombier 	pcireset();			/* this tends to hang after a reboot */
4633de6a9c0SDavid du Colombier 	iprint("ok\n");
4643de6a9c0SDavid du Colombier 
4653de6a9c0SDavid du Colombier 	chandevreset();			/* most devices are discovered here */
4663de6a9c0SDavid du Colombier //	i8250console();			/* too early; see init0 */
4673de6a9c0SDavid du Colombier 
4683de6a9c0SDavid du Colombier 	pageinit();			/* prints "1020M memory: ⋯ */
4693de6a9c0SDavid du Colombier 	swapinit();
4703de6a9c0SDavid du Colombier 	userinit();
4713de6a9c0SDavid du Colombier 
4723de6a9c0SDavid du Colombier 	/*
4733de6a9c0SDavid du Colombier 	 * starting a cpu will eventually result in it calling schedinit,
4743de6a9c0SDavid du Colombier 	 * so everything necessary to run user processes should be set up
4753de6a9c0SDavid du Colombier 	 * before starting secondary cpus.
4763de6a9c0SDavid du Colombier 	 */
4773de6a9c0SDavid du Colombier 	launchinit();
4783de6a9c0SDavid du Colombier 	/* SMP & FW are already on when we get here; u-boot set them? */
4793de6a9c0SDavid du Colombier 	for (cpu = 1; cpu < navailcpus; cpu++)
4803de6a9c0SDavid du Colombier 		if (startcpu(cpu) < 0)
4813de6a9c0SDavid du Colombier 			panic("cpu%d didn't start", cpu);
4823de6a9c0SDavid du Colombier 	l1diag();
4833de6a9c0SDavid du Colombier 
4843de6a9c0SDavid du Colombier 	schedinit();
4853de6a9c0SDavid du Colombier 	panic("cpu%d: schedinit returned", m->machno);
4863de6a9c0SDavid du Colombier }
4873de6a9c0SDavid du Colombier 
4883de6a9c0SDavid du Colombier static void
shutdown(int ispanic)4893de6a9c0SDavid du Colombier shutdown(int ispanic)
4903de6a9c0SDavid du Colombier {
4913de6a9c0SDavid du Colombier 	int ms, once;
4923de6a9c0SDavid du Colombier 
4933de6a9c0SDavid du Colombier 	lock(&active);
4943de6a9c0SDavid du Colombier 	if(ispanic)
4953de6a9c0SDavid du Colombier 		active.ispanic = ispanic;
4963de6a9c0SDavid du Colombier 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
4973de6a9c0SDavid du Colombier 		active.ispanic = 0;
4983de6a9c0SDavid du Colombier 	once = active.machs & (1<<m->machno);
4993de6a9c0SDavid du Colombier 	/*
5003de6a9c0SDavid du Colombier 	 * setting exiting will make hzclock() on each processor call exit(0),
5013de6a9c0SDavid du Colombier 	 * which calls shutdown(0) and idles non-bootstrap cpus and returns
5023de6a9c0SDavid du Colombier 	 * on bootstrap processors (to permit a reboot).  clearing our bit
5033de6a9c0SDavid du Colombier 	 * in machs avoids calling exit(0) from hzclock() on this processor.
5043de6a9c0SDavid du Colombier 	 */
5053de6a9c0SDavid du Colombier 	active.machs &= ~(1<<m->machno);
5063de6a9c0SDavid du Colombier 	active.exiting = 1;
5073de6a9c0SDavid du Colombier 	unlock(&active);
5083de6a9c0SDavid du Colombier 
5093de6a9c0SDavid du Colombier 	if(once) {
5103de6a9c0SDavid du Colombier 		delay(m->machno*1000);		/* stagger them */
5113de6a9c0SDavid du Colombier 		iprint("cpu%d: exiting\n", m->machno);
5123de6a9c0SDavid du Colombier 	}
5133de6a9c0SDavid du Colombier 	spllo();
5143de6a9c0SDavid du Colombier 	if (m->machno == 0)
5153de6a9c0SDavid du Colombier 		ms = 5*1000;
5163de6a9c0SDavid du Colombier 	else
5173de6a9c0SDavid du Colombier 		ms = 2*1000;
5183de6a9c0SDavid du Colombier 	for(; ms > 0; ms -= TK2MS(2)){
5193de6a9c0SDavid du Colombier 		delay(TK2MS(2));
5203de6a9c0SDavid du Colombier 		if(active.machs == 0 && consactive() == 0)
5213de6a9c0SDavid du Colombier 			break;
5223de6a9c0SDavid du Colombier 	}
5233de6a9c0SDavid du Colombier 	delay(500);
5243de6a9c0SDavid du Colombier }
5253de6a9c0SDavid du Colombier 
5263de6a9c0SDavid du Colombier /*
5273de6a9c0SDavid du Colombier  *  exit kernel either on a panic or user request
5283de6a9c0SDavid du Colombier  */
5293de6a9c0SDavid du Colombier void
exit(int code)5303de6a9c0SDavid du Colombier exit(int code)
5313de6a9c0SDavid du Colombier {
5323de6a9c0SDavid du Colombier 	shutdown(code);
5333de6a9c0SDavid du Colombier 	splhi();
5343de6a9c0SDavid du Colombier 	if (m->machno == 0)
5353de6a9c0SDavid du Colombier 		archreboot();
5363de6a9c0SDavid du Colombier 	else {
5373de6a9c0SDavid du Colombier 		intrcpushutdown();
5383de6a9c0SDavid du Colombier 		stopcpu(m->machno);
5393de6a9c0SDavid du Colombier 		for (;;)
5403de6a9c0SDavid du Colombier 			idlehands();
5413de6a9c0SDavid du Colombier 	}
5423de6a9c0SDavid du Colombier }
5433de6a9c0SDavid du Colombier 
5443de6a9c0SDavid du Colombier int
isaconfig(char * class,int ctlrno,ISAConf * isa)5453de6a9c0SDavid du Colombier isaconfig(char *class, int ctlrno, ISAConf *isa)
5463de6a9c0SDavid du Colombier {
5473de6a9c0SDavid du Colombier 	char cc[32], *p;
5483de6a9c0SDavid du Colombier 	int i;
5493de6a9c0SDavid du Colombier 
5503de6a9c0SDavid du Colombier 	snprint(cc, sizeof cc, "%s%d", class, ctlrno);
5513de6a9c0SDavid du Colombier 	p = getconf(cc);
5523de6a9c0SDavid du Colombier 	if(p == nil)
5533de6a9c0SDavid du Colombier 		return 0;
5543de6a9c0SDavid du Colombier 
5553de6a9c0SDavid du Colombier 	isa->type = "";
5563de6a9c0SDavid du Colombier 	isa->nopt = tokenize(p, isa->opt, NISAOPT);
5573de6a9c0SDavid du Colombier 	for(i = 0; i < isa->nopt; i++){
5583de6a9c0SDavid du Colombier 		p = isa->opt[i];
5593de6a9c0SDavid du Colombier 		if(cistrncmp(p, "type=", 5) == 0)
5603de6a9c0SDavid du Colombier 			isa->type = p + 5;
5613de6a9c0SDavid du Colombier 		else if(cistrncmp(p, "port=", 5) == 0)
5623de6a9c0SDavid du Colombier 			isa->port = strtoul(p+5, &p, 0);
5633de6a9c0SDavid du Colombier 		else if(cistrncmp(p, "irq=", 4) == 0)
5643de6a9c0SDavid du Colombier 			isa->irq = strtoul(p+4, &p, 0);
5653de6a9c0SDavid du Colombier 		else if(cistrncmp(p, "dma=", 4) == 0)
5663de6a9c0SDavid du Colombier 			isa->dma = strtoul(p+4, &p, 0);
5673de6a9c0SDavid du Colombier 		else if(cistrncmp(p, "mem=", 4) == 0)
5683de6a9c0SDavid du Colombier 			isa->mem = strtoul(p+4, &p, 0);
5693de6a9c0SDavid du Colombier 		else if(cistrncmp(p, "size=", 5) == 0)
5703de6a9c0SDavid du Colombier 			isa->size = strtoul(p+5, &p, 0);
5713de6a9c0SDavid du Colombier 		else if(cistrncmp(p, "freq=", 5) == 0)
5723de6a9c0SDavid du Colombier 			isa->freq = strtoul(p+5, &p, 0);
5733de6a9c0SDavid du Colombier 	}
5743de6a9c0SDavid du Colombier 	return 1;
5753de6a9c0SDavid du Colombier }
5763de6a9c0SDavid du Colombier 
5773de6a9c0SDavid du Colombier /*
5783de6a9c0SDavid du Colombier  * the new kernel is already loaded at address `code'
5793de6a9c0SDavid du Colombier  * of size `size' and entry point `entry'.
5803de6a9c0SDavid du Colombier  */
5813de6a9c0SDavid du Colombier void
reboot(void * entry,void * code,ulong size)5823de6a9c0SDavid du Colombier reboot(void *entry, void *code, ulong size)
5833de6a9c0SDavid du Colombier {
5843de6a9c0SDavid du Colombier 	int cpu, nmach, want, ms;
5853de6a9c0SDavid du Colombier 	void (*f)(ulong, ulong, ulong);
5863de6a9c0SDavid du Colombier 
5873de6a9c0SDavid du Colombier 	nmach = conf.nmach;
5883de6a9c0SDavid du Colombier 	writeconf();
5893de6a9c0SDavid du Colombier 
5903de6a9c0SDavid du Colombier 	/*
5913de6a9c0SDavid du Colombier 	 * the boot processor is cpu0.  execute this function on it
5923de6a9c0SDavid du Colombier 	 * so that the new kernel has the same cpu0.
5933de6a9c0SDavid du Colombier 	 */
5943de6a9c0SDavid du Colombier 	if (m->machno != 0) {
5953de6a9c0SDavid du Colombier 		procwired(up, 0);
5963de6a9c0SDavid du Colombier 		sched();
5973de6a9c0SDavid du Colombier 	}
5983de6a9c0SDavid du Colombier 	if (m->machno != 0)
5993de6a9c0SDavid du Colombier 		print("on cpu%d (not 0)!\n", m->machno);
6003de6a9c0SDavid du Colombier 
6013de6a9c0SDavid du Colombier 	/*
6023de6a9c0SDavid du Colombier 	 * the other cpus could be holding locks that will never get
6033de6a9c0SDavid du Colombier 	 * released (e.g., in the print path) if we put them into
6043de6a9c0SDavid du Colombier 	 * reset now, so force them to shutdown gracefully first.
6053de6a9c0SDavid du Colombier 	 */
6063de6a9c0SDavid du Colombier 	for (want = 0, cpu = 1; cpu < navailcpus; cpu++)
6073de6a9c0SDavid du Colombier 		want |= 1 << cpu;
6083de6a9c0SDavid du Colombier 	active.stopped = 0;
6093de6a9c0SDavid du Colombier 	shutdown(0);
6103de6a9c0SDavid du Colombier 	for (ms = 15*1000; ms > 0 && active.stopped != want; ms -= 10)
6113de6a9c0SDavid du Colombier 		delay(10);
6123de6a9c0SDavid du Colombier 	delay(20);
6133de6a9c0SDavid du Colombier 	if (active.stopped != want) {
6143de6a9c0SDavid du Colombier 		for (cpu = 1; cpu < nmach; cpu++)
6153de6a9c0SDavid du Colombier 			stopcpu(cpu);		/* make really sure */
6163de6a9c0SDavid du Colombier 		delay(20);
6173de6a9c0SDavid du Colombier 	}
6183de6a9c0SDavid du Colombier 
6193de6a9c0SDavid du Colombier 	/*
6203de6a9c0SDavid du Colombier 	 * should be the only processor running now
6213de6a9c0SDavid du Colombier 	 */
6223de6a9c0SDavid du Colombier 	pcireset();
6233de6a9c0SDavid du Colombier //	print("reboot entry %#lux code %#lux size %ld\n",
6243de6a9c0SDavid du Colombier //		PADDR(entry), PADDR(code), size);
6253de6a9c0SDavid du Colombier 
6263de6a9c0SDavid du Colombier 	/* turn off buffered serial console */
6273de6a9c0SDavid du Colombier 	serialoq = nil;
6283de6a9c0SDavid du Colombier 	kprintoq = nil;
6293de6a9c0SDavid du Colombier 	screenputs = nil;
6303de6a9c0SDavid du Colombier 
6313de6a9c0SDavid du Colombier 	/* shutdown devices */
6323de6a9c0SDavid du Colombier 	chandevshutdown();
6333de6a9c0SDavid du Colombier 
6343de6a9c0SDavid du Colombier 	/* call off the dog */
6353de6a9c0SDavid du Colombier 	clockshutdown();
6363de6a9c0SDavid du Colombier 
6373de6a9c0SDavid du Colombier 	splhi();
6383de6a9c0SDavid du Colombier 	intrshutdown();
6393de6a9c0SDavid du Colombier 
6403de6a9c0SDavid du Colombier 	/* setup reboot trampoline function */
6413de6a9c0SDavid du Colombier 	f = (void*)REBOOTADDR;
6423de6a9c0SDavid du Colombier 	memmove(f, rebootcode, sizeof(rebootcode));
6433de6a9c0SDavid du Colombier 	cachedwb();
6443de6a9c0SDavid du Colombier 	l2cache->wbinv();
6453de6a9c0SDavid du Colombier 	l2cache->off();
6463de6a9c0SDavid du Colombier 	cacheuwbinv();
6473de6a9c0SDavid du Colombier 
6483de6a9c0SDavid du Colombier 	/* off we go - never to return */
6493de6a9c0SDavid du Colombier 	(*f)(PADDR(entry), PADDR(code), size);
6503de6a9c0SDavid du Colombier 
6513de6a9c0SDavid du Colombier 	iprint("loaded kernel returned!\n");
6523de6a9c0SDavid du Colombier 	archreboot();
6533de6a9c0SDavid du Colombier }
6543de6a9c0SDavid du Colombier 
6553de6a9c0SDavid du Colombier /*
6563de6a9c0SDavid du Colombier  *  starting place for first process
6573de6a9c0SDavid du Colombier  */
6583de6a9c0SDavid du Colombier void
init0(void)6593de6a9c0SDavid du Colombier init0(void)
6603de6a9c0SDavid du Colombier {
6613de6a9c0SDavid du Colombier 	int i;
6623de6a9c0SDavid du Colombier 	char buf[2*KNAMELEN];
6633de6a9c0SDavid du Colombier 
6643de6a9c0SDavid du Colombier 	up->nerrlab = 0;
6653de6a9c0SDavid du Colombier 	coherence();
6663de6a9c0SDavid du Colombier 	spllo();
6673de6a9c0SDavid du Colombier 
6683de6a9c0SDavid du Colombier 	/*
6693de6a9c0SDavid du Colombier 	 * These are o.k. because rootinit is null.
6703de6a9c0SDavid du Colombier 	 * Then early kproc's will have a root and dot.
6713de6a9c0SDavid du Colombier 	 */
6723de6a9c0SDavid du Colombier 	up->slash = namec("#/", Atodir, 0, 0);
6733de6a9c0SDavid du Colombier 	pathclose(up->slash->path);
6743de6a9c0SDavid du Colombier 	up->slash->path = newpath("/");
6753de6a9c0SDavid du Colombier 	up->dot = cclone(up->slash);
6763de6a9c0SDavid du Colombier 
6773de6a9c0SDavid du Colombier 	chandevinit();
6783de6a9c0SDavid du Colombier 	i8250console();		/* might be redundant, but harmless */
6793de6a9c0SDavid du Colombier 	if(kbdq == nil)
6803de6a9c0SDavid du Colombier 		panic("init0: nil kbdq");
6813de6a9c0SDavid du Colombier 	if(serialoq == nil)
6823de6a9c0SDavid du Colombier 		panic("init0: nil serialoq");
6833de6a9c0SDavid du Colombier 	normalprint = 1;
6843de6a9c0SDavid du Colombier 
6853de6a9c0SDavid du Colombier 	if(!waserror()){
6863de6a9c0SDavid du Colombier 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
6873de6a9c0SDavid du Colombier 		ksetenv("terminal", buf, 0);
6883de6a9c0SDavid du Colombier 		ksetenv("cputype", "arm", 0);
6893de6a9c0SDavid du Colombier 		if(cpuserver)
6903de6a9c0SDavid du Colombier 			ksetenv("service", "cpu", 0);
6913de6a9c0SDavid du Colombier 		else
6923de6a9c0SDavid du Colombier 			ksetenv("service", "terminal", 0);
6933de6a9c0SDavid du Colombier 
6943de6a9c0SDavid du Colombier 		/* convert plan9.ini variables to #e and #ec */
6953de6a9c0SDavid du Colombier 		for(i = 0; i < nconf; i++) {
6963de6a9c0SDavid du Colombier 			ksetenv(confname[i], confval[i], 0);
6973de6a9c0SDavid du Colombier 			ksetenv(confname[i], confval[i], 1);
6983de6a9c0SDavid du Colombier 		}
6993de6a9c0SDavid du Colombier 		poperror();
7003de6a9c0SDavid du Colombier 	}
7013de6a9c0SDavid du Colombier 	kproc("alarm", alarmkproc, 0);
7023de6a9c0SDavid du Colombier //	kproc("startcpusproc", startcpusproc, nil);
7033de6a9c0SDavid du Colombier 
7043de6a9c0SDavid du Colombier 	touser(sp);
7053de6a9c0SDavid du Colombier }
7063de6a9c0SDavid du Colombier 
7073de6a9c0SDavid du Colombier static void
bootargs(uintptr base)7083de6a9c0SDavid du Colombier bootargs(uintptr base)
7093de6a9c0SDavid du Colombier {
7103de6a9c0SDavid du Colombier 	int i;
7113de6a9c0SDavid du Colombier 	ulong ssize;
7123de6a9c0SDavid du Colombier 	char **av, *p;
7133de6a9c0SDavid du Colombier 
7143de6a9c0SDavid du Colombier 	/*
7153de6a9c0SDavid du Colombier 	 * Push the boot args onto the stack.
7163de6a9c0SDavid du Colombier 	 * The initial value of the user stack must be such
7173de6a9c0SDavid du Colombier 	 * that the total used is larger than the maximum size
7183de6a9c0SDavid du Colombier 	 * of the argument list checked in syscall.
7193de6a9c0SDavid du Colombier 	 */
7203de6a9c0SDavid du Colombier 	i = oargblen+1;
721*5c88beaeSDavid du Colombier 	p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
7223de6a9c0SDavid du Colombier 	memmove(p, oargb, i);
7233de6a9c0SDavid du Colombier 
7243de6a9c0SDavid du Colombier 	/*
7253de6a9c0SDavid du Colombier 	 * Now push argc and the argv pointers.
7263de6a9c0SDavid du Colombier 	 * This isn't strictly correct as the code jumped to by
7273de6a9c0SDavid du Colombier 	 * touser in init9.s calls startboot (port/initcode.c) which
7283de6a9c0SDavid du Colombier 	 * expects arguments
7293de6a9c0SDavid du Colombier 	 * 	startboot(char *argv0, char **argv)
7303de6a9c0SDavid du Colombier 	 * not the usual (int argc, char* argv[]), but argv0 is
7313de6a9c0SDavid du Colombier 	 * unused so it doesn't matter (at the moment...).
7323de6a9c0SDavid du Colombier 	 */
7333de6a9c0SDavid du Colombier 	av = (char**)(p - (oargc+2)*sizeof(char*));
7343de6a9c0SDavid du Colombier 	ssize = base + BY2PG - PTR2UINT(av);
7353de6a9c0SDavid du Colombier 	*av++ = (char*)oargc;
7363de6a9c0SDavid du Colombier 	for(i = 0; i < oargc; i++)
7373de6a9c0SDavid du Colombier 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
7383de6a9c0SDavid du Colombier 	*av = nil;
7393de6a9c0SDavid du Colombier 
7403de6a9c0SDavid du Colombier 	/*
7413de6a9c0SDavid du Colombier 	 * Leave space for the return PC of the
7423de6a9c0SDavid du Colombier 	 * caller of initcode.
7433de6a9c0SDavid du Colombier 	 */
7443de6a9c0SDavid du Colombier 	sp = USTKTOP - ssize - sizeof(void*);
7453de6a9c0SDavid du Colombier }
7463de6a9c0SDavid du Colombier 
7473de6a9c0SDavid du Colombier /*
7483de6a9c0SDavid du Colombier  *  create the first process
7493de6a9c0SDavid du Colombier  */
7503de6a9c0SDavid du Colombier void
userinit(void)7513de6a9c0SDavid du Colombier userinit(void)
7523de6a9c0SDavid du Colombier {
7533de6a9c0SDavid du Colombier 	Proc *p;
7543de6a9c0SDavid du Colombier 	Segment *s;
7553de6a9c0SDavid du Colombier 	KMap *k;
7563de6a9c0SDavid du Colombier 	Page *pg;
7573de6a9c0SDavid du Colombier 
7583de6a9c0SDavid du Colombier 	/* no processes yet */
7593de6a9c0SDavid du Colombier 	up = nil;
7603de6a9c0SDavid du Colombier 
7613de6a9c0SDavid du Colombier 	p = newproc();
7623de6a9c0SDavid du Colombier 	p->pgrp = newpgrp();
7633de6a9c0SDavid du Colombier 	p->egrp = smalloc(sizeof(Egrp));
7643de6a9c0SDavid du Colombier 	p->egrp->ref = 1;
7653de6a9c0SDavid du Colombier 	p->fgrp = dupfgrp(nil);
7663de6a9c0SDavid du Colombier 	p->rgrp = newrgrp();
7673de6a9c0SDavid du Colombier 	p->procmode = 0640;
7683de6a9c0SDavid du Colombier 
7693de6a9c0SDavid du Colombier 	kstrdup(&eve, "");
7703de6a9c0SDavid du Colombier 	kstrdup(&p->text, "*init*");
7713de6a9c0SDavid du Colombier 	kstrdup(&p->user, eve);
7723de6a9c0SDavid du Colombier 
7733de6a9c0SDavid du Colombier 	/*
7743de6a9c0SDavid du Colombier 	 * Kernel Stack
7753de6a9c0SDavid du Colombier 	 */
7763de6a9c0SDavid du Colombier 	p->sched.pc = PTR2UINT(init0);
7773de6a9c0SDavid du Colombier 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
7783de6a9c0SDavid du Colombier 	p->sched.sp = STACKALIGN(p->sched.sp);
7793de6a9c0SDavid du Colombier 
7803de6a9c0SDavid du Colombier 	/*
7813de6a9c0SDavid du Colombier 	 * User Stack
7823de6a9c0SDavid du Colombier 	 *
7833de6a9c0SDavid du Colombier 	 * Technically, newpage can't be called here because it
7843de6a9c0SDavid du Colombier 	 * should only be called when in a user context as it may
7853de6a9c0SDavid du Colombier 	 * try to sleep if there are no pages available, but that
7863de6a9c0SDavid du Colombier 	 * shouldn't be the case here.
7873de6a9c0SDavid du Colombier 	 */
7883de6a9c0SDavid du Colombier 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
7893de6a9c0SDavid du Colombier 	s->flushme++;
7903de6a9c0SDavid du Colombier 	p->seg[SSEG] = s;
7913de6a9c0SDavid du Colombier 	pg = newpage(1, 0, USTKTOP-BY2PG);
7923de6a9c0SDavid du Colombier 	segpage(s, pg);
7933de6a9c0SDavid du Colombier 	k = kmap(pg);
7943de6a9c0SDavid du Colombier 	bootargs(VA(k));
7953de6a9c0SDavid du Colombier 	kunmap(k);
7963de6a9c0SDavid du Colombier 
7973de6a9c0SDavid du Colombier 	/*
7983de6a9c0SDavid du Colombier 	 * Text
7993de6a9c0SDavid du Colombier 	 */
8003de6a9c0SDavid du Colombier 	s = newseg(SG_TEXT, UTZERO, 1);
8013de6a9c0SDavid du Colombier 	p->seg[TSEG] = s;
8023de6a9c0SDavid du Colombier 	pg = newpage(1, 0, UTZERO);
8033de6a9c0SDavid du Colombier 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
8043de6a9c0SDavid du Colombier 	segpage(s, pg);
8053de6a9c0SDavid du Colombier 	k = kmap(s->map[0]->pages[0]);
8063de6a9c0SDavid du Colombier 	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
8073de6a9c0SDavid du Colombier 	kunmap(k);
8083de6a9c0SDavid du Colombier 
8093de6a9c0SDavid du Colombier 	ready(p);
8103de6a9c0SDavid du Colombier }
8113de6a9c0SDavid du Colombier 
8123de6a9c0SDavid du Colombier Conf conf;			/* XXX - must go - gag */
8133de6a9c0SDavid du Colombier 
8143de6a9c0SDavid du Colombier Confmem tsmem[nelem(conf.mem)] = {
8153de6a9c0SDavid du Colombier 	/*
8163de6a9c0SDavid du Colombier 	 * Memory available to Plan 9:
8173de6a9c0SDavid du Colombier 	 */
8183de6a9c0SDavid du Colombier 	{ .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
8193de6a9c0SDavid du Colombier };
8203de6a9c0SDavid du Colombier ulong memsize = DRAMSIZE;
8213de6a9c0SDavid du Colombier 
8223de6a9c0SDavid du Colombier static int
gotmem(uintptr sz)8233de6a9c0SDavid du Colombier gotmem(uintptr sz)
8243de6a9c0SDavid du Colombier {
8253de6a9c0SDavid du Colombier 	uintptr addr;
8263de6a9c0SDavid du Colombier 
8273de6a9c0SDavid du Colombier 	/* back off a little from the end */
8283de6a9c0SDavid du Colombier 	addr = (uintptr)KADDR(PHYSDRAM + sz - BY2WD);
8293de6a9c0SDavid du Colombier 	if (probeaddr(addr) >= 0) {	/* didn't trap? memory present */
8303de6a9c0SDavid du Colombier 		memsize = sz;
8313de6a9c0SDavid du Colombier 		return 0;
8323de6a9c0SDavid du Colombier 	}
8333de6a9c0SDavid du Colombier 	return -1;
8343de6a9c0SDavid du Colombier }
8353de6a9c0SDavid du Colombier 
8363de6a9c0SDavid du Colombier void
confinit(void)8373de6a9c0SDavid du Colombier confinit(void)
8383de6a9c0SDavid du Colombier {
8393de6a9c0SDavid du Colombier 	int i;
8403de6a9c0SDavid du Colombier 	ulong kpages;
8413de6a9c0SDavid du Colombier 	uintptr pa;
8423de6a9c0SDavid du Colombier 	char *p;
8433de6a9c0SDavid du Colombier 
8443de6a9c0SDavid du Colombier 	/*
8453de6a9c0SDavid du Colombier 	 * Copy the physical memory configuration to Conf.mem.
8463de6a9c0SDavid du Colombier 	 */
8473de6a9c0SDavid du Colombier 	if(nelem(tsmem) > nelem(conf.mem)){
8483de6a9c0SDavid du Colombier 		iprint("memory configuration botch\n");
8493de6a9c0SDavid du Colombier 		exit(1);
8503de6a9c0SDavid du Colombier 	}
8513de6a9c0SDavid du Colombier 	if(0 && (p = getconf("*maxmem")) != nil) {
8523de6a9c0SDavid du Colombier 		memsize = strtoul(p, 0, 0) - PHYSDRAM;
8533de6a9c0SDavid du Colombier 		if (memsize < 16*MB)		/* sanity */
8543de6a9c0SDavid du Colombier 			memsize = 16*MB;
8553de6a9c0SDavid du Colombier 	}
8563de6a9c0SDavid du Colombier 
8573de6a9c0SDavid du Colombier 	/*
8583de6a9c0SDavid du Colombier 	 * see if all that memory exists; if not, find out how much does.
8593de6a9c0SDavid du Colombier 	 * trapinit must have been called first.
8603de6a9c0SDavid du Colombier 	 */
8613de6a9c0SDavid du Colombier 	if (gotmem(memsize - RESRVDHIMEM) < 0)
8623de6a9c0SDavid du Colombier 		panic("can't find 1GB of memory");
8633de6a9c0SDavid du Colombier 
8643de6a9c0SDavid du Colombier 	tsmem[0].limit = PHYSDRAM + memsize;
8653de6a9c0SDavid du Colombier 	memmove(conf.mem, tsmem, sizeof(tsmem));
8663de6a9c0SDavid du Colombier 
8673de6a9c0SDavid du Colombier 	conf.npage = 0;
8683de6a9c0SDavid du Colombier 	pa = PADDR(PGROUND(PTR2UINT(end)));
8693de6a9c0SDavid du Colombier 
8703de6a9c0SDavid du Colombier 	/*
8713de6a9c0SDavid du Colombier 	 *  we assume that the kernel is at the beginning of one of the
8723de6a9c0SDavid du Colombier 	 *  contiguous chunks of memory and fits therein.
8733de6a9c0SDavid du Colombier 	 */
8743de6a9c0SDavid du Colombier 	for(i=0; i<nelem(conf.mem); i++){
8753de6a9c0SDavid du Colombier 		/* take kernel out of allocatable space */
8763de6a9c0SDavid du Colombier 		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
8773de6a9c0SDavid du Colombier 			conf.mem[i].base = pa;
8783de6a9c0SDavid du Colombier 
8793de6a9c0SDavid du Colombier 		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
8803de6a9c0SDavid du Colombier 		conf.npage += conf.mem[i].npage;
8813de6a9c0SDavid du Colombier 	}
8823de6a9c0SDavid du Colombier 
8833de6a9c0SDavid du Colombier 	conf.upages = (conf.npage*80)/100;
8843de6a9c0SDavid du Colombier 	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
8853de6a9c0SDavid du Colombier 
8863de6a9c0SDavid du Colombier 	/* set up other configuration parameters */
8873de6a9c0SDavid du Colombier 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
8883de6a9c0SDavid du Colombier 	if(cpuserver)
8893de6a9c0SDavid du Colombier 		conf.nproc *= 3;
8903de6a9c0SDavid du Colombier 	if(conf.nproc > 2000)
8913de6a9c0SDavid du Colombier 		conf.nproc = 2000;
8923de6a9c0SDavid du Colombier 	conf.nswap = conf.npage*3;
8933de6a9c0SDavid du Colombier 	conf.nswppo = 4096;
8943de6a9c0SDavid du Colombier 	conf.nimage = 200;
8953de6a9c0SDavid du Colombier 
8963de6a9c0SDavid du Colombier 	/*
8973de6a9c0SDavid du Colombier 	 * it's simpler on mp systems to take page-faults early,
8983de6a9c0SDavid du Colombier 	 * on reference, rather than later, on write, which might
8993de6a9c0SDavid du Colombier 	 * require tlb shootdowns.
9003de6a9c0SDavid du Colombier 	 */
9013de6a9c0SDavid du Colombier 	conf.copymode = 1;		/* copy on reference */
9023de6a9c0SDavid du Colombier 
9033de6a9c0SDavid du Colombier 	/*
9043de6a9c0SDavid du Colombier 	 * Guess how much is taken by the large permanent
9053de6a9c0SDavid du Colombier 	 * datastructures. Mntcache and Mntrpc are not accounted for
9063de6a9c0SDavid du Colombier 	 * (probably ~300KB).
9073de6a9c0SDavid du Colombier 	 */
9083de6a9c0SDavid du Colombier 	kpages = conf.npage - conf.upages;
9093de6a9c0SDavid du Colombier 	kpages *= BY2PG;
9103de6a9c0SDavid du Colombier 	kpages -= conf.upages*sizeof(Page)
9113de6a9c0SDavid du Colombier 		+ conf.nproc*sizeof(Proc)
9123de6a9c0SDavid du Colombier 		+ conf.nimage*sizeof(Image)
9133de6a9c0SDavid du Colombier 		+ conf.nswap
9143de6a9c0SDavid du Colombier 		+ conf.nswppo*sizeof(Page);
9153de6a9c0SDavid du Colombier 	mainmem->maxsize = kpages;
9163de6a9c0SDavid du Colombier 	if(!cpuserver)
9173de6a9c0SDavid du Colombier 		/*
9183de6a9c0SDavid du Colombier 		 * give terminals lots of image memory, too; the dynamic
9193de6a9c0SDavid du Colombier 		 * allocation will balance the load properly, hopefully.
9203de6a9c0SDavid du Colombier 		 * be careful with 32-bit overflow.
9213de6a9c0SDavid du Colombier 		 */
9223de6a9c0SDavid du Colombier 		imagmem->maxsize = kpages;
9233de6a9c0SDavid du Colombier 
9243de6a9c0SDavid du Colombier //	archconfinit();
9253de6a9c0SDavid du Colombier }
9263de6a9c0SDavid du Colombier 
9273de6a9c0SDavid du Colombier int
cmpswap(long * addr,long old,long new)9283de6a9c0SDavid du Colombier cmpswap(long *addr, long old, long new)
9293de6a9c0SDavid du Colombier {
9303de6a9c0SDavid du Colombier 	return cas((int *)addr, old, new);
9313de6a9c0SDavid du Colombier }
9323de6a9c0SDavid du Colombier 
9333de6a9c0SDavid du Colombier void
advertwfi(void)9343de6a9c0SDavid du Colombier advertwfi(void)			/* advertise my wfi status */
9353de6a9c0SDavid du Colombier {
9363de6a9c0SDavid du Colombier 	ilock(&active);
9373de6a9c0SDavid du Colombier 	active.wfi |= 1 << m->machno;
9383de6a9c0SDavid du Colombier 	iunlock(&active);
9393de6a9c0SDavid du Colombier }
9403de6a9c0SDavid du Colombier 
9413de6a9c0SDavid du Colombier void
unadvertwfi(void)9423de6a9c0SDavid du Colombier unadvertwfi(void)		/* do not advertise my wfi status */
9433de6a9c0SDavid du Colombier {
9443de6a9c0SDavid du Colombier 	ilock(&active);
9453de6a9c0SDavid du Colombier 	active.wfi &= ~(1 << m->machno);
9463de6a9c0SDavid du Colombier 	iunlock(&active);
9473de6a9c0SDavid du Colombier }
9483de6a9c0SDavid du Colombier 
9493de6a9c0SDavid du Colombier void
idlehands(void)9503de6a9c0SDavid du Colombier idlehands(void)
9513de6a9c0SDavid du Colombier {
9523de6a9c0SDavid du Colombier #ifdef use_ipi
9533de6a9c0SDavid du Colombier 	int advertised;
9543de6a9c0SDavid du Colombier 
9553de6a9c0SDavid du Colombier 	/* don't go into wfi until my local timer is ticking */
9563de6a9c0SDavid du Colombier 	if (m->ticks <= 1)
9573de6a9c0SDavid du Colombier 		return;
9583de6a9c0SDavid du Colombier 
9593de6a9c0SDavid du Colombier 	advertised = 0;
9603de6a9c0SDavid du Colombier 	m->inidlehands++;
9613de6a9c0SDavid du Colombier 	/* avoid recursion via ilock, advertise iff this cpu is initialised */
9623de6a9c0SDavid du Colombier 	if (m->inidlehands == 1 && m->syscall > 0) {
9633de6a9c0SDavid du Colombier 		advertwfi();
9643de6a9c0SDavid du Colombier 		advertised = 1;
9653de6a9c0SDavid du Colombier 	}
9663de6a9c0SDavid du Colombier 
9673de6a9c0SDavid du Colombier 	wfi();
9683de6a9c0SDavid du Colombier 
9693de6a9c0SDavid du Colombier 	if (advertised)
9703de6a9c0SDavid du Colombier 		unadvertwfi();
9713de6a9c0SDavid du Colombier 	m->inidlehands--;
9723de6a9c0SDavid du Colombier #endif
9733de6a9c0SDavid du Colombier }
9743de6a9c0SDavid du Colombier 
9753de6a9c0SDavid du Colombier void
wakewfi(void)9763de6a9c0SDavid du Colombier wakewfi(void)
9773de6a9c0SDavid du Colombier {
9783de6a9c0SDavid du Colombier #ifdef use_ipi
9793de6a9c0SDavid du Colombier 	uint cpu;
9803de6a9c0SDavid du Colombier 
9813de6a9c0SDavid du Colombier 	/*
9823de6a9c0SDavid du Colombier 	 * find any cpu other than me currently in wfi.
9833de6a9c0SDavid du Colombier 	 * need not be exact.
9843de6a9c0SDavid du Colombier 	 */
9853de6a9c0SDavid du Colombier 	cpu = BI2BY*BY2WD - 1 - clz(active.wfi & ~(1 << m->machno));
9863de6a9c0SDavid du Colombier 	if (cpu < MAXMACH)
9873de6a9c0SDavid du Colombier 		intrcpu(cpu);
9883de6a9c0SDavid du Colombier #endif
9893de6a9c0SDavid du Colombier }
990