plan 9 kernel history: overview | file list | diff list

1998/0717/pc/mp.c (diff list | history)

1997/0327/sys/src/9/pc/mp.c:187,1921997/0405/sys/src/9/pc/mp.c:187,195 (short | long)
1997/0327    
	 */ 
	v = vector; 
 
1997/0405    
	po = intr->flags & PcmpPOMASK; 
	el = intr->flags & PcmpELMASK; 
 
1997/0327    
	switch(intr->intr){ 
 
	default:				/* PcmpINT */ 
1997/0327/sys/src/9/pc/mp.c:195,2001997/0405/sys/src/9/pc/mp.c:198,205
1997/0327    
 
	case PcmpNMI: 
		v |= ApicNMI; 
1997/0405    
		po = PcmpHIGH; 
		el = PcmpEDGE; 
1997/0327    
		break; 
 
	case PcmpSMI: 
1997/0327/sys/src/9/pc/mp.c:206,2141997/0405/sys/src/9/pc/mp.c:211,216
1997/0327    
		break; 
	} 
 
	po = intr->flags & PcmpPOMASK; 
	el = intr->flags & PcmpELMASK; 
                 
	/* 
	 */ 
	if(bus->type == BusEISA && !po && !el /*&& !(elcr & (1<<(v-VectorPIC)))*/){ 
1997/0327/sys/src/9/pc/mp.c:368,3741997/0405/sys/src/9/pc/mp.c:370,376
1997/0327    
	PCMP *pcmp; 
	ulong *pte; 
	uchar *e, *p; 
	Apic *apic; 
1997/0405    
	Apic *apic, *bpapic; 
1997/0327    
	int clkin; 
 
	i8259init(); 
1997/0327/sys/src/9/pc/mp.c:376,3821997/0405/sys/src/9/pc/mp.c:378,383
1997/0327    
	if(_mp_ == 0) 
		return; 
	pcmp = KADDR(_mp_->physaddr); 
	clkin = 0; 
 
	/* 
	 * Map the local APIC. This should be in the same 4MB segment 
1997/0327/sys/src/9/pc/mp.c:389,3941997/0405/sys/src/9/pc/mp.c:390,397
1997/0327    
		mmuflushtlb(PADDR(m->pdb)); 
	} 
 
1997/0405    
	bpapic = 0; 
 
1997/0327    
	/* 
	 * Run through the table saving information needed for starting application 
	 * processors and initialising any I/O APICs. The table is guaranteed to be in 
1997/0327/sys/src/9/pc/mp.c:401,4071997/0405/sys/src/9/pc/mp.c:404,410
1997/0327    
	case PcmpPROCESSOR: 
		if(apic = mkprocessor((PCMPprocessor*)p)){ 
			/* 
			 * Must initialise the bootstrap processor APIC 
1997/0405    
			 * Must take a note of bootstrap processor APIC 
1997/0327    
			 * now as it will be needed in order to start the 
			 * application processors later and there's no 
			 * guarantee that the bootstrap processor appears 
1997/0327/sys/src/9/pc/mp.c:409,4151997/0405/sys/src/9/pc/mp.c:412,418
1997/0327    
			 */ 
			apic->addr = KADDR(pcmp->lapicbase); 
			if(apic->flags & PcmpBP) 
				clkin = lapicinit(apic); 
1997/0405    
				bpapic = apic; 
1997/0327    
		} 
		p += sizeof(PCMPprocessor); 
		continue; 
1997/0327/sys/src/9/pc/mp.c:437,4671997/0405/sys/src/9/pc/mp.c:440,472
1997/0327    
	} 
 
	/* 
	 * Initialise all the processors. 
1997/0405    
	 * No bootstrap processor, no need to go further. 
1997/0327    
	 */ 
	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); 
	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
		if(!(apic->flags & PcmpEN) || apic->type != PcmpPROCESSOR) 
			continue; 
1997/0405    
	if(bpapic == 0) 
		return; 
1997/0327    
 
		if(apic->flags & PcmpBP){ 
			lock(&mprdthilock); 
			mprdthi |= (1<<apic->apicno)<<24; 
			unlock(&mprdthilock); 
1997/0405    
	clkin = lapicinit(bpapic); 
	lock(&mprdthilock); 
	mprdthi |= (1<<bpapic->apicno)<<24; 
	unlock(&mprdthilock); 
1997/0327    
 
			/* 
			 * These interrupts are local to the processor 
			 * and do not appear in the I/O APIC so it is OK 
			 * to set them now. 
			 */ 
			intrenable(VectorTIMER, clockintr, 0, BUSUNKNOWN); 
			intrenable(VectorERROR, lapicerror, 0, BUSUNKNOWN); 
			intrenable(VectorSPURIOUS, lapicspurious, 0, BUSUNKNOWN); 
			lapiconline(clkin); 
			continue; 
		} 
1997/0405    
	/* 
	 * These interrupts are local to the processor 
	 * and do not appear in the I/O APIC so it is OK 
	 * to set them now. 
	 */ 
	intrenable(VectorTIMER, clockintr, 0, BUSUNKNOWN); 
	intrenable(VectorERROR, lapicerror, 0, BUSUNKNOWN); 
	intrenable(VectorSPURIOUS, lapicspurious, 0, BUSUNKNOWN); 
	lapiconline(clkin); 
1997/0327    
 
		mpstartap(apic); 
1997/0405    
	/* 
	 * Initialise the application processors. 
	 */ 
	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); 
	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN && apic->type == PcmpPROCESSOR) 
			mpstartap(apic); 
1997/0327    
	} 
 
	/* 
1997/0405/sys/src/9/pc/mp.c:359,3661997/0521/sys/src/9/pc/mp.c:359,373 (short | long)
1997/0327    
 
	nvramwrite(0x0F, 0x0A); 
	lapicstartap(apic, PADDR(APBOOTSTRAP)); 
	for(i = 0; i < 100000 && (active.machs & (1<<machno)) == 0; i++) 
1997/0521    
	for(i = 0; i < 100000; i++){ 
		lock(&mprdthilock); 
		if(mprdthi & ((1<<apic->apicno)<<24)){ 
			unlock(&mprdthilock); 
			break; 
		} 
		unlock(&mprdthilock); 
1997/0327    
		microdelay(10); 
1997/0521    
	} 
1997/0327    
	nvramwrite(0x0F, 0x00); 
} 
 
1997/0521/sys/src/9/pc/mp.c:207,2121997/0522/sys/src/9/pc/mp.c:207,214 (short | long)
1997/0327    
		break; 
 
	case PcmpExtINT: 
1997/0522    
po = PcmpHIGH; 
el = PcmpEDGE; 
1997/0327    
		v |= ApicExtINT; 
		break; 
	} 
1997/0522/sys/src/9/pc/mp.c:207,2151997/0524/sys/src/9/pc/mp.c:207,224 (short | long)
1997/0327    
		break; 
 
	case PcmpExtINT: 
1997/0522    
po = PcmpHIGH; 
el = PcmpEDGE; 
1997/0327    
		v |= ApicExtINT; 
1997/0524    
		/* 
		 * The AMI Goliath doesn't boot successfully with it's LINTR0 entry 
		 * which decodes to low+level. The PPro manual says ExtINT should be 
		 * level, whereas the Pentium is edge. Setting the Goliath to edge+high 
		 * seems to cure the problem. Other PPro MP tables (e.g. ASUS P/I-P65UP5 
		 * have a entry which decodes to edge+high, so who knows. 
		 * Perhaps it would be best just to not set an ExtINT entry at all, 
		 * it shouldn't be needed for SMP mode. 
		 */ 
		po = PcmpHIGH; 
		el = PcmpEDGE; 
1997/0327    
		break; 
	} 
 
1997/0522/sys/src/9/pc/mp.c:587,5931997/0524/sys/src/9/pc/mp.c:596,602
1997/0327    
	int r; 
 
	r = mpintrenablex(v, tbdf, irqctl); 
	if(r == -1 && tbdf != BUSUNKNOWN && _mp_->specrev == 1) 
1997/0524    
	if(r == -1 && tbdf != BUSUNKNOWN /*&& _mp_->specrev == 1*/) 
