cpu-exec.c 44.0 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
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
18
 */
B
bellard 已提交
19
#include "config.h"
20
#include "exec.h"
B
log fix  
bellard 已提交
21
#include "disas.h"
22
#include "tcg.h"
A
aliguori 已提交
23
#include "kvm.h"
J
Jan Kiszka 已提交
24
#include "qemu-barrier.h"
B
bellard 已提交
25

26 27 28 29 30 31 32 33 34 35 36
#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>
B
blueswir1 已提交
37
#ifdef __linux__
38 39
#include <sys/ucontext.h>
#endif
B
blueswir1 已提交
40
#endif
41

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

48 49
int tb_invalidated_flag;

50
//#define CONFIG_DEBUG_EXEC
B
bellard 已提交
51
//#define DEBUG_SIGNAL
B
bellard 已提交
52

53 54 55 56 57
int qemu_cpu_has_work(CPUState *env)
{
    return cpu_has_work(env);
}

B
bellard 已提交
58 59
void cpu_loop_exit(void)
{
P
Paolo Bonzini 已提交
60
    env->current_tb = NULL;
B
bellard 已提交
61 62
    longjmp(env->jmp_env, 1);
}
63

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

    env = env1;

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

#if !defined(CONFIG_SOFTMMU)
    if (puc) {
        /* XXX: use siglongjmp ? */
B
blueswir1 已提交
84
#ifdef __linux__
85 86 87
#ifdef __ia64
        sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
#else
88
        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
89
#endif
B
blueswir1 已提交
90 91 92
#elif defined(__OpenBSD__)
        sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
#endif
93 94
    }
#endif
95
    env->exception_index = -1;
96 97 98
    longjmp(env->jmp_env, 1);
}

P
pbrook 已提交
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
/* 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);
P
Paolo Bonzini 已提交
116
    env->current_tb = NULL;
P
pbrook 已提交
117 118 119 120

    if ((next_tb & 3) == 2) {
        /* Restore PC.  This may happen if async event occurs before
           the TB starts executing.  */
121
        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
122 123 124 125 126
    }
    tb_phys_invalidate(tb, -1);
    tb_free(tb);
}

127 128
static TranslationBlock *tb_find_slow(target_ulong pc,
                                      target_ulong cs_base,
129
                                      uint64_t flags)
130 131 132
{
    TranslationBlock *tb, **ptb1;
    unsigned int h;
P
Paul Brook 已提交
133 134
    tb_page_addr_t phys_pc, phys_page1, phys_page2;
    target_ulong virt_page2;
135

136
    tb_invalidated_flag = 0;
137

138
    /* find translated block using physical mappings */
P
Paul Brook 已提交
139
    phys_pc = get_page_addr_code(env, pc);
140 141 142 143 144 145 146 147
    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;
148
        if (tb->pc == pc &&
149
            tb->page_addr[0] == phys_page1 &&
150
            tb->cs_base == cs_base &&
151 152 153
            tb->flags == flags) {
            /* check next page if needed */
            if (tb->page_addr[1] != -1) {
154
                virt_page2 = (pc & TARGET_PAGE_MASK) +
155
                    TARGET_PAGE_SIZE;
P
Paul Brook 已提交
156
                phys_page2 = get_page_addr_code(env, virt_page2);
157 158 159 160 161 162 163 164 165
                if (tb->page_addr[1] == phys_page2)
                    goto found;
            } else {
                goto found;
            }
        }
        ptb1 = &tb->phys_hash_next;
    }
 not_found:
P
pbrook 已提交
166 167
   /* if no translated code available, then translate it now */
    tb = tb_gen_code(env, pc, cs_base, flags, 0);
168

169
 found:
170 171 172 173 174 175
    /* Move the last found TB to the head of the list */
    if (likely(*ptb1)) {
        *ptb1 = tb->phys_hash_next;
        tb->phys_hash_next = tb_phys_hash[h];
        tb_phys_hash[h] = tb;
    }
176 177 178 179 180 181 182 183 184
    /* 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;
185
    int flags;
186 187 188 189

    /* we record a subset of the CPU state. It will
       always be the same before a given translated block
       is executed. */
190
    cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
B
bellard 已提交
191
    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
192 193
    if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
                 tb->flags != flags)) {
194 195 196 197 198
        tb = tb_find_slow(pc, cs_base, flags);
    }
    return tb;
}

