cpu-exec.c 43.1 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;
}

B
bellard 已提交
199 200
/* main execution loop */

201 202
volatile sig_atomic_t exit_request;

B
bellard 已提交
203
int cpu_exec(CPUState *env1)
B
bellard 已提交
204
{
205
    volatile host_reg_t saved_env_reg;
206 207
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
208
    uint8_t *tc_ptr;
P
pbrook 已提交
209
    unsigned long next_tb;
210

211 212
    if (cpu_halted(env1) == EXCP_HALTED)
        return EXCP_HALTED;
B
bellard 已提交
213

214
    cpu_single_env = env1;
B
bellard 已提交
215

P
Paolo Bonzini 已提交
216 217 218 219 220
    /* 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 已提交
221
    barrier();
B
bellard 已提交
222
    env = env1;
B
bellard 已提交
223

J
Jan Kiszka 已提交
224
    if (unlikely(exit_request)) {
225 226 227
        env->exit_request = 1;
    }

228
#if defined(TARGET_I386)
229 230 231 232 233 234 235
    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);
    }
236
#elif defined(TARGET_SPARC)
P
pbrook 已提交
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)
244
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
245
#elif defined(TARGET_MIPS)
B
bellard 已提交
246
#elif defined(TARGET_SH4)
247
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
248
#elif defined(TARGET_S390X)
B
bellard 已提交
249
    /* XXXXX */
B
bellard 已提交
250 251 252
#else
#error unsupported target CPU
#endif
253
    env->exception_index = -1;
254

B
bellard 已提交
255
    /* prepare setjmp context for exception handling */
256 257
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
258
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
B
blueswir1 已提交
259 260 261 262
#undef env
                    env = cpu_single_env;
#define env cpu_single_env
#endif
263 264 265 266 267 268
            /* if an exception is pending, we execute it here */
            if (env->exception_index >= 0) {
                if (env->exception_index >= EXCP_INTERRUPT) {
                    /* exit request from the cpu execution loop */
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
269 270
                } else {
#if defined(CONFIG_USER_ONLY)
271
                    /* if user mode only, we simulate a fake exception
T
ths 已提交
272
                       which will be handled outside the cpu execution
273
                       loop */
B
bellard 已提交
274
#if defined(TARGET_I386)
275 276 277
                    do_interrupt_user(env->exception_index,
                                      env->exception_is_int,
                                      env->error_code,
278
                                      env->exception_next_eip);
279 280
                    /* successfully delivered */
                    env->old_exception = -1;
B
bellard 已提交
281
#endif
282 283
                    ret = env->exception_index;
                    break;
A
aurel32 已提交
284
#else
B
bellard 已提交
285
#if defined(TARGET_I386)
286 287 288
                    /* simulate a real cpu exception. On i386, it can
                       trigger new exceptions, but we do not handle
                       double or triple faults yet. */
289 290 291
                    do_interrupt(env->exception_index,
                                 env->exception_is_int,
                                 env->error_code,
B
bellard 已提交
292
                                 env->exception_next_eip, 0);
293 294
                    /* successfully delivered */
                    env->old_exception = -1;
295 296
#elif defined(TARGET_PPC)
                    do_interrupt(env);
297 298
#elif defined(TARGET_MICROBLAZE)
                    do_interrupt(env);
B
bellard 已提交
299 300
#elif defined(TARGET_MIPS)
                    do_interrupt(env);
301
#elif defined(TARGET_SPARC)
302
                    do_interrupt(env);
B
bellard 已提交
303 304
#elif defined(TARGET_ARM)
                    do_interrupt(env);
B
bellard 已提交
305 306
#elif defined(TARGET_SH4)
		    do_interrupt(env);
J
j_mayer 已提交
307 308
#elif defined(TARGET_ALPHA)
                    do_interrupt(env);
309 310
#elif defined(TARGET_CRIS)
                    do_interrupt(env);
P
pbrook 已提交
311 312
#elif defined(TARGET_M68K)
                    do_interrupt(0);
A
aurel32 已提交
313
#endif
314
                    env->exception_index = -1;
B
bellard 已提交
315
#endif
316
                }
317
            }
B
bellard 已提交
318

A
aliguori 已提交
319
            if (kvm_enabled()) {
A
aliguori 已提交
320 321
                kvm_cpu_exec(env);
                longjmp(env->jmp_env, 1);
A
aliguori 已提交
322 323
            }

324
            next_tb = 0; /* force lookup of first TB */
325
            for(;;) {
B
bellard 已提交
326
                interrupt_request = env->interrupt_request;
M
malc 已提交
327 328 329 330 331 332 333 334
                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);
                    }
