xref: /plan9/sys/src/9/kw/main.c (revision 23a969667fc2f16f64e45b0a4135d6dd31daef7a)
1154abd99SDavid du Colombier #include "u.h"
2154abd99SDavid du Colombier #include "../port/lib.h"
3154abd99SDavid du Colombier #include "mem.h"
4154abd99SDavid du Colombier #include "dat.h"
5154abd99SDavid du Colombier #include "fns.h"
6154abd99SDavid du Colombier 
7154abd99SDavid du Colombier #include "init.h"
8154abd99SDavid du Colombier #include "arm.h"
9154abd99SDavid du Colombier #include <pool.h>
10*23a96966SDavid du Colombier #include <tos.h>
11154abd99SDavid du Colombier 
12154abd99SDavid du Colombier #include "reboot.h"
13154abd99SDavid du Colombier 
14b72bcbbfSDavid du Colombier /*
15b72bcbbfSDavid du Colombier  * Where configuration info is left for the loaded programme.
16b72bcbbfSDavid du Colombier  * This will turn into a structure as more is done by the boot loader
17b72bcbbfSDavid du Colombier  * (e.g. why parse the .ini file twice?).
18b72bcbbfSDavid du Colombier  * There are 3584 bytes available at CONFADDR.
19b72bcbbfSDavid du Colombier  */
20b72bcbbfSDavid du Colombier #define BOOTARGS	((char*)CONFADDR)
21b72bcbbfSDavid du Colombier #define	BOOTARGSLEN	(16*KiB)		/* limit in devenv.c */
22ab6ce076SDavid du Colombier #define	MAXCONF		64
232a6809cbSDavid du Colombier #define MAXCONFLINE	160
24ab6ce076SDavid du Colombier 
25b649930dSDavid du Colombier enum {
26b649930dSDavid du Colombier 	Maxmem	= 512*MB,			/* limited by address ranges */
27b649930dSDavid du Colombier 	Minmem	= 256*MB,			/* conservative default */
28*23a96966SDavid du Colombier 
29*23a96966SDavid du Colombier 	/* space for syscall args, return PC, top-of-stack struct */
30*23a96966SDavid du Colombier 	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
31b649930dSDavid du Colombier };
32b649930dSDavid du Colombier 
33b72bcbbfSDavid du Colombier #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
34b72bcbbfSDavid du Colombier 
35154abd99SDavid du Colombier uintptr kseg0 = KZERO;
36154abd99SDavid du Colombier Mach* machaddr[MAXMACH];
37154abd99SDavid du Colombier 
38154abd99SDavid du Colombier /*
39154abd99SDavid du Colombier  * Option arguments from the command line.
40154abd99SDavid du Colombier  * oargv[0] is the boot file.
41154abd99SDavid du Colombier  * Optionsinit() is called from multiboot()
42154abd99SDavid du Colombier  * or some other machine-dependent place
43154abd99SDavid du Colombier  * to set it all up.
44154abd99SDavid du Colombier  */
45154abd99SDavid du Colombier static int oargc;
46154abd99SDavid du Colombier static char* oargv[20];
47154abd99SDavid du Colombier static char oargb[128];
48154abd99SDavid du Colombier static int oargblen;
49154abd99SDavid du Colombier static char oenv[4096];
50154abd99SDavid du Colombier 
51154abd99SDavid du Colombier static uintptr sp;		/* XXX - must go - user stack of init proc */
52154abd99SDavid du Colombier 
53154abd99SDavid du Colombier int vflag;
54154abd99SDavid du Colombier char debug[256];
55154abd99SDavid du Colombier 
56b72bcbbfSDavid du Colombier /* store plan9.ini contents here at least until we stash them in #ec */
57ab6ce076SDavid du Colombier static char confname[MAXCONF][KNAMELEN];
582a6809cbSDavid du Colombier static char confval[MAXCONF][MAXCONFLINE];
59ab6ce076SDavid du Colombier static int nconf;
60ab6ce076SDavid du Colombier 
61047f1f95SDavid du Colombier #ifdef CRYPTOSANDBOX
62047f1f95SDavid du Colombier uchar sandbox[64*1024+BY2PG];
63047f1f95SDavid du Colombier #endif
64047f1f95SDavid du Colombier 
65b72bcbbfSDavid du Colombier static int
findconf(char * name)66b72bcbbfSDavid du Colombier findconf(char *name)
67b72bcbbfSDavid du Colombier {
68b72bcbbfSDavid du Colombier 	int i;
69b72bcbbfSDavid du Colombier 
70b72bcbbfSDavid du Colombier 	for(i = 0; i < nconf; i++)
71b72bcbbfSDavid du Colombier 		if(cistrcmp(confname[i], name) == 0)
72b72bcbbfSDavid du Colombier 			return i;
73b72bcbbfSDavid du Colombier 	return -1;
74b72bcbbfSDavid du Colombier }
75b72bcbbfSDavid du Colombier 
76b72bcbbfSDavid du Colombier char*
getconf(char * name)77b72bcbbfSDavid du Colombier getconf(char *name)
78b72bcbbfSDavid du Colombier {
79b72bcbbfSDavid du Colombier 	int i;
80b72bcbbfSDavid du Colombier 
81b72bcbbfSDavid du Colombier 	i = findconf(name);
82b72bcbbfSDavid du Colombier 	if(i >= 0)
83b72bcbbfSDavid du Colombier 		return confval[i];
84b72bcbbfSDavid du Colombier 	return nil;
85b72bcbbfSDavid du Colombier }
86b72bcbbfSDavid du Colombier 
87b72bcbbfSDavid du Colombier void
addconf(char * name,char * val)88b72bcbbfSDavid du Colombier addconf(char *name, char *val)
89b72bcbbfSDavid du Colombier {
90b72bcbbfSDavid du Colombier 	int i;
91b72bcbbfSDavid du Colombier 
92b72bcbbfSDavid du Colombier 	i = findconf(name);
93b72bcbbfSDavid du Colombier 	if(i < 0){
94b72bcbbfSDavid du Colombier 		if(val == nil || nconf >= MAXCONF)
95b72bcbbfSDavid du Colombier 			return;
96b72bcbbfSDavid du Colombier 		i = nconf++;
97b72bcbbfSDavid du Colombier 		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
98b72bcbbfSDavid du Colombier 	}
992a6809cbSDavid du Colombier //	confval[i] = val;
1002a6809cbSDavid du Colombier 	strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
101b72bcbbfSDavid du Colombier }
102b72bcbbfSDavid du Colombier 
103b72bcbbfSDavid du Colombier static void
writeconf(void)104b72bcbbfSDavid du Colombier writeconf(void)
105b72bcbbfSDavid du Colombier {
106b72bcbbfSDavid du Colombier 	char *p, *q;
107b72bcbbfSDavid du Colombier 	int n;
108b72bcbbfSDavid du Colombier 
109b72bcbbfSDavid du Colombier 	p = getconfenv();
110b72bcbbfSDavid du Colombier 
111b72bcbbfSDavid du Colombier 	if(waserror()) {
112b72bcbbfSDavid du Colombier 		free(p);
113b72bcbbfSDavid du Colombier 		nexterror();
114b72bcbbfSDavid du Colombier 	}
115b72bcbbfSDavid du Colombier 
116b72bcbbfSDavid du Colombier 	/* convert to name=value\n format */
117b72bcbbfSDavid du Colombier 	for(q=p; *q; q++) {
118b72bcbbfSDavid du Colombier 		q += strlen(q);
119b72bcbbfSDavid du Colombier 		*q = '=';
120b72bcbbfSDavid du Colombier 		q += strlen(q);
121b72bcbbfSDavid du Colombier 		*q = '\n';
122b72bcbbfSDavid du Colombier 	}
123b72bcbbfSDavid du Colombier 	n = q - p + 1;
124b72bcbbfSDavid du Colombier 	if(n >= BOOTARGSLEN)
125b72bcbbfSDavid du Colombier 		error("kernel configuration too large");
126b72bcbbfSDavid du Colombier 	memmove(BOOTARGS, p, n);
127b72bcbbfSDavid du Colombier 	poperror();
128b72bcbbfSDavid du Colombier 	free(p);
129b72bcbbfSDavid du Colombier }
130b72bcbbfSDavid du Colombier 
131b72bcbbfSDavid du Colombier /*
132b72bcbbfSDavid du Colombier  * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
1332a6809cbSDavid du Colombier  * tftp in u-boot.  no longer uses malloc, so can be called early.
134b72bcbbfSDavid du Colombier  */
135b72bcbbfSDavid du Colombier static void
plan9iniinit(void)136b72bcbbfSDavid du Colombier plan9iniinit(void)
137b72bcbbfSDavid du Colombier {
138b72bcbbfSDavid du Colombier 	char *k, *v, *next;
139b72bcbbfSDavid du Colombier 
140b72bcbbfSDavid du Colombier 	k = (char *)CONFADDR;
141b72bcbbfSDavid du Colombier 	if(!isascii(*k))
142b72bcbbfSDavid du Colombier 		return;
143b72bcbbfSDavid du Colombier 
144b72bcbbfSDavid du Colombier 	for(; k && *k != '\0'; k = next) {
145b72bcbbfSDavid du Colombier 		if (!isascii(*k))		/* sanity check */
146b72bcbbfSDavid du Colombier 			break;
147b72bcbbfSDavid du Colombier 		next = strchr(k, '\n');
148b72bcbbfSDavid du Colombier 		if (next)
149b72bcbbfSDavid du Colombier 			*next++ = '\0';
150b72bcbbfSDavid du Colombier 
151b72bcbbfSDavid du Colombier 		if (*k == '\0' || *k == '\n' || *k == '#')
152b72bcbbfSDavid du Colombier 			continue;
153b72bcbbfSDavid du Colombier 		v = strchr(k, '=');
154b72bcbbfSDavid du Colombier 		if(v == nil)
155b72bcbbfSDavid du Colombier 			continue;		/* mal-formed line */
156b72bcbbfSDavid du Colombier 		*v++ = '\0';
157b72bcbbfSDavid du Colombier 
1582a6809cbSDavid du Colombier 		addconf(k, v);
159b72bcbbfSDavid du Colombier 	}
160b72bcbbfSDavid du Colombier }
161b72bcbbfSDavid du Colombier 
162154abd99SDavid du Colombier static void
optionsinit(char * s)163154abd99SDavid du Colombier optionsinit(char* s)
164154abd99SDavid du Colombier {
165154abd99SDavid du Colombier 	char *o;
166154abd99SDavid du Colombier 
167154abd99SDavid du Colombier 	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
168154abd99SDavid du Colombier 	if(getenv("bootargs", o, o - oargb) != nil)
169154abd99SDavid du Colombier 		*(o-1) = ' ';
170154abd99SDavid du Colombier 
171154abd99SDavid du Colombier 	oargblen = strlen(oargb);
172154abd99SDavid du Colombier 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
173154abd99SDavid du Colombier 	oargv[oargc] = nil;
174154abd99SDavid du Colombier }
175154abd99SDavid du Colombier 
176154abd99SDavid du Colombier char*
getenv(char * name,char * buf,int n)177154abd99SDavid du Colombier getenv(char* name, char* buf, int n)
178154abd99SDavid du Colombier {
179154abd99SDavid du Colombier 	char *e, *p, *q;
180154abd99SDavid du Colombier 
181154abd99SDavid du Colombier 	p = oenv;
182154abd99SDavid du Colombier 	while(*p != 0){
183154abd99SDavid du Colombier 		if((e = strchr(p, '=')) == nil)
184154abd99SDavid du Colombier 			break;
185154abd99SDavid du Colombier 		for(q = name; p < e; p++){
186154abd99SDavid du Colombier 			if(*p != *q)
187154abd99SDavid du Colombier 				break;
188154abd99SDavid du Colombier 			q++;
189154abd99SDavid du Colombier 		}
190154abd99SDavid du Colombier 		if(p == e && *q == 0){
191154abd99SDavid du Colombier 			strecpy(buf, buf+n, e+1);
192154abd99SDavid du Colombier 			return buf;
193154abd99SDavid du Colombier 		}
194154abd99SDavid du Colombier 		p += strlen(p)+1;
195154abd99SDavid du Colombier 	}
196154abd99SDavid du Colombier 
197154abd99SDavid du Colombier 	return nil;
198154abd99SDavid du Colombier }
199154abd99SDavid du Colombier 
2005e27dea9SDavid du Colombier #include "io.h"
201154abd99SDavid du Colombier 
202154abd99SDavid du Colombier typedef struct Spiregs Spiregs;
203154abd99SDavid du Colombier struct Spiregs {
204154abd99SDavid du Colombier 	ulong	ictl;		/* interface ctl */
205154abd99SDavid du Colombier 	ulong	icfg;		/* interface config */
206154abd99SDavid du Colombier 	ulong	out;		/* data out */
207154abd99SDavid du Colombier 	ulong	in;		/* data in */
208154abd99SDavid du Colombier 	ulong	ic;		/* interrupt cause */
209154abd99SDavid du Colombier 	ulong	im;		/* interrupt mask */
210154abd99SDavid du Colombier 	ulong	_pad[2];
211154abd99SDavid du Colombier 	ulong	dwrcfg;		/* direct write config */
212154abd99SDavid du Colombier 	ulong	dwrhdr;		/* direct write header */
213154abd99SDavid du Colombier };
214154abd99SDavid du Colombier 
215154abd99SDavid du Colombier enum {
216154abd99SDavid du Colombier 	/* ictl bits */
217154abd99SDavid du Colombier 	Csnact	= 1<<0,		/* serial memory activated */
218154abd99SDavid du Colombier 
219154abd99SDavid du Colombier 	/* icfg bits */
220154abd99SDavid du Colombier 	Bytelen	= 1<<5,		/* 2^(this_bit) bytes per transfer */
221154abd99SDavid du Colombier 	Dirrdcmd= 1<<10,	/* flag: fast read */
222154abd99SDavid du Colombier };
223154abd99SDavid du Colombier 
224154abd99SDavid du Colombier static void
dumpbytes(uchar * bp,long max)225154abd99SDavid du Colombier dumpbytes(uchar *bp, long max)
226154abd99SDavid du Colombier {
227154abd99SDavid du Colombier 	iprint("%#p: ", bp);
228154abd99SDavid du Colombier 	for (; max > 0; max--)
229154abd99SDavid du Colombier 		iprint("%02.2ux ", *bp++);
230154abd99SDavid du Colombier 	iprint("...\n");
231154abd99SDavid du Colombier }
232154abd99SDavid du Colombier 
233409b3affSDavid du Colombier void	archconsole(void);
234409b3affSDavid du Colombier vlong	probeaddr(uintptr);
235409b3affSDavid du Colombier 
236154abd99SDavid du Colombier static void
spiprobe(void)237154abd99SDavid du Colombier spiprobe(void)
238154abd99SDavid du Colombier {
2392a782499SDavid du Colombier if (0) {
2402a782499SDavid du Colombier /* generates repeated "spurious irqbridge interrupt: 00000010" on sheevaplug. */
2417365b686SDavid du Colombier 	Spiregs *rp = (Spiregs *)soc.spi;
242154abd99SDavid du Colombier 
243409b3affSDavid du Colombier 	if (probeaddr(soc.spi) < 0)
244409b3affSDavid du Colombier 		return;
245154abd99SDavid du Colombier 	rp->ictl |= Csnact;
246154abd99SDavid du Colombier 	coherence();
247154abd99SDavid du Colombier 	rp->icfg |= Dirrdcmd | 3<<8;	/* fast reads, 4-byte addresses */
248154abd99SDavid du Colombier 	rp->icfg &= ~Bytelen;		/* one-byte reads */
249154abd99SDavid du Colombier 	coherence();
250154abd99SDavid du Colombier 
251409b3affSDavid du Colombier 	print("spi flash ignored: ctlr %#p, data %#ux", rp, PHYSSPIFLASH);
252b649930dSDavid du Colombier 	mmuidmap(PHYSSPIFLASH, 1);
253409b3affSDavid du Colombier 	if (probeaddr(PHYSSPIFLASH) < 0)
254409b3affSDavid du Colombier 		print(" (no response)");
255409b3affSDavid du Colombier 	print(": memory reads enabled\n");
256154abd99SDavid du Colombier }
2572a782499SDavid du Colombier }
258154abd99SDavid du Colombier 
259154abd99SDavid du Colombier /*
260154abd99SDavid du Colombier  * entered from l.s with mmu enabled.
261154abd99SDavid du Colombier  *
262154abd99SDavid du Colombier  * we may have to realign the data segment; apparently 5l -H0 -R4096
263154abd99SDavid du Colombier  * does not pad the text segment.  on the other hand, we may have been
264154abd99SDavid du Colombier  * loaded by another kernel.
265154abd99SDavid du Colombier  *
266154abd99SDavid du Colombier  * be careful not to touch the data segment until we know it's aligned.
267154abd99SDavid du Colombier  */
268154abd99SDavid du Colombier void
main(Mach * mach)269154abd99SDavid du Colombier main(Mach* mach)
270154abd99SDavid du Colombier {
271154abd99SDavid du Colombier 	extern char bdata[], edata[], end[], etext[];
272154abd99SDavid du Colombier 	static ulong vfy = 0xcafebabe;
273154abd99SDavid du Colombier 
274154abd99SDavid du Colombier 	m = mach;
275154abd99SDavid du Colombier 	if (vfy != 0xcafebabe)
276154abd99SDavid du Colombier 		memmove(bdata, etext, edata - bdata);
277154abd99SDavid du Colombier 	if (vfy != 0xcafebabe) {
278154abd99SDavid du Colombier 		wave('?');
279154abd99SDavid du Colombier 		panic("misaligned data segment");
280154abd99SDavid du Colombier 	}
281154abd99SDavid du Colombier 	memset(edata, 0, end - edata);		/* zero bss */
282154abd99SDavid du Colombier 	vfy = 0;
283154abd99SDavid du Colombier 
284154abd99SDavid du Colombier wave('9');
285154abd99SDavid du Colombier 	machinit();
286154abd99SDavid du Colombier 	archreset();
287154abd99SDavid du Colombier 	mmuinit();
288154abd99SDavid du Colombier 
289154abd99SDavid du Colombier 	optionsinit("/boot/boot boot");
290154abd99SDavid du Colombier 	quotefmtinstall();
291154abd99SDavid du Colombier 	archconsole();
292b72bcbbfSDavid du Colombier wave(' ');
293154abd99SDavid du Colombier 
2942a6809cbSDavid du Colombier 	/* want plan9.ini to be able to affect memory sizing in confinit */
2952a6809cbSDavid du Colombier 	plan9iniinit();		/* before we step on plan9.ini in low memory */
2962a6809cbSDavid du Colombier 
297b649930dSDavid du Colombier 	/* set memsize before xinit */
298154abd99SDavid du Colombier 	confinit();
299b72bcbbfSDavid du Colombier 	/* xinit would print if it could */
300154abd99SDavid du Colombier 	xinit();
301154abd99SDavid du Colombier 
302154abd99SDavid du Colombier 	/*
303154abd99SDavid du Colombier 	 * Printinit will cause the first malloc call.
304154abd99SDavid du Colombier 	 * (printinit->qopen->malloc) unless any of the
305154abd99SDavid du Colombier 	 * above (like clockintr) do an irqenable, which
306154abd99SDavid du Colombier 	 * will call malloc.
307154abd99SDavid du Colombier 	 * If the system dies here it's probably due
308154abd99SDavid du Colombier 	 * to malloc(->xalloc) not being initialised
309154abd99SDavid du Colombier 	 * correctly, or the data segment is misaligned
310154abd99SDavid du Colombier 	 * (it's amazing how far you can get with
311154abd99SDavid du Colombier 	 * things like that completely broken).
312154abd99SDavid du Colombier 	 *
313154abd99SDavid du Colombier 	 * (Should be) boilerplate from here on.
314154abd99SDavid du Colombier 	 */
315154abd99SDavid du Colombier 	trapinit();
316154abd99SDavid du Colombier 	clockinit();
317154abd99SDavid du Colombier 
318154abd99SDavid du Colombier 	printinit();
319154abd99SDavid du Colombier 	uartkirkwoodconsole();
320ffc08dc1SDavid du Colombier 	/* only now can we print */
321b72bcbbfSDavid du Colombier 	print("from Bell Labs\n\n");
322ffc08dc1SDavid du Colombier 
323047f1f95SDavid du Colombier #ifdef CRYPTOSANDBOX
324047f1f95SDavid du Colombier 	print("sandbox: 64K at physical %#lux, mapped to 0xf10b0000\n",
325047f1f95SDavid du Colombier 		PADDR((uintptr)sandbox & ~(BY2PG-1)));
326047f1f95SDavid du Colombier #endif
327047f1f95SDavid du Colombier 
328154abd99SDavid du Colombier 	archconfinit();
329154abd99SDavid du Colombier 	cpuidprint();
330154abd99SDavid du Colombier 	timersinit();
331154abd99SDavid du Colombier 
332154abd99SDavid du Colombier 	procinit0();
333154abd99SDavid du Colombier 	initseg();
334154abd99SDavid du Colombier 	links();
335ea9e0a24SDavid du Colombier 	chandevreset();			/* most devices are discovered here */
336409b3affSDavid du Colombier 	spiprobe();
337154abd99SDavid du Colombier 
338154abd99SDavid du Colombier 	pageinit();
339154abd99SDavid du Colombier 	swapinit();
340154abd99SDavid du Colombier 	userinit();
341154abd99SDavid du Colombier 	schedinit();
342a7a38e3eSDavid du Colombier 	panic("schedinit returned");
343154abd99SDavid du Colombier }
344154abd99SDavid du Colombier 
345154abd99SDavid du Colombier void
cpuidprint(void)346154abd99SDavid du Colombier cpuidprint(void)
347154abd99SDavid du Colombier {
348154abd99SDavid du Colombier 	char name[64];
349154abd99SDavid du Colombier 
350154abd99SDavid du Colombier 	cputype2name(name, sizeof name);
351154abd99SDavid du Colombier 	print("cpu%d: %lldMHz ARM %s\n", m->machno, m->cpuhz/1000000, name);
352154abd99SDavid du Colombier }
353154abd99SDavid du Colombier 
354154abd99SDavid du Colombier void
machinit(void)355154abd99SDavid du Colombier machinit(void)
356154abd99SDavid du Colombier {
357154abd99SDavid du Colombier 	memset(m, 0, sizeof(Mach));
358154abd99SDavid du Colombier 	m->machno = 0;
359154abd99SDavid du Colombier 	machaddr[m->machno] = m;
360154abd99SDavid du Colombier 
361154abd99SDavid du Colombier 	m->ticks = 1;
362154abd99SDavid du Colombier 	m->perf.period = 1;
363154abd99SDavid du Colombier 
364154abd99SDavid du Colombier 	conf.nmach = 1;
365154abd99SDavid du Colombier 
366154abd99SDavid du Colombier 	active.machs = 1;
367154abd99SDavid du Colombier 	active.exiting = 0;
368154abd99SDavid du Colombier 
369154abd99SDavid du Colombier 	up = nil;
370154abd99SDavid du Colombier }
371154abd99SDavid du Colombier 
372154abd99SDavid du Colombier static void
shutdown(int ispanic)373154abd99SDavid du Colombier shutdown(int ispanic)
374154abd99SDavid du Colombier {
375154abd99SDavid du Colombier 	int ms, once;
376154abd99SDavid du Colombier 
377154abd99SDavid du Colombier 	lock(&active);
378154abd99SDavid du Colombier 	if(ispanic)
379154abd99SDavid du Colombier 		active.ispanic = ispanic;
380154abd99SDavid du Colombier 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
381154abd99SDavid du Colombier 		active.ispanic = 0;
382154abd99SDavid du Colombier 	once = active.machs & (1<<m->machno);
383154abd99SDavid du Colombier 	active.machs &= ~(1<<m->machno);
384154abd99SDavid du Colombier 	active.exiting = 1;
385154abd99SDavid du Colombier 	unlock(&active);
386154abd99SDavid du Colombier 
387154abd99SDavid du Colombier 	if(once)
388154abd99SDavid du Colombier 		iprint("cpu%d: exiting\n", m->machno);
389154abd99SDavid du Colombier 	spllo();
390154abd99SDavid du Colombier 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
391154abd99SDavid du Colombier 		delay(TK2MS(2));
392154abd99SDavid du Colombier 		if(active.machs == 0 && consactive() == 0)
393154abd99SDavid du Colombier 			break;
394154abd99SDavid du Colombier 	}
395154abd99SDavid du Colombier 	delay(1000);
396154abd99SDavid du Colombier }
397154abd99SDavid du Colombier 
398154abd99SDavid du Colombier /*
399154abd99SDavid du Colombier  *  exit kernel either on a panic or user request
400154abd99SDavid du Colombier  */
401154abd99SDavid du Colombier void
exit(int code)402154abd99SDavid du Colombier exit(int code)
403154abd99SDavid du Colombier {
404154abd99SDavid du Colombier 	shutdown(code);
405154abd99SDavid du Colombier 	splhi();
406154abd99SDavid du Colombier 	archreboot();
407154abd99SDavid du Colombier }
408154abd99SDavid du Colombier 
409154abd99SDavid du Colombier /*
410154abd99SDavid du Colombier  * the new kernel is already loaded at address `code'
411154abd99SDavid du Colombier  * of size `size' and entry point `entry'.
412154abd99SDavid du Colombier  */
413154abd99SDavid du Colombier void
reboot(void * entry,void * code,ulong size)414154abd99SDavid du Colombier reboot(void *entry, void *code, ulong size)
415154abd99SDavid du Colombier {
416154abd99SDavid du Colombier 	void (*f)(ulong, ulong, ulong);
417154abd99SDavid du Colombier 
418154abd99SDavid du Colombier 	iprint("starting reboot...");
419b72bcbbfSDavid du Colombier 	writeconf();
420b72bcbbfSDavid du Colombier 
421154abd99SDavid du Colombier 	shutdown(0);
422154abd99SDavid du Colombier 
423154abd99SDavid du Colombier 	/*
424154abd99SDavid du Colombier 	 * should be the only processor running now
425154abd99SDavid du Colombier 	 */
426154abd99SDavid du Colombier 
427154abd99SDavid du Colombier 	print("shutting down...\n");
428154abd99SDavid du Colombier 	delay(200);
429154abd99SDavid du Colombier 
430154abd99SDavid du Colombier 	/* turn off buffered serial console */
431154abd99SDavid du Colombier 	serialoq = nil;
432154abd99SDavid du Colombier 
433154abd99SDavid du Colombier 	/* shutdown devices */
434c8a340cdSDavid du Colombier 	chandevshutdown();
435154abd99SDavid du Colombier 
43656713243SDavid du Colombier 	/* call off the dog */
43756713243SDavid du Colombier 	clockshutdown();
43856713243SDavid du Colombier 
43956713243SDavid du Colombier 	splhi();
44056713243SDavid du Colombier 
441154abd99SDavid du Colombier 	/* setup reboot trampoline function */
442154abd99SDavid du Colombier 	f = (void*)REBOOTADDR;
443154abd99SDavid du Colombier 	memmove(f, rebootcode, sizeof(rebootcode));
444b72bcbbfSDavid du Colombier 	cacheuwbinv();
445a7a38e3eSDavid du Colombier 	l2cacheuwb();
446154abd99SDavid du Colombier 
447154abd99SDavid du Colombier 	print("rebooting...");
448154abd99SDavid du Colombier 	iprint("entry %#lux code %#lux size %ld\n",
449154abd99SDavid du Colombier 		PADDR(entry), PADDR(code), size);
450154abd99SDavid du Colombier 	delay(100);		/* wait for uart to quiesce */
451154abd99SDavid du Colombier 
452154abd99SDavid du Colombier 	/* off we go - never to return */
453b72bcbbfSDavid du Colombier 	cacheuwbinv();
454a7a38e3eSDavid du Colombier 	l2cacheuwb();
455154abd99SDavid du Colombier 	(*f)(PADDR(entry), PADDR(code), size);
456154abd99SDavid du Colombier 
457154abd99SDavid du Colombier 	iprint("loaded kernel returned!\n");
45856713243SDavid du Colombier 	delay(1000);
459154abd99SDavid du Colombier 	archreboot();
460154abd99SDavid du Colombier }
461154abd99SDavid du Colombier 
462154abd99SDavid du Colombier /*
463154abd99SDavid du Colombier  *  starting place for first process
464154abd99SDavid du Colombier  */
465154abd99SDavid du Colombier void
init0(void)466154abd99SDavid du Colombier init0(void)
467154abd99SDavid du Colombier {
468b72bcbbfSDavid du Colombier 	int i;
469154abd99SDavid du Colombier 	char buf[2*KNAMELEN];
470154abd99SDavid du Colombier 
471154abd99SDavid du Colombier 	assert(up != nil);
472154abd99SDavid du Colombier 	up->nerrlab = 0;
473154abd99SDavid du Colombier 	coherence();
474154abd99SDavid du Colombier 	spllo();
475154abd99SDavid du Colombier 
476154abd99SDavid du Colombier 	/*
477154abd99SDavid du Colombier 	 * These are o.k. because rootinit is null.
478154abd99SDavid du Colombier 	 * Then early kproc's will have a root and dot.
479154abd99SDavid du Colombier 	 */
480154abd99SDavid du Colombier 	up->slash = namec("#/", Atodir, 0, 0);
481154abd99SDavid du Colombier 	pathclose(up->slash->path);
482154abd99SDavid du Colombier 	up->slash->path = newpath("/");
483154abd99SDavid du Colombier 	up->dot = cclone(up->slash);
484154abd99SDavid du Colombier 
485c8a340cdSDavid du Colombier 	chandevinit();
486154abd99SDavid du Colombier 
487154abd99SDavid du Colombier 	if(!waserror()){
488154abd99SDavid du Colombier 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
489154abd99SDavid du Colombier 		ksetenv("terminal", buf, 0);
490154abd99SDavid du Colombier 		ksetenv("cputype", "arm", 0);
491154abd99SDavid du Colombier 		if(cpuserver)
492154abd99SDavid du Colombier 			ksetenv("service", "cpu", 0);
493154abd99SDavid du Colombier 		else
494154abd99SDavid du Colombier 			ksetenv("service", "terminal", 0);
495154abd99SDavid du Colombier 
496b72bcbbfSDavid du Colombier 		/* convert plan9.ini variables to #e and #ec */
497b72bcbbfSDavid du Colombier 		for(i = 0; i < nconf; i++) {
498b72bcbbfSDavid du Colombier 			ksetenv(confname[i], confval[i], 0);
499b72bcbbfSDavid du Colombier 			ksetenv(confname[i], confval[i], 1);
500b72bcbbfSDavid du Colombier 		}
501154abd99SDavid du Colombier 		poperror();
502154abd99SDavid du Colombier 	}
503154abd99SDavid du Colombier 	kproc("alarm", alarmkproc, 0);
504154abd99SDavid du Colombier 
505154abd99SDavid du Colombier 	touser(sp);
506154abd99SDavid du Colombier }
507154abd99SDavid du Colombier 
508154abd99SDavid du Colombier static void
bootargs(uintptr base)509154abd99SDavid du Colombier bootargs(uintptr base)
510154abd99SDavid du Colombier {
511154abd99SDavid du Colombier 	int i;
512154abd99SDavid du Colombier 	ulong ssize;
513154abd99SDavid du Colombier 	char **av, *p;
514154abd99SDavid du Colombier 
515154abd99SDavid du Colombier 	/*
516154abd99SDavid du Colombier 	 * Push the boot args onto the stack.
517154abd99SDavid du Colombier 	 * The initial value of the user stack must be such
518154abd99SDavid du Colombier 	 * that the total used is larger than the maximum size
519154abd99SDavid du Colombier 	 * of the argument list checked in syscall.
520154abd99SDavid du Colombier 	 */
521154abd99SDavid du Colombier 	i = oargblen+1;
522*23a96966SDavid du Colombier 	p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
523154abd99SDavid du Colombier 	memmove(p, oargb, i);
524154abd99SDavid du Colombier 
525154abd99SDavid du Colombier 	/*
526154abd99SDavid du Colombier 	 * Now push argc and the argv pointers.
527154abd99SDavid du Colombier 	 * This isn't strictly correct as the code jumped to by
528154abd99SDavid du Colombier 	 * touser in init9.s calls startboot (port/initcode.c) which
529154abd99SDavid du Colombier 	 * expects arguments
530154abd99SDavid du Colombier 	 * 	startboot(char *argv0, char **argv)
531154abd99SDavid du Colombier 	 * not the usual (int argc, char* argv[]), but argv0 is
532154abd99SDavid du Colombier 	 * unused so it doesn't matter (at the moment...).
533154abd99SDavid du Colombier 	 */
534154abd99SDavid du Colombier 	av = (char**)(p - (oargc+2)*sizeof(char*));
535b1c4f505SDavid du Colombier 	ssize = base + BY2PG - PTR2UINT(av);
536154abd99SDavid du Colombier 	*av++ = (char*)oargc;
537154abd99SDavid du Colombier 	for(i = 0; i < oargc; i++)
538154abd99SDavid du Colombier 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
539154abd99SDavid du Colombier 	*av = nil;
540154abd99SDavid du Colombier 
541154abd99SDavid du Colombier 	/*
542154abd99SDavid du Colombier 	 * Leave space for the return PC of the
543154abd99SDavid du Colombier 	 * caller of initcode.
544154abd99SDavid du Colombier 	 */
545154abd99SDavid du Colombier 	sp = USTKTOP - ssize - sizeof(void*);
546154abd99SDavid du Colombier }
547154abd99SDavid du Colombier 
548154abd99SDavid du Colombier /*
549154abd99SDavid du Colombier  *  create the first process
550154abd99SDavid du Colombier  */
551154abd99SDavid du Colombier void
userinit(void)552154abd99SDavid du Colombier userinit(void)
553154abd99SDavid du Colombier {
554154abd99SDavid du Colombier 	Proc *p;
555154abd99SDavid du Colombier 	Segment *s;
556154abd99SDavid du Colombier 	KMap *k;
557154abd99SDavid du Colombier 	Page *pg;
558154abd99SDavid du Colombier 
559154abd99SDavid du Colombier 	/* no processes yet */
560154abd99SDavid du Colombier 	up = nil;
561154abd99SDavid du Colombier 
562154abd99SDavid du Colombier 	p = newproc();
563154abd99SDavid du Colombier 	p->pgrp = newpgrp();
564154abd99SDavid du Colombier 	p->egrp = smalloc(sizeof(Egrp));
565154abd99SDavid du Colombier 	p->egrp->ref = 1;
566154abd99SDavid du Colombier 	p->fgrp = dupfgrp(nil);
567154abd99SDavid du Colombier 	p->rgrp = newrgrp();
568154abd99SDavid du Colombier 	p->procmode = 0640;
569154abd99SDavid du Colombier 
570154abd99SDavid du Colombier 	kstrdup(&eve, "");
571154abd99SDavid du Colombier 	kstrdup(&p->text, "*init*");
572154abd99SDavid du Colombier 	kstrdup(&p->user, eve);
573154abd99SDavid du Colombier 
574154abd99SDavid du Colombier 	/*
575154abd99SDavid du Colombier 	 * Kernel Stack
576154abd99SDavid du Colombier 	 */
577154abd99SDavid du Colombier 	p->sched.pc = PTR2UINT(init0);
578154abd99SDavid du Colombier 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
579154abd99SDavid du Colombier 	p->sched.sp = STACKALIGN(p->sched.sp);
580154abd99SDavid du Colombier 
581154abd99SDavid du Colombier 	/*
582154abd99SDavid du Colombier 	 * User Stack
583154abd99SDavid du Colombier 	 *
584154abd99SDavid du Colombier 	 * Technically, newpage can't be called here because it
585154abd99SDavid du Colombier 	 * should only be called when in a user context as it may
586154abd99SDavid du Colombier 	 * try to sleep if there are no pages available, but that
587154abd99SDavid du Colombier 	 * shouldn't be the case here.
588154abd99SDavid du Colombier 	 */
589154abd99SDavid du Colombier 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
590154abd99SDavid du Colombier 	p->seg[SSEG] = s;
591154abd99SDavid du Colombier 	pg = newpage(1, 0, USTKTOP-BY2PG);
592154abd99SDavid du Colombier 	segpage(s, pg);
593154abd99SDavid du Colombier 	k = kmap(pg);
594154abd99SDavid du Colombier 	bootargs(VA(k));
595154abd99SDavid du Colombier 	kunmap(k);
596154abd99SDavid du Colombier 
597154abd99SDavid du Colombier 	/*
598154abd99SDavid du Colombier 	 * Text
599154abd99SDavid du Colombier 	 */
600154abd99SDavid du Colombier 	s = newseg(SG_TEXT, UTZERO, 1);
601154abd99SDavid du Colombier 	s->flushme++;
602154abd99SDavid du Colombier 	p->seg[TSEG] = s;
603154abd99SDavid du Colombier 	pg = newpage(1, 0, UTZERO);
604154abd99SDavid du Colombier 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
605154abd99SDavid du Colombier 	segpage(s, pg);
606154abd99SDavid du Colombier 	k = kmap(s->map[0]->pages[0]);
607154abd99SDavid du Colombier 	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
608154abd99SDavid du Colombier 	kunmap(k);
609154abd99SDavid du Colombier 
610154abd99SDavid du Colombier 	ready(p);
611154abd99SDavid du Colombier }
612154abd99SDavid du Colombier 
613154abd99SDavid du Colombier Conf conf;			/* XXX - must go - gag */
614154abd99SDavid du Colombier 
615b649930dSDavid du Colombier Confmem sheevamem[nelem(conf.mem)] = {
616154abd99SDavid du Colombier 	/*
617154abd99SDavid du Colombier 	 * Memory available to Plan 9:
61806f6463aSDavid du Colombier 	 * the 8K is reserved for ethernet dma access violations to scribble on.
619154abd99SDavid du Colombier 	 */
62063c59e25SDavid du Colombier 	{ .base = PHYSDRAM, .limit = PHYSDRAM + Maxmem - 8*1024, },
621154abd99SDavid du Colombier };
622b649930dSDavid du Colombier ulong memsize = Maxmem;
623b649930dSDavid du Colombier 
624b649930dSDavid du Colombier static int
gotmem(uintptr sz)625b649930dSDavid du Colombier gotmem(uintptr sz)
626b649930dSDavid du Colombier {
627b649930dSDavid du Colombier 	uintptr addr;
628b649930dSDavid du Colombier 
629b649930dSDavid du Colombier 	addr = PHYSDRAM + sz - MB;
630b649930dSDavid du Colombier 	mmuidmap(addr, 1);
631b649930dSDavid du Colombier 	if (probeaddr(addr) >= 0) {
632b649930dSDavid du Colombier 		memsize = sz;
633b649930dSDavid du Colombier 		return 0;
634b649930dSDavid du Colombier 	}
635b649930dSDavid du Colombier 	return -1;
636b649930dSDavid du Colombier }
637154abd99SDavid du Colombier 
638154abd99SDavid du Colombier void
confinit(void)639154abd99SDavid du Colombier confinit(void)
640154abd99SDavid du Colombier {
641154abd99SDavid du Colombier 	int i;
642154abd99SDavid du Colombier 	ulong kpages;
643154abd99SDavid du Colombier 	uintptr pa;
644b649930dSDavid du Colombier 	char *p;
645154abd99SDavid du Colombier 
646154abd99SDavid du Colombier 	/*
647154abd99SDavid du Colombier 	 * Copy the physical memory configuration to Conf.mem.
648154abd99SDavid du Colombier 	 */
649154abd99SDavid du Colombier 	if(nelem(sheevamem) > nelem(conf.mem)){
650154abd99SDavid du Colombier 		iprint("memory configuration botch\n");
651154abd99SDavid du Colombier 		exit(1);
652154abd99SDavid du Colombier 	}
653b649930dSDavid du Colombier 	if((p = getconf("*maxmem")) != nil) {
654b649930dSDavid du Colombier 		memsize = strtoul(p, 0, 0) - PHYSDRAM;
655b649930dSDavid du Colombier 		if (memsize < 16*MB)		/* sanity */
656b649930dSDavid du Colombier 			memsize = 16*MB;
657b649930dSDavid du Colombier 	}
658b649930dSDavid du Colombier 
659b649930dSDavid du Colombier 	/*
660b649930dSDavid du Colombier 	 * see if all that memory exists; if not, find out how much does.
661b649930dSDavid du Colombier 	 * trapinit must have been called first.
662b649930dSDavid du Colombier 	 */
663b649930dSDavid du Colombier 	if (gotmem(memsize) < 0 && gotmem(256*MB) < 0 && gotmem(128*MB) < 0) {
664b649930dSDavid du Colombier 		iprint("can't find any memory, assuming %dMB\n", Minmem / MB);
665b649930dSDavid du Colombier 		memsize = Minmem;
666b649930dSDavid du Colombier 	}
667b649930dSDavid du Colombier 
668b649930dSDavid du Colombier 	sheevamem[0].limit = PHYSDRAM + memsize - 8*1024;
669154abd99SDavid du Colombier 	memmove(conf.mem, sheevamem, sizeof(sheevamem));
670154abd99SDavid du Colombier 
671154abd99SDavid du Colombier 	conf.npage = 0;
672154abd99SDavid du Colombier 	pa = PADDR(PGROUND(PTR2UINT(end)));
673154abd99SDavid du Colombier 
674154abd99SDavid du Colombier 	/*
675154abd99SDavid du Colombier 	 *  we assume that the kernel is at the beginning of one of the
676154abd99SDavid du Colombier 	 *  contiguous chunks of memory and fits therein.
677154abd99SDavid du Colombier 	 */
678154abd99SDavid du Colombier 	for(i=0; i<nelem(conf.mem); i++){
679154abd99SDavid du Colombier 		/* take kernel out of allocatable space */
680154abd99SDavid du Colombier 		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
681154abd99SDavid du Colombier 			conf.mem[i].base = pa;
682154abd99SDavid du Colombier 
683154abd99SDavid du Colombier 		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
684154abd99SDavid du Colombier 		conf.npage += conf.mem[i].npage;
685154abd99SDavid du Colombier 	}
686154abd99SDavid du Colombier 
687154abd99SDavid du Colombier 	conf.upages = (conf.npage*90)/100;
688154abd99SDavid du Colombier 	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
689154abd99SDavid du Colombier 
690154abd99SDavid du Colombier 	/* only one processor */
691154abd99SDavid du Colombier 	conf.nmach = 1;
692154abd99SDavid du Colombier 
693154abd99SDavid du Colombier 	/* set up other configuration parameters */
694154abd99SDavid du Colombier 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
695154abd99SDavid du Colombier 	if(cpuserver)
696154abd99SDavid du Colombier 		conf.nproc *= 3;
697154abd99SDavid du Colombier 	if(conf.nproc > 2000)
698154abd99SDavid du Colombier 		conf.nproc = 2000;
699154abd99SDavid du Colombier 	conf.nswap = conf.npage*3;
700154abd99SDavid du Colombier 	conf.nswppo = 4096;
701154abd99SDavid du Colombier 	conf.nimage = 200;
702154abd99SDavid du Colombier 
703154abd99SDavid du Colombier 	conf.copymode = 0;		/* copy on write */
704154abd99SDavid du Colombier 
705154abd99SDavid du Colombier 	/*
706154abd99SDavid du Colombier 	 * Guess how much is taken by the large permanent
707154abd99SDavid du Colombier 	 * datastructures. Mntcache and Mntrpc are not accounted for
708154abd99SDavid du Colombier 	 * (probably ~300KB).
709154abd99SDavid du Colombier 	 */
710154abd99SDavid du Colombier 	kpages = conf.npage - conf.upages;
711154abd99SDavid du Colombier 	kpages *= BY2PG;
712154abd99SDavid du Colombier 	kpages -= conf.upages*sizeof(Page)
713154abd99SDavid du Colombier 		+ conf.nproc*sizeof(Proc)
714154abd99SDavid du Colombier 		+ conf.nimage*sizeof(Image)
715154abd99SDavid du Colombier 		+ conf.nswap
716154abd99SDavid du Colombier 		+ conf.nswppo*sizeof(Page);
717154abd99SDavid du Colombier 	mainmem->maxsize = kpages;
718154abd99SDavid du Colombier 	if(!cpuserver)
719154abd99SDavid du Colombier 		/*
720154abd99SDavid du Colombier 		 * give terminals lots of image memory, too; the dynamic
721154abd99SDavid du Colombier 		 * allocation will balance the load properly, hopefully.
722154abd99SDavid du Colombier 		 * be careful with 32-bit overflow.
723154abd99SDavid du Colombier 		 */
724154abd99SDavid du Colombier 		imagmem->maxsize = kpages;
725154abd99SDavid du Colombier }
726154abd99SDavid du Colombier 
727154abd99SDavid du Colombier int
cmpswap(long * addr,long old,long new)728154abd99SDavid du Colombier cmpswap(long *addr, long old, long new)
729154abd99SDavid du Colombier {
730154abd99SDavid du Colombier 	return cas32(addr, old, new);
731154abd99SDavid du Colombier }
732