mp.c (3427B)
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 int 21 mpbcpu(void) 22 { 23 return bcpu-cpus; 24 } 25 26 static uchar 27 sum(uchar *addr, int len) 28 { 29 int i, sum; 30 31 sum = 0; 32 for(i=0; i<len; i++) 33 sum += addr[i]; 34 return sum; 35 } 36 37 // Look for an MP structure in the len bytes at addr. 38 static struct mp* 39 mpsearch1(uint a, int len) 40 { 41 uchar *e, *p, *addr; 42 43 addr = p2v(a); 44 e = addr+len; 45 for(p = addr; p < e; p += sizeof(struct mp)) 46 if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0) 47 return (struct mp*)p; 48 return 0; 49 } 50 51 // Search for the MP Floating Pointer Structure, which according to the 52 // spec is in one of the following three locations: 53 // 1) in the first KB of the EBDA; 54 // 2) in the last KB of system base memory; 55 // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF. 56 static struct mp* 57 mpsearch(void) 58 { 59 uchar *bda; 60 uint p; 61 struct mp *mp; 62 63 bda = (uchar *) P2V(0x400); 64 if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){ 65 if((mp = mpsearch1(p, 1024))) 66 return mp; 67 } else { 68 p = ((bda[0x14]<<8)|bda[0x13])*1024; 69 if((mp = mpsearch1(p-1024, 1024))) 70 return mp; 71 } 72 return mpsearch1(0xF0000, 0x10000); 73 } 74 75 // Search for an MP configuration table. For now, 76 // don't accept the default configurations (physaddr == 0). 77 // Check for correct signature, calculate the checksum and, 78 // if correct, check the version. 79 // To do: check extended table checksum. 80 static struct mpconf* 81 mpconfig(struct mp **pmp) 82 { 83 struct mpconf *conf; 84 struct mp *mp; 85 86 if((mp = mpsearch()) == 0 || mp->physaddr == 0) 87 return 0; 88 conf = (struct mpconf*) p2v((uintp) mp->physaddr); 89 if(memcmp(conf, "PCMP", 4) != 0) 90 return 0; 91 if(conf->version != 1 && conf->version != 4) 92 return 0; 93 if(sum((uchar*)conf, conf->length) != 0) 94 return 0; 95 *pmp = mp; 96 return conf; 97 } 98 99 void 100 mpinit(void) 101 { 102 uchar *p, *e; 103 struct mp *mp; 104 struct mpconf *conf; 105 struct mpproc *proc; 106 struct mpioapic *ioapic; 107 108 bcpu = &cpus[0]; 109 if((conf = mpconfig(&mp)) == 0) 110 return; 111 ismp = 1; 112 lapic = IO2V((uintp)conf->lapicaddr); 113 for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){ 114 switch(*p){ 115 case MPPROC: 116 proc = (struct mpproc*)p; 117 cprintf("mpinit ncpu=%d apicid=%d\n", ncpu, proc->apicid); 118 if(proc->flags & MPBOOT) 119 bcpu = &cpus[ncpu]; 120 cpus[ncpu].id = ncpu; 121 cpus[ncpu].apicid = proc->apicid; 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; 138 } 139 } 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; 146 } 147 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. 153 } 154 }