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