2 #include "../port/lib.h"
12 static char* buses[] = {
39 for(bus = mpbus; bus; bus = bus->next)
40 if(bus->busno == busno)
43 print("mpgetbus: can't find bus %d\n", busno);
49 mkprocessor(PCMPprocessor* p)
51 static int machno = 1;
56 if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpapic[apicno] != nil)
59 if((apic = xalloc(sizeof(Apic))) == nil)
60 panic("mkprocessor: no memory for Apic");
61 apic->type = PcmpPROCESSOR;
62 apic->apicno = apicno;
63 apic->flags = p->flags;
64 apic->lintr[0] = ApicIMASK;
65 apic->lintr[1] = ApicIMASK;
69 apic->machno = machno++;
70 mpapic[apicno] = apic;
81 for(i = 0; buses[i]; i++)
82 if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
87 if((bus = xalloc(sizeof(Bus))) == nil)
88 panic("mkbus: no memory for Bus");
90 mpbuslast->next = bus;
96 bus->busno = p->busno;
97 if(bus->type == BusEISA){
101 print("mkbus: more than one EISA bus\n");
102 mpeisabus = bus->busno;
104 else if(bus->type == BusPCI){
108 else if(bus->type == BusISA){
112 print("mkbus: more than one ISA bus\n");
113 mpisabus = bus->busno;
124 mkioapic(PCMPioapic* p)
131 if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpioapic[apicno] != nil)
136 if((va = vmap(p->addr, 1024)) == nil)
138 if((apic = xalloc(sizeof(Apic))) == nil)
139 panic("mkioapic: no memory for Apic");
140 apic->type = PcmpIOAPIC;
141 apic->apicno = apicno;
143 apic->paddr = p->addr;
144 apic->flags = p->flags;
145 mpioapic[apicno] = apic;
151 mkiointr(PCMPintr* p)
158 * According to the MultiProcessor Specification, a destination
159 * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
160 * It's unclear how that can possibly be correct so treat it as
163 if(p->apicno > MaxAPICNO || mpioapic[p->apicno] == nil)
166 if((bus = mpgetbus(p->busno)) == 0)
169 if((aintr = xalloc(sizeof(Aintr))) == nil)
170 panic("mkiointr: no memory for Aintr");
174 print("mkiointr: type %d intr type %d flags %#o "
175 "bus %d irq %d apicno %d intin %d\n",
176 p->type, p->intr, p->flags,
177 p->busno, p->irq, p->apicno, p->intin);
179 * Hack for Intel SR1520ML motherboard, which BIOS describes
180 * the i82575 dual ethernet controllers incorrectly.
182 if(memcmp(pcmp->product, "INTEL X38MLST ", 20) == 0){
183 if(p->busno == 1 && p->intin == 16 && p->irq == 1){
184 if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
185 panic("iointr: no memory for PCMPintr");
186 memmove(pcmpintr, p, sizeof(PCMPintr));
187 print("mkiointr: %20.20s bus %d intin %d irq %d\n",
188 (char*)pcmp->product,
189 pcmpintr->busno, pcmpintr->intin,
191 pcmpintr->intin = 17;
192 aintr->intr = pcmpintr;
195 aintr->apic = mpioapic[p->apicno];
196 aintr->next = bus->aintr;
210 * The offsets of vectors for LINT[01] are known to be
211 * 0 and 1 from the local APIC vector space at VectorLAPIC.
213 if((bus = mpgetbus(p->busno)) == 0)
218 * Pentium Pros have problems if LINT[01] are set to ExtINT
219 * so just bag it, SMP mode shouldn't need ExtINT anyway.
221 if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
224 v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
226 if(p->apicno == 0xFF){
227 for(i=0; i<=MaxAPICNO; i++){
228 if((apic = mpapic[i]) == nil)
230 if(apic->flags & PcmpEN)
231 apic->lintr[intin] = v;
235 if(apic = mpapic[p->apicno])
236 if(apic->flags & PcmpEN)
237 apic->lintr[intin] = v;
244 dumpmp(uchar *p, uchar *e)
248 for(i = 0; p < e; p++) {
249 if((i % 16) == 0) print("*mp%d=", i/16);
251 if((++i % 16) == 0) print("\n");
253 if((i % 16) != 0) print("\n");
258 mpoverride(uchar** newp, uchar** e)
265 size = atoi(getconf("*mp"));
266 if(size == 0) panic("mpoverride: invalid size in *mp");
267 *newp = p = xalloc(size);
268 if(p == nil) panic("mpoverride: can't allocate memory");
271 snprint(buf, sizeof buf, "*mp%d", i);
275 j = strtol(s, &s, 16);
276 if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
277 if(p >= *e) panic("mpoverride: overflow in %s", buf);
281 if(p != *e) panic("mpoverride: size doesn't match");
292 * Map the local APIC.
294 va = vmap(pcmp->lapicbase, 1024);
295 print("LAPIC: %.8lux %.8lux\n", pcmp->lapicbase, (ulong)va);
297 panic("pcmpinit: cannot map lapic %.8lux", pcmp->lapicbase);
299 p = ((uchar*)pcmp)+sizeof(PCMP);
300 e = ((uchar*)pcmp)+pcmp->length;
301 if(getconf("*dumpmp") != nil)
303 if(getconf("*mp") != nil)
307 * Run through the table saving information needed for starting
308 * application processors and initialising any I/O APICs. The table
309 * is guaranteed to be in order such that only one pass is necessary.
311 while(p < e) switch(*p){
313 print("pcmpinit: unknown PCMP type 0x%uX (e-p 0x%luX)\n",
322 if(apic = mkprocessor((PCMPprocessor*)p)){
324 apic->paddr = pcmp->lapicbase;
326 p += sizeof(PCMPprocessor);
331 p += sizeof(PCMPbus);
335 if(apic = mkioapic((PCMPioapic*)p))
336 ioapicinit(apic, apic->apicno);
337 p += sizeof(PCMPioapic);
341 mkiointr((PCMPintr*)p);
342 p += sizeof(PCMPintr);
346 mklintr((PCMPintr*)p);
347 p += sizeof(PCMPintr);
352 * Ininitalize local APIC and start application processors.
357 static int identify(void);
364 .intrenable= mpintrenable,
365 .intron= lapicintron,
366 .introff= lapicintroff,
367 .fastclock= i8253read,
368 .timerset= lapictimerset,
377 if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
381 * Search for an MP configuration table. For now,
382 * don't accept the default configurations (physaddr == 0).
383 * Check for correct signature, calculate the checksum and,
384 * if correct, check the version.
385 * To do: check extended table checksum.
387 if((_mp_ = sigsearch("_MP_")) == 0 || checksum(_mp_, sizeof(_MP_)) ||
388 (_mp_->physaddr == 0))
391 pcmp = KADDR(_mp_->physaddr);
392 if(memcmp(pcmp, "PCMP", 4) || checksum(pcmp, pcmp->length) ||
393 (pcmp->version != 1 && pcmp->version != 4)) {