cpu-exec.c 28.1 KB
Newer Older
B
bellard 已提交
1 2 3 4 5
/*
 *  i386 emulator main execution loop
 * 
 *  Copyright (c) 2003 Fabrice Bellard
 *
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 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
B
bellard 已提交
19
 */
B
bellard 已提交
20
#include "config.h"
21
#include "exec.h"
B
log fix  
bellard 已提交
22
#include "disas.h"
B
bellard 已提交
23

24 25
int tb_invalidated_flag;

B
bellard 已提交
26
//#define DEBUG_EXEC
B
bellard 已提交
27
//#define DEBUG_SIGNAL
B
bellard 已提交
28

29
#if defined(TARGET_ARM) || defined(TARGET_SPARC)
B
bellard 已提交
30 31 32 33 34 35 36
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
    longjmp(env->jmp_env, 1);
}
#endif

B
bellard 已提交
37 38
/* main execution loop */

B
bellard 已提交
39
int cpu_exec(CPUState *env1)
B
bellard 已提交
40
{
B
bellard 已提交
41 42
    int saved_T0, saved_T1, saved_T2;
    CPUState *saved_env;
B
bellard 已提交
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#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;
66 67 68
#endif
#ifdef __sparc__
    int saved_i7, tmp_T0;
B
bellard 已提交
69
#endif
B
bellard 已提交
70
    int code_gen_size, ret, interrupt_request;
B
bellard 已提交
71
    void (*gen_func)(void);
B
bellard 已提交
72
    TranslationBlock *tb, **ptb;
B
bellard 已提交
73
    uint8_t *tc_ptr, *cs_base, *pc;
B
bellard 已提交
74
    unsigned int flags;
75

B
bellard 已提交
76 77 78
    /* first we save global registers */
    saved_T0 = T0;
    saved_T1 = T1;
B
bellard 已提交
79
    saved_T2 = T2;
B
bellard 已提交
80 81
    saved_env = env;
    env = env1;
B
bellard 已提交
82 83 84 85 86 87
#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)
B
bellard 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
#ifdef reg_EAX
    saved_EAX = EAX;
    EAX = env->regs[R_EAX];
#endif
#ifdef reg_ECX
    saved_ECX = ECX;
    ECX = env->regs[R_ECX];
#endif
#ifdef reg_EDX
    saved_EDX = EDX;
    EDX = env->regs[R_EDX];
#endif
#ifdef reg_EBX
    saved_EBX = EBX;
    EBX = env->regs[R_EBX];
#endif
#ifdef reg_ESP
    saved_ESP = ESP;
    ESP = env->regs[R_ESP];
#endif
#ifdef reg_EBP
    saved_EBP = EBP;
    EBP = env->regs[R_EBP];
#endif
#ifdef reg_ESI
    saved_ESI = ESI;
    ESI = env->regs[R_ESI];
#endif
#ifdef reg_EDI
    saved_EDI = EDI;
    EDI = env->regs[R_EDI];
#endif
B
bellard 已提交
120
    
B
bellard 已提交
121
    /* put eflags in CPU temporary format */
B
bellard 已提交
122 123
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
B
bellard 已提交
124
    CC_OP = CC_OP_EFLAGS;
B
bellard 已提交
125
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
B
bellard 已提交
126 127 128 129 130 131 132 133 134
#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;
        env->cpsr = psr & ~0xf0000000;
    }
135
#elif defined(TARGET_SPARC)
136
#elif defined(TARGET_PPC)
B
bellard 已提交
137 138 139
#else
#error unsupported target CPU
#endif
140
    env->exception_index = -1;
141

B
bellard 已提交
142
    /* prepare setjmp context for exception handling */
