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