cpu-exec.c 25.2 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  i386 emulator main execution loop
3
 *
B
bellard 已提交
4
 *  Copyright (c) 2003-2005 Fabrice Bellard
B
bellard 已提交
5
 *
B
bellard 已提交
6 7 8 9
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
B
bellard 已提交
10
 *
B
bellard 已提交
11 12 13 14
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
B
bellard 已提交
15
 *
B
bellard 已提交
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/>.
B
bellard 已提交
18
 */
B
bellard 已提交
19
#include "config.h"
B
Blue Swirl 已提交
20
#include "cpu.h"
B
log fix  
bellard 已提交
21
#include "disas.h"
22
#include "tcg.h"
J
Jan Kiszka 已提交
23
#include "qemu-barrier.h"
B
bellard 已提交
24

25 26
int tb_invalidated_flag;

27
//#define CONFIG_DEBUG_EXEC
B
bellard 已提交
28

29
bool qemu_cpu_has_work(CPUState *env)
30 31 32 33
{
    return cpu_has_work(env);
}

B
Blue Swirl 已提交
34
void cpu_loop_exit(CPUState *env)
B
bellard 已提交
35
{
B
Blue Swirl 已提交
36 37
    env->current_tb = NULL;
    longjmp(env->jmp_env, 1);
B
bellard 已提交
38
}
39

40 41 42
/* exit the current TB from a signal handler. The host registers are
   restored in a state compatible with the CPU emulator
 */
43
#if defined(CONFIG_SOFTMMU)
B
Blue Swirl 已提交
44
void cpu_resume_from_signal(CPUState *env, void *puc)
45 46 47 48 49 50 51
{
    /* XXX: restore cpu registers saved in host registers */

    env->exception_index = -1;
    longjmp(env->jmp_env, 1);
}
#endif
52

P
pbrook 已提交
53 54
/* Execute the code without caching the generated code. An interpreter
   could be used if available. */
B
Blue Swirl 已提交
55 56
static void cpu_exec_nocache(CPUState *env, int max_cycles,
                             TranslationBlock *orig_tb)
P
pbrook 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69
{
    unsigned long next_tb;
    TranslationBlock *tb;

    /* Should never happen.
       We only end up here when an existing TB is too long.  */
    if (max_cycles > CF_COUNT_MASK)
        max_cycles = CF_COUNT_MASK;

    tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
                     max_cycles);
    env->current_tb = tb;
    /* execute the generated code */
B
Blue Swirl 已提交
70
    next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
P
Paolo Bonzini 已提交
71
    env->current_tb = NULL;
P
pbrook 已提交
72 73 74 75

    if ((next_tb & 3) == 2) {
        /* Restore PC.  This may happen if async event occurs before
           the TB starts executing.  */
76
        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
77 78 79 80 81
    }
    tb_phys_invalidate(tb, -1);
    tb_free(tb);
}

B
Blue Swirl 已提交
82 83
static TranslationBlock *tb_find_slow(CPUState *env,
                                      target_ulong pc,
84
                                      target_ulong cs_base,
85
                                      uint64_t flags)
86 87 88
{
    TranslationBlock *tb, **ptb1;
    unsigned int h;
89
    tb_page_addr_t phys_pc, phys_page1;
P
Paul Brook 已提交
90
    target_ulong virt_page2;
91

92
    tb_invalidated_flag = 0;
93

94
    /* find translated block using physical mappings */
P
Paul Brook 已提交
95
    phys_pc = get_page_addr_code(env, pc);
96 97 98 99 100 101 102
    phys_page1 = phys_pc & TARGET_PAGE_MASK;
    h = tb_phys_hash_func(phys_pc);
    ptb1 = &tb_phys_hash[h];
    for(;;) {
        tb = *ptb1;
        if (!tb)
            goto not_found;
103
        if (tb->pc == pc &&
104
            tb->page_addr[0] == phys_page1 &&
105
            tb->cs_base == cs_base &&
106 107 108
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
109 110
                tb_page_addr_t phys_page2;

111
                virt_page2 = (pc & TARGET_PAGE_MASK) +
112
                    TARGET_PAGE_SIZE;
P
Paul Brook 已提交
113
                phys_page2 = get_page_addr_code(env, virt_page2);
114 115 116 117 118 119 120 121 122
                if (tb->page_addr[1] == phys_page2)
                    goto found;
            } else {
                goto found;
            }
        }
        ptb1 = &tb->phys_hash_next;
    }
 not_found:
