cpu-exec.c 29.3 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
bool qemu_cpu_has_work(CPUState *cpu)
27
{
28
    return cpu_has_work(cpu);
29 30
}

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

    cpu->current_tb = NULL;
36
    siglongjmp(env->jmp_env, 1);
B
bellard 已提交
37
}
38

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

    env->exception_index = -1;
48
    siglongjmp(env->jmp_env, 1);
49 50
}
#endif
51

52 53 54 55
/* Execute a TB, and fix up the CPU state afterwards if necessary */
static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
{
    CPUArchState *env = cpu->env_ptr;
56
    uintptr_t next_tb = tcg_qemu_tb_exec(env, tb_ptr);
57 58 59 60 61
    if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
        /* We didn't start executing this TB (eg because the instruction
         * counter hit zero); we must restore the guest PC to the address
         * of the start of the TB.
         */
62
        CPUClass *cc = CPU_GET_CLASS(cpu);
63
        TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
64 65 66 67 68 69
        if (cc->synchronize_from_tb) {
            cc->synchronize_from_tb(cpu, tb);
        } else {
            assert(cc->set_pc);
            cc->set_pc(cpu, tb->pc);
        }
70
    }
71 72 73 74 75 76
    if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) {
        /* We were asked to stop executing TBs (probably a pending
         * interrupt. We've now stopped, so clear the flag.
         */
        cpu->tcg_exit_req = 0;
    }
77 78 79
    return next_tb;
}

P
pbrook 已提交
80 81
/* Execute the code without caching the generated code. An interpreter
   could be used if available. */
82
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
B
Blue Swirl 已提交
83
                             TranslationBlock *orig_tb)
P
pbrook 已提交
84
{
85
    CPUState *cpu = ENV_GET_CPU(env);
P
pbrook 已提交
86 87 88 89 90 91 92 93 94
    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);
95
    cpu->current_tb = tb;
P
pbrook 已提交
96
    /* execute the generated code */
97
    cpu_tb_exec(cpu, tb->tc_ptr);
98
    cpu->current_tb = NULL;
P
pbrook 已提交
99 100 101 102
    tb_phys_invalidate(tb, -1);
    tb_free(tb);
}

103
static TranslationBlock *tb_find_slow(CPUArchState *env,
B
Blue Swirl 已提交
104
                                      target_ulong pc,
105
                                      target_ulong cs_base,
106
                                      uint64_t flags)
107 108 109
{
    TranslationBlock *tb, **ptb1;
    unsigned int h;
110
    tb_page_addr_t phys_pc, phys_page1;
P
Paul Brook 已提交
111
    target_ulong virt_page2;
112

113
    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
114

115
    /* find translated block using physical mappings */
P
Paul Brook 已提交
116
    phys_pc = get_page_addr_code(env, pc);
117 118
    phys_page1 = phys_pc & TARGET_PAGE_MASK;
    h = tb_phys_hash_func(phys_pc);
119
    ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h];
120 121 122 123
    for(;;) {
        tb = *ptb1;
        if (!tb)
            goto not_found;
124
        if (tb->pc == pc &&
125
            tb->page_addr[0] == phys_page1 &&
126
            tb->cs_base == cs_base &&
127 128 129
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
130 131
                tb_page_addr_t phys_page2;

132
                virt_page2 = (pc & TARGET_PAGE_MASK) +
133
                    TARGET_PAGE_SIZE;
P
Paul Brook 已提交
134
                phys_page2 = get_page_addr_code(env, virt_page2);
135 136 137 138 139 140 141 142 143
                if (tb->page_addr[1] == phys_page2)
                    goto found;
            } else {
                goto found;
            }
        }
        ptb1 = &tb->phys_hash_next;
    }
 not_found:
P
pbrook 已提交
144 145
   /* if no translated code available, then translate it now */
    tb = tb_gen_code(env, pc, cs_base, flags, 0);
146

147
 found:
