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 #include "../ip/ip.h"
8 #include <pool.h>
9 #include <tos.h>
10 #include <bootexec.h>
11 #include "init.h"
12 #include "reboot.h"
13
14 enum {
15 /* space for syscall args, return PC, top-of-stack struct */
16 Stkheadroom = sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
17 };
18
19 typedef struct mipsexec Mipsexec;
20
21 #define MAXCONF 64
22 #define CONFBUFLEN 4096
23 #define MAXBOOTENV 256
24
25 /* only for reboot */
26 #define BOOTARGS ((char*)(CONFADDR))
27 #define BOOTARGSLEN CONFBUFLEN
28 #define CONFARGVLEN (MAXCONF*BY2WD)
29
30 /* args passed by boot loader for main() */
31 int _argc;
32 char **_argv;
33 char **_env;
34 static char *bootenvname[MAXBOOTENV];
35 static char *bootenvval[MAXBOOTENV];
36 static int nenv;
37
38 /* plan9.ini */
39 static char confbuf[CONFBUFLEN];
40 static char *confname[MAXCONF];
41 static char *confval[MAXCONF];
42 static int nconf;
43
44 /*
45 * Option arguments from the command line.
46 * oargv[0] is the boot file.
47 */
48 static int oargc;
49 static char* oargv[20];
50 static char oargb[128];
51 static int oargblen;
52
53 static uintptr sp; /* XXX - must go - user stack of init proc */
54
55 /*
56 * software tlb simulation
57 */
58 static Softtlb stlb[MAXMACH][STLBSIZE];
59
60 Mach *machaddr[MAXMACH];
61 Conf conf;
62 ulong memsize;
63 FPsave initfp;
64
65 int normalprint;
66 ulong cpufreq;
67
68 /*
69 * initialize a processor's mach structure. each processor does this
70 * for itself.
71 */
72 void
machinit(void)73 machinit(void)
74 {
75 /* Ensure CU1 is off */
76 clrfpintr();
77
78 m->stb = &stlb[m->machno][0];
79
80 clockinit();
81 }
82
83 static void
optionsinit(char * s)84 optionsinit(char* s)
85 {
86 strecpy(oargb, oargb+sizeof(oargb), s);
87
88 oargblen = strlen(oargb);
89 oargc = tokenize(oargb, oargv, nelem(oargv)-1);
90 oargv[oargc] = nil;
91 }
92
93 void
plan9iniinit(void)94 plan9iniinit(void)
95 {
96 char *cp;
97 int i;
98
99 nconf = 0;
100 if(_argv != nil){
101 memmove(confbuf, _argv[0], sizeof(confbuf));
102 for(i=1; i<_argc && nconf<MAXCONF; i++){
103 _argv[i] += confbuf - _argv[0];
104 if(*_argv[i] == '#')
105 continue;
106 cp = strchr(_argv[i], '=');
107 if(cp == nil)
108 continue;
109 *cp++ = '\0';
110 confname[nconf] = _argv[i];
111 confval[nconf] = cp;
112 nconf++;
113 }
114 }
115
116 nenv = 0;
117 if(_env != nil)
118 for(i=0; _env[i] != nil && nenv<MAXBOOTENV; i++){
119 if(*_env[i] == '#')
120 continue;
121 cp = strchr(_env[i], '=');
122 if(cp == nil)
123 continue;
124 *cp++ = '\0';
125 bootenvname[nenv] = _env[i];
126 bootenvval[nenv] = cp;
127 nenv++;
128 }
129 }
130
131 static int
findconf(char * name)132 findconf(char *name)
133 {
134 int i;
135
136 for(i = 0; i < nconf; i++)
137 if(cistrcmp(confname[i], name) == 0)
138 return i;
139 return -1;
140 }
141
142 char*
getconf(char * name)143 getconf(char *name)
144 {
145 int i;
146
147 i = findconf(name);
148 if(i >= 0)
149 return confval[i];
150 return nil;
151 }
152
153 static int
findbootenv(char * name)154 findbootenv(char *name)
155 {
156 int i;
157
158 for(i = 0; i < nenv; i++)
159 if(cistrcmp(bootenvname[i], name) == 0)
160 return i;
161 return -1;
162 }
163
164 static char*
getbootenv(char * name)165 getbootenv(char *name)
166 {
167 int i;
168
169 i = findbootenv(name);
170 if(i >= 0)
171 return bootenvval[i];
172 return nil;
173 }
174
175 void
confinit(void)176 confinit(void)
177 {
178 char *p;
179 int i;
180 ulong kpages, ktop;
181 ulong maxmem, highmemsize;
182
183 /* memory size */
184 memsize = MEMSIZE;
185 if((p = getbootenv("memsize")) != nil)
186 memsize = strtoul(p, 0, 0) * MB;
187 highmemsize = 0;
188 if((p = getbootenv("highmemsize")) != nil)
189 highmemsize = strtoul(p, 0, 0) * MB;
190 if((p = getconf("*maxmem")) != nil){
191 maxmem = strtoul(p, 0, 0);
192 memsize = MIN(memsize, maxmem);
193 maxmem -= memsize;
194 highmemsize = MIN(highmemsize, maxmem);
195 if(memsize < 16*MB) /* sanity */
196 memsize = 16*MB;
197 }
198
199 /* set up other configuration parameters */
200 conf.nproc = 2000;
201 conf.nswap = 262144;
202 conf.nswppo = 4096;
203 conf.nimage = 200;
204
205 /*
206 * divide memory to user pages and kernel.
207 */
208 conf.mem[0].base = ktop = PADDR(PGROUND((ulong)end));
209 conf.mem[0].npage = memsize/BY2PG - ktop/BY2PG;
210
211 conf.mem[1].base = HIGHMEM;
212 conf.mem[1].npage = highmemsize/BY2PG;
213
214 conf.npage = 0;
215 for(i=0; i<nelem(conf.mem); i++)
216 conf.npage += conf.mem[i].npage;
217
218 kpages = conf.npage - (conf.npage*80)/100;
219 if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
220 kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
221 kpages += (conf.nproc*KSTACK)/BY2PG;
222 }
223 conf.upages = conf.npage - kpages;
224 conf.ialloc = (kpages/2)*BY2PG;
225
226 kpages *= BY2PG;
227 kpages -= conf.upages*sizeof(Page)
228 + conf.nproc*sizeof(Proc)
229 + conf.nimage*sizeof(Image)
230 + conf.nswap
231 + conf.nswppo*sizeof(Page);
232 mainmem->maxsize = kpages;
233
234 /*
235 * set up CPU's mach structure
236 * cpu0's was zeroed in main() and our stack is in Mach, so don't zero it.
237 */
238 m->machno = 0;
239 m->hz = cpufreq; /* initial guess at MHz */
240 m->speed = m->hz / Mhz;
241 conf.nmach = 1;
242
243 conf.nuart = 1;
244 conf.copymode = 0; /* copy on write */
245 }
246
247 void
procrestore(Proc * p)248 procrestore(Proc *p)
249 {
250 uvlong t;
251
252 if(p->kp)
253 return;
254 cycles(&t);
255 p->pcycles -= t;
256 }
257
258 /*
259 * Save the mach dependent part of the process state.
260 */
261 void
procsave(Proc * p)262 procsave(Proc *p)
263 {
264 uvlong t;
265
266 cycles(&t);
267 p->pcycles += t;
268 //fpuprocsave(); // XXX
269 }
270
271 static void
fmtinit(void)272 fmtinit(void)
273 {
274 printinit();
275 quotefmtinstall();
276 /* ipreset installs these when chandevreset runs */
277 fmtinstall('i', eipfmt);
278 fmtinstall('I', eipfmt);
279 fmtinstall('E', eipfmt);
280 fmtinstall('V', eipfmt);
281 fmtinstall('M', eipfmt);
282 }
283
284 /*
285 * setup MIPS trap vectors
286 */
287 void
vecinit(void)288 vecinit(void)
289 {
290 memmove((ulong*)UTLBMISS, (ulong*)vector0, 0x80);
291 memmove((ulong*)XEXCEPTION, (ulong*)vector0, 0x80);
292 memmove((ulong*)CACHETRAP, (ulong*)vector100, 0x80);
293 memmove((ulong*)EXCEPTION, (ulong*)vector180, 0x80);
294 /* 0x200 not used in looongson 2e */
295 icflush((ulong*)UTLBMISS, 4*1024);
296
297 setstatus(getstatus() & ~BEV);
298 }
299
300 static void
prcpuid(void)301 prcpuid(void)
302 {
303 ulong cpuid, cfg;
304 char *cpu;
305
306 cpuid = prid();
307 cfg = getconfig();
308 if (((cpuid>>16) & MASK(8)) == 0) /* vendor */
309 cpu = "old mips";
310 else if (((cpuid>>16) & MASK(8)) == 1)
311 switch ((cpuid>>8) & MASK(8)) { /* processor */
312 case 0x93:
313 cpu = "mips 24k";
314 break;
315 case 0x96:
316 cpu = "mips 24ke";
317 break;
318 default:
319 cpu = "mips";
320 break;
321 }
322 else
323 cpu = "other mips";
324 delay(200);
325 print("cpu%d: %ldMHz %s %se 0x%ulx v%ld.%ld rev %ld has fpu\n",
326 m->machno, m->hz / Mhz, cpu, cfg & (1<<15)? "b": "l",
327 (cpuid>>8) & MASK(8), (cpuid>>5) & MASK(3), (cpuid>>2) & MASK(3),
328 cpuid & MASK(2));
329 delay(200);
330
331 print("cpu%d: %d tlb entries, using %dK pages\n", m->machno,
332 64, BY2PG/1024);
333 delay(50);
334 print("cpu%d: l1 i cache: %d sets 4 ways 32 bytes/line\n", m->machno,
335 32 << ((cfg>>9) & MASK(3)));
336 delay(50);
337 print("cpu%d: l1 d cache: %d sets 4 ways 32 bytes/line\n", m->machno,
338 32 << ((cfg>>6) & MASK(3)));
339 delay(500);
340 }
341
342 static int
ckpagemask(ulong mask,ulong size)343 ckpagemask(ulong mask, ulong size)
344 {
345 int s;
346 ulong pm;
347
348 s = splhi();
349 setpagemask(mask);
350 pm = getpagemask();
351 splx(s);
352 if(pm != mask){
353 iprint("page size %ldK not supported on this cpu; "
354 "mask %#lux read back as %#lux\n", size/1024, mask, pm);
355 return -1;
356 }
357 return 0;
358 }
359
360 void
init0(void)361 init0(void)
362 {
363 char buf[128];
364 int i;
365
366 up->nerrlab = 0;
367
368 spllo();
369
370 /*
371 * These are o.k. because rootinit is null.
372 * Then early kproc's will have a root and dot.
373 */
374 up->slash = namec("#/", Atodir, 0, 0);
375 pathclose(up->slash->path);
376 up->slash->path = newpath("/");
377 up->dot = cclone(up->slash);
378
379 chandevinit();
380
381 if(!waserror()){
382 ksetenv("cputype", "spim", 0);
383 snprint(buf, sizeof buf, "spim %s loongson 2e", conffile);
384 ksetenv("terminal", buf, 0);
385 if(cpuserver)
386 ksetenv("service", "cpu", 0);
387 else
388 ksetenv("service", "terminal", 0);
389 // ksetenv("nobootprompt", "local!/boot/bzroot", 0); // for bzroot
390 ksetenv("nvram", "/boot/nvram", 0);
391 /* convert plan9.ini variables to #e and #ec */
392 for(i = 0; i < nconf; i++) {
393 if(*confname[i] == '*')
394 continue;
395 ksetenv(confname[i], confval[i], 0);
396 ksetenv(confname[i], confval[i], 1);
397 }
398 poperror();
399 }
400 kproc("alarm", alarmkproc, 0);
401 i8250console();
402 touser(sp);
403 }
404
405 static void
bootargs(uintptr base)406 bootargs(uintptr base)
407 {
408 int i;
409 ulong ssize;
410 char **av, *p;
411
412 /*
413 * Push the boot args onto the stack.
414 * The initial value of the user stack must be such
415 * that the total used is larger than the maximum size
416 * of the argument list checked in syscall.
417 */
418 i = oargblen+1;
419 p = UINT2PTR(STACKALIGN(base + BY2PG - Stkheadroom - i));
420 memmove(p, oargb, i);
421
422 /*
423 * Now push the argv pointers.
424 * The code jumped to by touser in l.s expects arguments
425 * main(char* argv0, ...)
426 * and calls
427 * startboot("/boot/boot", &argv0)
428 * not the usual (int argc, char* argv[])
429 */
430 av = (char**)(p - (oargc+1)*sizeof(char*));
431 ssize = base + BY2PG - PTR2UINT(av);
432 for(i = 0; i < oargc; i++)
433 *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
434 *av = nil;
435 sp = USTKTOP - ssize;
436 }
437
438 void
userinit(void)439 userinit(void)
440 {
441 Proc *p;
442 KMap *k;
443 Page *pg;
444 Segment *s;
445
446 p = newproc();
447 p->pgrp = newpgrp();
448 p->egrp = smalloc(sizeof(Egrp));
449 p->egrp->ref = 1;
450 p->fgrp = dupfgrp(nil);
451 p->rgrp = newrgrp();
452 p->procmode = 0640;
453
454 kstrdup(&eve, "");
455 kstrdup(&p->text, "*init*");
456 kstrdup(&p->user, eve);
457
458 p->fpstate = FPinit;
459 p->fpsave.fpstatus = initfp.fpstatus;
460
461 /*
462 * Kernel Stack
463 */
464 p->sched.pc = (ulong)init0;
465 p->sched.sp = (ulong)p->kstack+KSTACK-Stkheadroom;
466 p->sched.sp = STACKALIGN(p->sched.sp);
467
468 /*
469 * User Stack
470 *
471 * Technically, newpage can't be called here because it
472 * should only be called when in a user context as it may
473 * try to sleep if there are no pages available, but that
474 * shouldn't be the case here.
475 */
476 s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
477 p->seg[SSEG] = s;
478 pg = newpage(1, 0, USTKTOP-BY2PG);
479 memset(pg->cachectl, PG_DATFLUSH, sizeof(pg->cachectl));
480 segpage(s, pg);
481 k = kmap(pg);
482 bootargs(VA(k));
483 kunmap(k);
484
485 /*
486 * Text
487 */
488 s = newseg(SG_TEXT, UTZERO, 1);
489 s->flushme++;
490 p->seg[TSEG] = s;
491 pg = newpage(1, 0, UTZERO);
492 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
493 segpage(s, pg);
494 k = kmap(s->map[0]->pages[0]);
495 memset((void*)VA(k), 0, BY2PG);
496 memmove((ulong*)VA(k), initcode, sizeof initcode);
497 kunmap(k);
498
499 ready(p);
500 }
501
502 /* called from rebootcmd() */
503 int
parsemipsboothdr(Chan * c,ulong magic,Execvals * evp)504 parsemipsboothdr(Chan *c, ulong magic, Execvals *evp)
505 {
506 long extra;
507 Mipsexec me;
508
509 /*
510 * BOOT_MAGIC is sometimes defined like this:
511 * #define BOOT_MAGIC (0x160<<16) || magic == ((0x160<<16)|3)
512 * so we can only use it in a fairly stylized manner.
513 */
514 if(magic == BOOT_MAGIC) {
515 c->offset = 0; /* back up */
516 readn(c, &me, sizeof me);
517 /* if binary is -H1, read an extra long */
518 if (l2be(me.amagic) == 0407 && me.nscns == 0)
519 readn(c, &extra, sizeof extra);
520 evp->entry = l2be(me.mentry);
521 evp->textsize = l2be(me.tsize);
522 evp->datasize = l2be(me.dsize);
523 return 0;
524 } else
525 return -1;
526 }
527
528 void
main(void)529 main(void)
530 {
531 extern char edata[], end[];
532
533 m = (Mach*)MACHADDR;
534 memset(m, 0, sizeof(Mach)); /* clear Mach */
535 m->machno = 0;
536 machaddr[m->machno] = m;
537 up = nil;
538 memset(edata, 0, end-edata); /* clear bss */
539
540 optionsinit("/boot/boot boot");
541 plan9iniinit();
542 confinit();
543 savefpregs(&initfp);
544
545 machinit();
546 active.exiting = 0;
547 active.machs = 1;
548
549 kmapinit();
550 xinit();
551 screeninit();
552
553 ckpagemask(PGSZ, BY2PG);
554 tlbinit();
555 machwire();
556
557 timersinit();
558 fmtinit();
559 vecinit();
560
561 normalprint = 1;
562 print("\nPlan 9\n");
563 print("\0\0\0\0\0\0\0"); // XXX 0c bug fixed -- leave this for sanity
564 prcpuid();
565 if(PTECACHABILITY == PTENONCOHERWT)
566 print("caches configured as write-through\n");
567 // xsummary();
568
569 i8259init();
570 kbdinit();
571 if(conf.monitor)
572 swcursorinit();
573
574 pageinit();
575 procinit0();
576 initseg();
577 links();
578 chandevreset();
579
580 swapinit();
581 userinit();
582 parseboothdr = parsemipsboothdr;
583 schedinit();
584 panic("schedinit returned");
585 }
586
587 static void
writeconf(void)588 writeconf(void)
589 {
590 char *p, *q;
591 int n;
592
593 p = getconfenv();
594
595 if(waserror()) {
596 free(p);
597 nexterror();
598 }
599
600 /* convert to name=value\0 format */
601 _argc = 1; /* skip _argv[0] */
602 _argv = (void*)CONFARGV;
603 _argv[0] = BOOTARGS;
604 for(q=p; *q; q++) {
605 _argv[_argc] = (char*)((ulong)BOOTARGS + (q - p));
606 _argc++;
607 q += strlen(q);
608 *q = '=';
609 q += strlen(q);
610 }
611 n = q - p + 1;
612 _env = &_argv[_argc];
613
614 if(n >= BOOTARGSLEN || (ulong)_env >= CONFARGV + CONFARGVLEN)
615 error("kernel configuration too large");
616 memmove(BOOTARGS, p, n);
617 memset(BOOTARGS + n, '\0', BOOTARGSLEN - n);
618 memset(_env, 0, CONFARGV + CONFARGVLEN - (ulong)_env);
619
620 poperror();
621 free(p);
622 }
623
624 static void
shutdown(int ispanic)625 shutdown(int ispanic)
626 {
627 int ms, once;
628
629 ilock(&active);
630 if(ispanic)
631 active.ispanic = ispanic;
632 else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
633 active.ispanic = 0;
634 once = active.machs & (1<<m->machno);
635 /*
636 * setting exiting will make hzclock() on each processor call exit(0),
637 * which calls shutdown(0) and idles non-bootstrap cpus and returns
638 * on bootstrap processors (to permit a reboot). clearing our bit
639 * in machs avoids calling exit(0) from hzclock() on this processor.
640 */
641 active.machs &= ~(1<<m->machno);
642 active.exiting = 1;
643 iunlock(&active);
644
645 if(once) {
646 delay(m->machno*1000); /* stagger them */
647 iprint("cpu%d: exiting\n", m->machno);
648 }
649 spllo();
650 for(ms = MAXMACH * 1000; ms > 0; ms -= TK2MS(2)){
651 delay(TK2MS(2));
652 if(active.machs == 0 && consactive() == 0)
653 break;
654 }
655 delay(100);
656 }
657
658 void
exit(int ispanic)659 exit(int ispanic)
660 {
661 int timer;
662
663 delay(1000);
664 shutdown(ispanic);
665 timer = 0;
666 while(active.machs || consactive()) {
667 if(timer++ > 400)
668 break;
669 delay(10);
670 }
671 delay(1000);
672 splhi();
673
674 setstatus(BEV);
675 coherence();
676
677 iprint("exit: awaiting reset\n");
678 delay(1000); /* await a reset */
679
680 if(!active.ispanic) {
681 iprint("exit: jumping to rom\n");
682 *Reset |= Rstcpucold; /* cpu cold reset */
683 }
684
685 iprint("exit: looping\n");
686 for(;;);
687 }
688
689 /*
690 * the new kernel is already loaded at address `code'
691 * of size `size' and entry point `entry'.
692 */
693 void
reboot(void * entry,void * code,ulong size)694 reboot(void *entry, void *code, ulong size)
695 {
696 void (*f)(ulong, ulong, ulong, ulong);
697
698 writeconf();
699
700 /*
701 * the boot processor is cpu0. execute this function on it
702 * so that the new kernel has the same cpu0.
703 */
704 if(m->machno != 0) {
705 procwired(up, 0);
706 sched();
707 }
708 if(m->machno != 0)
709 print("on cpu%d (not 0)!\n", m->machno);
710
711 if(code == nil || entry == nil)
712 exit(1);
713
714 shutdown(0);
715
716 /*
717 * should be the only processor running now
718 */
719 iprint("reboot: entry %#p code %#p size %ld\n", entry, code, size);
720 iprint("code[0] = %#lux\n", *(ulong *)code);
721
722 /* turn off buffered serial console */
723 serialoq = nil;
724 kprintoq = nil;
725 screenputs = nil;
726
727 /* shutdown devices */
728 chandevshutdown();
729
730 splhi();
731 intrshutdown();
732
733 /* setup reboot trampoline function */
734 f = (void*)REBOOTADDR;
735 memmove(f, rebootcode, sizeof(rebootcode));
736 icflush(f, sizeof(rebootcode));
737
738 setstatus(BEV); /* also, kernel mode, no interrupts */
739 coherence();
740
741 /* off we go - never to return */
742 (*f)((ulong)entry, (ulong)code, size, _argc);
743
744 panic("loaded kernel returned!");
745 }
746
747 /*
748 * stub for ../port/devpnp.c
749 */
750 int
isaconfig(char * class,int ctlrno,ISAConf * isa)751 isaconfig(char *class, int ctlrno, ISAConf *isa)
752 {
753 USED(class, ctlrno, isa);
754 return 0;
755 }
756