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,6 +28,11 @@ | ||
28 | #define tostring(s) #s | 28 | #define tostring(s) #s |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | +#ifndef THUNK_H | ||
32 | +/* horrible */ | ||
33 | +typedef uint32_t target_ulong; | ||
34 | +#endif | ||
35 | + | ||
31 | #if GCC_MAJOR < 3 | 36 | #if GCC_MAJOR < 3 |
32 | #define __builtin_expect(x, n) (x) | 37 | #define __builtin_expect(x, n) (x) |
33 | #endif | 38 | #endif |
@@ -77,10 +82,12 @@ int cpu_restore_state(struct TranslationBlock *tb, | @@ -77,10 +82,12 @@ int cpu_restore_state(struct TranslationBlock *tb, | ||
77 | CPUState *env, unsigned long searched_pc); | 82 | CPUState *env, unsigned long searched_pc); |
78 | void cpu_exec_init(void); | 83 | void cpu_exec_init(void); |
79 | int page_unprotect(unsigned long address); | 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 | void tlb_flush_page(CPUState *env, uint32_t addr); | 86 | void tlb_flush_page(CPUState *env, uint32_t addr); |
82 | void tlb_flush_page_write(CPUState *env, uint32_t addr); | 87 | void tlb_flush_page_write(CPUState *env, uint32_t addr); |
83 | void tlb_flush(CPUState *env); | 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 | #define CODE_GEN_MAX_SIZE 65536 | 92 | #define CODE_GEN_MAX_SIZE 65536 |
86 | #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ | 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,11 +95,47 @@ void tlb_flush(CPUState *env); | ||
88 | #define CODE_GEN_HASH_BITS 15 | 95 | #define CODE_GEN_HASH_BITS 15 |
89 | #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) | 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 | /* maximum total translate dcode allocated */ | 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 | //#define CODE_GEN_BUFFER_SIZE (128 * 1024) | 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 | #define USE_DIRECT_JUMP | 139 | #define USE_DIRECT_JUMP |
97 | #endif | 140 | #endif |
98 | 141 | ||
@@ -103,8 +146,14 @@ typedef struct TranslationBlock { | @@ -103,8 +146,14 @@ typedef struct TranslationBlock { | ||
103 | uint16_t size; /* size of target code for this block (1 <= | 146 | uint16_t size; /* size of target code for this block (1 <= |
104 | size <= TARGET_PAGE_SIZE) */ | 147 | size <= TARGET_PAGE_SIZE) */ |
105 | uint8_t *tc_ptr; /* pointer to the translated code */ | 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 | /* the following data are used to directly call another TB from | 157 | /* the following data are used to directly call another TB from |
109 | the code of this one. */ | 158 | the code of this one. */ |
110 | uint16_t tb_next_offset[2]; /* offset of original jump target */ | 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,11 +175,19 @@ static inline unsigned int tb_hash_func(unsigned long pc) | ||
126 | return pc & (CODE_GEN_HASH_SIZE - 1); | 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 | TranslationBlock *tb_alloc(unsigned long pc); | 183 | TranslationBlock *tb_alloc(unsigned long pc); |
130 | void tb_flush(CPUState *env); | 184 | void tb_flush(CPUState *env); |
131 | void tb_link(TranslationBlock *tb); | 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 | extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; | 189 | extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; |
190 | +extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | ||
134 | 191 | ||
135 | extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; | 192 | extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; |
136 | extern uint8_t *code_gen_ptr; | 193 | extern uint8_t *code_gen_ptr; |
@@ -159,8 +216,10 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, | @@ -159,8 +216,10 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, | ||
159 | return NULL; | 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 | static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) | 223 | static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) |
165 | { | 224 | { |
166 | uint32_t val, *ptr; | 225 | uint32_t val, *ptr; |
@@ -177,6 +236,14 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr | @@ -177,6 +236,14 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr | ||
177 | asm volatile ("sync" : : : "memory"); | 236 | asm volatile ("sync" : : : "memory"); |
178 | asm volatile ("isync" : : : "memory"); | 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 | static inline void tb_set_jmp_target(TranslationBlock *tb, | 248 | static inline void tb_set_jmp_target(TranslationBlock *tb, |
182 | int n, unsigned long addr) | 249 | int n, unsigned long addr) |
@@ -223,7 +290,7 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); | @@ -223,7 +290,7 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr); | ||
223 | 290 | ||
224 | #if defined(__powerpc__) | 291 | #if defined(__powerpc__) |
225 | 292 | ||
226 | -/* on PowerPC we patch the jump instruction directly */ | 293 | +/* we patch the jump instruction directly */ |
227 | #define JUMP_TB(opname, tbparam, n, eip)\ | 294 | #define JUMP_TB(opname, tbparam, n, eip)\ |
228 | do {\ | 295 | do {\ |
229 | asm volatile (".section \".data\"\n"\ | 296 | asm volatile (".section \".data\"\n"\ |
@@ -239,7 +306,28 @@ do {\ | @@ -239,7 +306,28 @@ do {\ | ||
239 | 306 | ||
240 | #define JUMP_TB2(opname, tbparam, n)\ | 307 | #define JUMP_TB2(opname, tbparam, n)\ |
241 | do {\ | 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 | } while (0) | 331 | } while (0) |
244 | 332 | ||
245 | #else | 333 | #else |
@@ -261,19 +349,11 @@ dummy_label ## n:\ | @@ -261,19 +349,11 @@ dummy_label ## n:\ | ||
261 | /* second jump to same destination 'n' */ | 349 | /* second jump to same destination 'n' */ |
262 | #define JUMP_TB2(opname, tbparam, n)\ | 350 | #define JUMP_TB2(opname, tbparam, n)\ |
263 | do {\ | 351 | do {\ |
264 | - goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\ | 352 | + goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n - 2]);\ |
265 | } while (0) | 353 | } while (0) |
266 | 354 | ||
267 | #endif | 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 | extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | 357 | extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; |
278 | extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; | 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,3 +521,26 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, | ||
441 | #undef env | 521 | #undef env |
442 | 522 | ||
443 | #endif | 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 | + |