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 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 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 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 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 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 cpuactive(0); 184 active.exiting = 0; 185 } 186 187 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 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 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 * 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 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* 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 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 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 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 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 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 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 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 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 680 mathover(Ureg*, void*) 681 { 682 pexit("math overrun", 0); 683 } 684 685 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 699 procsetup(Proc*p) 700 { 701 p->fpstate = FPinit; 702 fpoff(); 703 } 704 705 void 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 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 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 && !iscpuactive(m->machno)) 766 active.ispanic = 0; 767 once = iscpuactive(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 cpuinactive(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.nmachs == 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 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 memset(active.machsmap, 0, sizeof active.machsmap); 840 active.nmachs = 0; 841 if (m->machno != 0) 842 print("on cpu%d (not 0)!\n", m->machno); 843 844 print("shutting down...\n"); 845 delay(200); 846 847 splhi(); 848 849 /* turn off buffered serial console */ 850 serialoq = nil; 851 852 /* shutdown devices */ 853 chandevshutdown(); 854 arch->introff(); 855 856 /* 857 * Modify the machine page table to directly map the low 4MB of memory 858 * This allows the reboot code to turn off the page mapping 859 */ 860 pdb = m->pdb; 861 pdb[PDX(0)] = pdb[PDX(KZERO)]; 862 mmuflushtlb(PADDR(pdb)); 863 864 /* setup reboot trampoline function */ 865 f = (void*)REBOOTADDR; 866 memmove(f, rebootcode, sizeof(rebootcode)); 867 868 print("rebooting...\n"); 869 870 /* off we go - never to return */ 871 coherence(); 872 (*f)(PADDR(entry), PADDR(code), size); 873 } 874 875 876 void 877 exit(int ispanic) 878 { 879 shutdown(ispanic); 880 arch->reset(); 881 } 882 883 int 884 isaconfig(char *class, int ctlrno, ISAConf *isa) 885 { 886 char cc[32], *p; 887 int i; 888 889 snprint(cc, sizeof cc, "%s%d", class, ctlrno); 890 p = getconf(cc); 891 if(p == nil) 892 return 0; 893 894 isa->type = ""; 895 isa->nopt = tokenize(p, isa->opt, NISAOPT); 896 for(i = 0; i < isa->nopt; i++){ 897 p = isa->opt[i]; 898 if(cistrncmp(p, "type=", 5) == 0) 899 isa->type = p + 5; 900 else if(cistrncmp(p, "port=", 5) == 0) 901 isa->port = strtoul(p+5, &p, 0); 902 else if(cistrncmp(p, "irq=", 4) == 0) 903 isa->irq = strtoul(p+4, &p, 0); 904 else if(cistrncmp(p, "dma=", 4) == 0) 905 isa->dma = strtoul(p+4, &p, 0); 906 else if(cistrncmp(p, "mem=", 4) == 0) 907 isa->mem = strtoul(p+4, &p, 0); 908 else if(cistrncmp(p, "size=", 5) == 0) 909 isa->size = strtoul(p+5, &p, 0); 910 else if(cistrncmp(p, "freq=", 5) == 0) 911 isa->freq = strtoul(p+5, &p, 0); 912 } 913 return 1; 914 } 915 916 /* 917 * put the processor in the halt state if we've no processes to run. 918 * an interrupt will get us going again. 919 */ 920 void 921 idlehands(void) 922 { 923 /* 924 * we used to halt only on single-core setups. halting in an smp system 925 * can result in a startup latency for processes that become ready. 926 * if idle_spin is zero, we care more about saving energy 927 * than reducing this latency. 928 * 929 * the performance loss with idle_spin == 0 seems to be slight 930 * and it reduces lock contention (thus system time and real time) 931 * on many-core systems with large values of NPROC. 932 */ 933 if(conf.nmach == 1 || idle_spin == 0 || 934 idle_if_nproc && conf.nmach >= idle_if_nproc) 935 halt(); 936 } 937