📄 mp.c
字号:
{ ulong *apbootp, *pdb, *pte; Mach *mach, *mach0; int i, machno; uchar *p; mach0 = MACHP(0); /* * Initialise the AP page-tables and Mach structure. The page-tables * are the same as for the bootstrap processor with the exception of * the PTE for the Mach structure. * Xspanalloc will panic if an allocation can't be made. */ p = xspanalloc(3*BY2PG, BY2PG, 0); pdb = (ulong*)p; memmove(pdb, mach0->pdb, BY2PG); p += BY2PG; if((pte = mmuwalk(pdb, MACHADDR, 1, 0)) == nil) return; memmove(p, KADDR(PPN(*pte)), BY2PG); *pte = PADDR(p)|PTEWRITE|PTEVALID; p += BY2PG; mach = (Mach*)p; if((pte = mmuwalk(pdb, MACHADDR, 2, 0)) == nil) return; *pte = PADDR(mach)|PTEWRITE|PTEVALID; machno = apic->machno; MACHP(machno) = mach; mach->machno = machno; mach->pdb = pdb; /* * 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; *p++ = i; *p = i>>8; nvramwrite(0x0F, 0x0A); lapicstartap(apic, PADDR(APBOOTSTRAP)); for(i = 0; i < 100000; i++){ lock(&mprdthilock); if(mprdthi & ((1<<apic->apicno)<<24)){ unlock(&mprdthilock); break; } unlock(&mprdthilock); microdelay(10); } nvramwrite(0x0F, 0x00);}voidmpinit(void){ PCMP *pcmp; uchar *e, *p; Apic *apic, *bpapic; i8259init(); if(_mp_ == 0) return; pcmp = KADDR(_mp_->physaddr); /* * Map the local APIC. */ if(mmukmap(pcmp->lapicbase, 0, 1024) == 0) return; bpapic = 0; /* * 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 = KADDR(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, clockintr, 0, BUSUNKNOWN, "clock"); intrenable(IrqERROR, lapicerror, 0, BUSUNKNOWN, "lapicerror"); intrenable(IrqSPURIOUS, lapicspurious, 0, BUSUNKNOWN, "lapicspurious"); lapiconline(); checkmtrr(); /* * 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); } /* * Remember to set conf.copymode here if nmach > 1. * Should look for an ExtINT line and enable it. */ if(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); n = 0; for(bus = mpbus; bus != nil; bus = bus->next){ if(bus->type != type) continue; if(n == bno) break; n++; } 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 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 irq%d, tbdf %uX\n", v->irq, tbdf); return -1; } /* * 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; } 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 + -