cpu-exec.c 43.4 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 213 214 215 216 217
    if (env1->halted) {
        if (!cpu_has_work(env1)) {
            return EXCP_HALTED;
        }

        env1->halted = 0;
    }
B
bellard 已提交
218

219
    cpu_single_env = env1;
B
bellard 已提交
220

P
Paolo Bonzini 已提交
221 222 223 224 225
    /* 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 已提交
226
    barrier();
B
bellard 已提交
227
    env = env1;
B
bellard 已提交
228

J
Jan Kiszka 已提交
229
    if (unlikely(exit_request)) {
230 231 232
        env->exit_request = 1;
    }

233
#if defined(TARGET_I386)
234 235 236 237 238
    /* 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);
239
#elif defined(TARGET_SPARC)
P
pbrook 已提交
240 241 242 243
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
244 245 246
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_PPC)
M
Michael Walle 已提交
247
#elif defined(TARGET_LM32)
248
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
249
#elif defined(TARGET_MIPS)
B
bellard 已提交
250
#elif defined(TARGET_SH4)
251
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
252
#elif defined(TARGET_S390X)
B
bellard 已提交
253
    /* XXXXX */
B
bellard 已提交
254 255 256
#else
#error unsupported target CPU
#endif
257
    env->exception_index = -1;
258

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

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

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

B
bellard 已提交
634

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

    /* restore global registers */
J
Jan Kiszka 已提交
660
    barrier();
P
Paolo Bonzini 已提交
661
    env = (void *) saved_env_reg;
P
pbrook 已提交
662

B
bellard 已提交
663
    /* fail safe : never use cpu_single_env outside cpu_exec() */
664
    cpu_single_env = NULL;
B
bellard 已提交
665 666
    return ret;
}
B
bellard 已提交
667

668 669 670 671
/* 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)
{
672 673 674
    /* XXX: cannot enable it yet because it yields to MMU exception
       where NIP != read address on PowerPC */
#if 0
675 676 677
    target_ulong phys_addr;
    phys_addr = get_phys_addr_code(env, start);
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
678
#endif
679 680
}

B
bellard 已提交
681
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
682

B
bellard 已提交
683 684 685 686 687 688
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
B
bellard 已提交
689
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
B
bellard 已提交
690
        selector &= 0xffff;
691
        cpu_x86_load_seg_cache(env, seg_reg, selector,
B
bellard 已提交
692
                               (selector << 4), 0xffff, 0);
B
bellard 已提交
693
    } else {
B
bellard 已提交
694
        helper_load_seg(seg_reg, selector);
B
bellard 已提交
695
    }
B
bellard 已提交
696 697
    env = saved_env;
}
B
bellard 已提交
698

699
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
700 701 702 703 704
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
705

706
    helper_fsave(ptr, data32);
707 708 709 710

    env = saved_env;
}

711
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
712 713 714 715 716
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
717

718
    helper_frstor(ptr, data32);
719 720 721 722

    env = saved_env;
}

B
bellard 已提交
723 724
#endif /* TARGET_I386 */

B
bellard 已提交
725 726
#if !defined(CONFIG_SOFTMMU)

727
#if defined(TARGET_I386)
728 729 730 731
#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
#else
#define EXCEPTION_ACTION cpu_loop_exit()
#endif
732

733
/* 'pc' is the host PC at which the exception was raised. 'address' is
B
bellard 已提交
734 735 736
   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 已提交
737
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
738
                                    int is_write, sigset_t *old_set,
739
                                    void *puc)
B
bellard 已提交
740
{
B
bellard 已提交
741 742
    TranslationBlock *tb;
    int ret;
B
bellard 已提交
743

B
bellard 已提交
744 745
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
B
bellard 已提交
746
#if defined(DEBUG_SIGNAL)
747
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
748
                pc, address, is_write, *(unsigned long *)old_set);
B
bellard 已提交
749
#endif
750
    /* XXX: locking issue */
751
    if (is_write && page_unprotect(h2g(address), pc, puc)) {
B
bellard 已提交
752 753
        return 1;
    }
754

755
    /* see if it is an MMU fault */
756
    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
B
bellard 已提交
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
    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);
772
    EXCEPTION_ACTION;
P
pbrook 已提交
773 774

    /* never comes here */
775 776
    return 1;
}
B
bellard 已提交
777

B
bellard 已提交
778 779
#if defined(__i386__)

780 781 782 783 784 785
#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)
786
# define MASK_sig(context)    ((context)->uc_sigmask)
J
Juergen Lock 已提交
787 788 789 790 791 792 793 794 795 796 797 798 799 800
#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)
801 802 803 804 805
#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)
806 807 808 809
#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])
810
# define MASK_sig(context)    ((context)->uc_sigmask)
811 812
#endif

813
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
814
                       void *puc)
B
bellard 已提交
815
{
816
    siginfo_t *info = pinfo;
J
Juergen Lock 已提交
817 818 819
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
    ucontext_t *uc = puc;
#elif defined(__OpenBSD__)
820 821
    struct sigcontext *uc = puc;
#else
B
bellard 已提交
822
    struct ucontext *uc = puc;
823
#endif
B
bellard 已提交
824
    unsigned long pc;
825
    int trapno;
B
bellard 已提交
826

827 828
#ifndef REG_EIP
/* for glibc 2.1 */
B
bellard 已提交
829 830 831
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
832
#endif
833 834
    pc = EIP_sig(uc);
    trapno = TRAP_sig(uc);
B
bellard 已提交
835 836 837
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                             trapno == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
838
                             &MASK_sig(uc), puc);
