cpu-exec.c 29.4 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
void cpu_loop_exit(CPUArchState *env)
B
bellard 已提交
27
{
28 29 30
    CPUState *cpu = ENV_GET_CPU(env);

    cpu->current_tb = NULL;
31
    siglongjmp(env->jmp_env, 1);
B
bellard 已提交
32
}
33

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

    env->exception_index = -1;
43
    siglongjmp(env->jmp_env, 1);
44 45
}
#endif
46

47 48 49 50
/* 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;
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    uintptr_t next_tb;

#if defined(DEBUG_DISAS)
    if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
#if defined(TARGET_I386)
        log_cpu_state(cpu, CPU_DUMP_CCOP);
#elif defined(TARGET_M68K)
        /* ??? Should not modify env state for dumping.  */
        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);
        log_cpu_state(cpu, 0);
#else
        log_cpu_state(cpu, 0);
#endif
    }
#endif /* DEBUG_DISAS */

    next_tb = tcg_qemu_tb_exec(env, tb_ptr);
70 71 72 73 74
    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.
         */
75
        CPUClass *cc = CPU_GET_CLASS(cpu);
76
        TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
77 78 79 80 81 82
        if (cc->synchronize_from_tb) {
            cc->synchronize_from_tb(cpu, tb);
        } else {
            assert(cc->set_pc);
            cc->set_pc(cpu, tb->pc);
        }
83
    }
84 85 86 87 88 89
    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;
    }
90 91 92
    return next_tb;
}

P
pbrook 已提交
93 94
/* Execute the code without caching the generated code. An interpreter
   could be used if available. */
95
static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
B
Blue Swirl 已提交
96
                             TranslationBlock *orig_tb)
P
pbrook 已提交
97
{
98
    CPUState *cpu = ENV_GET_CPU(env);
P
pbrook 已提交
99 100 101 102 103 104 105 106 107
    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);
108
    cpu->current_tb = tb;
P
pbrook 已提交
109
    /* execute the generated code */
110
    cpu_tb_exec(cpu, tb->tc_ptr);
111
    cpu->current_tb = NULL;
P
pbrook 已提交
112 113 114 115
    tb_phys_invalidate(tb, -1);
    tb_free(tb);
}

116
static TranslationBlock *tb_find_slow(CPUArchState *env,
B
Blue Swirl 已提交
117
                                      target_ulong pc,
118
                                      target_ulong cs_base,
119
                                      uint64_t flags)
120 121 122
{
    TranslationBlock *tb, **ptb1;
    unsigned int h;
123
    tb_page_addr_t phys_pc, phys_page1;
P
Paul Brook 已提交
124
    target_ulong virt_page2;
125

126
    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
127

128
    /* find translated block using physical mappings */
P
Paul Brook 已提交
129
    phys_pc = get_page_addr_code(env, pc);
130 131
    phys_page1 = phys_pc & TARGET_PAGE_MASK;
    h = tb_phys_hash_func(phys_pc);
132
    ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h];
133 134 135 136
    for(;;) {
        tb = *ptb1;
        if (!tb)
            goto not_found;
137
        if (tb->pc == pc &&
138
            tb->page_addr[0] == phys_page1 &&
139
            tb->cs_base == cs_base &&
140 141 142
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
143 144
                tb_page_addr_t phys_page2;

145
                virt_page2 = (pc & TARGET_PAGE_MASK) +
146
                    TARGET_PAGE_SIZE;
P
Paul Brook 已提交
147
                phys_page2 = get_page_addr_code(env, virt_page2);
148 149 150 151 152 153 154 155 156
                if (tb->page_addr[1] == phys_page2)
                    goto found;
            } else {
                goto found;
            }
        }
        ptb1 = &tb->phys_hash_next;
    }
 not_found:
P
pbrook 已提交
157 158
   /* if no translated code available, then translate it now */
    tb = tb_gen_code(env, pc, cs_base, flags, 0);
159

160
 found:
161 162 163
    /* Move the last found TB to the head of the list */
    if (likely(*ptb1)) {
        *ptb1 = tb->phys_hash_next;
164 165
        tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h];
        tcg_ctx.tb_ctx.tb_phys_hash[h] = tb;
166
    }
167 168 169 170 171
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    return tb;
}

172
static inline TranslationBlock *tb_find_fast(CPUArchState *env)
173 174 175
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
176
    int flags;
177 178 179 180

    /* we record a subset of the CPU state. It will
       always be the same before a given translated block
       is executed. */
181
    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
B
bellard 已提交
182
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
183 184
    if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                 tb->flags != flags)) {
B
Blue Swirl 已提交
185
        tb = tb_find_slow(env, pc, cs_base, flags);
186 187 188 189
    }
    return tb;
}

190 191
static CPUDebugExcpHandler *debug_excp_handler;

192
void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
193 194 195 196
{
    debug_excp_handler = handler;
}

