cpu-exec.c 51.1 KB
Newer Older
bellard's avatar
bellard committed
1 2
/*
 *  i386 emulator main execution loop
3
 *
bellard's avatar
bellard committed
4
 *  Copyright (c) 2003-2005 Fabrice Bellard
bellard's avatar
bellard committed
5
 *
bellard's avatar
bellard committed
6 7 8 9
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
bellard's avatar
bellard committed
10
 *
bellard's avatar
bellard committed
11 12 13 14
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
bellard's avatar
bellard committed
15
 *
bellard's avatar
bellard committed
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
bellard's avatar
bellard committed
19
 */
20
#include "config.h"
21
#define CPU_NO_GLOBAL_REGS
22
#include "exec.h"
bellard's avatar
bellard committed
23
#include "disas.h"
24
#include "tcg.h"
aliguori's avatar
aliguori committed
25
#include "kvm.h"
bellard's avatar
bellard committed
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>
38
#ifdef __linux__
39 40
#include <sys/ucontext.h>
#endif
41
#endif
42

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

49 50
int tb_invalidated_flag;

51
//#define DEBUG_EXEC
bellard's avatar
bellard committed
52
//#define DEBUG_SIGNAL
bellard's avatar
bellard committed
53

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

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

    env = env1;

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

#if !defined(CONFIG_SOFTMMU)
    if (puc) {
        /* XXX: use siglongjmp ? */
82
#ifdef __linux__
83
        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
84 85 86
#elif defined(__OpenBSD__)
        sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
#endif
87 88 89 90 91
    }
#endif
    longjmp(env->jmp_env, 1);
}

pbrook's avatar
pbrook committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
/* Execute the code without caching the generated code. An interpreter
   could be used if available. */
static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
{
    unsigned long next_tb;
    TranslationBlock *tb;

    /* Should never happen.
       We only end up here when an existing TB is too long.  */
    if (max_cycles > CF_COUNT_MASK)
        max_cycles = CF_COUNT_MASK;

    tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
                     max_cycles);
    env->current_tb = tb;
    /* execute the generated code */
    next_tb = tcg_qemu_tb_exec(tb->tc_ptr);

    if ((next_tb & 3) == 2) {
        /* Restore PC.  This may happen if async event occurs before
           the TB starts executing.  */
113
        cpu_pc_from_tb(env, tb);
pbrook's avatar
pbrook committed
114 115 116 117 118
    }
    tb_phys_invalidate(tb, -1);
    tb_free(tb);
}

119 120
static TranslationBlock *tb_find_slow(target_ulong pc,
                                      target_ulong cs_base,
121
                                      uint64_t flags)
122 123 124 125
{
    TranslationBlock *tb, **ptb1;
    unsigned int h;
    target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
126

127
    tb_invalidated_flag = 0;
128

129
    regs_to_env(); /* XXX: do it just before cpu_gen_code() */
130

131 132 133 134 135 136 137 138 139 140
    /* 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;
141
        if (tb->pc == pc &&
142
            tb->page_addr[0] == phys_page1 &&
143
            tb->cs_base == cs_base &&
144 145 146
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
147
                virt_page2 = (pc & TARGET_PAGE_MASK) +
148 149 150 151 152 153 154 155 156 157 158
                    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:
pbrook's avatar
pbrook committed
159 160
   /* if no translated code available, then translate it now */
    tb = tb_gen_code(env, pc, cs_base, flags, 0);
161

162 163 164 165 166 167 168 169 170 171
 found:
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    return tb;
}

static inline TranslationBlock *tb_find_fast(void)
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
172
    int flags;
173 174 175 176

    /* we record a subset of the CPU state. It will
       always be the same before a given translated block
       is executed. */
177
    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
178
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
179 180
    if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                 tb->flags != flags)) {
181 182 183 184 185
        tb = tb_find_slow(pc, cs_base, flags);
    }
    return tb;
}

186 187 188 189 190 191 192 193 194 195
static CPUDebugExcpHandler *debug_excp_handler;

CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
{
    CPUDebugExcpHandler *old_handler = debug_excp_handler;

    debug_excp_handler = handler;
    return old_handler;
}

196 197 198 199 200
static void cpu_handle_debug_exception(CPUState *env)
{
    CPUWatchpoint *wp;

    if (!env->watchpoint_hit)
201
        TAILQ_FOREACH(wp, &env->watchpoints, entry)
202
            wp->flags &= ~BP_WATCHPOINT_HIT;
203 204 205

    if (debug_excp_handler)
        debug_excp_handler(env);
206 207
}

