]> git.proxmox.com Git - qemu.git/blame - exec-i386.c
comment
[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"
21
dc99065b 22//#define DEBUG_EXEC
7d13299d 23#define DEBUG_FLUSH
9de5e440 24//#define DEBUG_SIGNAL
7d13299d
FB
25
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)
6dbad63e 40
7d13299d 41typedef struct TranslationBlock {
dab2ed99
FB
42 unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
43 unsigned long cs_base; /* CS base for this block */
6dbad63e 44 unsigned int flags; /* flags defining in which context the code was generated */
7d13299d
FB
45 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
1b6b029e
FB
56/* 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
fb3e5849
FB
90#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
1b6b029e
FB
104int 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
9de5e440
FB
116/* 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)
7d13299d
FB
151static 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
9de5e440 184static void cpu_x86_dump_state(FILE *f)
7d13299d
FB
185{
186 int eflags;
187 eflags = cc_table[CC_OP].compute_all();
188 eflags |= (DF & DIRECTION_FLAG);
9de5e440 189 fprintf(f,
7d13299d
FB
190 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
191 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
9de5e440
FB
192 "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
193 "EIP=%08x\n",
7d13299d
FB
194 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' : '-',
9de5e440
FB
203 eflags & CC_C ? 'C' : '-',
204 env->eip);
7d13299d 205#if 1
9de5e440 206 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
7d13299d
FB
207 (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,
9de5e440
FB
238 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)
7d13299d
FB
243{
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;
dab2ed99 253 if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
7d13299d
FB
254 return tb;
255 ptb = &tb->hash_next;
256 }
9de5e440
FB
257 *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;
7d13299d
FB
266 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++];
7d13299d
FB
270 return tb;
271}
272
273int cpu_x86_exec(CPUX86State *env1)
274{
275 int saved_T0, saved_T1, saved_A0;
276 CPUX86State *saved_env;
04369ff2
FB
277#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
7d13299d
FB
301 int code_gen_size, ret;
302 void (*gen_func)(void);
9de5e440 303 TranslationBlock *tb, **ptb;
dab2ed99 304 uint8_t *tc_ptr, *cs_base, *pc;
6dbad63e
FB
305 unsigned int flags;
306
7d13299d
FB
307 /* first we save global registers */
308 saved_T0 = T0;
309 saved_T1 = T1;
310 saved_A0 = A0;
311 saved_env = env;
312 env = env1;
04369ff2
FB
313#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
7d13299d 345
9de5e440 346 /* put eflags in CPU temporary format */
fc2b4c48
FB
347 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
348 DF = 1 - (2 * ((env->eflags >> 10) & 1));
9de5e440 349 CC_OP = CC_OP_EFLAGS;
fc2b4c48 350 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
9de5e440
FB
351 env->interrupt_request = 0;
352
7d13299d
FB
353 /* prepare setjmp context for exception handling */
354 if (setjmp(env->jmp_env) == 0) {
355 for(;;) {
9de5e440
FB
356 if (env->interrupt_request) {
357 raise_exception(EXCP_INTERRUPT);
358 }
7d13299d
FB
359#ifdef DEBUG_EXEC
360 if (loglevel) {
9de5e440 361 cpu_x86_dump_state(logfile);
7d13299d
FB
362 }
363#endif
6dbad63e
FB
364 /* 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;
dab2ed99 367 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
6dbad63e
FB
368 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;
fc2b4c48 372 flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
dab2ed99
FB
373 cs_base = env->seg_cache[R_CS].base;
374 pc = cs_base + env->eip;
9de5e440
FB
375 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
376 flags);
377 if (!tb) {
7d13299d 378 /* if no translated code available, then translate it now */
1b6b029e
FB
379 /* XXX: very inefficient: we lock all the cpus when
380 generating code */
381 cpu_lock();
7d13299d 382 tc_ptr = code_gen_ptr;
9de5e440
FB
383 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;
7d13299d 395 tb->tc_ptr = tc_ptr;
9de5e440 396 tb->hash_next = NULL;
7d13299d 397 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
1b6b029e 398 cpu_unlock();
7d13299d
FB
399 }
400 /* execute the generated code */
9de5e440 401 tc_ptr = tb->tc_ptr;
7d13299d
FB
402 gen_func = (void *)tc_ptr;
403 gen_func();
404 }
405 }
406 ret = env->exception_index;
407
9de5e440 408 /* restore flags in standard format */
fc2b4c48 409 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
9de5e440 410
7d13299d 411 /* restore global registers */
04369ff2
FB
412#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
7d13299d
FB
436 T0 = saved_T0;
437 T1 = saved_T1;
438 A0 = saved_A0;
439 env = saved_env;
440 return ret;
441}
6dbad63e 442
9de5e440
FB
443void cpu_x86_interrupt(CPUX86State *s)
444{
445 s->interrupt_request = 1;
446}
447
448
6dbad63e
FB
449void 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}
9de5e440
FB
458
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
d691f669
FB
503#ifndef REG_EIP
504/* for glibc 2.1 */
505#define REG_EIP EIP
506#endif
fc2b4c48 507 pc = uc->uc_mcontext.gregs[REG_EIP];
9de5e440
FB
508 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}