qemu内存访问分析

2470阅读 0评论2015-04-27 thewayma
分类:LINUX

emu 内存访问过程:guest virtual addr (GVA) → guest physical addr (GPA) → host virtualaddr (HVA)。其中 GVA->HVA 由 qemu 负责完成,HVA->HPA 由 host 操作系统完成。tlb 的结构如下,addr_xxx 表示 GVA 地址,同时也表示了执行权限;addrend =gpa_base – gva_base;


  1. typedef struct CPUTLBEntry {  
  2. target_ulong addr_read; // 可读  
  3. target_ulong addr_write; // 可写  
  4. target_ulong addr_code; // 可执行  
  5. unsigned long addend;  
  6.   
  7. } CPUTLBEntry;  
    1.get_page_addr_code 会首先查看 tlb 是否命中,如果没有命中就 ldub_code 走 mmu 翻译这个分支,否则直接获取 hva。
  1. 313 /* NOTE: this function can trigger an exception */  
  2. 314 /* NOTE2: the returned address is not exactly the physical address: it 
  3. 315    is the offset relative to phys_ram_base */  
  4. 316 tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)  
  5. 317 {     
  6. 318     int mmu_idx, page_index, pd;  
  7. 319     void *p;  
  8. 320     MemoryRegion *mr;  
  9. 321                                         
  10. 322     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);  
  11. 323     mmu_idx = cpu_mmu_index(env1);      
  12. 324     if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=  
  13. 325                  (addr & TARGET_PAGE_MASK))) {  
  14. 326 #ifdef CONFIG_TCG_PASS_AREG0  
  15. 327         cpu_ldub_code(env1, addr);  
  16. 328 #else  
  17. 329         ldub_code(addr);  
  18. 330 #endif  
  19. 331     }  
  20. 332     pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;  
  21. 333     mr = iotlb_to_region(pd);  
  22. 334     if (memory_region_is_unassigned(mr)) {  
  23. 335 #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)  
  24. 336         cpu_unassigned_access(env1, addr, 0, 1, 0, 4);  
  25. 337 #else  
  26. 338         cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x"  
  27. 339                   TARGET_FMT_lx "\n", addr);  
  28. 340 #endif  
  29. 341     }  
  30. 342     p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);  
  31. 343     return qemu_ram_addr_from_host_nofail(p);  
  32. 344 }  
2.TLB 没有命中时,会通过 ldub_code,这个函数是由下面的宏产生。这个宏首先会在 tlb 检查下是
否命中,如果命中直接从 hva 地址中返回,否则还是通过 mmu 来获取。



  1.  95 static inline RES_TYPE  
  2.  96 glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM  
  3.  97                                                      target_ulong ptr)  
  4.  98 {  
  5.  99     int page_index;  
  6. 100     RES_TYPE res;  
  7. 101     target_ulong addr;  
  8. 102     int mmu_idx;  
  9. 103   
  10. 104     addr = ptr;  
  11. 105     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);  
  12. 106     mmu_idx = CPU_MMU_INDEX;  
  13. 107     if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=  
  14. 108                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {  
  15. 109         res = glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_VAR  
  16. 110                                                                      addr,  
  17. 111                                                                      mmu_idx);  
  18. 112     } else {  
  19. 113         uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;  
  20. 114         res = glue(glue(ld, USUFFIX), _raw)(hostaddr);  
  21. 115     }  
  22. 116     return res;  
  23. 117 }  