bellard's avatar
bellard committed
208 209
/* main execution loop */

210
int cpu_exec(CPUState *env1)
bellard's avatar
bellard committed
211
{
212 213
#define DECLARE_HOST_REGS 1
#include "hostregs_helper.h"
214 215
    int ret, interrupt_request;
    TranslationBlock *tb;
bellard's avatar
bellard committed
216
    uint8_t *tc_ptr;
pbrook's avatar
pbrook committed
217
    unsigned long next_tb;
218

219 220
    if (cpu_halted(env1) == EXCP_HALTED)
        return EXCP_HALTED;
bellard's avatar
bellard committed
221

222
    cpu_single_env = env1;
bellard's avatar
bellard committed
223

bellard's avatar
bellard committed
224
    /* first we save global registers */
225 226
#define SAVE_HOST_REGS 1
#include "hostregs_helper.h"
bellard's avatar
bellard committed
227
    env = env1;
228

229
    env_to_regs();
230
#if defined(TARGET_I386)
bellard's avatar
bellard committed
231
    /* put eflags in CPU temporary format */
bellard's avatar
bellard committed
232 233
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard's avatar
bellard committed
234
    CC_OP = CC_OP_EFLAGS;
bellard's avatar
bellard committed
235
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
236
#elif defined(TARGET_SPARC)
pbrook's avatar
pbrook committed
237 238 239 240
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
241 242 243
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_PPC)
bellard's avatar
bellard committed
244
#elif defined(TARGET_MIPS)
bellard's avatar
bellard committed
245
#elif defined(TARGET_SH4)
246
#elif defined(TARGET_CRIS)
bellard's avatar
bellard committed
247
    /* XXXXX */
248 249 250
#else
#error unsupported target CPU
#endif
251
    env->exception_index = -1;
252

bellard's avatar
bellard committed
253
    /* prepare setjmp context for exception handling */
254 255
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
256
            env->current_tb = NULL;
257 258 259 260 261
            /* if an exception is pending, we execute it here */
            if (env->exception_index >= 0) {
                if (env->exception_index >= EXCP_INTERRUPT) {
                    /* exit request from the cpu execution loop */
                    ret = env->exception_index;
262 263
                    if (ret == EXCP_DEBUG)
                        cpu_handle_debug_exception(env);
264 265 266
                    break;
                } else if (env->user_mode_only) {
                    /* if user mode only, we simulate a fake exception
ths's avatar
ths committed
267
                       which will be handled outside the cpu execution
268
                       loop */
bellard's avatar
bellard committed
269
#if defined(TARGET_I386)
270 271 272
                    do_interrupt_user(env->exception_index,
                                      env->exception_is_int,
                                      env->error_code,
273
                                      env->exception_next_eip);
274 275
                    /* successfully delivered */
                    env->old_exception = -1;
bellard's avatar
bellard committed
276
#endif
277 278 279
                    ret = env->exception_index;
                    break;
                } else {
bellard's avatar
bellard committed
280
#if defined(TARGET_I386)
281 282 283
                    /* simulate a real cpu exception. On i386, it can
                       trigger new exceptions, but we do not handle
                       double or triple faults yet. */
284 285 286
                    do_interrupt(env->exception_index,
                                 env->exception_is_int,
                                 env->error_code,
287
                                 env->exception_next_eip, 0);
288 289
                    /* successfully delivered */
                    env->old_exception = -1;
290 291
#elif defined(TARGET_PPC)
                    do_interrupt(env);
bellard's avatar
bellard committed
292 293
#elif defined(TARGET_MIPS)
                    do_interrupt(env);
294
#elif defined(TARGET_SPARC)
295
                    do_interrupt(env);
bellard's avatar
bellard committed
296 297
#elif defined(TARGET_ARM)
                    do_interrupt(env);
bellard's avatar
bellard committed
298 299
#elif defined(TARGET_SH4)
		    do_interrupt(env);
300 301
#elif defined(TARGET_ALPHA)
                    do_interrupt(env);
302 303
#elif defined(TARGET_CRIS)
                    do_interrupt(env);
pbrook's avatar
pbrook committed
304 305
#elif defined(TARGET_M68K)
                    do_interrupt(0);
bellard's avatar
bellard committed
306
#endif
307 308
                }
                env->exception_index = -1;
309
            }
