cpu-exec.c 52.5 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  i386 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 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
B
bellard 已提交
19
 */
B
bellard 已提交
20
#include "config.h"
21
#include "exec.h"
B
log fix  
bellard 已提交
22
#include "disas.h"
B
bellard 已提交
23

24 25 26 27 28 29 30 31 32 33 34 35 36 37
#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

38
int tb_invalidated_flag;
39
static unsigned long next_tb;
40

B
bellard 已提交
41
//#define DEBUG_EXEC
B
bellard 已提交
42
//#define DEBUG_SIGNAL
B
bellard 已提交
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
#define SAVE_GLOBALS()
#define RESTORE_GLOBALS()

#if defined(__sparc__) && !defined(HOST_SOLARIS)
#include <features.h>
#if defined(__GLIBC__) && ((__GLIBC__ < 2) || \
                           ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 90)))
// Work around ugly bugs in glibc that mangle global register contents

static volatile void *saved_env;
static volatile unsigned long saved_t0, saved_i7;
#undef SAVE_GLOBALS
#define SAVE_GLOBALS() do {                                     \
        saved_env = env;                                        \
        saved_t0 = T0;                                          \
        asm volatile ("st %%i7, [%0]" : : "r" (&saved_i7));     \
    } while(0)

#undef RESTORE_GLOBALS
#define RESTORE_GLOBALS() do {                                  \
        env = (void *)saved_env;                                \
        T0 = saved_t0;                                          \
        asm volatile ("ld [%0], %%i7" : : "r" (&saved_i7));     \
    } while(0)

static int sparc_setjmp(jmp_buf buf)
{
    int ret;

    SAVE_GLOBALS();
    ret = setjmp(buf);
    RESTORE_GLOBALS();
    return ret;
}
#undef setjmp
#define setjmp(jmp_buf) sparc_setjmp(jmp_buf)

static void sparc_longjmp(jmp_buf buf, int val)
{
    SAVE_GLOBALS();
    longjmp(buf, val);
}
#define longjmp(jmp_buf, val) sparc_longjmp(jmp_buf, val)
#endif
#endif

B
bellard 已提交
90 91
void cpu_loop_exit(void)
{
92 93 94
    /* NOTE: the register at this point must be saved by hand because
       longjmp restore them */
    regs_to_env();
B
bellard 已提交
95 96
    longjmp(env->jmp_env, 1);
}
97

P
pbrook 已提交
98
#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
B
bellard 已提交
99 100
#define reg_T2
#endif
B
bellard 已提交
101

102 103 104
/* exit the current TB from a signal handler. The host registers are
   restored in a state compatible with the CPU emulator
 */
105
void cpu_resume_from_signal(CPUState *env1, void *puc)
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
{
#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);
}

124 125
static TranslationBlock *tb_find_slow(target_ulong pc,
                                      target_ulong cs_base,
126
                                      uint64_t flags)
127 128 129 130 131 132
{
    TranslationBlock *tb, **ptb1;
    int code_gen_size;
    unsigned int h;
    target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
    uint8_t *tc_ptr;
133

134 135 136
    spin_lock(&tb_lock);

    tb_invalidated_flag = 0;
137

138
    regs_to_env(); /* XXX: do it just before cpu_gen_code() */
139

140 141 142 143 144 145 146 147 148 149
    /* 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;
150
        if (tb->pc == pc &&
151
            tb->page_addr[0] == phys_page1 &&
152
            tb->cs_base == cs_base &&
153 154 155
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
156
                virt_page2 = (pc & TARGET_PAGE_MASK) +
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
                    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 */
B
bellard 已提交
176
        tb_invalidated_flag = 1;
177 178 179 180 181
    }
    tc_ptr = code_gen_ptr;
    tb->tc_ptr = tc_ptr;
    tb->cs_base = cs_base;
    tb->flags = flags;
182
    SAVE_GLOBALS();
183
    cpu_gen_code(env, tb, &code_gen_size);
184
    RESTORE_GLOBALS();
185
    code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
186

187 188 189 190 191 192 193
    /* 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);
194

195 196 197 198 199 200 201 202 203 204 205
 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;
206
    uint64_t flags;
207 208 209 210 211 212 213

    /* 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));
T
ths 已提交
214
    flags |= env->intercept;
215 216 217 218
    cs_base = env->segs[R_CS].base;
    pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
    flags = env->thumb | (env->vfp.vec_len << 1)
B
bellard 已提交
219 220 221
            | (env->vfp.vec_stride << 4);
    if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
        flags |= (1 << 6);
P
pbrook 已提交
222 223
    if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
        flags |= (1 << 7);
P
pbrook 已提交
224
    flags |= (env->condexec_bits << 8);
225 226 227 228
    cs_base = 0;
    pc = env->regs[15];
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
B
bellard 已提交
229 230 231
    // 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);
232
#else
233 234
    // FPU enable . Supervisor
    flags = (env->psref << 4) | env->psrs;
235 236 237 238
#endif
    cs_base = env->npc;
    pc = env->pc;
#elif defined(TARGET_PPC)
239
    flags = env->hflags;
240 241 242
    cs_base = 0;
    pc = env->nip;
#elif defined(TARGET_MIPS)
243
    flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
B
bellard 已提交
244
    cs_base = 0;
245
    pc = env->PC[env->current_tc];
P
pbrook 已提交
246
#elif defined(TARGET_M68K)
P
pbrook 已提交
247 248 249
    flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
            | (env->sr & SR_S)            /* Bit  13 */
            | ((env->macsr >> 4) & 0xf);  /* Bits 0-3 */