P
pbrook 已提交
123 124
   /* if no translated code available, then translate it now */
    tb = tb_gen_code(env, pc, cs_base, flags, 0);
125

126
 found:
127 128 129 130 131 132
    /* Move the last found TB to the head of the list */
    if (likely(*ptb1)) {
        *ptb1 = tb->phys_hash_next;
        tb->phys_hash_next = tb_phys_hash[h];
        tb_phys_hash[h] = tb;
    }
133 134 135 136 137
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    return tb;
}

B
Blue Swirl 已提交
138
static inline TranslationBlock *tb_find_fast(CPUState *env)
139 140 141
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
142
    int flags;
143 144 145 146

    /* we record a subset of the CPU state. It will
       always be the same before a given translated block
       is executed. */
147
    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
B
bellard 已提交
148
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
149 150
    if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                 tb->flags != flags)) {
B
Blue Swirl 已提交
151
        tb = tb_find_slow(env, pc, cs_base, flags);
152 153 154 155
    }
    return tb;
}

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
static CPUDebugExcpHandler *debug_excp_handler;

CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
{
    CPUDebugExcpHandler *old_handler = debug_excp_handler;

    debug_excp_handler = handler;
    return old_handler;
}

static void cpu_handle_debug_exception(CPUState *env)
{
    CPUWatchpoint *wp;

    if (!env->watchpoint_hit) {
        QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
            wp->flags &= ~BP_WATCHPOINT_HIT;
        }
    }
    if (debug_excp_handler) {
        debug_excp_handler(env);
    }
}

B
bellard 已提交
180 181
/* main execution loop */

182 183
volatile sig_atomic_t exit_request;

