xref: /plan9-contrib/sys/src/9/pc/mp.c (revision 906943f9f6b8411972abb5e3a03ed19f74be7ccc)
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