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