bellard's avatar
bellard committed
310 311 312
#ifdef USE_KQEMU
            if (kqemu_is_ok(env) && env->interrupt_request == 0) {
                int ret;
pbrook's avatar
pbrook committed
313
                env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard's avatar
bellard committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
                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);
                    }
                }
333
            }
bellard's avatar
bellard committed
334 335
#endif

aliguori's avatar
aliguori committed
336
            if (kvm_enabled()) {
aliguori's avatar
aliguori committed
337 338
                kvm_cpu_exec(env);
                longjmp(env->jmp_env, 1);
aliguori's avatar
aliguori committed
339 340
            }

341
            next_tb = 0; /* force lookup of first TB */
342
            for(;;) {
bellard's avatar
bellard committed
343
                interrupt_request = env->interrupt_request;
344 345 346 347 348 349 350 351
                if (unlikely(interrupt_request)) {
                    if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
                        /* Mask out external interrupts for this step. */
                        interrupt_request &= ~(CPU_INTERRUPT_HARD |
                                               CPU_INTERRUPT_FIQ |
                                               CPU_INTERRUPT_SMI |
                                               CPU_INTERRUPT_NMI);
                    }
352 353 354 355 356
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                        env->exception_index = EXCP_DEBUG;
                        cpu_loop_exit();
                    }
357
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
358
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
359 360 361 362 363 364 365
                    if (interrupt_request & CPU_INTERRUPT_HALT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                        env->halted = 1;
                        env->exception_index = EXCP_HLT;
                        cpu_loop_exit();
                    }
#endif
bellard's avatar
bellard committed
366
#if defined(TARGET_I386)
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
                    if (env->hflags2 & HF2_GIF_MASK) {
                        if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                            !(env->hflags & HF_SMM_MASK)) {
                            svm_check_intercept(SVM_EXIT_SMI);
                            env->interrupt_request &= ~CPU_INTERRUPT_SMI;
                            do_smm_enter();
                            next_tb = 0;
                        } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
                                   !(env->hflags2 & HF2_NMI_MASK)) {
                            env->interrupt_request &= ~CPU_INTERRUPT_NMI;
                            env->hflags2 |= HF2_NMI_MASK;
                            do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
                            next_tb = 0;
                        } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
                                   (((env->hflags2 & HF2_VINTR_MASK) && 
                                     (env->hflags2 & HF2_HIF_MASK)) ||
                                    (!(env->hflags2 & HF2_VINTR_MASK) && 
                                     (env->eflags & IF_MASK && 
                                      !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
                            int intno;
                            svm_check_intercept(SVM_EXIT_INTR);
                            env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
                            intno = cpu_get_pic_interrupt(env);
                            if (loglevel & CPU_LOG_TB_IN_ASM) {
                                fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
                            }
                            do_interrupt(intno, 0, 0, 0, 1);
                            /* ensure that no TB jump will be modified as
                               the program flow was changed */
                            next_tb = 0;
ths's avatar
ths committed
397
#if !defined(CONFIG_USER_ONLY)
398 399 400 401 402 403 404 405 406 407 408 409
                        } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
                                   (env->eflags & IF_MASK) && 
                                   !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                            int intno;
                            /* FIXME: this should respect TPR */
                            svm_check_intercept(SVM_EXIT_VINTR);
                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
                            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, 0, 1);
                            next_tb = 0;
bellard's avatar
bellard committed
410
#endif
411
                        }
bellard's avatar
bellard committed
412
                    }
413
#elif defined(TARGET_PPC)
414 415 416 417 418
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
                        cpu_ppc_reset(env);
                    }
#endif
419
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
420 421 422
                        ppc_hw_interrupt(env);
                        if (env->pending_interrupts == 0)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
423
                        next_tb = 0;
424
                    }
bellard's avatar
bellard committed
425 426
#elif defined(TARGET_MIPS)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths's avatar
ths committed
427
                        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard's avatar
bellard committed
428
                        (env->CP0_Status & (1 << CP0St_IE)) &&
ths's avatar
ths committed
429 430
                        !(env->CP0_Status & (1 << CP0St_EXL)) &&
                        !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard's avatar
