Qemeソース分析

7497 ワード

参考:http://lists.gnu.org/archive/html/qemu-devel/2011-04/pdfhC5rVdz7U8.pdf
 
1.QemeとBochsの違い:
1.Bochs
BochsとQemeはソフトウェアのシミュレーションを主とする仮想ソフトウェアですが、両者の違いは何ですか?
Bochsは、ターゲットプログラム(OSおよび実行中のアプリケーション)をソフトウェアでシミュレートしたものです。Bochsは自分の内部でCPU、メモリ、IO装置のデータ構造を維持しています。Bochsがコマンドをシミュレーションするたびに、このコマンドに従って実際のハードウェア上で実行する時に発生すべき効果は、これらのソフトウェアのハードウェアデータ構造を維持する上で相応の影響を与えます。
このような一つ一つの処理方法は、実際の運転時と全く同じ粒度を維持し、学習と調整に便利です。しかし、これは一対の多マッピング方式であり、すなわち一つの機構命令であり、N個の命令実行と解釈されるので、効率の低下は避けられない。
 
2.qeme
Qemeは他の粒度のシミュレーションを行っています。
qemuはターゲットプログラムから、現在実行したいコードの一部を切り取り(Translation Blockと呼ばれる)、このコードをまず中間言語に訳してから、中間言語をホストシステム関連のバイナリコードに訳します。
Translation Blockの粒径は単一の機構指令の粒度より大きいので、qemeはbatch処理命令のシミュレーション動作に相当するので、プログレッシブ処理のBochs性能よりも若干速くなります。
また、QemeはTranslation Blockのキャッシュを最適化し、複数の接続を実行するTranslation Blockをリンクして同じロットで処理する。この2つの方法は繰り返し実行されるコードセグメントのシミュレーション性能を大幅に向上させる。
 
3.まとめ
簡単に言えば、Bochsは学習に適しています。また、簡単な任務処理もできます。Bochsが持っている調合器もとても力があります。BochsでLinuxカーネルを調整するのはいい選択です。http://www.cnblogs.com/long123king/p/3559816.htmlなど)が、実際に大型のオペレーティングシステムをシミュレートするのにはBochsが適していません。
Qemuは処理方式に最適化があるので、Bochsのようにコマンドレベルの実行過程を“元の味”で表現することができないので、勉強にはあまり適していません。しかし、Qemeの性能向上により、カーネル仮想モジュールkvm、さらにはxenにも対応することができますので、Qemeは、主流の仮想デスクトップソフト(Virtual Box、Vmwareなど)のように、複数のオペレーティングシステムをスムーズに実行することができます。Linux上でWindowsを仮想化する必要があるなら、きっとqemeの方がいいと思います。
 
tb_find_fast:次のTB(Translation Block)を検索し、ホストコードを生成する。
tcg_qemutb_exec:生成されたホストコードを実行し、ホストコードは三つの部分から構成されています。
 
2.Qemeの処理フロー
qemuのシミュレーションのメインサイクルはcpu-exc.cにあります。cpu_exec関数で
for(;;)
{
......
tb = tb_find_fast(env);
......
next_tb = cpu_tb_exec(cpu, tc_ptr);
......
}
1.tb_find_fast:
Translation Blockを準備します。キャッシュに用意されているTranslation Blockがあれば、そのまま返します。そうでないとtb_を呼び出しますfind_slow関数は、新しいTBを作成します。
tb_find_fast
    |
tb_find_slow
    |
tb_gen_code
    |
cpu_gen_code
    |
gen_intermediate_code 【Guest Code --> tcg op(    )】
    |
tcg_gen_code【tcg op(    ) --> Host Code】
 
その中で、ゲンゲintermediate_codeはシステムに関連する関数で実現され、x 86の実装はtaget-i 386/translate.cにあり、内部でdisas_を呼び出します。insnプログレッシブコマンドで処理します。
 
そしてtcg_gen_コードはtcg_を呼び出すことができますgen_code_commonは、TBから中間コードを取り出し、ホストコードに変換する。
2.cpu_tb_exec:
生成されたTBを実行します。
cpu_tb_exec
    |
tcg_qemu_tb_exec
#define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr)
prologueとepilogueはcomplerがターゲットコードを生成する時、関数スタックフレームの保存と回復のコードに対して、私達は手当たり次第に例を挙げます。
objdump -d vl.o
下のコードの赤い部分はそれぞれ関数のprologueとepilogueです。
000000000000013a :
     13a:       55                      
     13b:       48 89 e5               
     13e:       53                      
     13f:       48 83 ec 28             
     143:       48 89 7d d8             mov    %rdi,-0x28(%rbp)
     147:       89 75 d4                mov    %esi,-0x2c(%rbp)
     14a:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
     151:       00 00 
     153:       48 89 45 e8             mov    %rax,-0x18(%rbp)
     157:       31 c0                   xor    %eax,%eax
     159:       8b 45 d4                mov    -0x2c(%rbp),%eax
     15c:       83 f8 40                cmp    $0x40,%eax
     15f:       77 42                   ja     1a3 
     161:       48 8b 45 d8             mov    -0x28(%rbp),%rax
     165:       48 8b 10                mov    (%rax),%rdx
     168:       8b 45 d4                mov    -0x2c(%rbp),%eax
     16b:       48 98                   cltq   
     16d:       83 e0 3f                and    $0x3f,%eax
     170:       48 85 c0                test   %rax,%rax
     173:       74 19                   je     18e 
     175:       8b 45 d4                mov    -0x2c(%rbp),%eax
     178:       83 e0 3f                and    $0x3f,%eax
     17b:       be 01 00 00 00          mov    $0x1,%esi
     180:       89 c1                   mov    %eax,%ecx
     182:       48 d3 e6                shl    %cl,%rsi
     185:       48 89 f0                mov    %rsi,%rax
     188:       48 83 e8 01             sub    $0x1,%rax
     18c:       eb 07                   jmp    195 
     18e:       48 c7 c0 ff ff ff ff    mov    $0xffffffffffffffff,%rax
     195:       48 21 d0                and    %rdx,%rax
     198:       48 85 c0                test   %rax,%rax
     19b:       0f 94 c0                sete   %al
     19e:       0f b6 c0                movzbl %al,%eax
     1a1:       eb 11                   jmp    1b4 
     1a3:       8b 55 d4                mov    -0x2c(%rbp),%edx
     1a6:       48 8b 45 d8             mov    -0x28(%rbp),%rax
     1aa:       89 d6                   mov    %edx,%esi
     1ac:       48 89 c7                mov    %rax,%rdi
     1af:       e8 00 00 00 00          callq  1b4 
     1b4:       48 8b 5d e8             mov    -0x18(%rbp),%rbx
     1b8:       64 48 33 1c 25 28 00    xor    %fs:0x28,%rbx
     1bf:       00 00 
     1c1:       74 05                   je     1c8 
     1c3:       e8 00 00 00 00          callq  1c8 
     1c8:       48 83 c4 28             
     1cc:       5b                      
     1cd:       5d                      
     1ce:       c3                      retq  
qemeの実行プロセスの中で、もともとはqemeのコードで、私達はstatic codeと呼ぶことができます。TBによって生成されたホストコードは、dynamic codeと呼ばれることができます。だから、static codeがdynamic codeを呼び出してくれる入り口が必要です。qemeは似たような関数のprologueを採用しています。これもなぜ私達がコードを見たのですか?gen_prologueの原因。
code_gen_prologureは、TB全体に対して動的に生成されたprologueを指す。
 
 
転載先:https://www.cnblogs.com/long123king/p/3584053.html