grubの探検
asm.S
asm.Sの先頭からstage2の実行は始まる。
但し、このファイル全体が初期化シーケンスという事ではなくて、BIOSアクセスなど一連のローレベルなコードが大体ここに入っている。
ENTRY(main)
codestartへlong jump。
割り込みフラグをクリア、各セグメントレジスタに0を代入。
スタックアドレスを設定してreal_to_prot()を呼び出しプロテクトモードへ移行、最後にinit_bios_info()を呼び出す。
#疑問 帰ってこないの?
ENTRY(real_to_prot)
割り込みフラグをクリア、GDTRをロード。
cr0レジスタのprotection enableフラグに1をたてる。
CPUのプリフェッチキューをフラッシュしてCSレジスタをセットする為、プロテクトモードコードセグメントのprotcseg()へlong jumpする。
ここから32ビットコード:
DS, ES, FS, GS, SSレジスタにプロテクトモードデータセグメントのセレクタをロードする。
リターンアドレスをリアルモードのスタックにプッシュしておく。
プロテクトモードスタックのアドレスをセットする。
リターンアドレスをプロテクトモードのスタックにプッシュしておく。
#なんかやたらとリターンアドレスをプッシュするのは何事ですか?
#GDTだけ設定されてれば実はそれで良いわけ?486の本ではもっと色々やれとか書いてあるけど。
#リアルモードのスタックアドレス、どこで保存した?
ENTRY(prot_to_real)
GDTRをロード。
プロテクトモードのスタックアドレスを保存。
リターンアドレスをスタックから取得。
リアルモードのスタックを設定。
疑似リアルモードデータセグメントをDS, ES, FS, GS, SSに設定。
疑似リアルモードコードセグメントのtmpcseg()にlong jump。
ここから16ビットコード:
cr0レジスタのprotection enableフラグをクリア。
セグメントアドレス0のrealcsegにlong jump。
ds, es, fs, gs, ssレジスタを0クリア。
割り込み状態をリストア。
gdt
nullセグメント、プロテクトモードコードセグメント、プロテクトモードデータセグメント、リアルモードコードセグメント、リアルモードデータセグメ
ントをそれぞれ定義している。
単に0-4GBの全領域をセグメントに割り当てているだけ。
細かいパラメータはめんどいので誰か解析してください。
.word 0, 0 .byte 0, 0, 0, 0 /* code segment */ .word 0xFFFF, 0 .byte 0, 0x9A, 0xCF, 0 /* data segment */ .word 0xFFFF, 0 .byte 0, 0x92, 0xCF, 0 /* 16 bit real mode CS */ .word 0xFFFF, 0 .byte 0, 0x9E, 0, 0 /* 16 bit real mode DS */ .word 0xFFFF, 0 .byte 0, 0x92, 0, 0
gdtdesc
GDTR。 lgdtではこの変数を渡す。
/* this is the GDT descriptor */ gdtdesc: .word 0x27 /* limit */ .long gdt /* addr */