***本記事にはプロモーションが含まれています。***
QEMUには、main_loop_waitと、cpu_execという2つの大きなループがある。cpu_execは、main_loop_waitから呼ばれる。
cpu_execは、CPUの動作をエミュレートしている。その中では、ゲストのコードをトランスレートしてホストのコードに変換して実行している。TranslatonBlockというのが、その実行の単位。
main_loop_waitは、周辺機器も含めたPC全体の動作をエミュレートする。CPUも機器の1つだからcpu_execが含まれる。
PITが動作するには、その両方が動作することが必要。
CPUは、env->interrupt_requestにCPU_INTERRUPT_HARDが入っていることでCPUとしての割り込みを実行する。つまり、IDTに登録された割り込みハンドラを実行する。
QEMUを、-d in_asm つきで実行したときにできる、c:tmpqemu.logというログファイルの
Servicing hardware INT=0x20
というのがそれにあたる。
トランスレートされたコードは、再利用されるので、ログファイルには、アセンブラは2度目からは記録されていない。でも、実行されている。
では、周辺機器の割り込みのエミュレートと、CPUの動作がどうつながるのか。
もう1つの疑問は、host_alarm_handlerがホストのSIGALRM、Windowsの場合はマルチメディアタイマから呼ばれて実行されるけど、これは割り込みとどう関係しているのか。
host_alarm_handlerでは、CPU_INTERRUPT_EXITが設定されて、cpu_execのループを抜けることになる。
PITのエミュレートでは、初期設定を除くと、pit_irq_timer_updateは、main_loop_waitのqemu_run_timersからしか呼ばれない。
gdbで動かしつながら、というのはこの辺までだったので、host_alarm_handlerやmain_loop_waitで情報を書き出しながらみる。
timeout=10で10ms Sleepしているときでも、host_alarm_handlerは、1msごとに呼ばれています。PITを1msに設定したとき、qemu_timer_expiredに引っかかって割り込みが入ってもいいのに入らないことに気づく。
それで、SleepをWaitForMultipleObjectsにして、イベントでmain_loop_waitが起きるようにしてみると、割り込みがうまく動くようになるのを確認できました。
やれやれ。