1a4b213cfSFrans Kaashoek // Multiprocessor support
2eb52c7deSrsc // Search memory for MP description structures.
399b11b6cSrsc // http://developer.intel.com/design/pentium/datashts/24201606.pdf
499b11b6cSrsc
57baa34a4Skaashoek #include "types.h"
67baa34a4Skaashoek #include "defs.h"
721a88fd4Skaashoek #include "param.h"
89aa0337dSFrans Kaashoek #include "memlayout.h"
9558ab49fSrsc #include "mp.h"
1021a88fd4Skaashoek #include "x86.h"
1121a88fd4Skaashoek #include "mmu.h"
128b4e2a08Srtm #include "proc.h"
137baa34a4Skaashoek
148b4e2a08Srtm struct cpu cpus[NCPU];
158b4e2a08Srtm int ncpu;
1621575761Srsc uchar ioapicid;
17c8b29f6dSkaashoek
1899b11b6cSrsc static uchar
sum(uchar * addr,int len)1999b11b6cSrsc sum(uchar *addr, int len)
2099b11b6cSrsc {
2199b11b6cSrsc int i, sum;
2299b11b6cSrsc
2399b11b6cSrsc sum = 0;
2499b11b6cSrsc for(i=0; i<len; i++)
2599b11b6cSrsc sum += addr[i];
2699b11b6cSrsc return sum;
2799b11b6cSrsc }
2899b11b6cSrsc
2999b11b6cSrsc // Look for an MP structure in the len bytes at addr.
3099b11b6cSrsc static struct mp*
mpsearch1(uint a,int len)313a038106SFrans Kaashoek mpsearch1(uint a, int len)
3299b11b6cSrsc {
333a038106SFrans Kaashoek uchar *e, *p, *addr;
347baa34a4Skaashoek
35a7c03bd9SRobert Morris addr = P2V(a);
367baa34a4Skaashoek e = addr+len;
3799b11b6cSrsc for(p = addr; p < e; p += sizeof(struct mp))
3899b11b6cSrsc if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
39b5f17007Srsc return (struct mp*)p;
407baa34a4Skaashoek return 0;
417baa34a4Skaashoek }
427baa34a4Skaashoek
43f5527388Srsc // Search for the MP Floating Pointer Structure, which according to the
44f5527388Srsc // spec is in one of the following three locations:
45f5527388Srsc // 1) in the first KB of the EBDA;
46f5527388Srsc // 2) in the last KB of system base memory;
47f5527388Srsc // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
48b5f17007Srsc static struct mp*
mpsearch(void)4921575761Srsc mpsearch(void)
507baa34a4Skaashoek {
5129270816Srtm uchar *bda;
5229270816Srtm uint p;
53b5f17007Srsc struct mp *mp;
547baa34a4Skaashoek
553a038106SFrans Kaashoek bda = (uchar *) P2V(0x400);
56a6c4711aSrsc if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){
573a038106SFrans Kaashoek if((mp = mpsearch1(p, 1024)))
587baa34a4Skaashoek return mp;
59da942337Srsc } else {
607baa34a4Skaashoek p = ((bda[0x14]<<8)|bda[0x13])*1024;
613a038106SFrans Kaashoek if((mp = mpsearch1(p-1024, 1024)))
627baa34a4Skaashoek return mp;
637baa34a4Skaashoek }
643a038106SFrans Kaashoek return mpsearch1(0xF0000, 0x10000);
657baa34a4Skaashoek }
667baa34a4Skaashoek
67f5527388Srsc // Search for an MP configuration table. For now,
68f5527388Srsc // don't accept the default configurations (physaddr == 0).
69f5527388Srsc // Check for correct signature, calculate the checksum and,
70f5527388Srsc // if correct, check the version.
71f5527388Srsc // To do: check extended table checksum.
7299b11b6cSrsc static struct mpconf*
mpconfig(struct mp ** pmp)7321575761Srsc mpconfig(struct mp **pmp)
747baa34a4Skaashoek {
7599b11b6cSrsc struct mpconf *conf;
7699b11b6cSrsc struct mp *mp;
777baa34a4Skaashoek
7821575761Srsc if((mp = mpsearch()) == 0 || mp->physaddr == 0)
797baa34a4Skaashoek return 0;
80a7c03bd9SRobert Morris conf = (struct mpconf*) P2V((uint) mp->physaddr);
8199b11b6cSrsc if(memcmp(conf, "PCMP", 4) != 0)
8299b11b6cSrsc return 0;
8399b11b6cSrsc if(conf->version != 1 && conf->version != 4)
8499b11b6cSrsc return 0;
8599b11b6cSrsc if(sum((uchar*)conf, conf->length) != 0)
8699b11b6cSrsc return 0;
8799b11b6cSrsc *pmp = mp;
8899b11b6cSrsc return conf;
897baa34a4Skaashoek }
907baa34a4Skaashoek
917baa34a4Skaashoek void
mpinit(void)9221575761Srsc mpinit(void)
937baa34a4Skaashoek {
9429270816Srtm uchar *p, *e;
95*4f14d8d1SFrans Kaashoek int ismp;
9699b11b6cSrsc struct mp *mp;
9799b11b6cSrsc struct mpconf *conf;
9899b11b6cSrsc struct mpproc *proc;
99c8b29f6dSkaashoek struct mpioapic *ioapic;
1007baa34a4Skaashoek
10121575761Srsc if((conf = mpconfig(&mp)) == 0)
102*4f14d8d1SFrans Kaashoek panic("Expect to run on an SMP");
103f7017212Skaashoek ismp = 1;
10499b11b6cSrsc lapic = (uint*)conf->lapicaddr;
10599b11b6cSrsc for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
1067baa34a4Skaashoek switch(*p){
10799b11b6cSrsc case MPPROC:
10899b11b6cSrsc proc = (struct mpproc*)p;
109ae15515dSFrans Kaashoek if(ncpu < NCPU) {
110ae15515dSFrans Kaashoek cpus[ncpu].apicid = proc->apicid; // apicid may differ from ncpu
1117baa34a4Skaashoek ncpu++;
112ae15515dSFrans Kaashoek }
11399b11b6cSrsc p += sizeof(struct mpproc);
1147baa34a4Skaashoek continue;
11521a88fd4Skaashoek case MPIOAPIC:
116c8b29f6dSkaashoek ioapic = (struct mpioapic*)p;
11721575761Srsc ioapicid = ioapic->apicno;
118b5f17007Srsc p += sizeof(struct mpioapic);
1197baa34a4Skaashoek continue;
12099b11b6cSrsc case MPBUS:
12121a88fd4Skaashoek case MPIOINTR:
12299b11b6cSrsc case MPLINTR:
12399b11b6cSrsc p += 8;
1247baa34a4Skaashoek continue;
1257baa34a4Skaashoek default:
126af6a6a47SRuss Cox ismp = 0;
127ae15515dSFrans Kaashoek break;
1287baa34a4Skaashoek }
1297baa34a4Skaashoek }
130*4f14d8d1SFrans Kaashoek if(!ismp)
131*4f14d8d1SFrans Kaashoek panic("Didn't find a suitable machine");
132af6a6a47SRuss Cox
1330cfc7290Srsc if(mp->imcrp){
134da942337Srsc // Bochs doesn't support IMCR, so this doesn't run on Bochs.
135da942337Srsc // But it would on real hardware.
1360cfc7290Srsc outb(0x22, 0x70); // Select IMCR
137da942337Srsc outb(0x23, inb(0x23) | 1); // Mask external interrupts.
138c8b29f6dSkaashoek }
1398148b6eeSrtm }
140