197
static void cpu_handle_debug_exception(CPUArchState *env)
198 199 200 201 202 203 204 205 206 207 208 209 210
{
    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 已提交
211 212
/* main execution loop */

213 214
volatile sig_atomic_t exit_request;

215
int cpu_exec(CPUArchState *env)
B
bellard 已提交
216
{
217
    CPUState *cpu = ENV_GET_CPU(env);
218 219 220
#if !(defined(CONFIG_USER_ONLY) && \
      (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
    CPUClass *cc = CPU_GET_CLASS(cpu);
221 222 223
#endif
#ifdef TARGET_I386
    X86CPU *x86_cpu = X86_CPU(cpu);
224
#endif
225 226
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
227
    uint8_t *tc_ptr;
228
    uintptr_t next_tb;
229

230
    if (cpu->halted) {
231
        if (!cpu_has_work(cpu)) {
232 233 234
            return EXCP_HALTED;
        }

235
        cpu->halted = 0;
236
    }
B
bellard 已提交
237

238
    current_cpu = cpu;
B
bellard 已提交
239

240
    /* As long as current_cpu is null, up to the assignment just above,
241 242
     * 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
243
     * evaluation of the global value is performed past the current_cpu
244 245 246 247
     * value transition point, which requires a memory barrier as well as
     * an instruction scheduling constraint on modern architectures.  */
    smp_mb();

J
Jan Kiszka 已提交
248
    if (unlikely(exit_request)) {
249
        cpu->exit_request = 1;
250 251
    }

252
#if defined(TARGET_I386)
253 254
    /* put eflags in CPU temporary format */
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
L
liguang 已提交
255
    env->df = 1 - (2 * ((env->eflags >> 10) & 1));
256 257
    CC_OP = CC_OP_EFLAGS;
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
258
#elif defined(TARGET_SPARC)
P
pbrook 已提交
259 260 261 262
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
263 264
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
265
#elif defined(TARGET_UNICORE32)
266
#elif defined(TARGET_PPC)
267
    env->reserve_addr = -1;
M
Michael Walle 已提交
268
#elif defined(TARGET_LM32)
269
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
270
#elif defined(TARGET_MIPS)
A
Anthony Green 已提交
271
#elif defined(TARGET_MOXIE)
272
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
273
#elif defined(TARGET_SH4)
274
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
275
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
276
#elif defined(TARGET_XTENSA)
B
bellard 已提交
277
    /* XXXXX */
B
bellard 已提交
278 279 280
#else
#error unsupported target CPU
#endif
281
    env->exception_index = -1;
282

B
bellard 已提交
283
    /* prepare setjmp context for exception handling */
284
    for(;;) {
285
        if (sigsetjmp(env->jmp_env, 0) == 0) {
286 287 288 289 290
            /* 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;
291 292 293
                    if (ret == EXCP_DEBUG) {
                        cpu_handle_debug_exception(env);
                    }
294
                    break;
A
aurel32 已提交
295 296
                } else {
#if defined(CONFIG_USER_ONLY)
297
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
298
                       which will be handled outside the cpu execution
299
                       loop */
B
bellard 已提交
300
#if defined(TARGET_I386)
301
                    cc->do_interrupt(cpu);
B
bellard 已提交
302
#endif
303 304
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
305
#else
306
                    cc->do_interrupt(cpu);
307
                    env->exception_index = -1;
B
bellard 已提交
308
#endif
309
                }
310
            }
B
bellard 已提交
311

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

                /* 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. */
629
                cpu->current_tb = tb;
J
Jan Kiszka 已提交
630
                barrier();
631
                if (likely(!cpu->exit_request)) {
P
pbrook 已提交
632
                    tc_ptr = tb->tc_ptr;
633
                    /* execute the generated code */
634
                    next_tb = cpu_tb_exec(cpu, tc_ptr);
635 636 637 638 639 640 641 642 643 644 645 646 647 648
                    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 已提交
649
                        /* Instruction counter expired.  */
P
pbrook 已提交
650
                        int insns_left;
651
                        tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
P
pbrook 已提交
652
                        insns_left = env->icount_decr.u32;
653
                        if (cpu->icount_extra && insns_left >= 0) {
P
pbrook 已提交
654
                            /* Refill decrementer and continue execution.  */
655 656
                            cpu->icount_extra += insns_left;
                            if (cpu->icount_extra > 0xffff) {
P
pbrook 已提交
657 658
                                insns_left = 0xffff;
                            } else {
659
                                insns_left = cpu->icount_extra;
P
pbrook 已提交
660
                            }
661
                            cpu->icount_extra -= insns_left;
P
pbrook 已提交
662 663 664 665
                            env->icount_decr.u16.low = insns_left;
                        } else {
                            if (insns_left > 0) {
                                /* Execute remaining instructions.  */
B
Blue Swirl 已提交
666
                                cpu_exec_nocache(env, insns_left, tb);
P
pbrook 已提交
667 668 669
                            }
                            env->exception_index = EXCP_INTERRUPT;
                            next_tb = 0;
B
Blue Swirl 已提交
670
                            cpu_loop_exit(env);
P
pbrook 已提交
671
                        }
672 673 674 675
                        break;
                    }
                    default:
                        break;
P
pbrook 已提交
676 677
                    }
                }
678
                cpu->current_tb = NULL;
B
bellard 已提交
679 680
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
681
            } /* for(;;) */
682 683 684
        } else {
            /* Reload env after longjmp - the compiler may have smashed all
             * local variables as longjmp is marked 'noreturn'. */
685 686
            cpu = current_cpu;
            env = cpu->env_ptr;
687 688 689
#if !(defined(CONFIG_USER_ONLY) && \
      (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X)))
            cc = CPU_GET_CLASS(cpu);
690 691 692
#endif
#ifdef TARGET_I386
            x86_cpu = X86_CPU(cpu);
693
#endif
B
bellard 已提交
694
        }
695 696
    } /* for(;;) */

B
bellard 已提交
697

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

727 728
    /* fail safe : never use current_cpu outside cpu_exec() */
    current_cpu = NULL;
B
bellard 已提交
729 730
    return ret;
}