xref: /plan9/sys/src/9/kw/main.c (revision 23a969667fc2f16f64e45b0a4135d6dd31daef7a)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 
7 #include "init.h"
8 #include "arm.h"
9 #include <pool.h>
10 #include <tos.h>
11 
12 #include "reboot.h"
13 
14 /*
15  * Where configuration info is left for the loaded programme.
16  * This will turn into a structure as more is done by the boot loader
17  * (e.g. why parse the .ini file twice?).
18  * There are 3584 bytes available at CONFADDR.
19  */
20 #define BOOTARGS	((char*)CONFADDR)
21 #define	BOOTARGSLEN	(16*KiB)		/* limit in devenv.c */
22 #define	MAXCONF		64
23 #define MAXCONFLINE	160
24 
25 enum {
26 	Maxmem	= 512*MB,			/* limited by address ranges */
27 	Minmem	= 256*MB,			/* conservative default */
28 
29 	/* space for syscall args, return PC, top-of-stack struct */
30 	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
31 };
32 
33 #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
34 
35 uintptr kseg0 = KZERO;
36 Mach* machaddr[MAXMACH];
37 
38 /*
39  * Option arguments from the command line.
40  * oargv[0] is the boot file.
41  * Optionsinit() is called from multiboot()
42  * or some other machine-dependent place
43  * to set it all up.
44  */
45 static int oargc;
46 static char* oargv[20];
47 static char oargb[128];
48 static int oargblen;
49 static char oenv[4096];
50 
51 static uintptr sp;		/* XXX - must go - user stack of init proc */
52 
53 int vflag;
54 char debug[256];
55 
56 /* store plan9.ini contents here at least until we stash them in #ec */
57 static char confname[MAXCONF][KNAMELEN];
58 static char confval[MAXCONF][MAXCONFLINE];
59 static int nconf;
60 
61 #ifdef CRYPTOSANDBOX
62 uchar sandbox[64*1024+BY2PG];
63 #endif
64 
65 static int
findconf(char * name)66 findconf(char *name)
67 {
68 	int i;
69 
70 	for(i = 0; i < nconf; i++)
71 		if(cistrcmp(confname[i], name) == 0)
72 			return i;
73 	return -1;
74 }
75 
76 char*
getconf(char * name)77 getconf(char *name)
78 {
79 	int i;
80 
81 	i = findconf(name);
82 	if(i >= 0)
83 		return confval[i];
84 	return nil;
85 }
86 
87 void
addconf(char * name,char * val)88 addconf(char *name, char *val)
89 {
90 	int i;
91 
92 	i = findconf(name);
93 	if(i < 0){
94 		if(val == nil || nconf >= MAXCONF)
95 			return;
96 		i = nconf++;
97 		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
98 	}
99 //	confval[i] = val;
100 	strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
101 }
102 
103 static void
writeconf(void)104 writeconf(void)
105 {
106 	char *p, *q;
107 	int n;
108 
109 	p = getconfenv();
110 
111 	if(waserror()) {
112 		free(p);
113 		nexterror();
114 	}
115 
116 	/* convert to name=value\n format */
117 	for(q=p; *q; q++) {
118 		q += strlen(q);
119 		*q = '=';
120 		q += strlen(q);
121 		*q = '\n';
122 	}
123 	n = q - p + 1;
124 	if(n >= BOOTARGSLEN)
125 		error("kernel configuration too large");
126 	memmove(BOOTARGS, p, n);
127 	poperror();
128 	free(p);
129 }
130 
131 /*
132  * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
133  * tftp in u-boot.  no longer uses malloc, so can be called early.
134  */
135 static void
plan9iniinit(void)136 plan9iniinit(void)
137 {
138 	char *k, *v, *next;
139 
140 	k = (char *)CONFADDR;
141 	if(!isascii(*k))
142 		return;
143 
144 	for(; k && *k != '\0'; k = next) {
145 		if (!isascii(*k))		/* sanity check */
146 			break;
147 		next = strchr(k, '\n');
148 		if (next)
149 			*next++ = '\0';
150 
151 		if (*k == '\0' || *k == '\n' || *k == '#')
152 			continue;
153 		v = strchr(k, '=');
154 		if(v == nil)
155 			continue;		/* mal-formed line */
156 		*v++ = '\0';
157 
158 		addconf(k, v);
159 	}
160 }
161 
162 static void
optionsinit(char * s)163 optionsinit(char* s)
164 {
165 	char *o;
166 
167 	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
168 	if(getenv("bootargs", o, o - oargb) != nil)
169 		*(o-1) = ' ';
170 
171 	oargblen = strlen(oargb);
172 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
173 	oargv[oargc] = nil;
174 }
175 
176 char*
getenv(char * name,char * buf,int n)177 getenv(char* name, char* buf, int n)
178 {
179 	char *e, *p, *q;
180 
181 	p = oenv;
182 	while(*p != 0){
183 		if((e = strchr(p, '=')) == nil)
184 			break;
185 		for(q = name; p < e; p++){
186 			if(*p != *q)
187 				break;
188 			q++;
189 		}
190 		if(p == e && *q == 0){
191 			strecpy(buf, buf+n, e+1);
192 			return buf;
193 		}
194 		p += strlen(p)+1;
195 	}
196 
197 	return nil;
198 }
199 
200 #include "io.h"
201 
202 typedef struct Spiregs Spiregs;
203 struct Spiregs {
204 	ulong	ictl;		/* interface ctl */
205 	ulong	icfg;		/* interface config */
206 	ulong	out;		/* data out */
207 	ulong	in;		/* data in */
208 	ulong	ic;		/* interrupt cause */
209 	ulong	im;		/* interrupt mask */
210 	ulong	_pad[2];
211 	ulong	dwrcfg;		/* direct write config */
212 	ulong	dwrhdr;		/* direct write header */
213 };
214 
215 enum {
216 	/* ictl bits */
217 	Csnact	= 1<<0,		/* serial memory activated */
218 
219 	/* icfg bits */
220 	Bytelen	= 1<<5,		/* 2^(this_bit) bytes per transfer */
221 	Dirrdcmd= 1<<10,	/* flag: fast read */
222 };
223 
224 static void
dumpbytes(uchar * bp,long max)225 dumpbytes(uchar *bp, long max)
226 {
227 	iprint("%#p: ", bp);
228 	for (; max > 0; max--)
229 		iprint("%02.2ux ", *bp++);
230 	iprint("...\n");
231 }
232 
233 void	archconsole(void);
234 vlong	probeaddr(uintptr);
235 
236 static void
spiprobe(void)237 spiprobe(void)
238 {
239 if (0) {
240 /* generates repeated "spurious irqbridge interrupt: 00000010" on sheevaplug. */
241 	Spiregs *rp = (Spiregs *)soc.spi;
242 
243 	if (probeaddr(soc.spi) < 0)
244 		return;
245 	rp->ictl |= Csnact;
246 	coherence();
247 	rp->icfg |= Dirrdcmd | 3<<8;	/* fast reads, 4-byte addresses */
248 	rp->icfg &= ~Bytelen;		/* one-byte reads */
249 	coherence();
250 
251 	print("spi flash ignored: ctlr %#p, data %#ux", rp, PHYSSPIFLASH);
252 	mmuidmap(PHYSSPIFLASH, 1);
253 	if (probeaddr(PHYSSPIFLASH) < 0)
254 		print(" (no response)");
255 	print(": memory reads enabled\n");
256 }
257 }
258 
259 /*
260  * entered from l.s with mmu enabled.
261  *
262  * we may have to realign the data segment; apparently 5l -H0 -R4096
263  * does not pad the text segment.  on the other hand, we may have been
264  * loaded by another kernel.
265  *
266  * be careful not to touch the data segment until we know it's aligned.
267  */
268 void
main(Mach * mach)269 main(Mach* mach)
270 {
271 	extern char bdata[], edata[], end[], etext[];
272 	static ulong vfy = 0xcafebabe;
273 
274 	m = mach;
275 	if (vfy != 0xcafebabe)
276 		memmove(bdata, etext, edata - bdata);
277 	if (vfy != 0xcafebabe) {
278 		wave('?');
279 		panic("misaligned data segment");
280 	}
281 	memset(edata, 0, end - edata);		/* zero bss */
282 	vfy = 0;
283 
284 wave('9');
285 	machinit();
286 	archreset();
287 	mmuinit();
288 
289 	optionsinit("/boot/boot boot");
290 	quotefmtinstall();
291 	archconsole();
292 wave(' ');
293 
294 	/* want plan9.ini to be able to affect memory sizing in confinit */
295 	plan9iniinit();		/* before we step on plan9.ini in low memory */
296 
297 	/* set memsize before xinit */
298 	confinit();
299 	/* xinit would print if it could */
300 	xinit();
301 
302 	/*
303 	 * Printinit will cause the first malloc call.
304 	 * (printinit->qopen->malloc) unless any of the
305 	 * above (like clockintr) do an irqenable, which
306 	 * will call malloc.
307 	 * If the system dies here it's probably due
308 	 * to malloc(->xalloc) not being initialised
309 	 * correctly, or the data segment is misaligned
310 	 * (it's amazing how far you can get with
311 	 * things like that completely broken).
312 	 *
313 	 * (Should be) boilerplate from here on.
314 	 */
315 	trapinit();
316 	clockinit();
317 
318 	printinit();
319 	uartkirkwoodconsole();
320 	/* only now can we print */
321 	print("from Bell Labs\n\n");
322 
323 #ifdef CRYPTOSANDBOX
324 	print("sandbox: 64K at physical %#lux, mapped to 0xf10b0000\n",
325 		PADDR((uintptr)sandbox & ~(BY2PG-1)));
326 #endif
327 
328 	archconfinit();
329 	cpuidprint();
330 	timersinit();
331 
332 	procinit0();
333 	initseg();
334 	links();
335 	chandevreset();			/* most devices are discovered here */
336 	spiprobe();
337 
338 	pageinit();
339 	swapinit();
340 	userinit();
341 	schedinit();
342 	panic("schedinit returned");
343 }
344 
345 void
cpuidprint(void)346 cpuidprint(void)
347 {
348 	char name[64];
349 
350 	cputype2name(name, sizeof name);
351 	print("cpu%d: %lldMHz ARM %s\n", m->machno, m->cpuhz/1000000, name);
352 }
353 
354 void
machinit(void)355 machinit(void)
356 {
357 	memset(m, 0, sizeof(Mach));
358 	m->machno = 0;
359 	machaddr[m->machno] = m;
360 
361 	m->ticks = 1;
362 	m->perf.period = 1;
363 
364 	conf.nmach = 1;
365 
366 	active.machs = 1;
367 	active.exiting = 0;
368 
369 	up = nil;
370 }
371 
372 static void
shutdown(int ispanic)373 shutdown(int ispanic)
374 {
375 	int ms, once;
376 
377 	lock(&active);
378 	if(ispanic)
379 		active.ispanic = ispanic;
380 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
381 		active.ispanic = 0;
382 	once = active.machs & (1<<m->machno);
383 	active.machs &= ~(1<<m->machno);
384 	active.exiting = 1;
385 	unlock(&active);
386 
387 	if(once)
388 		iprint("cpu%d: exiting\n", m->machno);
389 	spllo();
390 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
391 		delay(TK2MS(2));
392 		if(active.machs == 0 && consactive() == 0)
393 			break;
394 	}
395 	delay(1000);
396 }
397 
398 /*
399  *  exit kernel either on a panic or user request
400  */
401 void
exit(int code)402 exit(int code)
403 {
404 	shutdown(code);
405 	splhi();
406 	archreboot();
407 }
408 
409 /*
410  * the new kernel is already loaded at address `code'
411  * of size `size' and entry point `entry'.
412  */
413 void
reboot(void * entry,void * code,ulong size)414 reboot(void *entry, void *code, ulong size)
415 {
416 	void (*f)(ulong, ulong, ulong);
417 
418 	iprint("starting reboot...");
419 	writeconf();
420 
421 	shutdown(0);
422 
423 	/*
424 	 * should be the only processor running now
425 	 */
426 
427 	print("shutting down...\n");
428 	delay(200);
429 
430 	/* turn off buffered serial console */
431 	serialoq = nil;
432 
433 	/* shutdown devices */
434 	chandevshutdown();
435 
436 	/* call off the dog */
437 	clockshutdown();
438 
439 	splhi();
440 
441 	/* setup reboot trampoline function */
442 	f = (void*)REBOOTADDR;
443 	memmove(f, rebootcode, sizeof(rebootcode));
444 	cacheuwbinv();
445 	l2cacheuwb();
446 
447 	print("rebooting...");
448 	iprint("entry %#lux code %#lux size %ld\n",
449 		PADDR(entry), PADDR(code), size);
450 	delay(100);		/* wait for uart to quiesce */
451 
452 	/* off we go - never to return */
453 	cacheuwbinv();
454 	l2cacheuwb();
455 	(*f)(PADDR(entry), PADDR(code), size);
456 
457 	iprint("loaded kernel returned!\n");
458 	delay(1000);
459 	archreboot();
460 }
461 
462 /*
463  *  starting place for first process
464  */
465 void
init0(void)466 init0(void)
467 {
468 	int i;
469 	char buf[2*KNAMELEN];
470 
471 	assert(up != nil);
472 	up->nerrlab = 0;
473 	coherence();
474 	spllo();
475 
476 	/*
477 	 * These are o.k. because rootinit is null.
478 	 * Then early kproc's will have a root and dot.
479 	 */
480 	up->slash = namec("#/", Atodir, 0, 0);
481 	pathclose(up->slash->path);
482 	up->slash->path = newpath("/");
483 	up->dot = cclone(up->slash);
484 
485 	chandevinit();
486 
487 	if(!waserror()){
488 		snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
489 		ksetenv("terminal", buf, 0);
490 		ksetenv("cputype", "arm", 0);
491 		if(cpuserver)
492 			ksetenv("service", "cpu", 0);
493 		else
494 			ksetenv("service", "terminal", 0);
495 
496 		/* convert plan9.ini variables to #e and #ec */
497 		for(i = 0; i < nconf; i++) {
498 			ksetenv(confname[i], confval[i], 0);
499 			ksetenv(confname[i], confval[i], 1);
500 		}
501 		poperror();
502 	}
503 	kproc("alarm", alarmkproc, 0);
504 
505 	touser(sp);
506 }
507 
508 static void
bootargs(uintptr base)509 bootargs(uintptr base)
510 {
511 	int i;
512 	ulong ssize;
513 	char **av, *p;
514 
515 	/*
516 	 * Push the boot args onto the stack.
517 	 * The initial value of the user stack must be such
518 	 * that the total used is larger than the maximum size
519 	 * of the argument list checked in syscall.
520 	 */
521 	i = oargblen+1;
522 	p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
523 	memmove(p, oargb, i);
524 
525 	/*
526 	 * Now push argc and the argv pointers.
527 	 * This isn't strictly correct as the code jumped to by
528 	 * touser in init9.s calls startboot (port/initcode.c) which
529 	 * expects arguments
530 	 * 	startboot(char *argv0, char **argv)
531 	 * not the usual (int argc, char* argv[]), but argv0 is
532 	 * unused so it doesn't matter (at the moment...).
533 	 */
534 	av = (char**)(p - (oargc+2)*sizeof(char*));
535 	ssize = base + BY2PG - PTR2UINT(av);
536 	*av++ = (char*)oargc;
537 	for(i = 0; i < oargc; i++)
538 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
539 	*av = nil;
540 
541 	/*
542 	 * Leave space for the return PC of the
543 	 * caller of initcode.
544 	 */
545 	sp = USTKTOP - ssize - sizeof(void*);
546 }
547 
548 /*
549  *  create the first process
550  */
551 void
userinit(void)552 userinit(void)
553 {
554 	Proc *p;
555 	Segment *s;
556 	KMap *k;
557 	Page *pg;
558 
559 	/* no processes yet */
560 	up = nil;
561 
562 	p = newproc();
563 	p->pgrp = newpgrp();
564 	p->egrp = smalloc(sizeof(Egrp));
565 	p->egrp->ref = 1;
566 	p->fgrp = dupfgrp(nil);
567 	p->rgrp = newrgrp();
568 	p->procmode = 0640;
569 
570 	kstrdup(&eve, "");
571 	kstrdup(&p->text, "*init*");
572 	kstrdup(&p->user, eve);
573 
574 	/*
575 	 * Kernel Stack
576 	 */
577 	p->sched.pc = PTR2UINT(init0);
578 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
579 	p->sched.sp = STACKALIGN(p->sched.sp);
580 
581 	/*
582 	 * User Stack
583 	 *
584 	 * Technically, newpage can't be called here because it
585 	 * should only be called when in a user context as it may
586 	 * try to sleep if there are no pages available, but that
587 	 * shouldn't be the case here.
588 	 */
589 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
590 	p->seg[SSEG] = s;
591 	pg = newpage(1, 0, USTKTOP-BY2PG);
592 	segpage(s, pg);
593 	k = kmap(pg);
594 	bootargs(VA(k));
595 	kunmap(k);
596 
597 	/*
598 	 * Text
599 	 */
600 	s = newseg(SG_TEXT, UTZERO, 1);
601 	s->flushme++;
602 	p->seg[TSEG] = s;
603 	pg = newpage(1, 0, UTZERO);
604 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
605 	segpage(s, pg);
606 	k = kmap(s->map[0]->pages[0]);
607 	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
608 	kunmap(k);
609 
610 	ready(p);
611 }
612 
613 Conf conf;			/* XXX - must go - gag */
614 
615 Confmem sheevamem[nelem(conf.mem)] = {
616 	/*
617 	 * Memory available to Plan 9:
618 	 * the 8K is reserved for ethernet dma access violations to scribble on.
619 	 */
620 	{ .base = PHYSDRAM, .limit = PHYSDRAM + Maxmem - 8*1024, },
621 };
622 ulong memsize = Maxmem;
623 
624 static int
gotmem(uintptr sz)625 gotmem(uintptr sz)
626 {
627 	uintptr addr;
628 
629 	addr = PHYSDRAM + sz - MB;
630 	mmuidmap(addr, 1);
631 	if (probeaddr(addr) >= 0) {
632 		memsize = sz;
633 		return 0;
634 	}
635 	return -1;
636 }
637 
638 void
confinit(void)639 confinit(void)
640 {
641 	int i;
642 	ulong kpages;
643 	uintptr pa;
644 	char *p;
645 
646 	/*
647 	 * Copy the physical memory configuration to Conf.mem.
648 	 */
649 	if(nelem(sheevamem) > nelem(conf.mem)){
650 		iprint("memory configuration botch\n");
651 		exit(1);
652 	}
653 	if((p = getconf("*maxmem")) != nil) {
654 		memsize = strtoul(p, 0, 0) - PHYSDRAM;
655 		if (memsize < 16*MB)		/* sanity */
656 			memsize = 16*MB;
657 	}
658 
659 	/*
660 	 * see if all that memory exists; if not, find out how much does.
661 	 * trapinit must have been called first.
662 	 */
663 	if (gotmem(memsize) < 0 && gotmem(256*MB) < 0 && gotmem(128*MB) < 0) {
664 		iprint("can't find any memory, assuming %dMB\n", Minmem / MB);
665 		memsize = Minmem;
666 	}
667 
668 	sheevamem[0].limit = PHYSDRAM + memsize - 8*1024;
669 	memmove(conf.mem, sheevamem, sizeof(sheevamem));
670 
671 	conf.npage = 0;
672 	pa = PADDR(PGROUND(PTR2UINT(end)));
673 
674 	/*
675 	 *  we assume that the kernel is at the beginning of one of the
676 	 *  contiguous chunks of memory and fits therein.
677 	 */
678 	for(i=0; i<nelem(conf.mem); i++){
679 		/* take kernel out of allocatable space */
680 		if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
681 			conf.mem[i].base = pa;
682 
683 		conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
684 		conf.npage += conf.mem[i].npage;
685 	}
686 
687 	conf.upages = (conf.npage*90)/100;
688 	conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
689 
690 	/* only one processor */
691 	conf.nmach = 1;
692 
693 	/* set up other configuration parameters */
694 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
695 	if(cpuserver)
696 		conf.nproc *= 3;
697 	if(conf.nproc > 2000)
698 		conf.nproc = 2000;
699 	conf.nswap = conf.npage*3;
700 	conf.nswppo = 4096;
701 	conf.nimage = 200;
702 
703 	conf.copymode = 0;		/* copy on write */
704 
705 	/*
706 	 * Guess how much is taken by the large permanent
707 	 * datastructures. Mntcache and Mntrpc are not accounted for
708 	 * (probably ~300KB).
709 	 */
710 	kpages = conf.npage - conf.upages;
711 	kpages *= BY2PG;
712 	kpages -= conf.upages*sizeof(Page)
713 		+ conf.nproc*sizeof(Proc)
714 		+ conf.nimage*sizeof(Image)
715 		+ conf.nswap
716 		+ conf.nswppo*sizeof(Page);
717 	mainmem->maxsize = kpages;
718 	if(!cpuserver)
719 		/*
720 		 * give terminals lots of image memory, too; the dynamic
721 		 * allocation will balance the load properly, hopefully.
722 		 * be careful with 32-bit overflow.
723 		 */
724 		imagmem->maxsize = kpages;
725 }
726 
727 int
cmpswap(long * addr,long old,long new)728 cmpswap(long *addr, long old, long new)
729 {
730 	return cas32(addr, old, new);
731 }
732