143 144
    for(;;) {
        if (setjmp(env->jmp_env) == 0) {
145
            env->current_tb = NULL;
146 147 148 149 150 151 152 153 154 155
            /* 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 */
B
bellard 已提交
156
#if defined(TARGET_I386)
157 158 159 160
                    do_interrupt_user(env->exception_index, 
                                      env->exception_is_int, 
                                      env->error_code, 
                                      env->exception_next_eip);
B
bellard 已提交
161
#endif
162 163 164
                    ret = env->exception_index;
                    break;
                } else {
B
bellard 已提交
165
#if defined(TARGET_I386)
166 167 168 169 170 171
                    /* 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, 
B
bellard 已提交
172
                                 env->exception_next_eip, 0);
173 174
#elif defined(TARGET_PPC)
                    do_interrupt(env);
B
bellard 已提交
175
#endif
176 177 178 179 180
                }
                env->exception_index = -1;
            }
            T0 = 0; /* force lookup of first TB */
            for(;;) {
181
#ifdef __sparc__
182 183
                /* g1 can be modified by some libc? functions */ 
                tmp_T0 = T0;
184
#endif	    
B
bellard 已提交
185
                interrupt_request = env->interrupt_request;
186
                if (__builtin_expect(interrupt_request, 0)) {
B
bellard 已提交
187 188 189
#if defined(TARGET_I386)
                    /* if hardware interrupt pending, we execute it */
                    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
190 191
                        (env->eflags & IF_MASK) && 
                        !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
B
bellard 已提交
192 193 194 195 196
                        int intno;
                        intno = cpu_x86_get_pic_interrupt(env);
                        if (loglevel) {
                            fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
                        }
B
bellard 已提交
197
                        do_interrupt(intno, 0, 0, 0, 1);
B
bellard 已提交
198
                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
B
bellard 已提交
199 200 201 202 203 204 205
                        /* ensure that no TB jump will be modified as
                           the program flow was changed */
#ifdef __sparc__
                        tmp_T0 = 0;
#else
                        T0 = 0;
#endif
B
bellard 已提交
206
                    }
207 208 209 210 211 212 213
#elif defined(TARGET_PPC)
                    if ((interrupt_request & CPU_INTERRUPT_HARD)) {
                        do_queue_exception(EXCP_EXTERNAL);
                        if (check_exception_state(env))
                            do_interrupt(env);
                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                    }
B
bellard 已提交
214
#endif
215 216 217 218 219 220 221 222 223 224
                    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
                    }
B
bellard 已提交
225 226 227 228 229
                    if (interrupt_request & CPU_INTERRUPT_EXIT) {
                        env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
                        env->exception_index = EXCP_INTERRUPT;
                        cpu_loop_exit();
                    }
230
                }
B
bellard 已提交
231
#ifdef DEBUG_EXEC
232
                if (loglevel) {
B
bellard 已提交
233
#if defined(TARGET_I386)
234 235 236 237 238 239 240 241 242 243
                    /* 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);
B
bellard 已提交
244
                    cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
245
                    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
B
bellard 已提交
246
#elif defined(TARGET_ARM)
B
bellard 已提交
247
                    env->cpsr = compute_cpsr();
248
                    cpu_arm_dump_state(env, logfile, 0);
B
bellard 已提交
249
                    env->cpsr &= ~0xf0000000;
250
#elif defined(TARGET_SPARC)
B
bellard 已提交
251
                    cpu_sparc_dump_state (env, logfile, 0);
252 253
#elif defined(TARGET_PPC)
                    cpu_ppc_dump_state(env, logfile, 0);
B
bellard 已提交
254 255 256
#else
#error unsupported target CPU 
#endif
257
                }
B
bellard 已提交
258
#endif
259 260 261
                /* we record a subset of the CPU state. It will
                   always be the same before a given translated block
                   is executed. */
B
bellard 已提交
262
#if defined(TARGET_I386)
263
                flags = env->hflags;
264
                flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
265 266
                cs_base = env->segs[R_CS].base;
                pc = cs_base + env->eip;
B
bellard 已提交
267
#elif defined(TARGET_ARM)
268 269 270
                flags = 0;
                cs_base = 0;
                pc = (uint8_t *)env->regs[15];
271
#elif defined(TARGET_SPARC)
272
                flags = 0;
273
                cs_base = (uint8_t *)env->npc;
274 275 276 277 278
                pc = (uint8_t *) env->pc;
#elif defined(TARGET_PPC)
                flags = 0;
                cs_base = 0;
                pc = (uint8_t *)env->nip;
B
bellard 已提交
279 280 281
#else
#error unsupported CPU
#endif
282 283
                tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
                             flags);
B
bellard 已提交
284
                if (!tb) {
B
bellard 已提交
285 286 287 288 289
                    TranslationBlock **ptb1;
                    unsigned int h;
                    target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
                    
                    
290
                    spin_lock(&tb_lock);
B
bellard 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

                    tb_invalidated_flag = 0;

                    /* find translated block using physical mappings */
                    phys_pc = get_phys_addr_code(env, (unsigned long)pc);
                    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;
                        if (tb->pc == (unsigned long)pc && 
                            tb->page_addr[0] == phys_page1 &&
                            tb->cs_base == (unsigned long)cs_base && 
                            tb->flags == flags) {
                            /* check next page if needed */
309 310 311
                            if (tb->page_addr[1] != -1) {
                                virt_page2 = ((unsigned long)pc & TARGET_PAGE_MASK) + 
                                    TARGET_PAGE_SIZE;
B
bellard 已提交
312 313 314 315 316 317 318 319 320 321
                                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:
322
                    /* if no translated code available, then translate it now */
B
bellard 已提交
323
                    tb = tb_alloc((unsigned long)pc);
324 325
                    if (!tb) {
                        /* flush must be done */
B
bellard 已提交
326
                        tb_flush(env);
327 328 329 330 331 332 333 334 335 336
                        /* cannot fail at this point */
                        tb = tb_alloc((unsigned long)pc);
                        /* don't forget to invalidate previous TB info */
                        ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
                        T0 = 0;
                    }
                    tc_ptr = code_gen_ptr;
                    tb->tc_ptr = tc_ptr;
                    tb->cs_base = (unsigned long)cs_base;
                    tb->flags = flags;
B
bellard 已提交
337
                    cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
B
bellard 已提交
338 339 340 341 342 343 344 345 346 347 348
                    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 */
                    virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
                    phys_page2 = -1;
                    if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
                        phys_page2 = get_phys_addr_code(env, virt_page2);
                    }
                    tb_link_phys(tb, phys_pc, phys_page2);

                found:
349 350 351 352 353 354 355 356 357
                    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 */
                        ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
                        while (*ptb != NULL)
                            ptb = &(*ptb)->hash_next;
                        T0 = 0;
                    }
B
bellard 已提交
358
                    /* we add the TB in the virtual pc hash table */
359 360 361
                    *ptb = tb;
                    tb->hash_next = NULL;
                    tb_link(tb);
362
                    spin_unlock(&tb_lock);
B
bellard 已提交
363
                }
364
#ifdef DEBUG_EXEC
365 366 367 368 369
                if (loglevel) {
                    fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
                            (long)tb->tc_ptr, (long)tb->pc,
                            lookup_symbol((void *)tb->pc));
                }