335 336 337 338 339
                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
                        env->exception_index = EXCP_DEBUG;
                        cpu_loop_exit();
                    }
340
#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
341 342
    defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
    defined(TARGET_MICROBLAZE)
343 344 345 346 347 348 349
                    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 已提交
350
#if defined(TARGET_I386)
351 352 353 354 355 356 357 358
                    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) {
359 360 361 362 363 364 365 366 367 368 369 370
                        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;
371 372 373 374
			} else if (interrupt_request & CPU_INTERRUPT_MCE) {
                            env->interrupt_request &= ~CPU_INTERRUPT_MCE;
                            do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
                            next_tb = 0;
375 376 377 378 379 380 381 382 383 384
                        } 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);
385
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
386
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
B
blueswir1 已提交
387 388 389 390
#undef env
                    env = cpu_single_env;
#define env cpu_single_env
#endif
391 392 393 394
                            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 已提交
395
#if !defined(CONFIG_USER_ONLY)
396 397 398 399 400 401 402
                        } 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));
403
                            qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
404
                            do_interrupt(intno, 0, 0, 0, 1);
405
                            env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
406
                            next_tb = 0;
B
bellard 已提交
407
#endif
408
                        }
B
bellard 已提交
409
                    }
410
#elif defined(TARGET_PPC)
411 412
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
413
                        cpu_reset(env);
414 415
                    }
#endif
416
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
417 418 419
                        ppc_hw_interrupt(env);
                        if (env->pending_interrupts == 0)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
420
                        next_tb = 0;
421
                    }
422 423 424 425 426 427 428 429 430
#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 已提交
431 432
#elif defined(TARGET_MIPS)
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
433
                        cpu_mips_hw_interrupts_pending(env)) {
B
bellard 已提交
434 435 436 437
                        /* Raise it */
                        env->exception_index = EXCP_EXT_INTERRUPT;
                        env->error_code = 0;
                        do_interrupt(env);
438
                        next_tb = 0;
B
bellard 已提交
439
                    }
440
#elif defined(TARGET_SPARC)
441 442 443 444 445 446 447 448 449 450 451 452 453 454
                    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;
                            }
                        }
455 456 457
		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
			//do_interrupt(0, 0, 0, 0, 0);
			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
458
		    }
B
bellard 已提交
459 460 461 462 463
#elif defined(TARGET_ARM)
                    if (interrupt_request & CPU_INTERRUPT_FIQ
                        && !(env->uncached_cpsr & CPSR_F)) {
                        env->exception_index = EXCP_FIQ;
                        do_interrupt(env);
464
                        next_tb = 0;
B
bellard 已提交
465
                    }
