]> Git Repo - qemu.git/blame - exec-i386.c
fixed GPF generation - fixed 'lret im' instruction (main fix for dosemu) - fixed...
[qemu.git] / exec-i386.c
CommitLineData
7d13299d
FB
1/*
2 * i386 emulator main execution loop
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
3ef693a0
FB
6 * 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.
7d13299d 10 *
3ef693a0
FB
11 * 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.
7d13299d 15 *
3ef693a0
FB
16 * 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
7d13299d
FB
19 */
20#include "exec-i386.h"
956034d7 21#include "disas.h"
7d13299d 22
dc99065b 23//#define DEBUG_EXEC
7d13299d 24#define DEBUG_FLUSH
9de5e440 25//#define DEBUG_SIGNAL
7d13299d
FB
26
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)
6dbad63e 41
7d13299d 42typedef struct TranslationBlock {
dab2ed99
FB
43 unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
44 unsigned long cs_base; /* CS base for this block */
6dbad63e 45 unsigned int flags; /* flags defining in which context the code was generated */
7d13299d
FB
46 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
1b6b029e
FB
57/* 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
fb3e5849
FB
91#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
e026db58
FB
105#ifdef __alpha__
106int testandset (int *p)
107{
108 int ret;
109 unsigned long one;
110
111 __asm__ __volatile__ ("0: mov 1,%2\n"
112 " ldl_l %0,%1\n"
113 " stl_c %2,%1\n"
114 " beq %2,1f\n"
115 ".subsection 2\n"
116 "1: br 0b\n"
117 ".previous"
118 : "=r" (ret), "=m" (*p), "=r" (one)
119 : "m" (*p));
120 return ret;
121}
122#endif
123
d014c98c
FB
124#ifdef __sparc__
125static inline int testandset (int *p)
126{
127 int ret;
128
129 __asm__ __volatile__("ldstub [%1], %0"
130 : "=r" (ret)
131 : "r" (p)
132 : "memory");
133
134 return (ret ? 1 : 0);
135}
136#endif
137
1b6b029e
FB
138int global_cpu_lock = 0;
139
140void cpu_lock(void)
141{
142 while (testandset(&global_cpu_lock));
143}
144
145void cpu_unlock(void)
146{
147 global_cpu_lock = 0;
148}
149
9de5e440
FB
150/* exception support */
151/* NOTE: not static to force relocation generation by GCC */
b56dad1c 152void raise_exception_err(int exception_index, int error_code)
9de5e440
FB
153{
154 /* NOTE: the register at this point must be saved by hand because
155 longjmp restore them */
156#ifdef reg_EAX
157 env->regs[R_EAX] = EAX;
158#endif
159#ifdef reg_ECX
160 env->regs[R_ECX] = ECX;
161#endif
162#ifdef reg_EDX
163 env->regs[R_EDX] = EDX;
164#endif
165#ifdef reg_EBX
166 env->regs[R_EBX] = EBX;
167#endif
168#ifdef reg_ESP
169 env->regs[R_ESP] = ESP;
170#endif
171#ifdef reg_EBP
172 env->regs[R_EBP] = EBP;
173#endif
174#ifdef reg_ESI
175 env->regs[R_ESI] = ESI;
176#endif
177#ifdef reg_EDI
178 env->regs[R_EDI] = EDI;
179#endif
180 env->exception_index = exception_index;
b56dad1c 181 env->error_code = error_code;
9de5e440
FB
182 longjmp(env->jmp_env, 1);
183}
184
b56dad1c
FB
185/* short cut if error_code is 0 or not present */
186void raise_exception(int exception_index)
187{
188 raise_exception_err(exception_index, 0);
189}
190
9de5e440 191#if defined(DEBUG_EXEC)
7d13299d
FB
192static const char *cc_op_str[] = {
193 "DYNAMIC",
194 "EFLAGS",
195 "MUL",
196 "ADDB",
197 "ADDW",
198 "ADDL",
199 "ADCB",
200 "ADCW",
201 "ADCL",
202 "SUBB",
203 "SUBW",
204 "SUBL",
205 "SBBB",
206 "SBBW",
207 "SBBL",
208 "LOGICB",
209 "LOGICW",
210 "LOGICL",
211 "INCB",
212 "INCW",
213 "INCL",
214 "DECB",
215 "DECW",
216 "DECL",
217 "SHLB",
218 "SHLW",
219 "SHLL",
220 "SARB",
221 "SARW",
222 "SARL",
223};
224
9de5e440 225static void cpu_x86_dump_state(FILE *f)
7d13299d
FB
226{
227 int eflags;
b56dad1c 228 char cc_op_name[32];
7d13299d 229 eflags = cc_table[CC_OP].compute_all();
956034d7 230 eflags |= (DF & DF_MASK);
b56dad1c
FB
231 if ((unsigned)env->cc_op < CC_OP_NB)
232 strcpy(cc_op_name, cc_op_str[env->cc_op]);
233 else
234 snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
9de5e440 235 fprintf(f,
7d13299d
FB
236 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
237 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
9de5e440
FB
238 "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
239 "EIP=%08x\n",
7d13299d
FB
240 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
241 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
b56dad1c 242 env->cc_src, env->cc_dst, cc_op_name,
956034d7 243 eflags & DF_MASK ? 'D' : '-',
7d13299d
FB
244 eflags & CC_O ? 'O' : '-',
245 eflags & CC_S ? 'S' : '-',
246 eflags & CC_Z ? 'Z' : '-',
247 eflags & CC_A ? 'A' : '-',
248 eflags & CC_P ? 'P' : '-',
9de5e440
FB
249 eflags & CC_C ? 'C' : '-',
250 env->eip);
7d13299d 251#if 1
9de5e440 252 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
7d13299d
FB
253 (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
254#endif
255}
256
257#endif
258
259void cpu_x86_tblocks_init(void)
260{
261 if (!code_gen_ptr) {
262 code_gen_ptr = code_gen_buffer;
263 }
264}
265
266/* flush all the translation blocks */
267static void tb_flush(void)
268{
269 int i;
270#ifdef DEBUG_FLUSH
271 printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
272 code_gen_ptr - code_gen_buffer,
273 nb_tbs,
274 (code_gen_ptr - code_gen_buffer) / nb_tbs);
275#endif
276 nb_tbs = 0;
277 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
278 tb_hash[i] = NULL;
279 code_gen_ptr = code_gen_buffer;
280 /* XXX: flush processor icache at this point */
281}
282
283/* find a translation block in the translation cache. If not found,
9de5e440
FB
284 return NULL and the pointer to the last element of the list in pptb */
285static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
286 unsigned long pc,
287 unsigned long cs_base,
288 unsigned int flags)
7d13299d
FB
289{
290 TranslationBlock **ptb, *tb;
291 unsigned int h;
292
293 h = pc & (CODE_GEN_HASH_SIZE - 1);
294 ptb = &tb_hash[h];
b56dad1c
FB
295#if 0
296 /* XXX: hack to handle 16 bit modyfing code */
297 if (flags & (1 << GEN_FLAG_CODE32_SHIFT))
298#endif
299 for(;;) {
300 tb = *ptb;
301 if (!tb)
302 break;
303 if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
7d13299d 304 return tb;
b56dad1c
FB
305 ptb = &tb->hash_next;
306 }
9de5e440
FB
307 *pptb = ptb;
308 return NULL;
309}
310
311/* allocate a new translation block. flush the translation buffer if
312 too many translation blocks or too much generated code */
313static inline TranslationBlock *tb_alloc(void)
314{
315 TranslationBlock *tb;
7d13299d
FB
316 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
317 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
318 tb_flush();
319 tb = &tbs[nb_tbs++];
7d13299d
FB
320 return tb;
321}
322
323int cpu_x86_exec(CPUX86State *env1)
324{
325 int saved_T0, saved_T1, saved_A0;
326 CPUX86State *saved_env;
04369ff2
FB
327#ifdef reg_EAX
328 int saved_EAX;
329#endif
330#ifdef reg_ECX
331 int saved_ECX;
332#endif
333#ifdef reg_EDX
334 int saved_EDX;
335#endif
336#ifdef reg_EBX
337 int saved_EBX;
338#endif
339#ifdef reg_ESP
340 int saved_ESP;
341#endif
342#ifdef reg_EBP
343 int saved_EBP;
344#endif
345#ifdef reg_ESI
346 int saved_ESI;
347#endif
348#ifdef reg_EDI
349 int saved_EDI;
350#endif
7d13299d
FB
351 int code_gen_size, ret;
352 void (*gen_func)(void);
9de5e440 353 TranslationBlock *tb, **ptb;
dab2ed99 354 uint8_t *tc_ptr, *cs_base, *pc;
6dbad63e
FB
355 unsigned int flags;
356
7d13299d
FB
357 /* first we save global registers */
358 saved_T0 = T0;
359 saved_T1 = T1;
360 saved_A0 = A0;
361 saved_env = env;
362 env = env1;
04369ff2
FB
363#ifdef reg_EAX
364 saved_EAX = EAX;
365 EAX = env->regs[R_EAX];
366#endif
367#ifdef reg_ECX
368 saved_ECX = ECX;
369 ECX = env->regs[R_ECX];
370#endif
371#ifdef reg_EDX
372 saved_EDX = EDX;
373 EDX = env->regs[R_EDX];
374#endif
375#ifdef reg_EBX
376 saved_EBX = EBX;
377 EBX = env->regs[R_EBX];
378#endif
379#ifdef reg_ESP
380 saved_ESP = ESP;
381 ESP = env->regs[R_ESP];
382#endif
383#ifdef reg_EBP
384 saved_EBP = EBP;
385 EBP = env->regs[R_EBP];
386#endif
387#ifdef reg_ESI
388 saved_ESI = ESI;
389 ESI = env->regs[R_ESI];
390#endif
391#ifdef reg_EDI
392 saved_EDI = EDI;
393 EDI = env->regs[R_EDI];
394#endif
7d13299d 395
9de5e440 396 /* put eflags in CPU temporary format */
fc2b4c48
FB
397 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
398 DF = 1 - (2 * ((env->eflags >> 10) & 1));
9de5e440 399 CC_OP = CC_OP_EFLAGS;
fc2b4c48 400 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
9de5e440
FB
401 env->interrupt_request = 0;
402
7d13299d
FB
403 /* prepare setjmp context for exception handling */
404 if (setjmp(env->jmp_env) == 0) {
405 for(;;) {
9de5e440
FB
406 if (env->interrupt_request) {
407 raise_exception(EXCP_INTERRUPT);
408 }
7d13299d
FB
409#ifdef DEBUG_EXEC
410 if (loglevel) {
9de5e440 411 cpu_x86_dump_state(logfile);
7d13299d
FB
412 }
413#endif
6dbad63e
FB
414 /* we compute the CPU state. We assume it will not
415 change during the whole generated block. */
416 flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
dab2ed99 417 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
6dbad63e
FB
418 flags |= (((unsigned long)env->seg_cache[R_DS].base |
419 (unsigned long)env->seg_cache[R_ES].base |
420 (unsigned long)env->seg_cache[R_SS].base) != 0) <<
421 GEN_FLAG_ADDSEG_SHIFT;
fc2b4c48 422 flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
b56dad1c
FB
423 flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT);
424 flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT;
dab2ed99
FB
425 cs_base = env->seg_cache[R_CS].base;
426 pc = cs_base + env->eip;
9de5e440
FB
427 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
428 flags);
429 if (!tb) {
7d13299d 430 /* if no translated code available, then translate it now */
1b6b029e
FB
431 /* XXX: very inefficient: we lock all the cpus when
432 generating code */
433 cpu_lock();
7d13299d 434 tc_ptr = code_gen_ptr;
9de5e440
FB
435 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
436 &code_gen_size, pc, cs_base, flags);
437 /* if invalid instruction, signal it */
438 if (ret != 0) {
439 cpu_unlock();
440 raise_exception(EXCP06_ILLOP);
441 }
442 tb = tb_alloc();
443 *ptb = tb;
444 tb->pc = (unsigned long)pc;
445 tb->cs_base = (unsigned long)cs_base;
446 tb->flags = flags;
7d13299d 447 tb->tc_ptr = tc_ptr;
9de5e440 448 tb->hash_next = NULL;
7d13299d 449 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
1b6b029e 450 cpu_unlock();
7d13299d 451 }
956034d7
FB
452 if (loglevel) {
453 fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
454 (long)tb->tc_ptr, (long)tb->pc,
455 lookup_symbol((void *)tb->pc));
456 fflush(logfile);
457 }
7d13299d 458 /* execute the generated code */
9de5e440 459 tc_ptr = tb->tc_ptr;
7d13299d
FB
460 gen_func = (void *)tc_ptr;
461 gen_func();
462 }
463 }
464 ret = env->exception_index;
465
9de5e440 466 /* restore flags in standard format */
fc2b4c48 467 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
9de5e440 468
7d13299d 469 /* restore global registers */
04369ff2
FB
470#ifdef reg_EAX
471 EAX = saved_EAX;
472#endif
473#ifdef reg_ECX
474 ECX = saved_ECX;
475#endif
476#ifdef reg_EDX
477 EDX = saved_EDX;
478#endif
479#ifdef reg_EBX
480 EBX = saved_EBX;
481#endif
482#ifdef reg_ESP
483 ESP = saved_ESP;
484#endif
485#ifdef reg_EBP
486 EBP = saved_EBP;
487#endif
488#ifdef reg_ESI
489 ESI = saved_ESI;
490#endif
491#ifdef reg_EDI
492 EDI = saved_EDI;
493#endif
7d13299d
FB
494 T0 = saved_T0;
495 T1 = saved_T1;
496 A0 = saved_A0;
497 env = saved_env;
498 return ret;
499}
6dbad63e 500
9de5e440
FB
501void cpu_x86_interrupt(CPUX86State *s)
502{
503 s->interrupt_request = 1;
504}
505
506
6dbad63e
FB
507void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
508{
509 CPUX86State *saved_env;
510
511 saved_env = env;
512 env = s;
513 load_seg(seg_reg, selector);
514 env = saved_env;
515}
9de5e440
FB
516
517#undef EAX
518#undef ECX
519#undef EDX
520#undef EBX
521#undef ESP
522#undef EBP
523#undef ESI
524#undef EDI
525#undef EIP
526#include <signal.h>
527#include <sys/ucontext.h>
528
b56dad1c
FB
529/* 'pc' is the host PC at which the exception was raised. 'address' is
530 the effective address of the memory exception */
9de5e440 531static inline int handle_cpu_signal(unsigned long pc,
b56dad1c 532 unsigned long address,
9de5e440
FB
533 sigset_t *old_set)
534{
535#ifdef DEBUG_SIGNAL
536 printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
537 pc, *(unsigned long *)old_set);
538#endif
539 if (pc >= (unsigned long)code_gen_buffer &&
540 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
541 /* the PC is inside the translated code. It means that we have
542 a virtual CPU fault */
543 /* we restore the process signal mask as the sigreturn should
544 do it */
545 sigprocmask(SIG_SETMASK, old_set, NULL);
546 /* XXX: need to compute virtual pc position by retranslating
547 code. The rest of the CPU state should be correct. */
b56dad1c
FB
548 env->cr2 = address;
549 /* XXX: more precise exception code */
550 raise_exception_err(EXCP0E_PAGE, 4);
9de5e440
FB
551 /* never comes here */
552 return 1;
553 } else {
554 return 0;
555 }
556}
557
558int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
559 void *puc)
560{
561#if defined(__i386__)
562 struct ucontext *uc = puc;
563 unsigned long pc;
564 sigset_t *pold_set;
565
d691f669
FB
566#ifndef REG_EIP
567/* for glibc 2.1 */
568#define REG_EIP EIP
569#endif
fc2b4c48 570 pc = uc->uc_mcontext.gregs[REG_EIP];
9de5e440 571 pold_set = &uc->uc_sigmask;
b56dad1c 572 return handle_cpu_signal(pc, (unsigned long)info->si_addr, pold_set);
9de5e440
FB
573#else
574#warning No CPU specific signal handler: cannot handle target SIGSEGV events
575 return 0;
576#endif
577}
This page took 0.092272 seconds and 4 git commands to generate.