P
pbrook 已提交
250 251
    cs_base = 0;
    pc = env->pc;
B
bellard 已提交
252
#elif defined(TARGET_SH4)
T
ths 已提交
253 254
    flags = env->flags;
    cs_base = 0;
B
bellard 已提交
255
    pc = env->pc;
J
j_mayer 已提交
256 257 258 259
#elif defined(TARGET_ALPHA)
    flags = env->ps;
    cs_base = 0;
    pc = env->pc;
260
#elif defined(TARGET_CRIS)
E
edgar_igl 已提交
261
    flags = env->pregs[PR_CCS] & U_FLAG;
262 263
    cs_base = 0;
    pc = env->pc;
264 265 266
#else
#error unsupported CPU
#endif
B
bellard 已提交
267
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
268 269 270
    if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                         tb->flags != flags, 0)) {
        tb = tb_find_slow(pc, cs_base, flags);
B
bellard 已提交
271 272 273 274 275 276
        /* 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 */
277
            next_tb = 0;
B
bellard 已提交
278
        }
279 280 281 282
    }
    return tb;
}

B
bellard 已提交
283 284
/* main execution loop */

B
bellard 已提交
285
int cpu_exec(CPUState *env1)
B
bellard 已提交
286
{
P
pbrook 已提交
287 288 289
#define DECLARE_HOST_REGS 1
#include "hostregs_helper.h"
#if defined(TARGET_SPARC)
B
bellard 已提交
290 291 292
#if defined(reg_REGWPTR)
    uint32_t *saved_regwptr;
#endif
B
bellard 已提交
293
#endif
294
    int ret, interrupt_request;
295
    unsigned long (*gen_func)(void);
296
    TranslationBlock *tb;
B
bellard 已提交
297
    uint8_t *tc_ptr;
298

299 300
    if (cpu_halted(env1) == EXCP_HALTED)
        return EXCP_HALTED;
B
bellard 已提交
301

302
    cpu_single_env = env1;
B
bellard 已提交
303

B
bellard 已提交
304
    /* first we save global registers */
P
pbrook 已提交
305 306
#define SAVE_HOST_REGS 1
#include "hostregs_helper.h"
B
bellard 已提交
307
    env = env1;
308
    SAVE_GLOBALS();
B
bellard 已提交
309

B
bellard 已提交
310
    env_to_regs();
311
#if defined(TARGET_I386)
B
bellard 已提交
312
    /* put eflags in CPU temporary format */
B
bellard 已提交
313 314
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
B
bellard 已提交
315
    CC_OP = CC_OP_EFLAGS;
B
bellard 已提交
316
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
317
#elif defined(TARGET_SPARC)
B
bellard 已提交
318 319 320
#if defined(reg_REGWPTR)
    saved_regwptr = REGWPTR;
#endif
P
pbrook 已提交
321 322 323 324
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
325 326 327
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_PPC)
B
bellard 已提交
328
#elif defined(TARGET_MIPS)
B
bellard 已提交
329
#elif defined(TARGET_SH4)
330
#elif defined(TARGET_CRIS)
B
bellard 已提交
331
    /* XXXXX */
B
bellard 已提交
332 333 334
#else
#error unsupported target CPU
#endif
335
    env->exception_index = -1;
336

B
bellard 已提交
337
    /* prepare setjmp context for exception handling */
338 339
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
340
            env->current_tb = NULL;
341 342 343 344 345 346 347 348
            /* 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
T
ths 已提交
349
                       which will be handled outside the cpu execution
350
                       loop */
B
bellard 已提交
351
#if defined(TARGET_I386)
352 353 354
                    do_interrupt_user(env->exception_index,
                                      env->exception_is_int,
                                      env->error_code,
355
                                      env->exception_next_eip);
B
bellard 已提交
356
#endif
357 358 359
                    ret = env->exception_index;
                    break;
                } else {
B
bellard 已提交
360
#if defined(TARGET_I386)
361 362 363
                    /* simulate a real cpu exception. On i386, it can
                       trigger new exceptions, but we do not handle
                       double or triple faults yet. */
364 365 366
                    do_interrupt(env->exception_index,
                                 env->exception_is_int,
                                 env->error_code,
B
bellard 已提交
367
                                 env->exception_next_eip, 0);
368 369
                    /* successfully delivered */
                    env->old_exception = -1;
370 371
#elif defined(TARGET_PPC)
                    do_interrupt(env);
B
bellard 已提交
372 373
#elif defined(TARGET_MIPS)
                    do_interrupt(env);
374
#elif defined(TARGET_SPARC)
B
bellard 已提交
375
                    do_interrupt(env->exception_index);
B
bellard 已提交
376 377
#elif defined(TARGET_ARM)
                    do_interrupt(env);
B
bellard 已提交
378 379
#elif defined(TARGET_SH4)
		    do_interrupt(env);
J
j_mayer 已提交
380 381
#elif defined(TARGET_ALPHA)
                    do_interrupt(env);
382 383
#elif defined(TARGET_CRIS)
                    do_interrupt(env);
P
pbrook 已提交
384 385
#elif defined(TARGET_M68K)
                    do_interrupt(0);
B
bellard 已提交
386
#endif
387 388
                }
                env->exception_index = -1;
389
            }
B
bellard 已提交
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
#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);
                    }
                }
413
            }
B
bellard 已提交
414 415
#endif

416
            next_tb = 0; /* force lookup of first TB */
