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