more FPU tests
[qemu] / exec-i386.c
1 /*
2  *  i386 emulator main execution loop
3  * 
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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
19  */
20 #include "exec-i386.h"
21 #include "disas.h"
22
23 //#define DEBUG_EXEC
24 //#define DEBUG_SIGNAL
25
26 /* main execution loop */
27
28 /* thread support */
29
30 spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
31
32 void cpu_lock(void)
33 {
34     spin_lock(&global_cpu_lock);
35 }
36
37 void cpu_unlock(void)
38 {
39     spin_unlock(&global_cpu_lock);
40 }
41
42 void cpu_loop_exit(void)
43 {
44     /* NOTE: the register at this point must be saved by hand because
45        longjmp restore them */
46 #ifdef __sparc__
47         /* We have to stay in the same register window as our caller,
48          * thus this trick.
49          */
50         __asm__ __volatile__("restore\n\t"
51                              "mov\t%o0, %i0");
52 #endif
53 #ifdef reg_EAX
54     env->regs[R_EAX] = EAX;
55 #endif
56 #ifdef reg_ECX
57     env->regs[R_ECX] = ECX;
58 #endif
59 #ifdef reg_EDX
60     env->regs[R_EDX] = EDX;
61 #endif
62 #ifdef reg_EBX
63     env->regs[R_EBX] = EBX;
64 #endif
65 #ifdef reg_ESP
66     env->regs[R_ESP] = ESP;
67 #endif
68 #ifdef reg_EBP
69     env->regs[R_EBP] = EBP;
70 #endif
71 #ifdef reg_ESI
72     env->regs[R_ESI] = ESI;
73 #endif
74 #ifdef reg_EDI
75     env->regs[R_EDI] = EDI;
76 #endif
77     longjmp(env->jmp_env, 1);
78 }
79
80 int cpu_x86_exec(CPUX86State *env1)
81 {
82     int saved_T0, saved_T1, saved_A0;
83     CPUX86State *saved_env;
84 #ifdef reg_EAX
85     int saved_EAX;
86 #endif
87 #ifdef reg_ECX
88     int saved_ECX;
89 #endif
90 #ifdef reg_EDX
91     int saved_EDX;
92 #endif
93 #ifdef reg_EBX
94     int saved_EBX;
95 #endif
96 #ifdef reg_ESP
97     int saved_ESP;
98 #endif
99 #ifdef reg_EBP
100     int saved_EBP;
101 #endif
102 #ifdef reg_ESI
103     int saved_ESI;
104 #endif
105 #ifdef reg_EDI
106     int saved_EDI;
107 #endif
108     int code_gen_size, ret;
109     void (*gen_func)(void);
110     TranslationBlock *tb, **ptb;
111     uint8_t *tc_ptr, *cs_base, *pc;
112     unsigned int flags;
113     
114     /* first we save global registers */
115     saved_T0 = T0;
116     saved_T1 = T1;
117     saved_A0 = A0;
118     saved_env = env;
119     env = env1;
120 #ifdef reg_EAX
121     saved_EAX = EAX;
122     EAX = env->regs[R_EAX];
123 #endif
124 #ifdef reg_ECX
125     saved_ECX = ECX;
126     ECX = env->regs[R_ECX];
127 #endif
128 #ifdef reg_EDX
129     saved_EDX = EDX;
130     EDX = env->regs[R_EDX];
131 #endif
132 #ifdef reg_EBX
133     saved_EBX = EBX;
134     EBX = env->regs[R_EBX];
135 #endif
136 #ifdef reg_ESP
137     saved_ESP = ESP;
138     ESP = env->regs[R_ESP];
139 #endif
140 #ifdef reg_EBP
141     saved_EBP = EBP;
142     EBP = env->regs[R_EBP];
143 #endif
144 #ifdef reg_ESI
145     saved_ESI = ESI;
146     ESI = env->regs[R_ESI];
147 #endif
148 #ifdef reg_EDI
149     saved_EDI = EDI;
150     EDI = env->regs[R_EDI];
151 #endif
152     
153     /* put eflags in CPU temporary format */
154     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
155     DF = 1 - (2 * ((env->eflags >> 10) & 1));
156     CC_OP = CC_OP_EFLAGS;
157     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
158     env->interrupt_request = 0;
159
160     /* prepare setjmp context for exception handling */
161     if (setjmp(env->jmp_env) == 0) {
162         T0 = 0; /* force lookup of first TB */
163         for(;;) {
164             if (env->interrupt_request) {
165                 env->exception_index = EXCP_INTERRUPT;
166                 cpu_loop_exit();
167             }
168 #ifdef DEBUG_EXEC
169             if (loglevel) {
170                 /* XXX: save all volatile state in cpu state */
171                 /* restore flags in standard format */
172                 env->regs[R_EAX] = EAX;
173                 env->regs[R_EBX] = EBX;
174                 env->regs[R_ECX] = ECX;
175                 env->regs[R_EDX] = EDX;
176                 env->regs[R_ESI] = ESI;
177                 env->regs[R_EDI] = EDI;
178                 env->regs[R_EBP] = EBP;
179                 env->regs[R_ESP] = ESP;
180                 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
181                 cpu_x86_dump_state(env, logfile, 0);
182                 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
183             }
184 #endif
185             /* we compute the CPU state. We assume it will not
186                change during the whole generated block. */
187             flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
188             flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
189             flags |= (((unsigned long)env->seg_cache[R_DS].base | 
190                        (unsigned long)env->seg_cache[R_ES].base |
191                        (unsigned long)env->seg_cache[R_SS].base) != 0) << 
192                 GEN_FLAG_ADDSEG_SHIFT;
193             if (!(env->eflags & VM_MASK)) {
194                 flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT;
195             } else {
196                 /* NOTE: a dummy CPL is kept */
197                 flags |= (1 << GEN_FLAG_VM_SHIFT);
198                 flags |= (3 << GEN_FLAG_CPL_SHIFT);
199             }
200             flags |= (env->eflags & (IOPL_MASK | TF_MASK));
201             cs_base = env->seg_cache[R_CS].base;
202             pc = cs_base + env->eip;
203             tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
204                          flags);
205             if (!tb) {
206                 spin_lock(&tb_lock);
207                 /* if no translated code available, then translate it now */
208                 tb = tb_alloc((unsigned long)pc);
209                 if (!tb) {
210                     /* flush must be done */
211                     tb_flush();
212                     /* cannot fail at this point */
213                     tb = tb_alloc((unsigned long)pc);
214                     /* don't forget to invalidate previous TB info */
215                     ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
216                     T0 = 0;
217                 }
218                 tc_ptr = code_gen_ptr;
219                 tb->tc_ptr = tc_ptr;
220                 tb->cs_base = (unsigned long)cs_base;
221                 tb->flags = flags;
222                 ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
223                 /* if invalid instruction, signal it */
224                 if (ret != 0) {
225                     /* NOTE: the tb is allocated but not linked, so we
226                        can leave it */
227                     spin_unlock(&tb_lock);
228                     raise_exception(EXCP06_ILLOP);
229                 }
230                 *ptb = tb;
231                 tb->hash_next = NULL;
232                 tb_link(tb);
233                 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
234                 spin_unlock(&tb_lock);
235             }
236 #ifdef DEBUG_EXEC
237             if (loglevel) {
238                 fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
239                         (long)tb->tc_ptr, (long)tb->pc,
240                         lookup_symbol((void *)tb->pc));
241             }
242 #endif
243             /* see if we can patch the calling TB */
244             if (T0 != 0 && !(env->eflags & TF_MASK)) {
245                 spin_lock(&tb_lock);
246                 tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
247                 spin_unlock(&tb_lock);
248             }
249
250             tc_ptr = tb->tc_ptr;
251
252             /* execute the generated code */
253             gen_func = (void *)tc_ptr;
254 #ifdef __sparc__
255             __asm__ __volatile__("call  %0\n\t"
256                                  " mov  %%o7,%%i0"
257                                  : /* no outputs */
258                                  : "r" (gen_func) 
259                                  : "i0", "i1", "i2", "i3", "i4", "i5");
260 #else
261             gen_func();
262 #endif
263         }
264     }
265     ret = env->exception_index;
266
267     /* restore flags in standard format */
268     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
269
270     /* restore global registers */
271 #ifdef reg_EAX
272     EAX = saved_EAX;
273 #endif
274 #ifdef reg_ECX
275     ECX = saved_ECX;
276 #endif
277 #ifdef reg_EDX
278     EDX = saved_EDX;
279 #endif
280 #ifdef reg_EBX
281     EBX = saved_EBX;
282 #endif
283 #ifdef reg_ESP
284     ESP = saved_ESP;
285 #endif
286 #ifdef reg_EBP
287     EBP = saved_EBP;
288 #endif
289 #ifdef reg_ESI
290     ESI = saved_ESI;
291 #endif
292 #ifdef reg_EDI
293     EDI = saved_EDI;
294 #endif
295     T0 = saved_T0;
296     T1 = saved_T1;
297     A0 = saved_A0;
298     env = saved_env;
299     return ret;
300 }
301
302 void cpu_x86_interrupt(CPUX86State *s)
303 {
304     s->interrupt_request = 1;
305 }
306
307
308 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
309 {
310     CPUX86State *saved_env;
311
312     saved_env = env;
313     env = s;
314     if (env->eflags & VM_MASK) {
315         SegmentCache *sc;
316         selector &= 0xffff;
317         sc = &env->seg_cache[seg_reg];
318         /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
319            so we must load them here */
320         sc->base = (void *)(selector << 4);
321         sc->limit = 0xffff;
322         sc->seg_32bit = 0;
323         env->segs[seg_reg] = selector;
324     } else {
325         load_seg(seg_reg, selector, 0);
326     }
327     env = saved_env;
328 }
329
330 void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
331 {
332     CPUX86State *saved_env;
333
334     saved_env = env;
335     env = s;
336     
337     helper_fsave(ptr, data32);
338
339     env = saved_env;
340 }
341
342 void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
343 {
344     CPUX86State *saved_env;
345
346     saved_env = env;
347     env = s;
348     
349     helper_frstor(ptr, data32);
350
351     env = saved_env;
352 }
353
354 #undef EAX
355 #undef ECX
356 #undef EDX
357 #undef EBX
358 #undef ESP
359 #undef EBP
360 #undef ESI
361 #undef EDI
362 #undef EIP
363 #include <signal.h>
364 #include <sys/ucontext.h>
365
366 /* 'pc' is the host PC at which the exception was raised. 'address' is
367    the effective address of the memory exception. 'is_write' is 1 if a
368    write caused the exception and otherwise 0'. 'old_set' is the
369    signal set which should be restored */
370 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
371                                     int is_write, sigset_t *old_set)
372 {
373     TranslationBlock *tb;
374     int ret;
375     uint32_t found_pc;
376     
377 #if defined(DEBUG_SIGNAL)
378     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", 
379            pc, address, is_write, *(unsigned long *)old_set);
380 #endif
381     /* XXX: locking issue */
382     if (is_write && page_unprotect(address)) {
383         return 1;
384     }
385     tb = tb_find_pc(pc);
386     if (tb) {
387         /* the PC is inside the translated code. It means that we have
388            a virtual CPU fault */
389         ret = cpu_x86_search_pc(tb, &found_pc, pc);
390         if (ret < 0)
391             return 0;
392         env->eip = found_pc - tb->cs_base;
393         env->cr2 = address;
394         /* we restore the process signal mask as the sigreturn should
395            do it (XXX: use sigsetjmp) */
396         sigprocmask(SIG_SETMASK, old_set, NULL);
397         raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
398         /* never comes here */
399         return 1;
400     } else {
401         return 0;
402     }
403 }
404
405 #if defined(__i386__)
406
407 int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
408                            void *puc)
409 {
410     struct ucontext *uc = puc;
411     unsigned long pc;
412     
413 #ifndef REG_EIP
414 /* for glibc 2.1 */
415 #define REG_EIP    EIP
416 #define REG_ERR    ERR
417 #define REG_TRAPNO TRAPNO
418 #endif
419     pc = uc->uc_mcontext.gregs[REG_EIP];
420     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
421                              uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? 
422                              (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
423                              &uc->uc_sigmask);
424 }
425
426 #elif defined(__powerpc)
427
428 int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
429                            void *puc)
430 {
431     struct ucontext *uc = puc;
432     struct pt_regs *regs = uc->uc_mcontext.regs;
433     unsigned long pc;
434     int is_write;
435
436     pc = regs->nip;
437     is_write = 0;
438 #if 0
439     /* ppc 4xx case */
440     if (regs->dsisr & 0x00800000)
441         is_write = 1;
442 #else
443     if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
444         is_write = 1;
445 #endif
446     return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
447                              is_write, &uc->uc_sigmask);
448 }
449
450 #else
451
452 #error CPU specific signal handler needed
453
454 #endif