417
            for(;;) {
418
                SAVE_GLOBALS();
B
bellard 已提交
419
                interrupt_request = env->interrupt_request;
T
ths 已提交
420 421 422 423
                if (__builtin_expect(interrupt_request, 0)
#if defined(TARGET_I386)
			&& env->hflags & HF_GIF_MASK
#endif
424
            && !(env->singlestep_enabled & SSTEP_NOIRQ)) {
425 426 427 428 429
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                        env->exception_index = EXCP_DEBUG;
                        cpu_loop_exit();
                    }
430
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
431
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
432 433 434 435 436 437 438
                    if (interrupt_request & CPU_INTERRUPT_HALT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                        env->halted = 1;
                        env->exception_index = EXCP_HLT;
                        cpu_loop_exit();
                    }
#endif
B
bellard 已提交
439
#if defined(TARGET_I386)
B
bellard 已提交
440 441
                    if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                        !(env->hflags & HF_SMM_MASK)) {
T
ths 已提交
442
                        svm_check_intercept(SVM_EXIT_SMI);
B
bellard 已提交
443 444
                        env->interrupt_request &= ~CPU_INTERRUPT_SMI;
                        do_smm_enter();
445
                        next_tb = 0;
A
aurel32 已提交
446 447 448 449 450
                    } 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);
451
                        next_tb = 0;
B
bellard 已提交
452
                    } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
T
ths 已提交
453
                        (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
454
                        !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
B
bellard 已提交
455
                        int intno;
T
ths 已提交
456
                        svm_check_intercept(SVM_EXIT_INTR);
T
ths 已提交
457
                        env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
458
                        intno = cpu_get_pic_interrupt(env);
459
                        if (loglevel & CPU_LOG_TB_IN_ASM) {
B
bellard 已提交
460 461
                            fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
                        }
B
bellard 已提交
462
                        do_interrupt(intno, 0, 0, 0, 1);
B
bellard 已提交
463 464
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
465
                        next_tb = 0;
T
ths 已提交
466 467 468 469 470 471
#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;
T
ths 已提交
472
                         svm_check_intercept(SVM_EXIT_VINTR);
T
ths 已提交
473 474 475 476
                         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);
T
ths 已提交
477 478
                         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);
479
                        next_tb = 0;
B
bellard 已提交
480
#endif
B
bellard 已提交
481
                    }
482
#elif defined(TARGET_PPC)
483 484 485 486 487
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
                        cpu_ppc_reset(env);
                    }
#endif
488
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
489 490 491
                        ppc_hw_interrupt(env);
                        if (env->pending_interrupts == 0)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
492
                        next_tb = 0;
493
                    }
B
bellard 已提交
494 495
#elif defined(TARGET_MIPS)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
T
ths 已提交
496
                        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
B
bellard 已提交
497
                        (env->CP0_Status & (1 << CP0St_IE)) &&
T
ths 已提交
498 499
                        !(env->CP0_Status & (1 << CP0St_EXL)) &&
                        !(env->CP0_Status & (1 << CP0St_ERL)) &&
B
bellard 已提交
500 501 502 503 504
                        !(env->hflags & MIPS_HFLAG_DM)) {
                        /* Raise it */
                        env->exception_index = EXCP_EXT_INTERRUPT;
                        env->error_code = 0;
                        do_interrupt(env);
505
                        next_tb = 0;
B
bellard 已提交
506
                    }
507
#elif defined(TARGET_SPARC)
B
bellard 已提交
508 509 510 511 512 513 514 515 516 517 518
                    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;
			    do_interrupt(env->interrupt_index);
			    env->interrupt_index = 0;
B
blueswir1 已提交
519 520 521
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
                            cpu_check_irqs(env);
#endif
522
                        next_tb = 0;
B
bellard 已提交
523
			}
524 525 526
		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
			//do_interrupt(0, 0, 0, 0, 0);
			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
527
		    }
B
bellard 已提交
528 529 530 531 532
#elif defined(TARGET_ARM)
                    if (interrupt_request & CPU_INTERRUPT_FIQ
                        && !(env->uncached_cpsr & CPSR_F)) {
                        env->exception_index = EXCP_FIQ;
                        do_interrupt(env);
533
                        next_tb = 0;
B
bellard 已提交
534
                    }
P
pbrook 已提交
535 536 537 538 539 540 541 542 543
                    /* 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.  */
B
bellard 已提交
544
                    if (interrupt_request & CPU_INTERRUPT_HARD
P
pbrook 已提交
545 546
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                            || !(env->uncached_cpsr & CPSR_I))) {
B
bellard 已提交
547 548
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
549
                        next_tb = 0;
B
bellard 已提交
550
                    }
B
bellard 已提交
551
#elif defined(TARGET_SH4)
552 553
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
554
                        next_tb = 0;
555
                    }
J
j_mayer 已提交
556 557 558
#elif defined(TARGET_ALPHA)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
559
                        next_tb = 0;
J
j_mayer 已提交
560
                    }
561 562 563
#elif defined(TARGET_CRIS)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
564
                        next_tb = 0;
565
                    }
P
pbrook 已提交
566 567 568 569 570 571 572 573 574 575 576
#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);
577
                        next_tb = 0;
P
pbrook 已提交
578
                    }
B
bellard 已提交
579
#endif
B
bellard 已提交
580 581
                   /* Don't use the cached interupt_request value,
                      do_interrupt may have updated the EXITTB flag. */
B
bellard 已提交
582
                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
583 584 585
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
586
                        next_tb = 0;
587
                    }
B
bellard 已提交
588 589 590 591 592
                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
                        env->exception_index = EXCP_INTERRUPT;
                        cpu_loop_exit();
                    }
