⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	mach = (Mach*)p;	if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil)		return;	*pte = PADDR(mach)|PTEWRITE|PTEVALID;	if(mach0->havepge)		*pte |= PTEGLOBAL;	p += BY2PG;	machno = apic->machno;	MACHP(machno) = mach;	mach->machno = machno;	mach->pdb = pdb;	mach->gdt = (Segdesc*)p;	/* filled by mmuinit */	/*	 * Tell the AP where its kernel vector and pdb are.	 * The offsets are known in the AP bootstrap code.	 */	apbootp = (ulong*)(APBOOTSTRAP+0x08);	*apbootp++ = (ulong)squidboy;	*apbootp++ = PADDR(pdb);	*apbootp = (ulong)apic;	/*	 * Universal Startup Algorithm.	 */	p = KADDR(0x467);	*p++ = PADDR(APBOOTSTRAP);	*p++ = PADDR(APBOOTSTRAP)>>8;	i = (PADDR(APBOOTSTRAP) & ~0xFFFF)/16;	/* code assumes i==0 */	if(i != 0)		print("mp: bad APBOOTSTRAP\n");	*p++ = i;	*p = i>>8;	nvramwrite(0x0F, 0x0A);	lapicstartap(apic, PADDR(APBOOTSTRAP));	for(i = 0; i < 1000; i++){		lock(&mprdthilock);		if(mprdthi & ((1<<apic->apicno)<<24)){			unlock(&mprdthilock);			break;		}		unlock(&mprdthilock);		delay(10);	}	nvramwrite(0x0F, 0x00);}voidmpinit(void){	int ncpu;	char *cp;	PCMP *pcmp;	uchar *e, *p;	Apic *apic, *bpapic;	void *va;	i8259init();	syncclock();	if(_mp_ == 0)		return;	pcmp = KADDR(_mp_->physaddr);	/*	 * Map the local APIC.	 */	if((va = vmap(pcmp->lapicbase, 1024)) == nil)		return;	print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);	bpapic = nil;	/*	 * 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.	 */	p = ((uchar*)pcmp)+sizeof(PCMP);	e = ((uchar*)pcmp)+pcmp->length;	while(p < e) switch(*p){	default:		print("mpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",			*p, e-p);		while(p < e){			print("%uX ", *p);			p++;		}		break;	case PcmpPROCESSOR:		if(apic = mkprocessor((PCMPprocessor*)p)){			/*			 * Must take a note of bootstrap processor APIC			 * now as it will be needed in order to start the			 * application processors later and there's no			 * guarantee that the bootstrap processor appears			 * first in the table before the others.			 */			apic->addr = va;			apic->paddr = pcmp->lapicbase;			if(apic->flags & PcmpBP)				bpapic = apic;		}		p += sizeof(PCMPprocessor);		continue;	case PcmpBUS:		mkbus((PCMPbus*)p);		p += sizeof(PCMPbus);		continue;	case PcmpIOAPIC:		if(apic = mkioapic((PCMPioapic*)p))			ioapicinit(apic, ((PCMPioapic*)p)->apicno);		p += sizeof(PCMPioapic);		continue;	case PcmpIOINTR:		mkiointr((PCMPintr*)p);		p += sizeof(PCMPintr);		continue;	case PcmpLINTR:		mklintr((PCMPintr*)p);		p += sizeof(PCMPintr);		continue;	}	/*	 * No bootstrap processor, no need to go further.	 */	if(bpapic == 0)		return;	lapicinit(bpapic);	lock(&mprdthilock);	mprdthi |= (1<<bpapic->apicno)<<24;	unlock(&mprdthilock);	/*	 * 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, lapicclock, 0, BUSUNKNOWN, "clock");	intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror");	intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious");	lapiconline();	checkmtrr();	/*	 * Initialise the application processors.	 */	if(cp = getconf("*ncpu")){		ncpu = strtol(cp, 0, 0);		if(ncpu < 1)			ncpu = 1;	}	else		ncpu = MaxAPICNO;	memmove((void*)APBOOTSTRAP, apbootstrap, sizeof(apbootstrap));	for(apic = mpapic; apic <= &mpapic[MaxAPICNO]; apic++){		if(ncpu <= 1)			break;		if((apic->flags & (PcmpBP|PcmpEN)) == PcmpEN		&& apic->type == PcmpPROCESSOR){			mpstartap(apic);			conf.nmach++;			ncpu--;		}	}	/*	 *  we don't really know the number of processors till	 *  here.	 *	 *  set conf.copymode here if nmach > 1.	 *  Should look for an ExtINT line and enable it.	 */	if(X86FAMILY(m->cpuidax) == 3 || conf.nmach > 1)		conf.copymode = 1;}static intmpintrenablex(Vctl* v, int tbdf){	Bus *bus;	Aintr *aintr;	Apic *apic;	Pcidev *pcidev;	int bno, dno, irq, lo, n, type, vno;	/*	 * Find the bus.	 */	type = BUSTYPE(tbdf);	bno = BUSBNO(tbdf);	dno = BUSDNO(tbdf);	if(type == BusISA)		bno = mpisabus;	for(bus = mpbus; bus != nil; bus = bus->next){		if(bus->type != type)			continue;		if(bus->busno == bno)			break;	}	if(bus == nil){		print("ioapicirq: can't find bus type %d\n", type);		return -1;	}	/*	 * 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.	 */	if(bus->type == BusPCI){		pcidev = pcimatchtbdf(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", tbdf, irq, v->irq);	}	else		irq = v->irq;	/*	 * Find a matching interrupt entry from the list of interrupts	 * attached to this bus.	 */	for(aintr = bus->aintr; aintr; aintr = aintr->next){		if(aintr->intr->irq != irq)			continue;		/*		 * 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.		 */		apic = aintr->apic;		ioapicrdtr(apic, aintr->intr->intin, 0, &lo);		if(!(lo & ApicIMASK)){			vno = lo & 0xFF;			n = mpintrinit(bus, aintr->intr, vno, v->irq);			n |= ApicLOGICAL;			lo &= ~(ApicRemoteIRR|ApicDELIVS);			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;		}		/*		 * 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.		 */		vno = VectorAPIC + (incref(&mpvnoref)-1)*8;		if(vno > MaxVectorAPIC){			print("mpintrenable: vno %d, irq %d, tbdf %uX\n",				vno, v->irq, tbdf);			return -1;		}		lo = mpintrinit(bus, aintr->intr, vno, v->irq);		//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);		if(lo & ApicIMASK)			return -1;		lo |= ApicLOGICAL;		if((apic->flags & PcmpEN) && apic->type == PcmpIOAPIC){			lock(&mprdthilock); 			ioapicrdtw(apic, aintr->intr->intin, mprdthi, lo);			unlock(&mprdthilock);		}		//else		//	print("lo not enabled 0x%uX %d\n",		//		apic->flags, apic->type);		v->isr = lapicisr;		v->eoi = lapiceoi;		return vno;	}	return -1;}intmpintrenable(Vctl* v){	int irq, tbdf, vno;	/*	 * 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).	 */	tbdf = v->tbdf;	if(tbdf != BUSUNKNOWN && (vno = mpintrenablex(v, tbdf)) != -1)		return vno;	irq = v->irq;	if(irq >= IrqLINT0 && irq <= MaxIrqLAPIC){		if(irq != IrqSPURIOUS)			v->isr = lapiceoi;		return VectorPIC+irq;	}	if(irq < 0 || irq > MaxIrqPIC){		print("mpintrenable: irq %d out of range\n", irq);		return -1;	}	/*	 * Either didn't find it or 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(mpeisabus != -1){		vno = mpintrenablex(v, MKBUS(BusEISA, 0, 0, 0));		if(vno != -1)			return vno;	}	if(mpisabus != -1){		vno = mpintrenablex(v, MKBUS(BusISA, 0, 0, 0));		if(vno != -1)			return vno;	}	print("mpintrenable: out of choices %d %d\n", mpeisabus, mpisabus);	return -1;}static Lock mpshutdownlock;voidmpshutdown(void){	/*	 * To be done...	 */	if(!canlock(&mpshutdownlock)){		/*		 * If this processor received the CTRL-ALT-DEL from		 * the keyboard, acknowledge it. Send an INIT to self.		 */#ifdef FIXTHIS		if(lapicisr(VectorKBD))			lapiceoi(VectorKBD);#endif /* FIX THIS */		idle();	}	print("apshutdown: active = 0x%2.2uX\n", active.machs);	delay(1000);	splhi();	/*	 * INIT all excluding self.	 */	lapicicrw(0, 0x000C0000|ApicINIT);#ifdef notdef	/*	 * Often the BIOS hangs during restart if a conventional 8042	 * warm-boot sequence is tried. The following is Intel specific and	 * seems to perform a cold-boot, but at least it comes back.	 */	*(ushort*)KADDR(0x472) = 0x1234;	/* BIOS warm-boot flag */	outb(0xCF9, 0x02);	outb(0xCF9, 0x06);#else	pcireset();	i8042reset();#endif /* notdef */}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -