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