A
aliguori 已提交
199 200 201 202 203 204 205 206 207 208
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;
}

209 210 211 212 213
static void cpu_handle_debug_exception(CPUState *env)
{
    CPUWatchpoint *wp;

    if (!env->watchpoint_hit)
B
Blue Swirl 已提交
214
        QTAILQ_FOREACH(wp, &env->watchpoints, entry)
215
            wp->flags &= ~BP_WATCHPOINT_HIT;
A
aliguori 已提交
216 217 218

    if (debug_excp_handler)
        debug_excp_handler(env);
219 220
}

B
bellard 已提交
221 222
/* main execution loop */

223 224
volatile sig_atomic_t exit_request;

B
bellard 已提交
225
int cpu_exec(CPUState *env1)
B
bellard 已提交
226
{
227
    volatile host_reg_t saved_env_reg;
228 229
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
230
    uint8_t *tc_ptr;
P
pbrook 已提交
231
    unsigned long next_tb;
232

233 234
    if (cpu_halted(env1) == EXCP_HALTED)
        return EXCP_HALTED;
B
bellard 已提交
235

236
    cpu_single_env = env1;
B
bellard 已提交
237

P
Paolo Bonzini 已提交
238 239 240 241 242
    /* the access to env below is actually saving the global register's
       value, so that files not including target-xyz/exec.h are free to
       use it.  */
    QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
    saved_env_reg = (host_reg_t) env;
J
Jan Kiszka 已提交
243
    barrier();
B
bellard 已提交
244
    env = env1;
B
bellard 已提交
245

J
Jan Kiszka 已提交
246
    if (unlikely(exit_request)) {
247 248 249
        env->exit_request = 1;
    }

250
#if defined(TARGET_I386)
251 252 253 254 255 256 257
    if (!kvm_enabled()) {
        /* 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);
    }
258
#elif defined(TARGET_SPARC)
P
pbrook 已提交
259 260 261 262
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
263 264 265
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_PPC)
266
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
267
#elif defined(TARGET_MIPS)
B
bellard 已提交
268
#elif defined(TARGET_SH4)
269
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
270
#elif defined(TARGET_S390X)
B
bellard 已提交
271
    /* XXXXX */
B
bellard 已提交
272 273 274
#else
#error unsupported target CPU
#endif
275
    env->exception_index = -1;
276

B
bellard 已提交
277
    /* prepare setjmp context for exception handling */
278 279
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
280
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
B
blueswir1 已提交
281 282 283 284
#undef env
                    env = cpu_single_env;
#define env cpu_single_env
#endif
285 286 287 288 289
            /* 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;
290 291
                    if (ret == EXCP_DEBUG)
                        cpu_handle_debug_exception(env);
292
                    break;
A
aurel32 已提交
293 294
                } else {
#if defined(CONFIG_USER_ONLY)
295
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
296
                       which will be handled outside the cpu execution
297
                       loop */
B
bellard 已提交
298
#if defined(TARGET_I386)
299 300 301
                    do_interrupt_user(env->exception_index,
                                      env->exception_is_int,
                                      env->error_code,
302
                                      env->exception_next_eip);
303 304
                    /* successfully delivered */
                    env->old_exception = -1;
B
bellard 已提交
305
#endif
306 307
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
308
#else
B
bellard 已提交
309
#if defined(TARGET_I386)
310 311 312
                    /* simulate a real cpu exception. On i386, it can
                       trigger new exceptions, but we do not handle
                       double or triple faults yet. */
313 314 315
                    do_interrupt(env->exception_index,
                                 env->exception_is_int,
                                 env->error_code,
B
bellard 已提交
316
                                 env->exception_next_eip, 0);
317 318
                    /* successfully delivered */
                    env->old_exception = -1;
319 320
#elif defined(TARGET_PPC)
                    do_interrupt(env);
321 322
#elif defined(TARGET_MICROBLAZE)
                    do_interrupt(env);
B
bellard 已提交
323 324
#elif defined(TARGET_MIPS)
                    do_interrupt(env);
325
#elif defined(TARGET_SPARC)
326
                    do_interrupt(env);
B
bellard 已提交
327 328
#elif defined(TARGET_ARM)
                    do_interrupt(env);
B
bellard 已提交
329 330
#elif defined(TARGET_SH4)
		    do_interrupt(env);
J
j_mayer 已提交
331 332
#elif defined(TARGET_ALPHA)
                    do_interrupt(env);
333 334
#elif defined(TARGET_CRIS)
                    do_interrupt(env);
P
pbrook 已提交
335 336
#elif defined(TARGET_M68K)
                    do_interrupt(0);
A
aurel32 已提交
337
#endif
338
                    env->exception_index = -1;
B
bellard 已提交
339
#endif
340
                }
341
            }
