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 "ureg.h"
8 #include "init.h"
9 #include "pool.h"
10 #include "reboot.h"
11 #include "mp.h"
12 #include <tos.h>
13
14 Mach *m;
15
16 /*
17 * Where configuration info is left for the loaded programme.
18 * This will turn into a structure as more is done by the boot loader
19 * (e.g. why parse the .ini file twice?).
20 * There are 3584 bytes available at CONFADDR.
21 */
22 #define BOOTLINE ((char*)CONFADDR)
23 #define BOOTLINELEN 64
24 #define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
25 #define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
26 #define MAXCONF 64
27
28 enum {
29 /* space for syscall args, return PC, top-of-stack struct */
30 Ustkheadroom = sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
31 };
32
33 char bootdisk[KNAMELEN];
34 Conf conf;
35 char *confname[MAXCONF];
36 char *confval[MAXCONF];
37 int nconf;
38 uchar *sp; /* user stack of init proc */
39 int delaylink;
40 int idle_spin, idle_if_nproc;
41
42 static void
options(void)43 options(void)
44 {
45 long i, n;
46 char *cp, *line[MAXCONF], *p, *q;
47
48 /*
49 * parse configuration args from dos file plan9.ini
50 */
51 cp = BOOTARGS; /* where b.com leaves its config */
52 cp[BOOTARGSLEN-1] = 0;
53
54 /*
55 * Strip out '\r', change '\t' -> ' '.
56 */
57 p = cp;
58 for(q = cp; *q; q++){
59 if(*q == '\r')
60 continue;
61 if(*q == '\t')
62 *q = ' ';
63 *p++ = *q;
64 }
65 *p = 0;
66
67 n = getfields(cp, line, MAXCONF, 1, "\n");
68 for(i = 0; i < n; i++){
69 if(*line[i] == '#')
70 continue;
71 cp = strchr(line[i], '=');
72 if(cp == nil)
73 continue;
74 *cp++ = '\0';
75 confname[nconf] = line[i];
76 confval[nconf] = cp;
77 nconf++;
78 }
79 }
80
81 extern void mmuinit0(void);
82 extern void (*i8237alloc)(void);
83
84 void
fpsavealloc(void)85 fpsavealloc(void)
86 {
87 m->fpsavalign = mallocalign(sizeof(FPssestate), FPalign, 0, 0);
88 if (m->fpsavalign == nil)
89 panic("cpu%d: can't allocate fpsavalign", m->machno);
90 }
91
92 static int
isa20on(void)93 isa20on(void)
94 {
95 int r;
96 ulong o;
97 ulong *zp, *mb1p;
98
99 zp = (ulong *)KZERO;
100 mb1p = (ulong *)(KZERO|MB);
101 o = *zp;
102
103 *zp = 0x1234;
104 *mb1p = 0x8765;
105 coherence();
106 wbinvd();
107 r = *zp != *mb1p;
108
109 *zp = o;
110 return r;
111 }
112
113 void
main(void)114 main(void)
115 {
116 cgapost(0);
117 mach0init();
118 options();
119 ioinit();
120 i8250console();
121 quotefmtinstall();
122 screeninit();
123
124 print("\nPlan 9\n");
125
126 trapinit0();
127 mmuinit0();
128
129 kbdinit();
130 i8253init();
131 cpuidentify();
132 meminit();
133 confinit();
134 archinit();
135 if(!isa20on())
136 panic("bootstrap didn't leave a20 address line enabled");
137 xinit();
138 if(i8237alloc != nil)
139 i8237alloc();
140 trapinit();
141 printinit();
142 cpuidprint();
143 mmuinit();
144 fpsavealloc();
145 if(arch->intrinit) /* launches other processors on an mp */
146 arch->intrinit();
147 timersinit();
148 mathinit();
149 kbdenable();
150 if(arch->clockenable)
151 arch->clockenable();
152 procinit0();
153 initseg();
154 if(delaylink){
155 bootlinks();
156 pcimatch(0, 0, 0);
157 }else
158 links();
159 conf.monitor = 1;
160 chandevreset();
161 cgapost(0xcd);
162
163 pageinit();
164 i8253link();
165 swapinit();
166 userinit();
167 active.thunderbirdsarego = 1;
168
169 cgapost(0x99);
170 schedinit();
171 }
172
173 void
mach0init(void)174 mach0init(void)
175 {
176 conf.nmach = 1;
177 MACHP(0) = (Mach*)CPU0MACH;
178 m->pdb = (ulong*)CPU0PDB;
179 m->gdt = (Segdesc*)CPU0GDT;
180
181 machinit();
182
183 active.machs = 1;
184 active.exiting = 0;
185 }
186
187 void
machinit(void)188 machinit(void)
189 {
190 int machno;
191 ulong *pdb;
192 Segdesc *gdt;
193
194 machno = m->machno;
195 pdb = m->pdb;
196 gdt = m->gdt;
197 memset(m, 0, sizeof(Mach));
198 m->machno = machno;
199 m->pdb = pdb;
200 m->gdt = gdt;
201 m->perf.period = 1;
202
203 /*
204 * For polled uart output at boot, need
205 * a default delay constant. 100000 should
206 * be enough for a while. Cpuidentify will
207 * calculate the real value later.
208 */
209 m->loopconst = 100000;
210 }
211
212 void
init0(void)213 init0(void)
214 {
215 int i;
216 char buf[2*KNAMELEN];
217
218 up->nerrlab = 0;
219
220 spllo();
221
222 /*
223 * These are o.k. because rootinit is null.
224 * Then early kproc's will have a root and dot.
225 */
226 up->slash = namec("#/", Atodir, 0, 0);
227 pathclose(up->slash->path);
228 up->slash->path = newpath("/");
229 up->dot = cclone(up->slash);
230
231 chandevinit();
232
233 if(!waserror()){
234 snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
235 ksetenv("terminal", buf, 0);
236 ksetenv("cputype", "386", 0);
237 if(cpuserver)
238 ksetenv("service", "cpu", 0);
239 else
240 ksetenv("service", "terminal", 0);
241 for(i = 0; i < nconf; i++){
242 if(confname[i][0] != '*')
243 ksetenv(confname[i], confval[i], 0);
244 ksetenv(confname[i], confval[i], 1);
245 }
246 poperror();
247 }
248 kproc("alarm", alarmkproc, 0);
249 cgapost(0x9);
250 touser(sp);
251 }
252
253 void
userinit(void)254 userinit(void)
255 {
256 void *v;
257 Proc *p;
258 Segment *s;
259 Page *pg;
260
261 p = newproc();
262 p->pgrp = newpgrp();
263 p->egrp = smalloc(sizeof(Egrp));
264 p->egrp->ref = 1;
265 p->fgrp = dupfgrp(nil);
266 p->rgrp = newrgrp();
267 p->procmode = 0640;
268
269 kstrdup(&eve, "");
270 kstrdup(&p->text, "*init*");
271 kstrdup(&p->user, eve);
272
273 p->fpstate = FPinit;
274 fpoff();
275
276 /*
277 * Kernel Stack
278 *
279 * N.B. make sure there's enough space for syscall to check
280 * for valid args and
281 * 4 bytes for gotolabel's return PC
282 */
283 p->sched.pc = (ulong)init0;
284 p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
285
286 /*
287 * User Stack
288 *
289 * N.B. cannot call newpage() with clear=1, because pc kmap
290 * requires up != nil. use tmpmap instead.
291 */
292 s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
293 p->seg[SSEG] = s;
294 pg = newpage(0, 0, USTKTOP-BY2PG);
295 v = tmpmap(pg);
296 memset(v, 0, BY2PG);
297 segpage(s, pg);
298 bootargs(v);
299 tmpunmap(v);
300
301 /*
302 * Text
303 */
304 s = newseg(SG_TEXT, UTZERO, 1);
305 s->flushme++;
306 p->seg[TSEG] = s;
307 pg = newpage(0, 0, UTZERO);
308 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
309 segpage(s, pg);
310 v = tmpmap(pg);
311 memset(v, 0, BY2PG);
312 memmove(v, initcode, sizeof initcode);
313 tmpunmap(v);
314
315 ready(p);
316 }
317
318 uchar *
pusharg(char * p)319 pusharg(char *p)
320 {
321 int n;
322
323 n = strlen(p)+1;
324 sp -= n;
325 memmove(sp, p, n);
326 return sp;
327 }
328
329 void
bootargs(void * base)330 bootargs(void *base)
331 {
332 int i, ac;
333 uchar *av[32];
334 uchar **lsp;
335 char *cp = BOOTLINE;
336 char buf[64];
337
338 sp = (uchar*)base + BY2PG - Ustkheadroom;
339
340 ac = 0;
341 av[ac++] = pusharg("/386/9dos");
342
343 /* when boot is changed to only use rc, this code can go away */
344 cp[BOOTLINELEN-1] = 0;
345 buf[0] = 0;
346 if(strncmp(cp, "fd", 2) == 0){
347 snprint(buf, sizeof buf, "local!#f/fd%lddisk",
348 strtol(cp+2, 0, 0));
349 av[ac++] = pusharg(buf);
350 } else if(strncmp(cp, "sd", 2) == 0){
351 snprint(buf, sizeof buf, "local!#S/sd%c%c/fs", *(cp+2), *(cp+3));
352 av[ac++] = pusharg(buf);
353 } else if(strncmp(cp, "ether", 5) == 0)
354 av[ac++] = pusharg("-n");
355
356 /* 4 byte word align stack */
357 sp = (uchar*)((ulong)sp & ~3);
358
359 /* build argc, argv on stack */
360 sp -= (ac+1)*sizeof(sp);
361 lsp = (uchar**)sp;
362 for(i = 0; i < ac; i++)
363 *lsp++ = av[i] + ((USTKTOP - BY2PG) - (ulong)base);
364 *lsp = 0;
365 sp += (USTKTOP - BY2PG) - (ulong)base - sizeof(ulong);
366 }
367
368 char*
getconf(char * name)369 getconf(char *name)
370 {
371 int i;
372
373 for(i = 0; i < nconf; i++)
374 if(cistrcmp(confname[i], name) == 0)
375 return confval[i];
376 return 0;
377 }
378
379 static void
writeconf(void)380 writeconf(void)
381 {
382 char *p, *q;
383 int n;
384
385 p = getconfenv();
386
387 if(waserror()) {
388 free(p);
389 nexterror();
390 }
391
392 /* convert to name=value\n format */
393 for(q=p; *q; q++) {
394 q += strlen(q);
395 *q = '=';
396 q += strlen(q);
397 *q = '\n';
398 }
399 n = q - p + 1;
400 if(n >= BOOTARGSLEN)
401 error("kernel configuration too large");
402 memset(BOOTLINE, 0, BOOTLINELEN);
403 memmove(BOOTARGS, p, n);
404 poperror();
405 free(p);
406 }
407
408 void
confinit(void)409 confinit(void)
410 {
411 char *p;
412 int i, userpcnt;
413 unsigned mb;
414 ulong kpages, ksize;
415
416 if(p = getconf("*kernelpercent"))
417 userpcnt = 100 - strtol(p, 0, 0);
418 else
419 userpcnt = 0;
420
421 conf.npage = 0;
422 for(i=0; i<nelem(conf.mem); i++)
423 conf.npage += conf.mem[i].npage;
424
425 conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
426 if(cpuserver)
427 conf.nproc *= 3;
428 if(conf.nproc > 2000)
429 conf.nproc = 2000;
430 conf.nimage = 200;
431 conf.nswap = conf.nproc*80;
432 conf.nswppo = 4096;
433
434 if(cpuserver) {
435 if(userpcnt < 10)
436 userpcnt = 70;
437 kpages = conf.npage - (conf.npage*userpcnt)/100;
438
439 /*
440 * Hack for the big boys. Only good while physmem < 4GB.
441 * Give the kernel fixed max + enough to allocate the
442 * page pool.
443 * This is an overestimate as conf.upages < conf.npages.
444 * The patch of nimage is a band-aid, scanning the whole
445 * page list in imagereclaim just takes too long.
446 */
447 for (mb = 400; mb >= 100; mb /= 2) {
448 ksize = mb*MB + conf.npage*sizeof(Page);
449 if(kpages > ksize/BY2PG && cankaddr(ksize)) {
450 kpages = ksize/BY2PG + (conf.nproc*KSTACK)/BY2PG;
451 conf.nimage = 2000;
452 break;
453 }
454 }
455 } else {
456 if(userpcnt < 10) {
457 if(conf.npage*BY2PG < 16*MB)
458 userpcnt = 40;
459 else
460 userpcnt = 60;
461 }
462 kpages = conf.npage - (conf.npage*userpcnt)/100;
463
464 /*
465 * Make sure terminals with low memory get at least
466 * 4MB on the first Image chunk allocation.
467 */
468 if(conf.npage*BY2PG < 16*MB)
469 imagmem->minarena = 4*1024*1024;
470 }
471
472 /*
473 * can't go past the end of virtual memory
474 * (ulong)-KZERO is 2^32 - KZERO
475 */
476 if(kpages > ((ulong)-KZERO)/BY2PG)
477 kpages = ((ulong)-KZERO)/BY2PG;
478
479 conf.upages = conf.npage - kpages;
480 conf.ialloc = (kpages/2)*BY2PG;
481
482 /*
483 * Guess how much is taken by the large permanent
484 * datastructures. Mntcache and Mntrpc are not accounted for
485 * (probably ~300KB).
486 */
487 kpages *= BY2PG;
488 kpages -= conf.upages*sizeof(Page)
489 + conf.nproc*sizeof(Proc)
490 + conf.nimage*sizeof(Image)
491 + conf.nswap
492 + conf.nswppo*sizeof(Page);
493 mainmem->maxsize = kpages;
494 if(!cpuserver){
495 /*
496 * give terminals lots of image memory, too; the dynamic
497 * allocation will balance the load properly, hopefully.
498 * be careful with 32-bit overflow.
499 */
500 imagmem->maxsize = kpages;
501 }
502 }
503
504 static char* mathmsg[] =
505 {
506 nil, /* handled below */
507 "denormalized operand",
508 "division by zero",
509 "numeric overflow",
510 "numeric underflow",
511 "precision loss",
512 };
513
514 static void
mathstate(ulong * stsp,ulong * pcp,ulong * ctlp)515 mathstate(ulong *stsp, ulong *pcp, ulong *ctlp)
516 {
517 ulong sts, fpc, ctl;
518 FPsave *f = &up->fpsave;
519
520 if(fpsave == fpx87save){
521 sts = f->status;
522 fpc = f->pc;
523 ctl = f->control;
524 } else {
525 sts = f->fsw;
526 fpc = f->fpuip;
527 ctl = f->fcw;
528 }
529 if(stsp)
530 *stsp = sts;
531 if(pcp)
532 *pcp = fpc;
533 if(ctlp)
534 *ctlp = ctl;
535 }
536
537 static void
mathnote(void)538 mathnote(void)
539 {
540 int i;
541 ulong status, pc;
542 char *msg, note[ERRMAX];
543
544 mathstate(&status, &pc, nil);
545
546 /*
547 * Some attention should probably be paid here to the
548 * exception masks and error summary.
549 */
550 msg = "unknown exception";
551 for(i = 1; i <= 5; i++){
552 if(!((1<<i) & status))
553 continue;
554 msg = mathmsg[i];
555 break;
556 }
557 if(status & 0x01){
558 if(status & 0x40){
559 if(status & 0x200)
560 msg = "stack overflow";
561 else
562 msg = "stack underflow";
563 }else
564 msg = "invalid operation";
565 }
566 snprint(note, sizeof note, "sys: fp: %s fppc=%#lux status=%#lux",
567 msg, pc, status);
568 postnote(up, 1, note, NDebug);
569 }
570
571 /*
572 * sse fp save and restore buffers have to be 16-byte (FPalign) aligned,
573 * so we shuffle the data down as needed or make copies.
574 */
575
576 void
fpssesave(FPsave * fps)577 fpssesave(FPsave *fps)
578 {
579 FPsave *afps;
580
581 fps->magic = 0x1234;
582 afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
583 fpssesave0(afps);
584 if (fps != afps) /* not aligned? shuffle down from aligned buffer */
585 memmove(fps, afps, sizeof(FPssestate));
586 if (fps->magic != 0x1234)
587 print("fpssesave: magic corrupted\n");
588 }
589
590 void
fpsserestore(FPsave * fps)591 fpsserestore(FPsave *fps)
592 {
593 FPsave *afps;
594
595 fps->magic = 0x4321;
596 afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
597 if (fps != afps) {
598 afps = m->fpsavalign;
599 memmove(afps, fps, sizeof(FPssestate)); /* make aligned copy */
600 }
601 fpsserestore0(afps);
602 if (fps->magic != 0x4321)
603 print("fpsserestore: magic corrupted\n");
604 }
605
606 /*
607 * math coprocessor error
608 */
609 static void
matherror(Ureg * ur,void *)610 matherror(Ureg *ur, void*)
611 {
612 ulong status, pc;
613
614 /*
615 * a write cycle to port 0xF0 clears the interrupt latch attached
616 * to the error# line from the 387
617 */
618 if(!(m->cpuiddx & Fpuonchip))
619 outb(0xF0, 0xFF);
620
621 /*
622 * save floating point state to check out error
623 */
624 fpenv(&up->fpsave); /* result ignored, but masks fp exceptions */
625 fpsave(&up->fpsave); /* also turns fpu off */
626 fpon();
627 mathnote();
628
629 if((ur->pc & 0xf0000000) == KZERO){
630 mathstate(&status, &pc, nil);
631 panic("fp: status %#lux fppc=%#lux pc=%#lux", status, pc, ur->pc);
632 }
633 }
634
635 /*
636 * math coprocessor emulation fault
637 */
638 static void
mathemu(Ureg * ureg,void *)639 mathemu(Ureg *ureg, void*)
640 {
641 ulong status, control;
642
643 if(up->fpstate & FPillegal){
644 /* someone did floating point in a note handler */
645 postnote(up, 1, "sys: floating point in note handler", NDebug);
646 return;
647 }
648 switch(up->fpstate){
649 case FPinit:
650 fpinit();
651 up->fpstate = FPactive;
652 break;
653 case FPinactive:
654 /*
655 * Before restoring the state, check for any pending
656 * exceptions, there's no way to restore the state without
657 * generating an unmasked exception.
658 * More attention should probably be paid here to the
659 * exception masks and error summary.
660 */
661 mathstate(&status, nil, &control);
662 if((status & ~control) & 0x07F){
663 mathnote();
664 break;
665 }
666 fprestore(&up->fpsave);
667 up->fpstate = FPactive;
668 break;
669 case FPactive:
670 panic("math emu pid %ld %s pc %#lux",
671 up->pid, up->text, ureg->pc);
672 break;
673 }
674 }
675
676 /*
677 * math coprocessor segment overrun
678 */
679 static void
mathover(Ureg *,void *)680 mathover(Ureg*, void*)
681 {
682 pexit("math overrun", 0);
683 }
684
685 void
mathinit(void)686 mathinit(void)
687 {
688 trapenable(VectorCERR, matherror, 0, "matherror");
689 if(X86FAMILY(m->cpuidax) == 3)
690 intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
691 trapenable(VectorCNA, mathemu, 0, "mathemu");
692 trapenable(VectorCSO, mathover, 0, "mathover");
693 }
694
695 /*
696 * set up floating point for a new process
697 */
698 void
procsetup(Proc * p)699 procsetup(Proc*p)
700 {
701 p->fpstate = FPinit;
702 fpoff();
703 }
704
705 void
procrestore(Proc * p)706 procrestore(Proc *p)
707 {
708 uvlong t;
709
710 if(p->kp)
711 return;
712 cycles(&t);
713 p->pcycles -= t;
714 }
715
716 /*
717 * Save the mach dependent part of the process state.
718 */
719 void
procsave(Proc * p)720 procsave(Proc *p)
721 {
722 uvlong t;
723
724 cycles(&t);
725 p->pcycles += t;
726 if(p->fpstate == FPactive){
727 if(p->state == Moribund)
728 fpclear();
729 else{
730 /*
731 * Fpsave() stores without handling pending
732 * unmasked exeptions. Postnote() can't be called
733 * here as sleep() already has up->rlock, so
734 * the handling of pending exceptions is delayed
735 * until the process runs again and generates an
736 * emulation fault to activate the FPU.
737 */
738 fpsave(&p->fpsave);
739 }
740 p->fpstate = FPinactive;
741 }
742
743 /*
744 * While this processor is in the scheduler, the process could run
745 * on another processor and exit, returning the page tables to
746 * the free list where they could be reallocated and overwritten.
747 * When this processor eventually has to get an entry from the
748 * trashed page tables it will crash.
749 *
750 * If there's only one processor, this can't happen.
751 * You might think it would be a win not to do this in that case,
752 * especially on VMware, but it turns out not to matter.
753 */
754 mmuflushtlb(PADDR(m->pdb));
755 }
756
757 static void
shutdown(int ispanic)758 shutdown(int ispanic)
759 {
760 int ms, once;
761
762 lock(&active);
763 if(ispanic)
764 active.ispanic = ispanic;
765 else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
766 active.ispanic = 0;
767 once = active.machs & (1<<m->machno);
768 /*
769 * setting exiting will make hzclock() on each processor call exit(0),
770 * which calls shutdown(0) and arch->reset(), which on mp systems is
771 * mpshutdown, which idles non-bootstrap cpus and returns on bootstrap
772 * processors (to permit a reboot). clearing our bit in machs avoids
773 * calling exit(0) from hzclock() on this processor.
774 */
775 active.machs &= ~(1<<m->machno);
776 active.exiting = 1;
777 unlock(&active);
778
779 if(once)
780 iprint("cpu%d: exiting\n", m->machno);
781
782 /* wait for any other processors to shutdown */
783 spllo();
784 for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
785 delay(TK2MS(2));
786 if(active.machs == 0 && consactive() == 0)
787 break;
788 }
789
790 if(active.ispanic){
791 if(!cpuserver)
792 for(;;)
793 halt();
794 if(getconf("*debug"))
795 delay(5*60*1000);
796 else
797 delay(10000);
798 }else
799 delay(1000);
800 }
801
802 void
reboot(void * entry,void * code,ulong size)803 reboot(void *entry, void *code, ulong size)
804 {
805 void (*f)(ulong, ulong, ulong);
806 ulong *pdb;
807
808 writeconf();
809
810 /*
811 * the boot processor is cpu0. execute this function on it
812 * so that the new kernel has the same cpu0. this only matters
813 * because the hardware has a notion of which processor was the
814 * boot processor and we look at it at start up.
815 */
816 if (m->machno != 0) {
817 procwired(up, 0);
818 sched();
819 }
820
821 if(conf.nmach > 1) {
822 /*
823 * the other cpus could be holding locks that will never get
824 * released (e.g., in the print path) if we put them into
825 * reset now, so force them to shutdown gracefully first.
826 */
827 lock(&active);
828 active.rebooting = 1;
829 unlock(&active);
830 shutdown(0);
831 if(arch->resetothers)
832 arch->resetothers();
833 delay(20);
834 }
835
836 /*
837 * should be the only processor running now
838 */
839 active.machs = 0;
840 if (m->machno != 0)
841 print("on cpu%d (not 0)!\n", m->machno);
842
843 print("shutting down...\n");
844 delay(200);
845
846 splhi();
847
848 /* turn off buffered serial console */
849 serialoq = nil;
850
851 /* shutdown devices */
852 chandevshutdown();
853 arch->introff();
854
855 /*
856 * Modify the machine page table to directly map the low 4MB of memory
857 * This allows the reboot code to turn off the page mapping
858 */
859 pdb = m->pdb;
860 pdb[PDX(0)] = pdb[PDX(KZERO)];
861 mmuflushtlb(PADDR(pdb));
862
863 /* setup reboot trampoline function */
864 f = (void*)REBOOTADDR;
865 memmove(f, rebootcode, sizeof(rebootcode));
866
867 print("rebooting...\n");
868
869 /* off we go - never to return */
870 coherence();
871 (*f)(PADDR(entry), PADDR(code), size);
872 }
873
874
875 void
exit(int ispanic)876 exit(int ispanic)
877 {
878 shutdown(ispanic);
879 arch->reset();
880 }
881
882 int
isaconfig(char * class,int ctlrno,ISAConf * isa)883 isaconfig(char *class, int ctlrno, ISAConf *isa)
884 {
885 char cc[32], *p;
886 int i;
887
888 snprint(cc, sizeof cc, "%s%d", class, ctlrno);
889 p = getconf(cc);
890 if(p == nil)
891 return 0;
892
893 isa->type = "";
894 isa->nopt = tokenize(p, isa->opt, NISAOPT);
895 for(i = 0; i < isa->nopt; i++){
896 p = isa->opt[i];
897 if(cistrncmp(p, "type=", 5) == 0)
898 isa->type = p + 5;
899 else if(cistrncmp(p, "port=", 5) == 0)
900 isa->port = strtoul(p+5, &p, 0);
901 else if(cistrncmp(p, "irq=", 4) == 0)
902 isa->irq = strtoul(p+4, &p, 0);
903 else if(cistrncmp(p, "dma=", 4) == 0)
904 isa->dma = strtoul(p+4, &p, 0);
905 else if(cistrncmp(p, "mem=", 4) == 0)
906 isa->mem = strtoul(p+4, &p, 0);
907 else if(cistrncmp(p, "size=", 5) == 0)
908 isa->size = strtoul(p+5, &p, 0);
909 else if(cistrncmp(p, "freq=", 5) == 0)
910 isa->freq = strtoul(p+5, &p, 0);
911 }
912 return 1;
913 }
914
915 int
cistrcmp(char * a,char * b)916 cistrcmp(char *a, char *b)
917 {
918 int ac, bc;
919
920 for(;;){
921 ac = *a++;
922 bc = *b++;
923
924 if(ac >= 'A' && ac <= 'Z')
925 ac = 'a' + (ac - 'A');
926 if(bc >= 'A' && bc <= 'Z')
927 bc = 'a' + (bc - 'A');
928 ac -= bc;
929 if(ac)
930 return ac;
931 if(bc == 0)
932 break;
933 }
934 return 0;
935 }
936
937 int
cistrncmp(char * a,char * b,int n)938 cistrncmp(char *a, char *b, int n)
939 {
940 unsigned ac, bc;
941
942 while(n > 0){
943 ac = *a++;
944 bc = *b++;
945 n--;
946
947 if(ac >= 'A' && ac <= 'Z')
948 ac = 'a' + (ac - 'A');
949 if(bc >= 'A' && bc <= 'Z')
950 bc = 'a' + (bc - 'A');
951
952 ac -= bc;
953 if(ac)
954 return ac;
955 if(bc == 0)
956 break;
957 }
958
959 return 0;
960 }
961
962 /*
963 * put the processor in the halt state if we've no processes to run.
964 * an interrupt will get us going again.
965 */
966 void
idlehands(void)967 idlehands(void)
968 {
969 /*
970 * we used to halt only on single-core setups. halting in an smp system
971 * can result in a startup latency for processes that become ready.
972 * if idle_spin is zero, we care more about saving energy
973 * than reducing this latency.
974 *
975 * the performance loss with idle_spin == 0 seems to be slight
976 * and it reduces lock contention (thus system time and real time)
977 * on many-core systems with large values of NPROC.
978 */
979 if(conf.nmach == 1 || idle_spin == 0 ||
980 idle_if_nproc && conf.nmach >= idle_if_nproc)
981 halt();
982 }
983