xref: /xv6-public/mp.c (revision 4f14d8d1)
1 // Multiprocessor support
2 // Search memory for MP description structures.
3 // http://developer.intel.com/design/pentium/datashts/24201606.pdf
4 
5 #include "types.h"
6 #include "defs.h"
7 #include "param.h"
8 #include "memlayout.h"
9 #include "mp.h"
10 #include "x86.h"
11 #include "mmu.h"
12 #include "proc.h"
13 
14 struct cpu cpus[NCPU];
15 int ncpu;
16 uchar ioapicid;
17 
18 static uchar
sum(uchar * addr,int len)19 sum(uchar *addr, int len)
20 {
21   int i, sum;
22 
23   sum = 0;
24   for(i=0; i<len; i++)
25     sum += addr[i];
26   return sum;
27 }
28 
29 // Look for an MP structure in the len bytes at addr.
30 static struct mp*
mpsearch1(uint a,int len)31 mpsearch1(uint a, int len)
32 {
33   uchar *e, *p, *addr;
34 
35   addr = P2V(a);
36   e = addr+len;
37   for(p = addr; p < e; p += sizeof(struct mp))
38     if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
39       return (struct mp*)p;
40   return 0;
41 }
42 
43 // Search for the MP Floating Pointer Structure, which according to the
44 // spec is in one of the following three locations:
45 // 1) in the first KB of the EBDA;
46 // 2) in the last KB of system base memory;
47 // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
48 static struct mp*
mpsearch(void)49 mpsearch(void)
50 {
51   uchar *bda;
52   uint p;
53   struct mp *mp;
54 
55   bda = (uchar *) P2V(0x400);
56   if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){
57     if((mp = mpsearch1(p, 1024)))
58       return mp;
59   } else {
60     p = ((bda[0x14]<<8)|bda[0x13])*1024;
61     if((mp = mpsearch1(p-1024, 1024)))
62       return mp;
63   }
64   return mpsearch1(0xF0000, 0x10000);
65 }
66 
67 // Search for an MP configuration table.  For now,
68 // don't accept the default configurations (physaddr == 0).
69 // Check for correct signature, calculate the checksum and,
70 // if correct, check the version.
71 // To do: check extended table checksum.
72 static struct mpconf*
mpconfig(struct mp ** pmp)73 mpconfig(struct mp **pmp)
74 {
75   struct mpconf *conf;
76   struct mp *mp;
77 
78   if((mp = mpsearch()) == 0 || mp->physaddr == 0)
79     return 0;
80   conf = (struct mpconf*) P2V((uint) mp->physaddr);
81   if(memcmp(conf, "PCMP", 4) != 0)
82     return 0;
83   if(conf->version != 1 && conf->version != 4)
84     return 0;
85   if(sum((uchar*)conf, conf->length) != 0)
86     return 0;
87   *pmp = mp;
88   return conf;
89 }
90 
91 void
mpinit(void)92 mpinit(void)
93 {
94   uchar *p, *e;
95   int ismp;
96   struct mp *mp;
97   struct mpconf *conf;
98   struct mpproc *proc;
99   struct mpioapic *ioapic;
100 
101   if((conf = mpconfig(&mp)) == 0)
102     panic("Expect to run on an SMP");
103   ismp = 1;
104   lapic = (uint*)conf->lapicaddr;
105   for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
106     switch(*p){
107     case MPPROC:
108       proc = (struct mpproc*)p;
109       if(ncpu < NCPU) {
110         cpus[ncpu].apicid = proc->apicid;  // apicid may differ from ncpu
111         ncpu++;
112       }
113       p += sizeof(struct mpproc);
114       continue;
115     case MPIOAPIC:
116       ioapic = (struct mpioapic*)p;
117       ioapicid = ioapic->apicno;
118       p += sizeof(struct mpioapic);
119       continue;
120     case MPBUS:
121     case MPIOINTR:
122     case MPLINTR:
123       p += 8;
124       continue;
125     default:
126       ismp = 0;
127       break;
128     }
129   }
130   if(!ismp)
131     panic("Didn't find a suitable machine");
132 
133   if(mp->imcrp){
134     // Bochs doesn't support IMCR, so this doesn't run on Bochs.
135     // But it would on real hardware.
136     outb(0x22, 0x70);   // Select IMCR
137     outb(0x23, inb(0x23) | 1);  // Mask external interrupts.
138   }
139 }
140