P
pbrook 已提交
466 467 468 469 470 471 472 473 474
                    /* 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 已提交
475
                    if (interrupt_request & CPU_INTERRUPT_HARD
P
pbrook 已提交
476 477
                        && ((IS_M(env) && env->regs[15] < 0xfffffff0)
                            || !(env->uncached_cpsr & CPSR_I))) {
B
bellard 已提交
478 479
                        env->exception_index = EXCP_IRQ;
                        do_interrupt(env);
480
                        next_tb = 0;
B
bellard 已提交
481
                    }
B
bellard 已提交
482
#elif defined(TARGET_SH4)
483 484
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
485
                        next_tb = 0;
486
                    }
J
j_mayer 已提交
487 488 489
#elif defined(TARGET_ALPHA)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
                        do_interrupt(env);
490
                        next_tb = 0;
J
j_mayer 已提交
491
                    }
492
#elif defined(TARGET_CRIS)
E
edgar_igl 已提交
493
                    if (interrupt_request & CPU_INTERRUPT_HARD
E
Edgar E. Iglesias 已提交
494 495
                        && (env->pregs[PR_CCS] & I_FLAG)
                        && !env->locked_irq) {
E
edgar_igl 已提交
496 497 498 499 500 501 502
                        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
                    }
P
pbrook 已提交
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;
P
pbrook 已提交
518
                    }
B
bellard 已提交
519
#endif
B
bellard 已提交
520 521
                   /* Don't use the cached interupt_request value,
                      do_interrupt may have updated the EXITTB flag. */
B
bellard 已提交
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
                    }
528 529 530 531 532
                }
                if (unlikely(env->exit_request)) {
                    env->exit_request = 0;
                    env->exception_index = EXCP_INTERRUPT;
                    cpu_loop_exit();
533
                }
534
#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
535
                if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
536
                    /* restore flags in standard format */
537
#if defined(TARGET_I386)
P
pbrook 已提交
538
                    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
539
                    log_cpu_state(env, X86_DUMP_CCOP);
540
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
P
pbrook 已提交
541 542 543 544 545
#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);
546
                    log_cpu_state(env, 0);
B
bellard 已提交
547
#else
548
                    log_cpu_state(env, 0);
B
bellard 已提交
549
#endif
550
                }
551
#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
P
pbrook 已提交
552
                spin_lock(&tb_lock);
553
                tb = tb_find_fast();
P
pbrook 已提交
554 555 556 557 558 559 560
                /* 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 已提交
561
                    tb_invalidated_flag = 0;
P
pbrook 已提交
562
                }
563
#ifdef CONFIG_DEBUG_EXEC
564 565 566
                qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                             (long)tb->tc_ptr, tb->pc,
                             lookup_symbol(tb->pc));
567
#endif
568 569 570
                /* see if we can patch the calling TB. When the TB
                   spans two pages, we cannot safely do a direct
                   jump. */
P
Paolo Bonzini 已提交
571
                if (next_tb != 0 && tb->page_addr[1] == -1) {
572
                    tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
573
                }
P
pbrook 已提交
574
                spin_unlock(&tb_lock);
575 576 577 578 579

                /* 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 已提交
580 581 582
                env->current_tb = tb;
                barrier();
                if (likely(!env->exit_request)) {
P
pbrook 已提交
583
                    tc_ptr = tb->tc_ptr;
584
                /* execute the generated code */
585
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
586
#undef env
P
pbrook 已提交
587
                    env = cpu_single_env;
588 589
#define env cpu_single_env
#endif
P
pbrook 已提交
590 591
                    next_tb = tcg_qemu_tb_exec(tc_ptr);
                    if ((next_tb & 3) == 2) {
T
ths 已提交
592
                        /* Instruction counter expired.  */
P
pbrook 已提交
593 594 595
                        int insns_left;
                        tb = (TranslationBlock *)(long)(next_tb & ~3);
                        /* Restore PC.  */
596
                        cpu_pc_from_tb(env, tb);
P
pbrook 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
                        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 已提交
619
                env->current_tb = NULL;
B
bellard 已提交
620 621
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
T
ths 已提交
622
            } /* for(;;) */
B
bellard 已提交
623
        }
624 625
    } /* for(;;) */

B
bellard 已提交
626

B
bellard 已提交
627
#if defined(TARGET_I386)
B
bellard 已提交
628
    /* restore flags in standard format */
P
pbrook 已提交
629
    env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
B
bellard 已提交
630
#elif defined(TARGET_ARM)
B
bellard 已提交
631
    /* XXX: Save/restore host fpu exception state?.  */
