cpu-exec.c 26.9 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"
20
#include "exec.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
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
26 27 28 29 30
// Work around ugly bugs in glibc that mangle global register contents
#undef env
#define env cpu_single_env
#endif

31 32
int tb_invalidated_flag;

33
//#define CONFIG_DEBUG_EXEC
B
bellard 已提交
34

35 36 37 38 39
int qemu_cpu_has_work(CPUState *env)
{
    return cpu_has_work(env);
}

B
bellard 已提交
40 41
void cpu_loop_exit(void)
{
P
Paolo Bonzini 已提交
42
    env->current_tb = NULL;
B
bellard 已提交
43 44
    longjmp(env->jmp_env, 1);
}
45

46 47 48
/* exit the current TB from a signal handler. The host registers are
   restored in a state compatible with the CPU emulator
 */
49 50 51 52 53 54 55 56 57 58 59
#if defined(CONFIG_SOFTMMU)
void cpu_resume_from_signal(CPUState *env1, void *puc)
{
    env = env1;

    /* XXX: restore cpu registers saved in host registers */

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

P
pbrook 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/* Execute the code without caching the generated code. An interpreter
   could be used if available. */
static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
{
    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 */
    next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
P
Paolo Bonzini 已提交
78
    env->current_tb = NULL;
P
pbrook 已提交
79 80 81 82

    if ((next_tb & 3) == 2) {
        /* Restore PC.  This may happen if async event occurs before
           the TB starts executing.  */
83
        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
84 85 86 87 88
    }
    tb_phys_invalidate(tb, -1);
    tb_free(tb);
}

89 90
static TranslationBlock *tb_find_slow(target_ulong pc,
                                      target_ulong cs_base,
91
                                      uint64_t flags)
92 93 94
{
    TranslationBlock *tb, **ptb1;
    unsigned int h;
P
Paul Brook 已提交
95 96
    tb_page_addr_t phys_pc, phys_page1, phys_page2;
    target_ulong virt_page2;
97

98
    tb_invalidated_flag = 0;
99

100
    /* find translated block using physical mappings */
P
Paul Brook 已提交
101
    phys_pc = get_page_addr_code(env, pc);
102 103 104 105 106 107 108 109
    phys_page1 = phys_pc & TARGET_PAGE_MASK;
    phys_page2 = -1;
    h = tb_phys_hash_func(phys_pc);
    ptb1 = &tb_phys_hash[h];
    for(;;) {
        tb = *ptb1;
        if (!tb)
            goto not_found;
110
        if (tb->pc == pc &&
111
            tb->page_addr[0] == phys_page1 &&
112
            tb->cs_base == cs_base &&
113 114 115
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
116
                virt_page2 = (pc & TARGET_PAGE_MASK) +
117
                    TARGET_PAGE_SIZE;
P
Paul Brook 已提交
118
                phys_page2 = get_page_addr_code(env, virt_page2);
119 120 121 122 123 124 125 126 127
                if (tb->page_addr[1] == phys_page2)
                    goto found;
            } else {
                goto found;
            }
        }
        ptb1 = &tb->phys_hash_next;
    }
 not_found:
P
pbrook 已提交
128 129
   /* if no translated code available, then translate it now */
    tb = tb_gen_code(env, pc, cs_base, flags, 0);
130

131
 found:
132 133 134 135 136 137
    /* 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;
    }
138 139 140 141 142 143 144 145 146
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    return tb;
}

static inline TranslationBlock *tb_find_fast(void)
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
147
    int flags;
148 149 150 151

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

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
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 已提交
185 186
/* main execution loop */

187 188
volatile sig_atomic_t exit_request;

B
bellard 已提交
189
int cpu_exec(CPUState *env1)
B
bellard 已提交
190
{
191
    volatile host_reg_t saved_env_reg;
192 193
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
194
    uint8_t *tc_ptr;
P
pbrook 已提交
195
    unsigned long next_tb;
196

197 198 199 200 201 202 203
    if (env1->halted) {
        if (!cpu_has_work(env1)) {
            return EXCP_HALTED;
        }

        env1->halted = 0;
    }
B
bellard 已提交
204

205
    cpu_single_env = env1;
B
bellard 已提交
206

P
Paolo Bonzini 已提交
207 208 209 210 211
    /* the access to env below is actually saving the global register's
       value, so that files not including target-xyz/exec.h are free to
       use it.  */
    QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
    saved_env_reg = (host_reg_t) env;
J
Jan Kiszka 已提交
212
    barrier();
B
bellard 已提交
213
    env = env1;
B
bellard 已提交
214

J
Jan Kiszka 已提交
215
    if (unlikely(exit_request)) {
216 217 218
        env->exit_request = 1;
    }

219
#if defined(TARGET_I386)
220 221 222 223 224
    /* 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);
225
#elif defined(TARGET_SPARC)
P
pbrook 已提交
226 227 228 229
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
230 231
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
232
#elif defined(TARGET_UNICORE32)
233
#elif defined(TARGET_PPC)
M
Michael Walle 已提交
234
#elif defined(TARGET_LM32)
235
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
236
#elif defined(TARGET_MIPS)
B
bellard 已提交
237
#elif defined(TARGET_SH4)
238
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
239
#elif defined(TARGET_S390X)
B
bellard 已提交
240
    /* XXXXX */
B
bellard 已提交
241 242 243
#else
#error unsupported target CPU
#endif
244
    env->exception_index = -1;
245

B
bellard 已提交
246
    /* prepare setjmp context for exception handling */
247 248
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
249
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
B
blueswir1 已提交
250
#undef env
251
            env = cpu_single_env;
B
blueswir1 已提交
252 253
#define env cpu_single_env
#endif
254 255 256 257 258
            /* 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;
259 260 261
                    if (ret == EXCP_DEBUG) {
                        cpu_handle_debug_exception(env);
                    }
262
                    break;
A
aurel32 已提交
263 264
                } else {
#if defined(CONFIG_USER_ONLY)
265
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
266
                       which will be handled outside the cpu execution
267
                       loop */
B
bellard 已提交
268
#if defined(TARGET_I386)
269 270 271
                    do_interrupt_user(env->exception_index,
                                      env->exception_is_int,
                                      env->error_code,
272
                                      env->exception_next_eip);
273 274
                    /* successfully delivered */
                    env->old_exception = -1;
B
bellard 已提交
275
#endif
276 277
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
278
#else
B
bellard 已提交
279
#if defined(TARGET_I386)
280 281 282
                    /* simulate a real cpu exception. On i386, it can
                       trigger new exceptions, but we do not handle
                       double or triple faults yet. */
283 284 285
                    do_interrupt(env->exception_index,
                                 env->exception_is_int,
                                 env->error_code,
B
bellard 已提交
286
                                 env->exception_next_eip, 0);
287 288
                    /* successfully delivered */
                    env->old_exception = -1;
289 290
#elif defined(TARGET_PPC)
                    do_interrupt(env);
M
Michael Walle 已提交
291 292
#elif defined(TARGET_LM32)
                    do_interrupt(env);
293 294
#elif defined(TARGET_MICROBLAZE)
                    do_interrupt(env);
B
bellard 已提交
295 296
#elif defined(TARGET_MIPS)
                    do_interrupt(env);
297
#elif defined(TARGET_SPARC)
298
                    do_interrupt(env);
B
bellard 已提交
299 300
#elif defined(TARGET_ARM)
                    do_interrupt(env);
301 302
#elif defined(TARGET_UNICORE32)
                    do_interrupt(env);
B
bellard 已提交
303 304
#elif defined(TARGET_SH4)
		    do_interrupt(env);
J
j_mayer 已提交
305 306
#elif defined(TARGET_ALPHA)
                    do_interrupt(env);
307 308
#elif defined(TARGET_CRIS)
                    do_interrupt(env);
P
pbrook 已提交
309 310
#elif defined(TARGET_M68K)
                    do_interrupt(0);
311 312
#elif defined(TARGET_S390X)
                    do_interrupt(env);
A
aurel32 已提交
313
#endif
314
                    env->exception_index = -1;
B
bellard 已提交
315
#endif
316
                }
317
            }
