/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- mpbcpu
- sum
- mpsearch1
- mpsearch
- mpconfig
- mpinit
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 static struct cpu *bcpu;
16 int ismp;
17 int ncpu;
18 uchar ioapicid;
19
20 int
21 mpbcpu(void)
22 {
23 return bcpu-cpus;
24 }
25
26 static uchar
27 sum(uchar *addr, int len)
28 {
29 int i, sum;
30
31 sum = 0;
32 for(i=0; i<len; i++)
33 sum += addr[i];
34 return sum;
35 }
36
37 // Look for an MP structure in the len bytes at addr.
38 static struct mp*
39 mpsearch1(uint a, int len)
40 {
41 uchar *e, *p, *addr;
42
43 addr = p2v(a);
44 e = addr+len;
45 for(p = addr; p < e; p += sizeof(struct mp))
46 if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
47 return (struct mp*)p;
48 return 0;
49 }
50
51 // Search for the MP Floating Pointer Structure, which according to the
52 // spec is in one of the following three locations:
53 // 1) in the first KB of the EBDA;
54 // 2) in the last KB of system base memory;
55 // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
56 static struct mp*
57 mpsearch(void)
58 {
59 uchar *bda;
60 uint p;
61 struct mp *mp;
62
63 bda = (uchar *) P2V(0x400);
64 if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){
65 if((mp = mpsearch1(p, 1024)))
66 return mp;
67 } else {
68 p = ((bda[0x14]<<8)|bda[0x13])*1024;
69 if((mp = mpsearch1(p-1024, 1024)))
70 return mp;
71 }
72 return mpsearch1(0xF0000, 0x10000);
73 }
74
75 // Search for an MP configuration table. For now,
76 // don't accept the default configurations (physaddr == 0).
77 // Check for correct signature, calculate the checksum and,
78 // if correct, check the version.
79 // To do: check extended table checksum.
80 static struct mpconf*
81 mpconfig(struct mp **pmp)
82 {
83 struct mpconf *conf;
84 struct mp *mp;
85
86 if((mp = mpsearch()) == 0 || mp->physaddr == 0)
87 return 0;
88 conf = (struct mpconf*) p2v((uint) mp->physaddr);
89 if(memcmp(conf, "PCMP", 4) != 0)
90 return 0;
91 if(conf->version != 1 && conf->version != 4)
92 return 0;
93 if(sum((uchar*)conf, conf->length) != 0)
94 return 0;
95 *pmp = mp;
96 return conf;
97 }
98
99 void
100 mpinit(void)
101 {
102 uchar *p, *e;
103 struct mp *mp;
104 struct mpconf *conf;
105 struct mpproc *proc;
106 struct mpioapic *ioapic;
107
108 bcpu = &cpus[0];
109 if((conf = mpconfig(&mp)) == 0)
110 return;
111 ismp = 1;
112 lapic = (uint*)conf->lapicaddr;
113 for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
114 switch(*p){
115 case MPPROC:
116 proc = (struct mpproc*)p;
117 if(ncpu != proc->apicid){
118 cprintf("mpinit: ncpu=%d apicid=%d\n", ncpu, proc->apicid);
119 ismp = 0;
120 }
121 if(proc->flags & MPBOOT)
122 bcpu = &cpus[ncpu];
123 cpus[ncpu].id = ncpu;
124 ncpu++;
125 p += sizeof(struct mpproc);
126 continue;
127 case MPIOAPIC:
128 ioapic = (struct mpioapic*)p;
129 ioapicid = ioapic->apicno;
130 p += sizeof(struct mpioapic);
131 continue;
132 case MPBUS:
133 case MPIOINTR:
134 case MPLINTR:
135 p += 8;
136 continue;
137 default:
138 cprintf("mpinit: unknown config type %x\n", *p);
139 ismp = 0;
140 }
141 }
142 if(!ismp){
143 // Didn't like what we found; fall back to no MP.
144 ncpu = 1;
145 lapic = 0;
146 ioapicid = 0;
147 return;
148 }
149
150 if(mp->imcrp){
151 // Bochs doesn't support IMCR, so this doesn't run on Bochs.
152 // But it would on real hardware.
153 outb(0x22, 0x70); // Select IMCR
154 outb(0x23, inb(0x23) | 1); // Mask external interrupts.
155 }
156 }