blob: f59e1ccecf1e25d6f5a7005593344edd69764ba9 [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
bellard3ef693a2003-03-23 20:17:16 +00006 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bellard7d132992003-03-06 23:23:54 +000019 */
20#include "exec-i386.h"
21
bellarddc990652003-03-19 00:00:28 +000022//#define DEBUG_EXEC
bellard7d132992003-03-06 23:23:54 +000023#define DEBUG_FLUSH
bellard9de5e442003-03-23 16:49:39 +000024//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000025
26/* main execution loop */
27
28/* maximum total translate dcode allocated */
29#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
30//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
31#define CODE_GEN_MAX_SIZE 65536
32#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
33
34/* threshold to flush the translated code buffer */
35#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
36
37#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
38#define CODE_GEN_HASH_BITS 15
39#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
bellard6dbad632003-03-16 18:05:05 +000040
bellard7d132992003-03-06 23:23:54 +000041typedef struct TranslationBlock {
bellarddab2ed92003-03-22 15:23:14 +000042 unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
43 unsigned long cs_base; /* CS base for this block */
bellard6dbad632003-03-16 18:05:05 +000044 unsigned int flags; /* flags defining in which context the code was generated */
bellard7d132992003-03-06 23:23:54 +000045 uint8_t *tc_ptr; /* pointer to the translated code */
46 struct TranslationBlock *hash_next; /* next matching block */
47} TranslationBlock;
48
49TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
50TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
51int nb_tbs;
52
53uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
54uint8_t *code_gen_ptr;
55
bellard1b6b0292003-03-22 17:31:38 +000056/* thread support */
57
58#ifdef __powerpc__
59static inline int testandset (int *p)
60{
61 int ret;
62 __asm__ __volatile__ (
63 "0: lwarx %0,0,%1 ;"
64 " xor. %0,%3,%0;"
65 " bne 1f;"
66 " stwcx. %2,0,%1;"
67 " bne- 0b;"
68 "1: "
69 : "=&r" (ret)
70 : "r" (p), "r" (1), "r" (0)
71 : "cr0", "memory");
72 return ret;
73}
74#endif
75
76#ifdef __i386__
77static inline int testandset (int *p)
78{
79 char ret;
80 long int readval;
81
82 __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
83 : "=q" (ret), "=m" (*p), "=a" (readval)
84 : "r" (1), "m" (*p), "a" (0)
85 : "memory");
86 return ret;
87}
88#endif
89
90int global_cpu_lock = 0;
91
92void cpu_lock(void)
93{
94 while (testandset(&global_cpu_lock));
95}
96
97void cpu_unlock(void)
98{
99 global_cpu_lock = 0;
100}
101
bellard9de5e442003-03-23 16:49:39 +0000102/* exception support */
103/* NOTE: not static to force relocation generation by GCC */
104void raise_exception(int exception_index)
105{
106 /* NOTE: the register at this point must be saved by hand because
107 longjmp restore them */
108#ifdef reg_EAX
109 env->regs[R_EAX] = EAX;
110#endif
111#ifdef reg_ECX
112 env->regs[R_ECX] = ECX;
113#endif
114#ifdef reg_EDX
115 env->regs[R_EDX] = EDX;
116#endif
117#ifdef reg_EBX
118 env->regs[R_EBX] = EBX;
119#endif
120#ifdef reg_ESP
121 env->regs[R_ESP] = ESP;
122#endif
123#ifdef reg_EBP
124 env->regs[R_EBP] = EBP;
125#endif
126#ifdef reg_ESI
127 env->regs[R_ESI] = ESI;
128#endif
129#ifdef reg_EDI
130 env->regs[R_EDI] = EDI;
131#endif
132 env->exception_index = exception_index;
133 longjmp(env->jmp_env, 1);
134}
135
136#if defined(DEBUG_EXEC)
bellard7d132992003-03-06 23:23:54 +0000137static const char *cc_op_str[] = {
138 "DYNAMIC",
139 "EFLAGS",
140 "MUL",
141 "ADDB",
142 "ADDW",
143 "ADDL",
144 "ADCB",
145 "ADCW",
146 "ADCL",
147 "SUBB",
148 "SUBW",
149 "SUBL",
150 "SBBB",
151 "SBBW",
152 "SBBL",
153 "LOGICB",
154 "LOGICW",
155 "LOGICL",
156 "INCB",
157 "INCW",
158 "INCL",
159 "DECB",
160 "DECW",
161 "DECL",
162 "SHLB",
163 "SHLW",
164 "SHLL",
165 "SARB",
166 "SARW",
167 "SARL",
168};
169
bellard9de5e442003-03-23 16:49:39 +0000170static void cpu_x86_dump_state(FILE *f)
bellard7d132992003-03-06 23:23:54 +0000171{
172 int eflags;
173 eflags = cc_table[CC_OP].compute_all();
174 eflags |= (DF & DIRECTION_FLAG);
bellard9de5e442003-03-23 16:49:39 +0000175 fprintf(f,
bellard7d132992003-03-06 23:23:54 +0000176 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
177 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
bellard9de5e442003-03-23 16:49:39 +0000178 "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
179 "EIP=%08x\n",
bellard7d132992003-03-06 23:23:54 +0000180 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
181 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
182 env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
183 eflags & DIRECTION_FLAG ? 'D' : '-',
184 eflags & CC_O ? 'O' : '-',
185 eflags & CC_S ? 'S' : '-',
186 eflags & CC_Z ? 'Z' : '-',
187 eflags & CC_A ? 'A' : '-',
188 eflags & CC_P ? 'P' : '-',
bellard9de5e442003-03-23 16:49:39 +0000189 eflags & CC_C ? 'C' : '-',
190 env->eip);
bellard7d132992003-03-06 23:23:54 +0000191#if 1
bellard9de5e442003-03-23 16:49:39 +0000192 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
bellard7d132992003-03-06 23:23:54 +0000193 (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
194#endif
195}
196
197#endif
198
199void cpu_x86_tblocks_init(void)
200{
201 if (!code_gen_ptr) {
202 code_gen_ptr = code_gen_buffer;
203 }
204}
205
206/* flush all the translation blocks */
207static void tb_flush(void)
208{
209 int i;
210#ifdef DEBUG_FLUSH
211 printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
212 code_gen_ptr - code_gen_buffer,
213 nb_tbs,
214 (code_gen_ptr - code_gen_buffer) / nb_tbs);
215#endif
216 nb_tbs = 0;
217 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
218 tb_hash[i] = NULL;
219 code_gen_ptr = code_gen_buffer;
220 /* XXX: flush processor icache at this point */
221}
222
223/* find a translation block in the translation cache. If not found,
bellard9de5e442003-03-23 16:49:39 +0000224 return NULL and the pointer to the last element of the list in pptb */
225static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
226 unsigned long pc,
227 unsigned long cs_base,
228 unsigned int flags)
bellard7d132992003-03-06 23:23:54 +0000229{
230 TranslationBlock **ptb, *tb;
231 unsigned int h;
232
233 h = pc & (CODE_GEN_HASH_SIZE - 1);
234 ptb = &tb_hash[h];
235 for(;;) {
236 tb = *ptb;
237 if (!tb)
238 break;
bellarddab2ed92003-03-22 15:23:14 +0000239 if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
bellard7d132992003-03-06 23:23:54 +0000240 return tb;
241 ptb = &tb->hash_next;
242 }
bellard9de5e442003-03-23 16:49:39 +0000243 *pptb = ptb;
244 return NULL;
245}
246
247/* allocate a new translation block. flush the translation buffer if
248 too many translation blocks or too much generated code */
249static inline TranslationBlock *tb_alloc(void)
250{
251 TranslationBlock *tb;
bellard7d132992003-03-06 23:23:54 +0000252 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
253 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
254 tb_flush();
255 tb = &tbs[nb_tbs++];
bellard7d132992003-03-06 23:23:54 +0000256 return tb;
257}
258
259int cpu_x86_exec(CPUX86State *env1)
260{
261 int saved_T0, saved_T1, saved_A0;
262 CPUX86State *saved_env;
bellard04369ff2003-03-20 22:33:23 +0000263#ifdef reg_EAX
264 int saved_EAX;
265#endif
266#ifdef reg_ECX
267 int saved_ECX;
268#endif
269#ifdef reg_EDX
270 int saved_EDX;
271#endif
272#ifdef reg_EBX
273 int saved_EBX;
274#endif
275#ifdef reg_ESP
276 int saved_ESP;
277#endif
278#ifdef reg_EBP
279 int saved_EBP;
280#endif
281#ifdef reg_ESI
282 int saved_ESI;
283#endif
284#ifdef reg_EDI
285 int saved_EDI;
286#endif
bellard7d132992003-03-06 23:23:54 +0000287 int code_gen_size, ret;
288 void (*gen_func)(void);
bellard9de5e442003-03-23 16:49:39 +0000289 TranslationBlock *tb, **ptb;
bellarddab2ed92003-03-22 15:23:14 +0000290 uint8_t *tc_ptr, *cs_base, *pc;
bellard6dbad632003-03-16 18:05:05 +0000291 unsigned int flags;
292
bellard7d132992003-03-06 23:23:54 +0000293 /* first we save global registers */
294 saved_T0 = T0;
295 saved_T1 = T1;
296 saved_A0 = A0;
297 saved_env = env;
298 env = env1;
bellard04369ff2003-03-20 22:33:23 +0000299#ifdef reg_EAX
300 saved_EAX = EAX;
301 EAX = env->regs[R_EAX];
302#endif
303#ifdef reg_ECX
304 saved_ECX = ECX;
305 ECX = env->regs[R_ECX];
306#endif
307#ifdef reg_EDX
308 saved_EDX = EDX;
309 EDX = env->regs[R_EDX];
310#endif
311#ifdef reg_EBX
312 saved_EBX = EBX;
313 EBX = env->regs[R_EBX];
314#endif
315#ifdef reg_ESP
316 saved_ESP = ESP;
317 ESP = env->regs[R_ESP];
318#endif
319#ifdef reg_EBP
320 saved_EBP = EBP;
321 EBP = env->regs[R_EBP];
322#endif
323#ifdef reg_ESI
324 saved_ESI = ESI;
325 ESI = env->regs[R_ESI];
326#endif
327#ifdef reg_EDI
328 saved_EDI = EDI;
329 EDI = env->regs[R_EDI];
330#endif
bellard7d132992003-03-06 23:23:54 +0000331
bellard9de5e442003-03-23 16:49:39 +0000332 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000333 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
334 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000335 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000336 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard9de5e442003-03-23 16:49:39 +0000337 env->interrupt_request = 0;
338
bellard7d132992003-03-06 23:23:54 +0000339 /* prepare setjmp context for exception handling */
340 if (setjmp(env->jmp_env) == 0) {
341 for(;;) {
bellard9de5e442003-03-23 16:49:39 +0000342 if (env->interrupt_request) {
343 raise_exception(EXCP_INTERRUPT);
344 }
bellard7d132992003-03-06 23:23:54 +0000345#ifdef DEBUG_EXEC
346 if (loglevel) {
bellard9de5e442003-03-23 16:49:39 +0000347 cpu_x86_dump_state(logfile);
bellard7d132992003-03-06 23:23:54 +0000348 }
349#endif
bellard6dbad632003-03-16 18:05:05 +0000350 /* we compute the CPU state. We assume it will not
351 change during the whole generated block. */
352 flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
bellarddab2ed92003-03-22 15:23:14 +0000353 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
bellard6dbad632003-03-16 18:05:05 +0000354 flags |= (((unsigned long)env->seg_cache[R_DS].base |
355 (unsigned long)env->seg_cache[R_ES].base |
356 (unsigned long)env->seg_cache[R_SS].base) != 0) <<
357 GEN_FLAG_ADDSEG_SHIFT;
bellardfc2b4c42003-03-29 16:52:44 +0000358 flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
bellarddab2ed92003-03-22 15:23:14 +0000359 cs_base = env->seg_cache[R_CS].base;
360 pc = cs_base + env->eip;
bellard9de5e442003-03-23 16:49:39 +0000361 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
362 flags);
363 if (!tb) {
bellard7d132992003-03-06 23:23:54 +0000364 /* if no translated code available, then translate it now */
bellard1b6b0292003-03-22 17:31:38 +0000365 /* XXX: very inefficient: we lock all the cpus when
366 generating code */
367 cpu_lock();
bellard7d132992003-03-06 23:23:54 +0000368 tc_ptr = code_gen_ptr;
bellard9de5e442003-03-23 16:49:39 +0000369 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
370 &code_gen_size, pc, cs_base, flags);
371 /* if invalid instruction, signal it */
372 if (ret != 0) {
373 cpu_unlock();
374 raise_exception(EXCP06_ILLOP);
375 }
376 tb = tb_alloc();
377 *ptb = tb;
378 tb->pc = (unsigned long)pc;
379 tb->cs_base = (unsigned long)cs_base;
380 tb->flags = flags;
bellard7d132992003-03-06 23:23:54 +0000381 tb->tc_ptr = tc_ptr;
bellard9de5e442003-03-23 16:49:39 +0000382 tb->hash_next = NULL;
bellard7d132992003-03-06 23:23:54 +0000383 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
bellard1b6b0292003-03-22 17:31:38 +0000384 cpu_unlock();
bellard7d132992003-03-06 23:23:54 +0000385 }
386 /* execute the generated code */
bellard9de5e442003-03-23 16:49:39 +0000387 tc_ptr = tb->tc_ptr;
bellard7d132992003-03-06 23:23:54 +0000388 gen_func = (void *)tc_ptr;
389 gen_func();
390 }
391 }
392 ret = env->exception_index;
393
bellard9de5e442003-03-23 16:49:39 +0000394 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000395 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard9de5e442003-03-23 16:49:39 +0000396
bellard7d132992003-03-06 23:23:54 +0000397 /* restore global registers */
bellard04369ff2003-03-20 22:33:23 +0000398#ifdef reg_EAX
399 EAX = saved_EAX;
400#endif
401#ifdef reg_ECX
402 ECX = saved_ECX;
403#endif
404#ifdef reg_EDX
405 EDX = saved_EDX;
406#endif
407#ifdef reg_EBX
408 EBX = saved_EBX;
409#endif
410#ifdef reg_ESP
411 ESP = saved_ESP;
412#endif
413#ifdef reg_EBP
414 EBP = saved_EBP;
415#endif
416#ifdef reg_ESI
417 ESI = saved_ESI;
418#endif
419#ifdef reg_EDI
420 EDI = saved_EDI;
421#endif
bellard7d132992003-03-06 23:23:54 +0000422 T0 = saved_T0;
423 T1 = saved_T1;
424 A0 = saved_A0;
425 env = saved_env;
426 return ret;
427}
bellard6dbad632003-03-16 18:05:05 +0000428
bellard9de5e442003-03-23 16:49:39 +0000429void cpu_x86_interrupt(CPUX86State *s)
430{
431 s->interrupt_request = 1;
432}
433
434
bellard6dbad632003-03-16 18:05:05 +0000435void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
436{
437 CPUX86State *saved_env;
438
439 saved_env = env;
440 env = s;
441 load_seg(seg_reg, selector);
442 env = saved_env;
443}
bellard9de5e442003-03-23 16:49:39 +0000444
445#undef EAX
446#undef ECX
447#undef EDX
448#undef EBX
449#undef ESP
450#undef EBP
451#undef ESI
452#undef EDI
453#undef EIP
454#include <signal.h>
455#include <sys/ucontext.h>
456
457static inline int handle_cpu_signal(unsigned long pc,
458 sigset_t *old_set)
459{
460#ifdef DEBUG_SIGNAL
461 printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
462 pc, *(unsigned long *)old_set);
463#endif
464 if (pc >= (unsigned long)code_gen_buffer &&
465 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
466 /* the PC is inside the translated code. It means that we have
467 a virtual CPU fault */
468 /* we restore the process signal mask as the sigreturn should
469 do it */
470 sigprocmask(SIG_SETMASK, old_set, NULL);
471 /* XXX: need to compute virtual pc position by retranslating
472 code. The rest of the CPU state should be correct. */
473 raise_exception(EXCP0D_GPF);
474 /* never comes here */
475 return 1;
476 } else {
477 return 0;
478 }
479}
480
481int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
482 void *puc)
483{
484#if defined(__i386__)
485 struct ucontext *uc = puc;
486 unsigned long pc;
487 sigset_t *pold_set;
488
bellardd691f662003-03-24 21:58:34 +0000489#ifndef REG_EIP
490/* for glibc 2.1 */
491#define REG_EIP EIP
492#endif
bellardfc2b4c42003-03-29 16:52:44 +0000493 pc = uc->uc_mcontext.gregs[REG_EIP];
bellard9de5e442003-03-23 16:49:39 +0000494 pold_set = &uc->uc_sigmask;
495 return handle_cpu_signal(pc, pold_set);
496#else
497#warning No CPU specific signal handler: cannot handle target SIGSEGV events
498 return 0;
499#endif
500}