cpu-exec.c 27.2 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"
21
#include "disas/disas.h"
22
#include "tcg.h"
23
#include "qemu/atomic.h"
24
#include "sysemu/qtest.h"
B
bellard 已提交
25

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

28
bool qemu_cpu_has_work(CPUState *cpu)
29
{
30
    return cpu_has_work(cpu);
31 32
}

33
void cpu_loop_exit(CPUArchState *env)
B
bellard 已提交
34
{
35 36 37
    CPUState *cpu = ENV_GET_CPU(env);

    cpu->current_tb = NULL;
38
    siglongjmp(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
{
    /* XXX: restore cpu registers saved in host registers */

    env->exception_index = -1;
50
    siglongjmp(env->jmp_env, 1);
51 52
}
#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
    CPUState *cpu = ENV_GET_CPU(env);
60
    tcg_target_ulong next_tb;
P
pbrook 已提交
61 62 63 64 65 66 67 68 69
    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);
70
    cpu->current_tb = tb;
P
pbrook 已提交
71
    /* execute the generated code */
B
Blue Swirl 已提交
72
    next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr);
73
    cpu->current_tb = NULL;
P
pbrook 已提交
74

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

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

94
    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
95

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

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

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

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

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

158 159
static CPUDebugExcpHandler *debug_excp_handler;

160
void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
161 162 163 164
{
    debug_excp_handler = handler;
}

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

181 182
volatile sig_atomic_t exit_request;

183
int cpu_exec(CPUArchState *env)
B
bellard 已提交
184
{
185
    CPUState *cpu = ENV_GET_CPU(env);
186 187
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
188
    uint8_t *tc_ptr;
189
    tcg_target_ulong next_tb;
190

B
Blue Swirl 已提交
191
    if (env->halted) {
192
        if (!cpu_has_work(cpu)) {
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
        cpu->exit_request = 1;
203 204
    }

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)
224
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
225
#elif defined(TARGET_SH4)
226
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
227
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
228
#elif defined(TARGET_XTENSA)
B
bellard 已提交
229
    /* XXXXX */
B
bellard 已提交
230 231 232
#else
#error unsupported target CPU
#endif
233
    env->exception_index = -1;
234

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

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

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

B
bellard 已提交
641

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

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