2010年01月18日
QEMUメモ(3)
前の2回にひきつづきqemuのソースを追いかけたときのメモを置いておきます。
メモなのでわかりやすくはありませんが、もしかしたらどなたかの役に立つこともあるかもしれないので。
QEMU TCG
関数tb_gen_codeの内側
tb_gen_code (exec.c) cpu_gen_code (translate-all.c) gen_intermediate_code (target-arm/translate.c) tcg_gen_code (tcg/tcg.c)
ターゲットの命令コードから中間コードを生成するのがgen_intermediate_code()
中間コードからホストの命令コードを生成するのがtcg_gen_code()
この2段階の生成は必ず続けて行うようになっている。
中間コードはいつも同じ固定の配列(gen_opc_buf[])に生成されるので、次回に上書きされる。保存されない。
ホストの命令コードはcode_gen_buffer[]に格納される。このバッファのデフォルトサイズは32MB。(ram_size / 4 :ram_sizeのデフォルトが128MB)。
code_gen_buffer[]が一杯になったときには全部消す。(最近実行したコードは残すとかそういう判断は無い。)
これらのサイズはqemuのコマンドラインオプションで変更可能。 (-m, -tb-size)
関数gen_intermediate_codeの内側
target-arm/translate.c
gen_intermediate_code gen_intermediate_code_internal disas_asm_insn disas_thumb_insn
TCG中間コードの構造
オペコードとオペランドが別々の配列に格納される。
- オペコード
uint_16 gen_opc_buf[OPC_BUF_SIZE]; //OPC_BUF_SIZE = 512 uint_16 *gen_opc_ptr;
- オペランド
TCGARG gen_opparam_buff[OPPARAM_BUF_SIZE]; //OPC_OPPAERAM_BUF_SIZE = 512 * 10 TCGARG *gen_opparam_ptr;
オペコードは各命令につき一個。オペランドは可変個で最大は10個。
生成した命令の個数は (gen_opc_ptr - gen_opc_buf)で簡単に求められる。
このように二つに分割したことで命令列を後ろからたどっていくことが簡単にできる。
中間コードからホストの命令コードの生成
みるべきところは tcg/i386 (tcg/armではないので注意。)
liveness analysisによって冗長な命令は削除されないようになっている。
qemu_system_arm(SOFT_MMU)の場合は論理アドレスから物理アドレスへの変換という通常ならMMUのハードウェアで行う処理のコードがインラインで埋め込まれる。