GRUBコードを読む
ソースコード
前回まででBIOSはpostが終わるとハードディスクから512バイト(MBR)を読み込むと説明しました。
ところでLinuxのブートローダーはたくさんありますが今回はGRUBを勉強してみようと思います。
ここを参照しながら読んでみてください。
ソースコード
コードスタート
.code16 .globl _start, start; _start: start: jmp LOCAL(after_BPB)
.code16は16ビットコードでの実行するという意味。
_start:はここから命令がはじまるよというラベル。
jmpはLOCAL(after_BPB)というラベルで指定されるメモリアドレスの命令に実行を移す命令です。
jmpでとばした部分には命令ではなくデータを保存する領域が続きますので、99行目のLOCAL(after_BPB):まで処理を飛ばしています。
このようにアセンブラはプログラマーが任意の位置にデータや命令を配置できるので混在しています。
disk_address_packet:というデータ構造体は後々使うので今は飛ばします。
LOCAL(after_BPB): cli boot_drive_check: jmp 3f testb $0x80, %dl jz 2f 3: testb $0x70, %dl jz 1f 2: movb $0x80, %dl 1: ljmp $0, $real_start real_start: xorw %ax, %ax movw %ax, %ds movw %ax, %ss movw $GRUB_BOOT_MACHINE_STACK_SEG, %sp sti
jmp LOCAL(after_BPB)命令でLOCAL(after_BPB):のラベルへジャンプしてきました。
cliは割り込みを禁止する命令で、最後のstiで割り込みを許可します。
jmp 3fは/* grub-setup may overwrite this jump */とコメントにあるようにハードディスクに書き込む際に上書きされnop(何もしない)命令に置き換えられます。
testb $0x80, %dl
test命令は論理積をとりますが、結果は捨てられEFLAGSレジスタの内容だけを変更します。
論理積は積とあるように2進数のかけ算を行うので、同じ桁の数字が1と1の場合以外は0に変わります。
0x80は2進数に変換すると10000000で同じ10000000以外で論理積をとると全ての桁が0になります。
最上位の桁は桁上がりして丸められます。
なので0x80とdlレジスタの内容が一致しない場合はZF(ゼロフラグ 演算の結果が0の時だけ入力される)が立ちます。
次の命令で条件分岐します。
jz 2f
jzはゼロフラグが立っていた場合、つまりdlが0x80以外の場合
2:
movb $0x80, %dl
へジャンプしてdlに0x80(これはハードディスクから読み込んだという印)を書き込みます。
何が何でもハードディスクから読み込んだことにしています。
その後はreal_startへジャンプします。
xorw %ax, %axは論理和を取りaxの内容を全てゼロでクリアにしています。
論理和、つまり2進数の足し算です。
同じ桁の値が同じだった場合0になります。
なので全く同じ値で論理和をとると0でクリアされることになります。
その後はaxの値をds、ssレジスタに設定し、スタックセグメントを設定します。
movb boot_drive, %al cmpb $0xff, %al je 1f movb %al, %dl 1: pushw %dx MSG(notification_string) movw $disk_address_packet, %si movb $0x41, %ah movw $0x55aa, %bx int $0x13
boot_driveのメモリアドレスにはセットアッププログラムによって0xffが書き込まれます。
cmpbでalとの値を比較し、同じならje命令で1へジャンプ、違っていればalの値をdlに読み込みます。
pushw命令で先ほどdlに移した値をスタックに退避して、MSG(notification_string)でメッセージを出力。
siにdap(ディスクアドレスポケット)のアドレスをセット。後で使います。
disk_address_packetのアドレスをsiに格納、ahに0x41、bxに0x55aaを設定しBIOSのルーチンへアクセスします。
レジスタに規定の値を入力してint 0x13で割り込み命令を出すと、決められたアドレスの命令を実行してくれます。
この場合はドライブの読み込みで利用できる機能を問い合わせています。
利用可能な機能はドライブへのタイプによって異なる制約があります。
利用できる機能によって返ってくる値が変わってきます。
成功した場合は利用可能な機能の番号が帰ってきます。
コメント