]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - cpu-exec.c
Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging
[lisovros/qemu_apohw.git] / cpu-exec.c
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, see <http://www.gnu.org/licenses/>.
18  */
19 #include "config.h"
20 #include "cpu.h"
21 #include "disas.h"
22 #include "tcg.h"
23 #include "qemu-barrier.h"
24
25 int tb_invalidated_flag;
26
27 //#define CONFIG_DEBUG_EXEC
28
29 bool qemu_cpu_has_work(CPUState *env)
30 {
31     return cpu_has_work(env);
32 }
33
34 void cpu_loop_exit(CPUState *env)
35 {
36     env->current_tb = NULL;
37     longjmp(env->jmp_env, 1);
38 }
39
40 /* exit the current TB from a signal handler. The host registers are
41    restored in a state compatible with the CPU emulator
42  */
43 #if defined(CONFIG_SOFTMMU)
44 void cpu_resume_from_signal(CPUState *env, void *puc)
45 {
46     /* XXX: restore cpu registers saved in host registers */
47
48     env->exception_index = -1;
49     longjmp(env->jmp_env, 1);
50 }
51 #endif
52
53 /* Execute the code without caching the generated code. An interpreter
54    could be used if available. */
55 static void cpu_exec_nocache(CPUState *env, int max_cycles,
56                              TranslationBlock *orig_tb)
57 {
58     unsigned long next_tb;
59     TranslationBlock *tb;
60
61     /* Should never happen.
62        We only end up here when an existing TB is too long.  */
63     if (max_cycles > CF_COUNT_MASK)
64         max_cycles = CF_COUNT_MASK;
65
66     tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
67                      max_cycles);
68     env->current_tb = tb;
69     /* execute the generated code */
70     next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
71     env->current_tb = NULL;
72
73     if ((next_tb & 3) == 2) {
74         /* Restore PC.  This may happen if async event occurs before
75            the TB starts executing.  */
76         cpu_pc_from_tb(env, tb);
77     }
78     tb_phys_invalidate(tb, -1);
79     tb_free(tb);
80 }
81
82 static TranslationBlock *tb_find_slow(CPUState *env,
83                                       target_ulong pc,
84                                       target_ulong cs_base,
85                                       uint64_t flags)
86 {
87     TranslationBlock *tb, **ptb1;
88     unsigned int h;
89     tb_page_addr_t phys_pc, phys_page1, phys_page2;
90     target_ulong virt_page2;
91
92     tb_invalidated_flag = 0;
93
94     /* find translated block using physical mappings */
95     phys_pc = get_page_addr_code(env, pc);
96     phys_page1 = phys_pc & TARGET_PAGE_MASK;
97     phys_page2 = -1;
98     h = tb_phys_hash_func(phys_pc);
99     ptb1 = &tb_phys_hash[h];
100     for(;;) {
101         tb = *ptb1;
102         if (!tb)
103             goto not_found;
104         if (tb->pc == pc &&
105             tb->page_addr[0] == phys_page1 &&
106             tb->cs_base == cs_base &&
107             tb->flags == flags) {
108             /* check next page if needed */
109             if (tb->page_addr[1] != -1) {
110                 virt_page2 = (pc & TARGET_PAGE_MASK) +
111                     TARGET_PAGE_SIZE;
112                 phys_page2 = get_page_addr_code(env, virt_page2);
113                 if (tb->page_addr[1] == phys_page2)
114                     goto found;
115             } else {
116                 goto found;
117             }
118         }
119         ptb1 = &tb->phys_hash_next;
120     }
121  not_found:
122    /* if no translated code available, then translate it now */
123     tb = tb_gen_code(env, pc, cs_base, flags, 0);
124
125  found:
126     /* Move the last found TB to the head of the list */
127     if (likely(*ptb1)) {
128         *ptb1 = tb->phys_hash_next;
129         tb->phys_hash_next = tb_phys_hash[h];
130         tb_phys_hash[h] = tb;
131     }
132     /* we add the TB in the virtual pc hash table */
133     env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
134     return tb;
135 }
136
137 static inline TranslationBlock *tb_find_fast(CPUState *env)
138 {
139     TranslationBlock *tb;
140     target_ulong cs_base, pc;
141     int flags;
142
143     /* we record a subset of the CPU state. It will
144        always be the same before a given translated block
145        is executed. */
146     cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
147     tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
148     if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
149                  tb->flags != flags)) {
150         tb = tb_find_slow(env, pc, cs_base, flags);
151     }
152     return tb;
153 }
154
155 static CPUDebugExcpHandler *debug_excp_handler;
156
157 CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
158 {
159     CPUDebugExcpHandler *old_handler = debug_excp_handler;
160
161     debug_excp_handler = handler;
162     return old_handler;
163 }
164
165 static void cpu_handle_debug_exception(CPUState *env)
166 {
167     CPUWatchpoint *wp;
168
169     if (!env->watchpoint_hit) {
170         QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
171             wp->flags &= ~BP_WATCHPOINT_HIT;
172         }
173     }
174     if (debug_excp_handler) {
175         debug_excp_handler(env);
176     }
177 }
178
179 /* main execution loop */
180
181 volatile sig_atomic_t exit_request;
182
183 int cpu_exec(CPUState *env)
184 {
185     int ret, interrupt_request;
186     TranslationBlock *tb;
187     uint8_t *tc_ptr;
188     unsigned long next_tb;
189
190     if (env->halted) {
191         if (!cpu_has_work(env)) {
192             return EXCP_HALTED;
193         }
194
195         env->halted = 0;
196     }
197
198     cpu_single_env = env;
199
200     if (unlikely(exit_request)) {
201         env->exit_request = 1;
202     }
203
204 #if defined(TARGET_I386)
205     /* put eflags in CPU temporary format */
206     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
207     DF = 1 - (2 * ((env->eflags >> 10) & 1));
208     CC_OP = CC_OP_EFLAGS;
209     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
210 #elif defined(TARGET_SPARC)
211 #elif defined(TARGET_M68K)
212     env->cc_op = CC_OP_FLAGS;
213     env->cc_dest = env->sr & 0xf;
214     env->cc_x = (env->sr >> 4) & 1;
215 #elif defined(TARGET_ALPHA)
216 #elif defined(TARGET_ARM)
217 #elif defined(TARGET_UNICORE32)
218 #elif defined(TARGET_PPC)
219 #elif defined(TARGET_LM32)
220 #elif defined(TARGET_MICROBLAZE)
221 #elif defined(TARGET_MIPS)
222 #elif defined(TARGET_SH4)
223 #elif defined(TARGET_CRIS)
224 #elif defined(TARGET_S390X)
225     /* XXXXX */
226 #else
227 #error unsupported target CPU
228 #endif
229     env->exception_index = -1;
230
231     /* prepare setjmp context for exception handling */
232     for(;;) {
233         if (setjmp(env->jmp_env) == 0) {
234             /* if an exception is pending, we execute it here */
235             if (env->exception_index >= 0) {
236                 if (env->exception_index >= EXCP_INTERRUPT) {
237                     /* exit request from the cpu execution loop */
238                     ret = env->exception_index;
239                     if (ret == EXCP_DEBUG) {
240                         cpu_handle_debug_exception(env);
241                     }
242                     break;
243                 } else {
244 #if defined(CONFIG_USER_ONLY)
245                     /* if user mode only, we simulate a fake exception
246                        which will be handled outside the cpu execution
247                        loop */
248 #if defined(TARGET_I386)
249                     do_interrupt(env);
250 #endif
251                     ret = env->exception_index;
252                     break;
253 #else
254                     do_interrupt(env);
255                     env->exception_index = -1;
256 #endif
257                 }
258             }
259
260             next_tb = 0; /* force lookup of first TB */
261             for(;;) {
262                 interrupt_request = env->interrupt_request;
263                 if (unlikely(interrupt_request)) {
264                     if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
265                         /* Mask out external interrupts for this step. */
266                         interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
267                     }
268                     if (interrupt_request & CPU_INTERRUPT_DEBUG) {
269                         env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
270                         env->exception_index = EXCP_DEBUG;
271                         cpu_loop_exit(env);
272                     }
273 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
274     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
275     defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
276                     if (interrupt_request & CPU_INTERRUPT_HALT) {
277                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
278                         env->halted = 1;
279                         env->exception_index = EXCP_HLT;
280                         cpu_loop_exit(env);
281                     }
282 #endif
283 #if defined(TARGET_I386)
284                     if (interrupt_request & CPU_INTERRUPT_INIT) {
285                             svm_check_intercept(env, SVM_EXIT_INIT);
286                             do_cpu_init(env);
287                             env->exception_index = EXCP_HALTED;
288                             cpu_loop_exit(env);
289                     } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
290                             do_cpu_sipi(env);
291                     } else if (env->hflags2 & HF2_GIF_MASK) {
292                         if ((interrupt_request & CPU_INTERRUPT_SMI) &&
293                             !(env->hflags & HF_SMM_MASK)) {
294                             svm_check_intercept(env, SVM_EXIT_SMI);
295                             env->interrupt_request &= ~CPU_INTERRUPT_SMI;
296                             do_smm_enter(env);
297                             next_tb = 0;
298                         } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
299                                    !(env->hflags2 & HF2_NMI_MASK)) {
300                             env->interrupt_request &= ~CPU_INTERRUPT_NMI;
301                             env->hflags2 |= HF2_NMI_MASK;
302                             do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
303                             next_tb = 0;
304                         } else if (interrupt_request & CPU_INTERRUPT_MCE) {
305                             env->interrupt_request &= ~CPU_INTERRUPT_MCE;
306                             do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
307                             next_tb = 0;
308                         } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
309                                    (((env->hflags2 & HF2_VINTR_MASK) && 
310                                      (env->hflags2 & HF2_HIF_MASK)) ||
311                                     (!(env->hflags2 & HF2_VINTR_MASK) && 
312                                      (env->eflags & IF_MASK && 
313                                       !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
314                             int intno;
315                             svm_check_intercept(env, SVM_EXIT_INTR);
316                             env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
317                             intno = cpu_get_pic_interrupt(env);
318                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
319                             do_interrupt_x86_hardirq(env, intno, 1);
320                             /* ensure that no TB jump will be modified as
321                                the program flow was changed */
322                             next_tb = 0;
323 #if !defined(CONFIG_USER_ONLY)
324                         } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
325                                    (env->eflags & IF_MASK) && 
326                                    !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
327                             int intno;
328                             /* FIXME: this should respect TPR */
329                             svm_check_intercept(env, SVM_EXIT_VINTR);
330                             intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
331                             qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
332                             do_interrupt_x86_hardirq(env, intno, 1);
333                             env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
334                             next_tb = 0;
335 #endif
336                         }
337                     }
338 #elif defined(TARGET_PPC)
339 #if 0
340                     if ((interrupt_request & CPU_INTERRUPT_RESET)) {
341                         cpu_reset(env);
342                     }
343 #endif
344                     if (interrupt_request & CPU_INTERRUPT_HARD) {
345                         ppc_hw_interrupt(env);
346                         if (env->pending_interrupts == 0)
347                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
348                         next_tb = 0;
349                     }
350 #elif defined(TARGET_LM32)
351                     if ((interrupt_request & CPU_INTERRUPT_HARD)
352                         && (env->ie & IE_IE)) {
353                         env->exception_index = EXCP_IRQ;
354                         do_interrupt(env);
355                         next_tb = 0;
356                     }
357 #elif defined(TARGET_MICROBLAZE)
358                     if ((interrupt_request & CPU_INTERRUPT_HARD)
359                         && (env->sregs[SR_MSR] & MSR_IE)
360                         && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
361                         && !(env->iflags & (D_FLAG | IMM_FLAG))) {
362                         env->exception_index = EXCP_IRQ;
363                         do_interrupt(env);
364                         next_tb = 0;
365                     }
366 #elif defined(TARGET_MIPS)
367                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
368                         cpu_mips_hw_interrupts_pending(env)) {
369                         /* Raise it */
370                         env->exception_index = EXCP_EXT_INTERRUPT;
371                         env->error_code = 0;
372                         do_interrupt(env);
373                         next_tb = 0;
374                     }
375 #elif defined(TARGET_SPARC)
376                     if (interrupt_request & CPU_INTERRUPT_HARD) {
377                         if (cpu_interrupts_enabled(env) &&
378                             env->interrupt_index > 0) {
379                             int pil = env->interrupt_index & 0xf;
380                             int type = env->interrupt_index & 0xf0;
381
382                             if (((type == TT_EXTINT) &&
383                                   cpu_pil_allowed(env, pil)) ||
384                                   type != TT_EXTINT) {
385                                 env->exception_index = env->interrupt_index;
386                                 do_interrupt(env);
387                                 next_tb = 0;
388                             }
389                         }
390                     }
391 #elif defined(TARGET_ARM)
392                     if (interrupt_request & CPU_INTERRUPT_FIQ
393                         && !(env->uncached_cpsr & CPSR_F)) {
394                         env->exception_index = EXCP_FIQ;
395                         do_interrupt(env);
396                         next_tb = 0;
397                     }
398                     /* ARMv7-M interrupt return works by loading a magic value
399                        into the PC.  On real hardware the load causes the
400                        return to occur.  The qemu implementation performs the
401                        jump normally, then does the exception return when the
402                        CPU tries to execute code at the magic address.
403                        This will cause the magic PC value to be pushed to
404                        the stack if an interrupt occurred at the wrong time.
405                        We avoid this by disabling interrupts when
406                        pc contains a magic address.  */
407                     if (interrupt_request & CPU_INTERRUPT_HARD
408                         && ((IS_M(env) && env->regs[15] < 0xfffffff0)
409                             || !(env->uncached_cpsr & CPSR_I))) {
410                         env->exception_index = EXCP_IRQ;
411                         do_interrupt(env);
412                         next_tb = 0;
413                     }
414 #elif defined(TARGET_UNICORE32)
415                     if (interrupt_request & CPU_INTERRUPT_HARD
416                         && !(env->uncached_asr & ASR_I)) {
417                         do_interrupt(env);
418                         next_tb = 0;
419                     }
420 #elif defined(TARGET_SH4)
421                     if (interrupt_request & CPU_INTERRUPT_HARD) {
422                         do_interrupt(env);
423                         next_tb = 0;
424                     }
425 #elif defined(TARGET_ALPHA)
426                     {
427                         int idx = -1;
428                         /* ??? This hard-codes the OSF/1 interrupt levels.  */
429                         switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
430                         case 0 ... 3:
431                             if (interrupt_request & CPU_INTERRUPT_HARD) {
432                                 idx = EXCP_DEV_INTERRUPT;
433                             }
434                             /* FALLTHRU */
435                         case 4:
436                             if (interrupt_request & CPU_INTERRUPT_TIMER) {
437                                 idx = EXCP_CLK_INTERRUPT;
438                             }
439                             /* FALLTHRU */
440                         case 5:
441                             if (interrupt_request & CPU_INTERRUPT_SMP) {
442                                 idx = EXCP_SMP_INTERRUPT;
443                             }
444                             /* FALLTHRU */
445                         case 6:
446                             if (interrupt_request & CPU_INTERRUPT_MCHK) {
447                                 idx = EXCP_MCHK;
448                             }
449                         }
450                         if (idx >= 0) {
451                             env->exception_index = idx;
452                             env->error_code = 0;
453                             do_interrupt(env);
454                             next_tb = 0;
455                         }
456                     }
457 #elif defined(TARGET_CRIS)
458                     if (interrupt_request & CPU_INTERRUPT_HARD
459                         && (env->pregs[PR_CCS] & I_FLAG)
460                         && !env->locked_irq) {
461                         env->exception_index = EXCP_IRQ;
462                         do_interrupt(env);
463                         next_tb = 0;
464                     }
465                     if (interrupt_request & CPU_INTERRUPT_NMI
466                         && (env->pregs[PR_CCS] & M_FLAG)) {
467                         env->exception_index = EXCP_NMI;
468                         do_interrupt(env);
469                         next_tb = 0;
470                     }
471 #elif defined(TARGET_M68K)
472                     if (interrupt_request & CPU_INTERRUPT_HARD
473                         && ((env->sr & SR_I) >> SR_I_SHIFT)
474                             < env->pending_level) {
475                         /* Real hardware gets the interrupt vector via an
476                            IACK cycle at this point.  Current emulated
477                            hardware doesn't rely on this, so we
478                            provide/save the vector when the interrupt is
479                            first signalled.  */
480                         env->exception_index = env->pending_vector;
481                         do_interrupt_m68k_hardirq(env);
482                         next_tb = 0;
483                     }
484 #elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
485                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
486                         (env->psw.mask & PSW_MASK_EXT)) {
487                         do_interrupt(env);
488                         next_tb = 0;
489                     }
490 #endif
491                    /* Don't use the cached interrupt_request value,
492                       do_interrupt may have updated the EXITTB flag. */
493                     if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
494                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
495                         /* ensure that no TB jump will be modified as
496                            the program flow was changed */
497                         next_tb = 0;
498                     }
499                 }
500                 if (unlikely(env->exit_request)) {
501                     env->exit_request = 0;
502                     env->exception_index = EXCP_INTERRUPT;
503                     cpu_loop_exit(env);
504                 }
505 #if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
506                 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
507                     /* restore flags in standard format */
508 #if defined(TARGET_I386)
509                     env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
510                         | (DF & DF_MASK);
511                     log_cpu_state(env, X86_DUMP_CCOP);
512                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
513 #elif defined(TARGET_M68K)
514                     cpu_m68k_flush_flags(env, env->cc_op);
515                     env->cc_op = CC_OP_FLAGS;
516                     env->sr = (env->sr & 0xffe0)
517                               | env->cc_dest | (env->cc_x << 4);
518                     log_cpu_state(env, 0);
519 #else
520                     log_cpu_state(env, 0);
521 #endif
522                 }
523 #endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
524                 spin_lock(&tb_lock);
525                 tb = tb_find_fast(env);
526                 /* Note: we do it here to avoid a gcc bug on Mac OS X when
527                    doing it in tb_find_slow */
528                 if (tb_invalidated_flag) {
529                     /* as some TB could have been invalidated because
530                        of memory exceptions while generating the code, we
531                        must recompute the hash index here */
532                     next_tb = 0;
533                     tb_invalidated_flag = 0;
534                 }
535 #ifdef CONFIG_DEBUG_EXEC
536                 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
537                              (long)tb->tc_ptr, tb->pc,
538                              lookup_symbol(tb->pc));
539 #endif
540                 /* see if we can patch the calling TB. When the TB
541                    spans two pages, we cannot safely do a direct
542                    jump. */
543                 if (next_tb != 0 && tb->page_addr[1] == -1) {
544                     tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
545                 }
546                 spin_unlock(&tb_lock);
547
548                 /* cpu_interrupt might be called while translating the
549                    TB, but before it is linked into a potentially
550                    infinite loop and becomes env->current_tb. Avoid
551                    starting execution if there is a pending interrupt. */
552                 env->current_tb = tb;
553                 barrier();
554                 if (likely(!env->exit_request)) {
555                     tc_ptr = tb->tc_ptr;
556                 /* execute the generated code */
557                     next_tb = tcg_qemu_tb_exec(env, tc_ptr);
558                     if ((next_tb & 3) == 2) {
559                         /* Instruction counter expired.  */
560                         int insns_left;
561                         tb = (TranslationBlock *)(long)(next_tb & ~3);
562                         /* Restore PC.  */
563                         cpu_pc_from_tb(env, tb);
564                         insns_left = env->icount_decr.u32;
565                         if (env->icount_extra && insns_left >= 0) {
566                             /* Refill decrementer and continue execution.  */
567                             env->icount_extra += insns_left;
568                             if (env->icount_extra > 0xffff) {
569                                 insns_left = 0xffff;
570                             } else {
571                                 insns_left = env->icount_extra;
572                             }
573                             env->icount_extra -= insns_left;
574                             env->icount_decr.u16.low = insns_left;
575                         } else {
576                             if (insns_left > 0) {
577                                 /* Execute remaining instructions.  */
578                                 cpu_exec_nocache(env, insns_left, tb);
579                             }
580                             env->exception_index = EXCP_INTERRUPT;
581                             next_tb = 0;
582                             cpu_loop_exit(env);
583                         }
584                     }
585                 }
586                 env->current_tb = NULL;
587                 /* reset soft MMU for next block (it can currently
588                    only be set by a memory fault) */
589             } /* for(;;) */
590         } else {
591             /* Reload env after longjmp - the compiler may have smashed all
592              * local variables as longjmp is marked 'noreturn'. */
593             env = cpu_single_env;
594         }
595     } /* for(;;) */
596
597
598 #if defined(TARGET_I386)
599     /* restore flags in standard format */
600     env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
601         | (DF & DF_MASK);
602 #elif defined(TARGET_ARM)
603     /* XXX: Save/restore host fpu exception state?.  */
604 #elif defined(TARGET_UNICORE32)
605 #elif defined(TARGET_SPARC)
606 #elif defined(TARGET_PPC)
607 #elif defined(TARGET_LM32)
608 #elif defined(TARGET_M68K)
609     cpu_m68k_flush_flags(env, env->cc_op);
610     env->cc_op = CC_OP_FLAGS;
611     env->sr = (env->sr & 0xffe0)
612               | env->cc_dest | (env->cc_x << 4);
613 #elif defined(TARGET_MICROBLAZE)
614 #elif defined(TARGET_MIPS)
615 #elif defined(TARGET_SH4)
616 #elif defined(TARGET_ALPHA)
617 #elif defined(TARGET_CRIS)
618 #elif defined(TARGET_S390X)
619     /* XXXXX */
620 #else
621 #error unsupported target CPU
622 #endif
623
624     /* fail safe : never use cpu_single_env outside cpu_exec() */
625     cpu_single_env = NULL;
626     return ret;
627 }