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