593
                }
B
bellard 已提交
594
#ifdef DEBUG_EXEC
B
bellard 已提交
595
                if ((loglevel & CPU_LOG_TB_CPU)) {
596
                    /* restore flags in standard format */
597 598
                    regs_to_env();
#if defined(TARGET_I386)
599
                    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
B
bellard 已提交
600
                    cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
601
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
B
bellard 已提交
602
#elif defined(TARGET_ARM)
B
bellard 已提交
603
                    cpu_dump_state(env, logfile, fprintf, 0);
604
#elif defined(TARGET_SPARC)
B
bellard 已提交
605 606 607
		    REGWPTR = env->regbase + (env->cwp * 16);
		    env->regwptr = REGWPTR;
                    cpu_dump_state(env, logfile, fprintf, 0);
608
#elif defined(TARGET_PPC)
B
bellard 已提交
609
                    cpu_dump_state(env, logfile, fprintf, 0);
P
pbrook 已提交
610 611 612 613 614 615
#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);
B
bellard 已提交
616 617
#elif defined(TARGET_MIPS)
                    cpu_dump_state(env, logfile, fprintf, 0);
B
bellard 已提交
618 619
#elif defined(TARGET_SH4)
		    cpu_dump_state(env, logfile, fprintf, 0);
J
j_mayer 已提交
620 621
#elif defined(TARGET_ALPHA)
                    cpu_dump_state(env, logfile, fprintf, 0);
622 623
#elif defined(TARGET_CRIS)
                    cpu_dump_state(env, logfile, fprintf, 0);
B
bellard 已提交
624
#else
625
#error unsupported target CPU
B
bellard 已提交
626
#endif
627
                }
B
bellard 已提交
628
#endif
629
                tb = tb_find_fast();
630
#ifdef DEBUG_EXEC
B
bellard 已提交
631
                if ((loglevel & CPU_LOG_EXEC)) {
B
bellard 已提交
632 633 634
                    fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                            (long)tb->tc_ptr, tb->pc,
                            lookup_symbol(tb->pc));
635
                }
636
#endif
637
                RESTORE_GLOBALS();
638 639 640
                /* see if we can patch the calling TB. When the TB
                   spans two pages, we cannot safely do a direct
                   jump. */
B
bellard 已提交
641
                {
642
                    if (next_tb != 0 &&
643
#ifdef USE_KQEMU
644 645
                        (env->kqemu_enabled != 2) &&
#endif
B
bellard 已提交
646
                        tb->page_addr[1] == -1) {
647
                    spin_lock(&tb_lock);
648
                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
649 650
                    spin_unlock(&tb_lock);
                }
B
bellard 已提交
651
                }
652
                tc_ptr = tb->tc_ptr;
B
bellard 已提交
653
                env->current_tb = tb;
654 655
                /* execute the generated code */
                gen_func = (void *)tc_ptr;
656
#if defined(__sparc__)
657 658 659
                __asm__ __volatile__("call	%0\n\t"
                                     "mov	%%o7,%%i0"
                                     : /* no outputs */
660
                                     : "r" (gen_func)
B
bellard 已提交
661
                                     : "i0", "i1", "i2", "i3", "i4", "i5",
662
                                       "o0", "o1", "o2", "o3", "o4", "o5",
B
bellard 已提交
663 664
                                       "l0", "l1", "l2", "l3", "l4", "l5",
                                       "l6", "l7");
A
aurel32 已提交
665 666 667 668
#elif defined(__hppa__)
                asm volatile ("ble  0(%%sr4,%1)\n"
                              "copy %%r31,%%r18\n"
                              "copy %%r28,%0\n"
669
                              : "=r" (next_tb)
A
aurel32 已提交
670 671 672 673 674 675
                              : "r" (gen_func)
                              : "r1", "r2", "r3", "r4", "r5", "r6", "r7",
                                "r8", "r9", "r10", "r11", "r12", "r13",
                                "r18", "r19", "r20", "r21", "r22", "r23",
                                "r24", "r25", "r26", "r27", "r28", "r29",
                                "r30", "r31");
676
#elif defined(__arm__)
677 678 679 680 681 682
                asm volatile ("mov pc, %0\n\t"
                              ".global exec_loop\n\t"
                              "exec_loop:\n\t"
                              : /* no outputs */
                              : "r" (gen_func)
                              : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
B
bellard 已提交
683 684 685 686 687 688 689 690 691
#elif defined(__ia64)
		struct fptr {
			void *ip;
			void *gp;
		} fp;

		fp.ip = tc_ptr;
		fp.gp = code_gen_buffer + 2 * (1 << 20);
		(*(void (*)(void)) &fp)();
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
#elif defined(__i386)
                asm volatile ("sub $12, %%esp\n\t"
                              "push %%ebp\n\t"
                              "call *%1\n\t"
                              "pop %%ebp\n\t"
                              "add $12, %%esp\n\t"
                              : "=a" (next_tb)
                              : "a" (gen_func)
                              : "ebx", "ecx", "edx", "esi", "edi", "cc",
                                "memory");
#elif defined(__x86_64__)
                asm volatile ("sub $8, %%rsp\n\t"
                              "push %%rbp\n\t"
                              "call *%1\n\t"
                              "pop %%rbp\n\t"
                              "add $8, %%rsp\n\t"
                              : "=a" (next_tb)
                              : "a" (gen_func)
                              : "rbx", "rcx", "rdx", "rsi", "rdi", "r8", "r9",
                                "r10", "r11", "r12", "r13", "r14", "r15", "cc",
                                "memory");
B
bellard 已提交
713
#else
714
                next_tb = gen_func();
B
bellard 已提交
715
#endif
B
bellard 已提交
716
                env->current_tb = NULL;
B
bellard 已提交
717 718 719
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
720 721
                if (env->hflags & HF_SOFTMMU_MASK) {
                    env->hflags &= ~HF_SOFTMMU_MASK;
B
bellard 已提交
722
                    /* do not allow linking to another block */
723
                    next_tb = 0;
B
bellard 已提交
724
                }
725 726 727 728 729 730 731
#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();
                }
