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
14struct cpu cpus[NCPU];
15int ncpu;
16uchar ioapicid;
17
18static uchar
19sum(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.
30static struct mp*
31mpsearch1(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.
48static struct mp*
49mpsearch(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.
72static struct mpconf*
73mpconfig(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
91void
92mpinit(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