cpu-exec.c 36.6 KB
Newer Older
bellard's avatar
bellard committed
1 2 3 4 5
/*
 *  i386 emulator main execution loop
 * 
 *  Copyright (c) 2003 Fabrice Bellard
 *
bellard's avatar
bellard committed
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.
bellard's avatar
bellard committed
10
 *
bellard's avatar
bellard committed
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.
bellard's avatar
bellard committed
15
 *
bellard's avatar
bellard committed
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
bellard's avatar
bellard committed
19
 */
20
#include "config.h"
21
#include "exec.h"
bellard's avatar
bellard committed
22
#include "disas.h"
bellard's avatar
bellard committed
23

24 25 26 27 28 29 30 31 32 33 34 35 36 37
#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>
#include <sys/ucontext.h>
#endif

38 39
int tb_invalidated_flag;

40
//#define DEBUG_EXEC
bellard's avatar
bellard committed
41
//#define DEBUG_SIGNAL
bellard's avatar
bellard committed
42

43
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
44 45 46 47 48 49 50
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
    longjmp(env->jmp_env, 1);
}
#endif

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
/* exit the current TB from a signal handler. The host registers are
   restored in a state compatible with the CPU emulator
 */
void cpu_resume_from_signal(CPUState *env1, void *puc) 
{
#if !defined(CONFIG_SOFTMMU)
    struct ucontext *uc = puc;
#endif

    env = env1;

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

#if !defined(CONFIG_SOFTMMU)
    if (puc) {
        /* XXX: use siglongjmp ? */
        sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
    }
#endif
    longjmp(env->jmp_env, 1);
}

bellard's avatar
bellard committed
73 74
/* main execution loop */

75
int cpu_exec(CPUState *env1)
bellard's avatar
bellard committed
76
{
77 78
    int saved_T0, saved_T1, saved_T2;
    CPUState *saved_env;
bellard's avatar
bellard committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
#ifdef reg_EAX
    int saved_EAX;
#endif
#ifdef reg_ECX
    int saved_ECX;
#endif
#ifdef reg_EDX
    int saved_EDX;
#endif
#ifdef reg_EBX
    int saved_EBX;
#endif
#ifdef reg_ESP
    int saved_ESP;
#endif
#ifdef reg_EBP
    int saved_EBP;
#endif
#ifdef reg_ESI
    int saved_ESI;
#endif
#ifdef reg_EDI
    int saved_EDI;
102 103 104
#endif
#ifdef __sparc__
    int saved_i7, tmp_T0;
bellard's avatar
bellard committed
105
#endif
bellard's avatar
bellard committed
106
    int code_gen_size, ret, interrupt_request;
bellard's avatar
bellard committed
107
    void (*gen_func)(void);
bellard's avatar
bellard committed
108
    TranslationBlock *tb, **ptb;
bellard's avatar
bellard committed
109 110
    target_ulong cs_base, pc;
    uint8_t *tc_ptr;
bellard's avatar
bellard committed
111
    unsigned int flags;
112

bellard's avatar
bellard committed
113
    /* first we save global registers */
bellard's avatar
bellard committed
114 115
    saved_env = env;
    env = env1;
bellard's avatar
bellard committed
116 117
    saved_T0 = T0;
    saved_T1 = T1;
118 119 120 121 122 123 124
    saved_T2 = T2;
#ifdef __sparc__
    /* we also save i7 because longjmp may not restore it */
    asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
#endif

#if defined(TARGET_I386)
bellard's avatar
bellard committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
#ifdef reg_EAX
    saved_EAX = EAX;
#endif
#ifdef reg_ECX
    saved_ECX = ECX;
#endif
#ifdef reg_EDX
    saved_EDX = EDX;
#endif
#ifdef reg_EBX
    saved_EBX = EBX;
#endif
#ifdef reg_ESP
    saved_ESP = ESP;
#endif
#ifdef reg_EBP
    saved_EBP = EBP;
#endif
#ifdef reg_ESI
    saved_ESI = ESI;
#endif
#ifdef reg_EDI
    saved_EDI = EDI;
#endif
149 150

    env_to_regs();
bellard's avatar
bellard committed
151
    /* put eflags in CPU temporary format */
bellard's avatar
bellard committed
152 153
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard's avatar
bellard committed
154
    CC_OP = CC_OP_EFLAGS;
bellard's avatar
bellard committed
155
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
156 157 158 159 160 161 162
#elif defined(TARGET_ARM)
    {
        unsigned int psr;
        psr = env->cpsr;
        env->CF = (psr >> 29) & 1;
        env->NZF = (psr & 0xc0000000) ^ 0x40000000;
        env->VF = (psr << 3) & 0x80000000;
bellard's avatar
bellard committed
163 164
        env->QF = (psr >> 27) & 1;
        env->cpsr = psr & ~CACHED_CPSR_BITS;
165
    }
166
#elif defined(TARGET_SPARC)
167
#elif defined(TARGET_PPC)
168 169 170
#else
#error unsupported target CPU
#endif
171
    env->exception_index = -1;
172

bellard's avatar
bellard committed
173
    /* prepare setjmp context for exception handling */
174 175
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
176
            env->current_tb = NULL;
177 178 179 180 181 182 183 184 185 186
            /* 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;
                } else if (env->user_mode_only) {
                    /* if user mode only, we simulate a fake exception
                       which will be hanlded outside the cpu execution
                       loop */
bellard's avatar
bellard committed
187
#if defined(TARGET_I386)
188 189 190 191
                    do_interrupt_user(env->exception_index, 
                                      env->exception_is_int, 
                                      env->error_code, 
                                      env->exception_next_eip);
bellard's avatar
bellard committed
192
#endif
193 194 195
                    ret = env->exception_index;
                    break;
                } else {
bellard's avatar
bellard committed
196
#if defined(TARGET_I386)
197 198 199 200 201 202
                    /* simulate a real cpu exception. On i386, it can
                       trigger new exceptions, but we do not handle
                       double or triple faults yet. */
                    do_interrupt(env->exception_index, 
                                 env->exception_is_int, 
                                 env->error_code, 
203
                                 env->exception_next_eip, 0);
204 205
#elif defined(TARGET_PPC)
                    do_interrupt(env);
206 207
#elif defined(TARGET_SPARC)
                    do_interrupt(env->exception_index, 
bellard's avatar
bellard committed
208
                                 env->error_code);
bellard's avatar
bellard committed
209
#endif
210 211
                }
                env->exception_index = -1;
