Linux勉強 パート11 GRUBコード GRUBカーネル2

Linux

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はサイズなのどの情報のみです。

プログラミングおすすめ書籍

おすすめ書籍

なぜプログラムが動くのか。
平易な言葉で学べますが、初心者には難しいかもしれません。
でも読み終わった頃にはなんとなく理解しているでしょう。
初心者には家にあって損はありません。

UNIXの思想を学べます。
高尚なタイトルですが、コードはおろか難しい言葉も殆どありません。取っ掛かりに最適でその後のプログラミングに対する理解を一変させます。
なぜならこの思想はプログラミングそのものだからです。
一読の価値ありで、これは良書なので今後紹介したいと思っています。

まだまだありますがまたの機会に紹介したいと思います。

Linux コンピューター
スポンサーリンク
himazinをフォローする
私の頭の上の消しゴム

コメント

タイトルとURLをコピーしました