2010年01月06日
QEMUメモ(1)
少し前にqemuのソースを追いかけたときのメモを放出します。
TCG
qemuは高速に実行するためにインタプリタでなくJITのようにターゲットのCPU命令列をホストのCPU列に変換して実行する。 version 0.10の頃からこの部分が従来のトランスレータからTCG(Tiny Code Generator)と呼ばれるものに置き換えられた。
TCGの概要
ターゲットの命令コードからホストの命令コードに変換する時に一度中間コードを生成する。
つまり、変換は
- ターゲットの命令コード -> 中間コード
- 中間コード -> ホストの命令コード
の2段階になる。
(原理的にはその間に中間コード->中間コードの最適化のパスを追加することが可能。)
このように中間コードを介すことで、サポートするターゲットCPUを追加する時にはそのターゲットの命令コードから中間コードを生成する部分を追加すればよい。
qemuの最新のソースアーカイブでは以下のものが、ターゲット、ホストのコードが存在する。(完成度については不明)
- target: alpha, arm, cris, i386, m68k, microblaze, mips, ppc, sh4, sparc
- host: arm, hppa, i386, ppc, ppc64, sparc, x86_64
ライセンス
QEMUは全体としてはGPL
libqemu.a はLGPL
多くのハードウェアデバイスエミュレーションのコードはBSDライセンスでリリースされている。
TCGが関連するところとしては
- ターゲットの命令コードを中間コードに変換する部分はLGPLv2
(ソースアーカイブの中のtarget-xxx のディレクトリ)
- 中間コードをホストの命令コードに変換して実行する部分はBSD likeライセンス
(ソースアーカイブの中のtcg以下のディレクトリ)
TCGの利点
従来のトランスレータと比較して、
- GCCのversionに依存しなくなった。従来のトランスレータはgcc3.xの生成するコードに依存していた。
- 中間コードのレベルでpeep hole optimizeがかけられるので若干の実行性能向上がある。
ソースコードの入手
gitリポジトリ
http://savannah.nongnu.org/git/?group=qemu
Ubuntu9.04 desktop x86_64の上で問題なくビルドできる。
libqemu.a
armでlibqemu.aには以下のファイルが含まれる。
ar rcs libqemu.a exec.o translate-all.o cpu-exec.o translate.o host-utils.o tcg/tcg.o tcg/tcg-runtime.o fpu/softfloat.o op_helper.o helper.o neon_helper.o iwmmxt_helper.o disas.o arm-dis.o i386-dis.o
その他
現時点でのTCGではFPU命令を直接はサポートしていない。FPU命令はターゲットの命令コードから中間コードに変換する段階でヘルパー関数を呼び出すようなコードに変換されるらしい。
AndroidのSDKのシミュレータはqemuの0.8.2(古いトランスレータ)を使っていた。そのためソースディストリビューションにはprebuildされたgcc3がついてきた。現在ではTCGを使うようにアップデートされている。ただしqemuのソースリポジトリの最新版には追いついていない。
libqemu.a 調査メモ
libqemu.a が提供するインタフェース (export)
qemu-system-armをビルドした時にわざとlibqemu.aをはずしてリンクエラーを起こさせ、そのときに報告されたundefined referenceをまとめてみた。以下の関数またはグローバル変数がlibqemu.aの外から使用されている。
arm_cpu_list cpsr_read cpsr_write cpu_abort cpu_arm_exec cpu_arm_init cpu_arm_set_cp_io cpu_breakpoint_insert cpu_breakpoint_remove cpu_breakpoint_remove_all cpu_dump_state cpu_exec_init_all cpu_exit cpu_get_physical_page_desc cpu_interrupt cpu_log_items cpu_memory_rw_debug cpu_physical_memory_map cpu_physical_memory_reset_dirty cpu_physical_memory_rw cpu_physical_memory_set_dirty_tracking cpu_physical_memory_unmap cpu_physical_memory_write_rom cpu_physical_sync_dirty_bitmap cpu_register_io_memory cpu_register_map_client cpu_register_physical_memory_offset cpu_reset cpu_reset_interrupt cpu_set_log cpu_set_log_filename cpu_single_env cpu_single_step cpu_str_to_log_mask cpu_unregister_io_memory cpu_watchpoint_insert cpu_watchpoint_remove cpu_watchpoint_remove_all dump_exec_info first_cpu last_ram_offset ldl_phys ldq_phys lduw_phys logfile monitor_disas phys_ram_dirty qemu_cpu_has_work qemu_get_ram_ptr qemu_icount qemu_ram_alloc qemu_register_coalesced_mmio qemu_unregister_coalesced_mmio stl_phys stl_phys_notdirty stw_phys syminfos tb_flush use_icount
libqemu.a が利用しているインタフェース (import)
libqemu.aとダミーのmainだけでリンクしたときに報告されたundefined reference をまとめてみた。libqemu.aを使うときには以下の参照(関数かグローバル変数かはこれだけではわからない)を用意する必要がある。
armv7m_nvic_acknowledge_irq armv7m_nvic_complete_irq armv7m_nvic_set_pending cpu_load cpu_save do_arm_semihosting gdb_register_coprocessor monitor_printf monitor_vprintf pstrcpy qemu_cpu_kick qemu_cpu_self qemu_free qemu_init_vcpu qemu_malloc qemu_mallocz qemu_memalign qemu_realloc qemu_vmalloc ram_size register_savevm semihosting_enabled singlestep vmstate_info_uint32 vmstate_register