blob: b75c6c70a0012b3ebef0a39f62a5fc06b818d234 [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"
bellard956034d2003-04-29 20:40:53 +000021#include "disas.h"
bellard7d132992003-03-06 23:23:54 +000022
bellarddc990652003-03-19 00:00:28 +000023//#define DEBUG_EXEC
bellard7d132992003-03-06 23:23:54 +000024#define DEBUG_FLUSH
bellard9de5e442003-03-23 16:49:39 +000025//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000026
27/* main execution loop */
28
29/* maximum total translate dcode allocated */
30#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
31//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
32#define CODE_GEN_MAX_SIZE 65536
33#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
34
35/* threshold to flush the translated code buffer */
36#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
37
38#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
39#define CODE_GEN_HASH_BITS 15
40#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
bellard6dbad632003-03-16 18:05:05 +000041
bellard7d132992003-03-06 23:23:54 +000042typedef struct TranslationBlock {
bellarddab2ed92003-03-22 15:23:14 +000043 unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
44 unsigned long cs_base; /* CS base for this block */
bellard6dbad632003-03-16 18:05:05 +000045 unsigned int flags; /* flags defining in which context the code was generated */
bellard7d132992003-03-06 23:23:54 +000046 uint8_t *tc_ptr; /* pointer to the translated code */
47 struct TranslationBlock *hash_next; /* next matching block */
48} TranslationBlock;
49
50TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
51TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
52int nb_tbs;
53
54uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
55uint8_t *code_gen_ptr;
56
bellard1b6b0292003-03-22 17:31:38 +000057/* thread support */
58
59#ifdef __powerpc__
60static inline int testandset (int *p)
61{
62 int ret;
63 __asm__ __volatile__ (
64 "0: lwarx %0,0,%1 ;"
65 " xor. %0,%3,%0;"
66 " bne 1f;"
67 " stwcx. %2,0,%1;"
68 " bne- 0b;"
69 "1: "
70 : "=&r" (ret)
71 : "r" (p), "r" (1), "r" (0)
72 : "cr0", "memory");
73 return ret;
74}
75#endif
76
77#ifdef __i386__
78static inline int testandset (int *p)
79{
80 char ret;
81 long int readval;
82
83 __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
84 : "=q" (ret), "=m" (*p), "=a" (readval)
85 : "r" (1), "m" (*p), "a" (0)
86 : "memory");
87 return ret;
88}
89#endif
90
bellardfb3e5842003-03-29 17:32:36 +000091#ifdef __s390__
92static inline int testandset (int *p)
93{
94 int ret;
95
96 __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
97 " jl 0b"
98 : "=&d" (ret)
99 : "r" (1), "a" (p), "0" (*p)
100 : "cc", "memory" );
101 return ret;
102}
103#endif
104
bellard1b6b0292003-03-22 17:31:38 +0000105int global_cpu_lock = 0;
106
107void cpu_lock(void)
108{
109 while (testandset(&global_cpu_lock));
110}
111
112void cpu_unlock(void)
113{
114 global_cpu_lock = 0;
115}
116
bellard9de5e442003-03-23 16:49:39 +0000117/* exception support */
118/* NOTE: not static to force relocation generation by GCC */
119void raise_exception(int exception_index)
120{
121 /* NOTE: the register at this point must be saved by hand because
122 longjmp restore them */
123#ifdef reg_EAX
124 env->regs[R_EAX] = EAX;
125#endif
126#ifdef reg_ECX
127 env->regs[R_ECX] = ECX;
128#endif
129#ifdef reg_EDX
130 env->regs[R_EDX] = EDX;
131#endif
132#ifdef reg_EBX
133 env->regs[R_EBX] = EBX;
134#endif
135#ifdef reg_ESP
136 env->regs[R_ESP] = ESP;
137#endif
138#ifdef reg_EBP
139 env->regs[R_EBP] = EBP;
140#endif
141#ifdef reg_ESI
142 env->regs[R_ESI] = ESI;
143#endif
144#ifdef reg_EDI
145 env->regs[R_EDI] = EDI;
146#endif
147 env->exception_index = exception_index;
148 longjmp(env->jmp_env, 1);
149}
150
151#if defined(DEBUG_EXEC)
bellard7d132992003-03-06 23:23:54 +0000152static const char *cc_op_str[] = {
153 "DYNAMIC",
154 "EFLAGS",
155 "MUL",
156 "ADDB",
157 "ADDW",
158 "ADDL",
159 "ADCB",
160 "ADCW",
161 "ADCL",
162 "SUBB",
163 "SUBW",
164 "SUBL",
165 "SBBB",
166 "SBBW",
167 "SBBL",
168 "LOGICB",
169 "LOGICW",
170 "LOGICL",
171 "INCB",
172 "INCW",
173 "INCL",
174 "DECB",
175 "DECW",
176 "DECL",
177 "SHLB",
178 "SHLW",
179 "SHLL",
180 "SARB",
181 "SARW",
182 "SARL",
183};
184
bellard9de5e442003-03-23 16:49:39 +0000185static void cpu_x86_dump_state(FILE *f)
bellard7d132992003-03-06 23:23:54 +0000186{
187 int eflags;
188 eflags = cc_table[CC_OP].compute_all();
bellard956034d2003-04-29 20:40:53 +0000189 eflags |= (DF & DF_MASK);
bellard9de5e442003-03-23 16:49:39 +0000190 fprintf(f,
bellard7d132992003-03-06 23:23:54 +0000191 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
192 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
bellard9de5e442003-03-23 16:49:39 +0000193 "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
194 "EIP=%08x\n",
bellard7d132992003-03-06 23:23:54 +0000195 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
196 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
197 env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
bellard956034d2003-04-29 20:40:53 +0000198 eflags & DF_MASK ? 'D' : '-',
bellard7d132992003-03-06 23:23:54 +0000199 eflags & CC_O ? 'O' : '-',
200 eflags & CC_S ? 'S' : '-',
201 eflags & CC_Z ? 'Z' : '-',
202 eflags & CC_A ? 'A' : '-',
203 eflags & CC_P ? 'P' : '-',
bellard9de5e442003-03-23 16:49:39 +0000204 eflags & CC_C ? 'C' : '-',
205 env->eip);
bellard7d132992003-03-06 23:23:54 +0000206#if 1
bellard9de5e442003-03-23 16:49:39 +0000207 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
bellard7d132992003-03-06 23:23:54 +0000208 (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
209#endif
210}
211
212#endif
213
214void cpu_x86_tblocks_init(void)
215{
216 if (!code_gen_ptr) {
217 code_gen_ptr = code_gen_buffer;
218 }
219}
220
221/* flush all the translation blocks */
222static void tb_flush(void)
223{
224 int i;
225#ifdef DEBUG_FLUSH
226 printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
227 code_gen_ptr - code_gen_buffer,
228 nb_tbs,
229 (code_gen_ptr - code_gen_buffer) / nb_tbs);
230#endif
231 nb_tbs = 0;
232 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
233 tb_hash[i] = NULL;
234 code_gen_ptr = code_gen_buffer;
235 /* XXX: flush processor icache at this point */
236}
237
238/* find a translation block in the translation cache. If not found,
bellard9de5e442003-03-23 16:49:39 +0000239 return NULL and the pointer to the last element of the list in pptb */
240static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
241 unsigned long pc,
242 unsigned long cs_base,
243 unsigned int flags)
bellard7d132992003-03-06 23:23:54 +0000244{
245 TranslationBlock **ptb, *tb;
246 unsigned int h;
247
248 h = pc & (CODE_GEN_HASH_SIZE - 1);
249 ptb = &tb_hash[h];
250 for(;;) {
251 tb = *ptb;
252 if (!tb)
253 break;
bellarddab2ed92003-03-22 15:23:14 +0000254 if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
bellard7d132992003-03-06 23:23:54 +0000255 return tb;
256 ptb = &tb->hash_next;
257 }
bellard9de5e442003-03-23 16:49:39 +0000258 *pptb = ptb;
259 return NULL;
260}
261
262/* allocate a new translation block. flush the translation buffer if
263 too many translation blocks or too much generated code */
264static inline TranslationBlock *tb_alloc(void)
265{
266 TranslationBlock *tb;
bellard7d132992003-03-06 23:23:54 +0000267 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
268 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
269 tb_flush();
270 tb = &tbs[nb_tbs++];
bellard7d132992003-03-06 23:23:54 +0000271 return tb;
272}
273
274int cpu_x86_exec(CPUX86State *env1)
275{
276 int saved_T0, saved_T1, saved_A0;
277 CPUX86State *saved_env;
bellard04369ff2003-03-20 22:33:23 +0000278#ifdef reg_EAX
279 int saved_EAX;
280#endif
281#ifdef reg_ECX
282 int saved_ECX;
283#endif
284#ifdef reg_EDX
285 int saved_EDX;
286#endif
287#ifdef reg_EBX
288 int saved_EBX;
289#endif
290#ifdef reg_ESP
291 int saved_ESP;
292#endif
293#ifdef reg_EBP
294 int saved_EBP;
295#endif
296#ifdef reg_ESI
297 int saved_ESI;
298#endif
299#ifdef reg_EDI
300 int saved_EDI;
301#endif
bellard7d132992003-03-06 23:23:54 +0000302 int code_gen_size, ret;
303 void (*gen_func)(void);
bellard9de5e442003-03-23 16:49:39 +0000304 TranslationBlock *tb, **ptb;
bellarddab2ed92003-03-22 15:23:14 +0000305 uint8_t *tc_ptr, *cs_base, *pc;
bellard6dbad632003-03-16 18:05:05 +0000306 unsigned int flags;
307
bellard7d132992003-03-06 23:23:54 +0000308 /* first we save global registers */
309 saved_T0 = T0;
310 saved_T1 = T1;
311 saved_A0 = A0;
312 saved_env = env;
313 env = env1;
bellard04369ff2003-03-20 22:33:23 +0000314#ifdef reg_EAX
315 saved_EAX = EAX;
316 EAX = env->regs[R_EAX];
317#endif
318#ifdef reg_ECX
319 saved_ECX = ECX;
320 ECX = env->regs[R_ECX];
321#endif
322#ifdef reg_EDX
323 saved_EDX = EDX;
324 EDX = env->regs[R_EDX];
325#endif
326#ifdef reg_EBX
327 saved_EBX = EBX;
328 EBX = env->regs[R_EBX];
329#endif
330#ifdef reg_ESP
331 saved_ESP = ESP;
332 ESP = env->regs[R_ESP];
333#endif
334#ifdef reg_EBP
335 saved_EBP = EBP;
336 EBP = env->regs[R_EBP];
337#endif
338#ifdef reg_ESI
339 saved_ESI = ESI;
340 ESI = env->regs[R_ESI];
341#endif
342#ifdef reg_EDI
343 saved_EDI = EDI;
344 EDI = env->regs[R_EDI];
345#endif
bellard7d132992003-03-06 23:23:54 +0000346
bellard9de5e442003-03-23 16:49:39 +0000347 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000348 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
349 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000350 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000351 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard9de5e442003-03-23 16:49:39 +0000352 env->interrupt_request = 0;
353
bellard7d132992003-03-06 23:23:54 +0000354 /* prepare setjmp context for exception handling */
355 if (setjmp(env->jmp_env) == 0) {
356 for(;;) {
bellard9de5e442003-03-23 16:49:39 +0000357 if (env->interrupt_request) {
358 raise_exception(EXCP_INTERRUPT);
359 }
bellard7d132992003-03-06 23:23:54 +0000360#ifdef DEBUG_EXEC
361 if (loglevel) {
bellard9de5e442003-03-23 16:49:39 +0000362 cpu_x86_dump_state(logfile);
bellard7d132992003-03-06 23:23:54 +0000363 }
364#endif
bellard6dbad632003-03-16 18:05:05 +0000365 /* we compute the CPU state. We assume it will not
366 change during the whole generated block. */
367 flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
bellarddab2ed92003-03-22 15:23:14 +0000368 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
bellard6dbad632003-03-16 18:05:05 +0000369 flags |= (((unsigned long)env->seg_cache[R_DS].base |
370 (unsigned long)env->seg_cache[R_ES].base |
371 (unsigned long)env->seg_cache[R_SS].base) != 0) <<
372 GEN_FLAG_ADDSEG_SHIFT;
bellardfc2b4c42003-03-29 16:52:44 +0000373 flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
bellarddab2ed92003-03-22 15:23:14 +0000374 cs_base = env->seg_cache[R_CS].base;
375 pc = cs_base + env->eip;
bellard9de5e442003-03-23 16:49:39 +0000376 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
377 flags);
378 if (!tb) {
bellard7d132992003-03-06 23:23:54 +0000379 /* if no translated code available, then translate it now */
bellard1b6b0292003-03-22 17:31:38 +0000380 /* XXX: very inefficient: we lock all the cpus when
381 generating code */
382 cpu_lock();
bellard7d132992003-03-06 23:23:54 +0000383 tc_ptr = code_gen_ptr;
bellard9de5e442003-03-23 16:49:39 +0000384 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
385 &code_gen_size, pc, cs_base, flags);
386 /* if invalid instruction, signal it */
387 if (ret != 0) {
388 cpu_unlock();
389 raise_exception(EXCP06_ILLOP);
390 }
391 tb = tb_alloc();
392 *ptb = tb;
393 tb->pc = (unsigned long)pc;
394 tb->cs_base = (unsigned long)cs_base;
395 tb->flags = flags;
bellard7d132992003-03-06 23:23:54 +0000396 tb->tc_ptr = tc_ptr;
bellard9de5e442003-03-23 16:49:39 +0000397 tb->hash_next = NULL;
bellard7d132992003-03-06 23:23:54 +0000398 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 +0000399 cpu_unlock();
bellard7d132992003-03-06 23:23:54 +0000400 }
bellard956034d2003-04-29 20:40:53 +0000401 if (loglevel) {
402 fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
403 (long)tb->tc_ptr, (long)tb->pc,
404 lookup_symbol((void *)tb->pc));
405 fflush(logfile);
406 }
bellard7d132992003-03-06 23:23:54 +0000407 /* execute the generated code */
bellard9de5e442003-03-23 16:49:39 +0000408 tc_ptr = tb->tc_ptr;
bellard7d132992003-03-06 23:23:54 +0000409 gen_func = (void *)tc_ptr;
410 gen_func();
411 }
412 }
413 ret = env->exception_index;
414
bellard9de5e442003-03-23 16:49:39 +0000415 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000416 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard9de5e442003-03-23 16:49:39 +0000417
bellard7d132992003-03-06 23:23:54 +0000418 /* restore global registers */
bellard04369ff2003-03-20 22:33:23 +0000419#ifdef reg_EAX
420 EAX = saved_EAX;
421#endif
422#ifdef reg_ECX
423 ECX = saved_ECX;
424#endif
425#ifdef reg_EDX
426 EDX = saved_EDX;
427#endif
428#ifdef reg_EBX
429 EBX = saved_EBX;
430#endif
431#ifdef reg_ESP
432 ESP = saved_ESP;
433#endif
434#ifdef reg_EBP
435 EBP = saved_EBP;
436#endif
437#ifdef reg_ESI
438 ESI = saved_ESI;
439#endif
440#ifdef reg_EDI
441 EDI = saved_EDI;
442#endif
bellard7d132992003-03-06 23:23:54 +0000443 T0 = saved_T0;
444 T1 = saved_T1;
445 A0 = saved_A0;
446 env = saved_env;
447 return ret;
448}
bellard6dbad632003-03-16 18:05:05 +0000449
bellard9de5e442003-03-23 16:49:39 +0000450void cpu_x86_interrupt(CPUX86State *s)
451{
452 s->interrupt_request = 1;
453}
454
455
bellard6dbad632003-03-16 18:05:05 +0000456void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
457{
458 CPUX86State *saved_env;
459
460 saved_env = env;
461 env = s;
462 load_seg(seg_reg, selector);
463 env = saved_env;
464}
bellard9de5e442003-03-23 16:49:39 +0000465
466#undef EAX
467#undef ECX
468#undef EDX
469#undef EBX
470#undef ESP
471#undef EBP
472#undef ESI
473#undef EDI
474#undef EIP
475#include <signal.h>
476#include <sys/ucontext.h>
477
478static inline int handle_cpu_signal(unsigned long pc,
479 sigset_t *old_set)
480{
481#ifdef DEBUG_SIGNAL
482 printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
483 pc, *(unsigned long *)old_set);
484#endif
485 if (pc >= (unsigned long)code_gen_buffer &&
486 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
487 /* the PC is inside the translated code. It means that we have
488 a virtual CPU fault */
489 /* we restore the process signal mask as the sigreturn should
490 do it */
491 sigprocmask(SIG_SETMASK, old_set, NULL);
492 /* XXX: need to compute virtual pc position by retranslating
493 code. The rest of the CPU state should be correct. */
494 raise_exception(EXCP0D_GPF);
495 /* never comes here */
496 return 1;
497 } else {
498 return 0;
499 }
500}
501
502int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
503 void *puc)
504{
505#if defined(__i386__)
506 struct ucontext *uc = puc;
507 unsigned long pc;
508 sigset_t *pold_set;
509
bellardd691f662003-03-24 21:58:34 +0000510#ifndef REG_EIP
511/* for glibc 2.1 */
512#define REG_EIP EIP
513#endif
bellardfc2b4c42003-03-29 16:52:44 +0000514 pc = uc->uc_mcontext.gregs[REG_EIP];
bellard9de5e442003-03-23 16:49:39 +0000515 pold_set = &uc->uc_sigmask;
516 return handle_cpu_signal(pc, pold_set);
517#else
518#warning No CPU specific signal handler: cannot handle target SIGSEGV events
519 return 0;
520#endif
521}