cpu-exec.c 49 KB
Newer Older
bellard's avatar
bellard committed
1 2
/*
 *  i386 emulator main execution loop
3
 *
bellard's avatar
bellard committed
4
 *  Copyright (c) 2003-2005 Fabrice Bellard
bellard's avatar
bellard committed
5
 *
bellard's avatar
bellard committed
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.
bellard's avatar
bellard committed
10
 *
bellard's avatar
bellard committed
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.
bellard's avatar
bellard committed
15
 *
bellard's avatar
bellard committed
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
bellard's avatar
bellard committed
19
 */
bellard's avatar
bellard committed
20
#include "config.h"
21
#define CPU_NO_GLOBAL_REGS
22
#include "exec.h"
bellard's avatar
log fix  
bellard committed
23
#include "disas.h"
24
#include "tcg.h"
bellard's avatar
bellard committed
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39
#if !defined(CONFIG_SOFTMMU)
#undef EAX
#undef ECX
#undef EDX
#undef EBX
#undef ESP
#undef EBP
#undef ESI
#undef EDI
#undef EIP
#include <signal.h>
#include <sys/ucontext.h>
#endif

40 41 42 43 44 45
#if defined(__sparc__) && !defined(HOST_SOLARIS)
// Work around ugly bugs in glibc that mangle global register contents
#undef env
#define env cpu_single_env
#endif

46
int tb_invalidated_flag;
47
static unsigned long next_tb;
48

bellard's avatar
bellard committed
49
//#define DEBUG_EXEC
bellard's avatar
bellard committed
50
//#define DEBUG_SIGNAL
bellard's avatar
bellard committed
51

bellard's avatar
bellard committed
52 53
void cpu_loop_exit(void)
{
54 55 56
    /* NOTE: the register at this point must be saved by hand because
       longjmp restore them */
    regs_to_env();
bellard's avatar
bellard committed
57 58
    longjmp(env->jmp_env, 1);
}
59

pbrook's avatar
pbrook committed
60
#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard's avatar
bellard committed
61 62
#define reg_T2
#endif
bellard's avatar
bellard committed
63

64 65 66
/* exit the current TB from a signal handler. The host registers are
   restored in a state compatible with the CPU emulator
 */
67
void cpu_resume_from_signal(CPUState *env1, void *puc)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
{
#if !defined(CONFIG_SOFTMMU)
    struct ucontext *uc = puc;
#endif

    env = env1;

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

#if !defined(CONFIG_SOFTMMU)
    if (puc) {
        /* XXX: use siglongjmp ? */
        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
    }
#endif
    longjmp(env->jmp_env, 1);
}

86 87
static TranslationBlock *tb_find_slow(target_ulong pc,
                                      target_ulong cs_base,
88
                                      uint64_t flags)
89 90 91 92 93 94
{
    TranslationBlock *tb, **ptb1;
    int code_gen_size;
    unsigned int h;
    target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
    uint8_t *tc_ptr;
95

96 97 98
    spin_lock(&tb_lock);

    tb_invalidated_flag = 0;
99

100
    regs_to_env(); /* XXX: do it just before cpu_gen_code() */
101

102 103 104 105 106 107 108 109 110 111
    /* find translated block using physical mappings */
    phys_pc = get_phys_addr_code(env, pc);
    phys_page1 = phys_pc & TARGET_PAGE_MASK;
    phys_page2 = -1;
    h = tb_phys_hash_func(phys_pc);
    ptb1 = &tb_phys_hash[h];
    for(;;) {
        tb = *ptb1;
        if (!tb)
            goto not_found;
112
        if (tb->pc == pc &&
113
            tb->page_addr[0] == phys_page1 &&
114
            tb->cs_base == cs_base &&
115 116 117
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
118
                virt_page2 = (pc & TARGET_PAGE_MASK) +
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
                    TARGET_PAGE_SIZE;
                phys_page2 = get_phys_addr_code(env, virt_page2);
                if (tb->page_addr[1] == phys_page2)
                    goto found;
            } else {
                goto found;
            }
        }
        ptb1 = &tb->phys_hash_next;
    }
 not_found:
    /* if no translated code available, then translate it now */
    tb = tb_alloc(pc);
    if (!tb) {
        /* flush must be done */
        tb_flush(env);
        /* cannot fail at this point */
        tb = tb_alloc(pc);
        /* don't forget to invalidate previous TB info */
bellard's avatar
bellard committed
138
        tb_invalidated_flag = 1;
139 140 141 142 143
    }
    tc_ptr = code_gen_ptr;
    tb->tc_ptr = tc_ptr;
    tb->cs_base = cs_base;
    tb->flags = flags;
