ブートローダー(その3)
bootsect.S の次の処理は、メモリの 0x90000 にロードされた bootsect.S が読み込んだ (はずの) セットアップルーチン start_to_setup ルーチン (arch/i386/setup.S) へ処理を移す。
ここでは、各種ハードウェアのチェックを行って、プロテクトモードに切替える処理をおなう。
早速ソースを見てゆく。
まずは、デバイスの初期化設定を行っている。int 0x13 (function 00) を呼び、%dl レジスタで指定したドライブを(恐らく再度*)初期化している。
(*) "恐らく"と言ったのは、GRUB や LILO がセットアップルーチンを読み込む為に、ドライブを読む為である。
次に、旧式のカーネルイメージかを気にしています。旧式のブートローダ(ここで言っているブートローダーとは、grub や lilo などのカーネルイメージをロードするプログラム)は大きいカーネルイメージをロードする事があるらしい。
__BIG_KERNEL__ が定義された時の $LOADED_HIGH 変数と loadflag のポインタ値が比較される事で判定される。
この判定に失敗した場合、 type_of_loader 変数によってブートローダのチェックが行われる(type_of_loader 変数は、linux がブートローダを認識する為の識別子であり、ブートローダの識別子とブートローダのバージョンから成り立つ)。
利用しているブートローダが旧式のLILOであった場合、loader_panic_mess にある文字列を出力して、hlt 命令を実行する(ちなみに、エラーメッセージは'LI'ではない)。
これに通ると、いよいよブートパラメータの設定を行う。
まずは、拡張メモリ領域(*2)のサイズを表すパラメータ($0x1e0)をクリアした後、($0x1e8)をクリアしている。この領域には、e820map 構造体(include/asm-i386/e820.h) が格納される。このデータ構造は、メインメモリのマップを格納するもので、"セグメント"を最小単位として、そのベースアドレス、長さ そして タイプを規定した20バイトのデータを最大128個持つ。
そして、INT 0x15 (function 0xe820) を呼び出し、0x1e8 をバッファアドレスとして、e820map 構造体を作成する。
(*2):リアルモードで扱えるメモリ範囲を越えたメモリ領域。ここでは、1M-16M と16M以降の領域を併せて言っている。前者は、INT 0x15 (function 87) によってメモリ転送が可能である。
次に、拡張メモリ領域サイズのチェックを行う。INT 0x15 (function e801)によって 1-16M における拡張メモリサイズと 16M 以降の拡張メモリサイズを把握できる。16M 以降のメモリは、64Kを1ブロックとして換算されるので、最大で4GBまでのメモリサイズを認識できる。
サービスルーチンからの戻り値 %bx (16MB 以降の拡張アドレス領域のサイズ)をコピーした %ebx を6ビット左シフトしているのは、0x1e8 のカーネルパラメータに、1MB-16MB までの拡張メモリ領域のサイズと、16MB 以降のそれの和を格納する為である。
ここまでで、linux(まだカーネルは呼ばれていないので、正確にはlinuxのセットアップルーチン)はどのセグメントのメモリ領域が予約領域で、どれが利用可能なメモリ領域かを判別できるよになった。又、拡張メモリ領域のサイズを知ることができた。
もしかすると、自分が想像していた bootsect.S の処理は自分が思っていたものよりもシンプルかもしれない。何故ならば、圧縮カーネルイメージを読み込ませるには拡張メモリ領域を利用しなければならないはずだが、bootsect.S が呼び出す、start_of_setup において、そのサイズを調べているわけだから。
とすると、前回自分が書いたプログラムが bootsect.S の仕事そのものだったのだろう。
次回は、この続きになるだろう。先は長い。
- Category(s)
- 学習経過
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/ohyama/30fc30c830ed30fc30fc-305d306e3/tbping