ブートローダー(その7)
以前に学習した内容を活用し、作りかけのブートローダ (現段階では、ブートローダというよりも、単なる 16bit プログラムとも言えなくもない) に手を加える。
ソースはこちら
http://dev.ariel-networks.com/Members/ohyama/stuff/boot_0331-tar.gz/download
主要な処理は全て second.S の GAS で書かれた部分で行われ、C で書かれたファイルはデバッグ処理 (画面への文字出力等) のみを行っている。
ブートしてからフロッピーの初期化をし、セカンドステージの読み出しとロードを行う処理については以前に書いたので、今回はその続きの処理から話をする。
second.S での処理を大まかに書くと以下の処理を順に行っている。
・拡張メモリサイズの取得と記録
・キーボードのリピート値とディレイ値の設定
・PS/2、APM のチェック
・A20 アドレスラインのチェックと設定
これらの設定内容は、Linux のブートシーケンスで処理されている事を模しただけで目新しい事は何もない(単に、自分でそれを作って、動かしただけにすぎない)。
これに、VRAM による文字出力と、割り込みベクタテーブルの機能を追加した。
VRAM は、0xB8000 から始まる予約領域で、各 2 バイトが、画面の 80*25 のマスに対応している。画面左上から直線的に配置されているメモリ領域の 2n (0 <= n <= 0x7D0) バイト目において、先頭バイトで文字(ascii コード)を表現し、次の 1 バイトで色を表現する。後方 1 バイトの色について、上位 4 bit は背景色を表し、下位 4 bit は文字色を表す(つまり色は、全 16 種)。各符号と色の対応は次のようになっている。
0x0 : 黒
0x1 : 青
0x2 : 暗い緑
0x3 : 水色
0x4 : 赤
0x5 : 紫
0x6 : 茶
0x7 : 灰
0x8 : ダークグレー
0x9 : 群青
0xa : 明るい緑
0xb : 明るい青
0xc : 朱
0xd : ピンク
0xe : 黄
0xf : 白
次は、割り込み処理についてである。
リアルモードでは割り込みベクタテーブルを作成し、そこに割り込みルーチンのアドレスを登録する。その前に、PIC の初期化を行う。
PIC に関する初期化処理については、sodexOS のソースと sodex 開発者のブログ
http://d.hatena.ne.jp/sodex/20070424
を参考にさせてもらった。又、8259A 割り込みコントローラの説明では、
http://community.osdev.info/index.php?(PIC)8259A
のサイトにも有益な情報が書かれている。
作法に従って、IRQ のベースアドレスは、マスターを 0x20 に、スレーブを 0x28 に設定している。又、マスター PIC のマスク設定は 0xFE とし、タイマ割り込みのみ許可している。
次に、割り込みベクタテーブルの初期化を行う。割り込みベクタテーブルは、アドレス 0x00000 からはじまる 1024 バイトの予約領域で、各割り込みベクタに対して 4 バイトの情報を持っている。
0x0000 をベースアドレスとする 4n (0 <= n <= 255) バイト目において、上位 2 バイトでオフセットのベースアドレスを、下位 2 バイトで割り込みサービスルーチンのオフセットを設定する。
タイマ割り込みの PIC ゲートは、PIC 0 になるので、IRQ 20 がタイマ割り込みに該当する。なので、0x0000:0x0080 に割り込みベクタを登録する。
さて、次は割り込みサービスルーチンである。
割り込みコントローラが割り込み信号を取得した場合、EFLAGS の割り込みフラグ(IF) を確認し、クリアされていない場合マスクの確認を行う。リアルモードにおける割り込みチェックはこれだけ(のはず)である。
これらのチェックで割り込みが許可されている場合、割り込み信号が CPU に送られ、割り込みサービスルーチンに処理が移行する。その際、割り込みが発生する直前に実行していたアドレス(IP レジスタの値)とコードセグメントアドレスがスタックに積まれる。
自分の環境において、何もしないサービスルーチン (iret で帰るだけのもの) を割り込みベクタに登録し、割り込みを起こすとアボートする。ダンプを見てみると、IP が異常に大きな値を示す。又、スタックポインタの位置が呼び出し時のアドレスと比較して少しずれている。詳しく調べてみると、割り込み発生時に積まれる IP と CS のレジスタは 16 bit レジスタとしてスタックに積まれるのに対して、iret 命令で実行されているスタックからのデータ取り出しにおいては、各データを 32 bit として扱っている。
原因がよくわからないので、割り込みサービスルーチンにおいて、においてスタック内部を直に書き換え、スタックポインタをずらすという行為をとり、ISR (処理中の割り込み番号が格納されている、 割り込みコントローラのレジスタ) をクリアし、ret でサービスルーチンを抜けている。
iret を使わない一連のスタック操作の処理は、極めてバカバカしい処理だが、謎なスタック操作が割り込み処理内部(命令レベルで)で行われている原因が、現時点でよくわかっていない事による、"逃げ"の方法である。
しかし、16bit リアルモードにおいて割り込み機構を実装するメリットがあまり無いので、早々と諦め、割り込みディスクリプタテーブルを作成する事にする。
・おまけ
make を実行した時に生成される boot.bin がフロッピーディスクイメージである。
これをバーチャルマシン等で実行してみると、リアルモード中でタイマ割り込みが実行され続けている事がわかる。
- Category(s)
- 学習経過
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/ohyama/30fc30c830ed30fc30fc-305d306e7/tbping