GRUBカーネル突入
ソースコード
ここを参照しながら読んでみてください。
ソースコード
GRUBカーネル
前回の続きです。
start: #ifdef __APPLE__ LOCAL(start): #endif .code32 movl %ecx, (LOCAL(real_to_prot_addr) - _start) (%esi) movl %edi, (LOCAL(prot_to_real_addr) - _start) (%esi) movl %eax, (EXT_C(grub_realidt) - _start) (%esi) #ifdef __APPLE__ movl $EXT_C(_edata), %ecx subl $LOCAL(start), %ecx #else movl $(_edata - _start), %ecx #endif movl $(_start), %edi rep movsb movl $LOCAL (cont), %esi jmp *%esi LOCAL(cont): #if 0 /* copy modules before cleaning out the bss */ movl EXT_C(grub_total_module_size), %ecx movl EXT_C(grub_kernel_image_size), %esi addl %ecx, %esi addl $_start, %esi decl %esi movl $END_SYMBOL, %edi addl %ecx, %edi decl %edi std rep movsb #endif #ifdef __APPLE__ /* clean out the bss */ movl $EXT_C(_edata), %edi /* compute the bss length */ movl $GRUB_MEMORY_MACHINE_SCRATCH_ADDR, %ecx #else /* clean out the bss */ movl $BSS_START_SYMBOL, %edi /* compute the bss length */ movl $END_SYMBOL, %ecx #endif subl %edi, %ecx /* clean out */ xorl %eax, %eax cld rep stosb movl %edx, EXT_C(grub_boot_device) /* * Call the start of main body of C code. */ call EXT_C(grub_main)
GRUBカーネルスタート
esiには展開先のアドレスが保存されています。
ecxに入れておいたreal_to_protのアドレスの値ををreal_to_prot_addrへ、prot_to_realをprot_to_real_addrへ保存します。
real_to_prot_addrのラベルの通り、メモリにreal_to_protサブルーチンのアドレスを保存しています。
プロテクトモードへ移行しても頻繁にリアルモードと切り替える必要があるの為こうしているのだと思われます。
同じようにrealidtにリアルモードのidtを格納。
これでリアルモードとプロテクトモードの行き来ができます。
prot_to_real_addrの構造
先へ進む前にprot_to_real_addrとprot_to_real_addrの構造を見てみます。
LOCAL(real_to_prot_addr): .long 0 LOCAL(prot_to_real_addr): .long 0 .macro PROT_TO_REAL movl LOCAL(prot_to_real_addr), %eax call *%eax .endm .macro REAL_TO_PROT movl LOCAL(real_to_prot_addr), %eax DATA32 call *%ax .endm
リアルモードとプロテクトモード用のそれぞれのラベルにはサブルーチンのアドレス用のlong長の大きさとマクロが用意されています。
処理の続きに戻ります。
movl $(_edata – _start), %ecx
はデータ領域の最後を示せすラベル_edataから_startを引いてコピーする大きさを決定します。
これはstartup.Sは0x100000に展開されていますが、実行するアドレスは0x09000にリンクされているためです。
つまりedataから_startの差の回数rep処理movsb命令を反復し0x100000に読み込まれた値を0x09000へ移し変えています。
0x09000へ移し変えてから移動します。
移動したcontへジャンプしてbss領域をクリアしていきます。
bss領域を更新する為にediにbss始まりのアドレスをecxに終わりのアドレスを格納し差を計算。
その回数分stosb命令でaxに格納した0でbssの開始アドレスから順にbssの終わりまで埋めていきます。
bssの準備が出来ました。
call EXT_C(grub_main)
でC言語で書かれたgrubのカーネルへ移動します。
bss領域
bssは初期化される時に0を含む変数の領域です。
.data領域との違いは簡単に言うと初期値があるかないか。
.data領域は初期値を設定しますが、.bssはサイズなのどの情報のみです。
コメント