1997/0327    
		return mpintrenablex(v, BUSUNKNOWN, irqctl); 
	return r; 
} 
1997/0524/sys/src/9/pc/mp.c:124,1501997/1101/sys/src/9/pc/mp.c:124,143 (short | long)
1997/0327    
mkioapic(PCMPioapic* p) 
{ 
	Apic *apic; 
	ulong addr, *pte; 
 
	if(!(p->flags & PcmpEN) || p->apicno > MaxAPICNO) 
		return 0; 
 
	/* 
	 * Map the I/O APIC. This should be in the same 4MB segment 
	 * as MACHADDR so no new 2nd level table will be allocated. 
1997/1101    
	 * Map the I/O APIC. 
1997/0327    
	 */ 
	addr = p->addr; 
	if((pte = mmuwalk(m->pdb, addr, 1)) == 0) 
1997/1101    
	if(mmukmap(p->addr, 0, 1024) == 0) 
1997/0327    
		return 0; 
	if(!(*pte & PTEVALID)){ 
		*pte = addr|PTEWRITE|PTEUNCACHED|PTEVALID; 
		mmuflushtlb(PADDR(m->pdb)); 
	} 
 
	apic = &mpapic[p->apicno]; 
	apic->type = PcmpIOAPIC; 
	apic->apicno = p->apicno; 
	apic->addr = KADDR(addr); 
1997/1101    
	apic->addr = KADDR(p->addr); 
1997/0327    
	apic->flags = p->flags; 
 
	return apic; 
1997/0524/sys/src/9/pc/mp.c:290,2971997/1101/sys/src/9/pc/mp.c:283,289
1997/0327    
{ 
	int clkin; 
 
	/*iprint("Hello Squidboy\n");*/ 
                 
1997/1101    
//	iprint("Hello Squidboy\n"); 
1997/0327    
	machinit(); 
	mmuinit(); 
 
1997/0524/sys/src/9/pc/mp.c:322,3461997/1101/sys/src/9/pc/mp.c:314,344
1997/0327    
mpstartap(Apic* apic) 
{ 
	ulong *apbootp, *pdb, *pte; 
	Mach *mach; 
1997/1101    
	Mach *mach, *mach0; 
1997/0327    
	int i, machno; 
	uchar *p; 
 
1997/1101    
	mach0 = MACHP(0); 
 
1997/0327    
	/* 
	 * Initialise the AP page-tables and Mach structure. These are 
	 * the same as for the bootstrap processor with the exception of 
1997/1101    
	 * Initialise the AP page-tables and Mach structure. The page-tables 
	 * are the same as for the bootstrap processor with the exception of 
1997/0327    
	 * the PTE for the Mach structure. 
	 * Xspanalloc will panic if an allocation can't be made. 
	 */ 
	pdb = xspanalloc(3*BY2PG, BY2PG, 0); 
	memmove(pdb, (void*)CPU0PDB, BY2PG); 
1997/1101    
	p = xspanalloc(3*BY2PG, BY2PG, 0); 
	pdb = (ulong*)p; 
	memmove(pdb, mach0->pdb, BY2PG); 
	p += BY2PG; 
1997/0327    
 
	pte = (ulong*)(((uchar*)pdb)+BY2PG); 
	memmove(pte, (void*)CPU0MACHPTE, BY2PG); 
	pdb[PDX(MACHADDR)] = PADDR(pte)|PTEWRITE|PTEVALID; 
1997/1101    
	if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil) 
		return; 
	memmove(p, KADDR(PPN(*pte)), BY2PG); 
	*pte = PADDR(p)|PTEWRITE|PTEVALID; 
	p += BY2PG; 
1997/0327    
 
	mach = (Mach*)(((uchar*)pdb)+2*BY2PG); 
	if((pte = mmuwalk(pdb, MACHADDR, 0)) == 0) 
1997/1101    
	mach = (Mach*)p; 
	if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil) 
1997/0327    
		return; 
	*pte = PADDR(mach)|PTEWRITE|PTEVALID; 
 
1997/0524/sys/src/9/pc/mp.c:386,3921997/1101/sys/src/9/pc/mp.c:384,389
1997/0327    
mpinit(void) 
{ 
	PCMP *pcmp; 
	ulong *pte; 
	uchar *e, *p; 
1997/0405    
	Apic *apic, *bpapic; 
1997/0327    
	int clkin; 
1997/0524/sys/src/9/pc/mp.c:398,4121997/1101/sys/src/9/pc/mp.c:395,404
1997/0327    
	pcmp = KADDR(_mp_->physaddr); 
 
	/* 
	 * Map the local APIC. This should be in the same 4MB segment 
	 * as MACHADDR so no new 2nd level table will be allocated. 
1997/1101    
	 * Map the local APIC. 
1997/0327    
	 */ 
	if((pte = mmuwalk(m->pdb, pcmp->lapicbase, 1)) == 0) 
1997/1101    
	if(mmukmap(pcmp->lapicbase, 0, 1024) == 0) 
1997/0327    
		return; 
	if(!(*pte & PTEVALID)){ 
		*pte = pcmp->lapicbase|PTEWRITE|PTEUNCACHED|PTEVALID; 
		mmuflushtlb(PADDR(m->pdb)); 
	} 
 
1997/0405    
	bpapic = 0; 
 
1997/0524/sys/src/9/pc/mp.c:633,6391997/1101/sys/src/9/pc/mp.c:625,631
1997/0327    
	 * warm-boot sequence is tried. The following is Intel specific and 
	 * seems to perform a cold-boot, but at least it comes back. 
	 */ 
	*(ushort*)(KZERO|0x472) = 0x1234;		/* BIOS warm-boot flag */ 
1997/1101    
	*(ushort*)KADDR(0x472) = 0x1234;		/* BIOS warm-boot flag */ 
1997/0327    
	outb(0xCF9, 0x02); 
	outb(0xCF9, 0x06); 
#else 
1997/1101/sys/src/9/pc/mp.c:12,171998/0320/sys/src/9/pc/mp.c:12,19 (short | long)
1997/0327    
 
static Bus* mpbus; 
static Bus* mpbuslast; 
1998/0320    
static int mpisabus = -1; 
static int mpeisabus = -1; 
1997/0327    
static Apic mpapic[MaxAPICNO+1]; 
static int machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */ 
static Lock mprdthilock; 
1997/1101/sys/src/9/pc/mp.c:93,1031998/0320/sys/src/9/pc/mp.c:95,115
1997/0327    
	if(bus->type == BusEISA){ 
		bus->po = PcmpLOW; 
		bus->el = PcmpLEVEL; 
1998/0320    
		if(mpeisabus != -1) 
			print("mkbus: more than one EISA bus\n"); 
		mpeisabus = bus->busno; 
1997/0327    
	} 
	else if(bus->type == BusPCI){ 
		bus->po = PcmpLOW; 
		bus->el = PcmpLEVEL; 
	} 
1998/0320    
	else if(bus->type == BusISA){ 
		bus->po = PcmpHIGH; 
		bus->el = PcmpEDGE; 
		if(mpisabus != -1) 
			print("mkbus: more than one ISA bus\n"); 
		mpisabus = bus->busno; 
	} 
1997/0327    
	else{ 
		bus->po = PcmpHIGH; 
		bus->el = PcmpEDGE; 
1997/1101/sys/src/9/pc/mp.c:495,5241998/0320/sys/src/9/pc/mp.c:507,519
1997/0327    
	Apic *apic; 
	int bno, dno, lo, n, type; 
 
	if(v >= VectorLAPIC && v <= MaxVectorLAPIC){ 
		if(v != VectorSPURIOUS) 
			irqctl->isr = lapiceoi; 
		irqctl->isintr = 1; 
		return v; 
	} 
                 
	if(v < VectorPIC || v > MaxVectorPIC) 
		return 0; 
                 
	/* 
	 * Find the bus, default is ISA. 
	 * There cannot be multiple ISA or EISA buses. 
	 */ 
	if(tbdf == BUSUNKNOWN){ 
		type = BusISA; 
		bno = 0; 
		dno = -1; 
	} 
	else{ 
		type = BUSTYPE(tbdf); 
		bno = BUSBNO(tbdf); 
		dno = BUSDNO(tbdf); 
	} 
1998/0320    
	type = BUSTYPE(tbdf); 
	bno = BUSBNO(tbdf); 
	dno = BUSDNO(tbdf); 
1997/0327    
	n = 0; 
	for(bus = mpbus; bus; bus = bus->next){ 
		if(bus->type != type) 
1997/1101/sys/src/9/pc/mp.c:528,5481998/0320/sys/src/9/pc/mp.c:523,530
1997/0327    
		n++; 
	} 
	if(bus == 0){ 
		/* 
		 * The MP configuration table on some older systems 
		 * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus 
		 * but none for ISA. It also has the interrupt type and 
		 * polarity set to 'default for this bus' which wouldn't 
		 * be compatible with ISA. 
		 */ 
		for(bus = mpbus; bus; bus = bus->next){ 
			if(bus->type == BusEISA) 
				break; 
		} 
		if(bus == 0){ 
			print("ioapicirq: can't find bus type %d\n", type); 
			return -1; 
		} 
1998/0320    
		print("ioapicirq: can't find bus type %d\n", type); 
		return -1; 
1997/0327    
	} 
 
	/* 
1997/1101/sys/src/9/pc/mp.c:553,5581998/0320/sys/src/9/pc/mp.c:535,547
1997/0327    
			n = (aintr->intr->irq>>2) & 0x1F; 
			if(n != dno) 
				continue; 
1998/0320    
			/* 
			 * Problem: there can be an entry for 
			 * each of the device #INT[ABCD] lines. 
			 * For now look only for #INTA. 
			 */ 
			if(aintr->intr->irq & 0x03) 
				continue; 
1997/0327    
		} 
		else{ 
			n = aintr->intr->irq; 
1997/1101/sys/src/9/pc/mp.c:587,5961998/0320/sys/src/9/pc/mp.c:576,624
1997/0327    
{ 
	int r; 
 
	r = mpintrenablex(v, tbdf, irqctl); 
1997/0524    
	if(r == -1 && tbdf != BUSUNKNOWN /*&& _mp_->specrev == 1*/) 
1997/0327    
		return mpintrenablex(v, BUSUNKNOWN, irqctl); 
	return r; 
1998/0320    
	/* 
	 * If the bus is known, try it. 
	 * BUSUNKNOWN is given both by [E]ISA devices and by 
	 * interrupts local to the processor (local APIC, coprocessor 
	 * breakpoint and page-fault). 
	 */ 
	if(tbdf != BUSUNKNOWN && (r = mpintrenablex(v, tbdf, irqctl)) != -1) 
		return r; 
 
	if(v >= VectorLAPIC && v <= MaxVectorLAPIC){ 
		if(v != VectorSPURIOUS) 
			irqctl->isr = lapiceoi; 
		irqctl->isintr = 1; 
		return v; 
	} 
	if(v < VectorPIC || v > MaxVectorPIC){ 
		print("mpintrenable: vector %d out of range\n", v); 
		return -1; 
	} 
 
	/* 
	 * Either didn't find it or we have to try the default 
	 * buses (ISA and EISA). This hack is due to either over-zealousness 
	 * or laziness on the part of some manufacturers. 
	 * 
	 * The MP configuration table on some older systems 
	 * (e.g. ASUS PCI/E-P54NP4) has an entry for the EISA bus 
	 * but none for ISA. It also has the interrupt type and 
	 * polarity set to 'default for this bus' which wouldn't 
	 * be compatible with ISA. 
	 */ 
	if(mpisabus != -1){ 
		r = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0), irqctl); 
		if(r != -1) 
			return r; 
	} 
	if(mpeisabus != -1){ 
		r = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0), irqctl); 
		if(r != -1) 
			return r; 
	} 
 
	return -1; 
1997/0327    
} 
 
void 
1998/0320/sys/src/9/pc/mp.c:4,91998/0401/sys/src/9/pc/mp.c:4,10 (short | long)
Add MTRR register support. Add NMI handler for debugging.
The NMI handler prints the CPUs current PC.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
1998/0401    
#include "ureg.h" 
1997/0327    
 
#include "mp.h" 
#include "apbootstrap.h" 
1998/0320/sys/src/9/pc/mp.c:287,2921998/0401/sys/src/9/pc/mp.c:288,345
1997/0327    
	return v; 
} 
 
1998/0401    
static void 
checkmtrr(void) 
{ 
	int i, vcnt; 
	Mach *mach0; 
 
	/* 
	 * If there are MTRR registers, snarf them for validation. 
	 */ 
	if(!(m->cpuiddx & 0x1000)) 
		return; 
 
	rdmsr(0x0FE, &m->mtrrcap); 
	rdmsr(0x2FF, &m->mtrrdef); 
	if(m->mtrrcap & 0x0100){ 
		rdmsr(0x250, &m->mtrrfix[0]); 
		rdmsr(0x258, &m->mtrrfix[1]); 
		rdmsr(0x259, &m->mtrrfix[2]); 
		for(i = 0; i < 8; i++) 
			rdmsr(0x268+i, &m->mtrrfix[(i+3)]); 
	} 
	vcnt = m->mtrrcap & 0x00FF; 
	if(vcnt > nelem(m->mtrrvar)) 
		vcnt = nelem(m->mtrrvar); 
	for(i = 0; i < vcnt; i++) 
		rdmsr(0x200+i, &m->mtrrvar[i]); 
 
	/* 
	 * If not the bootstrap processor, compare. 
	 */ 
	if(m->machno == 0) 
		return; 
 
	mach0 = MACHP(0); 
	if(mach0->mtrrcap != m->mtrrcap) 
		print("mtrrcap%d: %lluX %lluX\n", 
			m->machno, mach0->mtrrcap, m->mtrrcap); 
	if(mach0->mtrrdef != m->mtrrdef) 
		print("mtrrdef%d: %lluX %lluX\n", 
			m->machno, mach0->mtrrdef, m->mtrrdef); 
	for(i = 0; i < 11; i++){ 
		if(mach0->mtrrfix[i] != m->mtrrfix[i]) 
			print("mtrrfix%d: i%d: %lluX %lluX\n", 
				m->machno, i, mach0->mtrrfix[i], m->mtrrfix[i]); 
	} 
	for(i = 0; i < vcnt; i++){ 
		if(mach0->mtrrvar[i] != m->mtrrvar[i]) 
			print("mtrrvar%d: i%d: %lluX %lluX\n", 
				m->machno, i, mach0->mtrrvar[i], m->mtrrvar[i]); 
	} 
} 
 
1997/0327    
#define PDX(va)		((((ulong)(va))>>22) & 0x03FF) 
#define PTX(va)		((((ulong)(va))>>12) & 0x03FF) 
 
1998/0320/sys/src/9/pc/mp.c:301,3061998/0401/sys/src/9/pc/mp.c:354,360
1997/0327    
 
	cpuidentify(); 
	cpuidprint(); 
1998/0401    
	checkmtrr(); 
1997/0327    
 
	lock(&mprdthilock); 
	mprdthi |= (1<<apic->apicno)<<24; 
1998/0320/sys/src/9/pc/mp.c:392,3971998/0401/sys/src/9/pc/mp.c:446,466
1997/0327    
	nvramwrite(0x0F, 0x00); 
} 
 
1998/0401    
static void 
senddbgnmi(void) 
{ 
	/* 
	 * NMI all excluding self. 
	 */ 
	lapicicrw(0, 0x000C0000|ApicNMI); 
} 
 
static void 
mpdbg(Ureg* ureg, void*) 
{ 
	iprint("MPDBG: cpu%d: PC 0x%uX\n", m->machno, ureg->pc); 
} 
 
1997/0327    
void 
mpinit(void) 
{ 
1998/0320/sys/src/9/pc/mp.c:482,4871998/0401/sys/src/9/pc/mp.c:551,558
1997/0405    
	intrenable(VectorSPURIOUS, lapicspurious, 0, BUSUNKNOWN); 
	lapiconline(clkin); 
1997/0327    
 
1998/0401    
	checkmtrr(); 
 
1997/0405    
	/* 
	 * Initialise the application processors. 
	 */ 
1998/0320/sys/src/9/pc/mp.c:493,5021998/0401/sys/src/9/pc/mp.c:564,576
1997/0327    
 
	/* 
	 * Remember to set conf.copymode here if nmach > 1. 
	 * Look for an ExtINT line and enable it. 
1998/0401    
	 * Should look for an ExtINT line and enable it. 
1997/0327    
	 */ 
	if(conf.nmach > 1) 
		conf.copymode = 1; 
1998/0401    
 
	consdebug = senddbgnmi; 
	intrenable(VectorNMI, mpdbg, 0, BUSUNKNOWN); 
1997/0327    
} 
 
static int 
1998/0320/sys/src/9/pc/mp.c:624,6291998/0401/sys/src/9/pc/mp.c:698,705
1997/0327    
void 
mpshutdown(void) 
{ 
1998/0401    
	int apicno, machno; 
 
1997/0327    
	/* 
	 * To be done... 
	 */ 
1998/0320/sys/src/9/pc/mp.c:639,6441998/0401/sys/src/9/pc/mp.c:715,728
1997/0327    
	} 
 
	print("apshutdown: active = 0x%2.2uX\n", active.machs); 
1998/0401    
	if(active.machs){ 
		for(machno = 1; machno < conf.nmach; machno++){ 
			if(!(active.machs & (1<<machno))) 
				continue; 
			apicno = machno2apicno[machno]; 
			lapicicrw(1<<apicno, ApicNMI); 
		} 
	} 
1997/0327    
	delay(1000); 
	splhi(); 
 
1998/0401/sys/src/9/pc/mp.c:271,2781998/0605/sys/src/9/pc/mp.c:271,286 (short | long)
Bug fix: do not enable PcmpExtINT and PcmpNMI to fix problem with Pentium Pro.
Remove NMI debugging.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
	if((bus = mpgetbus(p->busno)) == 0) 
		return 0; 
	intin = p->intin; 
	v = mpintrinit(bus, p, VectorLAPIC+intin); 
 
1998/0605    
	/* 
	 * Pentium Pros have problems if LINT[01] are set to ExtINT 
	 * so just bag it. Should be OK for SMP mode. 
	 */ 
	if(p->intr == PcmpExtINT || p->intr == PcmpNMI) 
		v = ApicIMASK; 
	else 
		v = mpintrinit(bus, p, VectorLAPIC+intin); 
 
1997/0327    
	if(p->apicno == 0xFF){ 
		for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
			if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR) 
1998/0401/sys/src/9/pc/mp.c:446,4661998/0605/sys/src/9/pc/mp.c:454,459
1997/0327    
	nvramwrite(0x0F, 0x00); 
} 
 
1998/0401    
static void 
senddbgnmi(void) 
{ 
	/* 
	 * NMI all excluding self. 
	 */ 
	lapicicrw(0, 0x000C0000|ApicNMI); 
} 
                 
static void 
mpdbg(Ureg* ureg, void*) 
{ 
	iprint("MPDBG: cpu%d: PC 0x%uX\n", m->machno, ureg->pc); 
} 
                 
1997/0327    
void 
mpinit(void) 
{ 
1998/0401/sys/src/9/pc/mp.c:568,5761998/0605/sys/src/9/pc/mp.c:561,566
1997/0327    
	 */ 
	if(conf.nmach > 1) 
		conf.copymode = 1; 
1998/0401    
                 
	consdebug = senddbgnmi; 
	intrenable(VectorNMI, mpdbg, 0, BUSUNKNOWN); 
1997/0327    
} 
 