B
bellard 已提交
342

A
aliguori 已提交
343
            if (kvm_enabled()) {
A
aliguori 已提交
344 345
                kvm_cpu_exec(env);
                longjmp(env->jmp_env, 1);
A
aliguori 已提交
346 347
            }

348
            next_tb = 0; /* force lookup of first TB */
349
            for(;;) {
B
bellard 已提交
350
                interrupt_request = env->interrupt_request;
M
malc 已提交
351 352 353 354 355 356 357 358
                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);
                    }
359 360 361 362 363
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                        env->exception_index = EXCP_DEBUG;
                        cpu_loop_exit();
                    }
364
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
365 366
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
    defined(TARGET_MICROBLAZE)
367 368 369 370 371 372 373
                    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 已提交
374
#if defined(TARGET_I386)
375 376 377 378 379 380 381 382
                    if (interrupt_request & CPU_INTERRUPT_INIT) {
                            svm_check_intercept(SVM_EXIT_INIT);
                            do_cpu_init(env);
                            env->exception_index = EXCP_HALTED;
                            cpu_loop_exit();
                    } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
                            do_cpu_sipi(env);
                    } else if (env->hflags2 & HF2_GIF_MASK) {
383 384 385 386 387 388 389 390 391 392 393 394
                        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;
395 396 397 398
			} else if (interrupt_request & CPU_INTERRUPT_MCE) {
                            env->interrupt_request &= ~CPU_INTERRUPT_MCE;
                            do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
                            next_tb = 0;
399 400 401 402 403 404 405 406 407 408
                        } 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);
409
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
410
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
B
blueswir1 已提交
411 412 413 414
#undef env
                    env = cpu_single_env;
#define env cpu_single_env
#endif
415 416 417 418
                            do_interrupt(intno, 0, 0, 0, 1);
                            /* ensure that no TB jump will be modified as
                               the program flow was changed */
                            next_tb = 0;
T
ths 已提交
419
#if !defined(CONFIG_USER_ONLY)
420 421 422 423 424 425 426
                        } 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);
                            intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
427
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
428
                            do_interrupt(intno, 0, 0, 0, 1);
429
                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
430
                            next_tb = 0;
B
bellard 已提交
431
#endif
432
                        }
B
bellard 已提交
433
                    }
434
#elif defined(TARGET_PPC)
435 436
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
437
                        cpu_reset(env);
438 439
                    }
#endif
440
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
441 442 443
                        ppc_hw_interrupt(env);
                        if (env->pending_interrupts == 0)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
444
                        next_tb = 0;
445
                    }
446 447 448 449 450 451 452 453 454
#elif defined(TARGET_MICROBLAZE)
                    if ((interrupt_request & CPU_INTERRUPT_HARD)
                        && (env->sregs[SR_MSR] & MSR_IE)
                        && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
                        && !(env->iflags & (D_FLAG | IMM_FLAG))) {
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
                        next_tb = 0;
                    }
B
bellard 已提交
455 456
#elif defined(TARGET_MIPS)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
457
                        cpu_mips_hw_interrupts_pending(env) &&
B
bellard 已提交
458
                        (env->CP0_Status & (1 << CP0St_IE)) &&
T
ths 已提交
459 460
                        !(env->CP0_Status & (1 << CP0St_EXL)) &&
                        !(env->CP0_Status & (1 << CP0St_ERL)) &&
B
bellard 已提交
461 462 463 464 465
                        !(env->hflags & MIPS_HFLAG_DM)) {
                        /* Raise it */
                        env->exception_index = EXCP_EXT_INTERRUPT;
                        env->error_code = 0;
                        do_interrupt(env);
466
                        next_tb = 0;
B
bellard 已提交
467
                    }
