FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

xv6のブートプロセスにおけるEBDAとBDAについて

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の略称だそうだ。

Memory Map (x86) - OSDev Wiki

そうすると、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_とは何だろうか?

kernhack.hatenablog.com

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のコンフィグレーションを行っているわけか。