632
#elif defined(TARGET_SPARC)
633
#elif defined(TARGET_PPC)
P
pbrook 已提交
634 635 636 637 638
#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);
639
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
640
#elif defined(TARGET_MIPS)
B
bellard 已提交
641
#elif defined(TARGET_SH4)
J
j_mayer 已提交
642
#elif defined(TARGET_ALPHA)
643
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
644
#elif defined(TARGET_S390X)
B
bellard 已提交
645
    /* XXXXX */
B
bellard 已提交
646 647 648
#else
#error unsupported target CPU
#endif
P
pbrook 已提交
649 650

    /* restore global registers */
J
Jan Kiszka 已提交
651
    barrier();
P
Paolo Bonzini 已提交
652
    env = (void *) saved_env_reg;
P
pbrook 已提交
653

B
bellard 已提交
654
    /* fail safe : never use cpu_single_env outside cpu_exec() */
655
    cpu_single_env = NULL;
B
bellard 已提交
656 657
    return ret;
}
B
bellard 已提交
658

659 660 661 662
/* 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)
{
663 664 665
    /* XXX: cannot enable it yet because it yields to MMU exception
       where NIP != read address on PowerPC */
#if 0
666 667 668
    target_ulong phys_addr;
    phys_addr = get_phys_addr_code(env, start);
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
669
#endif
670 671
}

B
bellard 已提交
672
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
673

B
bellard 已提交
674 675 676 677 678 679
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
B
bellard 已提交
680
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
B
bellard 已提交
681
        selector &= 0xffff;
682
        cpu_x86_load_seg_cache(env, seg_reg, selector,
B
bellard 已提交
683
                               (selector << 4), 0xffff, 0);
B
bellard 已提交
684
    } else {
B
bellard 已提交
685
        helper_load_seg(seg_reg, selector);
B
bellard 已提交
686
    }
B
bellard 已提交
687 688
    env = saved_env;
}
B
bellard 已提交
689

690
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
691 692 693 694 695
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
696

697
    helper_fsave(ptr, data32);
698 699 700 701

    env = saved_env;
}

702
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
703 704 705 706 707
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
708

709
    helper_frstor(ptr, data32);
710 711 712 713

    env = saved_env;
}

B
bellard 已提交
714 715
#endif /* TARGET_I386 */

B
bellard 已提交
716 717
#if !defined(CONFIG_SOFTMMU)

718
#if defined(TARGET_I386)
719 720 721 722
#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
#else
#define EXCEPTION_ACTION cpu_loop_exit()
#endif
723

724
/* 'pc' is the host PC at which the exception was raised. 'address' is
B
bellard 已提交
725 726 727
   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 已提交
728
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
729
                                    int is_write, sigset_t *old_set,
730
                                    void *puc)
B
bellard 已提交
731
{
B
bellard 已提交
732 733
    TranslationBlock *tb;
    int ret;
B
bellard 已提交
734

B
bellard 已提交
735 736
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
B
bellard 已提交
737
#if defined(DEBUG_SIGNAL)
738
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
739
                pc, address, is_write, *(unsigned long *)old_set);
B
bellard 已提交
740
#endif
741
    /* XXX: locking issue */
742
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
743 744
        return 1;
    }
745

746
    /* see if it is an MMU fault */
747
    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
    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);
763
    EXCEPTION_ACTION;
P
pbrook 已提交
764 765

    /* never comes here */
766 767
    return 1;
}
B
bellard 已提交
768

B
bellard 已提交
769 770
#if defined(__i386__)

771 772 773 774 775 776
#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)
777
# define MASK_sig(context)    ((context)->uc_sigmask)
J
Juergen Lock 已提交
778 779 780 781 782 783 784 785 786 787 788 789 790 791
#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)
792 793 794 795 796
#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)
797 798 799 800
#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])
801
# define MASK_sig(context)    ((context)->uc_sigmask)
802 803
#endif

804
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
805
                       void *puc)