144
    cpu_gen_code(env, tb, &code_gen_size);
145
    code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
146

147 148 149 150 151 152 153
    /* check next page if needed */
    virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
    phys_page2 = -1;
    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
        phys_page2 = get_phys_addr_code(env, virt_page2);
    }
    tb_link_phys(tb, phys_pc, phys_page2);
154

155 156 157 158 159 160 161 162 163 164 165
 found:
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    spin_unlock(&tb_lock);
    return tb;
}

static inline TranslationBlock *tb_find_fast(void)
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
166
    uint64_t flags;
167 168 169 170 171 172 173

    /* we record a subset of the CPU state. It will
       always be the same before a given translated block
       is executed. */
#if defined(TARGET_I386)
    flags = env->hflags;
    flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths's avatar
ths committed
174
    flags |= env->intercept;
175 176 177 178
    cs_base = env->segs[R_CS].base;
    pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
    flags = env->thumb | (env->vfp.vec_len << 1)
bellard's avatar
bellard committed
179 180 181
            | (env->vfp.vec_stride << 4);
    if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
        flags |= (1 << 6);
pbrook's avatar
pbrook committed
182 183
    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
        flags |= (1 << 7);
pbrook's avatar
pbrook committed
184
    flags |= (env->condexec_bits << 8);
185 186 187 188
    cs_base = 0;
    pc = env->regs[15];
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
bellard's avatar
bellard committed
189 190 191
    // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
    flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
        | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
192
#else
193 194
    // FPU enable . Supervisor
    flags = (env->psref << 4) | env->psrs;
195 196 197 198
#endif
    cs_base = env->npc;
    pc = env->pc;
#elif defined(TARGET_PPC)
199
    flags = env->hflags;
200 201 202
    cs_base = 0;
    pc = env->nip;
#elif defined(TARGET_MIPS)
203
    flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellard's avatar
bellard committed
204
    cs_base = 0;
205
    pc = env->PC[env->current_tc];
pbrook's avatar
pbrook committed
206
#elif defined(TARGET_M68K)
pbrook's avatar
pbrook committed
207 208 209
    flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
            | (env->sr & SR_S)            /* Bit  13 */
            | ((env->macsr >> 4) & 0xf);  /* Bits 0-3 */
pbrook's avatar
pbrook committed
210 211
    cs_base = 0;
    pc = env->pc;
bellard's avatar
bellard committed
212
#elif defined(TARGET_SH4)
213 214
    flags = env->flags;
    cs_base = 0;
bellard's avatar
bellard committed
215
    pc = env->pc;
j_mayer's avatar
j_mayer committed
216 217 218 219
#elif defined(TARGET_ALPHA)
    flags = env->ps;
    cs_base = 0;
    pc = env->pc;
220
#elif defined(TARGET_CRIS)
edgar_igl's avatar
edgar_igl committed
221
    flags = env->pregs[PR_CCS] & U_FLAG;
222
    flags |= env->dslot;
223 224
    cs_base = 0;
    pc = env->pc;
225 226 227
#else
#error unsupported CPU
#endif
bellard's avatar
bellard committed
228
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
229 230 231
    if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                         tb->flags != flags, 0)) {
        tb = tb_find_slow(pc, cs_base, flags);
bellard's avatar
bellard committed
232 233 234 235 236 237
        /* Note: we do it here to avoid a gcc bug on Mac OS X when
           doing it in tb_find_slow */
        if (tb_invalidated_flag) {
            /* as some TB could have been invalidated because
               of memory exceptions while generating the code, we
               must recompute the hash index here */
238
            next_tb = 0;
bellard's avatar
bellard committed
239
        }
240 241 242 243
    }
    return tb;
}

bellard's avatar
bellard committed
244 245
/* main execution loop */

