VirtualBox

root/trunk/src/recompiler/cpu-exec.c

Revision 13839, 69.6 kB (checked in by vboxsync, 2 months ago)

And yet more %V* -> %R* changes...

  • Property svn:eol-style set to native
Line 
1 /*
2  *  i386 emulator main execution loop
3  *
4  *  Copyright (c) 2003-2005 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
21 /*
22  * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
23  * other than GPL or LGPL is available it will apply instead, Sun elects to use only
24  * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
25  * a choice of LGPL license versions is made available with the language indicating
26  * that LGPLv2 or any later version may be used, or where a choice of which version
27  * of the LGPL is applied is otherwise unspecified.
28  */
29 #include "config.h"
30 #include "exec.h"
31 #include "disas.h"
32
33 #if !defined(CONFIG_SOFTMMU)
34 #undef EAX
35 #undef ECX
36 #undef EDX
37 #undef EBX
38 #undef ESP
39 #undef EBP
40 #undef ESI
41 #undef EDI
42 #undef EIP
43 #include <signal.h>
44 #include <sys/ucontext.h>
45 #endif
46
47 int tb_invalidated_flag;
48
49 //#define DEBUG_EXEC
50 //#define DEBUG_SIGNAL
51
52 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
53 /* XXX: unify with i386 target */
54 void cpu_loop_exit(void)
55 {
56     longjmp(env->jmp_env, 1);
57 }
58 #endif
59 #if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
60 #define reg_T2
61 #endif
62
63 /* exit the current TB from a signal handler. The host registers are
64    restored in a state compatible with the CPU emulator
65  */
66 void cpu_resume_from_signal(CPUState *env1, void *puc)
67 {
68 #if !defined(CONFIG_SOFTMMU)
69     struct ucontext *uc = puc;
70 #endif
71
72     env = env1;
73
74     /* XXX: restore cpu registers saved in host registers */
75
76 #if !defined(CONFIG_SOFTMMU)
77     if (puc) {
78         /* XXX: use siglongjmp ? */
79         sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
80     }
81 #endif
82     longjmp(env->jmp_env, 1);
83 }
84
85
86 static TranslationBlock *tb_find_slow(target_ulong pc,
87                                       target_ulong cs_base,
88                                       unsigned int flags)
89 {
90     TranslationBlock *tb, **ptb1;
91     int code_gen_size;
92     unsigned int h;
93     target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
94     uint8_t *tc_ptr;
95
96     spin_lock(&tb_lock);
97
98     tb_invalidated_flag = 0;
99
100     regs_to_env(); /* XXX: do it just before cpu_gen_code() */
101
102     /* find translated block using physical mappings */
103     phys_pc = get_phys_addr_code(env, pc);
104     phys_page1 = phys_pc & TARGET_PAGE_MASK;
105     phys_page2 = -1;
106     h = tb_phys_hash_func(phys_pc);
107     ptb1 = &tb_phys_hash[h];
108     for(;;) {
109         tb = *ptb1;
110         if (!tb)
111             goto not_found;
112         if (tb->pc == pc &&
113             tb->page_addr[0] == phys_page1 &&
114             tb->cs_base == cs_base &&
115             tb->flags == flags) {
116             /* check next page if needed */
117             if (tb->page_addr[1] != -1) {
118                 virt_page2 = (pc & TARGET_PAGE_MASK) +
119                     TARGET_PAGE_SIZE;
120                 phys_page2 = get_phys_addr_code(env, virt_page2);
121                 if (tb->page_addr[1] == phys_page2)
122                     goto found;
123             } else {
124                 goto found;
125             }
126         }
127         ptb1 = &tb->phys_hash_next;
128     }
129  not_found:
130     /* if no translated code available, then translate it now */
131     tb = tb_alloc(pc);
132     if (!tb) {
133         /* flush must be done */
134         tb_flush(env);
135         /* cannot fail at this point */
136         tb = tb_alloc(pc);
137         /* don't forget to invalidate previous TB info */
138         tb_invalidated_flag = 1;
139     }
140     tc_ptr = code_gen_ptr;
141     tb->tc_ptr = tc_ptr;
142     tb->cs_base = cs_base;
143     tb->flags = flags;
144     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
145     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
146
147     /* check next page if needed */
148     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
149     phys_page2 = -1;
150     if ((pc & TARGET_PAGE_MASK) != virt_page2) {
151         phys_page2 = get_phys_addr_code(env, virt_page2);
152     }
153     tb_link_phys(tb, phys_pc, phys_page2);
154
155  found:
156     /* we add the TB in the virtual pc hash table */
157     env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
158     spin_unlock(&tb_lock);
159     return tb;
160 }
161
162 static inline TranslationBlock *tb_find_fast(void)
163 {
164     TranslationBlock *tb;
165     target_ulong cs_base, pc;
166     unsigned int flags;
167
168     /* we record a subset of the CPU state. It will
169        always be the same before a given translated block
170        is executed. */
171 #if defined(TARGET_I386)
172     flags = env->hflags;
173     flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
174     cs_base = env->segs[R_CS].base;
175     pc = cs_base + env->eip;
176 #elif defined(TARGET_ARM)
177     flags = env->thumb | (env->vfp.vec_len << 1)
178             | (env->vfp.vec_stride << 4);
179     if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
180         flags |= (1 << 6);
181     if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
182         flags |= (1 << 7);
183     cs_base = 0;
184     pc = env->regs[15];
185 #elif defined(TARGET_SPARC)
186 #ifdef TARGET_SPARC64
187     // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
188     flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
189         | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
190 #else
191     // FPU enable . MMU enabled . MMU no-fault . Supervisor
192     flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
193         | env->psrs;
194 #endif
195     cs_base = env->npc;
196     pc = env->pc;
197 #elif defined(TARGET_PPC)
198     flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
199         (msr_se << MSR_SE) | (msr_le << MSR_LE);
200     cs_base = 0;
201     pc = env->nip;
202 #elif defined(TARGET_MIPS)
203     flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
204     cs_base = 0;
205     pc = env->PC;
206 #elif defined(TARGET_M68K)
207     flags = env->fpcr & M68K_FPCR_PREC;
208     cs_base = 0;
209     pc = env->pc;
210 #elif defined(TARGET_SH4)
211     flags = env->sr & (SR_MD | SR_RB);
212     cs_base = 0;         /* XXXXX */
213     pc = env->pc;
214 #else
215 #error unsupported CPU
216 #endif
217     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
218     if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
219                          tb->flags != flags, 0)) {
220         tb = tb_find_slow(pc, cs_base, flags);
221         /* Note: we do it here to avoid a gcc bug on Mac OS X when
222            doing it in tb_find_slow */
223         if (tb_invalidated_flag) {
224             /* as some TB could have been invalidated because
225                of memory exceptions while generating the code, we
226                must recompute the hash index here */
227             T0 = 0;
228         }
229     }
230     return tb;
231 }
232
233
234 /* main execution loop */
235
236 #ifdef VBOX
237
238 int cpu_exec(CPUState *env1)
239 {
240 #define DECLARE_HOST_REGS 1
241 #include "hostregs_helper.h"
242     int ret, interrupt_request;
243     void (*gen_func)(void);
244     TranslationBlock *tb;
245     uint8_t *tc_ptr;
246
247 #if defined(TARGET_I386)
248     /* handle exit of HALTED state */
249     if (env1->hflags & HF_HALTED_MASK) {
250         /* disable halt condition */
251         if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
252             (env1->eflags & IF_MASK)) {
253             env1->hflags &= ~HF_HALTED_MASK;
254         } else {
255             return EXCP_HALTED;
256         }
257     }
258 #elif defined(TARGET_PPC)
259     if (env1->halted) {
260         if (env1->msr[MSR_EE] &&
261             (env1->interrupt_request &
262              (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
263             env1->halted = 0;
264         } else {
265             return EXCP_HALTED;
266         }
267     }
268 #elif defined(TARGET_SPARC)
269     if (env1->halted) {
270         if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
271             (env1->psret != 0)) {
272             env1->halted = 0;
273         } else {
274             return EXCP_HALTED;
275         }
276     }
277 #elif defined(TARGET_ARM)
278     if (env1->halted) {
279         /* An interrupt wakes the CPU even if the I and F CPSR bits are
280            set.  */
281         if (env1->interrupt_request
282             & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) {
283             env1->halted = 0;
284         } else {
285             return EXCP_HALTED;
286         }
287     }
288 #elif defined(TARGET_MIPS)
289     if (env1->halted) {
290         if (env1->interrupt_request &
291             (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
292             env1->halted = 0;
293         } else {
294             return EXCP_HALTED;
295         }
296     }
297 #endif
298
299     cpu_single_env = env1;
300
301     /* first we save global registers */
302 #define SAVE_HOST_REGS 1
303 #include "hostregs_helper.h"
304     env = env1;
305 #if defined(__sparc__) && !defined(HOST_SOLARIS)
306     /* we also save i7 because longjmp may not restore it */
307     asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
308 #endif
309
310 #if defined(TARGET_I386)
311
312     env_to_regs();
313     /* put eflags in CPU temporary format */
314     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
315     DF = 1 - (2 * ((env->eflags >> 10) & 1));
316     CC_OP = CC_OP_EFLAGS;
317     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
318 #elif defined(TARGET_ARM)
319 #elif defined(TARGET_SPARC)
320 #if defined(reg_REGWPTR)
321     saved_regwptr = REGWPTR;
322 #endif
323 #elif defined(TARGET_PPC)
324 #elif defined(TARGET_MIPS)
325 #elif defined(TARGET_SH4)
326     /* XXXXX */
327 #else
328 #error unsupported target CPU
329 #endif
330 #ifndef VBOX /* VBOX: We need to raise traps and suchlike from the outside. */
331     env->exception_index = -1;
332 #endif
333
334     /* prepare setjmp context for exception handling */
335     for(;;) {
336         if (setjmp(env->jmp_env) == 0)
337         {
338             env->current_tb = NULL;
339             VMMR3Unlock(env->pVM);
340             VMMR3Lock(env->pVM);
341
342             /*
343              * Check for fatal errors first
344              */
345             if (env->interrupt_request & CPU_INTERRUPT_RC) {
346                 env->exception_index = EXCP_RC;
347                 ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_RC);
348                 ret = env->exception_index;
349                 cpu_loop_exit();
350             }
351
352             /* if an exception is pending, we execute it here */
353             if (env->exception_index >= 0) {
354                 Assert(!env->user_mode_only);
355                 if (env->exception_index >= EXCP_INTERRUPT) {
356                     /* exit request from the cpu execution loop */
357                     ret = env->exception_index;
358                     break;
359                 } else {
360                     /* simulate a real cpu exception. On i386, it can
361                        trigger new exceptions, but we do not handle
362                        double or triple faults yet. */
363                     RAWEx_ProfileStart(env, STATS_IRQ_HANDLING);
364                     Log(("do_interrupt %d %d %RGv\n", env->exception_index, env->exception_is_int, env->exception_next_eip));
365                     do_interrupt(env->exception_index,
366                                  env->exception_is_int,
367                                  env->error_code,
368                                  env->exception_next_eip, 0);
369                     RAWEx_ProfileStop(env, STATS_IRQ_HANDLING);
370                 }
371                 env->exception_index = -1;
372             }
373
374             T0 = 0; /* force lookup of first TB */
375             for(;;)
376             {
377                 interrupt_request = env->interrupt_request;
378                 if (__builtin_expect(interrupt_request, 0))
379                 {
380                     /* Single instruction exec request, we execute it and return (one way or the other).
381                        The caller will always reschedule after doing this operation! */
382                     if (interrupt_request & CPU_INTERRUPT_SINGLE_INSTR)
383                     {
384                         /* not in flight are we? (if we are, we trapped) */
385                         if (!(env->interrupt_request & CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT))
386                         {
387                             ASMAtomicOrS32(&env->interrupt_request, CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT);
388                             env->exception_index = EXCP_SINGLE_INSTR;
389                             if (emulate_single_instr(env) == -1)
390                                 AssertMsgFailed(("REM: emulate_single_instr failed for EIP=%RGv!!\n", env->eip));
391
392                             /* When we receive an external interrupt during execution of this single
393                                instruction, then we should stay here. We will leave when we're ready
394                                for raw-mode or when interrupted by pending EMT requests.  */
395                             interrupt_request = env->interrupt_request; /* reload this! */
396                             if (   !(interrupt_request & CPU_INTERRUPT_HARD)
397                                 || !(env->eflags & IF_MASK)
398                                 ||  (env->hflags & HF_INHIBIT_IRQ_MASK)
399                                 ||  (env->state & CPU_RAW_HWACC)
400                                )
401                             {
402                                 env->exception_index = ret = EXCP_SINGLE_INSTR;
403                                 cpu_loop_exit();
404                             }
405                         }
406                         /* Clear CPU_INTERRUPT_SINGLE_INSTR and leave CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT set. */
407                         ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_SINGLE_INSTR);
408                     }
409
410                     RAWEx_ProfileStart(env, STATS_IRQ_HANDLING);
411                     if ((interrupt_request & CPU_INTERRUPT_SMI) &&
412                         !(env->hflags & HF_SMM_MASK)) {
413                         env->interrupt_request &= ~CPU_INTERRUPT_SMI;
414                         do_smm_enter();
415                         T0 = 0;
416                     }
417                     else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
418                              (env->eflags & IF_MASK) &&
419                              !(env->hflags & HF_INHIBIT_IRQ_MASK))
420                     {
421                         /* if hardware interrupt pending, we execute it */
422                         int intno;
423                         ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_HARD);
424                         intno = cpu_get_pic_interrupt(env);
425                         if (intno >= 0)
426                         {
427                             Log(("do_interrupt %d\n", intno));
428                             do_interrupt(intno, 0, 0, 0, 1);
429                         }
430                         /* ensure that no TB jump will be modified as
431                            the program flow was changed */
432                         T0 = 0;
433                     }
434                     if (env->interrupt_request & CPU_INTERRUPT_EXITTB)
435                     {
436                         ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_EXITTB);
437                         /* ensure that no TB jump will be modified as
438                            the program flow was changed */
439                         T0 = 0;
440                     }
441                     RAWEx_ProfileStop(env, STATS_IRQ_HANDLING);
442                     if (interrupt_request & CPU_INTERRUPT_EXIT)
443                     {
444                         env->exception_index = EXCP_INTERRUPT;
445                         ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_EXIT);
446                         ret = env->exception_index;
447                         cpu_loop_exit();
448                     }
449                     if (interrupt_request & CPU_INTERRUPT_RC)
450                     {
451                         env->exception_index = EXCP_RC;
452                         ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_RC);
453                         ret = env->exception_index;
454                         cpu_loop_exit();
455                     }
456                 }
457
458                 /*
459                  * Check if we the CPU state allows us to execute the code in raw-mode.
460                  */
461                 RAWEx_ProfileStart(env, STATS_RAW_CHECK);
462                 if (remR3CanExecuteRaw(env,
463                                        env->eip + env->segs[R_CS].base,
464                                        env->hflags | (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)),
465                                        &env->exception_index))
466                 {
467                     RAWEx_ProfileStop(env, STATS_RAW_CHECK);
468                     ret = env->exception_index;
469                     cpu_loop_exit();
470                 }
471                 RAWEx_ProfileStop(env, STATS_RAW_CHECK);
472
473                 RAWEx_ProfileStart(env, STATS_TLB_LOOKUP);
474                 tb = tb_find_fast();
475
476                 /* see if we can patch the calling TB. When the TB
477                    spans two pages, we cannot safely do a direct
478                    jump. */
479                 if (T0 != 0
480                     && !(tb->cflags & CF_RAW_MODE)
481                     && tb->page_addr[1] == -1)
482                 {
483                     spin_lock(&tb_lock);
484                     tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
485                     spin_unlock(&tb_lock);
486                 }
487                 tc_ptr = tb->tc_ptr;
488                 env->current_tb = tb;
489                 /* execute the generated code */
490                 gen_func = (void *)tc_ptr;
491                 RAWEx_ProfileStop(env, STATS_TLB_LOOKUP);
492
493 #if defined(DEBUG) && defined(VBOX) && !defined(DEBUG_dmik)
494 #if !defined(DEBUG_bird)
495                 if (((env->hflags >> HF_CPL_SHIFT) & 3) == 0 && (env->hflags & HF_PE_MASK) && (env->cr[0] & CR0_PG_MASK))
496                 {
497                     if(!(env->state & CPU_EMULATE_SINGLE_STEP))
498                     {
499                         Log(("EMR0: %RGv ESP=%RGv IF=%d TF=%d CPL=%d\n", env->eip, ESP, (env->eflags & IF_MASK) ? 1 : 0, (env->eflags & TF_MASK) ? 1 : 0, (env->hflags >> HF_CPL_SHIFT) & 3));
500                     }
501                 }
502                 else
503                 if (((env->hflags >> HF_CPL_SHIFT) & 3) == 3 && (env->hflags & HF_PE_MASK) && (env->cr[0] & CR0_PG_MASK))
504                 {
505                     if(!(env->state & CPU_EMULATE_SINGLE_STEP))
506                     {
507                         if(env->eflags & VM_MASK)
508                         {
509                             Log(("EMV86: %04X:%RGv IF=%d TF=%d CPL=%d CR0=%RGr\n", env->segs[R_CS].selector, env->eip, (env->eflags & IF_MASK) ? 1 : 0, (env->eflags & TF_MASK) ? 1 : 0, (env->hflags >> HF_CPL_SHIFT) & 3, env->cr[0]));
510                         }
511                         else
512                         {
513                             Log(("EMR3: %RGv ESP=%RGv IF=%d TF=%d CPL=%d IOPL=%d CR0=%RGr\n", env->eip, ESP, (env->eflags & IF_MASK) ? 1 : 0, (env->eflags & TF_MASK) ? 1 : 0, (env->hflags >> HF_CPL_SHIFT) & 3, ((env->eflags >> IOPL_SHIFT) & 3), env->cr[0]));
514                         }
515                     }
516                 }
517                 else
518                 {
519                     /* Seriously slows down realmode booting. */
520                     LogFlow(("EMRM: %04X:%RGv SS:ESP=%04X:%RGv IF=%d TF=%d CPL=%d PE=%d PG=%d\n", env->segs[R_CS].selector, env->eip, env->segs[R_SS].selector, ESP, (env->eflags & IF_MASK) ? 1 : 0, (env->eflags & TF_MASK) ? 1 : 0, (env->hflags >> HF_CPL_SHIFT) & 3, env->cr[0] & X86_CR0_PE, env->cr[0] & X86_CR0_PG));
521                 }
522 #endif /* !DEBUG_bird */
523                 if(env->state & CPU_EMULATE_SINGLE_STEP)
524                 {
525 #ifdef DEBUG_bird
526                     static int s_cTimes = 0;
527                     if (s_cTimes++ > 1000000)
528                     {
529                         RTLogPrintf("Enough stepping!\n");
530                         #if 0
531                         env->exception_index = EXCP_DEBUG;
532                         ret = env->exception_index;
533                         cpu_loop_exit();
534                         #else
535                         env->state &= ~CPU_EMULATE_SINGLE_STEP;
536                         #endif
537                     }
538 #endif
539                     TMCpuTickPause(env->pVM);
540                     remR3DisasInstr(env, -1, NULL);
541                     TMCpuTickResume(env->pVM);
542                     if(emulate_single_instr(env) == -1)
543                     {
544                         Log(("emulate_single_instr failed for EIP=%RGv!!\n", env->eip));
545                     }
546                 }
547                 else
548                 {
549                     RAWEx_ProfileStart(env, STATS_QEMU_RUN_EMULATED_CODE);
550                     gen_func();
551                     RAWEx_ProfileStop(env, STATS_QEMU_RUN_EMULATED_CODE);
552                 }
553 #else /* !DEBUG || !VBOX || DEBUG_dmik */
554
555                 RAWEx_ProfileStart(env, STATS_QEMU_RUN_EMULATED_CODE);
556                 gen_func();
557                 RAWEx_ProfileStop(env, STATS_QEMU_RUN_EMULATED_CODE);
558
559 #endif /* !DEBUG || !VBOX || DEBUG_dmik */
560                 env->current_tb = NULL;
561                 /* reset soft MMU for next block (it can currently
562                    only be set by a memory fault) */
563 #if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
564                 if (env->hflags & HF_SOFTMMU_MASK) {
565                     env->hflags &= ~HF_SOFTMMU_MASK;
566                     /* do not allow linking to another block */
567                     T0 = 0;
568                 }
569 #endif
570             }
571         } else {
572             env_to_regs();
573         }
574 #ifdef VBOX_HIGH_RES_TIMERS_HACK
575         /* NULL the current_tb here so cpu_interrupt() doesn't do
576            anything unnecessary (like crashing during emulate single instruction). */
577         env->current_tb = NULL;
578         TMTimerPoll(env1->pVM);
579 #endif
580     } /* for(;;) */
581
582 #if defined(TARGET_I386)
583     /* restore flags in standard format */
584     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
585 #else
586 #error unsupported target CPU
587 #endif
588 #include "hostregs_helper.h"
589     return ret;
590 }
591
592
593 #else /* !VBOX */
594
595
596 int cpu_exec(CPUState *env1)
597 {
598 #define DECLARE_HOST_REGS 1
599 #include "hostregs_helper.h"
600 #if defined(__sparc__) && !defined(HOST_SOLARIS)
601     int saved_i7;
602     target_ulong tmp_T0;
603 #endif
604     int ret, interrupt_request;
605     void (*gen_func)(void);
606     TranslationBlock *tb;
607     uint8_t *tc_ptr;
608
609 #if defined(TARGET_I386)
610     /* handle exit of HALTED state */
611     if (env1->hflags & HF_HALTED_MASK) {
612         /* disable halt condition */
613         if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
614             (env1->eflags & IF_MASK)) {
615             env1->hflags &= ~HF_HALTED_MASK;
616         } else {
617             return EXCP_HALTED;
618         }
619     }
620 #elif defined(TARGET_PPC)
621     if (env1->halted) {
622         if (env1->msr[MSR_EE] &&
623             (env1->interrupt_request &
624              (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
625             env1->halted = 0;
626         } else {
627             return EXCP_HALTED;
628         }
629     }
630 #elif defined(TARGET_SPARC)
631     if (env1->halted) {
632         if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
633             (env1->psret != 0)) {
634             env1->halted = 0;
635         } else {
636             return EXCP_HALTED;
637         }
638     }
639 #elif defined(TARGET_ARM)
640     if (env1->halted) {
641         /* An interrupt wakes the CPU even if the I and F CPSR bits are
642            set.  */
643         if (env1->interrupt_request
644             & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) {
645             env1->halted = 0;
646         } else {
647             return EXCP_HALTED;
648         }
649     }
650 #elif defined(TARGET_MIPS)
651     if (env1->halted) {
652         if (env1->interrupt_request &
653             (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
654             env1->halted = 0;
655         } else {
656             return EXCP_HALTED;
657         }
658     }
659 #endif
660
661     cpu_single_env = env1;
662
663     /* first we save global registers */
664 #define SAVE_HOST_REGS 1
665 #include "hostregs_helper.h"
666     env = env1;
667 #if defined(__sparc__) && !defined(HOST_SOLARIS)
668     /* we also save i7 because longjmp may not restore it */
669     asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
670 #endif
671
672 #if defined(TARGET_I386)
673     env_to_regs();
674     /* put eflags in CPU temporary format */
675     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
676     DF = 1 - (2 * ((env->eflags >> 10) & 1));
677     CC_OP = CC_OP_EFLAGS;
678     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
679 #elif defined(TARGET_ARM)
680 #elif defined(TARGET_SPARC)
681 #if defined(reg_REGWPTR)
682     saved_regwptr = REGWPTR;
683 #endif
684 #elif defined(TARGET_PPC)
685 #elif defined(TARGET_M68K)
686     env->cc_op = CC_OP_FLAGS;
687     env->cc_dest = env->sr & 0xf;
688     env->cc_x = (env->sr >> 4) & 1;
689 #elif defined(TARGET_MIPS)
690 #elif defined(TARGET_SH4)
691     /* XXXXX */
692 #else
693 #error unsupported target CPU
694 #endif
695 #ifndef VBOX /* VBOX: We need to raise traps and suchlike from the outside. */
696     env->exception_index = -1;
697 #endif
698
699     /* prepare setjmp context for exception handling */
700     for(;;) {
701         if (setjmp(env->jmp_env) == 0) {
702             env->current_tb = NULL;
703 #ifdef VBOX
704             VMMR3Unlock(env->pVM);
705             VMMR3Lock(env->pVM);
706
707             /* Check for high priority requests first (like fatal
708                errors). */
709             if (env->interrupt_request & CPU_INTERRUPT_RC) {
710                 env->exception_index = EXCP_RC;
711                 ASMAtomicAndS32(&env->interrupt_request, ~CPU_INTERRUPT_RC);
712                 ret = env->exception_index;
713                 cpu_loop_exit();
714             }
715 #endif /* VBOX */
716
717
718             /* if an exception is pending, we execute it here */
719             if (env->exception_index >= 0) {
720                 if (env->exception_index >= EXCP_INTERRUPT) {
721                     /* exit request from the cpu execution loop */
722                     ret = env->exception_index;
723                     break;
724                 } else if (env->user_mode_only) {
725                     /* if user mode only, we simulate a fake exception
726                        which will be handled outside the cpu execution
727                        loop */
728 #if defined(TARGET_I386)
729                     do_interrupt_user(env->exception_index,
730                                       env->exception_is_int,
731                                       env->error_code,
732                                       env->exception_next_eip);
733 #endif
734                     ret = env->exception_index;
735                     break;
736                 } else {
737 #if defined(TARGET_I386)
738                     /* simulate a real cpu exception. On i386, it can
739                        trigger new exceptions, but we do not handle
740                        double or triple faults yet. */
741                     do_interrupt(env->exception_index,
742                                  env->exception_is_int,
743                                  env->error_code,
744                                  env->exception_next_eip, 0);
745 #elif defined(TARGET_PPC)
746                     do_interrupt(env);
747 #elif defined(TARGET_MIPS)
748                     do_interrupt(env);
749 #elif defined(TARGET_SPARC)
750                     do_interrupt(env->exception_index);
751 #elif defined(TARGET_ARM)
752                     do_interrupt(env);
753 #elif defined(TARGET_SH4)
754                     do_interrupt(env);
755 #endif
756                 }
757                 env->exception_index = -1;
758             }
759 #ifdef USE_KQEMU
760             if (kqemu_is_ok(env) && env->interrupt_request == 0) {
761                 int ret;
762                 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
763                 ret = kqemu_cpu_exec(env);
764                 /* put eflags in CPU temporary format */
765                 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
766                 DF = 1 - (2 * ((env->eflags >> 10) & 1));
767                 CC_OP = CC_OP_EFLAGS;
768                 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
769                 if (ret == 1) {
770                     /* exception */
771                     longjmp(env->jmp_env, 1);
772                 } else if (ret == 2) {
773                     /* softmmu execution needed */
774                 } else {
775                     if (env->interrupt_request != 0) {
776                         /* hardware interrupt will be executed just after */
777                     } else {
778                         /* otherwise, we restart */
779                         longjmp(env->jmp_env, 1);
780                     }
781                 }
782             }
783 #endif
784
785             T0 = 0; /* force lookup of first TB */
786             for(;;) {
787 #if defined(__sparc__) && !defined(HOST_SOLARIS)
788                 /* g1 can be modified by some libc? functions */
789                 tmp_T0 = T0;
790 #endif
791                 interrupt_request = env->interrupt_request;
792                 if (__builtin_expect(interrupt_request, 0)) {
793 #ifdef VBOX
794                     /* Single instruction exec request, we execute it and return (one way or the other).
795                        The caller will always reschedule after doing this operation! */
796                     if (interrupt_request & CPU_INTERRUPT_SINGLE_INSTR)
797                     {
798                         /* not in flight are we? */
799                         if (!(env->interrupt_request & CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT))
800                         {
801                             ASMAtomicOrS32(&env->interrupt_request, CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT);
802                             env->exception_index = EXCP_SINGLE_INSTR;
803                             if (emulate_single_instr(env) == -1)
804                                 AssertMsgFailed(("REM: emulate_single_instr failed for EIP=%RGv!!\n", env->eip));
805
806                             /* When we receive an external interrupt during execution of this single
807                                instruction, then we should stay here. We will leave when we're ready
808                        &nbs