B
Blue Swirl 已提交
184
int cpu_exec(CPUState *env)
B
bellard 已提交
185
{
186 187
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
188
    uint8_t *tc_ptr;
P
pbrook 已提交
189
    unsigned long next_tb;
190

B
Blue Swirl 已提交
191 192
    if (env->halted) {
        if (!cpu_has_work(env)) {
193 194 195
            return EXCP_HALTED;
        }

B
Blue Swirl 已提交
196
        env->halted = 0;
197
    }
B
bellard 已提交
198

B
Blue Swirl 已提交
199
    cpu_single_env = env;
B
bellard 已提交
200

J
Jan Kiszka 已提交
201
    if (unlikely(exit_request)) {
202 203 204
        env->exit_request = 1;
    }

205
#if defined(TARGET_I386)
206 207 208 209 210
    /* put eflags in CPU temporary format */
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
    CC_OP = CC_OP_EFLAGS;
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
211
#elif defined(TARGET_SPARC)
P
pbrook 已提交
212 213 214 215
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
216 217
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
218
#elif defined(TARGET_UNICORE32)
219
#elif defined(TARGET_PPC)
220
    env->reserve_addr = -1;
M
Michael Walle 已提交
221
#elif defined(TARGET_LM32)
222
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
223
#elif defined(TARGET_MIPS)
B
bellard 已提交
224
#elif defined(TARGET_SH4)
225
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
226
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
227
#elif defined(TARGET_XTENSA)
B
bellard 已提交
228
    /* XXXXX */
B
bellard 已提交
229 230 231
#else
#error unsupported target CPU
#endif
232
    env->exception_index = -1;
233

B
bellard 已提交
234
    /* prepare setjmp context for exception handling */
235 236 237 238 239 240 241
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
            /* if an exception is pending, we execute it here */
            if (env->exception_index >= 0) {
                if (env->exception_index >= EXCP_INTERRUPT) {
                    /* exit request from the cpu execution loop */
                    ret = env->exception_index;
242 243 244
                    if (ret == EXCP_DEBUG) {
                        cpu_handle_debug_exception(env);
                    }
245
                    break;
A
aurel32 已提交
246 247
                } else {
#if defined(CONFIG_USER_ONLY)
248
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
249
                       which will be handled outside the cpu execution
250
                       loop */
B
bellard 已提交
251
#if defined(TARGET_I386)
252
                    do_interrupt(env);
B
bellard 已提交
253
#endif
254 255
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
256
#else
B
bellard 已提交
257
                    do_interrupt(env);
258
                    env->exception_index = -1;
B
bellard 已提交
259
#endif
260
                }
261
            }
B
bellard 已提交
262

263
            next_tb = 0; /* force lookup of first TB */
264
            for(;;) {
B
bellard 已提交
265
                interrupt_request = env->interrupt_request;
M
malc 已提交
266 267 268
                if (unlikely(interrupt_request)) {
                    if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
                        /* Mask out external interrupts for this step. */
269
                        interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
M
malc 已提交
270
                    }
271 272 273
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                        env->exception_index = EXCP_DEBUG;
B
Blue Swirl 已提交
274
                        cpu_loop_exit(env);
275
                    }
276
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
277
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
278
    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
279 280 281 282
                    if (interrupt_request & CPU_INTERRUPT_HALT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                        env->halted = 1;
                        env->exception_index = EXCP_HLT;
B
Blue Swirl 已提交
283
                        cpu_loop_exit(env);
284 285
                    }
#endif
B
bellard 已提交
286
#if defined(TARGET_I386)
287
                    if (interrupt_request & CPU_INTERRUPT_INIT) {
288
                            svm_check_intercept(env, SVM_EXIT_INIT);
289 290
                            do_cpu_init(env);
                            env->exception_index = EXCP_HALTED;
B
Blue Swirl 已提交
291
                            cpu_loop_exit(env);
292 293 294
                    } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
                            do_cpu_sipi(env);
                    } else if (env->hflags2 & HF2_GIF_MASK) {
295 296
                        if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                            !(env->hflags & HF_SMM_MASK)) {
297
                            svm_check_intercept(env, SVM_EXIT_SMI);
298
                            env->interrupt_request &= ~CPU_INTERRUPT_SMI;
299
                            do_smm_enter(env);
300 301 302 303 304
                            next_tb = 0;
                        } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
                                   !(env->hflags2 & HF2_NMI_MASK)) {
                            env->interrupt_request &= ~CPU_INTERRUPT_NMI;
                            env->hflags2 |= HF2_NMI_MASK;
305
                            do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
306
                            next_tb = 0;
307 308
			} else if (interrupt_request & CPU_INTERRUPT_MCE) {
                            env->interrupt_request &= ~CPU_INTERRUPT_MCE;
309
                            do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
310
                            next_tb = 0;
311 312 313 314 315 316 317
                        } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                                   (((env->hflags2 & HF2_VINTR_MASK) && 
                                     (env->hflags2 & HF2_HIF_MASK)) ||
                                    (!(env->hflags2 & HF2_VINTR_MASK) && 
                                     (env->eflags & IF_MASK && 
                                      !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
                            int intno;
318
                            svm_check_intercept(env, SVM_EXIT_INTR);
319 320
                            env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
                            intno = cpu_get_pic_interrupt(env);
321
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
322
                            do_interrupt_x86_hardirq(env, intno, 1);
323 324 325
                            /* ensure that no TB jump will be modified as
                               the program flow was changed */
                            next_tb = 0;
T
ths 已提交
326
#if !defined(CONFIG_USER_ONLY)
327 328 329 330 331
                        } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
                                   (env->eflags & IF_MASK) && 
                                   !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                            int intno;
                            /* FIXME: this should respect TPR */
332
                            svm_check_intercept(env, SVM_EXIT_VINTR);
333
                            intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
334
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
335
                            do_interrupt_x86_hardirq(env, intno, 1);
336
                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
337
                            next_tb = 0;
B
bellard 已提交
338
#endif
339
                        }
B
bellard 已提交
340
                    }
341
#elif defined(TARGET_PPC)
342 343
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
344
                        cpu_reset(env);
345 346
                    }
#endif
347
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
348 349 350
                        ppc_hw_interrupt(env);
                        if (env->pending_interrupts == 0)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
