xref: /plan9-contrib/sys/src/9/vt4/main.c (revision d6dfd9ef91cf0fa8514a249d5f2a550978c19369)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../ip/ip.h"
7 
8 #include <pool.h>
9 #include <tos.h>
10 
11 #include "qtm.h"
12 
13 #include "init.h"
14 
15 #define	MAXCONF		32
16 
17 ulong dverify = 0x01020304;
18 ulong bverify;
19 int securemem;
20 Conf conf;
21 
22 /*
23  * Option arguments from the command line.
24  * oargv[0] is the boot file.
25  * Optionsinit() is called from multiboot()
26  * or some other machine-dependent place
27  * to set it all up.
28  */
29 static int oargc;
30 static char* oargv[20];
31 static char oargb[128];
32 static int oargblen;
33 static char oenv[4096];
34 
35 static uintptr sp;		/* XXX - must go - user stack of init proc */
36 
37 static char confname[MAXCONF][KNAMELEN];
38 static char *confval[MAXCONF];
39 static int nconf;
40 
41 static void
mypanic(Pool * p,char * fmt,...)42 mypanic(Pool *p, char *fmt, ...)
43 {
44 	USED(p, fmt);
45 	print("malloc panic\n");
46 	delay(1000);
47 	splhi();
48 	for (;;)
49 		;
50 }
51 
52 void
machninit(int machno)53 machninit(int machno)
54 {
55 	if (machno >= MAXMACH)
56 		panic("machno %d >= MAXMACH %d", machno, MAXMACH);
57 	conf.nmach++;
58 	m = MACHP(machno);
59 	memset(m, 0, sizeof(Mach));
60 	m->machno = machno;
61 	m->cputype = getpvr()>>16;   /* OWN[0:11] and PCF[12:15] fields */
62 	m->delayloop = 20000;	/* initial estimate only; set by clockinit */
63  	m->perf.period = 1;
64 	/* other values set by archreset */
65 }
66 
67 void
cpuidprint(void)68 cpuidprint(void)
69 {
70 	char name[64];
71 
72 	cputype2name(name, sizeof name);
73 	print("cpu%d: %ldMHz PowerPC %s\n", m->machno, m->cpuhz/1000000, name);
74 }
75 
76 void
mach0init(void)77 mach0init(void)
78 {
79 	conf.nmach = 0;
80 
81 	machninit(0);
82 
83 	active.machs = 1;
84 	active.exiting = 0;
85 }
86 
87 static void
setconf(char * name,char * val)88 setconf(char *name, char *val)
89 {
90 	strncpy(confname[nconf], name, KNAMELEN);
91 	kstrdup(&confval[nconf], val);
92 	nconf++;
93 }
94 
95 static void
plan9iniinit(void)96 plan9iniinit(void)
97 {
98 	/* virtex configuration */
99 	setconf("nvram", "/boot/nvram");
100 	setconf("nvroff", "0");
101 	setconf("nvrlen", "512");
102 
103 	setconf("aoeif", "ether0");
104 	setconf("aoedev", "e!#æ/aoe/1.0");
105 }
106 
107 char*
getenv(char * name,char * buf,int n)108 getenv(char* name, char* buf, int n)
109 {
110 	char *e, *p, *q;
111 
112 	p = oenv;
113 	while(*p != 0){
114 		if((e = strchr(p, '=')) == nil)
115 			break;
116 		for(q = name; p < e; p++){
117 			if(*p != *q)
118 				break;
119 			q++;
120 		}
121 		if(p == e && *q == 0){
122 			strecpy(buf, buf+n, e+1);
123 			return buf;
124 		}
125 		p += strlen(p)+1;
126 	}
127 
128 	return nil;
129 }
130 
131 static void
optionsinit(char * s)132 optionsinit(char* s)
133 {
134 	char *o;
135 
136 	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
137 	if(getenv("bootargs", o, o - oargb) != nil)
138 		*(o-1) = ' ';
139 
140 	oargblen = strlen(oargb);
141 	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
142 	oargv[oargc] = nil;
143 }
144 
145 void
main(void)146 main(void)
147 {
148 	int machno;
149 
150 	/* entry to main pushed stuff onto the stack. */
151 
152 //	memset(edata, 0, (ulong)end-(ulong)edata);
153 
154 	machno = getpir();
155 	if (machno > 0)
156 		startcpu(machno);
157 
158 //	dcrcompile();
159 	if (dverify != 0x01020304) {
160 		uartlputs("data segment not initialised\n");
161 		panic("data segment not initialised");
162 	}
163 	if (bverify != 0) {
164 		uartlputs("bss segment not zeroed\n");
165 		panic("bss segment not zeroed");
166 	}
167 	mach0init();
168 	archreset();
169 	quotefmtinstall();
170 	optionsinit("/boot/boot boot");
171 //	archconsole();
172 
173 	meminit();
174 	confinit();
175 	mmuinit();
176 	xinit();			/* xinit would print if it could */
177 	trapinit();
178 	qtminit();
179 	ioinit();
180 	uncinit();
181 	printinit();
182 	uartliteconsole();
183 
184 	mainmem->flags |= POOL_ANTAGONISM;
185 	mainmem->panic = mypanic;
186 	ethermedium.maxtu = 1512;   /* must be multiple of 4 for temac's dma */
187 
188 //	print("\n\nPlan 9k H\n");	/* already printed by l.s */
189 	plan9iniinit();
190 	timersinit();
191 	clockinit();
192 
193 	dma0init();			/* does not start kprocs; see init0 */
194 	fpuinit();
195 	procinit0();
196 	initseg();
197 	links();
198 
199 	chandevreset();
200 	okprint = 1;			/* only now can we print */
201 	barriers();
202 	dcflush((uintptr)&okprint, sizeof okprint);
203 
204 	cpuidprint();
205 
206 	print("%d Hz clock", HZ);
207 	print("; memory size %,ud (%#ux)\n", (uint)memsz, (uint)memsz);
208 
209 	pageinit();
210 	swapinit();
211 	userinit();
212 	active.thunderbirdsarego = 1;
213 	dcflush((uintptr)&active.thunderbirdsarego,
214 		sizeof active.thunderbirdsarego);
215 	schedinit();
216 	/* no return */
217 	panic("schedinit returned");
218 }
219 
220 void
confinit(void)221 confinit(void)
222 {
223 	char *p;
224 	int i, userpcnt;
225 	ulong kpages;
226 
227 	if(p = getconf("*kernelpercent"))
228 		userpcnt = 100 - strtol(p, 0, 0);
229 	else
230 		userpcnt = 85;
231 
232 	conf.npage = 0;
233 	for(i=0; i<nelem(conf.mem); i++)
234 		conf.npage += conf.mem[i].npage;
235 
236 	/* see machninit for nmach setting */
237 	conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
238 	if(conf.nproc > 2000)
239 		conf.nproc = 2000;
240 	conf.nimage = 200;
241 	conf.nswap = conf.nproc*80;
242 	conf.nswppo = 4096;
243 	conf.copymode = 0;			/* copy on write */
244 
245 	if(userpcnt < 10)
246 		userpcnt = 60;
247 	kpages = conf.npage - (conf.npage*userpcnt)/100;
248 
249 	conf.upages = conf.npage - kpages;
250 	conf.ialloc = (kpages/2)*BY2PG;
251 
252 	kpages *= BY2PG;
253 	kpages -= conf.upages*sizeof(Page)
254 		+ conf.nproc*sizeof(Proc)
255 		+ conf.nimage*sizeof(Image)
256 		+ conf.nswap
257 		+ conf.nswppo*sizeof(Page);
258 	mainmem->maxsize = kpages;
259 }
260 
261 void
init0(void)262 init0(void)
263 {
264 	int i;
265 	char buf[2*KNAMELEN];
266 
267 	assert(up != nil);
268 	up->nerrlab = 0;
269 	barriers();
270 	intrack(~0);
271 	clrmchk();
272 	barriers();
273 	spllo();
274 
275 	/*
276 	 * These are o.k. because rootinit is null.
277 	 * Then early kproc's will have a root and dot.
278 	 */
279 	up->slash = namec("#/", Atodir, 0, 0);
280 	pathclose(up->slash->path);
281 	up->slash->path = newpath("/");
282 	up->dot = cclone(up->slash);
283 
284 	dmainit();			/* starts dma kprocs */
285 	devtabinit();
286 
287 	if(!waserror()){
288 		snprint(buf, sizeof(buf), "power %s", conffile);
289 		ksetenv("terminal", buf, 0);
290 		ksetenv("cputype", "power", 0);
291 		if(cpuserver)
292 			ksetenv("service", "cpu", 0);
293 		else
294 			ksetenv("service", "terminal", 0);
295 
296 		/* virtex configuration */
297 		ksetenv("nvram", "/boot/nvram", 0);
298 		ksetenv("nvroff", "0", 0);
299 		ksetenv("nvrlen", "512", 0);
300 
301 		ksetenv("nobootprompt", "tcp", 0);
302 
303 		poperror();
304 	}
305 	for(i = 0; i < nconf; i++){
306 		if(confval[i] == nil)
307 			continue;
308 		if(confname[i][0] != '*'){
309 			if(!waserror()){
310 				ksetenv(confname[i], confval[i], 0);
311 				poperror();
312 			}
313 		}
314 		if(!waserror()){
315 			ksetenv(confname[i], confval[i], 1);
316 			poperror();
317 		}
318 	}
319 
320 	kproc("alarm", alarmkproc, 0);
321 	if (securemem)
322 	 	kproc("mutate", mutateproc, 0);
323 	else
324 		print("no secure memory found\n");
325 
326 	/*
327 	 * The initial value of the user stack must be such
328 	 * that the total used is larger than the maximum size
329 	 * of the argument list checked in syscall.
330 	 */
331 	sync();
332 	isync();
333 	touser(sp);
334 }
335 
336 static void
bootargs(uintptr base)337 bootargs(uintptr base)
338 {
339 	int i;
340 	ulong ssize;
341 	char **av, *p;
342 
343 	/*
344 	 * Push the boot args onto the stack.
345 	 * The initial value of the user stack must be such
346 	 * that the total used is larger than the maximum size
347 	 * of the argument list checked in syscall.
348 	 */
349 	i = oargblen+1;
350 	p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(up->s.args) - i));
351 	memmove(p, oargb, i);
352 
353 	/*
354 	 * Now push argc and the argv pointers.
355 	 * This isn't strictly correct as the code jumped to by
356 	 * touser in init9.s calls startboot (port/initcode.c) which
357 	 * expects arguments
358 	 * 	startboot(char *argv0, char **argv)
359 	 * not the usual (int argc, char* argv[]), but argv0 is
360 	 * unused so it doesn't matter (at the moment...).
361 	 */
362 	av = (char**)(p - (oargc+2)*sizeof(char*));
363 	ssize = base + BY2PG - PTR2UINT(av);
364 	*av++ = (char*)oargc;
365 	for(i = 0; i < oargc; i++)
366 		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
367 	*av = nil;
368 
369 	/*
370 	 * Leave space for the return PC of the
371 	 * caller of initcode.
372 	 */
373 	sp = USTKTOP - ssize - sizeof(void*);
374 }
375 
376 void
userinit(void)377 userinit(void)
378 {
379 	Proc *p;
380 	Segment *s;
381 	KMap *k;
382 	Page *pg;
383 
384 	/* no processes yet */
385 	up = nil;
386 
387 	p = newproc();
388 	p->pgrp = newpgrp();
389 	p->egrp = smalloc(sizeof(Egrp));
390 	p->egrp->ref = 1;
391 	p->fgrp = dupfgrp(nil);
392 	p->rgrp = newrgrp();
393 	p->procmode = 0640;
394 
395 	kstrdup(&eve, "");
396 	kstrdup(&p->text, "*init*");
397 	kstrdup(&p->user, eve);
398 
399 	/*
400 	 * Kernel Stack
401 	 */
402 	p->sched.pc = PTR2UINT(init0);
403 	p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
404 	p->sched.sp = STACKALIGN(p->sched.sp);
405 
406 	/*
407 	 * User Stack
408 	 *
409 	 * Technically, newpage can't be called here because it
410 	 * should only be called when in a user context as it may
411 	 * try to sleep if there are no pages available, but that
412 	 * shouldn't be the case here.
413 	 */
414 	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
415 	p->seg[SSEG] = s;
416 	pg = newpage(1, 0, USTKTOP-BY2PG);
417 	segpage(s, pg);
418 	k = kmap(pg);
419 	bootargs(VA(k));
420 	kunmap(k);
421 
422 	/*
423 	 * Text
424 	 */
425 	s = newseg(SG_TEXT, UTZERO, 1);
426 	s->flushme++;
427 	p->seg[TSEG] = s;
428 	pg = newpage(1, 0, UTZERO);
429 	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
430 	segpage(s, pg);
431 	k = kmap(s->map[0]->pages[0]);
432 	memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
433 	sync();
434 	kunmap(k);
435 
436 	ready(p);
437 }
438 
439 /*
440  * power-saving wait for interrupt when nothing ready.
441  * ../port/proc.c should really call this splhi itself
442  * to avoid the race avoided here by the call to anyready
443  */
444 void
idlehands(void)445 idlehands(void)
446 {
447 	int s, oldbits;
448 
449 	/* we only use one processor, no matter what */
450 //	if (conf.nmach > 1)
451 //		return;
452 	s = splhi();
453 	if(!anyready()) {
454 		oldbits = lightstate(Ledidle);
455 		putmsr(getmsr() | MSR_WE | MSR_EE | MSR_CE); /* MSR_DE too? */
456 		lightstate(oldbits);
457 	}
458 	splx(s);
459 }
460 
461 /*
462  *  set mach dependent process state for a new process
463  */
464 void
procsetup(Proc * p)465 procsetup(Proc* p)
466 {
467 	fpusysprocsetup(p);
468 }
469 
470 /*
471  *  Save the mach dependent part of the process state.
472  */
473 void
procsave(Proc * p)474 procsave(Proc *p)
475 {
476 	fpuprocsave(p);
477 }
478 
479 void
shutdown(int ispanic)480 shutdown(int ispanic)
481 {
482 	int ms, once;
483 
484 	lock(&active);
485 	if(ispanic)
486 		active.ispanic = ispanic;
487 	else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
488 		active.ispanic = 0;
489 	once = active.machs & (1<<m->machno);
490 	active.machs &= ~(1<<m->machno);
491 	active.exiting = 1;
492 	unlock(&active);
493 
494 	if(once)
495 		print("cpu%d: exiting\n", m->machno);
496 	spllo();
497 	for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
498 		delay(TK2MS(2));
499 		if(active.machs == 0 && consactive() == 0)
500 			break;
501 	}
502 
503 #ifdef notdef
504 	if(active.ispanic && m->machno == 0){
505 		if(cpuserver)
506 			delay(30000);
507 		else
508 			for(;;)
509 				halt();
510 	}
511 	else
512 #endif /* notdef */
513 		delay(1000);
514 }
515 
516 void
writeconf(void)517 writeconf(void)
518 {
519 	char *p, *q;
520 	int n;
521 
522 	p = getconfenv();
523 
524 	if(waserror()) {
525 		free(p);
526 		nexterror();
527 	}
528 
529 	/* convert to name=value\n format */
530 	for(q=p; *q; q++) {
531 		q += strlen(q);
532 		*q = '=';
533 		q += strlen(q);
534 		*q = '\n';
535 	}
536 	n = q - p + 1;
537 	if(n >= BOOTARGSLEN)
538 		error("kernel configuration too large");
539 	memset(BOOTLINE, 0, BOOTLINELEN);	/* zero 9load boot line */
540 	memmove(BOOTARGS, p, n);
541 	poperror();
542 	free(p);
543 }
544 
545 void
archreboot(void)546 archreboot(void)
547 {
548 	splhi();
549 	iprint("reboot requested; going into wait state\n");
550 	for(;;)
551 		putmsr(getmsr() | MSR_WE);
552 }
553 
554 void
exit(int ispanic)555 exit(int ispanic)
556 {
557 	shutdown(ispanic);
558 	archreboot();
559 }
560 
561 static int
findconf(char * name)562 findconf(char *name)
563 {
564 	int i;
565 
566 	for(i = 0; i < nconf; i++)
567 		if(cistrcmp(confname[i], name) == 0)
568 			return i;
569 	return -1;
570 }
571 
572 void
addconf(char * name,char * val)573 addconf(char *name, char *val)
574 {
575 	int i;
576 
577 	i = findconf(name);
578 	if(i < 0){
579 		if(val == nil || nconf >= MAXCONF)
580 			return;
581 		i = nconf++;
582 		strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
583 	}
584 	confval[i] = val;
585 }
586 
587 char*
getconf(char * name)588 getconf(char *name)
589 {
590 	int i;
591 
592 	i = findconf(name);
593 	if(i >= 0)
594 		return confval[i];
595 	return nil;
596 }
597 
598 void
dump(void * vaddr,int words)599 dump(void *vaddr, int words)
600 {
601 	ulong *addr;
602 
603 	addr = vaddr;
604 	while (words-- > 0)
605 		print("%.8lux%c", *addr++, words % 8 == 0? '\n': ' ');
606 }
607