[PR]当たる!無料占いで運命鑑定:プロの占い師による本格運命鑑定が無料で

仮想86モードの準備が整いましたので、 いよいよ32bitコードからのソフトウェア割り込みを作ることにします。
すでに16bitコードとして INT 29h を作ってありますので、 これが完成すれば文字出力 API の INT 29h を呼び出せるようになり、 今後の開発が便利になります。

ソフトウェア割り込みに伴うレジスタの受け渡し方法はいろいろありますが、 将来 DPMI を実装した場合のことを考え、 今回は DPMI のレジスタ構造体 DPMI_REGS を使うことにしました。
DPMI_REGSは次の構造体です。
フラグが16bitしかありませんが、仮想86の呼び出しで問題になることはないでしょう。

仮想86に切り替えて 16 bit の割り込み(INT XXh)を シミュレートするコードは次のとおりです。
割り込みの戻り先として、 予め 16 bit 側で HLT コードを準備しておき、 そのアドレス (g_thunk16ret_seg:g_thunk16ret_off)を push します。
call_vm86_interrupt() を呼び出す場合は、 予め 16bit 側で 32bit からのコールバック用スタックを 準備しておき、ss:sp に設定してください。
asm_call_vm86_handler() は下請けコードです。
現在のスタックの値を TSS の ESP0 に保存してから、 仮想86に切り替えるためのデータを push 後、 IRET しています。
アセンブラで書いていますので複雑なことをやっているように 見えますが、データのコピーしかしていません。
dpmi_vm86_push と dpmi_vm86_pop は push と pop をシミュレートするコードです。 これらは次のとおりです。
32bit コードで IRET を実行すると、 仮想86モードに切り替わります。 これにより 16bit の割り込みがシミュレートされ、 割り込み処理後は g_thunk16ret_seg:g_thunk16ret_off に制御が返されます。
戻り先には予め HLT 命令を準備してありますので、 #GP(0)が発生して CPU は 32bit モードに戻ります。
#GP(0) で飛ばされる先は、 asm_call_vm86_handler() の呼び出し元ではありません。 IDT に設定した例外ハンドラです。
そのため、例外ハンドラでは asm_call_vm86_handler() 内で保存した esp0 に スタックを戻したうえで、 先の関数に戻る必要があります。

これを実現するには、まず 仮想86モードへの切り替えで HLT 命令を説明した方法で 検出し、 CS:IP が g_thunk16ret_seg:g_thunk16ret_off であることを確認します。
次に、#GP(0)発生時に保存したレジスタを コピーし、スタックを戻します。

これを実現するための 関数 vm86_returntopm32() は次のとおりです。
この関数は gpfault_handler() から呼び出します。
vm86_returntopm32() は下請けに2つのアセンブラ関数を呼び出しています。
asm_get_vm86_callregs() は呼び出し元の P32_DPMI_REGS へのポインタを 取得する関数、asm_return_from_vm86_handler() はスタックを切り替える関数です。
DS、ESは #GP(0) の時点で設定していますので、復元する必要はありません。
また、asm_call_vm86_handler() は見かけ上関数呼び出しですので、 関数呼び出しで保存されない EAX、ECX、EDX レジスタも復元する必要はありません。
asm_return_from_vm86_handler() を実行すると C 言語の longjmp のように、 asm_call_vm86_handler() に戻せます。


2005-09-25: ページ作成 (最終更新)
Copyright (C) 2005 hoverkid, all rights reserved.
[PR]≪占い奇跡の恋愛術≫初回無料:幸せな結婚へ導きます。本格結婚鑑定