B
bellard 已提交
318

319
            next_tb = 0; /* force lookup of first TB */
320
            for(;;) {
B
bellard 已提交
321
                interrupt_request = env->interrupt_request;
M
malc 已提交
322 323 324
                if (unlikely(interrupt_request)) {
                    if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
                        /* Mask out external interrupts for this step. */
325
                        interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
M
malc 已提交
326
                    }
327 328 329 330 331
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                        env->exception_index = EXCP_DEBUG;
                        cpu_loop_exit();
                    }
332
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
333
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
334
    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
335 336 337 338 339 340 341
                    if (interrupt_request & CPU_INTERRUPT_HALT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                        env->halted = 1;
                        env->exception_index = EXCP_HLT;
                        cpu_loop_exit();
                    }
#endif
B
bellard 已提交
342
#if defined(TARGET_I386)
343 344 345 346 347 348 349 350
                    if (interrupt_request & CPU_INTERRUPT_INIT) {
                            svm_check_intercept(SVM_EXIT_INIT);
                            do_cpu_init(env);
                            env->exception_index = EXCP_HALTED;
                            cpu_loop_exit();
                    } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
                            do_cpu_sipi(env);
                    } else if (env->hflags2 & HF2_GIF_MASK) {
351 352 353 354 355 356 357 358 359 360 361 362
                        if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                            !(env->hflags & HF_SMM_MASK)) {
                            svm_check_intercept(SVM_EXIT_SMI);
                            env->interrupt_request &= ~CPU_INTERRUPT_SMI;
                            do_smm_enter();
                            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;
                            do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
                            next_tb = 0;
363 364 365 366
			} else if (interrupt_request & CPU_INTERRUPT_MCE) {
                            env->interrupt_request &= ~CPU_INTERRUPT_MCE;
                            do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
                            next_tb = 0;
367 368 369 370 371 372 373 374 375 376
                        } 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;
                            svm_check_intercept(SVM_EXIT_INTR);
                            env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
                            intno = cpu_get_pic_interrupt(env);