bellard's avatar
bellard committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
            } 
#ifdef USE_KQEMU
            if (kqemu_is_ok(env) && env->interrupt_request == 0) {
                int ret;
                env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
                ret = kqemu_cpu_exec(env);
                /* 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);
                if (ret == 1) {
                    /* exception */
                    longjmp(env->jmp_env, 1);
                } else if (ret == 2) {
                    /* softmmu execution needed */
                } else {
                    if (env->interrupt_request != 0) {
                        /* hardware interrupt will be executed just after */
                    } else {
                        /* otherwise, we restart */
                        longjmp(env->jmp_env, 1);
                    }
                }
236
            }
bellard's avatar
bellard committed
237 238
#endif

239 240
            T0 = 0; /* force lookup of first TB */
            for(;;) {
241
#ifdef __sparc__
242 243
                /* g1 can be modified by some libc? functions */ 
                tmp_T0 = T0;
244
#endif	    
bellard's avatar
bellard committed
245
                interrupt_request = env->interrupt_request;
246
                if (__builtin_expect(interrupt_request, 0)) {
bellard's avatar
bellard committed
247 248 249
#if defined(TARGET_I386)
                    /* if hardware interrupt pending, we execute it */
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
250 251
                        (env->eflags & IF_MASK) && 
                        !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard's avatar
bellard committed
252
                        int intno;
253
                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
254
                        intno = cpu_get_pic_interrupt(env);
255
                        if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard's avatar
bellard committed
256 257
                            fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
                        }
258
                        do_interrupt(intno, 0, 0, 0, 1);
bellard's avatar
bellard committed
259 260 261 262 263 264 265
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
#ifdef __sparc__
                        tmp_T0 = 0;
#else
                        T0 = 0;
#endif
bellard's avatar
bellard committed
266
                    }
267
#elif defined(TARGET_PPC)
268 269 270 271 272 273
#if 0
                    if ((interrupt_request & CPU_INTERRUPT_RESET)) {
                        cpu_ppc_reset(env);
                    }
