cpu-exec.c 26.9 KB
Newer Older
B
bellard 已提交
1
/*
2
 *  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"
A
Anthony Liguori 已提交
24
#include "qtest.h"
B
bellard 已提交
25

26 27
int tb_invalidated_flag;

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

30
bool qemu_cpu_has_work(CPUArchState *env)
31 32 33 34
{
    return cpu_has_work(env);
}

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

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

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

P
pbrook 已提交
54 55
/* Execute the code without caching the generated code. An interpreter
   could be used if available. */
56
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
B
Blue Swirl 已提交
57
                             TranslationBlock *orig_tb)
P
pbrook 已提交
58
{
59
    tcg_target_ulong next_tb;
P
pbrook 已提交
60 61 62 63 64 65 66 67 68 69 70
    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 已提交
71
    next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
P
Paolo Bonzini 已提交
72
    env->current_tb = NULL;
P
pbrook 已提交
73 74 75 76

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

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

93
    tb_invalidated_flag = 0;
94

95
    /* find translated block using physical mappings */
P
Paul Brook 已提交
96
    phys_pc = get_page_addr_code(env, pc);
97 98 99 100 101 102 103
    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;
104
        if (tb->pc == pc &&
105
            tb->page_addr[0] == phys_page1 &&
106
            tb->cs_base == cs_base &&
107 108 109
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
110 111
                tb_page_addr_t phys_page2;

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

127
 found:
128 129 130 131 132 133
    /* 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;
    }
134 135 136 137 138
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    return tb;
}

139
static inline TranslationBlock *tb_find_fast(CPUArchState *env)
140 141 142
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
143
    int flags;
144 145 146 147

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

157 158 159 160 161 162 163 164 165 166
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;
}

167
static void cpu_handle_debug_exception(CPUArchState *env)
168 169 170 171 172 173 174 175 176 177 178 179 180
{
    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 已提交
181 182
/* main execution loop */

183 184
volatile sig_atomic_t exit_request;

185
int cpu_exec(CPUArchState *env)
B
bellard 已提交
186
{
187 188 189
#ifdef TARGET_PPC
    CPUState *cpu = ENV_GET_CPU(env);
#endif
190 191
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
192
    uint8_t *tc_ptr;
193
    tcg_target_ulong next_tb;
194

B
Blue Swirl 已提交
195 196
    if (env->halted) {
        if (!cpu_has_work(env)) {
197 198 199
            return EXCP_HALTED;
        }

B
Blue Swirl 已提交
200
        env->halted = 0;
201
    }
B
bellard 已提交
202

B
Blue Swirl 已提交
203
    cpu_single_env = env;
B
bellard 已提交
204

J
Jan Kiszka 已提交
205
    if (unlikely(exit_request)) {
206 207 208
        env->exit_request = 1;
    }

209
#if defined(TARGET_I386)
210 211 212 213 214
    /* 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);
215
#elif defined(TARGET_SPARC)
P
pbrook 已提交
216 217 218 219
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
220 221
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
222
#elif defined(TARGET_UNICORE32)
223
#elif defined(TARGET_PPC)
224
    env->reserve_addr = -1;
M
Michael Walle 已提交
225
#elif defined(TARGET_LM32)
226
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
227
#elif defined(TARGET_MIPS)
228
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
229
#elif defined(TARGET_SH4)
230
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
231
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
232
#elif defined(TARGET_XTENSA)
B
bellard 已提交
233
    /* XXXXX */
B
bellard 已提交
234 235 236
#else
#error unsupported target CPU
#endif
237
    env->exception_index = -1;
238

B
bellard 已提交
239
    /* prepare setjmp context for exception handling */
240 241 242 243 244 245 246
    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;
247 248 249
                    if (ret == EXCP_DEBUG) {
                        cpu_handle_debug_exception(env);
                    }
250
                    break;
A
aurel32 已提交
251 252
                } else {
#if defined(CONFIG_USER_ONLY)
253
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
254
                       which will be handled outside the cpu execution
255
                       loop */
B
bellard 已提交
256
#if defined(TARGET_I386)
257
                    do_interrupt(env);
B
bellard 已提交
258
#endif
259 260
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
261
#else
B
bellard 已提交
262
                    do_interrupt(env);
263
                    env->exception_index = -1;
B
bellard 已提交
264
#endif
265
                }
266
            }
B
bellard 已提交
267

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

                /* 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 已提交
598 599 600
                env->current_tb = tb;
                barrier();
                if (likely(!env->exit_request)) {
P
pbrook 已提交
601
                    tc_ptr = tb->tc_ptr;
602
                    /* execute the generated code */
B
Blue Swirl 已提交
603
                    next_tb = tcg_qemu_tb_exec(env, tc_ptr);
P
pbrook 已提交
604
                    if ((next_tb & 3) == 2) {
T
ths 已提交
605
                        /* Instruction counter expired.  */
P
pbrook 已提交
606
                        int insns_left;
607
                        tb = (TranslationBlock *)(next_tb & ~3);
P
pbrook 已提交
608
                        /* Restore PC.  */
609
                        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
610 611 612 613 614 615 616 617 618 619 620 621 622 623
                        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 已提交
624
                                cpu_exec_nocache(env, insns_left, tb);
P
pbrook 已提交
625 626 627
                            }
                            env->exception_index = EXCP_INTERRUPT;
                            next_tb = 0;
B
Blue Swirl 已提交
628
                            cpu_loop_exit(env);
P
pbrook 已提交
629 630 631
                        }
                    }
                }
J
Jan Kiszka 已提交
632
                env->current_tb = NULL;
B
bellard 已提交
633 634
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
635
            } /* for(;;) */
636 637 638 639
        } else {
            /* Reload env after longjmp - the compiler may have smashed all
             * local variables as longjmp is marked 'noreturn'. */
            env = cpu_single_env;
B
bellard 已提交
640
        }
641 642
    } /* for(;;) */

B
bellard 已提交
643

B
bellard 已提交
644
#if defined(TARGET_I386)
B
bellard 已提交
645
    /* restore flags in standard format */
646 647
    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
        | (DF & DF_MASK);
B
bellard 已提交
648
#elif defined(TARGET_ARM)
B
bellard 已提交
649
    /* XXX: Save/restore host fpu exception state?.  */
650
#elif defined(TARGET_UNICORE32)
651
#elif defined(TARGET_SPARC)
652
#elif defined(TARGET_PPC)
M
Michael Walle 已提交
653
#elif defined(TARGET_LM32)
P
pbrook 已提交
654 655 656 657 658
#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);
659
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
660
#elif defined(TARGET_MIPS)
661
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
662
#elif defined(TARGET_SH4)
J
j_mayer 已提交
663
#elif defined(TARGET_ALPHA)
664
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
665
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
666
#elif defined(TARGET_XTENSA)
B
bellard 已提交
667
    /* XXXXX */
B
bellard 已提交
668 669 670
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
671

B
bellard 已提交
672
    /* fail safe : never use cpu_single_env outside cpu_exec() */
673
    cpu_single_env = NULL;
B
bellard 已提交
674 675
    return ret;
}