370
#endif
371
#ifdef __sparc__
372
                T0 = tmp_T0;
373
#endif	    
B
bellard 已提交
374
                /* see if we can patch the calling TB. */
375 376 377 378 379 380
                if (T0 != 0
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
                    && (tb->cflags & CF_CODE_COPY) == 
                    (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
#endif
                    ) {
381 382 383 384 385
                    spin_lock(&tb_lock);
                    tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
                    spin_unlock(&tb_lock);
                }
                tc_ptr = tb->tc_ptr;
B
bellard 已提交
386
                env->current_tb = tb;
387 388
                /* execute the generated code */
                gen_func = (void *)tc_ptr;
389
#if defined(__sparc__)
390 391 392 393 394
                __asm__ __volatile__("call	%0\n\t"
                                     "mov	%%o7,%%i0"
                                     : /* no outputs */
                                     : "r" (gen_func) 
                                     : "i0", "i1", "i2", "i3", "i4", "i5");
395
#elif defined(__arm__)
396 397 398 399 400 401
                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");
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
{
    if (!(tb->cflags & CF_CODE_COPY)) {
        gen_func();
    } else {
        /* 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"
            );
    }
}
B
bellard 已提交
470
#else
471
                gen_func();
B
bellard 已提交
472
#endif
B
bellard 已提交
473
                env->current_tb = NULL;
B
bellard 已提交
474 475 476
                /* reset soft MMU for next block (it can currently
                   only be set by a memory fault) */
#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
477 478
                if (env->hflags & HF_SOFTMMU_MASK) {
                    env->hflags &= ~HF_SOFTMMU_MASK;
B
bellard 已提交
479 480 481 482
                    /* do not allow linking to another block */
                    T0 = 0;
                }
#endif
483 484
            }
        } else {
B
bellard 已提交
485
        }
486 487
    } /* for(;;) */

