]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/archmp.c
pc, pc64: new memory map code
[plan9front.git] / sys / src / 9 / pc / archmp.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7
8 #include "mp.h"
9
10 static PCMP *pcmp;
11
12 static char* buses[] = {
13         "CBUSI ",
14         "CBUSII",
15         "EISA  ",
16         "FUTURE",
17         "INTERN",
18         "ISA   ",
19         "MBI   ",
20         "MBII  ",
21         "MCA   ",
22         "MPI   ",
23         "MPSA  ",
24         "NUBUS ",
25         "PCI   ",
26         "PCMCIA",
27         "TC    ",
28         "VL    ",
29         "VME   ",
30         "XPRESS",
31         0,
32 };
33
34 static Bus*
35 mpgetbus(int busno)
36 {
37         Bus *bus;
38
39         for(bus = mpbus; bus; bus = bus->next)
40                 if(bus->busno == busno)
41                         return bus;
42
43         print("mpgetbus: can't find bus %d\n", busno);
44         return 0;
45 }
46
47 static Apic*
48 mkprocessor(PCMPprocessor* p)
49 {
50         static int machno = 1;
51         int apicno;
52         Apic *apic;
53
54         apicno = p->apicno;
55         if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpapic[apicno] != nil)
56                 return 0;
57
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;
65         if(p->flags & PcmpBP)
66                 apic->machno = 0;
67         else
68                 apic->machno = machno++;
69         mpapic[apicno] = apic;
70
71         return apic;
72 }
73
74 static Bus*
75 mkbus(PCMPbus* p)
76 {
77         Bus *bus;
78         int i;
79
80         for(i = 0; buses[i]; i++)
81                 if(strncmp(buses[i], p->string, sizeof(p->string)) == 0)
82                         break;
83         if(buses[i] == 0)
84                 return 0;
85
86         if((bus = xalloc(sizeof(Bus))) == nil)
87                 panic("mkbus: no memory for Bus");
88         if(mpbus)
89                 mpbuslast->next = bus;
90         else
91                 mpbus = bus;
92         mpbuslast = bus;
93
94         bus->type = i;
95         bus->busno = p->busno;
96         if(bus->type == BusEISA){
97                 bus->po = PcmpLOW;
98                 bus->el = PcmpLEVEL;
99                 if(mpeisabus != -1)
100                         print("mkbus: more than one EISA bus\n");
101                 mpeisabus = bus->busno;
102         }
103         else if(bus->type == BusPCI){
104                 bus->po = PcmpLOW;
105                 bus->el = PcmpLEVEL;
106         }
107         else if(bus->type == BusISA){
108                 bus->po = PcmpHIGH;
109                 bus->el = PcmpEDGE;
110                 if(mpisabus != -1)
111                         print("mkbus: more than one ISA bus\n");
112                 mpisabus = bus->busno;
113         }
114         else{
115                 bus->po = PcmpHIGH;
116                 bus->el = PcmpEDGE;
117         }
118
119         return bus;
120 }
121
122 static Apic*
123 mkioapic(PCMPioapic* p)
124 {
125         void *va;
126         int apicno;
127         Apic *apic;
128
129         apicno = p->apicno;
130         if(!(p->flags & PcmpEN) || apicno > MaxAPICNO || mpioapic[apicno] != nil)
131                 return 0;
132         /*
133          * Map the I/O APIC.
134          */
135         if((va = vmap(p->addr, 1024)) == nil)
136                 return 0;
137         if((apic = xalloc(sizeof(Apic))) == nil)
138                 panic("mkioapic: no memory for Apic");
139         apic->type = PcmpIOAPIC;
140         apic->apicno = apicno;
141         apic->addr = va;
142         apic->paddr = p->addr;
143         apic->flags = p->flags;
144         mpioapic[apicno] = apic;
145
146         return apic;
147 }
148
149 static Aintr*
150 mkiointr(PCMPintr* p)
151 {
152         Bus *bus;
153         Aintr *aintr;
154         PCMPintr* pcmpintr;
155
156         /*
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
160          * an error for now.
161          */
162         if(p->apicno > MaxAPICNO || mpioapic[p->apicno] == nil)
163                 return 0;
164         
165         if((bus = mpgetbus(p->busno)) == 0)
166                 return 0;
167
168         if((aintr = xalloc(sizeof(Aintr))) == nil)
169                 panic("mkiointr: no memory for Aintr");
170         aintr->intr = p;
171
172         if(0)
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);
177         /*
178          * Hack for Intel SR1520ML motherboard, which BIOS describes
179          * the i82575 dual ethernet controllers incorrectly.
180          */
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,
189                                 pcmpintr->irq);
190                         pcmpintr->intin = 17;
191                         aintr->intr = pcmpintr;
192                 }
193         }
194         aintr->apic = mpioapic[p->apicno];
195         aintr->next = bus->aintr;
196         bus->aintr = aintr;
197
198         return aintr;
199 }
200
201 static int
202 mklintr(PCMPintr* p)
203 {
204         Apic *apic;
205         Bus *bus;
206         int i, intin, v;
207
208         /*
209          * The offsets of vectors for LINT[01] are known to be
210          * 0 and 1 from the local APIC vector space at VectorLAPIC.
211          */
212         if((bus = mpgetbus(p->busno)) == 0)
213                 return 0;
214         intin = p->intin;
215
216         /*
217          * Pentium Pros have problems if LINT[01] are set to ExtINT
218          * so just bag it, SMP mode shouldn't need ExtINT anyway.
219          */
220         if(p->intr == PcmpExtINT || p->intr == PcmpNMI)
221                 v = ApicIMASK;
222         else
223                 v = mpintrinit(bus, p, VectorLAPIC+intin, p->irq);
224
225         if(p->apicno == 0xFF){
226                 for(i=0; i<=MaxAPICNO; i++){
227                         if((apic = mpapic[i]) == nil)
228                                 continue;
229                         if(apic->flags & PcmpEN)
230                                 apic->lintr[intin] = v;
231                 }
232         }
233         else{
234                 if(apic = mpapic[p->apicno])
235                         if(apic->flags & PcmpEN)
236                                 apic->lintr[intin] = v;
237         }
238
239         return v;
240 }
241
242 static void
243 dumpmp(uchar *p, uchar *e)
244 {
245         int i;
246
247         for(i = 0; p < e; p++) {
248                 if((i % 16) == 0) print("*mp%d=", i/16);
249                 print("%.2x ", *p);
250                 if((++i % 16) == 0) print("\n");
251         }
252         if((i % 16) != 0) print("\n");
253 }
254
255
256 static void
257 mpoverride(uchar** newp, uchar** e)
258 {
259         int size, i, j;
260         char buf[20];
261         uchar* p;
262         char* s;
263         
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");
268         *e = p + size;
269         for(i = 0; ; i++){
270                 snprint(buf, sizeof buf, "*mp%d", i);
271                 s = getconf(buf);
272                 if(s == nil) break;
273                 while(*s){
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);
277                         *p++ = j;
278                 }
279         }
280         if(p != *e) panic("mpoverride: size doesn't match");
281 }
282
283 static void
284 pcmpinit(void)
285 {
286         uchar *p, *e;
287         Apic *apic;
288         void *va;
289
290         /*
291          * Map the local APIC.
292          */
293         va = vmap(pcmp->lapicbase, 1024);
294
295         print("LAPIC: %.8lux %#p\n", pcmp->lapicbase, va);
296         if(va == nil)
297                 panic("pcmpinit: cannot map lapic %.8lux", pcmp->lapicbase);
298
299         p = ((uchar*)pcmp)+PCMPsz;
300         e = ((uchar*)pcmp)+pcmp->length;
301         if(getconf("*dumpmp") != nil)
302                 dumpmp(p, e);
303         if(getconf("*mp") != nil)
304                 mpoverride(&p, &e);
305
306         /*
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.
310          */
311         while(p < e) switch(*p){
312         default:
313                 print("pcmpinit: unknown PCMP type 0x%uX (e-p 0x%zuX)\n",
314                         *p, e-p);
315                 while(p < e){
316                         print("%uX ", *p);
317                         p++;
318                 }
319                 break;
320
321         case PcmpPROCESSOR:
322                 if(apic = mkprocessor((PCMPprocessor*)p)){
323                         apic->addr = va;
324                         apic->paddr = pcmp->lapicbase;
325                 }
326                 p += PCMPprocessorsz;
327                 continue;
328
329         case PcmpBUS:
330                 mkbus((PCMPbus*)p);
331                 p += PCMPbussz;
332                 continue;
333
334         case PcmpIOAPIC:
335                 if(apic = mkioapic((PCMPioapic*)p))
336                         ioapicinit(apic, apic->apicno);
337                 p += PCMPioapicsz;
338                 continue;
339
340         case PcmpIOINTR:
341                 mkiointr((PCMPintr*)p);
342                 p += PCMPintrsz;
343                 continue;
344
345         case PcmpLINTR:
346                 mklintr((PCMPintr*)p);
347                 p += PCMPintrsz;
348                 continue;
349         }
350
351         /*
352          * Ininitalize local APIC and start application processors.
353          */
354         mpinit();
355 }
356
357 static void
358 mpreset(void)
359 {
360         /* stop application processors */
361         mpshutdown();
362
363         /* do generic reset */
364         archreset();
365 }
366
367 static int identify(void);
368
369 PCArch archmp = {
370 .id=            "_MP_", 
371 .ident=         identify,
372 .reset=         mpreset,
373 .intrinit=      pcmpinit,
374 .intrenable=    mpintrenable,
375 .intron=        lapicintron,
376 .introff=       lapicintroff,
377 .fastclock=     i8253read,
378 .timerset=      lapictimerset,
379 };
380
381 static int
382 identify(void)
383 {
384         char *cp;
385         _MP_ *_mp_;
386         ulong pa, len;
387
388         if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
389                 return 1;
390
391         /*
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.
397          */
398         if((_mp_ = sigsearch("_MP_", _MP_sz)) == nil || _mp_->physaddr == 0)
399                 return 1;
400
401         len = PCMPsz;
402         pa = _mp_->physaddr;
403         if(pa + len-1 < pa)
404                 return 1;
405
406         memreserve(pa, len);
407         if((pcmp = vmap(pa, len)) == nil)
408                 return 1;
409         if(pcmp->length < PCMPsz
410         || pa + pcmp->length-1 < pa
411         || memcmp(pcmp, "PCMP", 4) != 0
412         || (pcmp->version != 1 && pcmp->version != 4)){
413 Bad:
414                 vunmap(pcmp, len);
415                 pcmp = nil;
416                 return 1;
417         }
418         len = pcmp->length;
419         memreserve(pa, len);
420         vunmap(pcmp, PCMPsz);
421         if((pcmp = vmap(pa, len)) == nil)
422                 return 1;
423
424         if(checksum(pcmp, len) != 0)
425                 goto Bad;
426
427         if(m->havetsc && getconf("*notsc") == nil)
428                 archmp.fastclock = tscticks;
429
430         return 0;
431 }