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 | + | ... | ... |