Startup(arch/i386/stand/boot/srt0.S)

biosbootからロードされたboot loaderプログラムは、最初にsrt0.S内にあるstartupルーチンが走り、boot loaderプログラムが動作するための初期化処理を行ないます。そして初期化終了後、startup ルーチン内からboot関数が呼ばれます。

arch/i386/stand/boot/srt0.S

Boot Magic NO.のチェック

biosbootがスタックに格納した、BOOTMAGICの値が正しいかチェックします。BOOTMAGICはMakeから渡される定数であり、sys/arch/i386/stand/Makefile.incに0xc001d00dと定義されています。しかし、BOOTMAGICの値が正しくなくても特にエラーにしたりはしていないようです。

起動ドライブ番号をレジスタにストア

stackに格納されている、起動ドライブ番号をedx レジスタにストアします。

割込み禁止に設定

セグメントの設定とリアルモードに移行処理を行うので割込み禁止にします。この後、boot関数をcallするまで割込み禁止になります。

プロテクトモード移行処理

プロテクトモード用のセグメントの設定

Gdtrの内容を、GDTR(Global Descriptor Table Register)にセットします。これにより、gdtにあるSegment Descriptor Tableが有効になり、これ以降プロテクトモード用のセグメントが扱えるようになります。

設定後は各セグメントはSelectorと呼ばれる値でアクセスすることになり、各セレクタ値のアクセス範囲・アクセス属性は下記のようになります。

GDTR設定後のセグメントアクセス範囲
GDTR設定後のセグメントアクセス範囲
プロテクトモードに移行

cr0 レジスタのPE bitを1にしてプロテクトモードに移行します。

パイプラインのクリア

jumpを実行し、パイプラインのクリアとCode Segment(CS) Registerをプロテクトモード用の値に再設定を行います。jump後Code Segment(CS) Registerはセレクタ値32bit code(0x8)で動作するようになります。

レジスタの設定

セグメント レジスタの設定

CS以外のセグメントレジスタを32bit data(0x10)に設定します。

スタックの設定

sp レジスタをBOOTSTACKに設定します。Stackは0xfffcになります。

設定後のレジスタ

設定後、各レジスタの設定値は下記のようになります。

Registerの設定値
Registerの設定値

起動ドライブ番号をセーブ

起動ドライブ番号をStackに格納し、起動ドライブ番号をbios_bootdevに格納します。

pmm_initをcall

pmm_initをcallして割込みの設定をします。

bss領域をゼロクリア

読込んだbootプログラムはELF形式であり、幾つかのセッションに分かれている。この中の未初期化データセッションである、bss領域をゼロクリアする。

elfは幾つかのセッションに分かれている。と言いましたが、これらのセッション情報はelf Headerに書かれています。elf Headerの情報は、objdump コマンドの"-h"オプションを使うことによって、可読可能な形式で見ることが出来きます。

例えば、bootのelf Header情報を表示させるには、objdumpを使えば必要な情報を見ることができます。

# objdump -h /usr/src/sys/arch/i386/stand/boot/obj/boot
	
readelf コマンドを使用すれば、さらに詳しい情報も見る事もできます。
# readelf -a /usr/src/sys/arch/i386/stand/boot/obj/boot
	

objdump コマンドを使用して、bootのマッピングを表示すると、下記のようになります。

boot:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000858f  00040120  00040120  00000120  2**4
                  CONTENTS, ALLOC, LOAD, CODE
  1 .rodata       00001dae  000486c0  000486c0  000086c0  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00000110  0004a470  0004a470  0000a470  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .bss          000011c8  0004a580  0004a580  0000a580  2**5
                  ALLOC

これを視覚化すると下記のようになります。

bootプログラムのデータマップ
bootプログラムのデータマップ

図を見ると分かるようにbbsの最初のアドレスには_edata、最後のアドレスには_endと言うラベルが定義されています(これらのラベルは、objdump -x bootで見ることが出来る)。bbsをクリアするには( _end - _edata )でオフセットを求め、_edataからオフセット分クリアすれば出来ますね。

boot関数に移行

boot関数をcallする。

_rtt関数

本来、boot関数からkernelに移行してしまうので、_rtt関数が呼ばれることは無い。( と思う ;-) )

Last modified: Tue Jan 22 17:55:49 2008 JST