468
#elif defined(TARGET_SPARC)
469 470 471 472 473 474 475 476 477 478 479 480 481 482
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        if (cpu_interrupts_enabled(env) &&
                            env->interrupt_index > 0) {
                            int pil = env->interrupt_index & 0xf;
                            int type = env->interrupt_index & 0xf0;

                            if (((type == TT_EXTINT) &&
                                  cpu_pil_allowed(env, pil)) ||
                                  type != TT_EXTINT) {
                                env->exception_index = env->interrupt_index;
                                do_interrupt(env);
                                next_tb = 0;
                            }
                        }
483 484 485
		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
			//do_interrupt(0, 0, 0, 0, 0);
			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
486
		    }
B
bellard 已提交
487 488 489 490 491
#elif defined(TARGET_ARM)
                    if (interrupt_request & CPU_INTERRUPT_FIQ
                        && !(env->uncached_cpsr & CPSR_F)) {
                        env->exception_index = EXCP_FIQ;
                        do_interrupt(env);
492
                        next_tb = 0;
B
bellard 已提交
493
                    }
P
pbrook 已提交
494 495 496 497 498 499 500 501 502
                    /* 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 已提交
503
                    if (interrupt_request & CPU_INTERRUPT_HARD
P
pbrook 已提交
504 505
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                            || !(env->uncached_cpsr & CPSR_I))) {
B
bellard 已提交
506 507
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
508
                        next_tb = 0;
B
bellard 已提交
509
                    }
B
bellard 已提交
510
#elif defined(TARGET_SH4)
511 512
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
513
                        next_tb = 0;
514
                    }
J
j_mayer 已提交
515 516 517
#elif defined(TARGET_ALPHA)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
518
                        next_tb = 0;
J
j_mayer 已提交
519
                    }
520
#elif defined(TARGET_CRIS)
E
edgar_igl 已提交
521
                    if (interrupt_request & CPU_INTERRUPT_HARD
E
Edgar E. Iglesias 已提交
522 523
                        && (env->pregs[PR_CCS] & I_FLAG)
                        && !env->locked_irq) {
E
edgar_igl 已提交
524 525 526 527 528 529 530
                        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;
531
                        do_interrupt(env);
532
                        next_tb = 0;
533
                    }
P
pbrook 已提交
534 535 536 537 538 539 540 541 542 543 544
#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);
545
                        next_tb = 0;
P
pbrook 已提交
546
                    }
B
bellard 已提交
547
#endif
B
bellard 已提交
548 549
                   /* Don't use the cached interupt_request value,
                      do_interrupt may have updated the EXITTB flag. */
B
bellard 已提交
550
                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
551 552 553
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
554
                        next_tb = 0;
555
                    }
556 557 558 559 560
                }
                if (unlikely(env->exit_request)) {
                    env->exit_request = 0;
                    env->exception_index = EXCP_INTERRUPT;
                    cpu_loop_exit();
561
                }
562
#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
563
                if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
564
                    /* restore flags in standard format */
565
#if defined(TARGET_I386)
P
pbrook 已提交
566
                    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
567
                    log_cpu_state(env, X86_DUMP_CCOP);
568
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
P
pbrook 已提交
569 570 571 572 573
#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);
574
                    log_cpu_state(env, 0);
B
bellard 已提交
575
#else
576
                    log_cpu_state(env, 0);
B
bellard 已提交
577
#endif
578
                }
579
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
P
pbrook 已提交
580
                spin_lock(&tb_lock);
581
                tb = tb_find_fast();
P
pbrook 已提交
582 583 584 585 586 587 588
                /* 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;
P
pbrook 已提交
589
                    tb_invalidated_flag = 0;
P
pbrook 已提交
590
                }
591
#ifdef CONFIG_DEBUG_EXEC
592 593 594
                qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                             (long)tb->tc_ptr, tb->pc,
                             lookup_symbol(tb->pc));
595
#endif
596 597 598
                /* see if we can patch the calling TB. When the TB
                   spans two pages, we cannot safely do a direct
                   jump. */
P
Paolo Bonzini 已提交
599
                if (next_tb != 0 && tb->page_addr[1] == -1) {
600
                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
601
                }
P
pbrook 已提交
602
                spin_unlock(&tb_lock);
603 604 605 606 607

                /* 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. */