#endif
                    if (msr_ee != 0) {
274
                    if ((interrupt_request & CPU_INTERRUPT_HARD)) {
275 276 277
			    /* Raise it */
			    env->exception_index = EXCP_EXTERNAL;
			    env->error_code = 0;
278 279
                            do_interrupt(env);
                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
280 281 282 283 284 285 286
			} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
			    /* Raise it */
			    env->exception_index = EXCP_DECR;
			    env->error_code = 0;
			    do_interrupt(env);
                            env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
			}
287
                    }
288 289
#elif defined(TARGET_SPARC)
                    if (interrupt_request & CPU_INTERRUPT_HARD) {
bellard's avatar
bellard committed
290
			do_interrupt(env->interrupt_index, 0);
291 292 293 294 295
                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
			//do_interrupt(0, 0, 0, 0, 0);
			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
		    }
bellard's avatar
bellard committed
296
#endif
297 298 299 300 301 302 303 304 305 306
                    if (interrupt_request & CPU_INTERRUPT_EXITTB) {
                        env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
#ifdef __sparc__
                        tmp_T0 = 0;
#else
                        T0 = 0;
#endif
                    }
bellard's avatar
bellard committed
307 308 309 310 311
                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
                        env->exception_index = EXCP_INTERRUPT;
                        cpu_loop_exit();
                    }
312
                }
bellard's avatar
bellard committed
313
#ifdef DEBUG_EXEC
bellard's avatar
bellard committed
314
                if ((loglevel & CPU_LOG_EXEC)) {
315
#if defined(TARGET_I386)
316 317 318 319 320 321 322 323 324 325
                    /* restore flags in standard format */
                    env->regs[R_EAX] = EAX;
                    env->regs[R_EBX] = EBX;
                    env->regs[R_ECX] = ECX;
                    env->regs[R_EDX] = EDX;
                    env->regs[R_ESI] = ESI;
                    env->regs[R_EDI] = EDI;
                    env->regs[R_EBP] = EBP;
                    env->regs[R_ESP] = ESP;
                    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard's avatar
bellard committed
326
                    cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
327
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
328
#elif defined(TARGET_ARM)
bellard's avatar
bellard committed
329
                    env->cpsr = compute_cpsr();
bellard's avatar
bellard committed
330
                    cpu_dump_state(env, logfile, fprintf, 0);
bellard's avatar
bellard committed
331
                    env->cpsr &= ~CACHED_CPSR_BITS;
332
#elif defined(TARGET_SPARC)
bellard's avatar
bellard committed
333
                    cpu_dump_state (env, logfile, fprintf, 0);
334
#elif defined(TARGET_PPC)
bellard's avatar
bellard committed
335
                    cpu_dump_state(env, logfile, fprintf, 0);
336 337 338
#else
#error unsupported target CPU 
#endif
339
                }
bellard's avatar
bellard committed
340
#endif
341 342 343
                /* we record a subset of the CPU state. It will
                   always be the same before a given translated block
                   is executed. */
344
#if defined(TARGET_I386)
345
                flags = env->hflags;
346
                flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
347 348
                cs_base = env->segs[R_CS].base;
                pc = cs_base + env->eip;
349
#elif defined(TARGET_ARM)
bellard's avatar
bellard committed
350
                flags = env->thumb;
351
                cs_base = 0;
bellard's avatar
bellard committed
352
                pc = env->regs[15];
353
#elif defined(TARGET_SPARC)
354
                flags = 0;
bellard's avatar
bellard committed
355 356
                cs_base = env->npc;
                pc = env->pc;
357 358 359
#elif defined(TARGET_PPC)
                flags = 0;
                cs_base = 0;
bellard's avatar
bellard committed
360
                pc = env->nip;
361 362 363
#else
#error unsupported CPU
#endif
bellard's avatar
bellard committed
364
                tb = tb_find(&ptb, pc, cs_base, 
365
                             flags);
