cpu-exec.c 29.5 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(cpu->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
    CPUState *cpu = ENV_GET_CPU(env);

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

44
    cpu->exception_index = -1;
45
    siglongjmp(cpu->jmp_env, 1);
46 47
}
#endif
48

49 50 51 52
/* 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;
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    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);
72 73 74 75 76
    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.
         */
77
        CPUClass *cc = CPU_GET_CLASS(cpu);
78
        TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
79 80 81 82 83 84
        if (cc->synchronize_from_tb) {
            cc->synchronize_from_tb(cpu, tb);
        } else {
            assert(cc->set_pc);
            cc->set_pc(cpu, tb->pc);
        }
85
    }
86 87 88 89 90 91
    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;
    }
92 93 94
    return next_tb;
}

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

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

129
    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
130

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

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

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

175
static inline TranslationBlock *tb_find_fast(CPUArchState *env)
176
{
177
    CPUState *cpu = ENV_GET_CPU(env);
178 179
    TranslationBlock *tb;
    target_ulong cs_base, pc;
180
    int flags;
181 182 183 184

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

194 195
static CPUDebugExcpHandler *debug_excp_handler;

196
void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
197 198 199 200
{
    debug_excp_handler = handler;
}

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

217 218
volatile sig_atomic_t exit_request;

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

234
    if (cpu->halted) {
235
        if (!cpu_has_work(cpu)) {
236 237 238
            return EXCP_HALTED;
        }

239
        cpu->halted = 0;
240
    }
B
bellard 已提交
241

242
    current_cpu = cpu;
B
bellard 已提交
243

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

J
Jan Kiszka 已提交
252
    if (unlikely(exit_request)) {
253
        cpu->exit_request = 1;
254 255
    }

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

B
bellard 已提交
287
    /* prepare setjmp context for exception handling */
288
    for(;;) {
289
        if (sigsetjmp(cpu->jmp_env, 0) == 0) {
290
            /* if an exception is pending, we execute it here */
291 292
            if (cpu->exception_index >= 0) {
                if (cpu->exception_index >= EXCP_INTERRUPT) {
293
                    /* exit request from the cpu execution loop */
294
                    ret = cpu->exception_index;
295 296 297
                    if (ret == EXCP_DEBUG) {
                        cpu_handle_debug_exception(env);
                    }
298
                    break;
A
aurel32 已提交
299 300
                } else {
#if defined(CONFIG_USER_ONLY)
301
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
302
                       which will be handled outside the cpu execution
303
                       loop */
B
bellard 已提交
304
#if defined(TARGET_I386)
305
                    cc->do_interrupt(cpu);
B
bellard 已提交
306
#endif
307
                    ret = cpu->exception_index;
308
                    break;
A
aurel32 已提交
309
#else
310
                    cc->do_interrupt(cpu);
311
                    cpu->exception_index = -1;
B
bellard 已提交
312
#endif
313
                }
314
            }
B
bellard 已提交
315

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

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

B
bellard 已提交
701

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

731 732
    /* fail safe : never use current_cpu outside cpu_exec() */
    current_cpu = NULL;
B
bellard 已提交
733 734
    return ret;
}