bellard's avatar
bellard committed
246
int cpu_exec(CPUState *env1)
bellard's avatar
bellard committed
247
{
pbrook's avatar
pbrook committed
248 249 250
#define DECLARE_HOST_REGS 1
#include "hostregs_helper.h"
#if defined(TARGET_SPARC)
bellard's avatar
bellard committed
251 252 253
#if defined(reg_REGWPTR)
    uint32_t *saved_regwptr;
#endif
bellard's avatar
bellard committed
254
#endif
255 256
    int ret, interrupt_request;
    TranslationBlock *tb;
bellard's avatar
bellard committed
257
    uint8_t *tc_ptr;
258

259 260
    if (cpu_halted(env1) == EXCP_HALTED)
        return EXCP_HALTED;
bellard's avatar
bellard committed
261

262
    cpu_single_env = env1;
bellard's avatar
bellard committed
263

bellard's avatar
bellard committed
264
    /* first we save global registers */
pbrook's avatar
pbrook committed
265 266
#define SAVE_HOST_REGS 1
#include "hostregs_helper.h"
bellard's avatar
bellard committed
267
    env = env1;
bellard's avatar
bellard committed
268

269
    env_to_regs();
270
#if defined(TARGET_I386)
bellard's avatar
bellard committed
271
    /* put eflags in CPU temporary format */
bellard's avatar
bellard committed
272 273
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard's avatar
bellard committed
274
    CC_OP = CC_OP_EFLAGS;
bellard's avatar
bellard committed
275
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
276
#elif defined(TARGET_SPARC)
bellard's avatar
bellard committed
277 278 279
#if defined(reg_REGWPTR)
    saved_regwptr = REGWPTR;
#endif
pbrook's avatar
pbrook committed
280 281 282 283
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
284 285 286
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_PPC)
bellard's avatar
bellard committed
287
#elif defined(TARGET_MIPS)
bellard's avatar
bellard committed
288
#elif defined(TARGET_SH4)
289
#elif defined(TARGET_CRIS)
bellard's avatar
bellard committed
290
    /* XXXXX */
bellard's avatar
bellard committed
291 292 293
#else
#error unsupported target CPU
#endif
294
    env->exception_index = -1;
295

bellard's avatar
bellard committed
296
    /* prepare setjmp context for exception handling */
297 298
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
299
            env->current_tb = NULL;
300 301 302 303 304 305 306 307
            /* 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;
                    break;
                } else if (env->user_mode_only) {
                    /* if user mode only, we simulate a fake exception
ths's avatar
ths committed
308
                       which will be handled outside the cpu execution
309
                       loop */
bellard's avatar
bellard committed
310
#if defined(TARGET_I386)
311 312 313
                    do_interrupt_user(env->exception_index,
                                      env->exception_is_int,
                                      env->error_code,
314
                                      env->exception_next_eip);
315 316
                    /* successfully delivered */
                    env->old_exception = -1;
bellard's avatar
bellard committed
317
#endif
318 319 320
                    ret = env->exception_index;
                    break;
                } else {
bellard's avatar
bellard committed
321
#if defined(TARGET_I386)
322 323 324
                    /* simulate a real cpu exception. On i386, it can
                       trigger new exceptions, but we do not handle
                       double or triple faults yet. */
325 326 327
                    do_interrupt(env->exception_index,
                                 env->exception_is_int,
                                 env->error_code,
bellard's avatar
bellard committed
328
                                 env->exception_next_eip, 0);
329 330
                    /* successfully delivered */
                    env->old_exception = -1;
331 332
#elif defined(TARGET_PPC)
                    do_interrupt(env);
bellard's avatar
bellard committed
333 334
#elif defined(TARGET_MIPS)
                    do_interrupt(env);
335
#elif defined(TARGET_SPARC)
336
                    do_interrupt(env);
bellard's avatar
bellard committed
337 338
#elif defined(TARGET_ARM)
                    do_interrupt(env);
bellard's avatar
bellard committed
339 340
#elif defined(TARGET_SH4)
		    do_interrupt(env);
j_mayer's avatar
j_mayer committed
341 342
#elif defined(TARGET_ALPHA)
                    do_interrupt(env);
343 344
#elif defined(TARGET_CRIS)
                    do_interrupt(env);
pbrook's avatar
pbrook committed
345 346
#elif defined(TARGET_M68K)
                    do_interrupt(0);
bellard's avatar
bellard committed
347
#endif
348 349
                }
                env->exception_index = -1;
350
            }