B
bellard 已提交
732
#endif
T
ths 已提交
733
            } /* for(;;) */
734
        } else {
B
bellard 已提交
735
            env_to_regs();
B
bellard 已提交
736
        }
737 738
    } /* for(;;) */

B
bellard 已提交
739

B
bellard 已提交
740
#if defined(TARGET_I386)
B
bellard 已提交
741
    /* restore flags in standard format */
B
bellard 已提交
742
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
B
bellard 已提交
743
#elif defined(TARGET_ARM)
B
bellard 已提交
744
    /* XXX: Save/restore host fpu exception state?.  */
745
#elif defined(TARGET_SPARC)
B
bellard 已提交
746 747 748
#if defined(reg_REGWPTR)
    REGWPTR = saved_regwptr;
#endif
749
#elif defined(TARGET_PPC)
P
pbrook 已提交
750 751 752 753 754
#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);
B
bellard 已提交
755
#elif defined(TARGET_MIPS)
B
bellard 已提交
756
#elif defined(TARGET_SH4)
J
j_mayer 已提交
757
#elif defined(TARGET_ALPHA)
758
#elif defined(TARGET_CRIS)
B
bellard 已提交
759
    /* XXXXX */
B
bellard 已提交
760 761 762
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
763 764

    /* restore global registers */
765
    RESTORE_GLOBALS();
P
pbrook 已提交
766 767
#include "hostregs_helper.h"

B
bellard 已提交
768
    /* fail safe : never use cpu_single_env outside cpu_exec() */
769
    cpu_single_env = NULL;
B
bellard 已提交
770 771
    return ret;
}
B
bellard 已提交
772

773 774 775 776
/* 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)
{
777 778 779
    /* XXX: cannot enable it yet because it yields to MMU exception
       where NIP != read address on PowerPC */
#if 0
780 781 782
    target_ulong phys_addr;
    phys_addr = get_phys_addr_code(env, start);
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
783
#endif
784 785
}

B
bellard 已提交
786
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
787

B
bellard 已提交
788 789 790 791 792 793
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
B
bellard 已提交
794
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
B
bellard 已提交
795
        selector &= 0xffff;
796
        cpu_x86_load_seg_cache(env, seg_reg, selector,
B
bellard 已提交
797
                               (selector << 4), 0xffff, 0);
B
bellard 已提交
798
    } else {
B
bellard 已提交
799
        load_seg(seg_reg, selector);
B
bellard 已提交
800
    }
B
bellard 已提交
801 802
    env = saved_env;
}
B
bellard 已提交
803

804
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
805 806 807 808 809
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
810

811
    helper_fsave(ptr, data32);
812 813 814 815

    env = saved_env;
}

816
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
817 818 819 820 821
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
822

823
    helper_frstor(ptr, data32);
824 825 826 827

    env = saved_env;
}

B
bellard 已提交
828 829
#endif /* TARGET_I386 */

B
bellard 已提交
830 831
#if !defined(CONFIG_SOFTMMU)

832 833
#if defined(TARGET_I386)

834
/* 'pc' is the host PC at which the exception was raised. 'address' is
B
bellard 已提交
835 836 837
   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 */
B
bellard 已提交
838
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
839
                                    int is_write, sigset_t *old_set,
840
                                    void *puc)
B
bellard 已提交
841
{
B
bellard 已提交
842 843
    TranslationBlock *tb;
    int ret;
B
bellard 已提交
844

B
bellard 已提交
845 846
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
B
bellard 已提交
847
#if defined(DEBUG_SIGNAL)
848
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
849
                pc, address, is_write, *(unsigned long *)old_set);
B
bellard 已提交
850
#endif
851
    /* XXX: locking issue */
852
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
853 854
        return 1;
    }
855

856
    /* see if it is an MMU fault */
857
    ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
858 859 860 861 862
    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 */
B
bellard 已提交
863 864
    tb = tb_find_pc(pc);
    if (tb) {
B
bellard 已提交
865 866
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
867
        cpu_restore_state(tb, env, pc, puc);
868
    }
B
bellard 已提交
869
    if (ret == 1) {
870
#if 0
871
        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
B
bellard 已提交
872
               env->eip, env->cr[2], env->error_code);
873
#endif
B
bellard 已提交
874 875 876
        /* we restore the process signal mask as the sigreturn should
           do it (XXX: use sigsetjmp) */
        sigprocmask(SIG_SETMASK, old_set, NULL);
B
bellard 已提交
877
        raise_exception_err(env->exception_index, env->error_code);
B
bellard 已提交
878 879
    } else {
        /* activate soft MMU for this block */
880
        env->hflags |= HF_SOFTMMU_MASK;
881
        cpu_resume_from_signal(env, puc);
B
bellard 已提交
882
    }
883 884 885 886
    /* never comes here */
    return 1;
}

B
bellard 已提交
887
#elif defined(TARGET_ARM)
888
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
889 890
                                    int is_write, sigset_t *old_set,
                                    void *puc)