bellard committed
431 432 433 434 435
                        !(env->hflags & MIPS_HFLAG_DM)) {
                        /* Raise it */
                        env->exception_index = EXCP_EXT_INTERRUPT;
                        env->error_code = 0;
                        do_interrupt(env);
436
                        next_tb = 0;
bellard's avatar
bellard committed
437
                    }
438
#elif defined(TARGET_SPARC)
bellard's avatar
bellard committed
439 440 441 442 443 444 445 446 447
                    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;
448 449
                            env->exception_index = env->interrupt_index;
                            do_interrupt(env);
bellard's avatar
bellard committed
450
			    env->interrupt_index = 0;
451 452 453
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
                            cpu_check_irqs(env);
#endif
454
                        next_tb = 0;
bellard's avatar
bellard committed
455
			}
456 457 458
		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
			//do_interrupt(0, 0, 0, 0, 0);
			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
459
		    }
bellard's avatar
bellard committed
460 461 462 463 464
#elif defined(TARGET_ARM)
                    if (interrupt_request & CPU_INTERRUPT_FIQ
                        && !(env->uncached_cpsr & CPSR_F)) {
                        env->exception_index = EXCP_FIQ;
                        do_interrupt(env);
465
                        next_tb = 0;
bellard's avatar
bellard committed
466
                    }
pbrook's avatar
pbrook committed
467 468 469 470 471 472 473 474 475
                    /* ARMv7-M interrupt return works by loading a magic value
                       into the PC.  On real hardware the load causes the
                       return to occur.  The qemu implementation performs the
                       jump normally, then does the exception return when the
                       CPU tries to execute code at the magic address.
                       This will cause the magic PC value to be pushed to
                       the stack if an interrupt occured at the wrong time.
                       We avoid this by disabling interrupts when
                       pc contains a magic address.  */
bellard's avatar
bellard committed
476
                    if (interrupt_request & CPU_INTERRUPT_HARD
pbrook's avatar
pbrook committed
477 478
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                            || !(env->uncached_cpsr & CPSR_I))) {
bellard's avatar
bellard committed
479 480
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
481
                        next_tb = 0;
bellard's avatar
bellard committed
482
                    }
bellard's avatar
bellard committed
483
#elif defined(TARGET_SH4)
484 485
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
486
                        next_tb = 0;
487
                    }
488 489 490
#elif defined(TARGET_ALPHA)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
491
                        next_tb = 0;
492
                    }
493
#elif defined(TARGET_CRIS)
edgar_igl's avatar
edgar_igl committed
494 495 496 497 498 499 500 501 502
                    if (interrupt_request & CPU_INTERRUPT_HARD
                        && (env->pregs[PR_CCS] & I_FLAG)) {
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
                        next_tb = 0;
                    }
                    if (interrupt_request & CPU_INTERRUPT_NMI
                        && (env->pregs[PR_CCS] & M_FLAG)) {
                        env->exception_index = EXCP_NMI;
503
                        do_interrupt(env);
504
                        next_tb = 0;
505
                    }
pbrook's avatar
pbrook committed
506 507 508 509 510 511 512 513 514 515 516
#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);
517
                        next_tb = 0;
pbrook's avatar
pbrook committed
518
                    }
bellard's avatar
bellard committed
519
#endif
bellard's avatar
bellard committed
520 521
                   /* Don't use the cached interupt_request value,
                      do_interrupt may have updated the EXITTB flag. */
bellard's avatar
bellard committed
522
                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
523 524 525
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
526
                        next_tb = 0;
527
                    }
bellard's avatar
bellard committed
528 529 530 531 532
                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
                        env->exception_index = EXCP_INTERRUPT;
                        cpu_loop_exit();
                    }
533
                }
