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