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);
48 mkprocessor(PCMPprocessor* p)
50 static int machno = 1;
55 if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpapic[apicno] != nil)
58 if((apic = xalloc(sizeof(Apic))) == nil)
59 panic("mkprocessor: no memory for Apic");
60 apic->type = PcmpPROCESSOR;
61 apic->apicno = apicno;
62 apic->flags = p->flags;
63 apic->lintr[0] = ApicIMASK;
64 apic->lintr[1] = ApicIMASK;
68 apic->machno = machno++;
69 mpapic[apicno] = apic;
80 for(i = 0; buses[i]; i++)
81 if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
86 if((bus = xalloc(sizeof(Bus))) == nil)
87 panic("mkbus: no memory for Bus");
89 mpbuslast->next = bus;
95 bus->busno = p->busno;
96 if(bus->type == BusEISA){
100 print("mkbus: more than one EISA bus\n");
101 mpeisabus = bus->busno;
103 else if(bus->type == BusPCI){
107 else if(bus->type == BusISA){
111 print("mkbus: more than one ISA bus\n");
112 mpisabus = bus->busno;
123 mkioapic(PCMPioapic* p)
130 if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpioapic[apicno] != nil)
135 if((va = vmap(p->addr, 1024)) == nil)
137 if((apic = xalloc(sizeof(Apic))) == nil)
138 panic("mkioapic: no memory for Apic");
139 apic->type = PcmpIOAPIC;
140 apic->apicno = apicno;
142 apic->paddr = p->addr;
143 apic->flags = p->flags;
144 mpioapic[apicno] = apic;
150 mkiointr(PCMPintr* p)
157 * According to the MultiProcessor Specification, a destination
158 * I/O APIC of 0xFF means the signal is routed to all I/O APICs.
159 * It's unclear how that can possibly be correct so treat it as
162 if(p->apicno > MaxAPICNO || mpioapic[p->apicno] == nil)
165 if((bus = mpgetbus(p->busno)) == 0)
168 if((aintr = xalloc(sizeof(Aintr))) == nil)
169 panic("mkiointr: no memory for Aintr");
173 print("mkiointr: type %d intr type %d flags %#o "
174 "bus %d irq %d apicno %d intin %d\n",
175 p->type, p->intr, p->flags,
176 p->busno, p->irq, p->apicno, p->intin);
178 * Hack for Intel SR1520ML motherboard, which BIOS describes
179 * the i82575 dual ethernet controllers incorrectly.
181 if(memcmp(pcmp->product, "INTEL X38MLST ", 20) == 0){
182 if(p->busno == 1 && p->intin == 16 && p->irq == 1){
183 if((pcmpintr = xalloc(sizeof(PCMPintr))) == nil)
184 panic("iointr: no memory for PCMPintr");
185 memmove(pcmpintr, p, sizeof(PCMPintr));
186 print("mkiointr: %20.20s bus %d intin %d irq %d\n",
187 (char*)pcmp->product,
188 pcmpintr->busno, pcmpintr->intin,
190 pcmpintr->intin = 17;
191 aintr->intr = pcmpintr;
194 aintr->apic = mpioapic[p->apicno];
195 aintr->next = bus->aintr;
209 * The offsets of vectors for LINT[01] are known to be
210 * 0 and 1 from the local APIC vector space at VectorLAPIC.
212 if((bus = mpgetbus(p->busno)) == 0)
217 * Pentium Pros have problems if LINT[01] are set to ExtINT
218 * so just bag it, SMP mode shouldn't need ExtINT anyway.
220 if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
223 v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
225 if(p->apicno == 0xFF){
226 for(i=0; i<=MaxAPICNO; i++){
227 if((apic = mpapic[i]) == nil)
229 if(apic->flags & PcmpEN)
230 apic->lintr[intin] = v;
234 if(apic = mpapic[p->apicno])
235 if(apic->flags & PcmpEN)
236 apic->lintr[intin] = v;
243 dumpmp(uchar *p, uchar *e)
247 for(i = 0; p < e; p++) {
248 if((i % 16) == 0) print("*mp%d=", i/16);
250 if((++i % 16) == 0) print("\n");
252 if((i % 16) != 0) print("\n");
257 mpoverride(uchar** newp, uchar** e)
264 size = strtol(getconf("*mp"), 0, 0);
265 if(size <= 0) panic("mpoverride: invalid size in *mp");
266 *newp = p = xalloc(size);
267 if(p == nil) panic("mpoverride: can't allocate memory");
270 snprint(buf, sizeof buf, "*mp%d", i);
274 j = strtol(s, &s, 16);
275 if(*s && *s != ' ' || j < 0 || j > 0xff) panic("mpoverride: invalid entry in %s", buf);
276 if(p >= *e) panic("mpoverride: overflow in %s", buf);
280 if(p != *e) panic("mpoverride: size doesn't match");
291 * Map the local APIC.
293 va = vmap(pcmp->lapicbase, 1024);
295 print("LAPIC: %.8lux %#p\n", pcmp->lapicbase, va);
297 panic("pcmpinit: cannot map lapic %.8lux", pcmp->lapicbase);
299 p = ((uchar*)pcmp)+PCMPsz;
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%zuX)\n",
322 if(apic = mkprocessor((PCMPprocessor*)p)){
324 apic->paddr = pcmp->lapicbase;
326 p += PCMPprocessorsz;
335 if(apic = mkioapic((PCMPioapic*)p))
336 ioapicinit(apic, apic->apicno);
341 mkiointr((PCMPintr*)p);
346 mklintr((PCMPintr*)p);
352 * Ininitalize local APIC and start application processors.
360 /* stop application processors */
363 /* do generic reset */
367 static int identify(void);
374 .intrenable= mpintrenable,
375 .intron= lapicintron,
376 .introff= lapicintroff,
377 .fastclock= i8253read,
378 .timerset= lapictimerset,
388 if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
392 * Search for an MP configuration table. For now,
393 * don't accept the default configurations (physaddr == 0).
394 * Check for correct signature, calculate the checksum and,
395 * if correct, check the version.
396 * To do: check extended table checksum.
398 if((_mp_ = sigsearch("_MP_", _MP_sz)) == nil || _mp_->physaddr == 0)
407 if((pcmp = vmap(pa, len)) == nil)
409 if(pcmp->length < PCMPsz
410 || pa + pcmp->length-1 < pa
411 || memcmp(pcmp, "PCMP", 4) != 0
412 || (pcmp->version != 1 && pcmp->version != 4)){
420 vunmap(pcmp, PCMPsz);
421 if((pcmp = vmap(pa, len)) == nil)
424 if(checksum(pcmp, len) != 0)
427 if(m->havetsc && getconf("*notsc") == nil)
428 archmp.fastclock = tscticks;