B
bellard 已提交
806
{
807
    siginfo_t *info = pinfo;
J
Juergen Lock 已提交
808 809 810
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
    ucontext_t *uc = puc;
#elif defined(__OpenBSD__)
811 812
    struct sigcontext *uc = puc;
#else
B
bellard 已提交
813
    struct ucontext *uc = puc;
814
#endif
B
bellard 已提交
815
    unsigned long pc;
816
    int trapno;
B
bellard 已提交
817

818 819
#ifndef REG_EIP
/* for glibc 2.1 */
B
bellard 已提交
820 821 822
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
823
#endif
824 825
    pc = EIP_sig(uc);
    trapno = TRAP_sig(uc);
B
bellard 已提交
826 827 828
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             trapno == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
829
                             &MASK_sig(uc), puc);
B
bellard 已提交
830 831
}

832 833
#elif defined(__x86_64__)

834
#ifdef __NetBSD__
835 836 837 838 839 840 841 842 843
#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 已提交
844 845 846 847 848 849 850
#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)
851
#else
852 853 854 855
#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)
856 857
#endif

858
int cpu_signal_handler(int host_signum, void *pinfo,
859 860
                       void *puc)
{
861
    siginfo_t *info = pinfo;
862
    unsigned long pc;
J
Juergen Lock 已提交
863
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
864
    ucontext_t *uc = puc;
865 866
#elif defined(__OpenBSD__)
    struct sigcontext *uc = puc;
867 868 869
#else
    struct ucontext *uc = puc;
#endif
870

871
    pc = PC_sig(uc);
872
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
873 874 875
                             TRAP_sig(uc) == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
                             &MASK_sig(uc), puc);
876 877
}

M
malc 已提交
878
#elif defined(_ARCH_PPC)
B
bellard 已提交
879

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
/***********************************************************************
 * 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 */

904 905 906 907 908 909 910 911 912 913 914 915 916 917
#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__ */

918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
#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__ */

943
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
944
                       void *puc)
B
bellard 已提交
945
{
946
    siginfo_t *info = pinfo;
947 948 949
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    ucontext_t *uc = puc;
#else
950
    struct ucontext *uc = puc;
951
#endif
952 953 954
    unsigned long pc;
    int is_write;

955
    pc = IAR_sig(uc);
956 957 958
    is_write = 0;
#if 0
    /* ppc 4xx case */
959
    if (DSISR_sig(uc) & 0x00800000)
960 961
        is_write = 1;
#else
962
    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
963 964
        is_write = 1;
#endif
965
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
966
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
967 968
}

B
bellard 已提交
969 970
#elif defined(__alpha__)

971
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
972 973
                           void *puc)
{
974
    siginfo_t *info = pinfo;
B
bellard 已提交
975 976 977 978 979
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

980
    /* XXX: need kernel patch to get write flag faster */
B
bellard 已提交
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
    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;
    }

996
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
997
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
998
}
999 1000
#elif defined(__sparc__)

1001
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1002
                       void *puc)