377
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
378
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
B
blueswir1 已提交
379 380 381 382
#undef env
                    env = cpu_single_env;
#define env cpu_single_env
#endif
383 384 385 386
                            do_interrupt(intno, 0, 0, 0, 1);
                            /* ensure that no TB jump will be modified as
                               the program flow was changed */
                            next_tb = 0;
T
ths 已提交
387
#if !defined(CONFIG_USER_ONLY)
388 389 390 391 392 393 394
                        } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
                                   (env->eflags & IF_MASK) && 
                                   !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                            int intno;
                            /* FIXME: this should respect TPR */
                            svm_check_intercept(SVM_EXIT_VINTR);
                            intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
395
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
396
                            do_interrupt(intno, 0, 0, 0, 1);
397
                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
398
                            next_tb = 0;
B
bellard 已提交
399
#endif
400
                        }
B
bellard 已提交
401
                    }
402
#elif defined(TARGET_PPC)
403 404
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
405
                        cpu_reset(env);
406 407
                    }
#endif
408
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
409 410 411
                        ppc_hw_interrupt(env);
                        if (env->pending_interrupts == 0)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
412
                        next_tb = 0;
413
                    }
M
Michael Walle 已提交
414 415 416 417 418 419 420
#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;
                    }
421 422 423 424 425 426 427 428 429
#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 已提交
430 431
#elif defined(TARGET_MIPS)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
432
                        cpu_mips_hw_interrupts_pending(env)) {
B
bellard 已提交
433 434 435 436
                        /* Raise it */
                        env->exception_index = EXCP_EXT_INTERRUPT;
                        env->error_code = 0;
                        do_interrupt(env);
437
                        next_tb = 0;
B
bellard 已提交
438
                    }
439
#elif defined(TARGET_SPARC)
440 441 442 443 444 445 446 447 448 449 450 451 452 453
                    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;
                            }
                        }
454
		    }
B
bellard 已提交
455 456 457 458 459
#elif defined(TARGET_ARM)
                    if (interrupt_request & CPU_INTERRUPT_FIQ
                        && !(env->uncached_cpsr & CPSR_F)) {
                        env->exception_index = EXCP_FIQ;
                        do_interrupt(env);
460
                        next_tb = 0;
B
bellard 已提交
461
                    }
P
pbrook 已提交
462 463 464 465 466 467
                    /* 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
468
                       the stack if an interrupt occurred at the wrong time.
P
pbrook 已提交
469 470
                       We avoid this by disabling interrupts when
                       pc contains a magic address.  */
B
bellard 已提交
471
                    if (interrupt_request & CPU_INTERRUPT_HARD
P
pbrook 已提交
472 473
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                            || !(env->uncached_cpsr & CPSR_I))) {
B
bellard 已提交
474 475
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
476
                        next_tb = 0;
B
bellard 已提交
477
                    }
478 479 480 481 482 483
#elif defined(TARGET_UNICORE32)
                    if (interrupt_request & CPU_INTERRUPT_HARD
                        && !(env->uncached_asr & ASR_I)) {
                        do_interrupt(env);
                        next_tb = 0;
                    }
B
bellard 已提交
484
#elif defined(TARGET_SH4)
485 486
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
487
                        next_tb = 0;
488
                    }
J
j_mayer 已提交
489
#elif defined(TARGET_ALPHA)
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
                    {
                        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 已提交
520
                    }
521
#elif defined(TARGET_CRIS)
E
edgar_igl 已提交
522
                    if (interrupt_request & CPU_INTERRUPT_HARD
E
Edgar E. Iglesias 已提交
523 524
                        && (env->pregs[PR_CCS] & I_FLAG)
                        && !env->locked_irq) {
E
edgar_igl 已提交
525 526 527 528 529 530 531
                        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;
532
                        do_interrupt(env);
533
                        next_tb = 0;
534
                    }