static int 
1998/0401/sys/src/9/pc/mp.c:695,7091998/0605/sys/src/9/pc/mp.c:685,699
1998/0320    
	return -1; 
1997/0327    
} 
 
1998/0605    
static Lock mpshutdownlock; 
 
1997/0327    
void 
mpshutdown(void) 
{ 
1998/0401    
	int apicno, machno; 
                 
1997/0327    
	/* 
	 * To be done... 
	 */ 
	if(m->machno){ 
1998/0605    
	if(!canlock(&mpshutdownlock)){ 
1997/0327    
		/* 
		 * If this processor received the CTRL-ALT-DEL from 
		 * the keyboard, acknowledge it. Send an INIT to self. 
1998/0401/sys/src/9/pc/mp.c:710,7281998/0605/sys/src/9/pc/mp.c:700,709
1997/0327    
		 */ 
		if(lapicisr(VectorKBD)) 
			lapiceoi(VectorKBD); 
		lapicicrw(0, 0x00040000|ApicINIT);	 
		idle(); 
	} 
 
	print("apshutdown: active = 0x%2.2uX\n", active.machs); 
1998/0401    
	if(active.machs){ 
		for(machno = 1; machno < conf.nmach; machno++){ 
			if(!(active.machs & (1<<machno))) 
				continue; 
			apicno = machno2apicno[machno]; 
			lapicicrw(1<<apicno, ApicNMI); 
		} 
	} 
1997/0327    
	delay(1000); 
	splhi(); 
 
1998/0605/sys/src/9/pc/mp.c:354,3621998/0716/sys/src/9/pc/mp.c:354,364 (short | long)
1997/0327    
static void 
squidboy(Apic* apic) 
{ 
	int clkin; 
                 
1997/1101    
//	iprint("Hello Squidboy\n"); 
1998/0716    
 
	/* synchronize cycle clocks */ 
	wrmsr(0x10, m->clockstart); 
 
1997/0327    
	machinit(); 
	mmuinit(); 
 
1998/0605/sys/src/9/pc/mp.c:374,3811998/0716/sys/src/9/pc/mp.c:376,383
1997/0327    
	while(MACHP(0)->ticks == 0) 
		; 
 
	clkin = lapicinit(apic); 
	lapiconline(clkin); 
1998/0716    
	lapicinit(apic); 
	lapiconline(); 
1997/0327    
 
	lock(&active); 
	active.machs |= 1<<m->machno; 
1998/0605/sys/src/9/pc/mp.c:441,4461998/0716/sys/src/9/pc/mp.c:443,449
1997/0327    
	*p = i>>8; 
 
	nvramwrite(0x0F, 0x0A); 
1998/0716    
	rdmsr(0x10, &mach->clockstart); 
1997/0327    
	lapicstartap(apic, PADDR(APBOOTSTRAP)); 
1997/0521    
	for(i = 0; i < 100000; i++){ 
		lock(&mprdthilock); 
1998/0605/sys/src/9/pc/mp.c:460,4661998/0716/sys/src/9/pc/mp.c:463,468
1997/0327    
	PCMP *pcmp; 
	uchar *e, *p; 
1997/0405    
	Apic *apic, *bpapic; 
1997/0327    
	int clkin; 
 
	i8259init(); 
 
1998/0605/sys/src/9/pc/mp.c:529,5351998/0716/sys/src/9/pc/mp.c:531,537
1997/0405    
	if(bpapic == 0) 
		return; 
1997/0327    
 
1997/0405    
	clkin = lapicinit(bpapic); 
1998/0716    
	lapicinit(bpapic); 
1997/0405    
	lock(&mprdthilock); 
	mprdthi |= (1<<bpapic->apicno)<<24; 
	unlock(&mprdthilock); 
1998/0605/sys/src/9/pc/mp.c:542,5481998/0716/sys/src/9/pc/mp.c:544,550
1997/0405    
	intrenable(VectorTIMER, clockintr, 0, BUSUNKNOWN); 
	intrenable(VectorERROR, lapicerror, 0, BUSUNKNOWN); 
	intrenable(VectorSPURIOUS, lapicspurious, 0, BUSUNKNOWN); 
	lapiconline(clkin); 
1998/0716    
	lapiconline(); 
1997/0327    
 
1998/0401    
	checkmtrr(); 
 
1998/0716/sys/src/9/pc/mp.c:356,3641998/0717/sys/src/9/pc/mp.c:356,361 (short | long)
Change clock synchronization mechanism: stomp on TSC while looping.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
{ 
1997/1101    
//	iprint("Hello Squidboy\n"); 
1998/0716    
 
	/* synchronize cycle clocks */ 
	wrmsr(0x10, m->clockstart); 
                 
1997/0327    
	machinit(); 
	mmuinit(); 
 
1998/0716/sys/src/9/pc/mp.c:374,3801998/0717/sys/src/9/pc/mp.c:371,377
1997/0327    
	 * Restrain your octopus! Don't let it go out on the sea! 
	 */ 
	while(MACHP(0)->ticks == 0) 
		; 
1998/0717    
		wrmsr(0x10, MACHP(0)->fastclock); /* synchronize fast counters */ 
1997/0327    
 
1998/0716    
	lapicinit(apic); 
	lapiconline(); 
1998/0716/sys/src/9/pc/mp.c:443,4491998/0717/sys/src/9/pc/mp.c:440,445
1997/0327    
	*p = i>>8; 
 
	nvramwrite(0x0F, 0x0A); 
1998/0716    
	rdmsr(0x10, &mach->clockstart); 
1997/0327    
	lapicstartap(apic, PADDR(APBOOTSTRAP)); 
1997/0521    
	for(i = 0; i < 100000; i++){ 
		lock(&mprdthilock); 
1998/0717/sys/src/9/pc/mp.c:483,4881998/0729/sys/src/9/pc/mp.c:483,496 (short | long)
1997/0327    
	e = ((uchar*)pcmp)+pcmp->length; 
	while(p < e) switch(*p){ 
 
1998/0729    
	default: 
		print("mpinit: unknown PCMP type 0x%uX (e-p 0x%uX)\n", *p, e-p); 
		while(p < e){ 
			print("%uX ", *p); 
			p++; 
		} 
		break; 
 
1997/0327    
	case PcmpPROCESSOR: 
		if(apic = mkprocessor((PCMPprocessor*)p)){ 
			/* 
1998/0729/sys/src/9/pc/mp.c:484,4901998/0825/sys/src/9/pc/mp.c:484,490 (short | long)
Bug fix: print format.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
	while(p < e) switch(*p){ 
 
1998/0729    
	default: 
		print("mpinit: unknown PCMP type 0x%uX (e-p 0x%uX)\n", *p, e-p); 
1998/0825    
		print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n", *p, e-p); 
1998/0729    
		while(p < e){ 
			print("%uX ", *p); 
			p++; 
1998/0825/sys/src/9/pc/mp.c:19,241998/0910/sys/src/9/pc/mp.c:19,25 (short | long)
XXX big interrupt change with vctl.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
static int machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */ 
static Lock mprdthilock; 
static int mprdthi; 
1998/0910    
static Ref mpvnoref;			/* unique vector assignment */ 
1997/0327    
 
static char* buses[] = { 
	"CBUSI ", 
1998/0825/sys/src/9/pc/mp.c:54,601998/0910/sys/src/9/pc/mp.c:55,60
1997/0327    
	apic->type = PcmpPROCESSOR; 
	apic->apicno = p->apicno; 
	apic->flags = p->flags; 
	apic->vecbase = VectorLAPIC; 
	apic->lintr[0] = ApicIMASK; 
	apic->lintr[1] = ApicIMASK; 
 
1998/0825/sys/src/9/pc/mp.c:183,1891998/0910/sys/src/9/pc/mp.c:183,189
1997/0327    
} 
 
static int 
mpintrinit(Bus* bus, PCMPintr* intr, int vector) 
1998/0910    
mpintrinit(Bus* bus, PCMPintr* intr, int vno) 
1997/0327    
{ 
	int el, po, v; 
 
1998/0825/sys/src/9/pc/mp.c:191,1971998/0910/sys/src/9/pc/mp.c:191,197
1997/0327    
	 * Parse an I/O or Local APIC interrupt table entry and 
	 * return the encoded vector. 
	 */ 
	v = vector; 
1998/0910    
	v = vno; 
1997/0327    
 
1997/0405    
	po = intr->flags & PcmpPOMASK; 
	el = intr->flags & PcmpELMASK; 
1998/0825/sys/src/9/pc/mp.c:230,2361998/0910/sys/src/9/pc/mp.c:230,236
1997/0327    
 
	/* 
	 */ 
	if(bus->type == BusEISA && !po && !el /*&& !(elcr & (1<<(v-VectorPIC)))*/){ 
1998/0910    
	if(bus->type == BusEISA && !po && !el){ 
1997/0327    
		po = PcmpHIGH; 
		el = PcmpEDGE; 
	} 
1998/0825/sys/src/9/pc/mp.c:265,2721998/0910/sys/src/9/pc/mp.c:265,270
1997/0327    
	/* 
	 * The offsets of vectors for LINT[01] are known to be 
	 * 0 and 1 from the local APIC vector space at VectorLAPIC. 
	 * Can't use apic->vecbase here as this vector may be applied 
	 * to all local APICs (apicno == 0xFF). 
	 */ 
	if((bus = mpgetbus(p->busno)) == 0) 
		return 0; 
1998/0825/sys/src/9/pc/mp.c:274,2801998/0910/sys/src/9/pc/mp.c:272,278
1997/0327    
 
1998/0605    
	/* 
	 * Pentium Pros have problems if LINT[01] are set to ExtINT 
	 * so just bag it. Should be OK for SMP mode. 
1998/0910    
	 * so just bag it, SMP mode shouldn't need ExtINT anyway. 
1998/0605    
	 */ 
	if(p->intr == PcmpExtINT || p->intr == PcmpNMI) 
		v = ApicIMASK; 
1998/0825/sys/src/9/pc/mp.c:545,5531998/0910/sys/src/9/pc/mp.c:543,551
1997/0405    
	 * and do not appear in the I/O APIC so it is OK 
	 * to set them now. 
	 */ 
	intrenable(VectorTIMER, clockintr, 0, BUSUNKNOWN); 
	intrenable(VectorERROR, lapicerror, 0, BUSUNKNOWN); 
	intrenable(VectorSPURIOUS, lapicspurious, 0, BUSUNKNOWN); 
1998/0910    
	intrenable(IrqTIMER, clockintr, 0, BUSUNKNOWN); 
	intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN); 
	intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN); 
1998/0716    
	lapiconline(); 
1997/0327    
 
1998/0401    
	checkmtrr(); 
1998/0825/sys/src/9/pc/mp.c:570,5911998/0910/sys/src/9/pc/mp.c:568,590
1997/0327    
} 
 
static int 
mpintrenablex(int v, int tbdf, Irqctl* irqctl) 
1998/0910    
mpintrenablex(Vctl* v) 
1997/0327    
{ 
	Bus *bus; 
	Aintr *aintr; 
	Apic *apic; 
	int bno, dno, lo, n, type; 
1998/0910    
	Pcidev *pcidev; 
	int bno, dno, irq, lo, n, type, vno; 
1997/0327    
 
	/* 
	 * Find the bus, default is ISA. 
	 * There cannot be multiple ISA or EISA buses. 
	 */ 
1998/0320    
	type = BUSTYPE(tbdf); 
	bno = BUSBNO(tbdf); 
	dno = BUSDNO(tbdf); 
1998/0910    
	type = BUSTYPE(v->tbdf); 
	bno = BUSBNO(v->tbdf); 
	dno = BUSDNO(v->tbdf); 
1997/0327    
	n = 0; 
	for(bus = mpbus; bus; bus = bus->next){ 
1998/0910    
	for(bus = mpbus; bus != nil; bus = bus->next){ 
1997/0327    
		if(bus->type != type) 
			continue; 
		if(n == bno) 
1998/0825/sys/src/9/pc/mp.c:592,6301998/0910/sys/src/9/pc/mp.c:591,662
1997/0327    
			break; 
		n++; 
	} 
	if(bus == 0){ 
1998/0910    
	if(bus == nil){ 
1998/0320    
		print("ioapicirq: can't find bus type %d\n", type); 
		return -1; 
1997/0327    
	} 
 
	/* 
	 * Find the interrupt info. 
1998/0910    
	 * For PCI devices the interrupt pin (INT[ABCD]) and device 
	 * number are encoded into the entry irq field, so create something 
	 * to match on. The interrupt pin used by the device has to be 
	 * obtained from the PCI config space. 
1997/0327    
	 */ 
1998/0910    
	if(bus->type == BusPCI){ 
		pcidev = pcimatchtbdf(v->tbdf); 
		if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0) 
			irq = (dno<<2)|(n-1); 
		else 
			irq = -1; 
		//print("pcidev %uX: irq %uX v->irq %uX\n", v->tbdf, irq, v->irq); 
	} 
	else 
		irq = v->irq; 
 
	/* 
	 * Find a matching interrupt entry from the list of interrupts 
	 * attached to this bus. 
	 */ 
1997/0327    
	for(aintr = bus->aintr; aintr; aintr = aintr->next){ 
		if(bus->type == BusPCI){ 
			n = (aintr->intr->irq>>2) & 0x1F; 
			if(n != dno) 
				continue; 
1998/0320    
			/* 
			 * Problem: there can be an entry for 
			 * each of the device #INT[ABCD] lines. 
			 * For now look only for #INTA. 
			 */ 
			if(aintr->intr->irq & 0x03) 
				continue; 
1998/0910    
		if(aintr->intr->irq != irq) 
			continue; 
 
		/* 
		 * Check not already enabled. This is a bad thing as it implies the 
		 * same device is requesting the same interrupt to be enabled multiple 
		 * times. The RDT read here is safe for now as currently interrupts 
		 * are never disabled once enabled. 
		 */ 
		apic = aintr->apic; 
		ioapicrdtr(apic, aintr->intr->intin, 0, &lo); 
		if(!(lo & ApicIMASK)){ 
			print("mpintrenable: multiple enable of irq %d, tbdf %uX\n", 
				v->irq, v->tbdf); 
			return -1; 
1997/0327    
		} 
		else{ 
			n = aintr->intr->irq; 
			if(n != (v-VectorPIC)) 
				continue; 
		} 
 
		lo = mpintrinit(bus, aintr->intr, v); 
1998/0910    
		/* 
		 * With the APIC a unique vector can be assigned to each request 
		 * to enable an interrupt. There are two reasons this is a good idea: 
		 * 1) to prevent lost interrupts, no more than 2 interrupts should 
		 *    be assigned per block of 16 vectors (there is an in-service 
		 *    entry and a holding entry for each priority level and there is 
		 *    a priority level per block of 16 interrupts). 
		 * 2) each input pin on the IOAPIC will receive a different vector 
		 *    regardless of whether the devices on that pin use the same IRQ 
		 *    as devices on another pin. 
		 */ 
		vno = VectorAPIC + (incref(&mpvnoref)-1)*8; 
		if(vno > MaxVectorAPIC){ 
			print("mpintrenable: vno %d, irq %d, tbdf %uX\n", 
				vno, v->irq, v->tbdf); 
			return -1; 
		} 
		lo = mpintrinit(bus, aintr->intr, vno); 
1997/0327    
		if(lo & ApicIMASK) 
			return -1; 
		lo |= ApicLOGICAL; 
 
		apic = aintr->apic; 
		if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC){ 
			lock(&mprdthilock); 
 			ioapicrdtw(apic, aintr->intr->intin, mprdthi, lo); 
1998/0825/sys/src/9/pc/mp.c:631,6411998/0910/sys/src/9/pc/mp.c:663,672
1997/0327    
			unlock(&mprdthilock); 
		} 
 
		irqctl->isr = lapicisr; 
		irqctl->eoi = lapiceoi; 
		irqctl->isintr = 1; 
1998/0910    
		v->isr = lapicisr; 
		v->eoi = lapiceoi; 
1997/0327    
 
		return lo & 0xFF; 
1998/0910    
		return vno; 
1997/0327    
	} 
 
	return -1; 
1998/0825/sys/src/9/pc/mp.c:642,6501998/0910/sys/src/9/pc/mp.c:673,681
1997/0327    
} 
 
int 
mpintrenable(int v, int tbdf, Irqctl* irqctl) 
1998/0910    
mpintrenable(Vctl* v) 
1997/0327    
{ 
	int r; 
1998/0910    
	int irq, tbdf, vno; 
1997/0327    
 
1998/0320    
	/* 
	 * If the bus is known, try it. 
1998/0825/sys/src/9/pc/mp.c:652,6741998/0910/sys/src/9/pc/mp.c:683,706
1998/0320    
	 * interrupts local to the processor (local APIC, coprocessor 
	 * breakpoint and page-fault). 
	 */ 
	if(tbdf != BUSUNKNOWN && (r = mpintrenablex(v, tbdf, irqctl)) != -1) 
		return r; 
1998/0910    
	tbdf = v->tbdf; 
	if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v)) != -1) 
		return vno; 
1998/0320    
 
	if(v >= VectorLAPIC && v <= MaxVectorLAPIC){ 
		if(v != VectorSPURIOUS) 
			irqctl->isr = lapiceoi; 
		irqctl->isintr = 1; 
		return v; 
1998/0910    
	irq = v->irq; 
	if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){ 
		if(irq != IrqSPURIOUS) 
			v->isr = lapiceoi; 
		return VectorPIC+irq; 
1998/0320    
	} 
	if(v < VectorPIC || v > MaxVectorPIC){ 
		print("mpintrenable: vector %d out of range\n", v); 
1998/0910    
	if(irq < 0 || irq > MaxIrqPIC){ 
		print("mpintrenable: irq %d out of range\n", irq); 
1998/0320    
		return -1; 
	} 
 
	/* 
	 * Either didn't find it or we have to try the default 
	 * buses (ISA and EISA). This hack is due to either over-zealousness 
1998/0910    
	 * Either didn't find it or have to try the default buses 
	 * (ISA and EISA). This hack is due to either over-zealousness  
1998/0320    
	 * or laziness on the part of some manufacturers. 
	 * 
	 * The MP configuration table on some older systems 
1998/0825/sys/src/9/pc/mp.c:678,6911998/0910/sys/src/9/pc/mp.c:710,725
1998/0320    
	 * be compatible with ISA. 
	 */ 
	if(mpisabus != -1){ 
		r = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0), irqctl); 
		if(r != -1) 
			return r; 
1998/0910    
		v->tbdf = MKBUS(BusISA, 0, 0, 0); 
		vno = mpintrenablex(v); 
		if(vno != -1) 
			return vno; 
1998/0320    
	} 
	if(mpeisabus != -1){ 
		r = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0), irqctl); 
		if(r != -1) 
			return r; 
1998/0910    
		v->tbdf = MKBUS(BusEISA, 0, 0, 0); 
		vno = mpintrenablex(v); 
		if(vno != -1) 
			return vno; 
1998/0320    
	} 
 
	return -1; 
1998/0825/sys/src/9/pc/mp.c:704,7111998/0910/sys/src/9/pc/mp.c:738,747
1997/0327    
		 * If this processor received the CTRL-ALT-DEL from 
		 * the keyboard, acknowledge it. Send an INIT to self. 
		 */ 
1998/0910    
#ifdef FIXTHIS 
1997/0327    
		if(lapicisr(VectorKBD)) 
			lapiceoi(VectorKBD); 
1998/0910    
#endif /* FIX THIS */ 
1997/0327    
		idle(); 
	} 
 
1998/0910/sys/src/9/pc/mp.c:9,161998/1021/sys/src/9/pc/mp.c:9,14 (short | long)
1997/0327    
#include "mp.h" 
#include "apbootstrap.h" 
 
extern int elcr; 
                 
static Bus* mpbus; 
static Bus* mpbuslast; 
1998/0320    
static int mpisabus = -1; 
1998/1021/sys/src/9/pc/mp.c:13,181998/1022/sys/src/9/pc/mp.c:13,19 (short | long)
1997/0327    
static Bus* mpbuslast; 
1998/0320    
static int mpisabus = -1; 
static int mpeisabus = -1; 
1998/1022    
extern int elcr;			/* mask of level-triggered interrupts */ 
1997/0327    
static Apic mpapic[MaxAPICNO+1]; 
static int machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */ 
static Lock mprdthilock; 
1998/1021/sys/src/9/pc/mp.c:181,1871998/1022/sys/src/9/pc/mp.c:182,188
1997/0327    
} 
 
static int 
1998/0910    
mpintrinit(Bus* bus, PCMPintr* intr, int vno) 
1998/1022    
mpintrinit(Bus* bus, PCMPintr* intr, int vno, int /*irq*/) 
1997/0327    
{ 
	int el, po, v; 
 
1998/1021/sys/src/9/pc/mp.c:228,2341998/1022/sys/src/9/pc/mp.c:229,235
1997/0327    
 
	/* 
	 */ 
1998/0910    
	if(bus->type == BusEISA && !po && !el){ 
1998/1022    
	if(bus->type == BusEISA && !po && !el /*&& !(elcr & (1<<irq))*/){ 
1997/0327    
		po = PcmpHIGH; 
		el = PcmpEDGE; 
	} 
1998/1021/sys/src/9/pc/mp.c:275,2811998/1022/sys/src/9/pc/mp.c:276,282
1998/0605    
	if(p->intr == PcmpExtINT || p->intr == PcmpNMI) 
		v = ApicIMASK; 
	else 
		v = mpintrinit(bus, p, VectorLAPIC+intin); 
1998/1022    
		v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq); 
1998/0605    
 
1997/0327    
	if(p->apicno == 0xFF){ 
		for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
1998/1021/sys/src/9/pc/mp.c:650,6561998/1022/sys/src/9/pc/mp.c:651,657
1998/0910    
				vno, v->irq, v->tbdf); 
			return -1; 
		} 
		lo = mpintrinit(bus, aintr->intr, vno); 
1998/1022    
		lo = mpintrinit(bus, aintr->intr, vno, v->irq); 
1997/0327    
		if(lo & ApicIMASK) 
			return -1; 
		lo |= ApicLOGICAL; 
1998/1022/sys/src/9/pc/mp.c:13,191999/0301/sys/src/9/pc/mp.c:13,19 (short | long)
1997/0327    
static Bus* mpbuslast; 
1998/0320    
static int mpisabus = -1; 
static int mpeisabus = -1; 
1998/1022    
extern int elcr;			/* mask of level-triggered interrupts */ 
1999/0301    
extern int i8259elcr;			/* mask of level-triggered interrupts */ 
1997/0327    
static Apic mpapic[MaxAPICNO+1]; 
static int machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */ 
static Lock mprdthilock; 
1999/0301/sys/src/9/pc/mp.c:351,3561999/0310/sys/src/9/pc/mp.c:351,358 (short | long)
1997/0327    
static void 
squidboy(Apic* apic) 
{ 
1999/0310    
	ulong x; 
 
1997/1101    
//	iprint("Hello Squidboy\n"); 
1998/0716    
 
1997/0327    
	machinit(); 
1999/0301/sys/src/9/pc/mp.c:367,3741999/0310/sys/src/9/pc/mp.c:369,380
1997/0327    
	/* 
	 * Restrain your octopus! Don't let it go out on the sea! 
	 */ 
	while(MACHP(0)->ticks == 0) 
1998/0717    
		wrmsr(0x10, MACHP(0)->fastclock); /* synchronize fast counters */ 
1999/0310    
	lock(&active); 
	x = MACHP(0)->ticks; 
	while(MACHP(0)->ticks == x) 
		; 
	wrmsr(0x10, MACHP(0)->fastclock); /* synchronize fast counters */ 
	unlock(&active); 
1997/0327    
 
1998/0716    
	lapicinit(apic); 
	lapiconline(); 
1999/0310/sys/src/9/pc/mp.c:348,3531999/0320/sys/src/9/pc/mp.c:348,355 (short | long)
1997/0327    
#define PDX(va)		((((ulong)(va))>>22) & 0x03FF) 
#define PTX(va)		((((ulong)(va))>>12) & 0x03FF) 
 
1999/0320    
Lock clocksynclock; 
 
1997/0327    
static void 
squidboy(Apic* apic) 
{ 
1999/0310/sys/src/9/pc/mp.c:369,3801999/0320/sys/src/9/pc/mp.c:371,382
1997/0327    
	/* 
	 * Restrain your octopus! Don't let it go out on the sea! 
	 */ 
1999/0310    
	lock(&active); 
1999/0320    
	ilock(&clocksynclock); 
1999/0310    
	x = MACHP(0)->ticks; 
	while(MACHP(0)->ticks == x) 
		; 
	wrmsr(0x10, MACHP(0)->fastclock); /* synchronize fast counters */ 
	unlock(&active); 
1999/0320    
	iunlock(&clocksynclock); 
1997/0327    
 
1998/0716    
	lapicinit(apic); 
	lapiconline(); 
1999/0320/sys/src/9/pc/mp.c:19,241999/0402/sys/src/9/pc/mp.c:19,25 (short | long)
1997/0327    
static Lock mprdthilock; 
static int mprdthi; 
1998/0910    
static Ref mpvnoref;			/* unique vector assignment */ 
1999/0402    
static Lock mpclocksynclock; 
1997/0327    
 
static char* buses[] = { 
	"CBUSI ", 
1999/0320/sys/src/9/pc/mp.c:214,2261999/0402/sys/src/9/pc/mp.c:215,228
1997/0327    
	case PcmpExtINT: 
		v |= ApicExtINT; 
1997/0524    
		/* 
		 * The AMI Goliath doesn't boot successfully with it's LINTR0 entry 
		 * which decodes to low+level. The PPro manual says ExtINT should be 
		 * level, whereas the Pentium is edge. Setting the Goliath to edge+high 
		 * seems to cure the problem. Other PPro MP tables (e.g. ASUS P/I-P65UP5 
		 * have a entry which decodes to edge+high, so who knows. 
		 * Perhaps it would be best just to not set an ExtINT entry at all, 
		 * it shouldn't be needed for SMP mode. 
1999/0402    
		 * The AMI Goliath doesn't boot successfully with it's LINTR0 
		 * entry which decodes to low+level. The PPro manual says ExtINT 
		 * should be level, whereas the Pentium is edge. Setting the 
		 * Goliath to edge+high seems to cure the problem. Other PPro 
		 * MP tables (e.g. ASUS P/I-P65UP5 have a entry which decodes 
		 * to edge+high, so who knows. 
		 * Perhaps it would be best just to not set an ExtINT entry at 
		 * all, it shouldn't be needed for SMP mode. 
1997/0524    
		 */ 
		po = PcmpHIGH; 
		el = PcmpEDGE; 
1999/0320/sys/src/9/pc/mp.c:229,2351999/0402/sys/src/9/pc/mp.c:231,237
1997/0327    
 
	/* 
	 */ 
1998/1022    
	if(bus->type == BusEISA && !po && !el /*&& !(elcr & (1<<irq))*/){ 
1999/0402    
	if(bus->type == BusEISA && !po && !el /*&& !(i8259elcr & (1<<irq))*/){ 
1997/0327    
		po = PcmpHIGH; 
		el = PcmpEDGE; 
	} 
1999/0320/sys/src/9/pc/mp.c:280,2861999/0402/sys/src/9/pc/mp.c:282,289
1998/0605    
 
1997/0327    
	if(p->apicno == 0xFF){ 
		for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
			if((apic->flags & PcmpEN) && apic->type == PcmpPROCESSOR) 
1999/0402    
			if((apic->flags & PcmpEN) 
			&& apic->type == PcmpPROCESSOR) 
1997/0327    
				apic->lintr[intin] = v; 
		} 
	} 
1999/0320/sys/src/9/pc/mp.c:348,3551999/0402/sys/src/9/pc/mp.c:351,356
1997/0327    
#define PDX(va)		((((ulong)(va))>>22) & 0x03FF) 
#define PTX(va)		((((ulong)(va))>>12) & 0x03FF) 
 
1999/0320    
Lock clocksynclock; 
                 
1997/0327    
static void 
squidboy(Apic* apic) 
{ 
1999/0320/sys/src/9/pc/mp.c:371,3821999/0402/sys/src/9/pc/mp.c:372,383
1997/0327    
	/* 
	 * Restrain your octopus! Don't let it go out on the sea! 
	 */ 
1999/0320    
	ilock(&clocksynclock); 
1999/0402    
	ilock(&mpclocksynclock); 
1999/0310    
	x = MACHP(0)->ticks; 
	while(MACHP(0)->ticks == x) 
		; 
	wrmsr(0x10, MACHP(0)->fastclock); /* synchronize fast counters */ 
1999/0320    
	iunlock(&clocksynclock); 
1999/0402    
	iunlock(&mpclocksynclock); 
1997/0327    
 
1998/0716    
	lapicinit(apic); 
	lapiconline(); 
1999/0320/sys/src/9/pc/mp.c:480,4881999/0402/sys/src/9/pc/mp.c:481,489
1997/0405    
	bpapic = 0; 
 
1997/0327    
	/* 
	 * Run through the table saving information needed for starting application 
	 * processors and initialising any I/O APICs. The table is guaranteed to be in 
	 * order such that only one pass is necessary. 
1999/0402    
	 * Run through the table saving information needed for starting 
	 * application processors and initialising any I/O APICs. The table 
	 * is guaranteed to be in order such that only one pass is necessary. 
1997/0327    
	 */ 
	p = ((uchar*)pcmp)+sizeof(PCMP); 
	e = ((uchar*)pcmp)+pcmp->length; 
1999/0320/sys/src/9/pc/mp.c:489,4951999/0402/sys/src/9/pc/mp.c:490,497
1997/0327    
	while(p < e) switch(*p){ 
 
1998/0729    
	default: 
1998/0825    
		print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n", *p, e-p); 
1999/0402    
		print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n", 
			*p, e-p); 
1998/0729    
		while(p < e){ 
			print("%uX ", *p); 
			p++; 
1999/0320/sys/src/9/pc/mp.c:562,5681999/0402/sys/src/9/pc/mp.c:564,571
1997/0405    
	 */ 
	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); 
	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN && apic->type == PcmpPROCESSOR) 
1999/0402    
		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN 
		&& apic->type == PcmpPROCESSOR) 
1997/0405    
			mpstartap(apic); 
1997/0327    
	} 
 
1999/0320/sys/src/9/pc/mp.c:575,5811999/0402/sys/src/9/pc/mp.c:578,584
1997/0327    
} 
 
static int 
1998/0910    
mpintrenablex(Vctl* v) 
1999/0402    
mpintrenablex(Vctl* v, int tbdf) 
1997/0327    
{ 
	Bus *bus; 
	Aintr *aintr; 
1999/0320/sys/src/9/pc/mp.c:584,5951999/0402/sys/src/9/pc/mp.c:587,597
1998/0910    
	int bno, dno, irq, lo, n, type, vno; 
1997/0327    
 
	/* 
	 * Find the bus, default is ISA. 
	 * There cannot be multiple ISA or EISA buses. 
1999/0402    
	 * Find the bus. 
1997/0327    
	 */ 
1998/0910    
	type = BUSTYPE(v->tbdf); 
	bno = BUSBNO(v->tbdf); 
	dno = BUSDNO(v->tbdf); 
1999/0402    
	type = BUSTYPE(tbdf); 
	bno = BUSBNO(tbdf); 
	dno = BUSDNO(tbdf); 
1997/0327    
	n = 0; 
1998/0910    
	for(bus = mpbus; bus != nil; bus = bus->next){ 
1997/0327    
		if(bus->type != type) 
1999/0320/sys/src/9/pc/mp.c:610,6211999/0402/sys/src/9/pc/mp.c:612,623
1998/0910    
	 * obtained from the PCI config space. 
1997/0327    
	 */ 
1998/0910    
	if(bus->type == BusPCI){ 
		pcidev = pcimatchtbdf(v->tbdf); 
1999/0402    
		pcidev = pcimatchtbdf(tbdf); 
1998/0910    
		if(pcidev != nil && (n = pcicfgr8(pcidev, PciINTP)) != 0) 
			irq = (dno<<2)|(n-1); 
		else 
			irq = -1; 
		//print("pcidev %uX: irq %uX v->irq %uX\n", v->tbdf, irq, v->irq); 
1999/0402    
		//print("pcidev %uX: irq %uX v->irq %uX\n", tbdf, irq, v->irq); 
1998/0910    
	} 
	else 
		irq = v->irq; 
1999/0320/sys/src/9/pc/mp.c:629,6651999/0402/sys/src/9/pc/mp.c:631,672
1998/0910    
			continue; 
 
		/* 
		 * Check not already enabled. This is a bad thing as it implies the 
		 * same device is requesting the same interrupt to be enabled multiple 
		 * times. The RDT read here is safe for now as currently interrupts 
		 * are never disabled once enabled. 
1999/0402    
		 * Check not already enabled. This is a bad thing as it implies 
		 * the same device is requesting the same interrupt to be 
		 * enabled multiple times. The RDT read here is safe for now 
		 * as currently interrupts are never disabled once enabled. 
1998/0910    
		 */ 
		apic = aintr->apic; 
		ioapicrdtr(apic, aintr->intr->intin, 0, &lo); 
		if(!(lo & ApicIMASK)){ 
			print("mpintrenable: multiple enable of irq %d, tbdf %uX\n", 
				v->irq, v->tbdf); 
1999/0402    
			print("mpintrenable: multiple enable irq%d, tbdf %uX\n", 
				v->irq, tbdf); 
1998/0910    
			return -1; 
1997/0327    
		} 
 
1998/0910    
		/* 
		 * With the APIC a unique vector can be assigned to each request 
		 * to enable an interrupt. There are two reasons this is a good idea: 
		 * 1) to prevent lost interrupts, no more than 2 interrupts should 
		 *    be assigned per block of 16 vectors (there is an in-service 
		 *    entry and a holding entry for each priority level and there is 
		 *    a priority level per block of 16 interrupts). 
		 * 2) each input pin on the IOAPIC will receive a different vector 
		 *    regardless of whether the devices on that pin use the same IRQ 
		 *    as devices on another pin. 
1999/0402    
		 * With the APIC a unique vector can be assigned to each 
		 * request to enable an interrupt. There are two reasons this 
		 * is a good idea: 
		 * 1) to prevent lost interrupts, no more than 2 interrupts 
		 *    should be assigned per block of 16 vectors (there is an 
		 *    in-service entry and a holding entry for each priority 
		 *    level and there is one priority level per block of 16 
		 *    interrupts). 
		 * 2) each input pin on the IOAPIC will receive a different 
		 *    vector regardless of whether the devices on that pin use 
		 *    the same IRQ as devices on another pin. 
1998/0910    
		 */ 
		vno = VectorAPIC + (incref(&mpvnoref)-1)*8; 
		if(vno > MaxVectorAPIC){ 
			print("mpintrenable: vno %d, irq %d, tbdf %uX\n", 
				vno, v->irq, v->tbdf); 
1999/0402    
				vno, v->irq, tbdf); 
1998/0910    
			return -1; 
		} 
1998/1022    
		lo = mpintrinit(bus, aintr->intr, vno, v->irq); 
1999/0402    
		//print("lo 0x%uX: busno %d intr %d vno %d irq %d elcr 0x%uX\n", 
		//	lo, bus->busno, aintr->intr->irq, vno, 
		//	v->irq, i8259elcr); 
1997/0327    
		if(lo & ApicIMASK) 
			return -1; 
		lo |= ApicLOGICAL; 
1999/0320/sys/src/9/pc/mp.c:669,6741999/0402/sys/src/9/pc/mp.c:676,684
1997/0327    
 			ioapicrdtw(apic, aintr->intr->intin, mprdthi, lo); 
			unlock(&mprdthilock); 
		} 
1999/0402    
		//else 
		//	print("lo not enabled 0x%uX %d\n", 
		//		apic->flags, apic->type); 
1997/0327    
 
1998/0910    
		v->isr = lapicisr; 
		v->eoi = lapiceoi; 
1999/0320/sys/src/9/pc/mp.c:691,6971999/0402/sys/src/9/pc/mp.c:701,707
1998/0320    
	 * breakpoint and page-fault). 
	 */ 
