加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

(转)qemu执行流程分析

(2014-04-24 12:56:35)
分类: 云计算与虚拟化
转自: http://blog.csdn.net/alloc7/article/details/7719823

一.qemu简介

         qemu是使用动态二进制翻译的cpu模拟器,它支持两种运行模式:全系统模拟和用户态模拟。在全系统模拟下,qemu可以模拟处理器和各种外设,可以运行操作系统。用户态可以运行为另外一种cpu编译的进程,前提是两者运行的os要一致。qemu使用了动态二进制翻译将targetinstruction翻译成hostinstruction,完成这个工作的是tcg模块。为了移植性和通用性方面的考虑,qemu定义了mirco-op,首先qemu会将targetinstruction翻译成mirco-op,然后tcgmirco-op翻译成host instruction

Qemu代码翻译流程:target instruction ->micro-op->tcg->host instruction

2.qemu代码执行流程:

    1. 这部分主要是创建了一个为执行tcg翻译和执行的线程,它的函数是qemu_tcg_cpu_thread_fn,这个函数会调用tcg_exec_all,最后cpu_exec.   

main
cpu_init
qemu_init_vcpu
qemu_tcg_init_vcpu

qemu_tcg_cpu_thread_fn

 

     2.执行主函数(cpu_exec)

                主要是处理中断异常, 找到代码翻译块,然后执行.

 

  1. for(;;)  
  2. process interruptrequest;  
  3.   
  4. tb_find_fast();  
  5.   
  6. tcg_qemu_tb_exec(tc_ptr);  
  7.  

 

 

        qemu会将翻译好到代码块暂存起来,因此首先会去查看该pc对应的代码是否已经翻译,如果已经存在直接返回,否则就进入tb_find_slow,进行翻译。

 

  1. 139 static inline TranslationBlock *tb_find_fast(CPUArchState *env)  
  2. 140  
  3. 141     TranslationBlock *tb;  
  4. 142     target_ulong cs_base, pc;  
  5. 143     int flags;  
  6. 144   
  7. 145       
  8. 148     cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);  
  9. 149     tb env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];  
  10. 150     if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||  
  11. 151                  tb->flags != flags))  
  12. 152         tb tb_find_slow(env, pc, cs_base, flags);  
  13. 153      
  14. 154     return tb;  
  15. 155  

 

       进入tb_find_slow后会调用tb_gen_code,首先分配TranslationBlock描述符,将要翻译的pc等信息记录下来,然后调用cpu_gen_code,这个函数完成代码翻译工作。qemu将翻译好的代码存在一个缓冲区里面。

  1. 1029 TranslationBlock *tb_gen_code(CPUArchState *env,  
  2. 1030                               target_ulong pc, target_ulong cs_base,  
  3. 1031                               int flags, int cflags)  
  4. 1032            
  5. 1033     TranslationBlock *tb;  
  6. 1034     uint8_t *tc_ptr;  
  7. 1035     tb_page_addr_t phys_pc, phys_page2;  
  8. 1036     target_ulong virt_page2;  
  9. 1037     int code_gen_size;  
  10. 1038      
  11. 1039     phys_pc get_page_addr_code(env, pc);  
  12. 1040     tb tb_alloc(pc);  
  13. 1041     if (!tb)  
  14. 1042           
  15. 1043         tb_flush(env);  
  16. 1044           
  1. 1045         tb tb_alloc(pc);  
  2. 1046           
  3. 1047         tb_invalidated_flag 1;  
  4. 1048      
  5. 1049     tc_ptr code_gen_ptr;  
  6. 1050     tb->tc_ptr tc_ptr;  
  7. 1051     tb->cs_base cs_base;  
  8. 1052     tb->flags flags;  
  9. 1053     tb->cflags cflags;  
  10. 1054     cpu_gen_code(env, tb, &code_gen_size);  
  11. 1055     code_gen_ptr (void *)(((uintptr_t)code_gen_ptr code_gen_size  
  12. 1056                              CODE_GEN_ALIGN 1) ~(CODE_GEN_ALIGN 1));  
  13. 1057   
  14. 1058       
  15. 1059     virt_page2 (pc tb->size 1) TARGET_PAGE_MASK;  
  16. 1060     phys_page2 -1;  
  17. 1061     if ((pc TARGET_PAGE_MASK) != virt_page2)  
  18. 1062         phys_page2 get_page_addr_code(env, virt_page2);  
  19. 1063      
  20. 1064     tb_link_page(tb, phys_pc, phys_page2);  
  21. 1065     return tb;  
  22. 1066  

 

     cpu_gen_code里面首先是将targetinstruction翻译成micro-op,然后将mirco-op翻译成host机器码。

 

  1. 54 int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr)  
  2.  55  
  3.  56     TCGContext *s &tcg_ctx;  
  4.  57     uint8_t *gen_code_buf;  
  5.  58     int gen_code_size;  
  6.  59 #ifdef CONFIG_PROFILER  
  7.  60     int64_t ti;  
  8.  61 #endif  
  9.  62   
  10.  63 #ifdef CONFIG_PROFILER  
  11.  64     s->tb_count1++;   
  12.  66     ti profile_getclock();  
  13.  67 #endif  
  14.  68     tcg_func_start(s);  
  15.  69   
  16.  70     gen_intermediate_code(env, tb);  
  17.  71   
  18.  72       
  19.  73     gen_code_buf tb->tc_ptr;  
  20.  74     tb->tb_next_offset[0] 0xffff;  
  21.  75     tb->tb_next_offset[1] 0xffff;  
  22.  76     s->tb_next_offset tb->tb_next_offset;  
  23.  77 #ifdef USE_DIRECT_JUMP  
  24.  78     s->tb_jmp_offset tb->tb_jmp_offset;  
  25.  79     s->tb_next NULL;  
  26.  80 #else  
  27.  81     s->tb_jmp_offset NULL;  
  28.  82     s->tb_next tb->tb_next;  
  29.  83 #endif  
  30.  84   
  31.  85 #ifdef CONFIG_PROFILER  
  32.  86     s->tb_count++;  
  33.  87     s->interm_time += profile_getclock() ti;  
  34.  88     s->code_time -= profile_getclock();  
  35.  89 #endif  
  36.  90     gen_code_size tcg_gen_code(s, gen_code_buf);  
  37.  91     *gen_code_size_ptr gen_code_size;  
  38.  92 #ifdef CONFIG_PROFILER  
  39.  93     s->code_time += profile_getclock();  
  40.  94     s->code_in_len += tb->size;  
  41.  95     s->code_out_len += gen_code_size;  
  42.  96 #endif  
  43.  97   
  44.  98 #ifdef DEBUG_DISAS  
  45.  99     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM))  
  46. 100         qemu_log("OUT: [size=%d]\n"*gen_code_size_ptr);  
  47. 101         log_disas(tb->tc_ptr, *gen_code_size_ptr);  
  48. 102         qemu_log("\n");  
  49. 103         qemu_log_flush();  
  50. 104      
  51. 105 #endif  
  52. 106     return 0;  
  53. 107  

 

       qemutarget翻译成中间码时,将操作码和操作数分开存储,分别存在gen_opc_bufgen_opparam_buf中。翻译的过程就是不断向gen_opc_bufgen_opparam_buf中填充操作码和操作数。接下来就是tcg_gen_code.

 

  1. 2175 int tcg_gen_code(TCGContext *s, uint8_t *gen_code_buf)  
  2. 2176  
  3. 2177 #ifdef CONFIG_PROFILER  
  4. 2178      
  5. 2179         int n;  
  6. 2180         (gen_opc_ptr gen_opc_buf);  
  7. 2181         s->op_count += n;  
  8. 2182         if (n s->op_count_max)  
  9. 2183             s->op_count_max n;  
  10. 2184   
  11. 2185         s->temp_count += s->nb_temps;  
  12. 2186         if (s->nb_temps s->temp_count_max)  
  13. 2187             s->temp_count_max s->nb_temps;  
  14. 2188      
  15. 2189 #endif  
  16. 2190   
  17. 2191     tcg_gen_code_common(s, gen_code_buf, -1);  
  18. 2192   
  19. 2193       
  20. 2194     flush_icache_range((tcg_target_ulong)gen_code_buf,  
  21. 2195                        (tcg_target_ulong)s->code_ptr);  
  22. 2196   
  23. 2197     return s->code_ptr  gen_code_buf;  
  24. 2198  

 

      tcg_gen_code的工作是将中间码翻译成host机器码,它的主要函数是tcg_gen_code_common.

 

  1. 2045 static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf,  
  2. 2046                                       long search_pc)  
  3. 2047  
  4. 2048     TCGOpcode opc;  
  5. 2049     int op_index;  
  6. 2050     const TCGOpDef *def;  
  7. 2051     unsigned int dead_args;  
  8. 2052     const TCGArg *args;  
  9. 2053   
  10. 2054 #ifdef DEBUG_DISAS  
  11. 2055     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))  
  12. 2056         qemu_log("OP:\n");  
  13. 2057         tcg_dump_ops(s);  
  14. 2058         qemu_log("\n");  
  15. 2059      
  16. 2060 #endif  
  17. 2061   
  18. 2062 #ifdef USE_TCG_OPTIMIZATIONS  
  19. 2063     gen_opparam_ptr  
  20. 2064         tcg_optimize(s, gen_opc_ptr, gen_opparam_buf, tcg_op_defs);  
  21. 2065 #endif  
  22. 2066   
  23. 2067 #ifdef CONFIG_PROFILER  
  24. 2068     s->la_time -= profile_getclock();  
  25. 2069 #endif  
  26. 2070     tcg_liveness_analysis(s);  
  27. 2071 #ifdef CONFIG_PROFILER  
  28. 2072     s->la_time += profile_getclock();  
  29. 2073 #endif  
  30. 2074   
  31. 2075 #ifdef DEBUG_DISAS  
  32. 2076     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)))  
  33. 2077         qemu_log("OP after liveness analysis:\n");  
  34. 2078         tcg_dump_ops(s);  
  35. 2079         qemu_log("\n");  
  36. 2080      
  37. 2081 #endif  
  38. 2082   
  39. 2083     tcg_reg_alloc_start(s);  
  40. 2084   
  41. 2085     s->code_buf gen_code_buf;  
  42. 2086     s->code_ptr gen_code_buf;  
  43. 2087   
  44. 2088     args gen_opparam_buf;  
  45.  2089     op_index 0;  
  46. 2090   
  47. 2091     for(;;)  
  48. 2092         opc gen_opc_buf[op_index];  
  49. 2093 #ifdef CONFIG_PROFILER  
  50. 2094         tcg_table_op_count[opc]++;  
  51. 2095 #endif  
  52. 2096         def &tcg_op_defs[opc];  
  53. 2097 #if  
  54. 2098         printf("%s: %d %d %d\n"def->name,  
  55. 2099                def->nb_oargs, def->nb_iargs, def->nb_cargs);  
  56. 2100         //        dump_regs(s);  
  57. 2101 #endif  
  58. 2102         switch(opc)  
  59. 2103         case INDEX_op_mov_i32:  
  60. 2104 #if TCG_TARGET_REG_BITS == 64  
  61. 2105         case INDEX_op_mov_i64:  
  62. 2106 #endif  
  63. 2107             dead_args s->op_dead_args[op_index];  
  64. 2108             tcg_reg_alloc_mov(s, def, args, dead_args);  
  65. 2109             break 
  66. 2110         case INDEX_op_movi_i32:  
  67. 2111 #if TCG_TARGET_REG_BITS == 64  
  68. 2112         case INDEX_op_movi_i64:  
  69. 2113 #endif  
  70. 2114             tcg_reg_alloc_movi(s, args);  
  71. 2115             break 
  72. 2116         case INDEX_op_debug_insn_start:  
  73. 2117               
  74. 2118             break 
  75. 2119         case INDEX_op_nop:  
  76. 2120         case INDEX_op_nop1:  
  77. 2121         case INDEX_op_nop2:  
  78. 2122         case INDEX_op_nop3:  
  79. 2123             break 
  80. 2124         case INDEX_op_nopn:  
  81. 2125             args += args[0];  
  82. 2126             goto next;  
  83. 2127         case INDEX_op_discard:  
  84. 2128              
  85.  2129                 TCGTemp *ts;  
  86. 2130                 ts &s->temps[args[0]];  
  87. 2131                   
  88. 2132                 if (!ts->fixed_reg)  
  89. 2133                     if (ts->val_type == TEMP_VAL_REG)  
  90. 2134                         s->reg_to_temp[ts->reg] -1;  
  91. 2135                     ts->val_type TEMP_VAL_DEAD;  
  92. 2136                  
  93. 2137              
  94. 2138             break 
  95. 2139         case INDEX_op_set_label:  
  96. 2140             tcg_reg_alloc_bb_end(s, s->reserved_regs);  
  97. 2141             tcg_out_label(s, args[0], s->code_ptr);  
  98. 2142             break 
  99. 2143         case INDEX_op_call:  
  100. 2144             dead_args s->op_dead_args[op_index];  
  101. 2145             args += tcg_reg_alloc_call(s, def, opc, args, dead_args);  
  102. 2146             goto next;  
  103. 2147         case INDEX_op_end:  
  104. 2148             goto the_end;  
  105. 2149         default 
  106. 2150               
  107. 2151             if (def->flags TCG_OPF_NOT_PRESENT)  
  108. 2152                 tcg_abort();  
  109. 2153              
  110. 2154               
  111. 2157             dead_args s->op_dead_args[op_index];  
  112. 2158             tcg_reg_alloc_op(s, def, opc, args, dead_args);  
  113. 2159             break 
  114. 2160          
  115. 2161         args += def->nb_args;  
  116. 2162     next:  
  117. 2163         if (search_pc >= && search_pc s->code_ptr gen_code_buf)  
  118. 2164             return op_index;  
  119. 2165          
  120. 2166         op_index++;  
  121. 2167 #ifndef NDEBUG  
  122. 2168         check_regs(s);  
  123. 2169 #endif  
  124. 2170      
  125.  2171  the_end:  
  126. 2172     return -1;  
  127. 2173  

 

       大部分执行default分支,tcg_reg_alloc_op主要是分析该指令的输入、输出约束,根据这些约束分配寄存器等,然后调用tcg_out_op将该中间码翻译成host机器码。

 