3.在这个模板中会对 tlb 进行查询,看是否命中,如果命中,还要根据是 io 还是 ram 进行分别处理;
如果没有命中,则需要通过 mmu 获取该虚拟地址所对应的物理地址,对 tlb 进行填充。
  1. 106 DATA_TYPE  
  2. 107 glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM  
  3. 108                                                        target_ulong addr,  
  4. 109                                                        int mmu_idx)  
  5. 110 {  
  6. 111     DATA_TYPE res;  
  7. 112     int index;  
  8. 113     target_ulong tlb_addr;  
  9. 114     target_phys_addr_t ioaddr;  
  10. 115     uintptr_t retaddr;  
  11. 116   
  12. 117     /* test if there is match for unaligned or IO access */  
  13. 118     /* XXX: could done more in memory macro in a non portable way */  
  14. 119     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);  
  15. 120  redo:  
  16. 121     tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;  
  17. 122     if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {  
  18. 123         if (tlb_addr & ~TARGET_PAGE_MASK) {  
  19. 124             /* IO access */  
  20. 125             if ((addr & (DATA_SIZE - 1)) != 0)  
  21. 126                 goto do_unaligned_access;  
  22. 127             retaddr = GETPC();  
  23. 128             ioaddr = env->iotlb[mmu_idx][index];  
  24. 129             res = glue(io_read, SUFFIX)(ENV_VAR ioaddr, addr, retaddr);  
  25. 130         } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {  
  26. 131             /* slow unaligned access (it spans two pages or IO) */  
  27. 132         do_unaligned_access:  
  28. 133             retaddr = GETPC();  
  29. 134 #ifdef ALIGNED_ONLY  
  30. 135             do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr);  
  31. 136 #endif  
  32. 137             res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr,  
  33. 138                                                          mmu_idx, retaddr);  
  34. 139         } else {  
  35. 140             /* unaligned/aligned access in the same page */  
  36. 141             uintptr_t addend;  
  37. 142 #ifdef ALIGNED_ONLY  
  38. 143             if ((addr & (DATA_SIZE - 1)) != 0) {  
  1. 144                 retaddr = GETPC();  
  2. 145                 do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr);  
  3. 146             }  
  4. 147 #endif  
  5. 148             addend = env->tlb_table[mmu_idx][index].addend;  
  6. 149             res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(intptr_t)  
  7. 150                                                 (addr + addend));  
  8. 151         }  
  9. 152     } else {  
  10. 153         /* the page is not in the TLB : fill it */  
  11. 154         retaddr = GETPC();  
  12. 155 #ifdef ALIGNED_ONLY  
  13. 156         if ((addr & (DATA_SIZE - 1)) != 0)  
  14. 157             do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr);  
  15. 158 #endif  
  16. 159         tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr);  
  17. 160         goto redo;  
  18. 161     }  
  19. 162     return res;  
  20. 163 }  
4.以 arm 为例,tlb_fill 会通过 cpu_arm_handle_mmu_fault 对虚实地址转换进行处理,如果该虚拟
地址没有对应的物理地址或者权限不够等情况,cpu 就会出现 page_fault 异常。



  1. 72 /* try to fill the TLB and return an exception if error. If retaddr is 
  2. 73    NULL, it means that the function was called in C code (i.e. not 
  3. 74    from generated code or from helper.c) */  
  4. 75 /* XXX: fix it to restore all registers */  
  5. 76 void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,  
  6. 77               uintptr_t retaddr)  
  7. 78 {  
  8. 79     TranslationBlock *tb;  
  9. 80     CPUARMState *saved_env;  
  10. 81     int ret;  
  11. 82   
  12. 83     saved_env = env;  
  13. 84     env = env1;  
  14. 85     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);  
  15. 86     if (unlikely(ret)) {  
  16. 87         if (retaddr) {                   
  17. 88             /* now we have a real cpu fault */  
  18. 89             tb = tb_find_pc(retaddr);    
  19. 90             if (tb) {  
  20. 91                 /* the PC is inside the translated code. It means that we have 
  21. 92                    a virtual CPU fault */  
  22. 93                 cpu_restore_state(tb, env, retaddr);  
  23. 94             }  
  24. 95         }  
  25. 96         raise_exception(env->exception_index);  
  26. 97     }  
  27. 98     env = saved_env;  
  28. 99 }  