J
Jan Kiszka 已提交
608 609 610
                env->current_tb = tb;
                barrier();
                if (likely(!env->exit_request)) {
P
pbrook 已提交
611
                    tc_ptr = tb->tc_ptr;
612
                /* execute the generated code */
613
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
614
#undef env
P
pbrook 已提交
615
                    env = cpu_single_env;
616 617
#define env cpu_single_env
#endif
P
pbrook 已提交
618 619
                    next_tb = tcg_qemu_tb_exec(tc_ptr);
                    if ((next_tb & 3) == 2) {
T
ths 已提交
620
                        /* Instruction counter expired.  */
P
pbrook 已提交
621 622 623
                        int insns_left;
                        tb = (TranslationBlock *)(long)(next_tb & ~3);
                        /* Restore PC.  */
624
                        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
                        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();
                        }
                    }
                }
J
Jan Kiszka 已提交
647
                env->current_tb = NULL;
B
bellard 已提交
648 649
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
650
            } /* for(;;) */
B
bellard 已提交
651
        }
652 653
    } /* for(;;) */

B
bellard 已提交
654

B
bellard 已提交
655
#if defined(TARGET_I386)
B
bellard 已提交
656
    /* restore flags in standard format */
P
pbrook 已提交
657
    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
B
bellard 已提交
658
#elif defined(TARGET_ARM)
B
bellard 已提交
659
    /* XXX: Save/restore host fpu exception state?.  */
660
#elif defined(TARGET_SPARC)
661
#elif defined(TARGET_PPC)
P
pbrook 已提交
662 663 664 665 666
#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);
667
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
668
#elif defined(TARGET_MIPS)
B
bellard 已提交
669
#elif defined(TARGET_SH4)
J
j_mayer 已提交
670
#elif defined(TARGET_ALPHA)
671
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
672
#elif defined(TARGET_S390X)
B
bellard 已提交
673
    /* XXXXX */
B
bellard 已提交
674 675 676
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
677 678

    /* restore global registers */
J
Jan Kiszka 已提交
679
    barrier();
P
Paolo Bonzini 已提交
680
    env = (void *) saved_env_reg;
P
pbrook 已提交
681

B
bellard 已提交
682
    /* fail safe : never use cpu_single_env outside cpu_exec() */
683
    cpu_single_env = NULL;
B
bellard 已提交
684 685
    return ret;
}
B
bellard 已提交
686

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

B
bellard 已提交
700
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
701

B
bellard 已提交
702 703 704 705 706 707
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
B
bellard 已提交
708
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
B
bellard 已提交
709
        selector &= 0xffff;
710
        cpu_x86_load_seg_cache(env, seg_reg, selector,
B
bellard 已提交
711
                               (selector << 4), 0xffff, 0);
B
bellard 已提交
712
    } else {
B
bellard 已提交
713
        helper_load_seg(seg_reg, selector);
B
bellard 已提交
714
    }
B
bellard 已提交
715 716
    env = saved_env;
}
B
bellard 已提交
717

718
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
719 720 721 722 723
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
724

725
    helper_fsave(ptr, data32);
726 727 728 729

    env = saved_env;
}

730
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
731 732 733 734 735
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
736

737
    helper_frstor(ptr, data32);
738 739 740 741

    env = saved_env;
}

B
bellard 已提交
742 743
#endif /* TARGET_I386 */

B
bellard 已提交
744 745
#if !defined(CONFIG_SOFTMMU)

746
#if defined(TARGET_I386)
747 748 749 750
#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
#else
#define EXCEPTION_ACTION cpu_loop_exit()
#endif
751

752
/* 'pc' is the host PC at which the exception was raised. 'address' is
B
bellard 已提交
753 754 755
   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 已提交
756
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
757
                                    int is_write, sigset_t *old_set,
758
                                    void *puc)
B
bellard 已提交
759
{
B
bellard 已提交
760 761
    TranslationBlock *tb;
    int ret;
B
bellard 已提交
762

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

774
    /* see if it is an MMU fault */
775
    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
    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);
791
    EXCEPTION_ACTION;
P
pbrook 已提交
792 793

    /* never comes here */
794 795
    return 1;
}
B
bellard 已提交
796

B
bellard 已提交
797 798
#if defined(__i386__)

799 800 801 802 803 804
#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)
805
# define MASK_sig(context)    ((context)->uc_sigmask)
J
Juergen Lock 已提交
806 807 808 809 810 811 812 813 814 815 816 817 818 819
#elif defined (__NetBSD__)
# include <ucontext.h>

