xv6のブートプロセスにおいて、mpinitという関数があり、予想ではマルチプロセッサ関係の初期化を行っている。
その中で、EBDAやBDAというBIOS関連のアクセスに入る部分があるので、具体的に何をしているのかを調べてみた。
void mpinit(void) { ... bcpu = &cpus[0]; if((conf = mpconfig(&mp)) == 0) { return; } ...
mpconfig()という関数を呼んでいるが、これは、
static struct mpconf* mpconfig(struct mp **pmp) { ... if((mp = mpsearch()) == 0 || mp->physaddr == 0) return 0;
mpsearch()という関数を読んでおり、これがBDAへのアクセスとなっている。
static struct mp* mpsearch(void) { ... bda = (uchar *) P2V(0x400); if((p = ((bda[0x0F]<<8)| bda[0x0E]) << 4)){
BDAとは何だろうか?調査してみると、BIOS Data Areaの略称らしい。さらにEBDAとはExtended BIOS Data Areaの略称だそうだ。
そうすると、mpsearch()の動作は、まずBDAを探索し、EBDAの場所を入手する。
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;
mpsearch1()ではEBDAを検索しており、
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; }
_MP_
とは何だろうか?
fpsのサイズは16バイトで、いくつかのフィールドがありますが、この中で実際に使っているのはfp_signature、fp_mp_tableの2個だけです。 fpsの先頭4バイトはシグネチャになっていて、そのシグネチャは"_MP_"であることと規定されてます。
MP Floating Pointer Structureを調べる - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモ
なるほど。それを探索しているのか。そして、mpsearch()およびmpsearch1()はMPの先頭、つまりFPSの先頭(MPで始まる)を返す。
for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){ switch(*p){ case MPPROC: proc = (struct mpproc*)p;
mpconfig()自体はmpconf構造体の先頭を返すのだが、conf+1
ということはその直後のデータを参照しており、これはおそらくmpproc
に当たっている。
struct mp { // floating pointer uchar signature[4]; // "_MP_" void *physaddr; // phys addr of MP config table uchar length; // 1 uchar specrev; // [14] uchar checksum; // all bytes must add up to 0 uchar type; // MP system config type uchar imcrp; uchar reserved[3]; }; struct mpconf { // configuration table header uchar signature[4]; // "PCMP" ushort length; // total table length uchar version; // [14] uchar checksum; // all bytes must add up to 0 uchar product[20]; // product id uint *oemtable; // OEM table pointer ushort oemlength; // OEM table length ushort entry; // entry count uint *lapicaddr; // address of local APIC ushort xlength; // extended table length uchar xchecksum; // extended table checksum uchar reserved; };
このエントリを舐めることにより、MPのコンフィグレーションを行っているわけか。