5. cpu_arm_handle_mmu_fault 里面主要是 page_walk,检查是否存在对应的物理地址和权限。如
果有,更新 tlb;否则,保存出错信息。

  1. 2122 int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,  
  2. 2123                               int access_type, int mmu_idx)  
  3. 2124 {  
  4. 2125     uint32_t phys_addr;  
  5. 2126     target_ulong page_size;  
  6. 2127     int prot;  
  7. 2128     int ret, is_user;  
  8. 2129          
  9. 2130     is_user = mmu_idx == MMU_USER_IDX;  
  10. 2131     ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot,  
  11. 2132                         &page_size);  
  12. 2133     if (ret == 0) {  
  13. 2134         /* Map a single [sub]page.  */  
  14. 2135         phys_addr &= ~(uint32_t)0x3ff;  
  15. 2136         address &= ~(uint32_t)0x3ff;   
  16. 2137         tlb_set_page (env, address, phys_addr, prot, mmu_idx, page_size);  
  17. 2138         return 0;  
  18. 2139     }  
  19. 2140      
  20. 2141     if (access_type == 2) {  
  21. 2142         env->cp15.c5_insn = ret;  
  22. 2143         env->cp15.c6_insn = address;  
  23. 2144         env->exception_index = EXCP_PREFETCH_ABORT;  
  24. 2145     } else {  
  25. 2146         env->cp15.c5_data = ret;  
  26. 2147         if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6))  
  27. 2148             env->cp15.c5_data |= (1 << 11);  
  28. 2149         env->cp15.c6_data = address;  
  29. 2150         env->exception_index = EXCP_DATA_ABORT;  
  30. 2151     }  
  31. 2152     return 1;  
  32. 2153 }  
        qemu 的内存访问模拟,qemu 并没有将内存访问用 IR 表示,这样一方面会更加翻译难度,同时也占
用大量的 code_buffer。Qemu 使用了外调函数来实现这个功能。在对 target 翻译过程中,对于内存访问操
作会生成如下形式的中间码:



  1. tmp = gen_ld16s(addr, IS_USER(s));  
  2. 783 static inline TCGv gen_ld16s(TCGv addr, int index)  
  3. 784 {  
  4. 785 TCGv tmp = tcg_temp_new_i32();  
  5. 786 tcg_gen_qemu_ld16s(tmp, addr, index);  
  6. 787 return tmp;  
  7. 788 }  