366
                if (!tb) {
bellard's avatar
bellard committed
367 368 369 370 371
                    TranslationBlock **ptb1;
                    unsigned int h;
                    target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
                    
                    
372
                    spin_lock(&tb_lock);
bellard's avatar
bellard committed
373 374

                    tb_invalidated_flag = 0;
375 376
                    
                    regs_to_env(); /* XXX: do it just before cpu_gen_code() */
bellard's avatar
bellard committed
377 378

                    /* find translated block using physical mappings */
bellard's avatar
bellard committed
379
                    phys_pc = get_phys_addr_code(env, pc);
bellard's avatar
bellard committed
380 381 382 383 384 385 386 387
                    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;
bellard's avatar
bellard committed
388
                        if (tb->pc == pc && 
bellard's avatar
bellard committed
389
                            tb->page_addr[0] == phys_page1 &&
bellard's avatar
bellard committed
390
                            tb->cs_base == cs_base && 
bellard's avatar
bellard committed
391 392
                            tb->flags == flags) {
                            /* check next page if needed */
393
                            if (tb->page_addr[1] != -1) {
bellard's avatar
bellard committed
394
                                virt_page2 = (pc & TARGET_PAGE_MASK) + 
395
                                    TARGET_PAGE_SIZE;
bellard's avatar
bellard committed
396 397 398 399 400 401 402 403 404 405
                                phys_page2 = get_phys_addr_code(env, virt_page2);
                                if (tb->page_addr[1] == phys_page2)
                                    goto found;
                            } else {
                                goto found;
                            }
                        }
                        ptb1 = &tb->phys_hash_next;
                    }
                not_found:
406
                    /* if no translated code available, then translate it now */
bellard's avatar
bellard committed
407
                    tb = tb_alloc(pc);
408 409
                    if (!tb) {
                        /* flush must be done */
bellard's avatar
bellard committed
410
                        tb_flush(env);
411
                        /* cannot fail at this point */
bellard's avatar
bellard committed
412
                        tb = tb_alloc(pc);
413
                        /* don't forget to invalidate previous TB info */
bellard's avatar
bellard committed
414
                        ptb = &tb_hash[tb_hash_func(pc)];
415 416 417 418
                        T0 = 0;
                    }
                    tc_ptr = code_gen_ptr;
                    tb->tc_ptr = tc_ptr;
bellard's avatar
bellard committed
419
                    tb->cs_base = cs_base;
420
                    tb->flags = flags;
bellard's avatar
bellard committed
421
                    cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
bellard's avatar
bellard committed
422 423 424
                    code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
                    
                    /* check next page if needed */
bellard's avatar
bellard committed
425
                    virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
bellard's avatar
bellard committed
426
                    phys_page2 = -1;
bellard's avatar
bellard committed
427
                    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
bellard's avatar
bellard committed
428 429 430 431 432
                        phys_page2 = get_phys_addr_code(env, virt_page2);
                    }
                    tb_link_phys(tb, phys_pc, phys_page2);

                found:
433 434 435 436
                    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 */
bellard's avatar
bellard committed
437
                        ptb = &tb_hash[tb_hash_func(pc)];
438 439 440 441
                        while (*ptb != NULL)
                            ptb = &(*ptb)->hash_next;
                        T0 = 0;
                    }
bellard's avatar
bellard committed
442
                    /* we add the TB in the virtual pc hash table */
443 444 445
                    *ptb = tb;
                    tb->hash_next = NULL;
                    tb_link(tb);
446
                    spin_unlock(&tb_lock);
bellard's avatar
bellard committed
447
                }
448
#ifdef DEBUG_EXEC
bellard's avatar
bellard committed
449
                if ((loglevel & CPU_LOG_EXEC)) {
bellard's avatar
bellard committed
450 451 452
                    fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
                            (long)tb->tc_ptr, tb->pc,
                            lookup_symbol(tb->pc));
453
                }
454
#endif
455
#ifdef __sparc__
456
                T0 = tmp_T0;
457
#endif	    
bellard's avatar
bellard committed
458
                /* see if we can patch the calling TB. */