# 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])
# define MASK_sig(context)    ((context)->uc_sigmask)
#elif defined (__FreeBSD__) || defined(__DragonFly__)
# include <ucontext.h>

# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
# define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
# define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
# define MASK_sig(context)    ((context)->uc_sigmask)
820 821 822 823 824
#elif defined(__OpenBSD__)
# define EIP_sig(context)     ((context)->sc_eip)
# define TRAP_sig(context)    ((context)->sc_trapno)
# define ERROR_sig(context)   ((context)->sc_err)
# define MASK_sig(context)    ((context)->sc_mask)
825 826 827 828
#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])
829
# define MASK_sig(context)    ((context)->uc_sigmask)
830 831
#endif

832
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
833
                       void *puc)
B
bellard 已提交
834
{
835
    siginfo_t *info = pinfo;
J
Juergen Lock 已提交
836 837 838
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
    ucontext_t *uc = puc;
#elif defined(__OpenBSD__)
839 840
    struct sigcontext *uc = puc;
#else
B
bellard 已提交
841
    struct ucontext *uc = puc;
842
#endif
B
bellard 已提交
843
    unsigned long pc;
844
    int trapno;
B
bellard 已提交
845

846 847
#ifndef REG_EIP
/* for glibc 2.1 */
B
bellard 已提交
848 849 850
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
851
#endif
852 853
    pc = EIP_sig(uc);
    trapno = TRAP_sig(uc);
B
bellard 已提交
854 855 856
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             trapno == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
857
                             &MASK_sig(uc), puc);
B
bellard 已提交
858 859
}

860 861
#elif defined(__x86_64__)

862
#ifdef __NetBSD__
863 864 865 866 867 868 869 870 871
#define PC_sig(context)       _UC_MACHINE_PC(context)
#define TRAP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
#define ERROR_sig(context)    ((context)->uc_mcontext.__gregs[_REG_ERR])
#define MASK_sig(context)     ((context)->uc_sigmask)
#elif defined(__OpenBSD__)
#define PC_sig(context)       ((context)->sc_rip)
#define TRAP_sig(context)     ((context)->sc_trapno)
#define ERROR_sig(context)    ((context)->sc_err)
#define MASK_sig(context)     ((context)->sc_mask)
J
Juergen Lock 已提交
872 873 874 875 876 877 878
#elif defined (__FreeBSD__) || defined(__DragonFly__)
#include <ucontext.h>

#define PC_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
#define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
#define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
#define MASK_sig(context)     ((context)->uc_sigmask)
879
#else
880 881 882 883
#define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
#define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
#define ERROR_sig(context)    ((context)->uc_mcontext.gregs[REG_ERR])
#define MASK_sig(context)     ((context)->uc_sigmask)
884 885
#endif

886
int cpu_signal_handler(int host_signum, void *pinfo,
887 888
                       void *puc)
{
889
    siginfo_t *info = pinfo;
890
    unsigned long pc;
J
Juergen Lock 已提交
891
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
892
    ucontext_t *uc = puc;
893 894
#elif defined(__OpenBSD__)
    struct sigcontext *uc = puc;
895 896 897
#else
    struct ucontext *uc = puc;
#endif
898

899
    pc = PC_sig(uc);
900
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
901 902 903
                             TRAP_sig(uc) == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
                             &MASK_sig(uc), puc);
904 905
}

M
malc 已提交
906
#elif defined(_ARCH_PPC)
B
bellard 已提交
907

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
/***********************************************************************
 * 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 */

932 933 934 935 936 937 938 939 940 941 942 943 944 945
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <ucontext.h>
# define IAR_sig(context)		((context)->uc_mcontext.mc_srr0)
# define MSR_sig(context)		((context)->uc_mcontext.mc_srr1)
# define CTR_sig(context)		((context)->uc_mcontext.mc_ctr)
# define XER_sig(context)		((context)->uc_mcontext.mc_xer)
# define LR_sig(context)		((context)->uc_mcontext.mc_lr)
# define CR_sig(context)		((context)->uc_mcontext.mc_cr)
/* Exception Registers access */
# define DAR_sig(context)		((context)->uc_mcontext.mc_dar)
# define DSISR_sig(context)		((context)->uc_mcontext.mc_dsisr)
# define TRAP_sig(context)		((context)->uc_mcontext.mc_exc)
#endif /* __FreeBSD__|| __FreeBSD_kernel__ */

