void mathinit(void) { trapenable(VectorCERR, matherror, 0, "matherror"); if(X86FAMILY(m->cpuidax) == 3) intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror"); trapenable(VectorCNA, mathemu, 0, "mathemu"); trapenable(VectorCSO, mathover, 0, "mathover"); }
static void x86wdenable(void) { Wd *wd; vlong r, t; int i, model; u32int evntsel; wd = &x86wd; ilock(wd); if(wd->inuse){ iunlock(wd); error(Einuse); } iunlock(wd); /* * keep this process on cpu 0 so we always see the same timers * and so that this will work even if all other cpus are shut down. */ runoncpu(0); /* * Check the processor is capable of doing performance * monitoring and that it has TSC, RDMSR/WRMSR and a local APIC. */ model = -1; if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0){ if(X86FAMILY(m->cpuidax) == 0x06) model = K6; else if(X86FAMILY(m->cpuidax) == 0x0F) model = K8; } else if(strncmp(m->cpuidid, "GenuineIntel", 12) == 0){ if(X86FAMILY(m->cpuidax) == 0x06) model = P6; else if(X86FAMILY(m->cpuidax) == 0x0F) model = P4; } if(model == -1 || (m->cpuiddx & (Cpuapic|Cpumsr|Tsc)) != (Cpuapic|Cpumsr|Tsc)) error(Enodev); ilock(wd); if(wd->inuse){ iunlock(wd); error(Einuse); } wd->model = model; wd->inuse = 1; wd->ticks = 0; /* * See the IA-32 Intel Architecture Software * Developer's Manual Volume 3: System Programming Guide, * Chapter 15 and the AMD equivalent for what all this * bit-whacking means. */ t = interval(); switch(model){ case P6: wrmsr(0x186, 0); /* evntsel */ wrmsr(0x187, 0); wrmsr(0xC1, 0); /* perfctr */ wrmsr(0xC2, 0); lapicnmienable(); evntsel = 0x00130000|0x79; wrmsr(0xC1, -t); wrmsr(0x186, 0x00400000|evntsel); break; case P4: rdmsr(0x1A0, &r); if(!(r & 0x0000000000000080LL)) return; for(i = 0; i < 18; i++) wrmsr(0x300+i, 0); /* perfctr */ for(i = 0; i < 18; i++) wrmsr(0x360+i, 0); /* ccr */ for(i = 0; i < 31; i++) wrmsr(0x3A0+i, 0); /* escr */ for(i = 0; i < 6; i++) wrmsr(0x3C0+i, 0); /* escr */ for(i = 0; i < 6; i++) wrmsr(0x3C8+i, 0); /* escr */ for(i = 0; i < 2; i++) wrmsr(0x3E0+i, 0); /* escr */ if(!(r & 0x0000000000001000LL)){ for(i = 0; i < 2; i++) wrmsr(0x3F1+i, 0); /* pebs */ } lapicnmienable(); wrmsr(0x3B8, 0x000000007E00000CLL); /* escr0 */ r = 0x0000000004FF8000ULL; wrmsr(0x36C, r); /* cccr0 */ wrmsr(0x30C, -t); wrmsr(0x36C, 0x0000000000001000LL|r); break; case K6: case K8: /* * PerfEvtSel 0-3, PerfCtr 0-4. */ for(i = 0; i < 8; i++) wrmsr(0xC0010000+i, 0); lapicnmienable(); evntsel = 0x00130000|0x76; wrmsr(0xC0010004, -t); wrmsr(0xC0010000, 0x00400000|evntsel); break; } iunlock(wd); }
void mpinit(void) { int ncpu, cpuson; char *cp; PCMP *pcmp; uchar *e, *p; Apic *apic, *bpapic; void *va; mpdebug = getconf("*debugmp") != nil; i8259init(); syncclock(); bpapic = nil; cpuson = 0; if(_mp_ == 0) { /* * We can easily get processor info from ACPI, but * interrupt routing, etc. would require interpreting AML. */ print("mpinit: no mp table found, assuming uniprocessor\n"); archrevert(); return; } pcmp = KADDR(_mp_->physaddr); /* * Map the local APIC. */ if((va = vmap(pcmp->lapicbase, 1024)) == nil) return; mppcmp = pcmp; print("LAPIC: %#lux %#lux\n", pcmp->lapicbase, (ulong)va); /* * 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; cpuson++; } 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; } dprint("mpinit: mp table describes %d cpus\n", cpuson); /* For now, always scan ACPI's MADT for processors that MP missed. */ trympacpi(); if (bpapic == nil) bpapic = bootapic; /* * No bootstrap processor, no need to go further. */ if(bpapic == 0) return; bpapic->online = 1; lapicinit(bpapic); /* * 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 if(ncpu > MAXMACH) ncpu = MAXMACH; } else ncpu = MAXMACH; 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; }
void mpinit(void) { int ncpu; char *cp; PCMP *pcmp; uchar *e, *p; Apic *apic, *bpapic; i8259init(); syncclock(); if(_mp_ == 0) return; pcmp = KADDR(_mp_->physaddr); /* * Map the local APIC. */ if(mmukmap(pcmp->lapicbase, 0, 1024) == 0) return; 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 = 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, 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; }