bellard's avatar
bellard committed
459 460
                {
                    if (T0 != 0
461 462 463 464 465
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
                    && (tb->cflags & CF_CODE_COPY) == 
                    (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
#endif
                    ) {
466
                    spin_lock(&tb_lock);
bellard's avatar
bellard committed
467
                    tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
468 469 470 471 472
#if defined(USE_CODE_COPY)
                    /* propagates the FP use info */
                    ((TranslationBlock *)(T0 & ~3))->cflags |= 
                        (tb->cflags & CF_FP_USED);
#endif
473 474
                    spin_unlock(&tb_lock);
                }
bellard's avatar
bellard committed
475
                }
476
                tc_ptr = tb->tc_ptr;
bellard's avatar
bellard committed
477
                env->current_tb = tb;
478 479
                /* execute the generated code */
                gen_func = (void *)tc_ptr;
480
#if defined(__sparc__)
481 482 483 484 485
                __asm__ __volatile__("call	%0\n\t"
                                     "mov	%%o7,%%i0"
                                     : /* no outputs */
                                     : "r" (gen_func) 
                                     : "i0", "i1", "i2", "i3", "i4", "i5");
486
#elif defined(__arm__)
487 488 489 490 491 492
                asm volatile ("mov pc, %0\n\t"
                              ".global exec_loop\n\t"
                              "exec_loop:\n\t"
                              : /* no outputs */
                              : "r" (gen_func)
                              : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
493 494 495
#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
{
    if (!(tb->cflags & CF_CODE_COPY)) {
496 497 498
        if ((tb->cflags & CF_FP_USED) && env->native_fp_regs) {
            save_native_fp_state(env);
        }
499 500
        gen_func();
    } else {
501 502 503
        if ((tb->cflags & CF_FP_USED) && !env->native_fp_regs) {
            restore_native_fp_state(env);
        }
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
        /* we work with native eflags */
        CC_SRC = cc_table[CC_OP].compute_all();
        CC_OP = CC_OP_EFLAGS;
        asm(".globl exec_loop\n"
            "\n"
            "debug1:\n"
            "    pushl %%ebp\n"
            "    fs movl %10, %9\n"
            "    fs movl %11, %%eax\n"
            "    andl $0x400, %%eax\n"
            "    fs orl %8, %%eax\n"
            "    pushl %%eax\n"
            "    popf\n"
            "    fs movl %%esp, %12\n"
            "    fs movl %0, %%eax\n"
            "    fs movl %1, %%ecx\n"
            "    fs movl %2, %%edx\n"
            "    fs movl %3, %%ebx\n"
            "    fs movl %4, %%esp\n"
            "    fs movl %5, %%ebp\n"
            "    fs movl %6, %%esi\n"
            "    fs movl %7, %%edi\n"
            "    fs jmp *%9\n"
            "exec_loop:\n"
            "    fs movl %%esp, %4\n"
            "    fs movl %12, %%esp\n"
            "    fs movl %%eax, %0\n"
            "    fs movl %%ecx, %1\n"
            "    fs movl %%edx, %2\n"
            "    fs movl %%ebx, %3\n"
            "    fs movl %%ebp, %5\n"
            "    fs movl %%esi, %6\n"
            "    fs movl %%edi, %7\n"
            "    pushf\n"
            "    popl %%eax\n"
            "    movl %%eax, %%ecx\n"
            "    andl $0x400, %%ecx\n"
            "    shrl $9, %%ecx\n"
            "    andl $0x8d5, %%eax\n"
            "    fs movl %%eax, %8\n"
            "    movl $1, %%eax\n"
            "    subl %%ecx, %%eax\n"
            "    fs movl %%eax, %11\n"
            "    fs movl %9, %%ebx\n" /* get T0 value */
            "    popl %%ebp\n"
            :
            : "m" (*(uint8_t *)offsetof(CPUState, regs[0])),
            "m" (*(uint8_t *)offsetof(CPUState, regs[1])),
            "m" (*(uint8_t *)offsetof(CPUState, regs[2])),
            "m" (*(uint8_t *)offsetof(CPUState, regs[3])),
            "m" (*(uint8_t *)offsetof(CPUState, regs[4])),
            "m" (*(uint8_t *)offsetof(CPUState, regs[5])),
            "m" (*(uint8_t *)offsetof(CPUState, regs[6])),
            "m" (*(uint8_t *)offsetof(CPUState, regs[7])),
            "m" (*(uint8_t *)offsetof(CPUState, cc_src)),
            "m" (*(uint8_t *)offsetof(CPUState, tmp0)),
            "a" (gen_func),
            "m" (*(uint8_t *)offsetof(CPUState, df)),
            "m" (*(uint8_t *)offsetof(CPUState, saved_esp))
            : "%ecx", "%edx"
            );
    }
}
bellard's avatar
bellard committed
567
#else
568
                gen_func();
bellard's avatar
bellard committed
569
#endif
bellard's avatar
bellard committed
570
                env->current_tb = NULL;
bellard's avatar
bellard committed
571 572 573
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
574 575
                if (env->hflags & HF_SOFTMMU_MASK) {
                    env->hflags &= ~HF_SOFTMMU_MASK;
bellard's avatar
bellard committed
576 577 578 579
                    /* do not allow linking to another block */
                    T0 = 0;
                }
#endif
580 581
            }
        } else {
582
            env_to_regs();
bellard's avatar
bellard committed
583
        }
