cpu-exec.c 49.9 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 39
int tb_invalidated_flag;

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

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

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

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

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

133 134 135
    spin_lock(&tb_lock);

    tb_invalidated_flag = 0;
136

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

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

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

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

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

P
pbrook 已提交
282
#define BREAK_CHAIN T0 = 0
283

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

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

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

303
    cpu_single_env = env1;
B
bellard 已提交
304

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

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

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

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

B
bellard 已提交
702

B
bellard 已提交
703
#if defined(TARGET_I386)
B
bellard 已提交
704
    /* restore flags in standard format */
B
bellard 已提交
705
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
B
bellard 已提交
706
#elif defined(TARGET_ARM)
B
bellard 已提交
707
    /* XXX: Save/restore host fpu exception state?.  */
708
#elif defined(TARGET_SPARC)
B
bellard 已提交
709 710 711
#if defined(reg_REGWPTR)
    REGWPTR = saved_regwptr;
#endif
712
#elif defined(TARGET_PPC)
P
pbrook 已提交
713 714 715 716 717
#elif defined(TARGET_M68K)
    cpu_m68k_flush_flags(env, env->cc_op);
    env->cc_op = CC_OP_FLAGS;
    env->sr = (env->sr & 0xffe0)
              | env->cc_dest | (env->cc_x << 4);
B
bellard 已提交
718
#elif defined(TARGET_MIPS)
B
bellard 已提交
719
#elif defined(TARGET_SH4)
J
j_mayer 已提交
720
#elif defined(TARGET_ALPHA)
721
#elif defined(TARGET_CRIS)
B
bellard 已提交
722
    /* XXXXX */
B
bellard 已提交
723 724 725
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
726 727

    /* restore global registers */
728
    RESTORE_GLOBALS();
P
pbrook 已提交
729 730
#include "hostregs_helper.h"

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

736 737 738 739
/* 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)
{
740 741 742
    /* XXX: cannot enable it yet because it yields to MMU exception
       where NIP != read address on PowerPC */
#if 0
743 744 745
    target_ulong phys_addr;
    phys_addr = get_phys_addr_code(env, start);
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
746
#endif
747 748
}

B
bellard 已提交
749
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
750

B
bellard 已提交
751 752 753 754 755 756
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
B
bellard 已提交
757
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
B
bellard 已提交
758
        selector &= 0xffff;
759
        cpu_x86_load_seg_cache(env, seg_reg, selector,
B
bellard 已提交
760
                               (selector << 4), 0xffff, 0);
B
bellard 已提交
761
    } else {
B
bellard 已提交
762
        load_seg(seg_reg, selector);
B
bellard 已提交
763
    }
B
bellard 已提交
764 765
    env = saved_env;
}
B
bellard 已提交
766

767
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
768 769 770 771 772
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
773

774
    helper_fsave(ptr, data32);
775 776 777 778

    env = saved_env;
}

779
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
780 781 782 783 784
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
785

786
    helper_frstor(ptr, data32);
787 788 789 790

    env = saved_env;
}

B
bellard 已提交
791 792
#endif /* TARGET_I386 */

B
bellard 已提交
793 794
#if !defined(CONFIG_SOFTMMU)

795 796
#if defined(TARGET_I386)

797
/* 'pc' is the host PC at which the exception was raised. 'address' is
B
bellard 已提交
798 799 800
   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 已提交
801
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
802
                                    int is_write, sigset_t *old_set,
803
                                    void *puc)
B
bellard 已提交
804
{
B
bellard 已提交
805 806
    TranslationBlock *tb;
    int ret;
B
bellard 已提交
807

B
bellard 已提交
808 809
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
B
bellard 已提交
810
#if defined(DEBUG_SIGNAL)
811
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
812
                pc, address, is_write, *(unsigned long *)old_set);
B
bellard 已提交
813
#endif
814
    /* XXX: locking issue */
815
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
816 817
        return 1;
    }
818

819
    /* see if it is an MMU fault */
820
    ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
821 822 823 824 825
    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 已提交
826 827
    tb = tb_find_pc(pc);
    if (tb) {
B
bellard 已提交
828 829
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
830
        cpu_restore_state(tb, env, pc, puc);
831
    }
B
bellard 已提交
832
    if (ret == 1) {
833
#if 0
834
        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
B
bellard 已提交
835
               env->eip, env->cr[2], env->error_code);
836
#endif
B
bellard 已提交
837 838 839
        /* we restore the process signal mask as the sigreturn should
           do it (XXX: use sigsetjmp) */
        sigprocmask(SIG_SETMASK, old_set, NULL);
B
bellard 已提交
840
        raise_exception_err(env->exception_index, env->error_code);
