added base src
[xv6-db.git] / mp.c
blob5ab348ef9eba2ea908d057989ebfebe7e77b3b6b
1 // Multiprocessor bootstrap.
2 // Search memory for MP description structures.
3 // http://developer.intel.com/design/pentium/datashts/24201606.pdf
5 #include "types.h"
6 #include "defs.h"
7 #include "param.h"
8 #include "mp.h"
9 #include "x86.h"
10 #include "mmu.h"
11 #include "proc.h"
13 struct cpu cpus[NCPU];
14 static struct cpu *bcpu;
15 int ismp;
16 int ncpu;
17 uchar ioapicid;
19 int
20 mpbcpu(void)
22 return bcpu-cpus;
25 static uchar
26 sum(uchar *addr, int len)
28 int i, sum;
30 sum = 0;
31 for(i=0; i<len; i++)
32 sum += addr[i];
33 return sum;
36 // Look for an MP structure in the len bytes at addr.
37 static struct mp*
38 mpsearch1(uchar *addr, int len)
40 uchar *e, *p;
42 e = addr+len;
43 for(p = addr; p < e; p += sizeof(struct mp))
44 if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
45 return (struct mp*)p;
46 return 0;
49 // Search for the MP Floating Pointer Structure, which according to the
50 // spec is in one of the following three locations:
51 // 1) in the first KB of the EBDA;
52 // 2) in the last KB of system base memory;
53 // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
54 static struct mp*
55 mpsearch(void)
57 uchar *bda;
58 uint p;
59 struct mp *mp;
61 bda = (uchar*)0x400;
62 if((p = ((bda[0x0F]<<8)|bda[0x0E]) << 4)){
63 if((mp = mpsearch1((uchar*)p, 1024)))
64 return mp;
65 } else {
66 p = ((bda[0x14]<<8)|bda[0x13])*1024;
67 if((mp = mpsearch1((uchar*)p-1024, 1024)))
68 return mp;
70 return mpsearch1((uchar*)0xF0000, 0x10000);
73 // Search for an MP configuration table. For now,
74 // don't accept the default configurations (physaddr == 0).
75 // Check for correct signature, calculate the checksum and,
76 // if correct, check the version.
77 // To do: check extended table checksum.
78 static struct mpconf*
79 mpconfig(struct mp **pmp)
81 struct mpconf *conf;
82 struct mp *mp;
84 if((mp = mpsearch()) == 0 || mp->physaddr == 0)
85 return 0;
86 conf = (struct mpconf*)mp->physaddr;
87 if(memcmp(conf, "PCMP", 4) != 0)
88 return 0;
89 if(conf->version != 1 && conf->version != 4)
90 return 0;
91 if(sum((uchar*)conf, conf->length) != 0)
92 return 0;
93 *pmp = mp;
94 return conf;
97 void
98 mpinit(void)
100 uchar *p, *e;
101 struct mp *mp;
102 struct mpconf *conf;
103 struct mpproc *proc;
104 struct mpioapic *ioapic;
106 bcpu = &cpus[0];
107 if((conf = mpconfig(&mp)) == 0)
108 return;
109 ismp = 1;
110 lapic = (uint*)conf->lapicaddr;
111 for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
112 switch(*p){
113 case MPPROC:
114 proc = (struct mpproc*)p;
115 if(ncpu != proc->apicid){
116 cprintf("mpinit: ncpu=%d apicid=%d\n", ncpu, proc->apicid);
117 ismp = 0;
119 if(proc->flags & MPBOOT)
120 bcpu = &cpus[ncpu];
121 cpus[ncpu].id = ncpu;
122 ncpu++;
123 p += sizeof(struct mpproc);
124 continue;
125 case MPIOAPIC:
126 ioapic = (struct mpioapic*)p;
127 ioapicid = ioapic->apicno;
128 p += sizeof(struct mpioapic);
129 continue;
130 case MPBUS:
131 case MPIOINTR:
132 case MPLINTR:
133 p += 8;
134 continue;
135 default:
136 cprintf("mpinit: unknown config type %x\n", *p);
137 ismp = 0;
140 if(!ismp){
141 // Didn't like what we found; fall back to no MP.
142 ncpu = 1;
143 lapic = 0;
144 ioapicid = 0;
145 return;
148 if(mp->imcrp){
149 // Bochs doesn't support IMCR, so this doesn't run on Bochs.
150 // But it would on real hardware.
151 outb(0x22, 0x70); // Select IMCR
152 outb(0x23, inb(0x23) | 1); // Mask external interrupts.