]> git.proxmox.com Git - mirror_qemu.git/blame - exec-i386.c
more syscalls
[mirror_qemu.git] / exec-i386.c
CommitLineData
7d13299d
FB
1/*
2 * i386 emulator main execution loop
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
90int global_cpu_lock = 0;
91
92void cpu_lock(void)
93{
94 while (testandset(&global_cpu_lock));
95}
96
97void cpu_unlock(void)
98{
99 global_cpu_lock = 0;
100}
101
9de5e440
FB
102/* exception support */
103/* NOTE: not static to force relocation generation by GCC */
104void raise_exception(int exception_index)
105{
106 /* NOTE: the register at this point must be saved by hand because
107 longjmp restore them */
108#ifdef reg_EAX
109 env->regs[R_EAX] = EAX;
110#endif
111#ifdef reg_ECX
112 env->regs[R_ECX] = ECX;
113#endif
114#ifdef reg_EDX
115 env->regs[R_EDX] = EDX;
116#endif
117#ifdef reg_EBX
118 env->regs[R_EBX] = EBX;
119#endif
120#ifdef reg_ESP
121 env->regs[R_ESP] = ESP;
122#endif
123#ifdef reg_EBP
124 env->regs[R_EBP] = EBP;
125#endif
126#ifdef reg_ESI
127 env->regs[R_ESI] = ESI;
128#endif
129#ifdef reg_EDI
130 env->regs[R_EDI] = EDI;
131#endif
132 env->exception_index = exception_index;
133 longjmp(env->jmp_env, 1);
134}
135
136#if defined(DEBUG_EXEC)
7d13299d
FB
137static const char *cc_op_str[] = {
138 "DYNAMIC",
139 "EFLAGS",
140 "MUL",
141 "ADDB",
142 "ADDW",
143 "ADDL",
144 "ADCB",
145 "ADCW",
146 "ADCL",
147 "SUBB",
148 "SUBW",
149 "SUBL",
150 "SBBB",
151 "SBBW",
152 "SBBL",
153 "LOGICB",
154 "LOGICW",
155 "LOGICL",
156 "INCB",
157 "INCW",
158 "INCL",
159 "DECB",
160 "DECW",
161 "DECL",
162 "SHLB",
163 "SHLW",
164 "SHLL",
165 "SARB",
166 "SARW",
167 "SARL",
168};
169
9de5e440 170static void cpu_x86_dump_state(FILE *f)
7d13299d
FB
171{
172 int eflags;
173 eflags = cc_table[CC_OP].compute_all();
174 eflags |= (DF & DIRECTION_FLAG);
9de5e440 175 fprintf(f,
7d13299d
FB
176 "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
177 "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
9de5e440
FB
178 "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n"
179 "EIP=%08x\n",
7d13299d
FB
180 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
181 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
182 env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
183 eflags & DIRECTION_FLAG ? 'D' : '-',
184 eflags & CC_O ? 'O' : '-',
185 eflags & CC_S ? 'S' : '-',
186 eflags & CC_Z ? 'Z' : '-',
187 eflags & CC_A ? 'A' : '-',
188 eflags & CC_P ? 'P' : '-',
9de5e440
FB
189 eflags & CC_C ? 'C' : '-',
190 env->eip);
7d13299d 191#if 1
9de5e440 192 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
7d13299d
FB
193 (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
194#endif
195}
196
197#endif
198
199void cpu_x86_tblocks_init(void)
200{
201 if (!code_gen_ptr) {
202 code_gen_ptr = code_gen_buffer;
203 }
204}
205
206/* flush all the translation blocks */
207static void tb_flush(void)
208{
209 int i;
210#ifdef DEBUG_FLUSH
211 printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
212 code_gen_ptr - code_gen_buffer,
213 nb_tbs,
214 (code_gen_ptr - code_gen_buffer) / nb_tbs);
215#endif
216 nb_tbs = 0;
217 for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
218 tb_hash[i] = NULL;
219 code_gen_ptr = code_gen_buffer;
220 /* XXX: flush processor icache at this point */
221}
222
223/* find a translation block in the translation cache. If not found,
9de5e440
FB
224 return NULL and the pointer to the last element of the list in pptb */
225static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
226 unsigned long pc,
227 unsigned long cs_base,
228 unsigned int flags)
7d13299d
FB
229{
230 TranslationBlock **ptb, *tb;
231 unsigned int h;
232
233 h = pc & (CODE_GEN_HASH_SIZE - 1);
234 ptb = &tb_hash[h];
235 for(;;) {
236 tb = *ptb;
237 if (!tb)
238 break;
dab2ed99 239 if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
7d13299d
FB
240 return tb;
241 ptb = &tb->hash_next;
242 }
9de5e440
FB
243 *pptb = ptb;
244 return NULL;
245}
246
247/* allocate a new translation block. flush the translation buffer if
248 too many translation blocks or too much generated code */
249static inline TranslationBlock *tb_alloc(void)
250{
251 TranslationBlock *tb;
7d13299d
FB
252 if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
253 (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
254 tb_flush();
255 tb = &tbs[nb_tbs++];
7d13299d
FB
256 return tb;
257}
258
259int cpu_x86_exec(CPUX86State *env1)
260{
261 int saved_T0, saved_T1, saved_A0;
262 CPUX86State *saved_env;
04369ff2
FB
263#ifdef reg_EAX
264 int saved_EAX;
265#endif
266#ifdef reg_ECX
267 int saved_ECX;
268#endif
269#ifdef reg_EDX
270 int saved_EDX;
271#endif
272#ifdef reg_EBX
273 int saved_EBX;
274#endif
275#ifdef reg_ESP
276 int saved_ESP;
277#endif
278#ifdef reg_EBP
279 int saved_EBP;
280#endif
281#ifdef reg_ESI
282 int saved_ESI;
283#endif
284#ifdef reg_EDI
285 int saved_EDI;
286#endif
7d13299d
FB
287 int code_gen_size, ret;
288 void (*gen_func)(void);
9de5e440 289 TranslationBlock *tb, **ptb;
dab2ed99 290 uint8_t *tc_ptr, *cs_base, *pc;
6dbad63e
FB
291 unsigned int flags;
292
7d13299d
FB
293 /* first we save global registers */
294 saved_T0 = T0;
295 saved_T1 = T1;
296 saved_A0 = A0;
297 saved_env = env;
298 env = env1;
04369ff2
FB
299#ifdef reg_EAX
300 saved_EAX = EAX;
301 EAX = env->regs[R_EAX];
302#endif
303#ifdef reg_ECX
304 saved_ECX = ECX;
305 ECX = env->regs[R_ECX];
306#endif
307#ifdef reg_EDX
308 saved_EDX = EDX;
309 EDX = env->regs[R_EDX];
310#endif
311#ifdef reg_EBX
312 saved_EBX = EBX;
313 EBX = env->regs[R_EBX];
314#endif
315#ifdef reg_ESP
316 saved_ESP = ESP;
317 ESP = env->regs[R_ESP];
318#endif
319#ifdef reg_EBP
320 saved_EBP = EBP;
321 EBP = env->regs[R_EBP];
322#endif
323#ifdef reg_ESI
324 saved_ESI = ESI;
325 ESI = env->regs[R_ESI];
326#endif
327#ifdef reg_EDI
328 saved_EDI = EDI;
329 EDI = env->regs[R_EDI];
330#endif
7d13299d 331
9de5e440
FB
332 /* put eflags in CPU temporary format */
333 T0 = env->eflags;
334 op_movl_eflags_T0();
335 CC_OP = CC_OP_EFLAGS;
336 env->interrupt_request = 0;
337
7d13299d
FB
338 /* prepare setjmp context for exception handling */
339 if (setjmp(env->jmp_env) == 0) {
340 for(;;) {
9de5e440
FB
341 if (env->interrupt_request) {
342 raise_exception(EXCP_INTERRUPT);
343 }
7d13299d
FB
344#ifdef DEBUG_EXEC
345 if (loglevel) {
9de5e440 346 cpu_x86_dump_state(logfile);
7d13299d
FB
347 }
348#endif
6dbad63e
FB
349 /* we compute the CPU state. We assume it will not
350 change during the whole generated block. */
351 flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
dab2ed99 352 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
6dbad63e
FB
353 flags |= (((unsigned long)env->seg_cache[R_DS].base |
354 (unsigned long)env->seg_cache[R_ES].base |
355 (unsigned long)env->seg_cache[R_SS].base) != 0) <<
356 GEN_FLAG_ADDSEG_SHIFT;
dab2ed99
FB
357 cs_base = env->seg_cache[R_CS].base;
358 pc = cs_base + env->eip;
9de5e440
FB
359 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
360 flags);
361 if (!tb) {
7d13299d 362 /* if no translated code available, then translate it now */
1b6b029e
FB
363 /* XXX: very inefficient: we lock all the cpus when
364 generating code */
365 cpu_lock();
7d13299d 366 tc_ptr = code_gen_ptr;
9de5e440
FB
367 ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
368 &code_gen_size, pc, cs_base, flags);
369 /* if invalid instruction, signal it */
370 if (ret != 0) {
371 cpu_unlock();
372 raise_exception(EXCP06_ILLOP);
373 }
374 tb = tb_alloc();
375 *ptb = tb;
376 tb->pc = (unsigned long)pc;
377 tb->cs_base = (unsigned long)cs_base;
378 tb->flags = flags;
7d13299d 379 tb->tc_ptr = tc_ptr;
9de5e440 380 tb->hash_next = NULL;
7d13299d 381 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
1b6b029e 382 cpu_unlock();
7d13299d
FB
383 }
384 /* execute the generated code */
9de5e440 385 tc_ptr = tb->tc_ptr;
7d13299d
FB
386 gen_func = (void *)tc_ptr;
387 gen_func();
388 }
389 }
390 ret = env->exception_index;
391
9de5e440
FB
392 /* restore flags in standard format */
393 op_movl_T0_eflags();
394 env->eflags = T0;
395
7d13299d 396 /* restore global registers */
04369ff2
FB
397#ifdef reg_EAX
398 EAX = saved_EAX;
399#endif
400#ifdef reg_ECX
401 ECX = saved_ECX;
402#endif
403#ifdef reg_EDX
404 EDX = saved_EDX;
405#endif
406#ifdef reg_EBX
407 EBX = saved_EBX;
408#endif
409#ifdef reg_ESP
410 ESP = saved_ESP;
411#endif
412#ifdef reg_EBP
413 EBP = saved_EBP;
414#endif
415#ifdef reg_ESI
416 ESI = saved_ESI;
417#endif
418#ifdef reg_EDI
419 EDI = saved_EDI;
420#endif
7d13299d
FB
421 T0 = saved_T0;
422 T1 = saved_T1;
423 A0 = saved_A0;
424 env = saved_env;
425 return ret;
426}
6dbad63e 427
9de5e440
FB
428void cpu_x86_interrupt(CPUX86State *s)
429{
430 s->interrupt_request = 1;
431}
432
433
6dbad63e
FB
434void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
435{
436 CPUX86State *saved_env;
437
438 saved_env = env;
439 env = s;
440 load_seg(seg_reg, selector);
441 env = saved_env;
442}
9de5e440
FB
443
444#undef EAX
445#undef ECX
446#undef EDX
447#undef EBX
448#undef ESP
449#undef EBP
450#undef ESI
451#undef EDI
452#undef EIP
453#include <signal.h>
454#include <sys/ucontext.h>
455
456static inline int handle_cpu_signal(unsigned long pc,
457 sigset_t *old_set)
458{
459#ifdef DEBUG_SIGNAL
460 printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n",
461 pc, *(unsigned long *)old_set);
462#endif
463 if (pc >= (unsigned long)code_gen_buffer &&
464 pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
465 /* the PC is inside the translated code. It means that we have
466 a virtual CPU fault */
467 /* we restore the process signal mask as the sigreturn should
468 do it */
469 sigprocmask(SIG_SETMASK, old_set, NULL);
470 /* XXX: need to compute virtual pc position by retranslating
471 code. The rest of the CPU state should be correct. */
472 raise_exception(EXCP0D_GPF);
473 /* never comes here */
474 return 1;
475 } else {
476 return 0;
477 }
478}
479
480int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
481 void *puc)
482{
483#if defined(__i386__)
484 struct ucontext *uc = puc;
485 unsigned long pc;
486 sigset_t *pold_set;
487
488 pc = uc->uc_mcontext.gregs[EIP];
489 pold_set = &uc->uc_sigmask;
490 return handle_cpu_signal(pc, pold_set);
491#else
492#warning No CPU specific signal handler: cannot handle target SIGSEGV events
493 return 0;
494#endif
495}