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

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

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

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

B
bellard 已提交
629

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

    /* restore global registers */
J
Jan Kiszka 已提交
655
    barrier();
P
Paolo Bonzini 已提交
656
    env = (void *) saved_env_reg;
P
pbrook 已提交
657

B
bellard 已提交
658
    /* fail safe : never use cpu_single_env outside cpu_exec() */
659
    cpu_single_env = NULL;
B
bellard 已提交
660 661
    return ret;
}
B
bellard 已提交
662

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

B
bellard 已提交
676
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
677

B
bellard 已提交
678 679 680 681 682 683
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

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

694
void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
695 696 697 698 699
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
700

701
    helper_fsave(ptr, data32);
702 703 704 705

    env = saved_env;
}

706
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
707 708 709 710 711
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
712

713
    helper_frstor(ptr, data32);
714 715 716 717

    env = saved_env;
}

B
bellard 已提交
718 719
#endif /* TARGET_I386 */

B
bellard 已提交
720 721
#if !defined(CONFIG_SOFTMMU)

722
#if defined(TARGET_I386)
723 724 725 726
#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
#else
#define EXCEPTION_ACTION cpu_loop_exit()
#endif
727

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

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

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

    /* never comes here */
770 771
    return 1;
}
B
bellard 已提交
772

B
bellard 已提交
773 774
#if defined(__i386__)

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

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

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

836 837
#elif defined(__x86_64__)

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

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

875
    pc = PC_sig(uc);
876
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
877 878 879
                             TRAP_sig(uc) == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
                             &MASK_sig(uc), puc);
880 881
}

M
malc 已提交
882
#elif defined(_ARCH_PPC)
B
bellard 已提交
883

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
/***********************************************************************
 * 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 */

908 909 910 911 912 913 914 915 916 917 918 919 920 921
#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__ */

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

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

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

B
bellard 已提交
973 974
#elif defined(__alpha__)

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

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

1000
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1001
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1002
}
1003 1004
#elif defined(__sparc__)

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

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

#elif defined(__arm__)

1062
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1063
                       void *puc)
1064
{
1065
    siginfo_t *info = pinfo;
1066 1067 1068
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1069

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

B
bellard 已提交
1082 1083
#elif defined(__mc68000)

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

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

B
bellard 已提交
1100 1101 1102 1103 1104 1105 1106
#elif defined(__ia64)

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

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

B
bellard 已提交
1134 1135
#elif defined(__s390__)

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

B
bellard 已提交
1145
    pc = uc->uc_mcontext.psw.addr;
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 1179 1180 1181 1182

    /* ??? 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;
    }
1183
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1184 1185 1186 1187 1188
                             is_write, &uc->uc_sigmask, puc);
}

#elif defined(__mips__)

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

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

A
aurel32 已提交
1203 1204 1205 1206 1207 1208 1209
#elif defined(__hppa__)

int cpu_signal_handler(int host_signum, void *pinfo,
                       void *puc)
{
    struct siginfo *info = pinfo;
    struct ucontext *uc = puc;
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 1236 1237 1238 1239
    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 已提交
1240 1241

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

B
bellard 已提交
1245
#else
B
bellard 已提交
1246

1247
#error host CPU specific signal handler needed
B
bellard 已提交
1248

B
bellard 已提交
1249
#endif
B
bellard 已提交
1250 1251

#endif /* !defined(CONFIG_SOFTMMU) */