mp.c 17 KB

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