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