3.翻译代码块的执行

     代码块翻译好之后,主函数调用tcg_qemu_tb_exec,该函数会进入tcg的入口函数。

 

hostarm为例,入口函数主要是保存寄存器的状态,然后将tcg_qemu_tb_exec传进来的第一的参数(env)TCG_AREG0,然后跳转至tb_ptr,开始执行代码。同时代码执行的返回地址也确定了,返回后恢复之前保存的状态。

以hostarm为例,入口函数主要是保存寄存器的状态,然后将tcg_qemu_tb_exec传进来的第一的参数(env)TCG_AREG0,然后跳转至tb_ptr,开始执行代码。同时代码执行的返回地址也确定了,返回后恢复之前保存的状态。
  1. 100 #define tcg_qemu_tb_exec(env, tb_ptr)  
  2. 101     ((long __attribute__ ((longcall))  
  3. 102       (*)(void *, void *))code_gen_prologue)(env, tb_ptr)  

      code_gen_prologuetcg的入口函数,在tcg初始化的时候会生成相应的代码.

        hostarm为例,入口函数主要是保存寄存器的状态,然后将tcg_qemu_tb_exec传进来的第一的参数(env)TCG_AREG0,然后跳转至tb_ptr,开始执行代码。同时代码执行的返回地址也确定了,返回后恢复之前保存的状态。

 

  1. 1881 static void tcg_target_qemu_prologue(TCGContext *s)  
  2. 1882  
  3. 1883       
  4. 1886       
  5. 1887       
  6. 1888     tcg_out32(s, (COND_AL << 28) 0x092d5ff0);  
  7. 1889   
  8. 1890     tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);  
  9. 1891   
  10. 1892     tcg_out_bx(s, COND_AL, tcg_target_call_iarg_regs[1]);  
  11. 1893     tb_ret_addr s->code_ptr;  
  12. 1894       
  13. 1895       
  14. 1896     tcg_out32(s, (COND_AL << 28) 0x08bd9ff0);  
  15. 1897     


 











更多0

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有