B
bellard 已提交
841 842
    } else {
        /* activate soft MMU for this block */
843
        env->hflags |= HF_SOFTMMU_MASK;
844
        cpu_resume_from_signal(env, puc);
B
bellard 已提交
845
    }
846 847 848 849
    /* never comes here */
    return 1;
}

B
bellard 已提交
850
#elif defined(TARGET_ARM)
851
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
852 853
                                    int is_write, sigset_t *old_set,
                                    void *puc)
854
{
B
bellard 已提交
855 856 857 858 859 860
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
861
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
862 863
           pc, address, is_write, *(unsigned long *)old_set);
#endif
B
bellard 已提交
864
    /* XXX: locking issue */
865
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
866 867
        return 1;
    }
B
bellard 已提交
868
    /* see if it is an MMU fault */
869
    ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
    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();
885
}
886 887
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
888 889
                                    int is_write, sigset_t *old_set,
                                    void *puc)
890
{
B
bellard 已提交
891 892 893 894 895 896
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
897
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
898 899
           pc, address, is_write, *(unsigned long *)old_set);
#endif
B
bellard 已提交
900
    /* XXX: locking issue */
901
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
902 903
        return 1;
    }
B
bellard 已提交
904
    /* see if it is an MMU fault */
905
    ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
    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();
921
}
922 923
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
924 925
                                    int is_write, sigset_t *old_set,
                                    void *puc)
926 927
{
    TranslationBlock *tb;
928
    int ret;
929

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

941
    /* see if it is an MMU fault */
942
    ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
943 944 945 946 947
    if (ret < 0)
        return 0; /* not an MMU fault */
    if (ret == 0)
        return 1; /* the MMU fault was handled without causing real CPU fault */

948 949 950 951 952
    /* 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 */
953
        cpu_restore_state(tb, env, pc, puc);
954
    }
955
    if (ret == 1) {
956
#if 0
957
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
958
               env->nip, env->error_code, tb);
959 960 961
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
962
        sigprocmask(SIG_SETMASK, old_set, NULL);
963
        do_raise_exception_err(env->exception_index, env->error_code);
964 965
    } else {
        /* activate soft MMU for this block */
966
        cpu_resume_from_signal(env, puc);
967
    }
968
    /* never comes here */
P
pbrook 已提交
969 970 971 972 973 974 975 976 977 978 979 980 981 982
    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)
983
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
P
pbrook 已提交
984 985 986 987 988 989 990
           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 */
991
    ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
P
pbrook 已提交
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
    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 */
1008 1009
    return 1;
}
B
bellard 已提交
1010 1011 1012 1013 1014 1015 1016 1017

#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;
1018

B
bellard 已提交
1019 1020 1021
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1022
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
1023 1024 1025
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
1026
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
1027 1028 1029 1030
        return 1;
    }

    /* see if it is an MMU fault */
1031
    ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
    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
1046
        printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
T
ths 已提交
1047
               env->PC, env->error_code, tb);
B
bellard 已提交
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
#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 已提交
1061 1062 1063 1064 1065 1066 1067
#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;
1068

B
bellard 已提交
1069 1070 1071
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1072
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
B
bellard 已提交
1073 1074 1075 1076 1077 1078 1079 1080
           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 */
1081
    ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
1082 1083 1084 1085 1086 1087
    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 已提交
1088 1089 1090 1091 1092 1093 1094
    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
1095
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
J
j_mayer 已提交
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
               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;
1113

J
j_mayer 已提交
1114 1115 1116
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1117
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
J
j_mayer 已提交
1118 1119 1120 1121 1122 1123 1124 1125
           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 */
1126
    ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
J
j_mayer 已提交
1127 1128 1129 1130 1131 1132
    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 已提交
1133 1134 1135 1136 1137 1138 1139
    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
1140
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
B
bellard 已提交
1141 1142 1143 1144
               env->nip, env->error_code, tb);
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
P
pbrook 已提交
1145 1146
    sigprocmask(SIG_SETMASK, old_set, NULL);
    cpu_loop_exit();
B
bellard 已提交
1147 1148 1149
    /* never comes here */
    return 1;
}
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
#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 */
1170
    ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    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 已提交
1191 1192 1193
#else
#error unsupported target CPU
#endif
B
bellard 已提交
1194

B
bellard 已提交
1195 1196
#if defined(__i386__)

1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
#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

1209
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1210
                       void *puc)
B
bellard 已提交
1211
{
1212
    siginfo_t *info = pinfo;
B
bellard 已提交
1213 1214
    struct ucontext *uc = puc;
    unsigned long pc;
1215
    int trapno;
B
bellard 已提交
1216

1217 1218
#ifndef REG_EIP
/* for glibc 2.1 */
B
bellard 已提交
1219 1220 1221
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
1222
#endif
1223 1224
    pc = EIP_sig(uc);
    trapno = TRAP_sig(uc);
B
bellard 已提交
1225 1226 1227 1228
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             trapno == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1229 1230
}