351
                        next_tb = 0;
352
                    }
M
Michael Walle 已提交
353 354 355 356 357 358 359
#elif defined(TARGET_LM32)
                    if ((interrupt_request & CPU_INTERRUPT_HARD)
                        && (env->ie & IE_IE)) {
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
                        next_tb = 0;
                    }
360 361 362 363 364 365 366 367 368
#elif defined(TARGET_MICROBLAZE)
                    if ((interrupt_request & CPU_INTERRUPT_HARD)
                        && (env->sregs[SR_MSR] & MSR_IE)
                        && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
                        && !(env->iflags & (D_FLAG | IMM_FLAG))) {
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
                        next_tb = 0;
                    }
B
bellard 已提交
369 370
#elif defined(TARGET_MIPS)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
371
                        cpu_mips_hw_interrupts_pending(env)) {
B
bellard 已提交
372 373 374 375
                        /* Raise it */
                        env->exception_index = EXCP_EXT_INTERRUPT;
                        env->error_code = 0;
                        do_interrupt(env);
376
                        next_tb = 0;
B
bellard 已提交
377
                    }
378
#elif defined(TARGET_SPARC)
379 380 381 382 383 384 385 386 387 388 389 390 391 392
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        if (cpu_interrupts_enabled(env) &&
                            env->interrupt_index > 0) {
                            int pil = env->interrupt_index & 0xf;
                            int type = env->interrupt_index & 0xf0;

                            if (((type == TT_EXTINT) &&
                                  cpu_pil_allowed(env, pil)) ||
                                  type != TT_EXTINT) {
                                env->exception_index = env->interrupt_index;
                                do_interrupt(env);
                                next_tb = 0;
                            }
                        }
393
		    }
B
bellard 已提交
394 395 396 397 398
#elif defined(TARGET_ARM)
                    if (interrupt_request & CPU_INTERRUPT_FIQ
                        && !(env->uncached_cpsr & CPSR_F)) {
                        env->exception_index = EXCP_FIQ;
                        do_interrupt(env);
399
                        next_tb = 0;
B
bellard 已提交
400
                    }
P
pbrook 已提交
401 402 403 404 405 406
                    /* ARMv7-M interrupt return works by loading a magic value
                       into the PC.  On real hardware the load causes the
                       return to occur.  The qemu implementation performs the
                       jump normally, then does the exception return when the
                       CPU tries to execute code at the magic address.
                       This will cause the magic PC value to be pushed to
407
                       the stack if an interrupt occurred at the wrong time.
P
pbrook 已提交
408 409
                       We avoid this by disabling interrupts when
                       pc contains a magic address.  */
B
bellard 已提交
410
                    if (interrupt_request & CPU_INTERRUPT_HARD
P
pbrook 已提交
411 412
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                            || !(env->uncached_cpsr & CPSR_I))) {
B
bellard 已提交
413 414
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
415
                        next_tb = 0;
B
bellard 已提交
416
                    }
417 418 419 420 421 422
#elif defined(TARGET_UNICORE32)
                    if (interrupt_request & CPU_INTERRUPT_HARD
                        && !(env->uncached_asr & ASR_I)) {
                        do_interrupt(env);
                        next_tb = 0;
                    }
B
bellard 已提交
423
#elif defined(TARGET_SH4)
424 425
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
426
                        next_tb = 0;
427
                    }
J
j_mayer 已提交
428
#elif defined(TARGET_ALPHA)
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
                    {
                        int idx = -1;
                        /* ??? This hard-codes the OSF/1 interrupt levels.  */
		        switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
                        case 0 ... 3:
                            if (interrupt_request & CPU_INTERRUPT_HARD) {
                                idx = EXCP_DEV_INTERRUPT;
                            }
                            /* FALLTHRU */
                        case 4:
                            if (interrupt_request & CPU_INTERRUPT_TIMER) {
                                idx = EXCP_CLK_INTERRUPT;
                            }
                            /* FALLTHRU */
                        case 5:
                            if (interrupt_request & CPU_INTERRUPT_SMP) {
                                idx = EXCP_SMP_INTERRUPT;
                            }
                            /* FALLTHRU */
                        case 6:
                            if (interrupt_request & CPU_INTERRUPT_MCHK) {
                                idx = EXCP_MCHK;
                            }
                        }
                        if (idx >= 0) {
                            env->exception_index = idx;
                            env->error_code = 0;
                            do_interrupt(env);
                            next_tb = 0;
                        }
