2009年6月17日水曜日

header.S

今日はブート時のエントリポイントが記述されている「arch/x86/boot/header.S」を見てみましょう。

その前に、前回見たリンカスクリプトのセクション定義の一部を抜粋。

. = 0;
.bstext : { *(.bstext) }
.bsdata : { *(.bsdata) }
. = 497;
.header : { *(.header) }
.inittext : { *(.inittext) }
.initdata : { *(.initdata) }
.text : { *(.text*) }


「header.S」を見てみると先頭に「.bstext」と「.bsdata」というセクションで記述されているのが分かります。これらはフロッピーからブートした場合に走る処理で推奨しない旨のメッセージを表示しています。

その次に「.header」セクションがあります。
この中にリンカスクリプトでエントリポイントとして指定のあった「_start」があります。
start_of_setupというアドレスまでいっきにジャンプしてしまいます。
この飛び越えてしまう間には後々に参照するための各種シンボルが定義されています。
では飛んだ先である「start_of_setup」から見てみましょう。
ここは「.inittext」セクションであるため、「.header」セクションの直後に位置することがリンカスクリプトから分かります。

#「.inittext」セクションに配置
.section ".inittext", "ax"
start_of_setup:

#「SAFE_RESET_DISK_CONTROLLER」が定義されていたらディスクコントローラをリセット
#ifdef SAFE_RESET_DISK_CONTROLLER
# Reset the disk controller.
movw $0x0000, %ax # Reset disk controller
movb $0x80, %dl # All disks
int $0x13
#endif

# Force %es = %ds
movw %ds, %ax #dsの値を
movw %ax, %es #esにコピー
cld #ディレクションフラグをクリア

# 過去のコードではssレジスタとdsレジストの値が一致しない状態でLILOからカーネルに
# 移譲されたときに問題が起きていました。
# ssレジスタの値が不正のときはスタックポインタを再計算します。
# そうでないときは放っておきます。
# Apparently some ancient versions of LILO invoked the kernel with %ss != %ds,
# which happened to work by accident for the old code. Recalculate the stack
# pointer if %ss is invalid. Otherwise leave it alone, LOADLIN sets up the
# stack behind its own code, so we can't blindly put it directly past the heap.

movw %ss, %dx
cmpw %ax, %dx # %ds == %ss?
movw %sp, %dx
je 2f # -> assume %sp is reasonably set

# ここに来たらssレジスタが不正
# Invalid %ss, make up a new stack
movw $_end, %dx
testb $CAN_USE_HEAP, loadflags
jz 1f
movw heap_end_ptr, %dx
1: addw $STACK_SIZE, %dx
jnc 2f
xorw %dx, %dx # Prevent wraparound

# dxがスタック領域の末尾を指すようにする
2: # Now %dx should point to the end of our stack space
andw $~3, %dx # dword align (might as well...)
jnz 3f
movw $0xfffc, %dx # Make sure we're not zero
3: movw %ax, %ss
movzwl %dx, %esp # Clear upper half of %esp
sti # Now we should have a working stack

# We will have entered with %cs = %ds+0x20, normalize %cs so
# it is on par with the other segments.
# スタックに「6f」を積んでからリターン(lretw)しているので直後の「6:」の
# ラベル位置にジャンプする。なぜこうする必要があるのだろう??
pushw %ds
pushw $6f
lretw
6:

# 「setup_sig」はリンカスクリプトにて
# .signature : {
# setup_sig = .;
# LONG(0x5a5aaa55)
#}
# と、定義されています
# Check signature at end of setup
cmpl $0x5a5aaa55, setup_sig
jne setup_bad

# 「__bss_start」もリンカスクリプトにて定義
# stosl命令はEAXの値をDIに書き込む
# 下記のコードはbss領域を0クリアしている
# Zero the bss
movw $__bss_start, %di
movw $_end+3, %cx
xorl %eax, %eax
subw %di, %cx
shrw $2, %cx
rep; stosl

# C言語で記述している「main」関数を呼び出す
# Jump to C code (should not return)
calll main

# Setup corrupt somehow...
...以下、エラー処理なので省略...



と、ようやく「main」関数の呼び出しです。

0 件のコメント:

コメントを投稿