cpu-exec.c 43.8 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 170 171 172 173 174 175 176 177 178
 found:
    /* we add the TB in the virtual pc hash table */
    env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
    return tb;
}

static inline TranslationBlock *tb_find_fast(void)
{
    TranslationBlock *tb;
    target_ulong cs_base, pc;
179
    int flags;
180 181 182 183

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

A
aliguori 已提交
193 194 195 196 197 198 199 200 201 202
static CPUDebugExcpHandler *debug_excp_handler;

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

    debug_excp_handler = handler;
    return old_handler;
}

203 204 205 206 207
static void cpu_handle_debug_exception(CPUState *env)
{
    CPUWatchpoint *wp;

    if (!env->watchpoint_hit)
B
Blue Swirl 已提交
208
        QTAILQ_FOREACH(wp, &env->watchpoints, entry)
209
            wp->flags &= ~BP_WATCHPOINT_HIT;
A
aliguori 已提交
210 211 212

    if (debug_excp_handler)
        debug_excp_handler(env);
213 214
}

B
bellard 已提交
215 216
/* main execution loop */

217 218
volatile sig_atomic_t exit_request;

B
bellard 已提交
219
int cpu_exec(CPUState *env1)
B
bellard 已提交
220
{
221
    volatile host_reg_t saved_env_reg;
222 223
    int ret, interrupt_request;
    TranslationBlock *tb;
B
bellard 已提交
224
    uint8_t *tc_ptr;
P
pbrook 已提交
225
    unsigned long next_tb;
226

227 228
    if (cpu_halted(env1) == EXCP_HALTED)
        return EXCP_HALTED;
B
bellard 已提交
229

230
    cpu_single_env = env1;
B
bellard 已提交
231

P
Paolo Bonzini 已提交
232 233 234 235 236
    /* 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 已提交
237
    barrier();
B
bellard 已提交
238
    env = env1;
B
bellard 已提交
239

J
Jan Kiszka 已提交
240
    if (unlikely(exit_request)) {
241 242 243
        env->exit_request = 1;
    }

244
#if defined(TARGET_I386)
245 246 247 248 249 250 251
    if (!kvm_enabled()) {
        /* put eflags in CPU temporary format */
        CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
        DF = 1 - (2 * ((env->eflags >> 10) & 1));
        CC_OP = CC_OP_EFLAGS;
        env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    }
252
#elif defined(TARGET_SPARC)
P
pbrook 已提交
253 254 255 256
#elif defined(TARGET_M68K)
    env->cc_op = CC_OP_FLAGS;
    env->cc_dest = env->sr & 0xf;
    env->cc_x = (env->sr >> 4) & 1;
257 258 259
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ARM)
#elif defined(TARGET_PPC)
260
#elif defined(TARGET_MICROBLAZE)
B
bellard 已提交
261
#elif defined(TARGET_MIPS)
B
bellard 已提交
262
#elif defined(TARGET_SH4)
263
#elif defined(TARGET_CRIS)
A
Alexander Graf 已提交
264
#elif defined(TARGET_S390X)
B
bellard 已提交
265
    /* XXXXX */
B
bellard 已提交
266 267 268
#else
#error unsupported target CPU
#endif
269
    env->exception_index = -1;
270

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

A
aliguori 已提交
337
            if (kvm_enabled()) {
A
aliguori 已提交
338 339
                kvm_cpu_exec(env);
                longjmp(env->jmp_env, 1);
A
aliguori 已提交
340 341
            }

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

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

B
bellard 已提交
648

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

    /* restore global registers */
J
Jan Kiszka 已提交
673
    barrier();
P
Paolo Bonzini 已提交
674
    env = (void *) saved_env_reg;
P
pbrook 已提交
675

B
bellard 已提交
676
    /* fail safe : never use cpu_single_env outside cpu_exec() */
677
    cpu_single_env = NULL;
B
bellard 已提交
678 679
    return ret;
}
B
bellard 已提交
680

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

B
bellard 已提交
694
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
695

B
bellard 已提交
696 697 698 699 700 701
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
B
bellard 已提交
702
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
B
bellard 已提交
703
        selector &= 0xffff;
704
        cpu_x86_load_seg_cache(env, seg_reg, selector,
B
bellard 已提交
705
                               (selector << 4), 0xffff, 0);
B
bellard 已提交
706
    } else {
B
bellard 已提交
707
        helper_load_seg(seg_reg, selector);
B
bellard 已提交
708
    }
B
bellard 已提交
709 710
    env = saved_env;
}
B
bellard 已提交
711

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

    saved_env = env;
    env = s;
718

719
    helper_fsave(ptr, data32);
720 721 722 723

    env = saved_env;
}

724
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
725 726 727 728 729
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
730

731
    helper_frstor(ptr, data32);
732 733 734 735

    env = saved_env;
}

B
bellard 已提交
736 737
#endif /* TARGET_I386 */

B
bellard 已提交
738 739
#if !defined(CONFIG_SOFTMMU)