J
j_mayer 已提交
459
                    }
460
#elif defined(TARGET_CRIS)
E
edgar_igl 已提交
461
                    if (interrupt_request & CPU_INTERRUPT_HARD
E
Edgar E. Iglesias 已提交
462 463
                        && (env->pregs[PR_CCS] & I_FLAG)
                        && !env->locked_irq) {
E
edgar_igl 已提交
464 465 466 467 468 469 470
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
                        next_tb = 0;
                    }
                    if (interrupt_request & CPU_INTERRUPT_NMI
                        && (env->pregs[PR_CCS] & M_FLAG)) {
                        env->exception_index = EXCP_NMI;
471
                        do_interrupt(env);
472
                        next_tb = 0;
473
                    }
P
pbrook 已提交
474 475 476 477 478 479 480 481 482 483
#elif defined(TARGET_M68K)
                    if (interrupt_request & CPU_INTERRUPT_HARD
                        && ((env->sr & SR_I) >> SR_I_SHIFT)
                            < env->pending_level) {
                        /* Real hardware gets the interrupt vector via an
                           IACK cycle at this point.  Current emulated
                           hardware doesn't rely on this, so we
                           provide/save the vector when the interrupt is
                           first signalled.  */
                        env->exception_index = env->pending_vector;
484
                        do_interrupt_m68k_hardirq(env);
485
                        next_tb = 0;
P
pbrook 已提交
486
                    }
487 488 489 490 491 492
#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                        (env->psw.mask & PSW_MASK_EXT)) {
                        do_interrupt(env);
                        next_tb = 0;
                    }
493 494 495 496 497 498
#elif defined(TARGET_XTENSA)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        env->exception_index = EXC_IRQ;
                        do_interrupt(env);
                        next_tb = 0;
                    }
B
bellard 已提交
499
#endif
500
                   /* Don't use the cached interrupt_request value,
B
bellard 已提交
501
                      do_interrupt may have updated the EXITTB flag. */
B
bellard 已提交
502
                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
503 504 505
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
506
                        next_tb = 0;
507
                    }
508 509 510 511
                }
                if (unlikely(env->exit_request)) {
                    env->exit_request = 0;
                    env->exception_index = EXCP_INTERRUPT;
B
Blue Swirl 已提交
512
                    cpu_loop_exit(env);
513
                }
514
#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
515
                if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
516
                    /* restore flags in standard format */
517
#if defined(TARGET_I386)
518 519
                    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
                        | (DF & DF_MASK);
520
                    log_cpu_state(env, X86_DUMP_CCOP);
521
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
P
pbrook 已提交
522 523 524 525 526
#elif defined(TARGET_M68K)
                    cpu_m68k_flush_flags(env, env->cc_op);
                    env->cc_op = CC_OP_FLAGS;
                    env->sr = (env->sr & 0xffe0)
                              | env->cc_dest | (env->cc_x << 4);
527
                    log_cpu_state(env, 0);
B
bellard 已提交
528
#else
529
                    log_cpu_state(env, 0);
B
bellard 已提交
530
#endif
531
                }
532
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
P
pbrook 已提交
533
                spin_lock(&tb_lock);
B
Blue Swirl 已提交
534
                tb = tb_find_fast(env);
P
pbrook 已提交
535 536 537 538 539 540 541
                /* Note: we do it here to avoid a gcc bug on Mac OS X when
                   doing it in tb_find_slow */
                if (tb_invalidated_flag) {
                    /* as some TB could have been invalidated because
                       of memory exceptions while generating the code, we
                       must recompute the hash index here */
                    next_tb = 0;
P
pbrook 已提交
542
                    tb_invalidated_flag = 0;
P
pbrook 已提交
543
                }
544
#ifdef CONFIG_DEBUG_EXEC
545 546 547
                qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                             (long)tb->tc_ptr, tb->pc,
                             lookup_symbol(tb->pc));