1231 1232
#elif defined(__x86_64__)

1233
int cpu_signal_handler(int host_signum, void *pinfo,
1234 1235
                       void *puc)
{
1236
    siginfo_t *info = pinfo;
1237 1238 1239 1240
    struct ucontext *uc = puc;
    unsigned long pc;

    pc = uc->uc_mcontext.gregs[REG_RIP];
1241 1242
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
1243 1244 1245 1246
                             (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
                             &uc->uc_sigmask, puc);
}

1247
#elif defined(__powerpc__)
B
bellard 已提交
1248

1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
/***********************************************************************
 * 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__ */

1298
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1299
                       void *puc)
B
bellard 已提交
1300
{
1301
    siginfo_t *info = pinfo;
1302 1303 1304 1305
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;

1306
    pc = IAR_sig(uc);
1307 1308 1309
    is_write = 0;
#if 0
    /* ppc 4xx case */
1310
    if (DSISR_sig(uc) & 0x00800000)
1311 1312
        is_write = 1;
#else
1313
    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1314 1315
        is_write = 1;
#endif
1316
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1317
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1318 1319
}

B
bellard 已提交
1320 1321
#elif defined(__alpha__)

1322
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1323 1324
                           void *puc)
{
1325
    siginfo_t *info = pinfo;
B
bellard 已提交
1326 1327 1328 1329 1330
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

1331
    /* XXX: need kernel patch to get write flag faster */
B
bellard 已提交
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
    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;
    }

1347
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1348
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1349
}
1350 1351
#elif defined(__sparc__)

1352
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1353
                       void *puc)
1354
{
1355
    siginfo_t *info = pinfo;
1356 1357 1358 1359 1360
    uint32_t *regs = (uint32_t *)(info + 1);
    void *sigmask = (regs + 20);
    unsigned long pc;
    int is_write;
    uint32_t insn;
1361

1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
    /* 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;
      }
    }
1380
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1381
                             is_write, sigmask, NULL);
1382 1383 1384 1385
}

#elif defined(__arm__)

1386
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1387
                       void *puc)
1388
{
1389
    siginfo_t *info = pinfo;
1390 1391 1392
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1393

1394 1395 1396
    pc = uc->uc_mcontext.gregs[R15];
    /* XXX: compute is_write */
    is_write = 0;
1397
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1398
                             is_write,
P
pbrook 已提交
1399
                             &uc->uc_sigmask, puc);
1400 1401
}

B
bellard 已提交
1402 1403
#elif defined(__mc68000)

1404
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1405 1406
                       void *puc)
{
1407
    siginfo_t *info = pinfo;
B
bellard 已提交
1408 1409 1410
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1411

B
bellard 已提交
1412 1413 1414
    pc = uc->uc_mcontext.gregs[16];
    /* XXX: compute is_write */
    is_write = 0;
1415
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
B
bellard 已提交
1416
                             is_write,
1417
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1418 1419
}

B
bellard 已提交
1420 1421 1422 1423 1424 1425 1426
#elif defined(__ia64)

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

1427
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
B
bellard 已提交
1428
{
1429
    siginfo_t *info = pinfo;
B
bellard 已提交
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
    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 已提交
1441
	  if (info->si_code && (info->si_segvflags & __ISR_VALID))
B
bellard 已提交
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
	      /* 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 已提交
1454 1455
#elif defined(__s390__)

1456
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1457 1458
                       void *puc)
{
1459
    siginfo_t *info = pinfo;
B
bellard 已提交
1460 1461 1462
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1463

B
bellard 已提交
1464 1465 1466
    pc = uc->uc_mcontext.psw.addr;
    /* XXX: compute is_write */
    is_write = 0;
1467
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1468 1469 1470 1471 1472
                             is_write, &uc->uc_sigmask, puc);
}

#elif defined(__mips__)

1473
int cpu_signal_handler(int host_signum, void *pinfo,
1474 1475
                       void *puc)
{
T
ths 已提交
1476
    siginfo_t *info = pinfo;
1477 1478 1479
    struct ucontext *uc = puc;
    greg_t pc = uc->uc_mcontext.pc;
    int is_write;
1480

1481 1482
    /* XXX: compute is_write */
    is_write = 0;
1483
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1484
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1485 1486
}

B
bellard 已提交
1487
#else
B
bellard 已提交
1488

1489
#error host CPU specific signal handler needed
B
bellard 已提交
1490

B
bellard 已提交
1491
#endif
B
bellard 已提交
1492 1493

#endif /* !defined(CONFIG_SOFTMMU) */