B
bellard 已提交
839 840
}

841 842
#elif defined(__x86_64__)

843
#ifdef __NetBSD__
844 845 846 847 848 849 850 851 852
#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 已提交
853 854 855 856 857 858 859
#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)
860
#else
861 862 863 864
#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)
865 866
#endif

867
int cpu_signal_handler(int host_signum, void *pinfo,
868 869
                       void *puc)
{
870
    siginfo_t *info = pinfo;
871
    unsigned long pc;
J
Juergen Lock 已提交
872
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
873
    ucontext_t *uc = puc;
874 875
#elif defined(__OpenBSD__)
    struct sigcontext *uc = puc;
876 877 878
#else
    struct ucontext *uc = puc;
#endif
879

880
    pc = PC_sig(uc);
881
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
882 883 884
                             TRAP_sig(uc) == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
                             &MASK_sig(uc), puc);
885 886
}

M
malc 已提交
887
#elif defined(_ARCH_PPC)
B
bellard 已提交
888

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
/***********************************************************************
 * 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 */

913 914 915 916 917 918 919 920 921 922 923 924 925 926
#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__ */

927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
#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__ */

952
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
953
                       void *puc)
B
bellard 已提交
954
{
955
    siginfo_t *info = pinfo;
956 957 958
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    ucontext_t *uc = puc;
#else
959
    struct ucontext *uc = puc;
960
#endif
961 962 963
    unsigned long pc;
    int is_write;

964
    pc = IAR_sig(uc);
965 966 967
    is_write = 0;
#if 0
    /* ppc 4xx case */
968
    if (DSISR_sig(uc) & 0x00800000)
969 970
        is_write = 1;
#else
971
    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
972 973
        is_write = 1;
#endif
974
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
975
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
976 977
}

B
bellard 已提交
978 979
#elif defined(__alpha__)

980
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
981 982
                           void *puc)
{
983
    siginfo_t *info = pinfo;
B
bellard 已提交
984 985 986 987 988
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

989
    /* XXX: need kernel patch to get write flag faster */
B
bellard 已提交
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
    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;
    }

1005
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1006
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1007
}
1008 1009
#elif defined(__sparc__)

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

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

#elif defined(__arm__)

1067
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1068
                       void *puc)
1069
{
1070
    siginfo_t *info = pinfo;
1071 1072 1073
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1074

1075
#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1076 1077
    pc = uc->uc_mcontext.gregs[R15];
#else
1078
    pc = uc->uc_mcontext.arm_pc;
1079
#endif
1080 1081
    /* XXX: compute is_write */
    is_write = 0;
1082
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1083
                             is_write,
P
pbrook 已提交
1084
                             &uc->uc_sigmask, puc);
1085 1086
}

B
bellard 已提交
1087 1088
#elif defined(__mc68000)

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

B
bellard 已提交
1097 1098 1099
    pc = uc->uc_mcontext.gregs[16];
    /* XXX: compute is_write */
    is_write = 0;
1100
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
B
bellard 已提交
1101
                             is_write,
1102
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1103 1104
}

B
bellard 已提交
1105 1106 1107 1108 1109 1110 1111
#elif defined(__ia64)

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

1112
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
B
bellard 已提交
1113
{
1114
    siginfo_t *info = pinfo;
B
bellard 已提交
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
    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 已提交
1126
	  if (info->si_code && (info->si_segvflags & __ISR_VALID))
B
bellard 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135
	      /* 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,
1136
                             (sigset_t *)&uc->uc_sigmask, puc);
B
bellard 已提交
1137 1138
}

B
bellard 已提交
1139 1140
#elif defined(__s390__)

1141
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1142 1143
                       void *puc)
{
1144
    siginfo_t *info = pinfo;
B
bellard 已提交
1145 1146
    struct ucontext *uc = puc;
    unsigned long pc;
1147 1148
    uint16_t *pinsn;
    int is_write = 0;
1149

B
bellard 已提交
1150
    pc = uc->uc_mcontext.psw.addr;
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 1179 1180 1181 1182 1183 1184 1185 1186 1187

    /* ??? 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;
    }
1188
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1189 1190 1191 1192 1193
                             is_write, &uc->uc_sigmask, puc);
}

#elif defined(__mips__)

1194
int cpu_signal_handler(int host_signum, void *pinfo,
1195 1196
                       void *puc)
{
T
ths 已提交
1197
    siginfo_t *info = pinfo;
1198 1199 1200
    struct ucontext *uc = puc;
    greg_t pc = uc->uc_mcontext.pc;
    int is_write;
1201

1202 1203
    /* XXX: compute is_write */
    is_write = 0;
1204
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1205
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1206 1207
}

A
aurel32 已提交
1208 1209 1210 1211 1212 1213 1214
#elif defined(__hppa__)

int cpu_signal_handler(int host_signum, void *pinfo,
                       void *puc)
{
    struct siginfo *info = pinfo;
    struct ucontext *uc = puc;
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
    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 已提交
1245 1246

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

B
bellard 已提交
1250
#else
B
bellard 已提交
1251

1252
#error host CPU specific signal handler needed
B
bellard 已提交
1253

B
bellard 已提交
1254
#endif
B
bellard 已提交
1255 1256

#endif /* !defined(CONFIG_SOFTMMU) */