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