148 149 150
    /* Move the last found TB to the head of the list */
    if (likely(*ptb1)) {
        *ptb1 = tb->phys_hash_next;
151 152
        tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h];
        tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
153
    }
154 155 156 157 158
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    return tb;
}

159
static inline TranslationBlock *tb_find_fast(CPUArchState *env)
160 161 162
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
163
    int flags;
164 165 166 167

    /* we record a subset of the CPU state. It will
       always be the same before a given translated block
       is executed. */
168
    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
B
bellard 已提交
169
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
170 171
    if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                 tb->flags != flags)) {
B
Blue Swirl 已提交
172
        tb = tb_find_slow(env, pc, cs_base, flags);
173 174 175 176
    }
    return tb;
}

177 178
static CPUDebugExcpHandler *debug_excp_handler;

179
void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
180 181 182 183
{
    debug_excp_handler = handler;
}

184
static void cpu_handle_debug_exception(CPUArchState *env)
185 186 187 188 189 190 191 192 193 194 195 196 197
{
    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 已提交
198 199
/* main execution loop */

200 201
volatile sig_atomic_t exit_request;

202
int cpu_exec(CPUArchState *env)
B
bellard 已提交
203
{
204
    CPUState *cpu = ENV_GET_CPU(env);
205 206 207 208
#if !(defined(CONFIG_USER_ONLY) && \
      (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
    CPUClass *cc = CPU_GET_CLASS(cpu);
#endif
209 210
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
211
    uint8_t *tc_ptr;
212
    uintptr_t next_tb;
213

214
    if (cpu->halted) {
215
        if (!cpu_has_work(cpu)) {
216 217 218
            return EXCP_HALTED;
        }

219
        cpu->halted = 0;
220
    }
B
bellard 已提交
221

222
    current_cpu = cpu;
B
bellard 已提交
223

224
    /* As long as current_cpu is null, up to the assignment just above,
225 226
     * requests by other threads to exit the execution loop are expected to
     * be issued using the exit_request global. We must make sure that our
227
     * evaluation of the global value is performed past the current_cpu
228 229 230 231
     * value transition point, which requires a memory barrier as well as
     * an instruction scheduling constraint on modern architectures.  */
    smp_mb();

J
Jan Kiszka 已提交
232
    if (unlikely(exit_request)) {
233
        cpu->exit_request = 1;
234 235
    }

236
#if defined(TARGET_I386)
237 238
    /* put eflags in CPU temporary format */
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
L
liguang 已提交
239
    env->df = 1 - (2 * ((env->eflags >> 10) & 1));
240 241
    CC_OP = CC_OP_EFLAGS;
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
242
#elif defined(TARGET_SPARC)
P
pbrook 已提交
243 244 245 246
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
247 248
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
249
#elif defined(TARGET_UNICORE32)
250
#elif defined(TARGET_PPC)
251
    env->reserve_addr = -1;
M
Michael Walle 已提交
252
#elif defined(TARGET_LM32)
253
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
254
#elif defined(TARGET_MIPS)
A
Anthony Green 已提交
255
#elif defined(TARGET_MOXIE)
256
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
257
#elif defined(TARGET_SH4)
258
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
259
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
260
#elif defined(TARGET_XTENSA)
B
bellard 已提交
261
    /* XXXXX */
B
bellard 已提交
262 263 264
#else
#error unsupported target CPU
#endif
265
    env->exception_index = -1;
266

B
bellard 已提交
267
    /* prepare setjmp context for exception handling */
268
    for(;;) {
269
        if (sigsetjmp(env->jmp_env, 0) == 0) {
270 271 272 273 274
            /* 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;
275 276 277
                    if (ret == EXCP_DEBUG) {
                        cpu_handle_debug_exception(env);
                    }
278
                    break;
A
aurel32 已提交
279 280
                } else {
#if defined(CONFIG_USER_ONLY)
281
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
282
                       which will be handled outside the cpu execution
283
                       loop */
B
bellard 已提交
284
#if defined(TARGET_I386)
285
                    cc->do_interrupt(cpu);
B
bellard 已提交
286
#endif
287 288
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
289
#else
290
                    cc->do_interrupt(cpu);
291
                    env->exception_index = -1;
B
bellard 已提交
292
#endif
293
                }
294
            }
B
bellard 已提交
295

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

                /* 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. */
626
                cpu->current_tb = tb;
J
Jan Kiszka 已提交
627
                barrier();
628
                if (likely(!cpu->exit_request)) {
P
pbrook 已提交
629
                    tc_ptr = tb->tc_ptr;
630
                    /* execute the generated code */
631
                    next_tb = cpu_tb_exec(cpu, tc_ptr);
632 633 634 635 636 637 638 639 640 641 642 643 644 645
                    switch (next_tb & TB_EXIT_MASK) {
                    case TB_EXIT_REQUESTED:
                        /* Something asked us to stop executing
                         * chained TBs; just continue round the main
                         * loop. Whatever requested the exit will also
                         * have set something else (eg exit_request or
                         * interrupt_request) which we will handle
                         * next time around the loop.
                         */
                        tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
                        next_tb = 0;
                        break;
                    case TB_EXIT_ICOUNT_EXPIRED:
                    {
T
ths 已提交
646
                        /* Instruction counter expired.  */
P
pbrook 已提交
647
                        int insns_left;
648
                        tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
P
pbrook 已提交
649 650 651 652 653 654 655 656 657 658 659 660 661 662
                        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 已提交
663
                                cpu_exec_nocache(env, insns_left, tb);
P
pbrook 已提交
664 665 666
                            }
                            env->exception_index = EXCP_INTERRUPT;
                            next_tb = 0;
B
Blue Swirl 已提交
667
                            cpu_loop_exit(env);
P
pbrook 已提交
668
                        }
669 670 671 672
                        break;
                    }
                    default:
                        break;
P
pbrook 已提交
673 674
                    }
                }
675
                cpu->current_tb = NULL;
B
bellard 已提交
676 677
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
678
            } /* for(;;) */
