]> Git Repo - qemu.git/blame - exec-i386.c
added CPL and IOPL as translation time constants - changed I/O function prototype...
[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 */
152void raise_exception(int exception_index)
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;
181 longjmp(env->jmp_env, 1);
182}
183
184#if defined(DEBUG_EXEC)
7d13299d
FB
185static const char *cc_op_str[] = {
186 "DYNAMIC",
187 "EFLAGS",
188 "MUL",
189 "ADDB",
190 "ADDW",
191 "ADDL",
192 "ADCB",
193 "ADCW",
194 "ADCL",
195 "SUBB",
196 "SUBW",
197 "SUBL",
198 "SBBB",
199 "SBBW",
200 "SBBL",
201 "LOGICB",
202 "LOGICW",
203 "LOGICL",
204 "INCB",
205 "INCW",
206 "INCL",
207 "DECB",
208 "DECW",
209 "DECL",
210 "SHLB",
211 "SHLW",
212 "SHLL",
213 "SARB",
214 "SARW",
215 "SARL",
216};
217
9de5e440 218static void cpu_x86_dump_state(FILE *f)
7d13299d
FB
219{
220 int eflags;
221 eflags = cc_table[CC_OP].compute_all();
956034d7 222 eflags |= (DF & DF_MASK);
9de5e440 223 fprintf(f,
7d13299d
FB
224 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
225 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
9de5e440
FB
226 "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
227 "EIP=%08x\n",
7d13299d
FB
228 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
229 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
230 env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
956034d7 231 eflags & DF_MASK ? 'D' : '-',
7d13299d
FB
232 eflags & CC_O ? 'O' : '-',
233 eflags & CC_S ? 'S' : '-',
234 eflags & CC_Z ? 'Z' : '-',
235 eflags & CC_A ? 'A' : '-',
236 eflags & CC_P ? 'P' : '-',
9de5e440
FB
237 eflags & CC_C ? 'C' : '-',
238 env->eip);
7d13299d 239#if 1
9de5e440 240 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
7d13299d
FB
241 (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
242#endif
243}
244
245#endif
246
247void cpu_x86_tblocks_init(void)
248{
249 if (!code_gen_ptr) {
250 code_gen_ptr = code_gen_buffer;
251 }
252}
253
254/* flush all the translation blocks */
255static void tb_flush(void)
256{
257 int i;
258#ifdef DEBUG_FLUSH
259 printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
260 code_gen_ptr - code_gen_buffer,
261 nb_tbs,
262 (code_gen_ptr - code_gen_buffer) / nb_tbs);
263#endif
264 nb_tbs = 0;
265 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
266 tb_hash[i] = NULL;
267 code_gen_ptr = code_gen_buffer;
268 /* XXX: flush processor icache at this point */
269}
270
271/* find a translation block in the translation cache. If not found,
9de5e440
FB
272 return NULL and the pointer to the last element of the list in pptb */
273static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
274 unsigned long pc,
275 unsigned long cs_base,
276 unsigned int flags)
7d13299d
FB
277{
278 TranslationBlock **ptb, *tb;
279 unsigned int h;
280
281 h = pc & (CODE_GEN_HASH_SIZE - 1);
282 ptb = &tb_hash[h];
283 for(;;) {
284 tb = *ptb;
285 if (!tb)
286 break;
dab2ed99 287 if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
7d13299d
FB
288 return tb;
289 ptb = &tb->hash_next;
290 }
9de5e440
FB
291 *pptb = ptb;
292 return NULL;
293}
294
295/* allocate a new translation block. flush the translation buffer if
296 too many translation blocks or too much generated code */
297static inline TranslationBlock *tb_alloc(void)
298{
299 TranslationBlock *tb;
7d13299d
FB
300 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
301 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
302 tb_flush();
303 tb = &tbs[nb_tbs++];
7d13299d
FB
304 return tb;
305}
306
307int cpu_x86_exec(CPUX86State *env1)
308{
309 int saved_T0, saved_T1, saved_A0;
310 CPUX86State *saved_env;
04369ff2
FB
311#ifdef reg_EAX
312 int saved_EAX;
313#endif
314#ifdef reg_ECX
315 int saved_ECX;
316#endif
317#ifdef reg_EDX
318 int saved_EDX;
319#endif
320#ifdef reg_EBX
321 int saved_EBX;
322#endif
323#ifdef reg_ESP
324 int saved_ESP;
325#endif
326#ifdef reg_EBP
327 int saved_EBP;
328#endif
329#ifdef reg_ESI
330 int saved_ESI;
331#endif
332#ifdef reg_EDI
333 int saved_EDI;
334#endif
7d13299d
FB
335 int code_gen_size, ret;
336 void (*gen_func)(void);
9de5e440 337 TranslationBlock *tb, **ptb;
dab2ed99 338 uint8_t *tc_ptr, *cs_base, *pc;
6dbad63e
FB
339 unsigned int flags;
340
7d13299d
FB
341 /* first we save global registers */
342 saved_T0 = T0;
343 saved_T1 = T1;
344 saved_A0 = A0;
345 saved_env = env;
346 env = env1;
04369ff2
FB
347#ifdef reg_EAX
348 saved_EAX = EAX;
349 EAX = env->regs[R_EAX];
350#endif
351#ifdef reg_ECX
352 saved_ECX = ECX;
353 ECX = env->regs[R_ECX];
354#endif
355#ifdef reg_EDX
356 saved_EDX = EDX;
357 EDX = env->regs[R_EDX];
358#endif
359#ifdef reg_EBX
360 saved_EBX = EBX;
361 EBX = env->regs[R_EBX];
362#endif
363#ifdef reg_ESP
364 saved_ESP = ESP;
365 ESP = env->regs[R_ESP];
366#endif
367#ifdef reg_EBP
368 saved_EBP = EBP;
369 EBP = env->regs[R_EBP];
370#endif
371#ifdef reg_ESI
372 saved_ESI = ESI;
373 ESI = env->regs[R_ESI];
374#endif
375#ifdef reg_EDI
376 saved_EDI = EDI;
377 EDI = env->regs[R_EDI];
378#endif
7d13299d 379
9de5e440 380 /* put eflags in CPU temporary format */
fc2b4c48
FB
381 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
382 DF = 1 - (2 * ((env->eflags >> 10) & 1));
9de5e440 383 CC_OP = CC_OP_EFLAGS;
fc2b4c48 384 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
9de5e440
FB
385 env->interrupt_request = 0;
386
7d13299d
FB
387 /* prepare setjmp context for exception handling */
388 if (setjmp(env->jmp_env) == 0) {
389 for(;;) {
9de5e440
FB
390 if (env->interrupt_request) {
391 raise_exception(EXCP_INTERRUPT);
392 }
7d13299d
FB
393#ifdef DEBUG_EXEC
394 if (loglevel) {
9de5e440 395 cpu_x86_dump_state(logfile);
7d13299d
FB
396 }
397#endif
6dbad63e
FB
398 /* we compute the CPU state. We assume it will not
399 change during the whole generated block. */
400 flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
dab2ed99 401 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
6dbad63e
FB
402 flags |= (((unsigned long)env->seg_cache[R_DS].base |
403 (unsigned long)env->seg_cache[R_ES].base |
404 (unsigned long)env->seg_cache[R_SS].base) != 0) <<
405 GEN_FLAG_ADDSEG_SHIFT;
fc2b4c48 406 flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
dab2ed99
FB
407 cs_base = env->seg_cache[R_CS].base;
408 pc = cs_base + env->eip;
9de5e440
FB
409 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
410 flags);
411 if (!tb) {
7d13299d 412 /* if no translated code available, then translate it now */
1b6b029e
FB
413 /* XXX: very inefficient: we lock all the cpus when
414 generating code */
415 cpu_lock();
7d13299d 416 tc_ptr = code_gen_ptr;
9de5e440
FB
417 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
418 &code_gen_size, pc, cs_base, flags);
419 /* if invalid instruction, signal it */
420 if (ret != 0) {
421 cpu_unlock();
422 raise_exception(EXCP06_ILLOP);
423 }
424 tb = tb_alloc();
425 *ptb = tb;
426 tb->pc = (unsigned long)pc;
427 tb->cs_base = (unsigned long)cs_base;
428 tb->flags = flags;
7d13299d 429 tb->tc_ptr = tc_ptr;
9de5e440 430 tb->hash_next = NULL;
7d13299d 431 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
1b6b029e 432 cpu_unlock();
7d13299d 433 }
956034d7
FB
434 if (loglevel) {
435 fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
436 (long)tb->tc_ptr, (long)tb->pc,
437 lookup_symbol((void *)tb->pc));
438 fflush(logfile);
439 }
7d13299d 440 /* execute the generated code */
9de5e440 441 tc_ptr = tb->tc_ptr;
7d13299d
FB
442 gen_func = (void *)tc_ptr;
443 gen_func();
444 }
445 }
446 ret = env->exception_index;
447
9de5e440 448 /* restore flags in standard format */
fc2b4c48 449 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
9de5e440 450
7d13299d 451 /* restore global registers */
04369ff2
FB
452#ifdef reg_EAX
453 EAX = saved_EAX;
454#endif
455#ifdef reg_ECX
456 ECX = saved_ECX;
457#endif
458#ifdef reg_EDX
459 EDX = saved_EDX;
460#endif
461#ifdef reg_EBX
462 EBX = saved_EBX;
463#endif
464#ifdef reg_ESP
465 ESP = saved_ESP;
466#endif
467#ifdef reg_EBP
468 EBP = saved_EBP;
469#endif
470#ifdef reg_ESI
471 ESI = saved_ESI;
472#endif
473#ifdef reg_EDI
474 EDI = saved_EDI;
475#endif
7d13299d
FB
476 T0 = saved_T0;
477 T1 = saved_T1;
478 A0 = saved_A0;
479 env = saved_env;
480 return ret;
481}
6dbad63e 482
9de5e440
FB
483void cpu_x86_interrupt(CPUX86State *s)
484{
485 s->interrupt_request = 1;
486}
487
488
6dbad63e
FB
489void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
490{
491 CPUX86State *saved_env;
492
493 saved_env = env;
494 env = s;
495 load_seg(seg_reg, selector);
496 env = saved_env;
497}
9de5e440
FB
498
499#undef EAX
500#undef ECX
501#undef EDX
502#undef EBX
503#undef ESP
504#undef EBP
505#undef ESI
506#undef EDI
507#undef EIP
508#include <signal.h>
509#include <sys/ucontext.h>
510
511static inline int handle_cpu_signal(unsigned long pc,
512 sigset_t *old_set)
513{
514#ifdef DEBUG_SIGNAL
515 printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
516 pc, *(unsigned long *)old_set);
517#endif
518 if (pc >= (unsigned long)code_gen_buffer &&
519 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
520 /* the PC is inside the translated code. It means that we have
521 a virtual CPU fault */
522 /* we restore the process signal mask as the sigreturn should
523 do it */
524 sigprocmask(SIG_SETMASK, old_set, NULL);
525 /* XXX: need to compute virtual pc position by retranslating
526 code. The rest of the CPU state should be correct. */
527 raise_exception(EXCP0D_GPF);
528 /* never comes here */
529 return 1;
530 } else {
531 return 0;
532 }
533}
534
535int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
536 void *puc)
537{
538#if defined(__i386__)
539 struct ucontext *uc = puc;
540 unsigned long pc;
541 sigset_t *pold_set;
542
d691f669
FB
543#ifndef REG_EIP
544/* for glibc 2.1 */
545#define REG_EIP EIP
546#endif
fc2b4c48 547 pc = uc->uc_mcontext.gregs[REG_EIP];
9de5e440
FB
548 pold_set = &uc->uc_sigmask;
549 return handle_cpu_signal(pc, pold_set);
550#else
551#warning No CPU specific signal handler: cannot handle target SIGSEGV events
552 return 0;
553#endif
554}
This page took 0.087644 seconds and 4 git commands to generate.