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 9 #include "mp.h" 10 #include "apbootstrap.h" 11 12 static Bus* mpbus; 13 static Bus* mpbuslast; 14 static int mpisabus = -1; 15 static int mpeisabus = -1; 16 extern int i8259elcr; /* mask of level-triggered interrupts */ 17 static Apic mpapic[MaxAPICNO+1]; 18 static int machno2apicno[MaxAPICNO+1]; /* inverse map: machno -> APIC ID */ 19 static Lock mprdthilock; 20 static int mprdthi; 21 static Ref mpvnoref; /* unique vector assignment */ 22 static int mpmachno = 1; 23 24 static char* buses[] = { 25 "CBUSI ", 26 "CBUSII", 27 "EISA ", 28 "FUTURE", 29 "INTERN", 30 "ISA ", 31 "MBI ", 32 "MBII ", 33 "MCA ", 34 "MPI ", 35 "MPSA ", 36 "NUBUS ", 37 "PCI ", 38 "PCMCIA", 39 "TC ", 40 "VL ", 41 "VME ", 42 "XPRESS", 43 0, 44 }; 45 46 static Apic* 47 mkprocessor(PCMPprocessor* p) 48 { 49 Apic *apic; 50 51 if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO) 52 return 0; 53 54 apic = &mpapic[p->apicno]; 55 apic->type = PcmpPROCESSOR; 56 apic->apicno = p->apicno; 57 apic->flags = p->flags; 58 apic->lintr[0] = ApicIMASK; 59 apic->lintr[1] = ApicIMASK; 60 61 if(p->flags & PcmpBP){ 62 machno2apicno[0] = p->apicno; 63 apic->machno = 0; 64 } 65 else{ 66 machno2apicno[mpmachno] = p->apicno; 67 apic->machno = mpmachno; 68 mpmachno++; 69 } 70 71 return apic; 72 } 73 74 static Bus* 75 mkbus(PCMPbus* p) 76 { 77 Bus *bus; 78 int i; 79 80 for(i = 0; buses[i]; i++){ 81 if(strncmp(buses[i], p->string, sizeof(p->string)) == 0) 82 break; 83 } 84 if(buses[i] == 0) 85 return 0; 86 87 bus = xalloc(sizeof(Bus)); 88 if(mpbus) 89 mpbuslast->next = bus; 90 else 91 mpbus = bus; 92 mpbuslast = bus; 93 94 bus->type = i; 95 bus->busno = p->busno; 96 if(bus->type == BusEISA){ 97 bus->po = PcmpLOW; 98 bus->el = PcmpLEVEL; 99 if(mpeisabus != -1) 100 print("mkbus: more than one EISA bus\n"); 101 mpeisabus = bus->busno; 102 } 103 else if(bus->type == BusPCI){ 104 bus->po = PcmpLOW; 105 bus->el = PcmpLEVEL; 106 } 107 else if(bus->type == BusISA){ 108 bus->po = PcmpHIGH; 109 bus->el = PcmpEDGE; 110 if(mpisabus != -1) 111 print("mkbus: more than one ISA bus\n"); 112 mpisabus = bus->busno; 113 } 114 else{ 115 bus->po = PcmpHIGH; 116 bus->el = PcmpEDGE; 117 } 118 119 return bus; 120 } 121 122 static Bus* 123 mpgetbus(int busno) 124 { 125 Bus *bus; 126 127 for(bus = mpbus; bus; bus = bus->next){ 128 if(bus->busno == busno) 129 return bus; 130 } 131 print("mpgetbus: can't find bus %d\n", busno); 132 133 return 0; 134 } 135 136 static Apic* 137 mkioapic(PCMPioapic* p) 138 { 139 Apic *apic; 140 void *va; 141 142 if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO) 143 return 0; 144 145 /* 146 * Map the I/O APIC. 147 */ 148 if((va = vmap(p->addr, 1024)) == nil) 149 return 0; 150 151 apic = &mpapic[p->apicno]; 152 apic->type = PcmpIOAPIC; 153 apic->apicno = p->apicno; 154 apic->addr = va; 155 apic->paddr = p->addr; 156 apic->flags = p->flags; 157 158 return apic; 159 } 160 161 static Aintr* 162 mkiointr(PCMPintr* p) 163 { 164 Bus *bus; 165 Aintr *aintr; 166 167 /* 168 * According to the MultiProcessor Specification, a destination 169 * I/O APIC of 0xFF means the signal is routed to all I/O APICs. 170 * It's unclear how that can possibly be correct so treat it as 171 * an error for now. 172 */ 173 if(p->apicno == 0xFF) 174 return 0; 175 if((bus = mpgetbus(p->busno)) == 0) 176 return 0; 177 178 aintr = xalloc(sizeof(Aintr)); 179 aintr->intr = p; 180 aintr->apic = &mpapic[p->apicno]; 181 aintr->next = bus->aintr; 182 bus->aintr = aintr; 183 184 return aintr; 185 } 186 187 static int 188 mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/) 189 { 190 int el, po, v; 191 192 /* 193 * Parse an I/O or Local APIC interrupt table entry and 194 * return the encoded vector. 195 */ 196 v = vno; 197 198 po = intr->flags & PcmpPOMASK; 199 el = intr->flags & PcmpELMASK; 200 201 switch(intr->intr){ 202 203 default: /* PcmpINT */ 204 v |= ApicLOWEST; 205 break; 206 207 case PcmpNMI: 208 v |= ApicNMI; 209 po = PcmpHIGH; 210 el = PcmpEDGE; 211 break; 212 213 case PcmpSMI: 214 v |= ApicSMI; 215 break; 216 217 case PcmpExtINT: 218 v |= ApicExtINT; 219 /* 220 * The AMI Goliath doesn't boot successfully with it's LINTR0 221 * entry which decodes to low+level. The PPro manual says ExtINT 222 * should be level, whereas the Pentium is edge. Setting the 223 * Goliath to edge+high seems to cure the problem. Other PPro 224 * MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes 225 * to edge+high, so who knows. 226 * Perhaps it would be best just to not set an ExtINT entry at 227 * all, it shouldn't be needed for SMP mode. 228 */ 229 po = PcmpHIGH; 230 el = PcmpEDGE; 231 break; 232 } 233 234 /* 235 */ 236 if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){ 237 po = PcmpHIGH; 238 el = PcmpEDGE; 239 } 240 if(!po) 241 po = bus->po; 242 if(po == PcmpLOW) 243 v |= ApicLOW; 244 else if(po != PcmpHIGH){ 245 print("mpintrinit: bad polarity 0x%uX\n", po); 246 return ApicIMASK; 247 } 248 249 if(!el) 250 el = bus->el; 251 if(el == PcmpLEVEL) 252 v |= ApicLEVEL; 253 else if(el != PcmpEDGE){ 254 print("mpintrinit: bad trigger 0x%uX\n", el); 255 return ApicIMASK; 256 } 257 258 return v; 259 } 260 261 static int 262 mklintr(PCMPintr* p) 263 { 264 Apic *apic; 265 Bus *bus; 266 int intin, v; 267 268 /* 269 * The offsets of vectors for LINT[01] are known to be 270 * 0 and 1 from the local APIC vector space at VectorLAPIC. 271 */ 272 if((bus = mpgetbus(p->busno)) == 0) 273 return 0; 274 intin = p->intin; 275 276 /* 277 * Pentium Pros have problems if LINT[01] are set to ExtINT 278 * so just bag it, SMP mode shouldn't need ExtINT anyway. 279 */ 280 if(p->intr == PcmpExtINT || p->intr == PcmpNMI) 281 v = ApicIMASK; 282 else 283 v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq); 284 285 if(p->apicno == 0xFF){ 286 for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 287 if((apic->flags & PcmpEN) 288 && apic->type == PcmpPROCESSOR) 289 apic->lintr[intin] = v; 290 } 291 } 292 else{ 293 apic = &mpapic[p->apicno]; 294 if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR) 295 apic->lintr[intin] = v; 296 } 297 298 return v; 299 } 300 301 static void 302 checkmtrr(void) 303 { 304 int i, vcnt; 305 Mach *mach0; 306 307 /* 308 * If there are MTRR registers, snarf them for validation. 309 */ 310 if(!(m->cpuiddx & 0x1000)) 311 return; 312 313 rdmsr(0x0FE, &m->mtrrcap); 314 rdmsr(0x2FF, &m->mtrrdef); 315 if(m->mtrrcap & 0x0100){ 316 rdmsr(0x250, &m->mtrrfix[0]); 317 rdmsr(0x258, &m->mtrrfix[1]); 318 rdmsr(0x259, &m->mtrrfix[2]); 319 for(i = 0; i < 8; i++) 320 rdmsr(0x268+i, &m->mtrrfix[(i+3)]); 321 } 322 vcnt = m->mtrrcap & 0x00FF; 323 if(vcnt > nelem(m->mtrrvar)) 324 vcnt = nelem(m->mtrrvar); 325 for(i = 0; i < vcnt; i++) 326 rdmsr(0x200+i, &m->mtrrvar[i]); 327 328 /* 329 * If not the bootstrap processor, compare. 330 */ 331 if(m->machno == 0) 332 return; 333 334 mach0 = MACHP(0); 335 if(mach0->mtrrcap != m->mtrrcap) 336 print("mtrrcap%d: %lluX %lluX\n", 337 m->machno, mach0->mtrrcap, m->mtrrcap); 338 if(mach0->mtrrdef != m->mtrrdef) 339 print("mtrrdef%d: %lluX %lluX\n", 340 m->machno, mach0->mtrrdef, m->mtrrdef); 341 for(i = 0; i < 11; i++){ 342 if(mach0->mtrrfix[i] != m->mtrrfix[i]) 343 print("mtrrfix%d: i%d: %lluX %lluX\n", 344 m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]); 345 } 346 for(i = 0; i < vcnt; i++){ 347 if(mach0->mtrrvar[i] != m->mtrrvar[i]) 348 print("mtrrvar%d: i%d: %lluX %lluX\n", 349 m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]); 350 } 351 } 352 353 static void 354 squidboy(Apic* apic) 355 { 356 // iprint("Hello Squidboy\n"); 357 358 machinit(); 359 mmuinit(); 360 361 cpuidentify(); 362 cpuidprint(); 363 checkmtrr(); 364 365 lock(&mprdthilock); 366 mprdthi |= (1<<apic->apicno)<<24; 367 unlock(&mprdthilock); 368 369 lapicinit(apic); 370 lapiconline(); 371 syncclock(); 372 timersinit(); 373 374 fpoff(); 375 376 lock(&active); 377 active.machs |= 1<<m->machno; 378 unlock(&active); 379 380 while(!active.thunderbirdsarego) 381 microdelay(100); 382 383 schedinit(); 384 } 385 386 static void 387 mpstartap(Apic* apic) 388 { 389 ulong *apbootp, *pdb, *pte; 390 Mach *mach, *mach0; 391 int i, machno; 392 uchar *p; 393 394 mach0 = MACHP(0); 395 396 /* 397 * Initialise the AP page-tables and Mach structure. The page-tables 398 * are the same as for the bootstrap processor with the exception of 399 * the PTE for the Mach structure. 400 * Xspanalloc will panic if an allocation can't be made. 401 */ 402 p = xspanalloc(4*BY2PG, BY2PG, 0); 403 pdb = (ulong*)p; 404 memmove(pdb, mach0->pdb, BY2PG); 405 p += BY2PG; 406 407 if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil) 408 return; 409 memmove(p, KADDR(PPN(*pte)), BY2PG); 410 *pte = PADDR(p)|PTEWRITE|PTEVALID; 411 if(mach0->havepge) 412 *pte |= PTEGLOBAL; 413 p += BY2PG; 414 415 mach = (Mach*)p; 416 if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil) 417 return; 418 *pte = PADDR(mach)|PTEWRITE|PTEVALID; 419 if(mach0->havepge) 420 *pte |= PTEGLOBAL; 421 p += BY2PG; 422 423 machno = apic->machno; 424 MACHP(machno) = mach; 425 mach->machno = machno; 426 mach->pdb = pdb; 427 mach->gdt = (Segdesc*)p; /* filled by mmuinit */ 428 429 /* 430 * Tell the AP where its kernel vector and pdb are. 431 * The offsets are known in the AP bootstrap code. 432 */ 433 apbootp = (ulong*)(APBOOTSTRAP+0x08); 434 *apbootp++ = (ulong)squidboy; 435 *apbootp++ = PADDR(pdb); 436 *apbootp = (ulong)apic; 437 438 /* 439 * Universal Startup Algorithm. 440 */ 441 p = KADDR(0x467); 442 *p++ = PADDR(APBOOTSTRAP); 443 *p++ = PADDR(APBOOTSTRAP)>>8; 444 i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16; 445 /* code assumes i==0 */ 446 if(i != 0) 447 print("mp: bad APBOOTSTRAP\n"); 448 *p++ = i; 449 *p = i>>8; 450 451 nvramwrite(0x0F, 0x0A); 452 lapicstartap(apic, PADDR(APBOOTSTRAP)); 453 for(i = 0; i < 1000; i++){ 454 lock(&mprdthilock); 455 if(mprdthi & ((1<<apic->apicno)<<24)){ 456 unlock(&mprdthilock); 457 break; 458 } 459 unlock(&mprdthilock); 460 delay(10); 461 } 462 nvramwrite(0x0F, 0x00); 463 } 464 465 void 466 mpinit(void) 467 { 468 int ncpu; 469 char *cp; 470 PCMP *pcmp; 471 uchar *e, *p; 472 Apic *apic, *bpapic; 473 void *va; 474 475 i8259init(); 476 syncclock(); 477 478 if(_mp_ == 0) 479 return; 480 pcmp = KADDR(_mp_->physaddr); 481 482 /* 483 * Map the local APIC. 484 */ 485 if((va = vmap(pcmp->lapicbase, 1024)) == nil) 486 return; 487 print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va); 488 489 bpapic = nil; 490 491 /* 492 * Run through the table saving information needed for starting 493 * application processors and initialising any I/O APICs. The table 494 * is guaranteed to be in order such that only one pass is necessary. 495 */ 496 p = ((uchar*)pcmp)+sizeof(PCMP); 497 e = ((uchar*)pcmp)+pcmp->length; 498 while(p < e) switch(*p){ 499 500 default: 501 print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n", 502 *p, e-p); 503 while(p < e){ 504 print("%uX ", *p); 505 p++; 506 } 507 break; 508 509 case PcmpPROCESSOR: 510 if(apic = mkprocessor((PCMPprocessor*)p)){ 511 /* 512 * Must take a note of bootstrap processor APIC 513 * now as it will be needed in order to start the 514 * application processors later and there's no 515 * guarantee that the bootstrap processor appears 516 * first in the table before the others. 517 */ 518 apic->addr = va; 519 apic->paddr = pcmp->lapicbase; 520 if(apic->flags & PcmpBP) 521 bpapic = apic; 522 } 523 p += sizeof(PCMPprocessor); 524 continue; 525 526 case PcmpBUS: 527 mkbus((PCMPbus*)p); 528 p += sizeof(PCMPbus); 529 continue; 530 531 case PcmpIOAPIC: 532 if(apic = mkioapic((PCMPioapic*)p)) 533 ioapicinit(apic, ((PCMPioapic*)p)->apicno); 534 p += sizeof(PCMPioapic); 535 continue; 536 537 case PcmpIOINTR: 538 mkiointr((PCMPintr*)p); 539 p += sizeof(PCMPintr); 540 continue; 541 542 case PcmpLINTR: 543 mklintr((PCMPintr*)p); 544 p += sizeof(PCMPintr); 545 continue; 546 } 547 548 /* 549 * No bootstrap processor, no need to go further. 550 */ 551 if(bpapic == 0) 552 return; 553 554 lapicinit(bpapic); 555 lock(&mprdthilock); 556 mprdthi |= (1<<bpapic->apicno)<<24; 557 unlock(&mprdthilock); 558 559 /* 560 * These interrupts are local to the processor 561 * and do not appear in the I/O APIC so it is OK 562 * to set them now. 563 */ 564 intrenable(IrqTIMER, lapicclock, 0, BUSUNKNOWN, "clock"); 565 intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror"); 566 intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious"); 567 lapiconline(); 568 569 checkmtrr(); 570 571 /* 572 * Initialise the application processors. 573 */ 574 if(cp = getconf("*ncpu")){ 575 ncpu = strtol(cp, 0, 0); 576 if(ncpu < 1) 577 ncpu = 1; 578 } 579 else 580 ncpu = MaxAPICNO; 581 memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); 582 for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 583 if(ncpu <= 1) 584 break; 585 if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN 586 && apic->type == PcmpPROCESSOR){ 587 mpstartap(apic); 588 conf.nmach++; 589 ncpu--; 590 } 591 } 592 593 /* 594 * we don't really know the number of processors till 595 * here. 596 * 597 * set conf.copymode here if nmach > 1. 598 * Should look for an ExtINT line and enable it. 599 */ 600 if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1) 601 conf.copymode = 1; 602 } 603 604 static int 605 mpintrenablex(Vctl* v, int tbdf) 606 { 607 Bus *bus; 608 Aintr *aintr; 609 Apic *apic; 610 Pcidev *pcidev; 611 int bno, dno, irq, lo, n, type, vno; 612 613 /* 614 * Find the bus. 615 */ 616 type = BUSTYPE(tbdf); 617 bno = BUSBNO(tbdf); 618 dno = BUSDNO(tbdf); 619 if(type == BusISA) 620 bno = mpisabus; 621 for(bus = mpbus; bus != nil; bus = bus->next){ 622 if(bus->type != type) 623 continue; 624 if(bus->busno == bno) 625 break; 626 } 627 if(bus == nil){ 628 print("ioapicirq: can't find bus type %d\n", type); 629 return -1; 630 } 631 632 /* 633 * For PCI devices the interrupt pin (INT[ABCD]) and device 634 * number are encoded into the entry irq field, so create something 635 * to match on. The interrupt pin used by the device has to be 636 * obtained from the PCI config space. 637 */ 638 if(bus->type == BusPCI){ 639 pcidev = pcimatchtbdf(tbdf); 640 if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0) 641 irq = (dno<<2)|(n-1); 642 else 643 irq = -1; 644 //print("pcidev %uX: irq %uX v->irq %uX\n", tbdf, irq, v->irq); 645 } 646 else 647 irq = v->irq; 648 649 /* 650 * Find a matching interrupt entry from the list of interrupts 651 * attached to this bus. 652 */ 653 for(aintr = bus->aintr; aintr; aintr = aintr->next){ 654 if(aintr->intr->irq != irq) 655 continue; 656 657 /* 658 * Check if already enabled. Multifunction devices may share 659 * INT[A-D]# so, if already enabled, check the polarity matches 660 * and the trigger is level. 661 * 662 * Should check the devices differ only in the function number, 663 * but that can wait for the planned enable/disable rewrite. 664 * The RDT read here is safe for now as currently interrupts 665 * are never disabled once enabled. 666 */ 667 apic = aintr->apic; 668 ioapicrdtr(apic, aintr->intr->intin, 0, &lo); 669 670 if(!(lo & ApicIMASK)){ 671 vno = lo & 0xFF; 672 n = mpintrinit(bus, aintr->intr, vno, v->irq); 673 n |= ApicLOGICAL; 674 lo &= ~(ApicRemoteIRR|ApicDELIVS); 675 if(n != lo || !(n & ApicLEVEL)){ 676 print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n", 677 v->irq, tbdf, lo, n); 678 return -1; 679 } 680 681 v->isr = lapicisr; 682 v->eoi = lapiceoi; 683 684 return vno; 685 } 686 687 /* 688 * With the APIC a unique vector can be assigned to each 689 * request to enable an interrupt. There are two reasons this 690 * is a good idea: 691 * 1) to prevent lost interrupts, no more than 2 interrupts 692 * should be assigned per block of 16 vectors (there is an 693 * in-service entry and a holding entry for each priority 694 * level and there is one priority level per block of 16 695 * interrupts). 696 * 2) each input pin on the IOAPIC will receive a different 697 * vector regardless of whether the devices on that pin use 698 * the same IRQ as devices on another pin. 699 */ 700 vno = VectorAPIC + (incref(&mpvnoref)-1)*8; 701 if(vno > MaxVectorAPIC){ 702 print("mpintrenable: vno %d, irq %d, tbdf %uX\n", 703 vno, v->irq, tbdf); 704 return -1; 705 } 706 lo = mpintrinit(bus, aintr->intr, vno, v->irq); 707 //print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n", 708 // lo, bus->busno, aintr->intr->irq, vno, 709 // v->irq, i8259elcr); 710 if(lo & ApicIMASK) 711 return -1; 712 lo |= ApicLOGICAL; 713 714 if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC){ 715 lock(&mprdthilock); 716 ioapicrdtw(apic, aintr->intr->intin, mprdthi, lo); 717 unlock(&mprdthilock); 718 } 719 //else 720 // print("lo not enabled 0x%uX %d\n", 721 // apic->flags, apic->type); 722 723 v->isr = lapicisr; 724 v->eoi = lapiceoi; 725 726 return vno; 727 } 728 729 return -1; 730 } 731 732 int 733 mpintrenable(Vctl* v) 734 { 735 int irq, tbdf, vno; 736 737 /* 738 * If the bus is known, try it. 739 * BUSUNKNOWN is given both by [E]ISA devices and by 740 * interrupts local to the processor (local APIC, coprocessor 741 * breakpoint and page-fault). 742 */ 743 tbdf = v->tbdf; 744 if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1) 745 return vno; 746 747 irq = v->irq; 748 if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){ 749 if(irq != IrqSPURIOUS) 750 v->isr = lapiceoi; 751 return VectorPIC+irq; 752 } 753 if(irq < 0 || irq > MaxIrqPIC){ 754 print("mpintrenable: irq %d out of range\n", irq); 755 return -1; 756 } 757 758 /* 759 * Either didn't find it or have to try the default buses 760 * (ISA and EISA). This hack is due to either over-zealousness 761 * or laziness on the part of some manufacturers. 762 * 763 * The MP configuration table on some older systems 764 * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus 765 * but none for ISA. It also has the interrupt type and 766 * polarity set to 'default for this bus' which wouldn't 767 * be compatible with ISA. 768 */ 769 if(mpeisabus != -1){ 770 vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0)); 771 if(vno != -1) 772 return vno; 773 } 774 if(mpisabus != -1){ 775 vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0)); 776 if(vno != -1) 777 return vno; 778 } 779 print("mpintrenable: out of choices eisa %d isa %d tbdf %#ux irq %d\n", 780 mpeisabus, mpisabus, v->tbdf, v->irq); 781 return -1; 782 } 783 784 static Lock mpshutdownlock; 785 786 void 787 mpshutdown(void) 788 { 789 /* 790 * To be done... 791 */ 792 if(!canlock(&mpshutdownlock)){ 793 /* 794 * If this processor received the CTRL-ALT-DEL from 795 * the keyboard, acknowledge it. Send an INIT to self. 796 */ 797 #ifdef FIXTHIS 798 if(lapicisr(VectorKBD)) 799 lapiceoi(VectorKBD); 800 #endif /* FIX THIS */ 801 idle(); 802 } 803 804 print("apshutdown: active = 0x%2.2uX\n", active.machs); 805 delay(1000); 806 splhi(); 807 808 /* 809 * INIT all excluding self. 810 */ 811 lapicicrw(0, 0x000C0000|ApicINIT); 812 813 pcireset(); 814 i8042reset(); 815 816 /* 817 * Often the BIOS hangs during restart if a conventional 8042 818 * warm-boot sequence is tried. The following is Intel specific and 819 * seems to perform a cold-boot, but at least it comes back. 820 * And sometimes there is no keyboard... 821 * 822 * The reset register (0xcf9) is usually in one of the bridge 823 * chips. The actual location and sequence could be extracted from 824 * ACPI but why bother, this is the end of the line anyway. 825 */ 826 print("no kbd; trying bios warm boot..."); 827 *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */ 828 outb(0xCF9, 0x02); 829 outb(0xCF9, 0x06); 830 831 print("can't reset\n"); 832 for(;;) 833 idle(); 834 } 835