Yabu.log

ITなどの雑記

30日OS自作本9日目

30日OS自作本9日目

9日はメモリ管理です。

BIOSからメモリの情報を取得する方法(失敗)

この辺を参考にINT 0x15命令を適切なパラメータで呼べばBIOSからCX,DXレジスタにメモリの情報っぽいものを得れることがわかりました。

Typical Output: AX = CX = extended memory between 1M and 16M, in K (max 3C00h = 15MB) BX = DX = extended memory above 16M, in 64K blocks

naskだと動かない命令がいくつかあったので書き直してみました。

_memoryfromBIOS:

        ;EDXとECXを退避
        PUSH    EDX
        PUSH    ECX

    ;ECXとEDXを初期化
        MOV ECX, 0x0000
        MOV EDX, 0x0000

    ;パラメータをAXに設定してINT 0x15命令を呼ぶ
        MOV AX, 0xDA88
        INT 0x15        

                ;メモリの情報をAX,BXに入れ戻り値とする?
        MOV AX, CX
        MOV BX, DX

        ;退避したEDXとECXを元に戻す
        POP ECX
        POP EDX
        RET

あれ?AXに設定すれば戻り値になるのはわかるけどBXに設定したのはなんでだろう?

まぁとりあえず外部から呼べるように.nasにGLOBAL修飾子を足します

GLOBAL  _memoryfromBIOS

bootpack.hに関数の定義を書いて*1

void memoryfromBIOS(void);

これをmain関数から呼びます

多分動くと思ったのですが、INT 0x15を呼び出すとそのあとのプログラムの動きが止まってしまうようです。*2 これは多分、

  • INT 0x15を呼び出すための準備(設定のようなもの)がきちんとできていない
  • INT 0x15を読んだ後にすべき後処理がきちんとできていない

が原因だと思うのですが、調べてもよくわからないのでこの辺で打ち切ります。(あまりこの辺に時間をかけても美味しくない)

BIOSの機能を使わずOS側のPGで使用可能メモリを調査する

BIOSは使わずにプログラムからメモリの書き込み可否を操作していきます。*3

  • 1.固定データ書き込み
  • 2.書き込みデータを反転
  • 3.再度読み込み

で1で書き込んだデータが3で読み込んだデータの反転した値になっているか、をチェックします。*4

unsigned int i, *p, old, pat0 = 0xaa55aa55, pat1 = 0x55aa55aa;
for (i = start; i <= end; i += 0x1000) {
  p = (unsigned int *) (i + 0xffc);
  old = *p;         /* いじる前の値を覚えておく */
  *p = pat0;            /* ためしに書いてみる */
  *p ^= 0xffffffff;    /* そしてそれを反転してみる */
  if (*p != pat1) {   /* 反転結果になったか? */
not_memory:
    *p = old;
    break;
  }
  *p ^= 0xffffffff;    /* もう一度反転してみる */
  if (*p != pat0) {   /* 元に戻ったか? */
    goto not_memory;
  }
  *p = old;         /* いじった値を元に戻す */
}

結局上記Cのコードはコンパイル時の最適の影響でうまく動かなくなるためアセンブリで同じ内容のコードを書くことになりました。

キャッシュ禁止の設定方法

上記のようなメモリを触りに行くことが目的のコードでキャッシュを使われると困るので、キャッシュを禁止するように設定しました。 CR0レジスタ0x60000000を書き込みます これは多分、先頭2bit,3bit目を1にすると設定できる、とうい風なことだと思います(0x6=0b0110)

486

この章で486の話題が出てきましたが、以前からこの本を読もうと思っています。

電子版があったり、ちょっと前にruiさんがtwitterで進めていたりしたので、ちょくちょく立ち読みしていました。

*1:void型なのはとりあえず読んでみたかったから。多分本当に使うときはunsigned int型(2バイト)になると思う

*2:いろんな位置で呼び出してみたり、アセンブリの中身をINX 0x15のみにしてみたり試しました。

*3:書き込みに失敗したところまでが使用可能メモリとみなす

*4:なぜわざわざ反転するかというと,そのままの読み書きだとうまくいかないハードがあるようです。