cpu-exec.c 28.7 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
//#define CONFIG_DEBUG_EXEC
B
bellard 已提交
27

28
bool qemu_cpu_has_work(CPUState *cpu)
29
{
30
    return cpu_has_work(cpu);
31 32
}

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

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

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

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

54 55 56 57 58 59 60 61 62 63 64 65 66
/* 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;
    tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr);
    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.
         */
        TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
        cpu_pc_from_tb(env, tb);
    }
67 68 69 70 71 72
    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;
    }
73 74 75
    return next_tb;
}

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

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

109
    tcg_ctx.tb_ctx.tb_invalidated_flag = 0;
110

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

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

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

155
static inline TranslationBlock *tb_find_fast(CPUArchState *env)
156 157 158
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
159
    int flags;
160 161 162 163

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

173 174
static CPUDebugExcpHandler *debug_excp_handler;

175
void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
176 177 178 179
{
    debug_excp_handler = handler;
}

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

196 197
volatile sig_atomic_t exit_request;

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

210
    if (cpu->halted) {
211
        if (!cpu_has_work(cpu)) {
212 213 214
            return EXCP_HALTED;
        }

215
        cpu->halted = 0;
216
    }
B
bellard 已提交
217

B
Blue Swirl 已提交
218
    cpu_single_env = env;
B
bellard 已提交
219

J
Jan Kiszka 已提交
220
    if (unlikely(exit_request)) {
221
        cpu->exit_request = 1;
222 223
    }

224
#if defined(TARGET_I386)
225 226 227 228 229
    /* put eflags in CPU temporary format */
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
    CC_OP = CC_OP_EFLAGS;
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
230
#elif defined(TARGET_SPARC)
P
pbrook 已提交
231 232 233 234
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
235 236
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
237
#elif defined(TARGET_UNICORE32)
238
#elif defined(TARGET_PPC)
239
    env->reserve_addr = -1;
M
Michael Walle 已提交
240
#elif defined(TARGET_LM32)
241
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
242
#elif defined(TARGET_MIPS)
243
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
244
#elif defined(TARGET_SH4)
245
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
246
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
247
#elif defined(TARGET_XTENSA)
B
bellard 已提交
248
    /* XXXXX */
B
bellard 已提交
249 250 251
#else
#error unsupported target CPU
#endif
252
    env->exception_index = -1;
253

B
bellard 已提交
254
    /* prepare setjmp context for exception handling */
255
    for(;;) {
256
        if (sigsetjmp(env->jmp_env, 0) == 0) {
257 258 259 260 261
            /* 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;
262 263 264
                    if (ret == EXCP_DEBUG) {
                        cpu_handle_debug_exception(env);
                    }
265
                    break;
A
aurel32 已提交
266 267
                } else {
#if defined(CONFIG_USER_ONLY)
268
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
269
                       which will be handled outside the cpu execution
270
                       loop */
B
bellard 已提交
271
#if defined(TARGET_I386)
272
                    cc->do_interrupt(cpu);
B
bellard 已提交
273
#endif
274 275
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
276
#else
277
                    cc->do_interrupt(cpu);
278
                    env->exception_index = -1;
B
bellard 已提交
279
#endif
280
                }
281
            }
B
bellard 已提交
282

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

                /* 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. */
617
                cpu->current_tb = tb;
J
Jan Kiszka 已提交
618
                barrier();
619
                if (likely(!cpu->exit_request)) {
P
pbrook 已提交
620
                    tc_ptr = tb->tc_ptr;
621
                    /* execute the generated code */
622
                    next_tb = cpu_tb_exec(cpu, tc_ptr);
623 624 625 626 627 628 629 630 631 632 633 634 635 636
                    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 已提交
637
                        /* Instruction counter expired.  */
P
pbrook 已提交
638
                        int insns_left;
639
                        tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
P
pbrook 已提交
640 641 642 643 644 645 646 647 648 649 650 651 652 653
                        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 已提交
654
                                cpu_exec_nocache(env, insns_left, tb);
P
pbrook 已提交
655 656 657
                            }
                            env->exception_index = EXCP_INTERRUPT;
                            next_tb = 0;
B
Blue Swirl 已提交
658
                            cpu_loop_exit(env);
P
pbrook 已提交
659
                        }
660 661 662 663
                        break;
                    }
                    default:
                        break;
P
pbrook 已提交
664 665
                    }
                }
666
                cpu->current_tb = NULL;
B
bellard 已提交
667 668
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
669
            } /* for(;;) */
670 671 672 673
        } else {
            /* Reload env after longjmp - the compiler may have smashed all
             * local variables as longjmp is marked 'noreturn'. */
            env = cpu_single_env;
B
bellard 已提交
674
        }
675 676
    } /* for(;;) */

B
bellard 已提交
677

B
bellard 已提交
678
#if defined(TARGET_I386)
B
bellard 已提交
679
    /* restore flags in standard format */
680 681
    env->eflags = env->eflags | cpu_cc_compute_all(env, CC_OP)
        | (DF & DF_MASK);
B
bellard 已提交
682
#elif defined(TARGET_ARM)
B
bellard 已提交
683
    /* XXX: Save/restore host fpu exception state?.  */
684
#elif defined(TARGET_UNICORE32)
685
#elif defined(TARGET_SPARC)
686
#elif defined(TARGET_PPC)
M
Michael Walle 已提交
687
#elif defined(TARGET_LM32)
P
pbrook 已提交
688 689 690 691 692
#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);
693
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
694
#elif defined(TARGET_MIPS)
695
#elif defined(TARGET_OPENRISC)
B
bellard 已提交
696
#elif defined(TARGET_SH4)
J
j_mayer 已提交
697
#elif defined(TARGET_ALPHA)
698
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
699
#elif defined(TARGET_S390X)
M
Max Filippov 已提交
700
#elif defined(TARGET_XTENSA)
B
bellard 已提交
701
    /* XXXXX */
B
bellard 已提交
702 703 704
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
705

B
bellard 已提交
706
    /* fail safe : never use cpu_single_env outside cpu_exec() */
707
    cpu_single_env = NULL;
B
bellard 已提交
708 709
    return ret;
}