891
{
B
bellard 已提交
892 893 894 895 896 897
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
898
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
899 900
           pc, address, is_write, *(unsigned long *)old_set);
#endif
B
bellard 已提交
901
    /* XXX: locking issue */
902
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
903 904
        return 1;
    }
B
bellard 已提交
905
    /* see if it is an MMU fault */
906
    ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
    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 */
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        cpu_restore_state(tb, env, pc, puc);
    }
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
    sigprocmask(SIG_SETMASK, old_set, NULL);
    cpu_loop_exit();
A
aurel32 已提交
922 923
    /* never comes here */
    return 1;
924
}
925 926
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
927 928
                                    int is_write, sigset_t *old_set,
                                    void *puc)
929
{
B
bellard 已提交
930 931 932 933 934 935
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
936
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
937 938
           pc, address, is_write, *(unsigned long *)old_set);
#endif
B
bellard 已提交
939
    /* XXX: locking issue */
940
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
941 942
        return 1;
    }
B
bellard 已提交
943
    /* see if it is an MMU fault */
944
    ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
    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 */
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        cpu_restore_state(tb, env, pc, puc);
    }
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
    sigprocmask(SIG_SETMASK, old_set, NULL);
    cpu_loop_exit();
A
aurel32 已提交
960 961
    /* never comes here */
    return 1;
962
}
963 964
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
965 966
                                    int is_write, sigset_t *old_set,
                                    void *puc)
967 968
{
    TranslationBlock *tb;
969
    int ret;
970

971 972 973
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
974
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
975 976 977
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
978
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
979 980 981
        return 1;
    }

982
    /* see if it is an MMU fault */
983
    ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
984 985 986 987 988
    if (ret < 0)
        return 0; /* not an MMU fault */
    if (ret == 0)
        return 1; /* the MMU fault was handled without causing real CPU fault */

989 990 991 992 993
    /* now we have a real cpu fault */
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
994
        cpu_restore_state(tb, env, pc, puc);
995
    }
996
    if (ret == 1) {
997
#if 0
998
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
999
               env->nip, env->error_code, tb);
1000 1001 1002
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
1003
        sigprocmask(SIG_SETMASK, old_set, NULL);
1004
        do_raise_exception_err(env->exception_index, env->error_code);
1005 1006
    } else {
        /* activate soft MMU for this block */
1007
        cpu_resume_from_signal(env, puc);
1008
    }
1009
    /* never comes here */
P
pbrook 已提交
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
    return 1;
}

#elif defined(TARGET_M68K)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                    int is_write, sigset_t *old_set,
                                    void *puc)
{
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1024
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
P
pbrook 已提交
1025 1026 1027 1028 1029 1030 1031
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
    if (is_write && page_unprotect(address, pc, puc)) {
        return 1;
    }
    /* see if it is an MMU fault */
1032
    ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
P
pbrook 已提交
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
    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 */
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        cpu_restore_state(tb, env, pc, puc);
    }
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
    sigprocmask(SIG_SETMASK, old_set, NULL);
    cpu_loop_exit();
    /* never comes here */
1049 1050
    return 1;
}
B
bellard 已提交
1051 1052 1053 1054 1055 1056 1057 1058

#elif defined (TARGET_MIPS)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                    int is_write, sigset_t *old_set,
                                    void *puc)
{
    TranslationBlock *tb;
    int ret;
1059

B
bellard 已提交
1060 1061 1062
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1063
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
1064 1065 1066
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
1067
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
1068 1069 1070 1071
        return 1;
    }

    /* see if it is an MMU fault */
1072
    ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
    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 */
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        cpu_restore_state(tb, env, pc, puc);
    }
    if (ret == 1) {
#if 0
1087
        printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
T
ths 已提交
1088
               env->PC, env->error_code, tb);
B
bellard 已提交
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
        sigprocmask(SIG_SETMASK, old_set, NULL);
        do_raise_exception_err(env->exception_index, env->error_code);
    } else {
        /* activate soft MMU for this block */
        cpu_resume_from_signal(env, puc);
    }
    /* never comes here */
    return 1;
}

B
bellard 已提交
1102 1103 1104 1105 1106 1107 1108
#elif defined (TARGET_SH4)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                    int is_write, sigset_t *old_set,
                                    void *puc)
{
    TranslationBlock *tb;
    int ret;
1109

B
bellard 已提交
1110 1111 1112
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1113
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
1114 1115 1116 1117 1118 1119 1120 1121
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
        return 1;
    }

    /* see if it is an MMU fault */
1122
    ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
1123 1124 1125 1126 1127 1128
    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 */
J
j_mayer 已提交
1129 1130 1131 1132 1133 1134 1135
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        cpu_restore_state(tb, env, pc, puc);
    }
#if 0
1136
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
J
j_mayer 已提交
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
               env->nip, env->error_code, tb);
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
    sigprocmask(SIG_SETMASK, old_set, NULL);
    cpu_loop_exit();
    /* never comes here */
    return 1;
}

#elif defined (TARGET_ALPHA)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                    int is_write, sigset_t *old_set,
                                    void *puc)
{
    TranslationBlock *tb;
    int ret;
1154

J
j_mayer 已提交
1155 1156 1157
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1158
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
J
j_mayer 已提交
1159 1160 1161 1162 1163 1164 1165 1166
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
        return 1;
    }

    /* see if it is an MMU fault */
1167
    ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
J
j_mayer 已提交
1168 1169 1170 1171 1172 1173
    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 */
B
bellard 已提交
1174 1175 1176 1177 1178 1179 1180
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        cpu_restore_state(tb, env, pc, puc);
    }
