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
    CPUState *cpu = ENV_GET_CPU(env);
122 123
    TranslationBlock *tb, **ptb1;
    unsigned int h;
124
    tb_page_addr_t phys_pc, phys_page1;
P
Paul Brook 已提交
125
    target_ulong virt_page2;
126

127
    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
128

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

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

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

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

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

192 193
static CPUDebugExcpHandler *debug_excp_handler;

194
void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
195 196 197 198
{
    debug_excp_handler = handler;
}

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

215 216
volatile sig_atomic_t exit_request;

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

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

237
        cpu->halted = 0;
238
    }
B
bellard 已提交
239

240
    current_cpu = cpu;
B
bellard 已提交
241

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

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

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

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

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

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

B
bellard 已提交
699

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

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