タイマー/時計のパッチとバイナリ

タイマー/時計のパッチとバイナリを作りました。
http://www.h7.dion.ne.jp/~qemu-win/download/qemu-20060330-timer.patch
http://www.h6.dion.ne.jp/~kazuw/qemu-win/qemu-20060330-timer.zip
1ms間隔の割り込みをサポートします。
Kqemu/Qvm86を使ったときでも、時間が正確です。
時計の遅れは、main_loop_waitがSleepしているとき、割り込みの時間切れになっても、タイマー割り込みが起こらないことが原因でした。イベントオブジェクトを使って解決しています。
QEMUの時間測定は、RDTSCを使っていたのですが、見ているとどうも時間が安定していないです。ticks_per_secの時間測定は、_ftimeを使っていたんですけど、精度がよくないので、QueryPerformanceCounter/QueryPerformanceFrequencyを使う方法に変えてみました。すると、びっくりするくらい時計が安定しました。
もしかすると、SMP(HTもしくはマルチコア)のシステムでも、使えるかもしれません。未確認ですけど。
これで、ベンチマークソフトが使えます。今まで、時計が不安定で使えなかったので。
これでうれしい人が多いかもね。とりあえず、できてよかった。
追記:
Windowsホストだけです。Win2k/XPゲストのタスクバーの時計をダブルクリックしてはいけません。画面がフリーズして終了できなくなってしまいます。

PITと割り込み

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が起きるようにしてみると、割り込みがうまく動くようになるのを確認できました。
やれやれ。

QEMUのPIT

とりあえず調べてみる。
PITのモードは、2。gdbで、pit_ioport_writeにブレークポイントを仕掛けると、6回止まる。最初の3回は、BIOSが初期設定をしている。後の3回はhariboteがio_out8したもの。
PITの設定が終わると、pit_irq_timerが定期的に実行されるようになります。
関係ないけど、MS-DOSは、55msのタイマ割り込みを設定しているそうですね。
pit_get_next_transition_timeという関数は、irqが次に変化する時間を計算している。
PITの設定は、その時間をs->next_transition_timeに設定し、qemu_mod_timerで、expire_timeを設定している。
時間がたつと関数が実行されるメカニズムは、時間のタイムアウトを設定しておくと、vl.cのmain_loop_waitのなかで、qemu_run_timersを呼んで、時間切れがあったら、ts->cb(ts->opaque)というコールバック関数を呼んでいること。このts->cbにpit_irq_timerが登録されていて、実行される。
もう1つ、CPUの実行中に割り込みが起こるというのは、cpu-exec.cのcpu-exec関数のループの中で、env->interrupt_requestを調べる。CPU_INTERRUPT_HARDが設定されていると、cpu_get_pic_interruptでどの割り込み番号が設定されているかを調べる。do_interrupt(intno, 0, 0, 0, 1)で次に実行するenv->eipを設定したりして、ゲストOSがIDTに登録した関数が実行されるようにする。
QEMU内部での、プログラムとしての時間切れの処理と、ゲストOS内でやってほしいことの2つあるということか。
main_loop_waitで、pit_irq_timerを呼んでいるので、ゲストOSがHLTで止まると、Sleepしてしまい、PITも止まってしまうことになるのかな。
もう1つ、host_alarm_handlerがホストの時間に従って、割り込みを入れているようなんだけど、これって、どういう役割になるんだろうか。
あまりよくわかってなくて書いているので、間違っているかも。

OS自作入門12日目

問題のタイマのお話。ちょっと、QEMUの内部まで見てみようと思う。
PCには、PIT(Programmable Interval Timer)とRTC(Real Time Clock)というタイマに関するものが2つあって、それぞれirq 0とirq 8につながれている。
RTCには、日時の情報とかがあるみたいです。
Hariboteのクロックを実際の時間と比べると、少し遅い。1分で4秒くらい遅くなります。なぜ?
PITを1msで割り込みを発生しようと、count=1193=0x04a9を入れてみると、タイマは少し速くなりますけど、1.6倍くらいにしかなりません。QEMUのタイマには限界があるのかな。
WinXPホストのクロックを起動したりすると、hariboteのクロックが一瞬停止したりするのが見れる。Kqemu/Qvm86を使ったときにフリーズしてしまうのはこんなのが関係しているのだろうか。
WinNTは、RTCを見て時計の較正をしているそうです。Win2k/XPも同じなんだろうか。どんな較正なのかわからないですけどね。
Windows上のQEMUではtimeSetEventというマルチメディアタイマを使っていますけど、1msを刻むことはどうやってやっているのでしょう。
なんか、疑問ばかり。

Accelerated-KNOPPIX

試してみた。
ずいぶん速くなっています。素のKnoppixでは、QEMUで起動する気にならないくらい遅かったのですが、こんな感じでした。
QEMU-0.8.0/kqemu-0.7.2
qemu -L ./pc-bios -cdrom accel.img -m 256
で起動。
knoppix desktop=icewm のとき、1min 45sec
knoppix desktop=twm のとき、 1min 40sec
knoppix desktop=kde のとき、 2min 50sec
KDEでは、遅いなと思うけど、icewmなら何とかという感じ。-m 256 がないとスワップしてつらいと思います。
キーを押し続けてもリピートがうまくいかないみたいですけど。
ちなみに、Morphixは、1minで立ち上がるのでまだまだですけどね。

OS自作入門7日目&8日目

FIFOは、読み書きの位置のほかに長さの情報を持っているというのがポイントになるかな。
もし、位置を変えることと、長さを変えることの間で割り込みが入ると、長さが0でも読み書きの位置が違うという変なことになるけど、そのへん割り込みの禁止をうまく使っているなと思った。
OSの起動のところは、3日目に調べたのでそれでいいかな。

OS自作入門5日目&6日目

この開発環境って、関数名を間違えるとWarningがでるだけで、エラーにならない。バイナリができてしまうので、走らせて見ると、突然OSが暴走し始めてなかなかバグが見つからないということがあった。
Makefileの一般規則で書いた場合、生成された中間ファイル.nasとか.gasが削除されるみたいです。こういうものなんでしょうか。
割り込みが動き出すと、システムが動いてるっていう気がする。割り込みの動作をイメージするのは難しいと思う。以前、デバッガを動かしていたときにステップ実行で次の行に行こうとすると、突然見知らぬコードが実行されてなかなか次の行に行けなかったことがあります。後で気づいたら、タイマの割り込みハンドラが実行されていたのでした。それで、割り込みってこういうものなんだと納得したことがあります。

シリアルの名前つきパイプとファイル出力

シリアルのパッチとバイナリを作りました。
http://www.h6.dion.ne.jp/~kazuw/qemu-win/qemu-20060320-serial.zip
http://www.h7.dion.ne.jp/~qemu-win/download/qemu-20060320-serial-3.patch
サポートすオプションは、
-serial pipe:com_1
-serial file:test.txt
です。pipe:とfile:は小文字を使ってください。-serialオプションは、1つだけサポートします。-serial pipe:オプションで、windbgと接続できます。
詳しくはこちらに書くつもり。
http://www.h7.dion.ne.jp/~qemu-win/DebuggingTips-ja.html#windbg
書いた。