天天看點

Something about Qemu

qemu運用動态翻譯的技術将guest binary instructions動态翻譯成host binary instructions,之後由host運作翻譯後的指令。在qemu-0.9之前的版本都采用dyngen的動态翻譯技術,而從qemu-0.10開始的版本開始采用tcg(tiny  code generator)的翻譯技術。

tbs ( translated blocks )

qemu将tb定義為碰到下一個jump指令或修改cpu state的指令之前的所有代碼稱為一個tb。

動态翻譯的基本思想就是把每一條target指令切分成為若幹條微指令,每條微指令由一段簡單的c代碼來實作,運作時通過一個動态代碼生成器把這些微指令組合成一個函數,最後執行這個函數,就相當于執行了一條target指令

從qemu-0.10.0開始,tcg成為qemu新的翻譯引擎.

tcg的全稱為“tiny code generator”, 主要負責分析、優化target代碼以及生成host代碼

target指令 ----> tcg ----> host指令

多數cpu指令不外乎以下幾大類:資料傳送、算術運算、邏輯運算、程式控制;

例如,資料傳送包括:傳送指令(如mov)、堆棧操作(push、pop)等

            程式控制包括:函數調用(call)、轉移指令(jmp)等;

基于此,tcg就把微指令按以上幾大類定義(見tcg/i386/tcg-target.c)

tcg在生成目标指令的過程中是采用寫死的,是以,要讓tcg運作在不同的host平台上,就必須為不同的平台編寫微操作函數.

qemu維護着一個稱為 cpustate 的資料結構,這個結構包括了target機cpu的所有寄存器,像eax,ebp,esp,cs,eip,eflags等。它總是代表着target機的目前狀态

用變量env來表示 cpustate 結構,則qemu每次解析target指令時,總是以 env.cs+env.eip 為開始位址的。 

eg: typedef struct cpux86state {...} in target-i386/cpu.h

tcg翻譯流程

guest binary instructions -> tcg ir(intermediate representation) -> host binary instructions 

tcg ir大緻可以分為以下幾類:

- mov類操作: mov, movi, ...

- 邏輯操作: and, or, xor, shl, shr, ...

- 算術操作: add, sub, mul, div, ...

- 分支跳轉操作: jmp, br, brcond

- 函數調用: call - 記憶體操作: ld, st

- qemu的特殊操作: tb_exit, goto_tb, qemu_ld/qemu_st

每條tcg指令的具體用法,參見qemu源碼tcg/readme。

在qemu源碼中,target-arch/* 定義了如何将guest binary instructions 反彙編成 tcg ir,tcg/arch 定義了如何將 tcg ir 翻譯成 host binary instructions。

starting from qemu 1.0, all emulated cpus run in a single thread.

qemu的main函數定義在/vl.c中,它也是執行的起點,這個函數的功能主要是建立一個虛拟的硬體環境.

所有的硬體裝置都在/hw/ 目錄下面,所有的裝置都有獨自的檔案,包括總線,序列槽,網卡,滑鼠等等。它們通過裝置子產品串在一起,在vl.c中的machine _init中初始化。

/target-arch/目錄就對應了相應架構(guest)的代碼,如/target-i386/就對應了x86系列的代碼部分。雖然不同架構做法不同,但是都是為了實作将對應客戶機cpu架構的tbs轉化成tcg的中間代碼。這個就是tcg的前半部分.

使用tcg代碼生成主機的代碼在/tcg/裡面,在這個目錄裡面也對應了不同的架構(host),分别在不同的子目錄裡面,如i386就在/tcg/i386中。整個生成主機代碼的過程也可以稱為tcg的後半部分。

/vl.c                                   最主要的模拟循環,虛拟機機器環境初始化,和cpu的執行。

/target-arch/translate.c   将客戶機代碼轉化成不同架構的tcg操作碼。

/tcg/tcg.c                           主要的tcg代碼。

/tcg/arch/tcg-target.c       将tcg代碼轉化生成主機代碼

/cpu-exec.c                      其中的cpu-exec()函數主要尋找下一個tb(翻譯代碼塊),如果沒找到就請求得到下一個tb,并且操作生成的代碼塊。

在qemu中,從代碼cache到靜态代碼再回到代碼cache,這個過程比較耗時,是以在qemu中涉及了一個tb鍊将所有tb連在一起,可以讓一個tb執行完以後直接跳到下一個tb,而不用每次都傳回到靜态代碼部分。

cpu_exex() --> prologue --> tb1 --> ... --> tbn --> epilogue --> cpu_exex()