740
#if defined(TARGET_I386)
741 742 743 744
#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
#else
#define EXCEPTION_ACTION cpu_loop_exit()
#endif
745

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

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

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

    /* never comes here */
788 789
    return 1;
}
B
bellard 已提交
790

B
bellard 已提交
791 792
#if defined(__i386__)

793 794 795 796 797 798
#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)
799
# define MASK_sig(context)    ((context)->uc_sigmask)
J
Juergen Lock 已提交
800 801 802 803 804 805 806 807 808 809 810 811 812 813
#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)
814 815 816 817 818
#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)
819 820 821 822
#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])
823
# define MASK_sig(context)    ((context)->uc_sigmask)
824 825
#endif

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

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

854 855
#elif defined(__x86_64__)

856
#ifdef __NetBSD__
857 858 859 860 861 862 863 864 865
#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 已提交
866 867 868 869 870 871 872
#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)
873
#else
874 875 876 877
#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)
878 879
#endif

880
int cpu_signal_handler(int host_signum, void *pinfo,
881 882
                       void *puc)
{
883
    siginfo_t *info = pinfo;
884
    unsigned long pc;
J
Juergen Lock 已提交
885
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
886
    ucontext_t *uc = puc;
887 888
#elif defined(__OpenBSD__)
    struct sigcontext *uc = puc;
889 890 891
#else
    struct ucontext *uc = puc;
#endif
892

893
    pc = PC_sig(uc);
894
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
895 896 897
                             TRAP_sig(uc) == 0xe ?
                             (ERROR_sig(uc) >> 1) & 1 : 0,
                             &MASK_sig(uc), puc);
898 899
}

M
malc 已提交
900
#elif defined(_ARCH_PPC)
B
bellard 已提交
901

902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
/***********************************************************************
 * 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 */

926 927 928 929 930 931 932 933 934 935 936 937 938 939
#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__ */

940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
#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__ */

965
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
966
                       void *puc)
B
bellard 已提交
967
{
968
    siginfo_t *info = pinfo;
969 970 971
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    ucontext_t *uc = puc;
#else
972
    struct ucontext *uc = puc;
973
#endif
974 975 976
    unsigned long pc;
    int is_write;

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

B
bellard 已提交
991 992
#elif defined(__alpha__)

993
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
994 995
                           void *puc)
{
996
    siginfo_t *info = pinfo;
B
bellard 已提交
997 998 999 1000 1001
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

1002
    /* XXX: need kernel patch to get write flag faster */
B
bellard 已提交
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
    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;
    }

1018
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1019
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1020
}
1021 1022
#elif defined(__sparc__)

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

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

#elif defined(__arm__)

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

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

B
bellard 已提交
1100 1101
#elif defined(__mc68000)

1102
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1103 1104
                       void *puc)
{
1105
    siginfo_t *info = pinfo;
B
bellard 已提交
1106 1107 1108
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
1109

B
bellard 已提交
1110 1111 1112
    pc = uc->uc_mcontext.gregs[16];
    /* XXX: compute is_write */
    is_write = 0;
1113
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
B
bellard 已提交
1114
                             is_write,
1115
                             &uc->uc_sigmask, puc);
B
bellard 已提交
1116 1117
}

B
bellard 已提交
1118 1119 1120 1121 1122 1123 1124
#elif defined(__ia64)

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

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

B
bellard 已提交
1152 1153
#elif defined(__s390__)

1154
int cpu_signal_handler(int host_signum, void *pinfo,
B
bellard 已提交
1155 1156
                       void *puc)
{
1157
    siginfo_t *info = pinfo;
B
bellard 已提交
1158 1159
    struct ucontext *uc = puc;
    unsigned long pc;
1160 1161
    uint16_t *pinsn;
    int is_write = 0;
1162

B
bellard 已提交
1163
    pc = uc->uc_mcontext.psw.addr;
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200

    /* ??? 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;
    }
1201
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1202 1203 1204 1205 1206
                             is_write, &uc->uc_sigmask, puc);
}

#elif defined(__mips__)

1207
int cpu_signal_handler(int host_signum, void *pinfo,
1208 1209
                       void *puc)
{
T
ths 已提交
1210
    siginfo_t *info = pinfo;
1211 1212 1213
    struct ucontext *uc = puc;
    greg_t pc = uc->uc_mcontext.pc;
    int is_write;
1214

1215 1216
    /* XXX: compute is_write */
    is_write = 0;
1217
    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1218
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
1219 1220
}

A
aurel32 已提交
1221 1222 1223 1224 1225 1226 1227
#elif defined(__hppa__)

int cpu_signal_handler(int host_signum, void *pinfo,
                       void *puc)
{
    struct siginfo *info = pinfo;
    struct ucontext *uc = puc;
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
    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 已提交
1258 1259

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

B
bellard 已提交
1263
#else
B
bellard 已提交
1264

1265
#error host CPU specific signal handler needed
B
bellard 已提交
1266

B
bellard 已提交
1267
#endif
B
bellard 已提交
1268 1269

#endif /* !defined(CONFIG_SOFTMMU) */