bellard's avatar
bellard committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
#ifdef USE_KQEMU
            if (kqemu_is_ok(env) && env->interrupt_request == 0) {
                int ret;
                env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
                ret = kqemu_cpu_exec(env);
                /* 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);
                if (ret == 1) {
                    /* exception */
                    longjmp(env->jmp_env, 1);
                } else if (ret == 2) {
                    /* softmmu execution needed */
                } else {
                    if (env->interrupt_request != 0) {
                        /* hardware interrupt will be executed just after */
                    } else {
                        /* otherwise, we restart */
                        longjmp(env->jmp_env, 1);
                    }
                }
374
            }
bellard's avatar
bellard committed
375 376
#endif

377
            next_tb = 0; /* force lookup of first TB */
378
            for(;;) {
bellard's avatar
bellard committed
379
                interrupt_request = env->interrupt_request;
ths's avatar
ths committed
380 381 382 383
                if (__builtin_expect(interrupt_request, 0)
#if defined(TARGET_I386)
			&& env->hflags & HF_GIF_MASK
#endif
384
            && likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
385 386 387 388 389
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                        env->exception_index = EXCP_DEBUG;
                        cpu_loop_exit();
                    }
390
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
391
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
392 393 394 395 396 397 398
                    if (interrupt_request & CPU_INTERRUPT_HALT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                        env->halted = 1;
                        env->exception_index = EXCP_HLT;
                        cpu_loop_exit();
                    }
#endif
bellard's avatar
bellard committed
399
#if defined(TARGET_I386)
bellard's avatar
bellard committed
400 401
                    if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                        !(env->hflags & HF_SMM_MASK)) {
ths's avatar
ths committed
402
                        svm_check_intercept(SVM_EXIT_SMI);
bellard's avatar
bellard committed
403 404
                        env->interrupt_request &= ~CPU_INTERRUPT_SMI;
                        do_smm_enter();
405
                        next_tb = 0;
aurel32's avatar
aurel32 committed
406 407 408 409 410
                    } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
                        !(env->hflags & HF_NMI_MASK)) {
                        env->interrupt_request &= ~CPU_INTERRUPT_NMI;
                        env->hflags |= HF_NMI_MASK;
                        do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
411
                        next_tb = 0;
bellard's avatar
bellard committed
412
                    } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths's avatar
ths committed
413
                        (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
414
                        !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard's avatar
bellard committed
415
                        int intno;
ths's avatar
ths committed
416
                        svm_check_intercept(SVM_EXIT_INTR);
ths's avatar
ths committed
417
                        env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
418
                        intno = cpu_get_pic_interrupt(env);
419
                        if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard's avatar
bellard committed
420 421
                            fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
                        }
bellard's avatar
bellard committed
422
                        do_interrupt(intno, 0, 0, 0, 1);
bellard's avatar
bellard committed
423 424
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
425
                        next_tb = 0;
ths's avatar
ths committed
426 427 428 429 430 431
#if !defined(CONFIG_USER_ONLY)
                    } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
                        (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                         int intno;
                         /* FIXME: this should respect TPR */
                         env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths's avatar
ths committed
432
                         svm_check_intercept(SVM_EXIT_VINTR);
ths's avatar
ths committed
433 434 435 436
                         intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
                         if (loglevel & CPU_LOG_TB_IN_ASM)
                             fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
	                 do_interrupt(intno, 0, 0, -1, 1);
ths's avatar
ths committed
437 438
                         stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
                                  ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
439
                        next_tb = 0;
bellard's avatar
bellard committed
440
#endif
bellard's avatar
bellard committed
441
                    }
442
#elif defined(TARGET_PPC)
443 444 445 446 447
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
                        cpu_ppc_reset(env);
                    }
#endif
448
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
449 450 451
                        ppc_hw_interrupt(env);
                        if (env->pending_interrupts == 0)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
452
                        next_tb = 0;
453
                    }
bellard's avatar
bellard committed
454 455
#elif defined(TARGET_MIPS)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths's avatar
ths committed
456
                        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard's avatar
bellard committed
457
                        (env->CP0_Status & (1 << CP0St_IE)) &&
ths's avatar
ths committed
458 459
                        !(env->CP0_Status & (1 << CP0St_EXL)) &&
                        !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard's avatar
bellard committed
460 461 462 463 464
                        !(env->hflags & MIPS_HFLAG_DM)) {
                        /* Raise it */
                        env->exception_index = EXCP_EXT_INTERRUPT;
                        env->error_code = 0;
                        do_interrupt(env);
465
                        next_tb = 0;
bellard's avatar
bellard committed
466
                    }