接下来在 tcg 翻译将中间码翻译成 host 机器码时,会首先查询 tlb,如果命中就直接返回结果;否则就调用
以下 qemu_ld/st_helpers 中的函数进行 target 的虚拟地址和物理地址转换的工作。



  1. 928 #ifdef CONFIG_SOFTMMU  
  2. 929  
  3. 930 #include "../../softmmu_defs.h"  
  4. 931  
  5. 932 #ifdef CONFIG_TCG_PASS_AREG0  
  6. 933 /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, 
  7. 934 int mmu_idx) */  
  8. 935 static const void * const qemu_ld_helpers[4] = {  
  9. 936 helper_ldb_mmu,  
  10. 937 helper_ldw_mmu,  
  11. 938 helper_ldl_mmu,  
  12. 939 helper_ldq_mmu,  
  13. 940 };  
  14. 941  
  15. 942 /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, 
  16. 943 uintxx_t val, int mmu_idx) */  
  17. 944 static const void * const qemu_st_helpers[4] = {  
  18. 945 helper_stb_mmu,  
  19. 946 helper_stw_mmu,  
  20. 947 helper_stl_mmu,  
  21. 948 helper_stq_mmu,  
  22. 949 };  
  23. 950 #else  
  24. 951 /* legacy helper signature: __ld_mmu(target_ulong addr, int 
  25. 952 mmu_idx) */  
  26. 953 static void *qemu_ld_helpers[4] = {  
  27. 954 __ldb_mmu,  
  28. 955 __ldw_mmu,  
  29. 956 __ldl_mmu,  
  30. 957 __ldq_mmu,  
  31. 958 };  
  32. 959  
  33. 960 /* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, 
  34. 961 int mmu_idx) */  
  35. 962 static void *qemu_st_helpers[4] = {  
  36. 963 __stb_mmu,  
  37. 964 __stw_mmu,  
  38. 965 __stl_mmu,  
  39. 966 __stq_mmu,  
  40. 967 };  
  41. 968 #endif  
  42. 969 #endif  



  1.  971 #define TLB_SHIFT       (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)  
  2.  972   
  3.  973 static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)  
  4.  974 {  
  5.  975     int addr_reg, data_reg, data_reg2, bswap;  
  6.  976 #ifdef CONFIG_SOFTMMU  
  7.  977     int mem_index, s_bits;  
  8.  978 # if TARGET_LONG_BITS == 64  
  9.  979     int addr_reg2;  
  10.  980 # endif  
  11.  981     uint32_t *label_ptr;  
  12.  982 #endif  
  13.  983   
  14.  984 #ifdef TARGET_WORDS_BIGENDIAN  
  15.  985     bswap = 1;  
  16.  986 #else  
  17.  987     bswap = 0;  
  18.  988 #endif  
  19.  989     data_reg = *args++;  
  20.  990     if (opc == 3)  
  21.  991         data_reg2 = *args++;  
  22.  992     else  
  23.  993         data_reg2 = 0; /* suppress warning */  
  24.  994     addr_reg = *args++;  
  25.  995 #ifdef CONFIG_SOFTMMU  
  26.  996 # if TARGET_LONG_BITS == 64  
  27.  997     addr_reg2 = *args++;  
  28.  998 # endif  
  29.  999     mem_index = *args;  
  30. 1000     s_bits = opc & 3;  
  31. 1001   
  32. 1002     /* Should generate something like the following: 
  33. 1003      *  shr r8, addr_reg, #TARGET_PAGE_BITS 
  34. 1004      *  and r0, r8, #(CPU_TLB_SIZE - 1)   @ Assumption: CPU_TLB_BITS <= 8 
  35. 1005      *  add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS 
  36. 1006      */  
  37. 1007 #  if CPU_TLB_BITS > 8  
  38. 1008 #   error  
  39. 1009 #  endif  
  40. 1010     tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_R8,  
  41. 1011                     0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));  
  42. 1012     tcg_out_dat_imm(s, COND_AL, ARITH_AND,  
  43. 1013                     TCG_REG_R0, TCG_REG_R8, CPU_TLB_SIZE - 1);  
  44. "code" class="cpp">1014     tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_AREG0,  
  45. 1015                     TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));  
  46. 1016     /* In the 
  47. 1017      *  ldr r1 [r0, #(offsetof(CPUArchState, tlb_table[mem_index][0].addr_read))] 
  48. 1018      * below, the offset is likely to exceed 12 bits if mem_index != 0 and 
  49. 1019      * not exceed otherwise, so use an 
  50. 1020      *  add r0, r0, #(mem_index * sizeof *CPUArchState.tlb_table) 
  51. 1021      * before. 
  52. 1022      */  
  53. 1023     if (mem_index)  
  54. 1024         tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,  
  55. 1025                         (mem_index << (TLB_SHIFT & 1)) |  
  56. 1026                         ((16 - (TLB_SHIFT >> 1)) << 8));  
  57. 1027     tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R0,  
  58. 1028                     offsetof(CPUArchState, tlb_table[0][0].addr_read));  
  59. 1029     tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,  
  60. 1030                     TCG_REG_R8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));  
  61. 1031     /* Check alignment.  */  
  62. 1032     if (s_bits)  
  63. 1033         tcg_out_dat_imm(s, COND_EQ, ARITH_TST,  
  64. 1034                         0, addr_reg, (1 << s_bits) - 1);  
  65. 1035 #  if TARGET_LONG_BITS == 64  
  66. 1036     /* XXX: possibly we could use a block data load or writeback in 
  67. 1037      * the first access.  */  
  68. 1038     tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,  
  69. 1039                     offsetof(CPUArchState, tlb_table[0][0].addr_read) + 4);  
  70. 1040     tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,  
  71. 1041                     TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));  
  72. 1042 #  endif  
  73. 1043     tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,  
  74. 1044                     offsetof(CPUArchState, tlb_table[0][0].addend));  
  75. 1045   
  76. 1046     switch (opc) {  
  77. 1047     case 0:  
  78. 1048         tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);  
  79. 1049         break;  
  80. 1050     case 0 | 4:  
  81. 1051         tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);  
  82. 1052         break;  
  83. 1053     case 1:  
  84. 1054         tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);  
  85. 1055         if (bswap) {  
  86. 1056             tcg_out_bswap16(s, COND_EQ, data_reg, data_reg);  
  87. 1057         }  
  88. 1058         break;  
  89. 1059     case 1 | 4:  
  90. 1060         if (bswap) {  
  91. 1061             tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);  
  92. 1062             tcg_out_bswap16s(s, COND_EQ, data_reg, data_reg);  
  93. 1063         } else {  
  94. 1064             tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);  
  95. 1065         }  
  96. 1066         break;  
  97. 1067     case 2:  
  98. 1068     default:  
  99. 1069         tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);  
  100. 1070         if (bswap) {  
  101. 1071             tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);  
  102. 1072         }  
  103. 1073         break;  
  104. 1074     case 3:  
  105. 1075         if (bswap) {  
  106. 1076             tcg_out_ld32_rwb(s, COND_EQ, data_reg2, TCG_REG_R1, addr_reg);  
  107. 1077             tcg_out_ld32_12(s, COND_EQ, data_reg, TCG_REG_R1, 4);  
  108. 1078             tcg_out_bswap32(s, COND_EQ, data_reg2, data_reg2);  
  109. 1079             tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);  
  110. 1080         } else {  
  111. 1081             tcg_out_ld32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);  
  112. 1082             tcg_out_ld32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);  
  113. 1083         }  
  114. 1084         break;  
  115. 1085     }  
  116. 1086   
  117. 1087     label_ptr = (void *) s->code_ptr;  
  118. 1088     tcg_out_b_noaddr(s, COND_EQ);  
  119. 1089   
  120. 1090     /* TODO: move this code to where the constants pool will be */  
  121. 1091     if (addr_reg != TCG_REG_R0) {  
  122. 1092         tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  123. 1093                         TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));  
  124. 1094     }  
  125. 1095 # if TARGET_LONG_BITS == 32  
  126. 1096     tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R1, 0, mem_index);  
  127. 1097 # else  
  128. 1098     tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  129. 1099                     TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));  
  130. 1100     tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);  
  131. 1101 # endif  
  132. 1102 #ifdef CONFIG_TCG_PASS_AREG0  
  133. 1103     /* XXX/FIXME: suboptimal and incorrect for 64 bit */  
  134. 1104     tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  135. 1105                     tcg_target_call_iarg_regs[2], 0,  
  136. 1106                     tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));  
  137. 1107     tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  138. 1108                     tcg_target_call_iarg_regs[1], 0,  
  139. 1109                     tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));  
  140. 1110   
  141. 1111     tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  142. 1112                     tcg_target_call_iarg_regs[0], 0, TCG_AREG0,  
  143. 1113                     SHIFT_IMM_LSL(0));  
  144. 1114 #endif  
  145. 1115     tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);  
  146. 1116   
  147. 1117     switch (opc) {  
  148. 1118     case 0 | 4:  
  149. 1119         tcg_out_ext8s(s, COND_AL, data_reg, TCG_REG_R0);  
  150. 1120         break;  
  151. 1121     case 1 | 4:  
  152. 1122         tcg_out_ext16s(s, COND_AL, data_reg, TCG_REG_R0);  
  153. 1123         break;  
  154. 1124     case 0:  
  155. 1125     case 1:  
  156. 1126     case 2:  
  157. 1127     default:  
  158. 1128         if (data_reg != TCG_REG_R0) {  
  159. 1129             tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  160. 1130                             data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));  
  161. 1131         }  
  162. 1132         break;  
  163. 1133     case 3:  
  164. 1134         if (data_reg != TCG_REG_R0) {  
  165. 1135             tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  166. 1136                             data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));  
  167. 1137         }  
  168. 1138         if (data_reg2 != TCG_REG_R1) {  
  169. 1139             tcg_out_dat_reg(s, COND_AL, ARITH_MOV,  
  170. 1140                             data_reg2, 0, TCG_REG_R1, SHIFT_IMM_LSL(0));  
  171. 1141         }  
  172. 1142         break;  
  173. 1143     }  
  174. 1144   
  175. 1145     reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);  
  176. 1146 #else /* !CONFIG_SOFTMMU */  
  177. 1147     if (GUEST_BASE) {  
  178. 1148         uint32_t offset = GUEST_BASE;  
  179. 1149         int i;  
  180. 1150         int rot;  
  181. 1151   
  182. 1152         while (offset) {  
  183. 1153             i = ctz32(offset) & ~1;  
  184. 1154             rot = ((32 - i) << 7) & 0xf00;  
  185. 1155   
  186. 1156             tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R8, addr_reg,  
  187. 1157                             ((offset >> i) & 0xff) | rot);  
  188. 1158             addr_reg = TCG_REG_R8;  
  189. 1159             offset &= ~(0xff << i);  
  190. 1160         }  
  191. 1161     }  
  192. 1162     switch (opc) {  
  193. 1163     case 0:  
  194. 1164         tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);  
  195. 1165         break;  
  196. 1166     case 0 | 4:  
  197. 1167         tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0);  
  198. 1168         break;  
  199. 1169     case 1:  
  200. 1170         tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);  
  201. 1171         if (bswap) {  
  202. 1172             tcg_out_bswap16(s, COND_AL, data_reg, data_reg);  
  203. 1173         }  
  204. 1174         break;  
  205. 1175     case 1 | 4:  
  206. 1176         if (bswap) {  
  207. 1177             tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);  
  208. 1178             tcg_out_bswap16s(s, COND_AL, data_reg, data_reg);  
  209. 1179         } else {  
  210. 1180             tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0);  
  211. 1181         }  
  212. 1182         break;  
  213. 1183     case 2:  
  214. 1184     default:  
  215. 1185         tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);  
  216. 1186         if (bswap) {  
  217. 1187             tcg_out_bswap32(s, COND_AL, data_reg, data_reg);  
  218. 1188         }  
  219. 1189         break;  
  220. 1190     case 3:  
  221. 1191         /* TODO: use block load - 
  222. 1192          * check that data_reg2 > data_reg or the other way */  
  223. 1193         if (data_reg == addr_reg) {  
  224. 1194             tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);  
  225. 1195             tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);  
  226. 1196         } else {  
  227. 1197             tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);  
  228. 1198             tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);  
  229. 1199         }  
  230. 1200         if (bswap) {  
  231. 1201             tcg_out_bswap32(s, COND_AL, data_reg, data_reg);  
  232. 1202             tcg_out_bswap32(s, COND_AL, data_reg2, data_reg2);  
  233. 1203         }  
  234. 1204         break;  
  235. 1205     }  
  236. 1206 #endif  
  237. 1207 }  
  238.   
  239.   
  240.   
  241.   
  242.        上面的内存访问中将查找tlb部分直接翻译成了host指令,而对于target 的mmu转换则使用了外调相送的函数来实现的。这样对提升速度是有好处的。
     
上一篇:Qemu对内部寄存器的模拟
下一篇:QEMU 访存机制介绍与应用