B
bellard 已提交
488

B
bellard 已提交
489
#if defined(TARGET_I386)
B
bellard 已提交
490
    /* restore flags in standard format */
B
bellard 已提交
491
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
B
bellard 已提交
492

B
bellard 已提交
493
    /* restore global registers */
B
bellard 已提交
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
#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;
517
#endif
B
bellard 已提交
518
#elif defined(TARGET_ARM)
B
bellard 已提交
519
    env->cpsr = compute_cpsr();
520
#elif defined(TARGET_SPARC)
521
#elif defined(TARGET_PPC)
B
bellard 已提交
522 523 524
#else
#error unsupported target CPU
#endif
525 526
#ifdef __sparc__
    asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
B
bellard 已提交
527
#endif
B
bellard 已提交
528 529
    T0 = saved_T0;
    T1 = saved_T1;
B
bellard 已提交
530
    T2 = saved_T2;
B
bellard 已提交
531 532 533
    env = saved_env;
    return ret;
}
B
bellard 已提交
534

B
bellard 已提交
535
#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
B
bellard 已提交
536

B
bellard 已提交
537 538 539 540 541 542
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
B
bellard 已提交
543
    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
B
bellard 已提交
544
        selector &= 0xffff;
545 546
        cpu_x86_load_seg_cache(env, seg_reg, selector, 
                               (uint8_t *)(selector << 4), 0xffff, 0);
B
bellard 已提交
547
    } else {
B
bellard 已提交
548
        load_seg(seg_reg, selector);
B
bellard 已提交
549
    }
B
bellard 已提交
550 551
    env = saved_env;
}
B
bellard 已提交
552

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
    
    helper_fsave(ptr, data32);

    env = saved_env;
}

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

    saved_env = env;
    env = s;
    
    helper_frstor(ptr, data32);

    env = saved_env;
}

B
bellard 已提交
577 578
#endif /* TARGET_I386 */

B
bellard 已提交
579 580 581 582 583 584 585 586 587 588 589 590
#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>

591 592
#if defined(TARGET_I386)

593
/* 'pc' is the host PC at which the exception was raised. 'address' is
B
bellard 已提交
594 595 596
   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 已提交
597
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
598 599
                                    int is_write, sigset_t *old_set, 
                                    void *puc)
B
bellard 已提交
600
{
B
bellard 已提交
601 602
    TranslationBlock *tb;
    int ret;
B
bellard 已提交
603

B
bellard 已提交
604 605
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
B
bellard 已提交
606
#if defined(DEBUG_SIGNAL)
607 608
    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
                pc, address, is_write, *(unsigned long *)old_set);
B
bellard 已提交
609
#endif
610
    /* XXX: locking issue */
B
bellard 已提交
611 612 613
    if (is_write && page_unprotect(address)) {
        return 1;
    }
614
    /* see if it is an MMU fault */
B
bellard 已提交
615 616
    ret = cpu_x86_handle_mmu_fault(env, address, is_write, 
                                   ((env->hflags & HF_CPL_MASK) == 3), 0);
617 618 619 620 621
    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 */
B
bellard 已提交
622 623
    tb = tb_find_pc(pc);
    if (tb) {
B
bellard 已提交
624 625
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
626
        cpu_restore_state(tb, env, pc, puc);
627
    }
B
bellard 已提交
628
    if (ret == 1) {
629
#if 0
B
bellard 已提交
630 631
        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
               env->eip, env->cr[2], env->error_code);
632
#endif
B
bellard 已提交
633 634 635 636 637 638
        /* 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 */
639
        env->hflags |= HF_SOFTMMU_MASK;
B
bellard 已提交
640 641 642
        sigprocmask(SIG_SETMASK, old_set, NULL);
        cpu_loop_exit();
    }
643 644 645 646
    /* never comes here */
    return 1;
}

B
bellard 已提交
647
#elif defined(TARGET_ARM)
648
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
649 650
                                    int is_write, sigset_t *old_set,
                                    void *puc)
651 652 653 654
{
    /* XXX: do more */
    return 0;
}
655 656
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
657 658
                                    int is_write, sigset_t *old_set,
                                    void *puc)