584 585
    } /* for(;;) */

bellard's avatar
bellard committed
586

587
#if defined(TARGET_I386)
588 589 590 591 592
#if defined(USE_CODE_COPY)
    if (env->native_fp_regs) {
        save_native_fp_state(env);
    }
#endif
bellard's avatar
bellard committed
593
    /* restore flags in standard format */
bellard's avatar
bellard committed
594
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard's avatar
bellard committed
595

bellard's avatar
bellard committed
596
    /* restore global registers */
bellard's avatar
bellard committed
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
#ifdef reg_EAX
    EAX = saved_EAX;
#endif
#ifdef reg_ECX
    ECX = saved_ECX;
#endif
#ifdef reg_EDX
    EDX = saved_EDX;
#endif
#ifdef reg_EBX
    EBX = saved_EBX;
#endif
#ifdef reg_ESP
    ESP = saved_ESP;
#endif
#ifdef reg_EBP
    EBP = saved_EBP;
#endif
#ifdef reg_ESI
    ESI = saved_ESI;
#endif
#ifdef reg_EDI
    EDI = saved_EDI;
620
#endif
621
#elif defined(TARGET_ARM)
bellard's avatar
bellard committed
622
    env->cpsr = compute_cpsr();
623
#elif defined(TARGET_SPARC)
624
#elif defined(TARGET_PPC)
625 626 627
#else
#error unsupported target CPU
#endif
628 629
#ifdef __sparc__
    asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
bellard's avatar
bellard committed
630
#endif
bellard's avatar
bellard committed
631 632
    T0 = saved_T0;
    T1 = saved_T1;
633
    T2 = saved_T2;
bellard's avatar
bellard committed
634 635 636
    env = saved_env;
    return ret;
}
bellard's avatar
bellard committed
637

638 639 640 641
/* 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)
{
642 643 644
    /* XXX: cannot enable it yet because it yields to MMU exception
       where NIP != read address on PowerPC */
#if 0
645 646 647
    target_ulong phys_addr;
    phys_addr = get_phys_addr_code(env, start);
    tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
648
#endif
649 650
}

bellard's avatar
bellard committed
651
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
652

bellard's avatar
bellard committed
653 654 655 656 657 658
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
bellard's avatar
bellard committed
659
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellard's avatar
bellard committed
660
        selector &= 0xffff;
661
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
bellard's avatar
bellard committed
662
                               (selector << 4), 0xffff, 0);
bellard's avatar
bellard committed
663
    } else {
bellard's avatar
bellard committed
664
        load_seg(seg_reg, selector);
bellard's avatar
bellard committed
665
    }
bellard's avatar
bellard committed
666 667
    env = saved_env;
}
bellard's avatar
bellard committed
668

669 670 671 672 673 674 675
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
    
bellard's avatar
bellard committed
676
    helper_fsave((target_ulong)ptr, data32);
677 678 679 680 681 682 683 684 685 686 687

    env = saved_env;
}

void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
    
bellard's avatar
bellard committed
688
    helper_frstor((target_ulong)ptr, data32);
689 690 691 692

    env = saved_env;
}

693 694
#endif /* TARGET_I386 */

bellard's avatar
bellard committed
695 696
#if !defined(CONFIG_SOFTMMU)

697 698
#if defined(TARGET_I386)

699
/* 'pc' is the host PC at which the exception was raised. 'address' is
bellard's avatar
bellard committed
700 701 702
   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 */
bellard's avatar
bellard committed
703
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
704 705
                                    int is_write, sigset_t *old_set, 
                                    void *puc)
bellard's avatar
bellard committed
706
{
bellard's avatar
bellard committed
707 708
    TranslationBlock *tb;
    int ret;
bellard's avatar
bellard committed
709

bellard's avatar
bellard committed
710 711
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard's avatar
bellard committed
712
#if defined(DEBUG_SIGNAL)
713 714
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
                pc, address, is_write, *(unsigned long *)old_set);
bellard's avatar
bellard committed
715
#endif
716
    /* XXX: locking issue */