946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
#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__ */

971
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
972
                       void *puc)
B
bellard 已提交
973
{
974
    siginfo_t *info = pinfo;
975 976 977
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    ucontext_t *uc = puc;
#else
978
    struct ucontext *uc = puc;
979
#endif
980 981 982
    unsigned long pc;
    int is_write;

983
    pc = IAR_sig(uc);
984 985 986
    is_write = 0;
#if 0
    /* ppc 4xx case */
987
    if (DSISR_sig(uc) & 0x00800000)
988 989
        is_write = 1;
#else
990
    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
991 992
        is_write = 1;
#endif
993
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
994
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
995 996
}

B
bellard 已提交
997 998
#elif defined(__alpha__)

999
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1000 1001
                           void *puc)
{
1002
    siginfo_t *info = pinfo;
B
bellard 已提交
1003 1004 1005 1006 1007
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

1008
    /* XXX: need kernel patch to get write flag faster */
B
bellard 已提交
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
    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;
    }

1024
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1025
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1026
}
1027 1028
#elif defined(__sparc__)

1029
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1030
                       void *puc)
1031
{
1032
    siginfo_t *info = pinfo;
1033 1034
    int is_write;
    uint32_t insn;
1035
#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
B
blueswir1 已提交
1036 1037
    uint32_t *regs = (uint32_t *)(info + 1);
    void *sigmask = (regs + 20);
1038
    /* XXX: is there a standard glibc define ? */
B
blueswir1 已提交
1039 1040
    unsigned long pc = regs[1];
#else
B
blueswir1 已提交
1041
#ifdef __linux__
B
blueswir1 已提交
1042 1043 1044
    struct sigcontext *sc = puc;
    unsigned long pc = sc->sigc_regs.tpc;
    void *sigmask = (void *)sc->sigc_mask;
B
blueswir1 已提交
1045 1046 1047 1048 1049
#elif defined(__OpenBSD__)
    struct sigcontext *uc = puc;
    unsigned long pc = uc->sc_pc;
    void *sigmask = (void *)(long)uc->sc_mask;
#endif
B
blueswir1 已提交
1050 1051
#endif

1052 1053 1054 1055 1056 1057
    /* 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
1058
      case 0x15: // stba
1059
      case 0x06: // sth
1060
      case 0x16: // stha
1061
      case 0x04: // st
1062
      case 0x14: // sta
1063
      case 0x07: // std
1064 1065 1066
      case 0x17: // stda
      case 0x0e: // stx
      case 0x1e: // stxa
1067
      case 0x24: // stf
1068
      case 0x34: // stfa
1069
      case 0x27: // stdf
1070 1071 1072
      case 0x37: // stdfa
      case 0x26: // stqf
      case 0x36: // stqfa
1073
      case 0x25: // stfsr
1074 1075
      case 0x3c: // casa
      case 0x3e: // casxa
1076 1077 1078 1079
	is_write = 1;
	break;
      }
    }
1080
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1081
                             is_write, sigmask, NULL);
1082 1083 1084 1085
}

#elif defined(__arm__)

1086
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1087
                       void *puc)
1088
{
1089
    siginfo_t *info = pinfo;
1090 1091 1092
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1093

1094
#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1095 1096
    pc = uc->uc_mcontext.gregs[R15];
#else
1097
    pc = uc->uc_mcontext.arm_pc;
1098
#endif
1099 1100
    /* XXX: compute is_write */
    is_write = 0;
1101
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1102
                             is_write,
P
pbrook 已提交
1103
                             &uc->uc_sigmask, puc);
1104 1105
}

B
bellard 已提交
1106 1107
#elif defined(__mc68000)

1108
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1109 1110
                       void *puc)
{
1111
    siginfo_t *info = pinfo;
B
bellard 已提交
1112 1113 1114
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1115

B
bellard 已提交
1116 1117 1118
    pc = uc->uc_mcontext.gregs[16];
    /* XXX: compute is_write */
    is_write = 0;
1119
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
B
bellard 已提交
1120
                             is_write,
1121
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1122 1123
}

B
bellard 已提交
1124 1125 1126 1127 1128 1129 1130
#elif defined(__ia64)

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

