Linux勉強 パート8 GRUBコード後半 real_to_protとprot_to_real

Linux

リアルモードからプロテクトモードへ

real_to_protのコード

ここを参照しながら読んでみてください。
GRUB後半コード
ソースコード

前回プロテクトモード用にセグメントレジスタにデータをロードしたところからの続き。

movl	(%esp), %eax
movl	%eax, GRUB_MEMORY_MACHINE_REAL_STACK
movl	protstack, %eax
movl	%eax, %esp
movl	%eax, %ebp
movl	GRUB_MEMORY_MACHINE_REAL_STACK, %eax
movl	%eax, (%esp)

xor eax,eax

sidt  LOCAL(realidt)  
lidt  protidt
ret

Real_to_protを呼び出したプログラムに戻るリターンアドレスを退避しておきます。
これをなくすと元に処理に復帰できなくなります。

bpとspを書き換えてプロテクトモード用のスタックを作ります。

対比しておいたリターンアドレスをプロテクトモード用のスタックにおきます。
これはret命令がスタックの一番上をリターンアドレスとして利用するためです。

これでスタックの切り替えが終わありました。

sidtは指定したアドレスにidtレジスタの値を保存します。
realidtには保存の為の領域を確保しています。
lidt命令は指定したアドレスからidtをロードする逆の命令です。
この処理によってリアルモードとプロテクトモードのidtの切り替えができました。
しかし
ret命令で元のアドレスに復帰します。

protid:
.word 0
.long 0

は大きさ0となっているのでプロテクトモードではidtは使用しません。
プロテクトモードで割り込みは行わないだけで、割り込み処理はリアルモードに切り替えて割り込み処理を行う。
スタックにprot_to_real、real_to_protのアドレスを積んでいるから使い必要に応じてジャンプしてリアルモードとプロテクトモードを切り替えられます。

prot_to_realのコード

次はprot_to_realを見てみます。
基本的にreal_to_protと逆の処理をするだけです。

prot_to_real:
lgdt	gdtdesc
sidt    protidt
lidt    LOCAL(realidt)
movl	%esp, %eax
movl	%eax, protstack
movl	(%esp), %eax
movl	%eax, GRUB_MEMORY_MACHINE_REAL_STACK
movl	$GRUB_MEMORY_MACHINE_REAL_STACK, %eax
movl	%eax, %esp
movl	%eax, %ebp

movw	$GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG, %ax
movw	%ax, %ds
movw	%ax, %es
movw	%ax, %fs
movw	%ax, %gs
movw	%ax, %ss
ljmp	$GRUB_MEMORY_MACHINE_PSEUDO_REAL_CSEG, $tmpcseg

lgdtでをgdtdescにgdtをレジスタに読み込み、sidtでprtoidtにidtを保存。
lidtでリアルモードのidtをメモリからレジスタにセットします。

eaxの内容をプロテクトモード用のスタックポインタをprotstackに保存。
このルーチンを抜けて帰還するリターンアドレスをGRUB_MEMORY_MACHINE_REAL_STACKへ退避しておきます。
リターンアドレスを退避したGRUB_MEMORY_MACHINE_REAL_STACKのアドレスをspとbpにセットしてスタックを作成。

セグメントをセットしてtmpcsegにジャンプ。

16ビットモード用に切り替えます。

tmpcseg:
.code16
movl	%cr0, %eax
andl 	$(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax
movl	%eax, %cr0
DATA32	ljmp	$0, $realcseg

realcseg:
xorl	%eax, %eax
movw	%ax, %ds
movw	%ax, %es
movw	%ax, %fs
movw	%ax, %gs
movw	%ax, %ss
sti
DATA32	ret

プロテクトモードから移ってきたので16ビットで動かすことをcpuに伝えます。
cr0レジスタの最下位に0をセットして16ビットへ移行します。

リアルモードからプロテクトモードへ移行する時にもプリフェッチキューをフラッシュして初期化しました。
逆の場合でもljmp命令を使いプリフェッチキューをクリアしcsレジスタに0をセットします。
これは決まり事です。

その後realcsegルーチンでコードセグメントやデータセグメントなどのセグメントレジスタを0でクリアしリアルモード用のセグメントを設定します。
その後プロテクトモードでは停止させていた割り込み機能をstiで復活させて、リアルモードからプロテクトモードへの移行を完了。
DATA32 ret命令でリアルモードを呼び出した処理へ復帰します。

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

おすすめ書籍

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

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

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

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

コメント

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