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