1998/0910    
	tbdf = v->tbdf; 
	if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v)) != -1) 
1999/0402    
	if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1) 
1998/0910    
		return vno; 
1998/0320    
 
1998/0910    
	irq = v->irq; 
1999/0320/sys/src/9/pc/mp.c:716,7301999/0402/sys/src/9/pc/mp.c:726,738
1998/0320    
	 * polarity set to 'default for this bus' which wouldn't 
	 * be compatible with ISA. 
	 */ 
	if(mpisabus != -1){ 
1998/0910    
		v->tbdf = MKBUS(BusISA, 0, 0, 0); 
		vno = mpintrenablex(v); 
1999/0402    
	if(mpeisabus != -1){ 
		vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0)); 
1998/0910    
		if(vno != -1) 
			return vno; 
1998/0320    
	} 
	if(mpeisabus != -1){ 
1998/0910    
		v->tbdf = MKBUS(BusEISA, 0, 0, 0); 
		vno = mpintrenablex(v); 
1999/0402    
	if(mpisabus != -1){ 
		vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0)); 
1998/0910    
		if(vno != -1) 
			return vno; 
1998/0320    
	} 
1999/0320/sys/src/9/pc/mp.c:767,7731999/0402/sys/src/9/pc/mp.c:775,781
1997/0327    
	 * warm-boot sequence is tried. The following is Intel specific and 
	 * seems to perform a cold-boot, but at least it comes back. 
	 */ 