1003
{
1004
    siginfo_t *info = pinfo;
1005 1006
    int is_write;
    uint32_t insn;
1007
#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
B
blueswir1 已提交
1008 1009
    uint32_t *regs = (uint32_t *)(info + 1);
    void *sigmask = (regs + 20);
1010
    /* XXX: is there a standard glibc define ? */
B
blueswir1 已提交
1011 1012
    unsigned long pc = regs[1];
#else
B
blueswir1 已提交
1013
#ifdef __linux__
B
blueswir1 已提交
1014 1015 1016
    struct sigcontext *sc = puc;
    unsigned long pc = sc->sigc_regs.tpc;
    void *sigmask = (void *)sc->sigc_mask;
B
blueswir1 已提交
1017 1018 1019 1020 1021
#elif defined(__OpenBSD__)
    struct sigcontext *uc = puc;
    unsigned long pc = uc->sc_pc;
    void *sigmask = (void *)(long)uc->sc_mask;
#endif
B
blueswir1 已提交
1022 1023
#endif

1024 1025 1026 1027 1028 1029
    /* 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
1030
      case 0x15: // stba
1031
      case 0x06: // sth
1032
      case 0x16: // stha
1033
      case 0x04: // st
1034
      case 0x14: // sta
1035
      case 0x07: // std
1036 1037 1038
      case 0x17: // stda
      case 0x0e: // stx
      case 0x1e: // stxa
1039
      case 0x24: // stf
1040
      case 0x34: // stfa
1041
      case 0x27: // stdf
1042 1043 1044
      case 0x37: // stdfa
      case 0x26: // stqf
      case 0x36: // stqfa
1045
      case 0x25: // stfsr
1046 1047
      case 0x3c: // casa
      case 0x3e: // casxa
1048 1049 1050 1051
	is_write = 1;
	break;
      }
    }
1052
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1053
                             is_write, sigmask, NULL);
1054 1055 1056 1057
}

#elif defined(__arm__)

1058
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1059
                       void *puc)
1060
{
1061
    siginfo_t *info = pinfo;
1062 1063 1064
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1065

1066
#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1067 1068
    pc = uc->uc_mcontext.gregs[R15];
#else
1069
    pc = uc->uc_mcontext.arm_pc;
1070
#endif
1071 1072
    /* XXX: compute is_write */
    is_write = 0;
1073
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1074
                             is_write,
P
pbrook 已提交
1075
                             &uc->uc_sigmask, puc);
1076 1077
}

B
bellard 已提交
1078 1079
#elif defined(__mc68000)

1080
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1081 1082
                       void *puc)
{
1083
    siginfo_t *info = pinfo;
B
bellard 已提交
1084 1085 1086
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1087

B
bellard 已提交
1088 1089 1090
    pc = uc->uc_mcontext.gregs[16];
    /* XXX: compute is_write */
    is_write = 0;
1091
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
B
bellard 已提交
1092
                             is_write,
1093
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1094 1095
}

B
bellard 已提交
1096 1097 1098 1099 1100 1101 1102
#elif defined(__ia64)

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

1103
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
B
bellard 已提交
1104
{
1105
    siginfo_t *info = pinfo;
B
bellard 已提交
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
    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 已提交
1117
	  if (info->si_code && (info->si_segvflags & __ISR_VALID))
B
bellard 已提交
1118 1119 1120 1121 1122 1123 1124 1125 1126
	      /* 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,
1127
                             (sigset_t *)&uc->uc_sigmask, puc);
B
bellard 已提交
1128 1129
}

B
bellard 已提交
1130 1131
#elif defined(__s390__)

1132
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1133 1134
                       void *puc)
{
1135
    siginfo_t *info = pinfo;
B
bellard 已提交
1136 1137
    struct ucontext *uc = puc;
    unsigned long pc;
1138 1139
    uint16_t *pinsn;
    int is_write = 0;
1140

B
bellard 已提交
1141
    pc = uc->uc_mcontext.psw.addr;
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178

    /* ??? 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;
    }
1179
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1180 1181 1182 1183 1184
                             is_write, &uc->uc_sigmask, puc);
}

#elif defined(__mips__)

1185
int cpu_signal_handler(int host_signum, void *pinfo,
1186 1187
                       void *puc)
{
T
ths 已提交
1188
    siginfo_t *info = pinfo;
1189 1190 1191
    struct ucontext *uc = puc;
    greg_t pc = uc->uc_mcontext.pc;
    int is_write;
1192

1193 1194
    /* XXX: compute is_write */
    is_write = 0;
1195
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1196
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1197 1198
}

A
aurel32 已提交
1199 1200 1201 1202 1203 1204 1205
#elif defined(__hppa__)

int cpu_signal_handler(int host_signum, void *pinfo,
                       void *puc)
{
    struct siginfo *info = pinfo;
    struct ucontext *uc = puc;
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
    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 已提交
1236 1237

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

B
bellard 已提交
1241
#else
B
bellard 已提交
1242

1243
#error host CPU specific signal handler needed
B
bellard 已提交
1244

B
bellard 已提交
1245
#endif
B
bellard 已提交
1246 1247

#endif /* !defined(CONFIG_SOFTMMU) */