bellard's avatar
bellard committed
534
#ifdef DEBUG_EXEC
bellard's avatar
bellard committed
535
                if ((loglevel & CPU_LOG_TB_CPU)) {
536
                    /* restore flags in standard format */
537 538
                    regs_to_env();
#if defined(TARGET_I386)
pbrook's avatar
pbrook committed
539
                    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellard's avatar
bellard committed
540
                    cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
541
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
542
#elif defined(TARGET_ARM)
bellard's avatar
bellard committed
543
                    cpu_dump_state(env, logfile, fprintf, 0);
544
#elif defined(TARGET_SPARC)
bellard's avatar
bellard committed
545
                    cpu_dump_state(env, logfile, fprintf, 0);
546
#elif defined(TARGET_PPC)
bellard's avatar
bellard committed
547
                    cpu_dump_state(env, logfile, fprintf, 0);
pbrook's avatar
pbrook committed
548 549 550 551 552 553
#elif defined(TARGET_M68K)
                    cpu_m68k_flush_flags(env, env->cc_op);
                    env->cc_op = CC_OP_FLAGS;
                    env->sr = (env->sr & 0xffe0)
                              | env->cc_dest | (env->cc_x << 4);
                    cpu_dump_state(env, logfile, fprintf, 0);
bellard's avatar
bellard committed
554 555
#elif defined(TARGET_MIPS)
                    cpu_dump_state(env, logfile, fprintf, 0);
bellard's avatar
bellard committed
556 557
#elif defined(TARGET_SH4)
		    cpu_dump_state(env, logfile, fprintf, 0);
558 559
#elif defined(TARGET_ALPHA)
                    cpu_dump_state(env, logfile, fprintf, 0);
560 561
#elif defined(TARGET_CRIS)
                    cpu_dump_state(env, logfile, fprintf, 0);
562
#else
563
#error unsupported target CPU
564
#endif
565
                }
bellard's avatar
bellard committed
566
#endif
pbrook's avatar
pbrook committed
567
                spin_lock(&tb_lock);
568
                tb = tb_find_fast();
pbrook's avatar
pbrook committed
569 570 571 572 573 574 575
                /* 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 */
                    next_tb = 0;
pbrook's avatar
pbrook committed
576
                    tb_invalidated_flag = 0;
pbrook's avatar
pbrook committed
577
                }
578
#ifdef DEBUG_EXEC
bellard's avatar
bellard committed
579
                if ((loglevel & CPU_LOG_EXEC)) {
bellard's avatar
bellard committed
580 581 582
                    fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                            (long)tb->tc_ptr, tb->pc,
                            lookup_symbol(tb->pc));
583
                }
584
#endif
585 586 587
                /* see if we can patch the calling TB. When the TB
                   spans two pages, we cannot safely do a direct
                   jump. */
bellard's avatar
bellard committed
588
                {
589
                    if (next_tb != 0 &&
590
#ifdef USE_KQEMU
591 592
                        (env->kqemu_enabled != 2) &&
#endif
593
                        tb->page_addr[1] == -1) {
594
                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
595
                }
bellard's avatar
bellard committed
596
                }
pbrook's avatar
pbrook committed
597
                spin_unlock(&tb_lock);
bellard's avatar
bellard committed
598
                env->current_tb = tb;
599 600 601 602 603 604 605 606

                /* cpu_interrupt might be called while translating the
                   TB, but before it is linked into a potentially
                   infinite loop and becomes env->current_tb. Avoid
                   starting execution if there is a pending interrupt. */
                if (unlikely (env->interrupt_request & CPU_INTERRUPT_EXIT))
                    env->current_tb = NULL;

pbrook's avatar
pbrook committed
607 608
                while (env->current_tb) {
                    tc_ptr = tb->tc_ptr;
609
                /* execute the generated code */
610 611
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env
pbrook's avatar
pbrook committed
612
                    env = cpu_single_env;
613 614
#define env cpu_single_env
#endif
pbrook's avatar
pbrook committed
615 616 617
                    next_tb = tcg_qemu_tb_exec(tc_ptr);
                    env->current_tb = NULL;
                    if ((next_tb & 3) == 2) {
618
                        /* Instruction counter expired.  */
pbrook's avatar
pbrook committed
619 620 621
                        int insns_left;
                        tb = (TranslationBlock *)(long)(next_tb & ~3);
                        /* Restore PC.  */
622
                        cpu_pc_from_tb(env, tb);
pbrook's avatar
pbrook committed
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
                        insns_left = env->icount_decr.u32;
                        if (env->icount_extra && insns_left >= 0) {
                            /* Refill decrementer and continue execution.  */
                            env->icount_extra += insns_left;
                            if (env->icount_extra > 0xffff) {
                                insns_left = 0xffff;
                            } else {
                                insns_left = env->icount_extra;
                            }
                            env->icount_extra -= insns_left;
                            env->icount_decr.u16.low = insns_left;
                        } else {
                            if (insns_left > 0) {
                                /* Execute remaining instructions.  */
                                cpu_exec_nocache(insns_left, tb);
                            }
                            env->exception_index = EXCP_INTERRUPT;
                            next_tb = 0;
                            cpu_loop_exit();
                        }
                    }
                }