467
#elif defined(TARGET_SPARC)
bellard's avatar
bellard committed
468 469 470 471 472 473 474 475 476
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
			(env->psret != 0)) {
			int pil = env->interrupt_index & 15;
			int type = env->interrupt_index & 0xf0;

			if (((type == TT_EXTINT) &&
			     (pil == 15 || pil > env->psrpil)) ||
			    type != TT_EXTINT) {
			    env->interrupt_request &= ~CPU_INTERRUPT_HARD;
477 478
                            env->exception_index = env->interrupt_index;
                            do_interrupt(env);
bellard's avatar
bellard committed
479
			    env->interrupt_index = 0;
blueswir1's avatar
blueswir1 committed
480 481 482
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
                            cpu_check_irqs(env);
#endif
483
                        next_tb = 0;
bellard's avatar
bellard committed
484
			}
485 486 487
		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
			//do_interrupt(0, 0, 0, 0, 0);
			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
488
		    }
bellard's avatar
bellard committed
489 490 491 492 493
#elif defined(TARGET_ARM)
                    if (interrupt_request & CPU_INTERRUPT_FIQ
                        && !(env->uncached_cpsr & CPSR_F)) {
                        env->exception_index = EXCP_FIQ;
                        do_interrupt(env);
494
                        next_tb = 0;
bellard's avatar
bellard committed
495
                    }
pbrook's avatar
pbrook committed
496 497 498 499 500 501 502 503 504
                    /* 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
                       the stack if an interrupt occured at the wrong time.
                       We avoid this by disabling interrupts when
                       pc contains a magic address.  */
bellard's avatar
bellard committed
505
                    if (interrupt_request & CPU_INTERRUPT_HARD
pbrook's avatar
pbrook committed
506 507
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                            || !(env->uncached_cpsr & CPSR_I))) {
bellard's avatar
bellard committed
508 509
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
510
                        next_tb = 0;
bellard's avatar
bellard committed
511
                    }
bellard's avatar
bellard committed
512
#elif defined(TARGET_SH4)
513 514
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
515
                        next_tb = 0;
516
                    }
j_mayer's avatar
j_mayer committed
517 518 519
#elif defined(TARGET_ALPHA)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
520
                        next_tb = 0;
j_mayer's avatar
j_mayer committed
521
                    }
522 523 524
#elif defined(TARGET_CRIS)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
525
                        next_tb = 0;
526
                    }
pbrook's avatar
pbrook committed
527 528 529 530 531 532 533 534 535 536 537
#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;
                        do_interrupt(1);
538
                        next_tb = 0;
pbrook's avatar
pbrook committed
539
                    }
bellard's avatar
bellard committed
540
#endif
bellard's avatar
bellard committed
541 542
                   /* Don't use the cached interupt_request value,
                      do_interrupt may have updated the EXITTB flag. */
bellard's avatar
bellard committed
543
                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
544 545 546
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
547
                        next_tb = 0;
548
                    }
bellard's avatar
bellard committed
549 550 551 552 553
                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
                        env->exception_index = EXCP_INTERRUPT;
                        cpu_loop_exit();
                    }
554
                }
bellard's avatar
bellard committed
555
#ifdef DEBUG_EXEC
bellard's avatar
bellard committed
556
                if ((loglevel & CPU_LOG_TB_CPU)) {
557
                    /* restore flags in standard format */
558 559
                    regs_to_env();
#if defined(TARGET_I386)
560
                    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard's avatar
bellard committed
561
                    cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
562
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard's avatar
bellard committed
563
#elif defined(TARGET_ARM)
bellard's avatar
bellard committed
564
                    cpu_dump_state(env, logfile, fprintf, 0);
565
#elif defined(TARGET_SPARC)
bellard's avatar
bellard committed
566 567 568
		    REGWPTR = env->regbase + (env->cwp * 16);
		    env->regwptr = REGWPTR;
                    cpu_dump_state(env, logfile, fprintf, 0);
569
#elif defined(TARGET_PPC)
bellard's avatar
bellard committed
570
                    cpu_dump_state(env, logfile, fprintf, 0);
pbrook's avatar
pbrook committed
571 572 573 574 575 576
#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);
                    cpu_dump_state(env, logfile, fprintf, 0);
bellard's avatar
bellard committed
577 578
#elif defined(TARGET_MIPS)
                    cpu_dump_state(env, logfile, fprintf, 0);
bellard's avatar
bellard committed
579 580
#elif defined(TARGET_SH4)
		    cpu_dump_state(env, logfile, fprintf, 0);
j_mayer's avatar
j_mayer committed
581 582
#elif defined(TARGET_ALPHA)
                    cpu_dump_state(env, logfile, fprintf, 0);
583 584
#elif defined(TARGET_CRIS)
                    cpu_dump_state(env, logfile, fprintf, 0);
bellard's avatar
bellard committed
585
#else
586
#error unsupported target CPU
bellard's avatar
bellard committed
587
#endif
588
                }
