Commit 4390df510788b6e19cce96db48a94ab2e519e469
1 parent
ecd854fd
added support for direct patching on i386 host (faster emulation) - increased tr…
…anslation buffer size - added new TLB support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@517 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
120 additions
and
17 deletions
exec-all.h
| ... | ... | @@ -28,6 +28,11 @@ |
| 28 | 28 | #define tostring(s) #s |
| 29 | 29 | #endif |
| 30 | 30 | |
| 31 | +#ifndef THUNK_H | |
| 32 | +/* horrible */ | |
| 33 | +typedef uint32_t target_ulong; | |
| 34 | +#endif | |
| 35 | + | |
| 31 | 36 | #if GCC_MAJOR < 3 |
| 32 | 37 | #define __builtin_expect(x, n) (x) |
| 33 | 38 | #endif |
| ... | ... | @@ -77,10 +82,12 @@ int cpu_restore_state(struct TranslationBlock *tb, |
| 77 | 82 | CPUState *env, unsigned long searched_pc); |
| 78 | 83 | void cpu_exec_init(void); |
| 79 | 84 | int page_unprotect(unsigned long address); |
| 80 | -void tb_invalidate_page(unsigned long address); | |
| 85 | +void tb_invalidate_page_range(target_ulong start, target_ulong end); | |
| 81 | 86 | void tlb_flush_page(CPUState *env, uint32_t addr); |
| 82 | 87 | void tlb_flush_page_write(CPUState *env, uint32_t addr); |
| 83 | 88 | void tlb_flush(CPUState *env); |
| 89 | +int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, | |
| 90 | + int is_user, int is_softmmu); | |
| 84 | 91 | |
| 85 | 92 | #define CODE_GEN_MAX_SIZE 65536 |
| 86 | 93 | #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ |
| ... | ... | @@ -88,11 +95,47 @@ void tlb_flush(CPUState *env); |
| 88 | 95 | #define CODE_GEN_HASH_BITS 15 |
| 89 | 96 | #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) |
| 90 | 97 | |
| 98 | +#define CODE_GEN_PHYS_HASH_BITS 15 | |
| 99 | +#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) | |
| 100 | + | |
| 91 | 101 | /* maximum total translate dcode allocated */ |
| 92 | -#define CODE_GEN_BUFFER_SIZE (2048 * 1024) | |
| 102 | + | |
| 103 | +/* NOTE: the translated code area cannot be too big because on some | |
| 104 | + archs the range of "fast" function calls are limited. Here is a | |
| 105 | + summary of the ranges: | |
| 106 | + | |
| 107 | + i386 : signed 32 bits | |
| 108 | + arm : signed 26 bits | |
| 109 | + ppc : signed 24 bits | |
| 110 | + sparc : signed 32 bits | |
| 111 | + alpha : signed 23 bits | |
| 112 | +*/ | |
| 113 | + | |
| 114 | +#if defined(__alpha__) | |
| 115 | +#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) | |
| 116 | +#elif defined(__powerpc__) | |
| 117 | +#define CODE_GEN_BUFFER_SIZE (6 * 1024) | |
| 118 | +#else | |
| 119 | +#define CODE_GEN_BUFFER_SIZE (8 * 1024 * 1024) | |
| 120 | +#endif | |
| 121 | + | |
| 93 | 122 | //#define CODE_GEN_BUFFER_SIZE (128 * 1024) |
| 94 | 123 | |
| 95 | -#if defined(__powerpc__) | |
| 124 | +/* estimated block size for TB allocation */ | |
| 125 | +/* XXX: use a per code average code fragment size and modulate it | |
| 126 | + according to the host CPU */ | |
| 127 | +#if defined(CONFIG_SOFTMMU) | |
| 128 | +#define CODE_GEN_AVG_BLOCK_SIZE 128 | |
| 129 | +#else | |
| 130 | +#define CODE_GEN_AVG_BLOCK_SIZE 64 | |
| 131 | +#endif | |
| 132 | + | |
| 133 | +#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE) | |
| 134 | + | |
| 135 | +#if defined(__powerpc__) | |
| 136 | +#define USE_DIRECT_JUMP | |
| 137 | +#endif | |
| 138 | +#if defined(__i386__) | |
| 96 | 139 | #define USE_DIRECT_JUMP |
| 97 | 140 | #endif |
| 98 | 141 | |
| ... | ... | @@ -103,8 +146,14 @@ typedef struct TranslationBlock { |
| 103 | 146 | uint16_t size; /* size of target code for this block (1 <= |
| 104 | 147 | size <= TARGET_PAGE_SIZE) */ |
| 105 | 148 | uint8_t *tc_ptr; /* pointer to the translated code */ |
| 106 | - struct TranslationBlock *hash_next; /* next matching block */ | |
| 107 | - struct TranslationBlock *page_next[2]; /* next blocks in even/odd page */ | |
| 149 | + struct TranslationBlock *hash_next; /* next matching tb for virtual address */ | |
| 150 | + /* next matching tb for physical address. */ | |
| 151 | + struct TranslationBlock *phys_hash_next; | |
| 152 | + /* first and second physical page containing code. The lower bit | |
| 153 | + of the pointer tells the index in page_next[] */ | |
| 154 | + struct TranslationBlock *page_next[2]; | |
| 155 | + target_ulong page_addr[2]; | |
| 156 | + | |
| 108 | 157 | /* the following data are used to directly call another TB from |
| 109 | 158 | the code of this one. */ |
| 110 | 159 | uint16_t tb_next_offset[2]; /* offset of original jump target */ |
| ... | ... | @@ -126,11 +175,19 @@ static inline unsigned int tb_hash_func(unsigned long pc) |
| 126 | 175 | return pc & (CODE_GEN_HASH_SIZE - 1); |
| 127 | 176 | } |
| 128 | 177 | |
| 178 | +static inline unsigned int tb_phys_hash_func(unsigned long pc) | |
| 179 | +{ | |
| 180 | + return pc & (CODE_GEN_PHYS_HASH_SIZE - 1); | |
| 181 | +} | |
| 182 | + | |
| 129 | 183 | TranslationBlock *tb_alloc(unsigned long pc); |
| 130 | 184 | void tb_flush(CPUState *env); |
| 131 | 185 | void tb_link(TranslationBlock *tb); |
| 186 | +void tb_link_phys(TranslationBlock *tb, | |
| 187 | + target_ulong phys_pc, target_ulong phys_page2); | |
| 132 | 188 | |
| 133 | 189 | extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; |
| 190 | +extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | |
| 134 | 191 | |
| 135 | 192 | extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; |
| 136 | 193 | extern uint8_t *code_gen_ptr; |
| ... | ... | @@ -159,8 +216,10 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, |
| 159 | 216 | return NULL; |
| 160 | 217 | } |
| 161 | 218 | |
| 162 | -#if defined(__powerpc__) | |
| 163 | 219 | |
| 220 | +#if defined(USE_DIRECT_JUMP) | |
| 221 | + | |
| 222 | +#if defined(__powerpc__) | |
| 164 | 223 | static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) |
| 165 | 224 | { |
| 166 | 225 | uint32_t val, *ptr; |
| ... | ... | @@ -177,6 +236,14 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr |
| 177 | 236 | asm volatile ("sync" : : : "memory"); |
| 178 | 237 | asm volatile ("isync" : : : "memory"); |
| 179 | 238 | } |
| 239 | +#elif defined(__i386__) | |
| 240 | +static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) | |
| 241 | +{ | |
| 242 | + /* patch the branch destination */ | |
| 243 | + *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); | |
| 244 | + /* no need to flush icache explicitely */ | |
| 245 | +} | |
| 246 | +#endif | |
| 180 | 247 | |
| 181 | 248 | static inline void tb_set_jmp_target(TranslationBlock *tb, |
| 182 | 249 | int n, unsigned long addr) |
| ... | ... | @@ -223,7 +290,7 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); |
| 223 | 290 | |
| 224 | 291 | #if defined(__powerpc__) |
| 225 | 292 | |
| 226 | -/* on PowerPC we patch the jump instruction directly */ | |
| 293 | +/* we patch the jump instruction directly */ | |
| 227 | 294 | #define JUMP_TB(opname, tbparam, n, eip)\ |
| 228 | 295 | do {\ |
| 229 | 296 | asm volatile (".section \".data\"\n"\ |
| ... | ... | @@ -239,7 +306,28 @@ do {\ |
| 239 | 306 | |
| 240 | 307 | #define JUMP_TB2(opname, tbparam, n)\ |
| 241 | 308 | do {\ |
| 242 | - asm volatile ("b __op_jmp%0\n" : : "i" (n + 2));\ | |
| 309 | + asm volatile ("b __op_jmp" #n "\n");\ | |
| 310 | +} while (0) | |
| 311 | + | |
| 312 | +#elif defined(__i386__) && defined(USE_DIRECT_JUMP) | |
| 313 | + | |
| 314 | +/* we patch the jump instruction directly */ | |
| 315 | +#define JUMP_TB(opname, tbparam, n, eip)\ | |
| 316 | +do {\ | |
| 317 | + asm volatile (".section \".data\"\n"\ | |
| 318 | + "__op_label" #n "." stringify(opname) ":\n"\ | |
| 319 | + ".long 1f\n"\ | |
| 320 | + ".previous\n"\ | |
| 321 | + "jmp __op_jmp" #n "\n"\ | |
| 322 | + "1:\n");\ | |
| 323 | + T0 = (long)(tbparam) + (n);\ | |
| 324 | + EIP = eip;\ | |
| 325 | + EXIT_TB();\ | |
| 326 | +} while (0) | |
| 327 | + | |
| 328 | +#define JUMP_TB2(opname, tbparam, n)\ | |
| 329 | +do {\ | |
| 330 | + asm volatile ("jmp __op_jmp" #n "\n");\ | |
| 243 | 331 | } while (0) |
| 244 | 332 | |
| 245 | 333 | #else |
| ... | ... | @@ -261,19 +349,11 @@ dummy_label ## n:\ |
| 261 | 349 | /* second jump to same destination 'n' */ |
| 262 | 350 | #define JUMP_TB2(opname, tbparam, n)\ |
| 263 | 351 | do {\ |
| 264 | - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ | |
| 352 | + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\ | |
| 265 | 353 | } while (0) |
| 266 | 354 | |
| 267 | 355 | #endif |
| 268 | 356 | |
| 269 | -/* physical memory access */ | |
| 270 | -#define IO_MEM_NB_ENTRIES 256 | |
| 271 | -#define TLB_INVALID_MASK (1 << 3) | |
| 272 | -#define IO_MEM_SHIFT 4 | |
| 273 | -#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT) | |
| 274 | - | |
| 275 | -unsigned long physpage_find(unsigned long page); | |
| 276 | - | |
| 277 | 357 | extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; |
| 278 | 358 | extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; |
| 279 | 359 | |
| ... | ... | @@ -441,3 +521,26 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, |
| 441 | 521 | #undef env |
| 442 | 522 | |
| 443 | 523 | #endif |
| 524 | + | |
| 525 | +#if defined(CONFIG_USER_ONLY) | |
| 526 | +static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) | |
| 527 | +{ | |
| 528 | + return addr; | |
| 529 | +} | |
| 530 | +#else | |
| 531 | +/* NOTE: this function can trigger an exception */ | |
| 532 | +/* XXX: i386 target specific */ | |
| 533 | +static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) | |
| 534 | +{ | |
| 535 | + int is_user, index; | |
| 536 | + | |
| 537 | + index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); | |
| 538 | + is_user = ((env->hflags & HF_CPL_MASK) == 3); | |
| 539 | + if (__builtin_expect(env->tlb_read[is_user][index].address != | |
| 540 | + (addr & TARGET_PAGE_MASK), 0)) { | |
| 541 | + ldub_code((void *)addr); | |
| 542 | + } | |
| 543 | + return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base; | |
| 544 | +} | |
| 545 | +#endif | |
| 546 | + | ... | ... |