679 680 681
        } else {
            /* Reload env after longjmp - the compiler may have smashed all
             * local variables as longjmp is marked 'noreturn'. */
682 683
            cpu = current_cpu;
            env = cpu->env_ptr;
684 685 686 687
#if !(defined(CONFIG_USER_ONLY) && \
      (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
            cc = CPU_GET_CLASS(cpu);
#endif
B
bellard 已提交
688
        }
689 690
    } /* for(;;) */

B
bellard 已提交
691

B
bellard 已提交
692
#if defined(TARGET_I386)
B
bellard 已提交
693
    /* restore flags in standard format */
694
    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
L
liguang 已提交
695
        | (env->df & DF_MASK);
B
bellard 已提交
696
#elif defined(TARGET_ARM)
B
bellard 已提交
697
    /* XXX: Save/restore host fpu exception state?.  */
698
#elif defined(TARGET_UNICORE32)
699
#elif defined(TARGET_SPARC)
700
#elif defined(TARGET_PPC)
M
Michael Walle 已提交
701
#elif defined(TARGET_LM32)
P
pbrook 已提交
702 703 704 705 706
#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);
707
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
708
#elif defined(TARGET_MIPS)
A
Anthony Green 已提交
709
#elif defined(TARGET_MOXIE)
710
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
711
#elif defined(TARGET_SH4)
J
j_mayer 已提交
712
#elif defined(TARGET_ALPHA)
713
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
714
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
715
#elif defined(TARGET_XTENSA)
B
bellard 已提交
716
    /* XXXXX */
B
bellard 已提交
717 718 719
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
720

721 722
    /* fail safe : never use current_cpu outside cpu_exec() */
    current_cpu = NULL;
B
bellard 已提交
723 724
    return ret;
}