717
    if (is_write && page_unprotect(address, pc, puc)) {
bellard's avatar
bellard committed
718 719
        return 1;
    }
720

721
    /* see if it is an MMU fault */
bellard's avatar
bellard committed
722 723
    ret = cpu_x86_handle_mmu_fault(env, address, is_write, 
                                   ((env->hflags & HF_CPL_MASK) == 3), 0);
724 725 726 727 728
    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 */
bellard's avatar
bellard committed
729 730
    tb = tb_find_pc(pc);
    if (tb) {
bellard's avatar
bellard committed
731 732
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
733
        cpu_restore_state(tb, env, pc, puc);
734
    }
bellard's avatar
bellard committed
735
    if (ret == 1) {
736
#if 0
bellard's avatar
bellard committed
737 738
        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
               env->eip, env->cr[2], env->error_code);
739
#endif
bellard's avatar
bellard committed
740 741 742 743 744 745
        /* we restore the process signal mask as the sigreturn should
           do it (XXX: use sigsetjmp) */
        sigprocmask(SIG_SETMASK, old_set, NULL);
        raise_exception_err(EXCP0E_PAGE, env->error_code);
    } else {
        /* activate soft MMU for this block */
746
        env->hflags |= HF_SOFTMMU_MASK;
747
        cpu_resume_from_signal(env, puc);
bellard's avatar
bellard committed
748
    }
749 750 751 752
    /* never comes here */
    return 1;
}

753
#elif defined(TARGET_ARM)
754
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
755 756
                                    int is_write, sigset_t *old_set,
                                    void *puc)
757
{
bellard's avatar
bellard committed
758 759 760 761 762 763 764 765 766
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
           pc, address, is_write, *(unsigned long *)old_set);
#endif
bellard's avatar
bellard committed
767 768 769 770
    /* XXX: locking issue */
    if (is_write && page_unprotect(address, pc, puc)) {
        return 1;
    }
bellard's avatar
bellard committed
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
    /* see if it is an MMU fault */
    ret = cpu_arm_handle_mmu_fault(env, address, is_write, 1, 0);
    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);
    cpu_loop_exit();
788
}
789 790
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
791 792
                                    int is_write, sigset_t *old_set,
                                    void *puc)
793
{
bellard's avatar
bellard committed
794 795 796 797 798 799 800 801 802
    TranslationBlock *tb;
    int ret;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
           pc, address, is_write, *(unsigned long *)old_set);
#endif
bellard's avatar
bellard committed
803
    /* XXX: locking issue */
804
    if (is_write && page_unprotect(address, pc, puc)) {
bellard's avatar
bellard committed
805 806
        return 1;
    }
bellard's avatar
bellard committed
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
    /* see if it is an MMU fault */
    ret = cpu_sparc_handle_mmu_fault(env, address, is_write, 1, 0);
    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);
    cpu_loop_exit();
824
}
825 826
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
827 828
                                    int is_write, sigset_t *old_set,
                                    void *puc)
829 830
{
    TranslationBlock *tb;
831
    int ret;
832 833 834 835 836 837 838 839
    
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
           pc, address, is_write, *(unsigned long *)old_set);
#endif
    /* XXX: locking issue */
840
    if (is_write && page_unprotect(address, pc, puc)) {
841 842 843
        return 1;
    }

844
    /* see if it is an MMU fault */
bellard's avatar
bellard committed
845
    ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
846 847 848 849 850
    if (ret < 0)
        return 0; /* not an MMU fault */
    if (ret == 0)
        return 1; /* the MMU fault was handled without causing real CPU fault */

851 852 853 854 855
    /* 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 */
856
        cpu_restore_state(tb, env, pc, puc);
857
    }
858
    if (ret == 1) {
859
#if 0
860 861
        printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
               env->nip, env->error_code, tb);
862 863 864
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
865
        sigprocmask(SIG_SETMASK, old_set, NULL);
866
        do_raise_exception_err(env->exception_index, env->error_code);
867 868
    } else {
        /* activate soft MMU for this block */
869
        cpu_resume_from_signal(env, puc);
870
    }
871 872 873
    /* never comes here */
    return 1;
}
874 875 876
#else
#error unsupported target CPU
#endif
bellard's avatar
bellard committed
877