1997/1101    
	*(ushort*)KADDR(0x472) = 0x1234;		/* BIOS warm-boot flag */ 
1999/0402    
	*(ushort*)KADDR(0x472) = 0x1234;	/* BIOS warm-boot flag */ 
1997/0327    
	outb(0xCF9, 0x02); 
	outb(0xCF9, 0x06); 
#else 
1999/0402/sys/src/9/pc/mp.c:552,5601999/0819/sys/src/9/pc/mp.c:552,560 (short | long)
1997/0405    
	 * and do not appear in the I/O APIC so it is OK 
	 * to set them now. 
	 */ 
1998/0910    
	intrenable(IrqTIMER, clockintr, 0, BUSUNKNOWN); 
	intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN); 
	intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN); 
1999/0819    
	intrenable(IrqTIMER, clockintr, 0, BUSUNKNOWN, "clock"); 
	intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror"); 
	intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious"); 
1998/0716    
	lapiconline(); 
1997/0327    
 
1998/0401    
	checkmtrr(); 
1999/0819/sys/src/9/pc/mp.c:462,4672001/0127/sys/src/9/pc/mp.c:462,469 (short | long)
1997/0327    
void 
mpinit(void) 
{ 
2001/0127    
	int ncpu; 
	char *cp; 
1997/0327    
	PCMP *pcmp; 
	uchar *e, *p; 
1997/0405    
	Apic *apic, *bpapic; 
1999/0819/sys/src/9/pc/mp.c:562,5722001/0127/sys/src/9/pc/mp.c:564,585
1997/0405    
	/* 
	 * Initialise the application processors. 
	 */ 
2001/0127    
	if(cp = getconf("*ncpu")){ 
		ncpu = strtol(cp, 0, 0); 
		if(ncpu < 1) 
			ncpu = 1; 
	} 
	else 
		ncpu = MaxAPICNO; 
1997/0405    
	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); 
	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
