読者です 読者をやめる 読者になる 読者になる

MP Floating Pointer Structureを調べる

x86

MINIX2のsmp実装を見ていく上で出てくる用語の一つがfps
仕様書だとfpsと略してないですが、smp実装のソースコードで使っているのでそれに合わせます。

fpsとはMP Floating Pointer Structureの略で、以下の2つの情報を保持しているテーブル。

1.MP Configuration tableのアドレス
2.その他のMP機能に関する情報

このうち、2番目はminix2smpの実装を見ていく上では必要なさそうなので1番目のみ調べる。
MPの仕様書でMUSTと言っている仕様は、「fpsは規程のアドレスに存在しないといけない」ということ。
そのアドレスはどこかというと、
a. Extended BIOS Data Area(EBDA)の最初の1KB以内。または、
b. EDBAが定義されていない場合は、ベースメモリ領域の最後の1KB(ベースメモリ領域が640KBなら639-640KBの範囲)。または、
c. BIOSのROM内。アドレス0F0000h〜0FFFFFの範囲。
*bの640KB以内というのは8086時代からある640KBの壁というやつだと思います。
fpsが置かれるアドレスをMUST項目としている理由は、どこにFPSがあるか分からなければOSがFPSを探せないからということですね。

1の「MP Configuration table Headerのアドレス」について。x86でMP Configuration table HeaderにMP環境でのコンフィギュレーション情報があります。といっても、情報の本体ではなくて、本物の情報(Process EntriesやBus Entriesと呼ばれるテーブル)にアクセスするのに必要な情報ですが。
#仕様書にはオプショナルとも書いてありましたけど・・・
このテーブル(MP Configuration table Header)とProcess Entriesなどのテーブルはメモリ上では連続しているのでMP Configuration table Headerのテーブルへのアドレスさえ分かれば後はデータを辿っていけます。
fpsにあるフィールドの一つはこの先頭のテーブルのアドレスを保持していて、OSはここに書かれているアドレスを起点として情報を読み込んで行きます。

minix2の実装では以下のような構造体でfpsを表現してます。

struct floating_pointer {
  char   fp_signature[4];       /* must be _MP_ */
  u32_t  fp_mp_table;           /* address to MP table */
  u8_t   fp_length;             /* FPS size in 16-byte parragraphs */
  u8_t   fp_version;            /* version number: 04h for 1.4 */
  u8_t   fp_cheksum;            /* bytes in FPS must sum 0 */
  u8_t   fp_sd_config_num;      /* standar config number (0 for none) */
  u8_t   fp_imcrp;              /* bit 7 is IMCR present and PIC mode */
  char   unused[3];             /* last 3 bytes are reserved */
};

fpsのサイズは16バイトで、いくつかのフィールドがありますが、この中で実際に使っているのはfp_signature、fp_mp_tableの2個だけです。
fpsの先頭4バイトはシグネチャになっていて、そのシグネチャは"_MP_"であることと規定されてます。
OSがfpsを探すときはfpsが置かれているべきアドレスのスタート地点から16バイトおきにメモリの内容を読み込んで、
先頭4バイトがMPの仕様で定義しているシグネチャと一致すれば、そこがfpsだと仮定できます。
fpsかどうかのチェックは2段階あり、シグネチャチェックサムの確認によって行います。
チェックサムの確認はfpsの領域(16バイト)を1バイトずつ読み込んで数値として足し算していき、結果が0ならOKとなります。

実装はこんな感じになっています。

int test_fps_checksum(struct floating_pointer *fps) {
   unsigned char *data, checksum;
   int i;
 
/* Check in a FPS structure for a valid signature and checksum 
   Return noncero on success */
   /* fisrt look for signature */
   for (i=0; i<4; i++)
      if (fps->fp_signature[i] != SIGN_FPS[i]) return 0;

最初にシグネチャを確認して、正しいシグネチャなら次にチェックサムの計算をします。

   /* then calculate checksum*/
   data=(unsigned char *)fps;
   checksum=0;
   for (i=0; i<sizeof (struct floating_pointer); i++)
      checksum+= data[i];
   return (!checksum);  /* checksum ok if sums 0 */
}

データを1バイトずつ数値として足し算していって結果判定しています。
シグネチャチェックサムがMPの仕様通りなら読み込んだ領域は間違いなくfpsと言えるので、
fp_mp_tableに保持されてるMP Configuration table Headerのアドレスを使ってデータを読み込んで行きます。

fpsについての説明はここまで。
#ちなみに、MP Configuration table Headerもシグネチャチェックサムで正当性を検証しますが、
#そこで使用する方法はfpsと同じく、シグネチャ&チェックサム方式です。