bellard's avatar
bellard committed
645 646
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
647 648 649 650 651 652
#if defined(USE_KQEMU)
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
                if (kqemu_is_ok(env) &&
                    (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
                    cpu_loop_exit();
                }
bellard's avatar
bellard committed
653
#endif
ths's avatar
ths committed
654
            } /* for(;;) */
655
        } else {
656
            env_to_regs();
bellard's avatar
bellard committed
657
        }
658 659
    } /* for(;;) */

bellard's avatar
bellard committed
660

661
#if defined(TARGET_I386)
bellard's avatar
bellard committed
662
    /* restore flags in standard format */
pbrook's avatar
pbrook committed
663
    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
664
#elif defined(TARGET_ARM)
bellard's avatar
bellard committed
665
    /* XXX: Save/restore host fpu exception state?.  */
666
#elif defined(TARGET_SPARC)
667
#elif defined(TARGET_PPC)
pbrook's avatar
pbrook committed
668 669 670 671 672
#elif defined(TARGET_M68K)
    cpu_m68k_flush_flags(env, env->cc_op);
    env->cc_op = CC_OP_FLAGS;
    env->sr = (env->sr & 0xffe0)
              | env->cc_dest | (env->cc_x << 4);
bellard's avatar
bellard committed
673
#elif defined(TARGET_MIPS)
bellard's avatar
bellard committed
674
#elif defined(TARGET_SH4)
675
#elif defined(TARGET_ALPHA)
676
#elif defined(TARGET_CRIS)
bellard's avatar
bellard committed
677
    /* XXXXX */
678 679 680
#else
#error unsupported target CPU
#endif
681 682 683 684

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

bellard's avatar
bellard committed
685
    /* fail safe : never use cpu_single_env outside cpu_exec() */
686
    cpu_single_env = NULL;
bellard's avatar
bellard committed
687 688
    return ret;
}
bellard's avatar
bellard committed
689

690 691 692 693
/* 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)
{
694 695 696
    /* XXX: cannot enable it yet because it yields to MMU exception
       where NIP != read address on PowerPC */
#if 0
697 698 699
    target_ulong phys_addr;
    phys_addr = get_phys_addr_code(env, start);
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
700
#endif
701 702
}

bellard's avatar
bellard committed
703
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
704

bellard's avatar
bellard committed
705 706 707 708 709 710
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
bellard's avatar
bellard committed
711
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellard's avatar
bellard committed
712
        selector &= 0xffff;
713
        cpu_x86_load_seg_cache(env, seg_reg, selector,
bellard's avatar
bellard committed
714
                               (selector << 4), 0xffff, 0);
bellard's avatar
bellard committed
715
    } else {
bellard's avatar
bellard committed
716
        helper_load_seg(seg_reg, selector);
bellard's avatar
bellard committed
717
    }
bellard's avatar
bellard committed
718 719
    env = saved_env;
}
bellard's avatar
bellard committed
720

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

    saved_env = env;
    env = s;
727

728
    helper_fsave(ptr, data32);
729 730 731 732

    env = saved_env;
}

733
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
734 735 736 737 738
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
739

740
    helper_frstor(ptr, data32);
741 742 743 744

    env = saved_env;
}

745 746
#endif /* TARGET_I386 */

bellard's avatar
bellard committed
747 748
#if !defined(CONFIG_SOFTMMU)

749 750
#if defined(TARGET_I386)

751
/* 'pc' is the host PC at which the exception was raised. 'address' is
bellard's avatar
bellard committed
752 753 754
   the effective address of the memory exception. 'is_write' is 1 if a
   write caused the exception and otherwise 0'. 'old_set' is the
   signal set which should be restored */
bellard's avatar
bellard committed
755
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
756
                                    int is_write, sigset_t *old_set,
757
                                    void *puc)
bellard's avatar
bellard committed
758
{
bellard's avatar
bellard committed
759 760
    TranslationBlock *tb;
    int ret;
bellard's avatar
bellard committed
761

bellard's avatar
bellard committed
762 763
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard's avatar
bellard committed
764
#if defined(DEBUG_SIGNAL)
765
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
766
                pc, address, is_write, *(unsigned long *)old_set);