2001/0127    
		if(ncpu <= 1) 
			break; 
1999/0402    
		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN 
		&& apic->type == PcmpPROCESSOR) 
2001/0127    
		&& apic->type == PcmpPROCESSOR){ 
1997/0405    
			mpstartap(apic); 
2001/0127    
			ncpu--; 
		} 
1997/0327    
	} 
 
	/* 
2001/0127/sys/src/9/pc/mp.c:462,4692001/0527/sys/src/9/pc/mp.c:462,467 (short | long)
1997/0327    
void 
mpinit(void) 
{ 
2001/0127    
	int ncpu; 
	char *cp; 
1997/0327    
	PCMP *pcmp; 
	uchar *e, *p; 
1997/0405    
	Apic *apic, *bpapic; 
2001/0127/sys/src/9/pc/mp.c:564,5852001/0527/sys/src/9/pc/mp.c:562,572
1997/0405    
	/* 
	 * Initialise the application processors. 
	 */ 
2001/0127    
	if(cp = getconf("*ncpu")){ 
		ncpu = strtol(cp, 0, 0); 
		if(ncpu < 1) 
			ncpu = 1; 
	} 
	else 
		ncpu = MaxAPICNO; 
1997/0405    
	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); 
	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
2001/0127    
		if(ncpu <= 1) 
			break; 