#if 0
1181
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
B
bellard 已提交
1182 1183 1184 1185
               env->nip, env->error_code, tb);
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
P
pbrook 已提交
1186 1187
    sigprocmask(SIG_SETMASK, old_set, NULL);
    cpu_loop_exit();
B
bellard 已提交
1188 1189 1190
    /* never comes here */
    return 1;
}
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
#elif defined (TARGET_CRIS)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                    int is_write, sigset_t *old_set,
                                    void *puc)
{
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
        return 1;
    }

    /* see if it is an MMU fault */
1211
    ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
    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 */
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        cpu_restore_state(tb, env, pc, puc);
    }
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
    sigprocmask(SIG_SETMASK, old_set, NULL);
    cpu_loop_exit();
    /* never comes here */
    return 1;
}

B
bellard 已提交
1232 1233 1234
#else
#error unsupported target CPU
#endif
B
bellard 已提交
1235

B
bellard 已提交
1236 1237
#if defined(__i386__)

1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
#if defined(__APPLE__)
# include <sys/ucontext.h>

# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
# define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
# define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
#else
# define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
# define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
# define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
#endif

1250
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1251
                       void *puc)
B
bellard 已提交
1252
{
1253
    siginfo_t *info = pinfo;
B
bellard 已提交
1254 1255
    struct ucontext *uc = puc;
    unsigned long pc;
1256
    int trapno;
B
bellard 已提交
1257

1258 1259
#ifndef REG_EIP
/* for glibc 2.1 */
B
bellard 已提交
1260 1261 1262
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
1263
#endif
1264 1265
    pc = EIP_sig(uc);
    trapno = TRAP_sig(uc);
B
bellard 已提交
1266 1267 1268 1269
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             trapno == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1270 1271
}

1272 1273
#elif defined(__x86_64__)

1274
int cpu_signal_handler(int host_signum, void *pinfo,
1275 1276
                       void *puc)
{
1277
    siginfo_t *info = pinfo;
1278 1279 1280 1281
    struct ucontext *uc = puc;
    unsigned long pc;

    pc = uc->uc_mcontext.gregs[REG_RIP];
1282 1283
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
1284 1285 1286 1287
                             (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
                             &uc->uc_sigmask, puc);
}

1288
#elif defined(__powerpc__)
B
bellard 已提交
1289

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
/***********************************************************************
 * signal context platform-specific definitions
 * From Wine
 */
#ifdef linux
/* All Registers access - only for local access */
# define REG_sig(reg_name, context)		((context)->uc_mcontext.regs->reg_name)
/* Gpr Registers access  */
# define GPR_sig(reg_num, context)		REG_sig(gpr[reg_num], context)
# define IAR_sig(context)			REG_sig(nip, context)	/* Program counter */
# define MSR_sig(context)			REG_sig(msr, context)   /* Machine State Register (Supervisor) */
# define CTR_sig(context)			REG_sig(ctr, context)   /* Count register */
# define XER_sig(context)			REG_sig(xer, context) /* User's integer exception register */
# define LR_sig(context)			REG_sig(link, context) /* Link register */
# define CR_sig(context)			REG_sig(ccr, context) /* Condition register */
/* Float Registers access  */
# define FLOAT_sig(reg_num, context)		(((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
# define FPSCR_sig(context)			(*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
/* Exception Registers access */
# define DAR_sig(context)			REG_sig(dar, context)
# define DSISR_sig(context)			REG_sig(dsisr, context)
# define TRAP_sig(context)			REG_sig(trap, context)
#endif /* linux */

#ifdef __APPLE__
# include <sys/ucontext.h>
typedef struct ucontext SIGCONTEXT;
/* All Registers access - only for local access */
# define REG_sig(reg_name, context)		((context)->uc_mcontext->ss.reg_name)
# define FLOATREG_sig(reg_name, context)	((context)->uc_mcontext->fs.reg_name)
# define EXCEPREG_sig(reg_name, context)	((context)->uc_mcontext->es.reg_name)
# define VECREG_sig(reg_name, context)		((context)->uc_mcontext->vs.reg_name)
/* Gpr Registers access */
# define GPR_sig(reg_num, context)		REG_sig(r##reg_num, context)
# define IAR_sig(context)			REG_sig(srr0, context)	/* Program counter */
# define MSR_sig(context)			REG_sig(srr1, context)  /* Machine State Register (Supervisor) */
# define CTR_sig(context)			REG_sig(ctr, context)
# define XER_sig(context)			REG_sig(xer, context) /* Link register */
# define LR_sig(context)			REG_sig(lr, context)  /* User's integer exception register */
# define CR_sig(context)			REG_sig(cr, context)  /* Condition register */
/* Float Registers access */
# define FLOAT_sig(reg_num, context)		FLOATREG_sig(fpregs[reg_num], context)
# define FPSCR_sig(context)			((double)FLOATREG_sig(fpscr, context))
/* Exception Registers access */
# define DAR_sig(context)			EXCEPREG_sig(dar, context)     /* Fault registers for coredump */
# define DSISR_sig(context)			EXCEPREG_sig(dsisr, context)
# define TRAP_sig(context)			EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
#endif /* __APPLE__ */

1339
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1340
                       void *puc)
B
bellard 已提交
1341
{
1342
    siginfo_t *info = pinfo;
1343 1344 1345 1346
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;

1347
    pc = IAR_sig(uc);
1348 1349 1350
    is_write = 0;
#if 0
    /* ppc 4xx case */
1351
    if (DSISR_sig(uc) & 0x00800000)
1352 1353
        is_write = 1;
#else
1354
    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1355 1356
        is_write = 1;
#endif
1357
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1358
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1359 1360
}