bellard's avatar
bellard committed
767
#endif
768
    /* XXX: locking issue */
769
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard's avatar
bellard committed
770 771
        return 1;
    }
772

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

804
#elif defined(TARGET_ARM)
805
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
806 807
                                    int is_write, sigset_t *old_set,
                                    void *puc)
808
{
bellard's avatar
bellard committed
809 810 811 812 813 814
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
815
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard's avatar
bellard committed
816 817
           pc, address, is_write, *(unsigned long *)old_set);
#endif
bellard's avatar
bellard committed
818
    /* XXX: locking issue */
819
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard's avatar
bellard committed
820 821
        return 1;
    }
bellard's avatar
bellard committed
822
    /* see if it is an MMU fault */
823
    ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard's avatar
bellard committed
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
    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();
aurel32's avatar
aurel32 committed
839 840
    /* never comes here */
    return 1;
841
}
842 843
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
844 845
                                    int is_write, sigset_t *old_set,
                                    void *puc)
846
{
bellard's avatar
bellard committed
847 848 849 850 851 852
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
853
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard's avatar
bellard committed
854 855
           pc, address, is_write, *(unsigned long *)old_set);
#endif
bellard's avatar
bellard committed
856
    /* XXX: locking issue */
857
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard's avatar
bellard committed
858 859
        return 1;
    }
bellard's avatar
bellard committed
860
    /* see if it is an MMU fault */
861
    ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard's avatar
bellard committed
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
    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();
aurel32's avatar
aurel32 committed
877 878
    /* never comes here */
    return 1;
879
}
880 881
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
882 883
                                    int is_write, sigset_t *old_set,
                                    void *puc)
884 885
{
    TranslationBlock *tb;
886
    int ret;
887

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

899
    /* see if it is an MMU fault */
900
    ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
901 902 903 904 905
    if (ret < 0)
        return 0; /* not an MMU fault */
    if (ret == 0)
        return 1; /* the MMU fault was handled without causing real CPU fault */

906 907 908 909 910
    /* 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 */
911
        cpu_restore_state(tb, env, pc, puc);
912
    }
913
    if (ret == 1) {
914
#if 0
915
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
916
               env->nip, env->error_code, tb);
917 918 919
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
920
        sigprocmask(SIG_SETMASK, old_set, NULL);
aurel32's avatar
aurel32 committed
921
        cpu_loop_exit();
922 923
    } else {
        /* activate soft MMU for this block */
924
        cpu_resume_from_signal(env, puc);
925
    }
926
    /* never comes here */
pbrook's avatar
pbrook committed
927 928 929 930 931 932 933 934 935 936 937 938 939 940
    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)
941
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrook's avatar
pbrook committed
942 943 944 945 946 947 948
           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 */
949
    ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrook's avatar
pbrook committed
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
    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 */
966 967
    return 1;
}
bellard's avatar
bellard committed
968 969 970 971 972 973 974 975

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

bellard's avatar
bellard committed
977 978 979
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
980
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard's avatar
bellard committed
981 982 983
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
984
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard's avatar
bellard committed
985 986 987 988
        return 1;
    }

    /* see if it is an MMU fault */
989
    ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard's avatar
bellard committed
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
    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
1004
        printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths's avatar
ths committed
1005
               env->PC, env->error_code, tb);
bellard's avatar
bellard committed
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
#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;
}

bellard's avatar
bellard committed
1019 1020 1021 1022 1023 1024 1025
#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;
1026

bellard's avatar
bellard committed
1027 1028 1029
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1030
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard's avatar
bellard committed
1031 1032 1033 1034 1035 1036 1037 1038
           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 */
1039
    ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard's avatar
bellard committed
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 */
1046 1047 1048 1049 1050 1051 1052
    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
1053
        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
               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;
1071

1072 1073 1074
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
1075
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1076 1077 1078 1079 1080 1081 1082 1083
           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 */
1084
    ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
1085 1086 1087 1088 1089 1090
    if (ret < 0)
        return 0; /* not an MMU fault */
    if (ret == 0)
        return 1; /* the MMU fault was handled without causing real CPU fault */

    /* now we have a real cpu fault */
bellard's avatar
bellard committed
1091 1092 1093 1094 1095 1096 1097
    tb = tb_find_pc(pc);
    if (tb) {
        /* the PC is inside the translated code. It means that we have