blob: dedcbfabd6015554d1b479ba0f9494673968df87 [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
bellardfb3e5842003-03-29 17:32:36 +000090#ifdef __s390__
91static inline int testandset (int *p)
92{
93 int ret;
94
95 __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
96 " jl 0b"
97 : "=&d" (ret)
98 : "r" (1), "a" (p), "0" (*p)
99 : "cc", "memory" );
100 return ret;
101}
102#endif
103
bellard1b6b0292003-03-22 17:31:38 +0000104int global_cpu_lock = 0;
105
106void cpu_lock(void)
107{
108 while (testandset(&global_cpu_lock));
109}
110
111void cpu_unlock(void)
112{
113 global_cpu_lock = 0;
114}
115
bellard9de5e442003-03-23 16:49:39 +0000116/* exception support */
117/* NOTE: not static to force relocation generation by GCC */
118void raise_exception(int exception_index)
119{
120 /* NOTE: the register at this point must be saved by hand because
121 longjmp restore them */
122#ifdef reg_EAX
123 env->regs[R_EAX] = EAX;
124#endif
125#ifdef reg_ECX
126 env->regs[R_ECX] = ECX;
127#endif
128#ifdef reg_EDX
129 env->regs[R_EDX] = EDX;
130#endif
131#ifdef reg_EBX
132 env->regs[R_EBX] = EBX;
133#endif
134#ifdef reg_ESP
135 env->regs[R_ESP] = ESP;
136#endif
137#ifdef reg_EBP
138 env->regs[R_EBP] = EBP;
139#endif
140#ifdef reg_ESI
141 env->regs[R_ESI] = ESI;
142#endif
143#ifdef reg_EDI
144 env->regs[R_EDI] = EDI;
145#endif
146 env->exception_index = exception_index;
147 longjmp(env->jmp_env, 1);
148}
149
150#if defined(DEBUG_EXEC)
bellard7d132992003-03-06 23:23:54 +0000151static const char *cc_op_str[] = {
152 "DYNAMIC",
153 "EFLAGS",
154 "MUL",
155 "ADDB",
156 "ADDW",
157 "ADDL",
158 "ADCB",
159 "ADCW",
160 "ADCL",
161 "SUBB",
162 "SUBW",
163 "SUBL",
164 "SBBB",
165 "SBBW",
166 "SBBL",
167 "LOGICB",
168 "LOGICW",
169 "LOGICL",
170 "INCB",
171 "INCW",
172 "INCL",
173 "DECB",
174 "DECW",
175 "DECL",
176 "SHLB",
177 "SHLW",
178 "SHLL",
179 "SARB",
180 "SARW",
181 "SARL",
182};
183
bellard9de5e442003-03-23 16:49:39 +0000184static void cpu_x86_dump_state(FILE *f)
bellard7d132992003-03-06 23:23:54 +0000185{
186 int eflags;
187 eflags = cc_table[CC_OP].compute_all();
188 eflags |= (DF & DIRECTION_FLAG);
bellard9de5e442003-03-23 16:49:39 +0000189 fprintf(f,
bellard7d132992003-03-06 23:23:54 +0000190 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
191 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
bellard9de5e442003-03-23 16:49:39 +0000192 "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
193 "EIP=%08x\n",
bellard7d132992003-03-06 23:23:54 +0000194 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
195 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
196 env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
197 eflags & DIRECTION_FLAG ? 'D' : '-',
198 eflags & CC_O ? 'O' : '-',
199 eflags & CC_S ? 'S' : '-',
200 eflags & CC_Z ? 'Z' : '-',
201 eflags & CC_A ? 'A' : '-',
202 eflags & CC_P ? 'P' : '-',
bellard9de5e442003-03-23 16:49:39 +0000203 eflags & CC_C ? 'C' : '-',
204 env->eip);
bellard7d132992003-03-06 23:23:54 +0000205#if 1
bellard9de5e442003-03-23 16:49:39 +0000206 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
bellard7d132992003-03-06 23:23:54 +0000207 (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
208#endif
209}
210
211#endif
212
213void cpu_x86_tblocks_init(void)
214{
215 if (!code_gen_ptr) {
216 code_gen_ptr = code_gen_buffer;
217 }
218}
219
220/* flush all the translation blocks */
221static void tb_flush(void)
222{
223 int i;
224#ifdef DEBUG_FLUSH
225 printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
226 code_gen_ptr - code_gen_buffer,
227 nb_tbs,
228 (code_gen_ptr - code_gen_buffer) / nb_tbs);
229#endif
230 nb_tbs = 0;
231 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
232 tb_hash[i] = NULL;
233 code_gen_ptr = code_gen_buffer;
234 /* XXX: flush processor icache at this point */
235}
236
237/* find a translation block in the translation cache. If not found,
bellard9de5e442003-03-23 16:49:39 +0000238 return NULL and the pointer to the last element of the list in pptb */
239static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
240 unsigned long pc,
241 unsigned long cs_base,
242 unsigned int flags)
bellard7d132992003-03-06 23:23:54 +0000243{
244 TranslationBlock **ptb, *tb;
245 unsigned int h;
246
247 h = pc & (CODE_GEN_HASH_SIZE - 1);
248 ptb = &tb_hash[h];
249 for(;;) {
250 tb = *ptb;
251 if (!tb)
252 break;
bellarddab2ed92003-03-22 15:23:14 +0000253 if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
bellard7d132992003-03-06 23:23:54 +0000254 return tb;
255 ptb = &tb->hash_next;
256 }
bellard9de5e442003-03-23 16:49:39 +0000257 *pptb = ptb;
258 return NULL;
259}
260
261/* allocate a new translation block. flush the translation buffer if
262 too many translation blocks or too much generated code */
263static inline TranslationBlock *tb_alloc(void)
264{
265 TranslationBlock *tb;
bellard7d132992003-03-06 23:23:54 +0000266 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
267 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
268 tb_flush();
269 tb = &tbs[nb_tbs++];
bellard7d132992003-03-06 23:23:54 +0000270 return tb;
271}
272
273int cpu_x86_exec(CPUX86State *env1)
274{
275 int saved_T0, saved_T1, saved_A0;
276 CPUX86State *saved_env;
bellard04369ff2003-03-20 22:33:23 +0000277#ifdef reg_EAX
278 int saved_EAX;
279#endif
280#ifdef reg_ECX
281 int saved_ECX;
282#endif
283#ifdef reg_EDX
284 int saved_EDX;
285#endif
286#ifdef reg_EBX
287 int saved_EBX;
288#endif
289#ifdef reg_ESP
290 int saved_ESP;
291#endif
292#ifdef reg_EBP
293 int saved_EBP;
294#endif
295#ifdef reg_ESI
296 int saved_ESI;
297#endif
298#ifdef reg_EDI
299 int saved_EDI;
300#endif
bellard7d132992003-03-06 23:23:54 +0000301 int code_gen_size, ret;
302 void (*gen_func)(void);
bellard9de5e442003-03-23 16:49:39 +0000303 TranslationBlock *tb, **ptb;
bellarddab2ed92003-03-22 15:23:14 +0000304 uint8_t *tc_ptr, *cs_base, *pc;
bellard6dbad632003-03-16 18:05:05 +0000305 unsigned int flags;
306
bellard7d132992003-03-06 23:23:54 +0000307 /* first we save global registers */
308 saved_T0 = T0;
309 saved_T1 = T1;
310 saved_A0 = A0;
311 saved_env = env;
312 env = env1;
bellard04369ff2003-03-20 22:33:23 +0000313#ifdef reg_EAX
314 saved_EAX = EAX;
315 EAX = env->regs[R_EAX];
316#endif
317#ifdef reg_ECX
318 saved_ECX = ECX;
319 ECX = env->regs[R_ECX];
320#endif
321#ifdef reg_EDX
322 saved_EDX = EDX;
323 EDX = env->regs[R_EDX];
324#endif
325#ifdef reg_EBX
326 saved_EBX = EBX;
327 EBX = env->regs[R_EBX];
328#endif
329#ifdef reg_ESP
330 saved_ESP = ESP;
331 ESP = env->regs[R_ESP];
332#endif
333#ifdef reg_EBP
334 saved_EBP = EBP;
335 EBP = env->regs[R_EBP];
336#endif
337#ifdef reg_ESI
338 saved_ESI = ESI;
339 ESI = env->regs[R_ESI];
340#endif
341#ifdef reg_EDI
342 saved_EDI = EDI;
343 EDI = env->regs[R_EDI];
344#endif
bellard7d132992003-03-06 23:23:54 +0000345
bellard9de5e442003-03-23 16:49:39 +0000346 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000347 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
348 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000349 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000350 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard9de5e442003-03-23 16:49:39 +0000351 env->interrupt_request = 0;
352
bellard7d132992003-03-06 23:23:54 +0000353 /* prepare setjmp context for exception handling */
354 if (setjmp(env->jmp_env) == 0) {
355 for(;;) {
bellard9de5e442003-03-23 16:49:39 +0000356 if (env->interrupt_request) {
357 raise_exception(EXCP_INTERRUPT);
358 }
bellard7d132992003-03-06 23:23:54 +0000359#ifdef DEBUG_EXEC
360 if (loglevel) {
bellard9de5e442003-03-23 16:49:39 +0000361 cpu_x86_dump_state(logfile);
bellard7d132992003-03-06 23:23:54 +0000362 }
363#endif
bellard6dbad632003-03-16 18:05:05 +0000364 /* we compute the CPU state. We assume it will not
365 change during the whole generated block. */
366 flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
bellarddab2ed92003-03-22 15:23:14 +0000367 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
bellard6dbad632003-03-16 18:05:05 +0000368 flags |= (((unsigned long)env->seg_cache[R_DS].base |
369 (unsigned long)env->seg_cache[R_ES].base |
370 (unsigned long)env->seg_cache[R_SS].base) != 0) <<
371 GEN_FLAG_ADDSEG_SHIFT;
bellardfc2b4c42003-03-29 16:52:44 +0000372 flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
bellarddab2ed92003-03-22 15:23:14 +0000373 cs_base = env->seg_cache[R_CS].base;
374 pc = cs_base + env->eip;
bellard9de5e442003-03-23 16:49:39 +0000375 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
376 flags);
377 if (!tb) {
bellard7d132992003-03-06 23:23:54 +0000378 /* if no translated code available, then translate it now */
bellard1b6b0292003-03-22 17:31:38 +0000379 /* XXX: very inefficient: we lock all the cpus when
380 generating code */
381 cpu_lock();
bellard7d132992003-03-06 23:23:54 +0000382 tc_ptr = code_gen_ptr;
bellard9de5e442003-03-23 16:49:39 +0000383 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
384 &code_gen_size, pc, cs_base, flags);
385 /* if invalid instruction, signal it */
386 if (ret != 0) {
387 cpu_unlock();
388 raise_exception(EXCP06_ILLOP);
389 }
390 tb = tb_alloc();
391 *ptb = tb;
392 tb->pc = (unsigned long)pc;
393 tb->cs_base = (unsigned long)cs_base;
394 tb->flags = flags;
bellard7d132992003-03-06 23:23:54 +0000395 tb->tc_ptr = tc_ptr;
bellard9de5e442003-03-23 16:49:39 +0000396 tb->hash_next = NULL;
bellard7d132992003-03-06 23:23:54 +0000397 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 +0000398 cpu_unlock();
bellard7d132992003-03-06 23:23:54 +0000399 }
400 /* execute the generated code */
bellard9de5e442003-03-23 16:49:39 +0000401 tc_ptr = tb->tc_ptr;
bellard7d132992003-03-06 23:23:54 +0000402 gen_func = (void *)tc_ptr;
403 gen_func();
404 }
405 }
406 ret = env->exception_index;
407
bellard9de5e442003-03-23 16:49:39 +0000408 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000409 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard9de5e442003-03-23 16:49:39 +0000410
bellard7d132992003-03-06 23:23:54 +0000411 /* restore global registers */
bellard04369ff2003-03-20 22:33:23 +0000412#ifdef reg_EAX
413 EAX = saved_EAX;
414#endif
415#ifdef reg_ECX
416 ECX = saved_ECX;
417#endif
418#ifdef reg_EDX
419 EDX = saved_EDX;
420#endif
421#ifdef reg_EBX
422 EBX = saved_EBX;
423#endif
424#ifdef reg_ESP
425 ESP = saved_ESP;
426#endif
427#ifdef reg_EBP
428 EBP = saved_EBP;
429#endif
430#ifdef reg_ESI
431 ESI = saved_ESI;
432#endif
433#ifdef reg_EDI
434 EDI = saved_EDI;
435#endif
bellard7d132992003-03-06 23:23:54 +0000436 T0 = saved_T0;
437 T1 = saved_T1;
438 A0 = saved_A0;
439 env = saved_env;
440 return ret;
441}
bellard6dbad632003-03-16 18:05:05 +0000442
bellard9de5e442003-03-23 16:49:39 +0000443void cpu_x86_interrupt(CPUX86State *s)
444{
445 s->interrupt_request = 1;
446}
447
448
bellard6dbad632003-03-16 18:05:05 +0000449void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
450{
451 CPUX86State *saved_env;
452
453 saved_env = env;
454 env = s;
455 load_seg(seg_reg, selector);
456 env = saved_env;
457}
bellard9de5e442003-03-23 16:49:39 +0000458
459#undef EAX
460#undef ECX
461#undef EDX
462#undef EBX
463#undef ESP
464#undef EBP
465#undef ESI
466#undef EDI
467#undef EIP
468#include <signal.h>
469#include <sys/ucontext.h>
470
471static inline int handle_cpu_signal(unsigned long pc,
472 sigset_t *old_set)
473{
474#ifdef DEBUG_SIGNAL
475 printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
476 pc, *(unsigned long *)old_set);
477#endif
478 if (pc >= (unsigned long)code_gen_buffer &&
479 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
480 /* the PC is inside the translated code. It means that we have
481 a virtual CPU fault */
482 /* we restore the process signal mask as the sigreturn should
483 do it */
484 sigprocmask(SIG_SETMASK, old_set, NULL);
485 /* XXX: need to compute virtual pc position by retranslating
486 code. The rest of the CPU state should be correct. */
487 raise_exception(EXCP0D_GPF);
488 /* never comes here */
489 return 1;
490 } else {
491 return 0;
492 }
493}
494
495int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
496 void *puc)
497{
498#if defined(__i386__)
499 struct ucontext *uc = puc;
500 unsigned long pc;
501 sigset_t *pold_set;
502
bellardd691f662003-03-24 21:58:34 +0000503#ifndef REG_EIP
504/* for glibc 2.1 */
505#define REG_EIP EIP
506#endif
bellardfc2b4c42003-03-29 16:52:44 +0000507 pc = uc->uc_mcontext.gregs[REG_EIP];
bellard9de5e442003-03-23 16:49:39 +0000508 pold_set = &uc->uc_sigmask;
509 return handle_cpu_signal(pc, pold_set);
510#else
511#warning No CPU specific signal handler: cannot handle target SIGSEGV events
512 return 0;
513#endif
514}