| // Multiprocessor support | |
| // Search memory for MP description structures. | |
| // http://developer.intel.com/design/pentium/datashts/24201606.pdf | |
| struct cpu cpus[NCPU]; | |
| int ncpu; | |
| uchar ioapicid; | |
| static uchar | |
| sum(uchar *addr, int len) | |
| { | |
| int i, sum; | |
| sum = 0; | |
| for(i=0; i<len; i++) | |
| sum += addr[i]; | |
| return sum; | |
| } | |
| // Look for an MP structure in the len bytes at addr. | |
| static struct mp* | |
| mpsearch1(uint a, int len) | |
| { | |
| uchar *e, *p, *addr; | |
| addr = P2V(a); | |
| e = addr+len; | |
| for(p = addr; p < e; p += sizeof(struct mp)) | |
| if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0) | |
| return (struct mp*)p; | |
| return 0; | |
| } | |
| // Search for the MP Floating Pointer Structure, which according to the | |
| // spec is in one of the following three locations: | |
| // 1) in the first KB of the EBDA; | |
| // 2) in the last KB of system base memory; | |
| // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF. | |
| static struct mp* | |
| mpsearch(void) | |
| { | |
| uchar *bda; | |
| uint p; | |
| struct mp *mp; | |
| bda = (uchar *) P2V(0x400); | |
| if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){ | |
| if((mp = mpsearch1(p, 1024))) | |
| return mp; | |
| } else { | |
| p = ((bda[0x14]<<8)|bda[0x13])*1024; | |
| if((mp = mpsearch1(p-1024, 1024))) | |
| return mp; | |
| } | |
| return mpsearch1(0xF0000, 0x10000); | |
| } | |
| // Search for an MP configuration table. For now, | |
| // don't accept the default configurations (physaddr == 0). | |
| // Check for correct signature, calculate the checksum and, | |
| // if correct, check the version. | |
| // To do: check extended table checksum. | |
| static struct mpconf* | |
| mpconfig(struct mp **pmp) | |
| { | |
| struct mpconf *conf; | |
| struct mp *mp; | |
| if((mp = mpsearch()) == 0 || mp->physaddr == 0) | |
| return 0; | |
| conf = (struct mpconf*) P2V((uint) mp->physaddr); | |
| if(memcmp(conf, "PCMP", 4) != 0) | |
| return 0; | |
| if(conf->version != 1 && conf->version != 4) | |
| return 0; | |
| if(sum((uchar*)conf, conf->length) != 0) | |
| return 0; | |
| *pmp = mp; | |
| return conf; | |
| } | |
| void | |
| mpinit(void) | |
| { | |
| uchar *p, *e; | |
| int ismp; | |
| struct mp *mp; | |
| struct mpconf *conf; | |
| struct mpproc *proc; | |
| struct mpioapic *ioapic; | |
| if((conf = mpconfig(&mp)) == 0) | |
| panic("Expect to run on an SMP"); | |
| ismp = 1; | |
| lapic = (uint*)conf->lapicaddr; | |
| for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){ | |
| switch(*p){ | |
| case MPPROC: | |
| proc = (struct mpproc*)p; | |
| if(ncpu < NCPU) { | |
| cpus[ncpu].apicid = proc->apicid; // apicid may differ from ncpu | |
| ncpu++; | |
| } | |
| p += sizeof(struct mpproc); | |
| continue; | |
| case MPIOAPIC: | |
| ioapic = (struct mpioapic*)p; | |
| ioapicid = ioapic->apicno; | |
| p += sizeof(struct mpioapic); | |
| continue; | |
| case MPBUS: | |
| case MPIOINTR: | |
| case MPLINTR: | |
| p += 8; | |
| continue; | |
| default: | |
| ismp = 0; | |
| break; | |
| } | |
| } | |
| if(!ismp) | |
| panic("Didn't find a suitable machine"); | |
| if(mp->imcrp){ | |
| // Bochs doesn't support IMCR, so this doesn't run on Bochs. | |
| // But it would on real hardware. | |
| outb(0x22, 0x70); // Select IMCR | |
| outb(0x23, inb(0x23) | 1); // Mask external interrupts. | |
| } | |
| } | |
| int syscallcount(int cpu) | |
| { | |
| if(cpu < 0 || cpu >= ncpu) | |
| return -1; | |
| return cpus[cpu].syscallcount; | |
| } | |
| int reset_syscallcount(int cpu){ | |
| if(cpu < 0 || cpu >= ncpu) | |
| return -1; | |
| cpus[cpu].syscallcount = 0; | |
| return 0; | |
| } |
Xet Storage Details
- Size:
- 3.39 kB
- Xet hash:
- cce8bf8cbfdcccb8eabf16a9e1c76d28a27962ad2883ab41c34a7787a3ac51df
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.