B
bellard 已提交
1361 1362
#elif defined(__alpha__)

1363
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1364 1365
                           void *puc)
{
1366
    siginfo_t *info = pinfo;
B
bellard 已提交
1367 1368 1369 1370 1371
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

1372
    /* XXX: need kernel patch to get write flag faster */
B
bellard 已提交
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
    switch (insn >> 26) {
    case 0x0d: // stw
    case 0x0e: // stb
    case 0x0f: // stq_u
    case 0x24: // stf
    case 0x25: // stg
    case 0x26: // sts
    case 0x27: // stt
    case 0x2c: // stl
    case 0x2d: // stq
    case 0x2e: // stl_c
    case 0x2f: // stq_c
	is_write = 1;
    }

1388
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1389
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1390
}
1391 1392
#elif defined(__sparc__)

1393
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1394
                       void *puc)
1395
{
1396
    siginfo_t *info = pinfo;
1397 1398 1399 1400 1401
    uint32_t *regs = (uint32_t *)(info + 1);
    void *sigmask = (regs + 20);
    unsigned long pc;
    int is_write;
    uint32_t insn;
1402

1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
    /* XXX: is there a standard glibc define ? */
    pc = regs[1];
    /* XXX: need kernel patch to get write flag faster */
    is_write = 0;
    insn = *(uint32_t *)pc;
    if ((insn >> 30) == 3) {
      switch((insn >> 19) & 0x3f) {
      case 0x05: // stb
      case 0x06: // sth
      case 0x04: // st
      case 0x07: // std
      case 0x24: // stf
      case 0x27: // stdf
      case 0x25: // stfsr
	is_write = 1;
	break;
      }
    }
1421
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1422
                             is_write, sigmask, NULL);
1423 1424 1425 1426
}

#elif defined(__arm__)

1427
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1428
                       void *puc)
1429
{
1430
    siginfo_t *info = pinfo;
1431 1432 1433
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1434

1435
    pc = uc->uc_mcontext.arm_pc;
1436 1437
    /* XXX: compute is_write */
    is_write = 0;
1438
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1439
                             is_write,
P
pbrook 已提交
1440
                             &uc->uc_sigmask, puc);
1441 1442
}

B
bellard 已提交
1443 1444
#elif defined(__mc68000)

1445
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1446 1447
                       void *puc)
{
1448
    siginfo_t *info = pinfo;
B
bellard 已提交
1449 1450 1451
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1452

B
bellard 已提交
1453 1454 1455
    pc = uc->uc_mcontext.gregs[16];
    /* XXX: compute is_write */
    is_write = 0;
1456
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
B
bellard 已提交
1457
                             is_write,
1458
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1459 1460
}

B
bellard 已提交
1461 1462 1463 1464 1465 1466 1467
#elif defined(__ia64)

#ifndef __ISR_VALID
  /* This ought to be in <bits/siginfo.h>... */
# define __ISR_VALID	1
#endif

1468
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
B
bellard 已提交
1469
{
1470
    siginfo_t *info = pinfo;
B
bellard 已提交
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
    struct ucontext *uc = puc;
    unsigned long ip;
    int is_write = 0;

    ip = uc->uc_mcontext.sc_ip;
    switch (host_signum) {
      case SIGILL:
      case SIGFPE:
      case SIGSEGV:
      case SIGBUS:
      case SIGTRAP:
B
bellard 已提交
1482
	  if (info->si_code && (info->si_segvflags & __ISR_VALID))
B
bellard 已提交
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
	      /* ISR.W (write-access) is bit 33:  */
	      is_write = (info->si_isr >> 33) & 1;
	  break;

      default:
	  break;
    }
    return handle_cpu_signal(ip, (unsigned long)info->si_addr,
                             is_write,
                             &uc->uc_sigmask, puc);
}

B
bellard 已提交
1495 1496
#elif defined(__s390__)

1497
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1498 1499
                       void *puc)
{
1500
    siginfo_t *info = pinfo;
B
bellard 已提交
1501 1502 1503
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1504

B
bellard 已提交
1505 1506 1507
    pc = uc->uc_mcontext.psw.addr;
    /* XXX: compute is_write */
    is_write = 0;
1508
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1509 1510 1511 1512 1513
                             is_write, &uc->uc_sigmask, puc);
}

#elif defined(__mips__)

1514
int cpu_signal_handler(int host_signum, void *pinfo,
1515 1516
                       void *puc)
{
T
ths 已提交
1517
    siginfo_t *info = pinfo;
1518 1519 1520
    struct ucontext *uc = puc;
    greg_t pc = uc->uc_mcontext.pc;
    int is_write;
1521

1522 1523
    /* XXX: compute is_write */
    is_write = 0;
1524
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1525
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1526 1527
}

A
aurel32 已提交
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
#elif defined(__hppa__)

int cpu_signal_handler(int host_signum, void *pinfo,
                       void *puc)
{
    struct siginfo *info = pinfo;
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;

    pc = uc->uc_mcontext.sc_iaoq[0];
    /* FIXME: compute is_write */
    is_write = 0;
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                             is_write,
                             &uc->uc_sigmask, puc);
}

B
bellard 已提交
1546
#else
B
bellard 已提交
1547

1548
#error host CPU specific signal handler needed
B
bellard 已提交
1549

B
bellard 已提交
1550
#endif
B
bellard 已提交
1551 1552

#endif /* !defined(CONFIG_SOFTMMU) */