1999/0402    
		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN 
2001/0127    
		&& apic->type == PcmpPROCESSOR){ 
2001/0527    
		&& apic->type == PcmpPROCESSOR) 
1997/0405    
			mpstartap(apic); 
2001/0127    
			ncpu--; 
		} 
1997/0327    
	} 
 
	/* 
2001/0527/sys/src/9/pc/mp.c:462,4672001/0830/sys/src/9/pc/mp.c:462,469 (short | long)
1997/0327    
void 
mpinit(void) 
{ 
2001/0830    
	int ncpu; 
	char *cp; 
1997/0327    
	PCMP *pcmp; 
	uchar *e, *p; 
1997/0405    
	Apic *apic, *bpapic; 
2001/0527/sys/src/9/pc/mp.c:562,5722001/0830/sys/src/9/pc/mp.c:564,585
1997/0405    
	/* 
	 * Initialise the application processors. 
	 */ 
2001/0830    
	if(cp = getconf("*ncpu")){ 
		ncpu = strtol(cp, 0, 0); 
		if(ncpu < 1) 
			ncpu = 1; 
	} 
	else 
		ncpu = MaxAPICNO; 
1997/0405    
	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap)); 
	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){ 
2001/0830    
		if(ncpu <= 1) 
			break; 
1999/0402    
		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN 
2001/0527    
		&& apic->type == PcmpPROCESSOR) 
2001/0830    
		&& apic->type == PcmpPROCESSOR){ 
1997/0405    
			mpstartap(apic); 
2001/0830    
			ncpu--; 
		} 
1997/0327    
	} 
 
	/* 
2001/0527/sys/src/9/pc/mp.c:631,6472001/0830/sys/src/9/pc/mp.c:644,674
1998/0910    
			continue; 
 
		/* 
1999/0402    
		 * Check not already enabled. This is a bad thing as it implies 
		 * the same device is requesting the same interrupt to be 
		 * enabled multiple times. The RDT read here is safe for now 
		 * as currently interrupts are never disabled once enabled. 
2001/0830    
		 * Check if already enabled. Multifunction devices may share 
		 * INT[A-D]# so, if already enabled, check the polarity matches 
		 * and the trigger is level. 
		 * 
		 * Should check the devices differ only in the function number, 
		 * but that can wait for the planned enable/disable rewrite. 
		 * The RDT read here is safe for now as currently interrupts 
		 * are never disabled once enabled. 
1998/0910    
		 */ 
		apic = aintr->apic; 
		ioapicrdtr(apic, aintr->intr->intin, 0, &lo); 
		if(!(lo & ApicIMASK)){ 
1999/0402    
			print("mpintrenable: multiple enable irq%d, tbdf %uX\n", 
				v->irq, tbdf); 
1998/0910    
			return -1; 
2001/0830    
			vno = lo & 0xFF; 
			n = mpintrinit(bus, aintr->intr, vno, v->irq); 
			n |= ApicLOGICAL; 
			if(n != lo || !(n & ApicLEVEL)){ 
				print("mpintrenable: multiple botch irq%d, tbdf %uX, lo %8.8uX, n %8.8uX\n", 
					v->irq, tbdf, lo, n); 
				return -1; 
			} 
 
			v->isr = lapicisr; 
			v->eoi = lapiceoi; 
 
			return vno; 
1997/0327    
		} 
 
1998/0910    
		/* 
2001/0830/sys/src/9/pc/mp.c:348,3562002/0109/sys/src/9/pc/mp.c:348,353 (short | long)
1998/0401    
	} 
} 
 
1997/0327    
#define PDX(va)		((((ulong)(va))>>22) & 0x03FF) 
#define PTX(va)		((((ulong)(va))>>12) & 0x03FF) 
                 
static void 
squidboy(Apic* apic) 
{ 
2002/0109/sys/src/9/pc/mp.c:43,482002/0404/sys/src/9/pc/mp.c:43,85 (short | long)
1997/0327    
	0, 
}; 
 
2002/0404    
void 
apicclkenable(void) 
{ 
	Apic *apic; 
 
	i8259init(); 
 
	/* Uniprocessor local apic init for apic clock */ 
	apic = &mpapic[0]; 
	apic->type = PcmpPROCESSOR; 
	apic->apicno = 0; 
	apic->flags = 0; 
	apic->lintr[0] = ApicIMASK; 
	apic->lintr[1] = ApicIMASK; 
	apic->machno = 0; 
	apic->addr = (ulong*)0xfee00000; 
	machno2apicno[0] = 0; 
 
	/* 
	 * Map the local APIC. 
	 */ 
	if(mmukmap((ulong)apic->addr, 0, 1024) == 0) 
		return; 
 
	/* 
	 * These interrupts are local to the processor 
	 * and do not appear in the I/O APIC so it is OK 
	 * to set them now. 
	 */ 
	intrenable(IrqTIMER, clockintr, 0, BUSUNKNOWN, "clock"); 
	intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror"); 
	intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious"); 
 
	lapicinit(apic); 
	lapiconline(); 
} 
 
1997/0327    
static Apic* 
mkprocessor(PCMPprocessor* p) 
{ 
Too many diffs (26 > 25). Stopping.


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)