bellard's avatar
bellard committed
589
#endif
590
                tb = tb_find_fast();
591
#ifdef DEBUG_EXEC
bellard's avatar
bellard committed
592
                if ((loglevel & CPU_LOG_EXEC)) {
bellard's avatar
bellard committed
593 594 595
                    fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                            (long)tb->tc_ptr, tb->pc,
                            lookup_symbol(tb->pc));
596
                }
597
#endif
598 599 600
                /* see if we can patch the calling TB. When the TB
                   spans two pages, we cannot safely do a direct
                   jump. */
bellard's avatar
bellard committed
601
                {
602
                    if (next_tb != 0 &&
603
#ifdef USE_KQEMU
604 605
                        (env->kqemu_enabled != 2) &&
#endif
606
                        tb->page_addr[1] == -1) {
607
                    spin_lock(&tb_lock);
608
                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
609 610
                    spin_unlock(&tb_lock);
                }
bellard's avatar
bellard committed
611
                }
612
                tc_ptr = tb->tc_ptr;
bellard's avatar
bellard committed
613
                env->current_tb = tb;
614
                /* execute the generated code */
615 616 617 618 619
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env
                env = cpu_single_env;
#define env cpu_single_env
#endif
620
                next_tb = tcg_qemu_tb_exec(tc_ptr);
bellard's avatar
bellard committed
621
                env->current_tb = NULL;
bellard's avatar
bellard committed
622 623 624
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
625 626
                if (env->hflags & HF_SOFTMMU_MASK) {
                    env->hflags &= ~HF_SOFTMMU_MASK;
bellard's avatar
bellard committed
627
                    /* do not allow linking to another block */
628
                    next_tb = 0;
bellard's avatar
bellard committed
629
                }
630 631 632 633 634 635 636
#endif
#if defined(USE_KQEMU)
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
                if (kqemu_is_ok(env) &&
                    (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
                    cpu_loop_exit();
                }
bellard's avatar
bellard committed
637
#endif
ths's avatar
ths committed
638
            } /* for(;;) */
639
        } else {
640
            env_to_regs();
bellard's avatar
bellard committed
641
        }
642 643
    } /* for(;;) */

bellard's avatar
bellard committed
644

bellard's avatar
bellard committed
645
#if defined(TARGET_I386)
bellard's avatar
bellard committed
646
    /* restore flags in standard format */
bellard's avatar
bellard committed
647
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard's avatar
bellard committed
648
#elif defined(TARGET_ARM)
bellard's avatar
bellard committed
649
    /* XXX: Save/restore host fpu exception state?.  */
650
#elif defined(TARGET_SPARC)
bellard's avatar
bellard committed
651 652 653
#if defined(reg_REGWPTR)
    REGWPTR = saved_regwptr;
#endif
654
#elif defined(TARGET_PPC)
pbrook's avatar
pbrook committed
655 656 657 658 659
#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);
bellard's avatar
bellard committed
660
#elif defined(TARGET_MIPS)
bellard's avatar
bellard committed
661
#elif defined(TARGET_SH4)
j_mayer's avatar
j_mayer committed
662
#elif defined(TARGET_ALPHA)
663
#elif defined(TARGET_CRIS)
bellard's avatar
bellard committed
664
    /* XXXXX */
bellard's avatar
bellard committed
665 666 667
#else
#error unsupported target CPU
#endif
pbrook's avatar
pbrook committed
668 669 670 671

    /* restore global registers */
#include "hostregs_helper.h"

bellard's avatar
bellard committed
672
    /* fail safe : never use cpu_single_env outside cpu_exec() */
673
    cpu_single_env = NULL;
bellard's avatar
bellard committed
674 675
    return ret;
}
bellard's avatar
bellard committed
676

677 678 679 680
/* must only be called from the generated code as an exception can be
   generated */
