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

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

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

131
    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
132

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

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

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

177
static inline TranslationBlock *tb_find_fast(CPUArchState *env)
178 179 180
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
181
    int flags;
182 183 184 185

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

195 196
static CPUDebugExcpHandler *debug_excp_handler;

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

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

218 219
volatile sig_atomic_t exit_request;

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

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

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

243
    current_cpu = cpu;
B
bellard 已提交
244

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

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

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

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

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

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

B
bellard 已提交
702

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

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