2010年01月14日
QEMUメモ(2)
cpu_exec.c
大雑把に書くとこんな感じ。
(instruction counter に関してはよくわからなかったのでここでは省略。)
cpu_exec() { for(;;) { if (setjmp(env->jmp_env) == 0) { exceptionの処理など(2) ループを抜ける要求があればbreak; for (;;) { exceptionの処理など(1) ARMの場合はFIQの処理。 //PCに対応する変換済みのコードを探す。なければ変換する。 tb = tb_find_fast(); //変換済みのコードを実行する next_tb = tcg_qemu_tb_exec(tb->tc_ptr); } } else { longjmpするとここを経由してループの先頭へ。 } } }
tbの表すコードの断片は基本的に(コンパイラ用語での)basic block。
厳密には、分岐命令までか仮想メモリのページの境界まで。
swi(ソフトウェア割り込み), wfi(割り込み待ち)も分岐命令として扱われるが、条件付き実行命令はここでは分岐命令としては扱われない。
tcg_qemu_tb_exec ではレジスタの退避してから変換されたコードに飛ぶ。戻ってきたときにレジスタの復帰を行う。
この中で例外を検出したときにはlongjmpすれば、例外処理を行うところまで行くことができる。
JITのコード変換の部分は命令キャッシュだと考えると理解しやすい。キャッシュにヒットすればそれを実行し、ミスした場合はキャッシュフィルを行う。
本物のCPUではキャッシュフィルはデータの転送だが、qemuの場合はキャッシュフィルの段階で命令の変換が行われると考える。
cpu_exec までのコールスタック
main (vl.c) main_loop (vl.c) tcg_cpu_exec (vl.c) qemu_cpu_exec (vl.c) cpu_exec (cpu_exec.c)
tcg_cpu_exec の中でマルチコアをシミュレートするループがある。各コアで時間を区切ってTSSのように実行される。マルチスレッドにはなっていない。
tb_find_fastの内側
exec.c
tb_find_fast (cpu-exec.c) tb_find_slow (cpu-exec.c) not_found: tb = tb_gen_code( ... ); (exec.c)
変換済みのtb (TranslationBlock) を探すためにまずハッシュテーブルを探し、次に物理アドレスのマップから探す。それでも無ければtb_gen_code が呼ばれてコード変換を行う。
次回QEMUメモ(3)ではTCGの深いところを追いかけてみる。
トラックバックURL
トラックバック一覧
1. クロス開発でのQEMU まとめ(基礎編) [ KMC Staff Blog ] 2010年09月16日 11:08
ここまでのQEMUの記事のリンク集です。
なお、CELFテクニカルジャンボリーにて、時間をいただきましたので、このあたりについて話をさせていただきます。
(3月5日 中野サンプラザ 入場無料) よろしければご参加ください。