void tb_invalidate_page_range(target_ulong start, target_ulong end)
{
681 682 683
    /* XXX: cannot enable it yet because it yields to MMU exception
       where NIP != read address on PowerPC */
#if 0
684 685 686
    target_ulong phys_addr;
    phys_addr = get_phys_addr_code(env, start);
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
687
#endif
688 689
}

bellard's avatar
bellard committed
690
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellard's avatar
bellard committed
691

bellard's avatar
bellard committed
692 693 694 695 696 697
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
bellard's avatar
bellard committed
698
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellard's avatar
bellard committed
699
        selector &= 0xffff;
700
        cpu_x86_load_seg_cache(env, seg_reg, selector,
bellard's avatar
bellard committed
701
                               (selector << 4), 0xffff, 0);
bellard's avatar
bellard committed
702
    } else {
bellard's avatar
bellard committed
703
        helper_load_seg(seg_reg, selector);
bellard's avatar
bellard committed
704
    }
bellard's avatar
bellard committed
705 706
    env = saved_env;
}
bellard's avatar
bellard committed
707

708
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
709 710 711 712 713
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
714

715
    helper_fsave(ptr, data32);
716 717 718 719

    env = saved_env;
}

720
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
721 722 723 724 725
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
726

727
    helper_frstor(ptr, data32);
728 729 730 731

    env = saved_env;
}

bellard's avatar
bellard committed
732 733
#endif /* TARGET_I386 */

bellard's avatar
bellard committed
734 735
#if !defined(CONFIG_SOFTMMU)

736 737
#if defined(TARGET_I386)

738
/* 'pc' is the host PC at which the exception was raised. 'address' is
bellard's avatar
bellard committed
739 740 741
   the effective address of the memory exception. 'is_write' is 1 if a
   write caused the exception and otherwise 0'. 'old_set' is the
   signal set which should be restored */
bellard's avatar
bellard committed
742
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
743
                                    int is_write, sigset_t *old_set,
744
                                    void *puc)
bellard's avatar
bellard committed
745
{
bellard's avatar
bellard committed
746 747
    TranslationBlock *tb;
    int ret;
bellard's avatar
bellard committed
748

bellard's avatar
bellard committed
749 750
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard's avatar
bellard committed
751
#if defined(DEBUG_SIGNAL)
752
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
753
                pc, address, is_write, *(unsigned long *)old_set);
bellard's avatar
bellard committed
754
#endif
755
    /* XXX: locking issue */
756
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard's avatar
bellard committed
757 758
        return 1;
    }
759

760
    /* see if it is an MMU fault */
761
    ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
762 763 764 765 766
    if (ret < 0)
        return 0; /* not an MMU fault */
    if (ret == 0)
        return 1; /* the MMU fault was handled without causing real CPU fault */
    /* now we have a real cpu fault */
bellard's avatar
bellard committed
767 768
    tb = tb_find_pc(pc);
    if (tb) {
bellard's avatar
bellard committed
769 770
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
771
        cpu_restore_state(tb, env, pc, puc);
772
    }
bellard's avatar
bellard committed
773
    if (ret == 1) {
774
#if 0
775
        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard's avatar
bellard committed
776
               env->eip, env->cr[2], env->error_code);
777
#endif
bellard's avatar
bellard committed
778 779 780
        /* we restore the process signal mask as the sigreturn should
           do it (XXX: use sigsetjmp) */
        sigprocmask(SIG_SETMASK, old_set, NULL);
781
        raise_exception_err(env->exception_index, env->error_code);
bellard's avatar
bellard committed
782 783
    } else {
        /* activate soft MMU for this block */
784
        env->hflags |= HF_SOFTMMU_MASK;
785
        cpu_resume_from_signal(env, puc);
bellard's avatar
bellard committed
786
    }
787 788 789 790
    /* never comes here */
    return 1;
}

bellard's avatar
bellard committed
791
#elif defined(TARGET_ARM)
792
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
793 794
                                    int is_write, sigset_t *old_set,
                                    void *puc)
795
{
bellard's avatar
bellard committed
796 797 798 799 800 801
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
802
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard's avatar
bellard committed
803 804
           pc, address, is_write, *(unsigned long *)old_set);
#endif
bellard's avatar
bellard committed
805
    /* XXX: locking issue */
806
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard's avatar
bellard committed
807 808
        return 1;
    }
bellard's avatar
bellard committed
809
    /* see if it is an MMU fault */
810
    ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard's avatar
bellard committed
811