P
pbrook 已提交
535 536 537 538 539 540 541 542 543 544 545
#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;
                        do_interrupt(1);
546
                        next_tb = 0;
P
pbrook 已提交
547
                    }
548 549 550 551 552 553
#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;
                    }
B
bellard 已提交
554
#endif
555
                   /* Don't use the cached interrupt_request value,
B
bellard 已提交
556
                      do_interrupt may have updated the EXITTB flag. */
B
bellard 已提交
557
                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
558 559 560
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
561
                        next_tb = 0;
562
                    }
563 564 565 566 567
                }
                if (unlikely(env->exit_request)) {
                    env->exit_request = 0;
                    env->exception_index = EXCP_INTERRUPT;
                    cpu_loop_exit();
568
                }
569
#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
570
                if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
571
                    /* restore flags in standard format */
572
#if defined(TARGET_I386)
P
pbrook 已提交
573
                    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
574
                    log_cpu_state(env, X86_DUMP_CCOP);
575
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
P
pbrook 已提交
576 577 578 579 580
#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);
581
                    log_cpu_state(env, 0);
B
bellard 已提交
582
#else
583
                    log_cpu_state(env, 0);
B
bellard 已提交
584
#endif
585
                }
586
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
P
pbrook 已提交
587
                spin_lock(&tb_lock);
588
                tb = tb_find_fast();
P
pbrook 已提交
589 590 591 592 593 594 595
                /* 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 已提交
596
                    tb_invalidated_flag = 0;
P
pbrook 已提交
597
                }
598
#ifdef CONFIG_DEBUG_EXEC
599 600 601
                qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                             (long)tb->tc_ptr, tb->pc,
                             lookup_symbol(tb->pc));
602
#endif
603 604 605
                /* see if we can patch the calling TB. When the TB
                   spans two pages, we cannot safely do a direct
                   jump. */
P
Paolo Bonzini 已提交
606
                if (next_tb != 0 && tb->page_addr[1] == -1) {
607
                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
608
                }
P
pbrook 已提交
609
                spin_unlock(&tb_lock);
610 611 612 613 614

                /* 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 已提交
615 616 617
                env->current_tb = tb;
                barrier();
                if (likely(!env->exit_request)) {
P
pbrook 已提交
618
                    tc_ptr = tb->tc_ptr;
619
                /* execute the generated code */
620
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
621
#undef env
P
pbrook 已提交
622
                    env = cpu_single_env;
623 624
#define env cpu_single_env
#endif
P
pbrook 已提交
625 626
                    next_tb = tcg_qemu_tb_exec(tc_ptr);
                    if ((next_tb & 3) == 2) {
T
ths 已提交
627
                        /* Instruction counter expired.  */
P
pbrook 已提交
628 629 630
                        int insns_left;
                        tb = (TranslationBlock *)(long)(next_tb & ~3);
                        /* Restore PC.  */
631
                        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
                        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.  */
                                cpu_exec_nocache(insns_left, tb);
                            }
                            env->exception_index = EXCP_INTERRUPT;
                            next_tb = 0;
                            cpu_loop_exit();
                        }
                    }
                }
J
Jan Kiszka 已提交
654
                env->current_tb = NULL;
B
bellard 已提交
655 656
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
657
            } /* for(;;) */
B
bellard 已提交
658
        }
659 660
    } /* for(;;) */

B
bellard 已提交
661

B
bellard 已提交
662
#if defined(TARGET_I386)
B
bellard 已提交
663
    /* restore flags in standard format */
P
pbrook 已提交
664
    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
B
bellard 已提交
665
#elif defined(TARGET_ARM)
B
bellard 已提交
666
    /* XXX: Save/restore host fpu exception state?.  */
667
#elif defined(TARGET_UNICORE32)
668
#elif defined(TARGET_SPARC)
669
#elif defined(TARGET_PPC)
M
Michael Walle 已提交
670
#elif defined(TARGET_LM32)
P
pbrook 已提交
671 672 673 674 675
#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);
676
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
677
#elif defined(TARGET_MIPS)
B
bellard 已提交
678
#elif defined(TARGET_SH4)
J
j_mayer 已提交
679
#elif defined(TARGET_ALPHA)
680
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
681
#elif defined(TARGET_S390X)
B
bellard 已提交
682
    /* XXXXX */
B
bellard 已提交
683 684 685
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
686 687

    /* restore global registers */
J
Jan Kiszka 已提交
688
    barrier();
P
Paolo Bonzini 已提交
689
    env = (void *) saved_env_reg;
P
pbrook 已提交
690

B
bellard 已提交
691
    /* fail safe : never use cpu_single_env outside cpu_exec() */
692
    cpu_single_env = NULL;
B
bellard 已提交
693 694
    return ret;
}