bellard's avatar
bellard committed
878 879
#if defined(__i386__)

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
#if defined(USE_CODE_COPY)
static void cpu_send_trap(unsigned long pc, int trap, 
                          struct ucontext *uc)
{
    TranslationBlock *tb;

    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
    /* 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, uc);
    }
    sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
    raise_exception_err(trap, env->error_code);
}
#endif

900 901
int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
bellard's avatar
bellard committed
902 903 904
{
    struct ucontext *uc = puc;
    unsigned long pc;
905
    int trapno;
906

907 908
#ifndef REG_EIP
/* for glibc 2.1 */
bellard's avatar
bellard committed
909 910 911
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
912
#endif
bellard's avatar
bellard committed
913
    pc = uc->uc_mcontext.gregs[REG_EIP];
914 915 916 917 918 919 920 921 922 923 924 925
    trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
    if (trapno == 0x00 || trapno == 0x05) {
        /* send division by zero or bound exception */
        cpu_send_trap(pc, trapno, uc);
        return 1;
    } else
#endif
        return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                                 trapno == 0xe ? 
                                 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
                                 &uc->uc_sigmask, puc);
bellard's avatar
bellard committed
926 927
}

928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
#elif defined(__x86_64__)

int cpu_signal_handler(int host_signum, struct siginfo *info,
                       void *puc)
{
    struct ucontext *uc = puc;
    unsigned long pc;

    pc = uc->uc_mcontext.gregs[REG_RIP];
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? 
                             (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
                             &uc->uc_sigmask, puc);
}

943
#elif defined(__powerpc__)
bellard's avatar
bellard committed
944

945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
/***********************************************************************
 * 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 */

#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__ */

bellard's avatar
bellard committed
994
int cpu_signal_handler(int host_signum, struct siginfo *info, 
995
                       void *puc)
bellard's avatar
bellard committed
996
{
997 998 999 1000
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;

1001
    pc = IAR_sig(uc);
1002 1003 1004
    is_write = 0;
#if 0
    /* ppc 4xx case */
1005
    if (DSISR_sig(uc) & 0x00800000)
1006 1007
        is_write = 1;
#else
1008
    if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1009 1010 1011
        is_write = 1;
#endif
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1012
                             is_write, &uc->uc_sigmask, puc);
bellard's avatar
bellard committed
1013 1014
}

bellard's avatar
bellard committed
1015 1016
#elif defined(__alpha__)

1017
int cpu_signal_handler(int host_signum, struct siginfo *info, 
bellard's avatar
bellard committed
1018 1019 1020 1021 1022 1023 1024
                           void *puc)
{
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

1025
    /* XXX: need kernel patch to get write flag faster */
bellard's avatar
bellard committed
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
    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;
    }

    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1042
                             is_write, &uc->uc_sigmask, puc);
bellard's avatar
bellard committed
1043
}
1044 1045
#elif defined(__sparc__)

1046 1047
int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
{
    uint32_t *regs = (uint32_t *)(info + 1);
    void *sigmask = (regs + 20);
    unsigned long pc;
    int is_write;
    uint32_t insn;
    
    /* XXX: is there a standard glibc define ? */
    pc = regs[1];
    /* 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
      case 0x06: // sth
      case 0x04: // st
      case 0x07: // std
      case 0x24: // stf
      case 0x27: // stdf
      case 0x25: // stfsr
	is_write = 1;
	break;
      }
    }
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
1074
                             is_write, sigmask, NULL);
1075 1076 1077 1078
}

#elif defined(__arm__)

1079 1080
int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
{
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
    
    pc = uc->uc_mcontext.gregs[R15];
    /* XXX: compute is_write */
    is_write = 0;
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                             is_write,
                             &uc->uc_sigmask);
}

bellard's avatar
bellard committed
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
#elif defined(__mc68000)

int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
{
    struct ucontext *uc = puc;
    unsigned long pc;
    int is_write;
    
    pc = uc->uc_mcontext.gregs[16];
    /* XXX: compute is_write */
    is_write = 0;
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                             is_write,
1108
                             &uc->uc_sigmask, puc);
bellard's avatar
bellard committed
1109 1110
}

bellard's avatar
bellard committed
1111
#else
bellard's avatar
bellard committed
1112

1113
#error host CPU specific signal handler needed
bellard's avatar
bellard committed
1114

bellard's avatar
bellard committed
1115
#endif
bellard's avatar
bellard committed
1116 1117

#endif /* !defined(CONFIG_SOFTMMU) */