1131
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
B
bellard 已提交
1132
{
1133
    siginfo_t *info = pinfo;
B
bellard 已提交
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
    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 已提交
1145
	  if (info->si_code && (info->si_segvflags & __ISR_VALID))
B
bellard 已提交
1146 1147 1148 1149 1150 1151 1152 1153 1154
	      /* 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,
1155
                             (sigset_t *)&uc->uc_sigmask, puc);
B
bellard 已提交
1156 1157
}

B
bellard 已提交
1158 1159
#elif defined(__s390__)

1160
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1161 1162
                       void *puc)
{
1163
    siginfo_t *info = pinfo;
B
bellard 已提交
1164 1165
    struct ucontext *uc = puc;
    unsigned long pc;
1166 1167
    uint16_t *pinsn;
    int is_write = 0;
1168

B
bellard 已提交
1169
    pc = uc->uc_mcontext.psw.addr;
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206

    /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
       of the normal 2 arguments.  The 3rd argument contains the "int_code"
       from the hardware which does in fact contain the is_write value.
       The rt signal handler, as far as I can tell, does not give this value
       at all.  Not that we could get to it from here even if it were.  */
    /* ??? This is not even close to complete, since it ignores all
       of the read-modify-write instructions.  */
    pinsn = (uint16_t *)pc;
    switch (pinsn[0] >> 8) {
    case 0x50: /* ST */
    case 0x42: /* STC */
    case 0x40: /* STH */
        is_write = 1;
        break;
    case 0xc4: /* RIL format insns */
        switch (pinsn[0] & 0xf) {
        case 0xf: /* STRL */
        case 0xb: /* STGRL */
        case 0x7: /* STHRL */
            is_write = 1;
        }
        break;
    case 0xe3: /* RXY format insns */
        switch (pinsn[2] & 0xff) {
        case 0x50: /* STY */
        case 0x24: /* STG */
        case 0x72: /* STCY */
        case 0x70: /* STHY */
        case 0x8e: /* STPQ */
        case 0x3f: /* STRVH */
        case 0x3e: /* STRV */
        case 0x2f: /* STRVG */
            is_write = 1;
        }
        break;
    }
1207
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1208 1209 1210 1211 1212
                             is_write, &uc->uc_sigmask, puc);
}

#elif defined(__mips__)

1213
int cpu_signal_handler(int host_signum, void *pinfo,
1214 1215
                       void *puc)
{
T
ths 已提交
1216
    siginfo_t *info = pinfo;
1217 1218 1219
    struct ucontext *uc = puc;
    greg_t pc = uc->uc_mcontext.pc;
    int is_write;
1220

1221 1222
    /* XXX: compute is_write */
    is_write = 0;
1223
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1224
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1225 1226
}

A
aurel32 已提交
1227 1228 1229 1230 1231 1232 1233
#elif defined(__hppa__)

int cpu_signal_handler(int host_signum, void *pinfo,
                       void *puc)
{
    struct siginfo *info = pinfo;
    struct ucontext *uc = puc;
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
    unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
    uint32_t insn = *(uint32_t *)pc;
    int is_write = 0;

    /* XXX: need kernel patch to get write flag faster.  */
    switch (insn >> 26) {
    case 0x1a: /* STW */
    case 0x19: /* STH */
    case 0x18: /* STB */
    case 0x1b: /* STWM */
        is_write = 1;
        break;

    case 0x09: /* CSTWX, FSTWX, FSTWS */
    case 0x0b: /* CSTDX, FSTDX, FSTDS */
        /* Distinguish from coprocessor load ... */
        is_write = (insn >> 9) & 1;
        break;

    case 0x03:
        switch ((insn >> 6) & 15) {
        case 0xa: /* STWS */
        case 0x9: /* STHS */
        case 0x8: /* STBS */
        case 0xe: /* STWAS */
        case 0xc: /* STBYS */
            is_write = 1;
        }
        break;
    }
A
aurel32 已提交
1264 1265

    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1266
                             is_write, &uc->uc_sigmask, puc);
A
aurel32 已提交
1267 1268
}

B
bellard 已提交
1269
#else
B
bellard 已提交
1270

1271
#error host CPU specific signal handler needed
B
bellard 已提交
1272

B
bellard 已提交
1273
#endif
B
bellard 已提交
1274 1275

#endif /* !defined(CONFIG_SOFTMMU) */