548
#endif
549 550 551
                /* see if we can patch the calling TB. When the TB
                   spans two pages, we cannot safely do a direct
                   jump. */
P
Paolo Bonzini 已提交
552
                if (next_tb != 0 && tb->page_addr[1] == -1) {
553
                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
554
                }
P
pbrook 已提交
555
                spin_unlock(&tb_lock);
556 557 558 559 560

                /* cpu_interrupt might be called while translating the
                   TB, but before it is linked into a potentially
                   infinite loop and becomes env->current_tb. Avoid
                   starting execution if there is a pending interrupt. */
J
Jan Kiszka 已提交
561 562 563
                env->current_tb = tb;
                barrier();
                if (likely(!env->exit_request)) {
P
pbrook 已提交
564
                    tc_ptr = tb->tc_ptr;
565
                /* execute the generated code */
B
Blue Swirl 已提交
566
                    next_tb = tcg_qemu_tb_exec(env, tc_ptr);
P
pbrook 已提交
567
                    if ((next_tb & 3) == 2) {
T
ths 已提交
568
                        /* Instruction counter expired.  */
P
pbrook 已提交
569 570 571
                        int insns_left;
                        tb = (TranslationBlock *)(long)(next_tb & ~3);
                        /* Restore PC.  */
572
                        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586
                        insns_left = env->icount_decr.u32;
                        if (env->icount_extra && insns_left >= 0) {
                            /* Refill decrementer and continue execution.  */
                            env->icount_extra += insns_left;
                            if (env->icount_extra > 0xffff) {
                                insns_left = 0xffff;
                            } else {
                                insns_left = env->icount_extra;
                            }
                            env->icount_extra -= insns_left;
                            env->icount_decr.u16.low = insns_left;
                        } else {
                            if (insns_left > 0) {
                                /* Execute remaining instructions.  */
B
Blue Swirl 已提交
587
                                cpu_exec_nocache(env, insns_left, tb);
P
pbrook 已提交
588 589 590
                            }
                            env->exception_index = EXCP_INTERRUPT;
                            next_tb = 0;
B
Blue Swirl 已提交
591
                            cpu_loop_exit(env);
P
pbrook 已提交
592 593 594
                        }
                    }
                }
J
Jan Kiszka 已提交
595
                env->current_tb = NULL;
B
bellard 已提交
596 597
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
598
            } /* for(;;) */
599 600 601 602
        } else {
            /* Reload env after longjmp - the compiler may have smashed all
             * local variables as longjmp is marked 'noreturn'. */
            env = cpu_single_env;
B
bellard 已提交
603
        }
604 605
    } /* for(;;) */

B
bellard 已提交
606

B
bellard 已提交
607
#if defined(TARGET_I386)
B
bellard 已提交
608
    /* restore flags in standard format */
609 610
    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
        | (DF & DF_MASK);
B
bellard 已提交
611
#elif defined(TARGET_ARM)
B
bellard 已提交
612
    /* XXX: Save/restore host fpu exception state?.  */
613
#elif defined(TARGET_UNICORE32)
614
#elif defined(TARGET_SPARC)
615
#elif defined(TARGET_PPC)
M
Michael Walle 已提交
616
#elif defined(TARGET_LM32)
P
pbrook 已提交
617 618 619 620 621
#elif defined(TARGET_M68K)
    cpu_m68k_flush_flags(env, env->cc_op);
    env->cc_op = CC_OP_FLAGS;
    env->sr = (env->sr & 0xffe0)
              | env->cc_dest | (env->cc_x << 4);
622
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
623
#elif defined(TARGET_MIPS)
B
bellard 已提交
624
#elif defined(TARGET_SH4)
J
j_mayer 已提交
625
#elif defined(TARGET_ALPHA)
626
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
627
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
628
#elif defined(TARGET_XTENSA)
B
bellard 已提交
629
    /* XXXXX */
B
bellard 已提交
630 631 632
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
633

B
bellard 已提交
634
    /* fail safe : never use cpu_single_env outside cpu_exec() */
635
    cpu_single_env = NULL;
B
bellard 已提交
636 637
    return ret;
}