659
{
B
bellard 已提交
660 661 662 663 664
    /* XXX: locking issue */
    if (is_write && page_unprotect(address)) {
        return 1;
    }
    return 0;
665
}
666 667
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
668 669
                                    int is_write, sigset_t *old_set,
                                    void *puc)
670 671
{
    TranslationBlock *tb;
672
    int ret;
673
    
674
#if 1
675 676 677 678 679 680 681 682 683 684 685 686
    if (cpu_single_env)
        env = cpu_single_env; /* XXX: find a correct solution for multithread */
#endif
#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 */
    if (is_write && page_unprotect(address)) {
        return 1;
    }

687
    /* see if it is an MMU fault */
B
bellard 已提交
688
    ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
689 690 691 692 693
    if (ret < 0)
        return 0; /* not an MMU fault */
    if (ret == 0)
        return 1; /* the MMU fault was handled without causing real CPU fault */

694 695 696 697 698
    /* 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 */
699
        cpu_restore_state(tb, env, pc, puc);
700
    }
701
    if (ret == 1) {
702
#if 0
703 704
        printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
               env->nip, env->error_code, tb);
705 706 707
#endif
    /* we restore the process signal mask as the sigreturn should
       do it (XXX: use sigsetjmp) */
708
        sigprocmask(SIG_SETMASK, old_set, NULL);
709 710 711 712 713 714
        do_queue_exception_err(env->exception_index, env->error_code);
    } else {
        /* activate soft MMU for this block */
        sigprocmask(SIG_SETMASK, old_set, NULL);
        cpu_loop_exit();
    }
715 716 717
    /* never comes here */
    return 1;
}
B
bellard 已提交
718 719 720
#else
#error unsupported target CPU
#endif
B
bellard 已提交
721

B
bellard 已提交
722 723
#if defined(__i386__)

724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
#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

B
bellard 已提交
744 745
int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
B
bellard 已提交
746 747 748
{
    struct ucontext *uc = puc;
    unsigned long pc;
749
    int trapno;
B
bellard 已提交
750
    
751 752
#ifndef REG_EIP
/* for glibc 2.1 */
B
bellard 已提交
753 754 755
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
756
#endif
B
bellard 已提交
757
    pc = uc->uc_mcontext.gregs[REG_EIP];
758 759 760 761 762 763 764 765 766 767 768 769
    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);
B
bellard 已提交
770 771
}

772
#elif defined(__powerpc)
B
bellard 已提交
773

B
bellard 已提交
774 775
int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
B
bellard 已提交
776
{
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
    struct ucontext *uc = puc;
    struct pt_regs *regs = uc->uc_mcontext.regs;
    unsigned long pc;
    int is_write;

    pc = regs->nip;
    is_write = 0;
#if 0
    /* ppc 4xx case */
    if (regs->dsisr & 0x00800000)
        is_write = 1;
#else
    if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
        is_write = 1;
#endif
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
793
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
794 795
}

B
bellard 已提交
796 797
#elif defined(__alpha__)

B
bellard 已提交
798
int cpu_signal_handler(int host_signum, struct siginfo *info, 
B
bellard 已提交
799 800 801 802 803 804 805
                           void *puc)
{
    struct ucontext *uc = puc;
    uint32_t *pc = uc->uc_mcontext.sc_pc;
    uint32_t insn = *pc;
    int is_write = 0;

806
    /* XXX: need kernel patch to get write flag faster */
B
bellard 已提交
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
    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, 
823
                             is_write, &uc->uc_sigmask, puc);
B
bellard 已提交
824
}
825 826
#elif defined(__sparc__)

B
bellard 已提交
827 828
int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
{
    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, 
855
                             is_write, sigmask, NULL);
856 857 858 859
}

#elif defined(__arm__)

B
bellard 已提交
860 861
int cpu_signal_handler(int host_signum, struct siginfo *info, 
                       void *puc)
862 863 864 865 866 867 868 869 870 871 872 873 874
{
    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);
}

B
bellard 已提交
875 876 877 878 879 880 881 882 883 884 885 886 887 888
#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,
889
                             &uc->uc_sigmask, puc);
B
bellard 已提交
890 891
}

B
bellard 已提交
892
#else
B
bellard 已提交
893

894
#error host CPU specific signal handler needed
B
bellard 已提交
895

B
bellard 已提交
896
#endif